[
  {
    "path": ".gitignore",
    "content": "*.bak\r\ngen\r\nbin\r\n.settings\r\n.idea\r\n.gradle\r\n*.iml\r\n*.jar\r\n*.classpath\r\n*.project\r\nbuild\r\ndoclava\r\nlocal.properties\r\n/gradle.properties\r\n"
  },
  {
    "path": "README.md",
    "content": "# rcsjta\nRCS-e stack for Android with GSMA API **RCS-e stack for Android with GSMA API**\n\n<img src='https://github.com/android-rcs/rcsjta/blob/master/docs/website/twitter-bird-16x16.png'> <a href='http://twitter.com/androidrcsstack'>Follow @androidrcsstack</a><br>\n\nThe RCS-e stack is an open source implementation of the Rich Communication Suite standards for Google Android platform. This implementation is compliant to GSMA RCS-e Blackbird standards. Thanks to its client/server API, the stack may be easily integrated with existing native Android applications (e.g. address book, dialer) and permits to create new RCS applications (e.g. chat, widgets).\n\n##About RCS, Rich Communication Suite:\n\nThe Rich Communication Suite Initiative is a GSM Association programme dedicated to deliver convergent rich communication services. RCS should be the first set of services using IMS architecture in the mobile field. \"joyn\" is the commercial name of RCS.\n\nSee also the RCS website at GSM Association, [http://www.gsma.com/rcs/](http://www.gsma.com/rcs/).\n\nThe RCS specifications (product, technical, API, Guidelines) are available at [http://www.gsma.com/network2020/rcs/specs-and-product-docs/](http://www.gsma.com/network2020/rcs/specs-and-product-docs/).\n\nNote: the [supported standards](https://rawgit.com/android-rcs/rcsjta/master/docs/SUPPORTED-STANDARDS.txt).\n\n##Licensing:\nThe RCS core stack is under [Apache 2 license](https://rawgit.com/android-rcs/rcsjta/master/core/LICENSE-2.0.txt) and uses the following open source libraries:\n\n- the SIP stack comes from [NIST-SIP project] (http://jsip.java.net/'>http://jsip.java.net/), see [License](https://rawgit.com/android-rcs/rcsjta/master/core/LICENSE-NIST.txt).\n\n- the DNS stack comes from [DNSJava project](http://www.dnsjava.org/), see [License](https://rawgit.com/android-rcs/rcsjta/master/core/LICENSE-DNS.txt).\n\n- the cryptography API comes from Legion of the [Bouncy Castle Inc] (https://www.bouncycastle.org/), see [License](https://rawgit.com/android-rcs/rcsjta/master/core/LICENSE-BOUNCYCASTLE.txt).\n\n##Project:\n\n- see [Project management](https://rawgit.com/android-rcs/rcsjta/master/docs/RCSJTA_open_source.ppt).\n\n- see [GIT branches](https://github.com/android-rcs/rcsjta/blob/wiki/Branches.md).\n\n##RCS API definition:\n\n- TAPI 1.5\n\n  * see [TAPI 1.5.1 specification](https://rawgit.com/android-rcs/rcsjta/master/docs/tapi/RCC.53_v3.0_1.5.1-r1.docx).\n\n  * see [TAPI 1.5.1 Javadoc] (https://rawgit.com/android-rcs/rcsjta.javadoc/javadoc1.5/index.html).\n  \n\n- TAPI 1.6\n\n  * see [TAPI 1.6.1 specification](https://rawgit.com/android-rcs/rcsjta/master/docs/tapi/RCC.53_CR1005_1.6.1.docx).\n\n  * see [TAPI 1.6.1 Javadoc] (https://rawgit.com/android-rcs/rcsjta.javadoc/javadoc1.6/index.html).\n\n\n##SDK nightly builds:\n- see latest SDK of [tapi_1.5](https://github.com/android-rcs/rcsjta.build/tree/tapi_1.5) branch.\n- see latest SDK of [tapi_1.6](https://github.com/android-rcs/rcsjta.build/tree/tapi_1.6) branch.\n\n##Stack overview:\n\n<img src='https://github.com/android-rcs/rcsjta/blob/master/docs/website/overview.png'><br>\n\n##More docs:\n\n- see [Wiki](https://github.com/android-rcs/rcsjta/wiki).\n\n\n\n\n"
  },
  {
    "path": "RI/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<manifest package=\"com.gsma.rcs.ri\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <permission\n        android:name=\"com.gsma.rcs.ri.permission.MAPS_RECEIVE\"\n        android:protectionLevel=\"signature\"/>\n\n    <uses-permission android:name=\"com.gsma.rcs.ri.permission.MAPS_RECEIVE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n    <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n    <uses-permission android:name=\"android.permission.CALL_PHONE\"/>\n    <uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>\n    <uses-permission android:name=\"android.permission.CAMERA\"/>\n    <uses-permission android:name=\"android.permission.VIBRATE\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.READ_CALL_LOG\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n    <!-- Required to show current location -->\n    <uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\"/>\n\n    <!-- Required OpenGL ES 2.0. for Maps V2 -->\n    <uses-feature\n        android:glEsVersion=\"0x00020000\"\n        android:required=\"true\"/>\n\n    <application\n        android:name=\"com.gsma.rcs.ri.RiApplication\"\n        android:allowBackup=\"false\"\n        android:icon=\"@drawable/app_icon\"\n        android:label=\"@string/app_name\">\n        <meta-data\n            android:name=\"com.gsma.services.rcs.capability.EXTENSION\"\n            android:value=\"ext.messaging;ext.streaming\"/>\n\n        <uses-library android:name=\"com.google.android.maps\"/>\n\n        <!-- Insert here your own key for accessing the Google Maps Android API -->\n        <meta-data\n            android:name=\"com.google.android.maps.v2.API_KEY\"\n            android:value=\"AIzaSyBzry65BIdSaSjXk3dsT1XMPyksclNCnVo\"/>\n        <meta-data\n            android:name=\"com.google.android.gms.version\"\n            android:value=\"@integer/google_play_services_version\"/>\n\n        <!-- Main -->\n        <activity\n            android:name=\"com.gsma.rcs.ri.RI\"\n            android:label=\"@string/app_name\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.AboutRI\"\n            android:label=\"@string/menu_about\"/>\n\n        <receiver android:name=\"com.gsma.rcs.ri.DeviceBoot\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\"/>\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.RcsServiceNotifManager\"\n            android:exported=\"false\"/>\n\n        <!-- Intents API -->\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.intents.TestIntentApps\"\n            android:label=\"@string/menu_apps\"/>\n\n        <!-- Service API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.service.TestServiceApi\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.service.ServiceStatus\"\n            android:label=\"@string/menu_service\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.service.RegistrationStatus\"\n            android:label=\"@string/menu_registration_status\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.service.ServiceConfigurationActivity\"\n            android:label=\"@string/menu_service_configuration\"/>\n\n        <!-- Contacts API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.contacts.TestContactsApi\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.contacts.RcsContactsList\"\n            android:label=\"@string/menu_list_rcs_contacts\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.contacts.ContactVCard\"\n            android:label=\"@string/menu_contact_vcard\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.contacts.BlockingContact\"\n            android:label=\"@string/menu_blocking_contact\"/>\n\n        <!-- Capabilities API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.capabilities.TestCapabilitiesApi\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.capabilities.RequestCapabilities\"\n            android:label=\"@string/menu_capabilities\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.capabilities.MyCapabilities\"\n            android:label=\"@string/menu_my_capabilities\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.capabilities.RequestAllCapabilities\"\n            android:label=\"@string/menu_refresh_capabilities\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.capabilities.CapabilitiesList\"\n            android:label=\"@string/menu_capabilities_log\"/>\n\n        <!-- Messaging API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.messaging.TestMessagingApi\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.OneToOneTalkView\"\n            android:label=\"@string/title_talk_1to1_view\"\n            android:launchMode=\"singleTop\"/>\n\n        <!-- File transfer API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.messaging.filetransfer.TestFileTransferApi\"/>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.InitiateFileTransfer\"\n            android:icon=\"@drawable/ri_quick_ft_icon\"\n            android:label=\"@string/menu_transfer_file\">\n            <intent-filter>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <action android:name=\"com.gsma.services.rcs.action.INITIATE_ONE_TO_ONE_FILE_TRANSFER\"/>\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n                <data android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.file-transfer\"/>\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.FileTransferInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.filetransfer.action.NEW_FILE_TRANSFER\"/>\n            </intent-filter>\n        </receiver>\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.FileTransferResumeReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.filetransfer.action.RESUME_FILE_TRANSFER\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.ReceiveFileTransfer\"\n            android:label=\"@string/title_file_transfer\"\n            android:launchMode=\"singleTop\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.FileTransferServiceConfigActivity\"\n            android:icon=\"@drawable/ri_quick_ft_icon\"\n            android:label=\"@string/menu_ft_config\"/>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.FileTransferIntentService\"\n            android:exported=\"false\"/>\n\n        <!-- Multiple files transfer -->\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.multi.SendMultiFileGroupChat\"\n            android:label=\"@string/title_multi_file_transfer\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.multi.SendMultiFileSingleChat\"\n            android:label=\"@string/title_multi_file_transfer\"/>\n\n        <!-- Chat API -->\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.TestChatApi\"\n            android:icon=\"@drawable/ri_quick_chat_icon\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.single.InitiateSingleChat\"\n            android:icon=\"@drawable/ri_quick_chat_icon\"\n            android:label=\"@string/menu_initiate_chat\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <data android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.im-session\"/>\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.action.SEND_ONE_TO_ONE_CHAT_MESSAGE\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.chat.single.SingleChatInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.ChatServiceConfigActivity\"\n            android:icon=\"@drawable/ri_quick_chat_icon\"\n            android:label=\"@string/menu_chat_config\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.group.InitiateGroupChat\"\n            android:icon=\"@drawable/ri_quick_chat_icon\"\n            android:label=\"@string/menu_initiate_group_chat\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.action.INITIATE_GROUP_CHAT\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.chat.group.GroupChatMessageReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT_MESSAGE\"/>\n            </intent-filter>\n        </receiver>\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.chat.group.GroupChatInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.GroupTalkView\"\n            android:icon=\"@drawable/ri_quick_chat_icon\"\n            android:label=\"@string/title_group_chat\"\n            android:launchMode=\"singleTop\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.GroupDeliveryInfoList\"\n            android:label=\"@string/title_group_delivery_info\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.geoloc.EditGeoloc\"\n            android:label=\"@string/menu_send_geoloc\"\n            android:windowSoftInputMode=\"stateHidden\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.geoloc.ShowGeoloc\"\n            android:label=\"@string/title_display_geoloc\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.geoloc.SelectGeoloc\"\n            android:label=\"@string/label_select_geoloc\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.geoloc.DisplayGeoloc\"\n            android:label=\"@string/title_display_geoloc\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.group.SendGroupFile\"\n            android:icon=\"@drawable/ri_quick_ft_icon\"\n            android:label=\"@string/menu_transfer_file\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.single.SendSingleFile\"\n            android:icon=\"@drawable/ri_quick_ft_icon\"\n            android:label=\"@string/menu_transfer_file\"/>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.messaging.chat.single.SingleChatIntentService\"\n            android:exported=\"false\"/>\n        <service\n            android:name=\"com.gsma.rcs.ri.messaging.chat.group.GroupChatIntentService\"\n            android:exported=\"false\"/>\n\n        <!-- Sharing API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.sharing.TestSharingApi\"/>\n\n        <!-- Image sharing API -->\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.image.InitiateImageSharing\"\n            android:label=\"@string/menu_initiate_image_sharing\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <data android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.image-share\"/>\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.sharing.image.ImageSharingInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.sharing.image.action.NEW_IMAGE_SHARING\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.image.ReceiveImageSharing\"\n            android:label=\"@string/title_image_sharing\"\n            android:launchMode=\"singleTop\"/>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.sharing.image.ImageSharingIntentService\"\n            android:exported=\"false\"/>\n\n        <!-- Geoloc sharing API -->\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.geoloc.InitiateGeolocSharing\"\n            android:label=\"@string/menu_initiate_geoloc_sharing\"/>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.sharing.geoloc.GeolocSharingInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.sharing.geoloc.action.NEW_GEOLOC_SHARING\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.geoloc.ReceiveGeolocSharing\"\n            android:label=\"@string/title_geoloc_sharing\"\n            android:launchMode=\"singleTop\"/>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.sharing.geoloc.GeolocSharingIntentService\"\n            android:exported=\"false\"/>\n\n        <!-- Video sharing API -->\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.video.OutgoingVideoSharing\"\n            android:label=\"@string/menu_video_sharing\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <data android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.video-share\"/>\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.sharing.video.VideoSharingInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.sharing.video.action.NEW_VIDEO_SHARING\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.video.IncomingVideoSharing\"\n            android:exported=\"true\"\n            android:label=\"@string/menu_video_sharing\"/>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.sharing.video.VideoSharingIntentService\"\n            android:exported=\"false\"/>\n\n        <!-- MM session API -->\n\n        <activity android:name=\"com.gsma.rcs.ri.extension.TestMultimediaSessionApi\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.messaging.InitiateMessagingSession\"\n            android:label=\"@string/menu_initiate_messaging_session\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <data android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.extensions\"/>\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.messaging.MessagingSessionView\"\n            android:label=\"@string/title_messaging_session\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.messaging.MessagingSessionList\"\n            android:label=\"@string/menu_messaging_sessions_list\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.streaming.InitiateStreamingSession\"\n            android:label=\"@string/menu_initiate_streaming_session\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.streaming.StreamingSessionView\"\n            android:label=\"@string/title_streaming_session\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.SendInstantMessage\"\n            android:label=\"@string/title_instant_session\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.extension.streaming.StreamingSessionList\"\n            android:label=\"@string/menu_streaming_sessions_list\"/>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.extension.SessionInvitationReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.extension.action.NEW_MESSAGING_SESSION\"/>\n                <data android:mimeType=\"com.gsma.services.rcs/ext.messaging\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.extension.action.NEW_STREAMING_SESSION\"/>\n                <data android:mimeType=\"com.gsma.services.rcs/ext.streaming\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </receiver>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.extension.InstantMessageReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.extension.action.NEW_INSTANT_MESSAGE\"/>\n                <data android:mimeType=\"com.gsma.services.rcs/ext.messaging\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\"com.gsma.rcs.ri.extension.MultiMediaSessionIntentService\"\n            android:exported=\"false\"/>\n\n        <!-- File Upload API -->\n\n        <activity\n            android:name=\"com.gsma.rcs.ri.upload.InitiateFileUpload\"\n            android:label=\"@string/title_initiate_upload\"/>\n\n        <!-- Log API -->\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.TalkList\"\n            android:label=\"@string/title_history_log_messaging\"\n            android:launchMode=\"singleTop\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\"/>\n                <action android:name=\"android.intent.action.SEND_MULTIPLE\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <data android:mimeType=\"application/*\"/>\n                <data android:mimeType=\"audio/*\"/>\n                <data android:mimeType=\"image/*\"/>\n                <data android:mimeType=\"message/*\"/>\n                <data android:mimeType=\"multipart/*\"/>\n                <data android:mimeType=\"text/*\"/>\n                <data android:mimeType=\"video/*\"/>\n            </intent-filter>\n            <intent-filter>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <action android:name=\"com.gsma.services.rcs.action.VIEW_ONE_TO_ONE_CHAT\"/>\n            </intent-filter>\n            <intent-filter>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <action android:name=\"com.gsma.services.rcs.action.VIEW_GROUP_CHAT\"/>\n            </intent-filter>\n            <intent-filter>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n\n                <action android:name=\"com.gsma.services.rcs.action.VIEW_FILE_TRANSFER\"/>\n            </intent-filter>\n\n        </activity>\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.geoloc.GeolocSharingLogView\"\n            android:label=\"@string/title_sharing_log_item\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.image.ImageSharingLogView\"\n            android:label=\"@string/title_sharing_log_item\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.video.VideoSharingLogView\"\n            android:label=\"@string/title_sharing_log_item\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.FileTransferLogView\"\n            android:label=\"@string/title_sharing_log_item\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.chat.ChatMessageLogView\"\n            android:label=\"@string/title_sharing_log_item\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.AudioMessageRecordActivity\"\n            android:label=\"@string/menu_transfer_file\"/>\n        <activity\n            android:name=\"com.gsma.rcs.ri.sharing.SharingListView\"\n            android:label=\"@string/title_sharing_log\"/>\n\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.chat.single.UndeliveredMessageReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.chat.action.MESSAGE_DELIVERY_EXPIRED\"/>\n            </intent-filter>\n        </receiver>\n        <receiver\n            android:name=\"com.gsma.rcs.ri.messaging.filetransfer.UndeliveredFileReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.filetransfer.action.FILE_TRANSFER_DELIVERY_EXPIRED\"/>\n            </intent-filter>\n        </receiver>\n\n        <activity\n            android:name=\".permissions.PermissionsActivity\"\n            android:label=\"@string/app_name\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "RI/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "RI/README.md",
    "content": "# The Reference Implementation\n\nThis application shows how to use the RCSJTA api.<br>\nIt gives examples of use cases for a RCSJTA client application.\n\nBuild instruction:\n\n<code>../gradlew :RI:build</code>\n\n**Additional steps for Eclipse compatibility:**\n\n<code>ant libs</code>\n\nThis will create the following jar files under the \"libs\" folder:\n- api.jar\n- rcs_media.jar\n- api_cnx.jar\n\nDownload the [android-support-v4.jar](https://developer.android.com/tools/support-library/setup.html) library and copy under the \"libs\" folder.\n\nSet up the [google play service library](https://developers.google.com/android/guides/setup).\n\nSet up the api connection library by importing the Android project '../libs/api_cnx/build/intermediates/bundles/debug/'\n"
  },
  {
    "path": "RI/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n\t\tdisable 'IconLocation'\n        disable 'IconDuplicates'\n\t\tdisable 'IconDuplicatesConfig'\n\t\tdisable 'IconColors'\n\t\tdisable 'IconMissingDensityFolder'\n\t\tdisable 'IconDensities'\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.gsma.rcs.ri\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 2\n        versionName \"2.0\"\n        archivesBaseName = \"RI\"\n    }\n}\n\ndependencies {\n    compile project(':api')\n    compile project(':api_cnx')\n    compile project(':mediaplayer')\n    compile 'com.android.support:support-v4:25.0.1'\n\tcompile 'com.google.android.gms:play-services:8.4.0'\n}\n\n//Below install dependecy was added to always install RCS service before\n//a RCS client to secure that Android handles RCS permissions correctly.\ntask installServiceFirst(dependsOn: ':core:installDebug') << {\n    println 'RCS core service was installed first!'\n}\ntasks.whenTaskAdded { task ->\n    if (task.name == 'installDebug') {\n        task.dependsOn installServiceFirst\n    }\n}\n"
  },
  {
    "path": "RI/build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"RI\" default=\"help\">\n\n\t<!-- This script to populate ./libs folder with generated jar files for building compatibility with Eclipse.\n\tThis script must be executed after dependent libraries have been generated by gradle.\n\tThis script must be removed after migration to Android Studio.\n\t-->\n\t<property name=\"terminal.root\" value=\".\" />\n\t<property name=\"terminal.lib_dst\" value=\"${terminal.root}/libs\" />\n\t<property name=\"terminal.lib_src2\" value=\"${terminal.root}/../libs/api/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.lib_src3\" value=\"${terminal.root}/../libs/api_cnx/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.lib_src1\" value=\"${terminal.root}/../mediaplayer/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.target2\" value=\"api.jar\" />\n\t<property name=\"terminal.target3\" value=\"api_cnx.jar\" />\n\t<property name=\"terminal.target1\" value=\"rcs_media.jar\" />\n\n\t<target name=\"libs\">\n\t\t<echo>Copy ${terminal.target1} file</echo>\n\t\t<copy file=\"${terminal.lib_src1}\" tofile=\"${terminal.lib_dst}/${terminal.target1}\" />\n\t\t<echo>Copy ${terminal.target2} file</echo>\n\t\t<copy file=\"${terminal.lib_src2}\" tofile=\"${terminal.lib_dst}/${terminal.target2}\"/>\n\t\t<echo>Copy ${terminal.target3} file</echo>\n\t\t<copy file=\"${terminal.lib_src3}\" tofile=\"${terminal.lib_dst}/${terminal.target3}\"/>\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<echo>Delete library files</echo>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target1}\"/>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target2}\"/>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target3}\"/>\n\t</target>\n\n\t<target name=\"all\" depends=\"clean,libs\" />\n\n\t<target name=\"help\">\n\t\t<echo>Library Ant Build. Available targets:</echo>\n\t\t<echo> help: Displays this help.</echo>\n\t\t<echo> clean: Removes output files created by other targets.</echo>\n\t\t<echo> libs: Generate input libraries.</echo>\n\t\t<echo> all: Deletes then copy input libraries.</echo>\n\t</target>\n\n</project>\n"
  },
  {
    "path": "RI/default.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n# \n# This file must be checked in Version Control Systems.\n# \n# To customize properties used by the Ant build system use,\n# \"build.properties\", and override values to adapt the script to your\n# project structure.\n\n# Indicates whether an apk should be generated for each density.\nsplit.density=false\n# Project target.\ntarget=Google Inc.:Google APIs:10\n"
  },
  {
    "path": "RI/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "RI/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system use,\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n\n# Indicates whether an apk should be generated for each density.\nsplit.density=false\n# Project target.\ntarget=Google Inc.:Google APIs:22\nandroid.library.reference.1=../../../../../adt-bundle-windows-x86_64/sdk/extras/google/google_play_services/libproject/google-play-services_lib\n"
  },
  {
    "path": "RI/res/drawable/counter_circle.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n    <solid android:color=\"#FFA500\" />\n\n    <padding\n        android:bottom=\"2dip\"\n        android:left=\"5dip\"\n        android:right=\"5dip\"\n        android:top=\"2dip\" />\n</shape>"
  },
  {
    "path": "RI/res/drawable/talk_item_rcs_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*******************************************************************************\n  ~  * Software Name : RCS IMS Stack\n  ~  *\n  ~  * Copyright (C) 2010 France Telecom S.A.\n  ~  *\n  ~  * Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  * you may not use this file except in compliance with the License.\n  ~  * You may obtain a copy of the License at\n  ~  *\n  ~  *      http://www.apache.org/licenses/LICENSE-2.0\n  ~  *\n  ~  * Unless required by applicable law or agreed to in writing, software\n  ~  * distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  * See the License for the specific language governing permissions and\n  ~  * limitations under the License.\n  ~  ******************************************************************************/\n  -->\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"#FAE2A1\" />\n    <stroke\n        android:width=\"3dip\"\n        android:color=\"#FAE2A1\" />\n    <corners android:radius=\"10dip\" />\n    <padding\n        android:bottom=\"0dip\"\n        android:left=\"0dip\"\n        android:right=\"0dip\"\n        android:top=\"0dip\" />\n</shape>"
  },
  {
    "path": "RI/res/drawable/talk_item_rcs_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*******************************************************************************\n  ~  * Software Name : RCS IMS Stack\n  ~  *\n  ~  * Copyright (C) 2010 France Telecom S.A.\n  ~  *\n  ~  * Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  * you may not use this file except in compliance with the License.\n  ~  * You may obtain a copy of the License at\n  ~  *\n  ~  *      http://www.apache.org/licenses/LICENSE-2.0\n  ~  *\n  ~  * Unless required by applicable law or agreed to in writing, software\n  ~  * distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  * See the License for the specific language governing permissions and\n  ~  * limitations under the License.\n  ~  ******************************************************************************/\n  -->\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"#F8F66E\" />\n    <stroke\n        android:width=\"3dip\"\n        android:color=\"#F8F66E\" />\n    <corners android:radius=\"10dip\" />\n    <padding\n        android:bottom=\"0dip\"\n        android:left=\"0dip\"\n        android:right=\"0dip\"\n        android:top=\"0dip\" />\n</shape>"
  },
  {
    "path": "RI/res/layout/app_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\" >\n\n    <ImageView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"10dp\"\n        android:layout_marginTop=\"10dp\"\n        android:src=\"@drawable/rcs_icon\" >\n    </ImageView>\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:text=\"@string/label_about_title\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\"\n        android:textStyle=\"bold\" />\n\n    <TextView\n        android:id=\"@+id/app_version\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <TextView\n        android:id=\"@+id/gsma_version\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/ask_permissions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"fill_parent\"\n              android:layout_height=\"fill_parent\"\n              android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:text=\"@string/label_ungranted_permission\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:textStyle=\"bold\"/>\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"/>\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/audio_msg_record.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:stretchColumns=\"1\">\n\n        <TableRow android:paddingTop=\"5dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:gravity=\"end\"\n                android:text=\"@string/label_audio_record\" />\n\n            <TextView\n                android:id=\"@+id/uri\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:singleLine=\"true\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow android:paddingTop=\"5dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:gravity=\"end\"\n                android:text=\"@string/label_size\" />\n\n            <TextView\n                android:id=\"@+id/size\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:singleLine=\"true\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow android:paddingTop=\"5dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:gravity=\"end\"\n                android:text=\"@string/label_duration\" />\n\n            <TextView\n                android:id=\"@+id/duration\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:singleLine=\"true\"\n                android:textStyle=\"bold\" />\n\n        </TableRow>\n\n        <Button\n            android:id=\"@+id/buttonRecord\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/label_start_record\" />\n\n        <Button\n            android:id=\"@+id/buttonStop\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/label_stop_record\" />\n\n        <Button\n            android:id=\"@+id/buttonPlay\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/label_play_record\" />\n\n    </TableLayout>\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/capabilities_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:listSelector=\"@android:drawable/list_selector_background\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n\n    <TextView\n        android:id=\"@android:id/empty\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:gravity=\"center\"\n        android:text=\"@string/label_capabilities_empty\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/capabilities_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingEnd=\"12dip\"\n                android:paddingRight=\"12dip\"\n                android:paddingStart=\"12dip\">\n\n    <View\n        android:id=\"@+id/divider\"\n        android:layout_width=\"1dip\"\n        android:layout_height=\"fill_parent\"\n        android:layout_marginEnd=\"11dip\"\n        android:layout_marginRight=\"11dip\"/>\n\n    <TextView\n        android:id=\"@+id/number\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"5dip\"\n        android:singleLine=\"true\"\n        android:textStyle=\"bold\"/>\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/number\"\n        android:paddingTop=\"5dip\"\n        android:stretchColumns=\"1\">\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_capabilities\"/>\n\n            <CheckBox\n                android:id=\"@+id/image_sharing\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_image\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView android:gravity=\"end\"/>\n\n            <CheckBox\n                android:id=\"@+id/video_sharing\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_video\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView android:gravity=\"end\"/>\n\n            <CheckBox\n                android:id=\"@+id/file_transfer\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_ft\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView android:gravity=\"end\"/>\n\n            <CheckBox\n                android:id=\"@+id/im\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_im\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView android:gravity=\"end\"/>\n\n            <CheckBox\n                android:id=\"@+id/geoloc_push\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_geolocation_push\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_capabilities_extensions\"/>\n\n            <TextView\n                android:id=\"@+id/extensions\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_automata\"/>\n\n            <CheckBox\n                android:id=\"@+id/automata\"\n                android:clickable=\"false\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_capabilities_timestamp\"/>\n\n            <TextView\n                android:id=\"@+id/last_refresh\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n    </TableLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "RI/res/layout/capabilities_mine.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:stretchColumns=\"1\">\n\n        <TableRow android:paddingTop=\"5dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_capabilities\" />\n\n            <CheckBox\n                android:id=\"@+id/image_sharing\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_image\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/video_sharing\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_video\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/file_transfer\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_ft\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/im\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_im\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/geoloc_push\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_geolocation_push\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_capabilities_extensions\" />\n\n            <TextView\n                android:id=\"@+id/extensions\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_automata\" />\n\n            <CheckBox\n                android:id=\"@+id/automata\"\n                android:clickable=\"false\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/capabilities_refresh.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"10dip\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:text=\"@string/label_refresh_all_capabilities\" />\n\n    <Button\n        android:id=\"@+id/refresh_btn\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:text=\"@string/label_refresh\" />\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/capabilities_request.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:stretchColumns=\"1\">\n\n        <Spinner\n            android:id=\"@+id/contact\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <Button\n            android:id=\"@+id/refresh_btn\"\n            android:text=\"@string/label_refresh\" />\n\n        <TableRow android:paddingTop=\"5dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_capabilities\" />\n\n            <CheckBox\n                android:id=\"@+id/image_sharing\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_image\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/video_sharing\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_video\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/file_transfer\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_ft\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/im\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_im\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\" />\n\n            <CheckBox\n                android:id=\"@+id/geoloc_push\"\n                android:clickable=\"false\"\n                android:text=\"@string/label_capabilities_geolocation_push\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_capabilities_extensions\" />\n\n            <TextView\n                android:id=\"@+id/extensions\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_automata\" />\n\n            <CheckBox\n                android:id=\"@+id/automata\"\n                android:clickable=\"false\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_capabilities_timestamp\" />\n\n            <TextView\n                android:id=\"@+id/last_refresh\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/chat_initiate_group.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <Button\n        android:id=\"@+id/invite_btn\"\n        android:text=\"@string/label_invite\" />\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_subject\" />\n\n        <EditText\n            android:id=\"@+id/subject\"\n            android:inputType=\"text\"\n            android:maxLength=\"50\"\n            android:singleLine=\"true\" />\n    </TableRow>\n\n    <TextView\n        android:padding=\"2dip\"\n        android:text=\"@string/label_contacts\" />\n\n    <ListView\n        android:id=\"@+id/contacts\"\n        android:layout_width=\"fill_parent\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\"\n        android:paddingTop=\"5dip\" />\n\n</TableLayout>"
  },
  {
    "path": "RI/res/layout/chat_initiate_single.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:orientation=\"vertical\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\">\n\n    <Spinner\n        android:id=\"@+id/contact\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\" />\n\n    <Button\n        android:id=\"@+id/invite_btn\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_invite\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/chat_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:listSelector=\"@android:drawable/list_selector_background\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n\n    <TextView\n        android:id=\"@android:id/empty\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:gravity=\"center\"\n        android:text=\"@string/label_chat_empty\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/chat_message_log_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:fillViewport=\"true\">\n\n    <TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                 android:layout_width=\"fill_parent\"\n                 android:layout_height=\"wrap_content\"\n                 android:layout_margin=\"5dp\">\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_id\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_id\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_chat_id\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_chat_id\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_contact\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_contact\"\n                android:text=\"@string/contact_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_state\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_state\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_reason\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_reason\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_dir\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_direction\"\n                android:text=\"@string/direction_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_sent\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_sent\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_delivered\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_delivered\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_displayed\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_displayed\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_read_status\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_read_status\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_expired_delivery\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_expired_delivery\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_mime\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_mime\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_content\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_content\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n    </TableLayout>\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/chat_send_file.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"5dip\"\n        android:stretchColumns=\"1\">\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <CheckBox\n                android:id=\"@+id/ft_thumb\"\n                android:enabled=\"true\"\n                android:text=\"@string/label_ft_thumb\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_file\"/>\n\n            <TextView\n                android:id=\"@+id/uri\"\n                android:singleLine=\"true\"\n                android:text=\"@string/text_dummy\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_size\"/>\n\n            <TextView\n                android:id=\"@+id/size\"\n                android:singleLine=\"true\"\n                android:text=\"@string/number_dummy\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_progress_status\"/>\n\n            <TextView\n                android:id=\"@+id/progress_status\"\n                android:singleLine=\"true\"\n                android:text=\"@string/text_dummy\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_progress_bar\"/>\n\n            <ProgressBar\n                android:id=\"@+id/progress_bar\"\n                style=\"@android:style/Widget.ProgressBar.Horizontal\"\n                android:layout_marginEnd=\"5dip\"\n                android:layout_marginRight=\"5dip\"/>\n        </TableRow>\n\n        <CheckBox\n            android:id=\"@+id/send_audio_msg\"\n            android:enabled=\"true\"\n            android:text=\"@string/label_send_audio_msg\"/>\n\n        <Button\n            android:id=\"@+id/select_btn\"\n            android:text=\"@string/label_select_file\"/>\n\n        <Button\n            android:id=\"@+id/invite_btn\"\n            android:text=\"@string/label_initiate_sharing\"/>\n\n        <Button\n            android:id=\"@+id/pause_btn\"\n            android:text=\"@string/label_pause_transfer\"/>\n\n        <Button\n            android:id=\"@+id/resume_btn\"\n            android:text=\"@string/label_resume_transfer\"/>\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/chat_service_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"5dip\"\n        android:stretchColumns=\"1\">\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_WarnSF\" />\n\n            <CheckBox\n                android:id=\"@+id/WarnSF\"\n                android:clickable=\"false\"\n                android:enabled=\"false\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_IsComposingTimeout\" />\n\n            <TextView android:id=\"@+id/IsComposingTimeout\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_GroupChatSupported\" />\n\n            <CheckBox\n                android:id=\"@+id/GroupChatSupported\"\n                android:clickable=\"false\"\n                android:enabled=\"false\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_MinGroupChatParticipants\" />\n\n            <TextView android:id=\"@+id/MinGroupChatParticipants\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_MaxGroupChatParticipants\" />\n\n            <TextView android:id=\"@+id/MaxGroupChatParticipants\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_MaxMsgLengthGroupChat\" />\n\n            <TextView android:id=\"@+id/MaxMsgLengthGroupChat\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_GroupChatSubjectMaxLength\" />\n\n            <TextView android:id=\"@+id/GroupChatSubjectMaxLength\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_MaxMsgLengthOneToOneChat\" />\n\n            <TextView android:id=\"@+id/MaxMsgLengthOneToOneChat\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_SmsFallback\" />\n\n            <CheckBox\n                android:id=\"@+id/SmsFallback\"\n                android:clickable=\"false\"\n                android:enabled=\"false\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_RespondToDisplayReports\" />\n\n            <CheckBox android:id=\"@+id/RespondToDisplayReports\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_MaxGeolocLabelLength\" />\n\n            <TextView android:id=\"@+id/MaxGeolocLabelLength\" />\n        </TableRow>\n\n        <TableRow android:padding=\"2dip\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_GeolocExpireTime\" />\n\n            <TextView android:id=\"@+id/GeolocExpireTime\" />\n        </TableRow>\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/chat_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:divider=\"#FFFFFF\"\n        android:dividerHeight=\"1dp\"\n        android:fadeScrollbars=\"true\"\n        android:paddingBottom=\"6dip\"\n        android:paddingLeft=\"5dp\"\n        android:paddingRight=\"5dp\"\n        android:paddingTop=\"5dp\"\n        android:scrollbarStyle=\"outsideOverlay\"\n        android:stackFromBottom=\"true\"\n        android:transcriptMode=\"normal\" />\n\n    <ScrollView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/isComposingText\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:visibility=\"gone\" />\n\n            <RelativeLayout\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:paddingLeft=\"5dp\"\n                android:paddingRight=\"5dp\"\n                android:paddingTop=\"5dp\">\n\n                <EditText\n                    android:id=\"@+id/userText\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_alignBottom=\"@+id/send_button\"\n                    android:layout_alignParentLeft=\"true\"\n                    android:layout_alignParentStart=\"true\"\n                    android:layout_alignTop=\"@+id/send_button\"\n                    android:layout_toLeftOf=\"@+id/send_button\"\n                    android:layout_toStartOf=\"@+id/send_button\"\n                    android:inputType=\"text\"\n                    android:textSize=\"14sp\" />\n\n                <Button\n                    android:id=\"@+id/send_button\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"50dp\"\n                    android:layout_alignParentEnd=\"true\"\n                    android:layout_alignParentRight=\"true\"\n                    android:text=\"@string/label_chat_send\" />\n            </RelativeLayout>\n        </LinearLayout>\n    </ScrollView>\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/contact_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\">\n\n    <include\n        android:id=\"@+id/capabilities\"\n        layout=\"@layout/capabilities_list_item\"/>\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/capabilities\"\n        android:paddingTop=\"5dip\"\n        android:stretchColumns=\"1\">\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_is_online\"/>\n\n            <CheckBox\n                android:id=\"@+id/is_online\"\n                android:clickable=\"false\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_is_blocked\"/>\n\n            <CheckBox\n                android:id=\"@+id/is_blocked\"\n                android:clickable=\"false\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n        <TableRow>\n\n            <TextView\n                android:gravity=\"end\"\n                android:text=\"@string/label_block_timestamp\"/>\n\n            <TextView\n                android:id=\"@+id/block_timestamp\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:textAppearance=\"?android:attr/textAppearanceSmall\"/>\n        </TableRow>\n\n    </TableLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "RI/res/layout/contacts_blocking.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\" >\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:stretchColumns=\"1\" >\n\n        <Spinner\n            android:id=\"@+id/contact\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <ToggleButton\n            android:id=\"@+id/block_btn\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:textOff=\"@string/label_block\"\n            android:textOn=\"@string/label_unblock\" />\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/contacts_rcs_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:listSelector=\"@android:drawable/list_selector_background\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n\n    <TextView\n        android:id=\"@android:id/empty\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:gravity=\"center\"\n        android:text=\"@string/label_log_empty\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/contacts_vcard.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingTop=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <Spinner\n        android:id=\"@+id/contact\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\" />\n\n    <TableRow android:paddingTop=\"5dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginStart=\"5dip\"\n            android:text=\"@string/label_vcard\" />\n\n        <TextView\n            android:id=\"@+id/vcard\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n    <Button\n        android:id=\"@+id/show_btn\"\n        android:text=\"@string/label_show_vcard\" />\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/delivery_info_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:textAppearance=\"?android:attr/textAppearanceSmall\" >\n\n    <TextView\n        android:id=\"@+id/contact\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:textColor=\"@android:color/darker_gray\" />\n\n    <TextView\n        android:id=\"@+id/deliver\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_below=\"@id/contact\" />\n\n    <TextView\n        android:id=\"@+id/display\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_below=\"@id/deliver\" />\n\n    <TextView\n        android:id=\"@+id/status\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_below=\"@id/display\" />\n\n    <TextView\n        android:id=\"@+id/reason\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_below=\"@id/status\" />\n\n</RelativeLayout>"
  },
  {
    "path": "RI/res/layout/delivery_info_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:listSelector=\"@android:drawable/list_selector_background\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/extension_initiate_session.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\" >\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:shrinkColumns=\"1\"\n        android:stretchColumns=\"1\" >\n\n        <Spinner\n            android:id=\"@+id/contact\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <Button\n            android:id=\"@+id/initiate_btn\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_initiate_session\" />\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/extension_messaging_session_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\" >\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:shrinkColumns=\"1\"\n        android:stretchColumns=\"1\"\n        android:layout_margin=\"5dip\">\n\n        <TableRow\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_remote\" />\n\n            <TextView\n                android:id=\"@+id/contact\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow android:paddingTop=\"5dip\" >\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_service_id\" />\n\n            <TextView\n                android:id=\"@+id/feature_tag\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow android:paddingTop=\"5dip\" >\n\n            <Button\n                android:id=\"@+id/send_btn\"\n                android:text=\"@string/label_send_data\" />\n        </TableRow>\n\n        <TableRow android:paddingTop=\"5dip\" >\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginStart=\"5dip\"\n                android:text=\"@string/label_recv_data\" />\n\n            <TextView\n                android:id=\"@+id/recv_data\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/extension_send_instant_message.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\" >\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:shrinkColumns=\"1\"\n        android:stretchColumns=\"1\" >\n\n        <Spinner\n            android:id=\"@+id/contact\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <Button\n            android:id=\"@+id/send_btn\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_send_message\" />\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/extension_session_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:listSelector=\"@android:drawable/list_selector_background\"\n        android:scrollbarStyle=\"outsideOverlay\" />\n\n    <TextView\n        android:id=\"@android:id/empty\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\"\n        android:gravity=\"center\"\n        android:text=\"@string/label_no_session\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/extension_streaming_session_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\">\n\n    <TableLayout\n        android:id=\"@+id/table\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentTop=\"true\">\n\n        <TableRow\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"5dip\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/label_remote\" />\n\n            <TextView\n                android:id=\"@+id/contact\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/contact_dummy\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"5dip\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/label_service_id\" />\n\n            <TextView\n                android:id=\"@+id/feature_tag\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/extension_dummy\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n    </TableLayout>\n\n    <Button\n        android:id=\"@+id/start_stop_btn\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:layout_margin=\"5dip\"\n        android:text=\"@string/label_start\" />\n\n    <TableLayout\n        android:id=\"@+id/table_counter\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/start_stop_btn\"\n        android:layout_centerInParent=\"true\">\n\n        <TableRow\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"5dip\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/label_rx_count\" />\n\n            <TextView\n                android:id=\"@+id/rx_data\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/number_dummy\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"5dip\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/label_tx_count\" />\n\n            <TextView\n                android:id=\"@+id/tx_data\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"5dip\"\n                android:text=\"@string/number_dummy\"\n                android:textStyle=\"bold\" />\n        </TableRow>\n\n    </TableLayout>\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_centerInParent=\"true\"\n        android:gravity=\"center\"\n        android:padding=\"5dip\"\n        android:text=\"@string/label_streaming_info\" />\n\n</RelativeLayout>"
  },
  {
    "path": "RI/res/layout/filetransfer_custom_title.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"35dip\"\n    android:background=\"#323331\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:padding=\"10dp\">\n\n    <ImageView\n        android:id=\"@+id/filetransfer_alert_title_icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:paddingEnd=\"10dp\"\n        android:paddingRight=\"10dp\" />\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/title_file_transfer\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/filetransfer_initiate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"5dip\"\n        android:stretchColumns=\"1\">\n\n        <Spinner\n            android:id=\"@+id/contact\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"/>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <CheckBox\n                android:id=\"@+id/ft_thumb\"\n                android:enabled=\"false\"\n                android:text=\"@string/label_ft_thumb\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView android:text=\"@string/label_file\"/>\n\n            <TextView\n                android:id=\"@+id/uri\"\n                android:singleLine=\"true\"\n                android:text=\"@string/text_dummy\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView android:text=\"@string/label_size\"/>\n\n            <TextView\n                android:id=\"@+id/size\"\n                android:singleLine=\"true\"\n                android:text=\"@string/number_dummy\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView android:text=\"@string/label_progress_status\"/>\n\n            <TextView\n                android:id=\"@+id/progress_status\"\n                android:singleLine=\"true\"\n                android:text=\"@string/text_dummy\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dip\">\n\n            <TextView android:text=\"@string/label_progress_bar\"/>\n\n            <ProgressBar\n                android:id=\"@+id/progress_bar\"\n                style=\"@android:style/Widget.ProgressBar.Horizontal\"\n                android:layout_marginEnd=\"5dip\"\n                android:layout_marginRight=\"5dip\"/>\n        </TableRow>\n\n        <TableRow\n            android:id=\"@+id/expiration\"\n            android:layout_margin=\"2dip\">\n\n            <TextView android:text=\"@string/label_expiration\"/>\n\n            <TextView\n                android:id=\"@+id/value_expiration\"\n                android:singleLine=\"true\"\n                android:textStyle=\"bold\"/>\n        </TableRow>\n\n        <CheckBox\n            android:id=\"@+id/send_audio_msg\"\n            android:enabled=\"false\"\n            android:text=\"@string/label_send_audio_msg\"/>\n\n        <Button\n            android:id=\"@+id/select_btn\"\n            android:text=\"@string/label_select_file\"/>\n\n        <Button\n            android:id=\"@+id/invite_btn\"\n            android:text=\"@string/label_initiate_sharing\"/>\n\n        <Button\n            android:id=\"@+id/pause_btn\"\n            android:text=\"@string/label_pause_transfer\"/>\n\n        <Button\n            android:id=\"@+id/resume_btn\"\n            android:text=\"@string/label_resume_transfer\"/>\n    </TableLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/filetransfer_log_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:fillViewport=\"true\">\n\n    <TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                 android:layout_width=\"fill_parent\"\n                 android:layout_height=\"wrap_content\"\n                 android:layout_margin=\"5dp\">\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_id\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_id\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_chat_id\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_chat_id\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_contact\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_contact\"\n                android:text=\"@string/contact_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_state\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_state\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_reason\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_reason\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_dir\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_direction\"\n                android:text=\"@string/direction_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_disposition\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_disposition\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_sent\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_sent\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_delivered\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_delivered\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_displayed\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_displayed\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_read_status\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_read_status\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_expired_delivery\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_expired_delivery\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_filename\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_filename\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_file_size\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_size\"\n                android:text=\"@string/number_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_transferred\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_transferred\"\n                android:text=\"@string/number_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_mime\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_mime\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_file_expiration\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_file_expiration\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_file_uri\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_uri\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_icon_mime\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_icon_mime\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_date_icon_expiration\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_date_icon_expiration\"\n                android:text=\"@string/timestamp_dummy\"/>\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginEnd=\"10dp\"\n                android:layout_marginRight=\"10dp\"\n                android:text=\"@string/label_log_icon_uri\"/>\n\n            <TextView\n                android:id=\"@+id/history_log_item_icon\"\n                android:text=\"@string/text_dummy\"/>\n        </TableRow>\n\n    </TableLayout>\n</ScrollView>\n"
  },
  {
    "path": "RI/res/layout/filetransfer_receive.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:fillViewport=\"false\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/from\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <TextView\n            android:id=\"@+id/image_filename\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <TextView\n            android:id=\"@+id/image_size\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <TextView\n            android:id=\"@+id/expiration\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_progress_status\" />\n\n            <TextView\n                android:id=\"@+id/progress_status\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"5dip\"\n                android:text=\"@string/label_progress_bar\" />\n\n            <ProgressBar\n                android:id=\"@+id/progress_bar\"\n                style=\"@android:style/Widget.ProgressBar.Horizontal\"\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"5dip\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <Button\n                android:id=\"@+id/pause_btn\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:text=\"@string/label_pause_transfer\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <Button\n                android:id=\"@+id/resume_btn\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/label_resume_transfer\" />\n        </LinearLayout>\n    </LinearLayout>\n\n</ScrollView>"
  },
  {
    "path": "RI/res/layout/filetransfer_send_multi_file.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n       <Button\n           android:id=\"@+id/ft_start_btn\"\n           android:layout_width=\"fill_parent\"\n           android:layout_height=\"wrap_content\"\n           android:layout_marginLeft=\"5dip\"\n           android:layout_marginRight=\"5dip\"\n           android:text=\"@string/label_ft_start_file_transfer\"\n           android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n       <ListView\n           android:id=\"@android:id/list\"\n           android:layout_width=\"fill_parent\"\n           android:layout_height=\"wrap_content\"\n           android:listSelector=\"@android:drawable/list_selector_background\"\n           android:scrollbarStyle=\"outsideOverlay\" >\n       </ListView>\n        \n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/filetransfer_send_multi_file_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"5dip\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:padding=\"2dip\">\n\n        <CheckBox\n            android:id=\"@+id/ft_thumb\"\n            android:enabled=\"true\"\n            android:text=\"@string/label_ft_thumb\" />\n    </TableRow>\n\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_file\" />\n\n        <TextView\n            android:id=\"@+id/uri\"\n            android:singleLine=\"true\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_ft_filesize\" />\n\n        <TextView\n            android:id=\"@+id/filesize\"\n            android:singleLine=\"true\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_progress_status\" />\n\n        <TextView\n            android:id=\"@+id/progress_status\"\n            android:singleLine=\"true\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_progress_bar\" />\n\n        <ProgressBar\n            android:id=\"@+id/progress_bar\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n    </TableRow>\n\n    <TableRow\n        android:id=\"@+id/row_reason_code\"\n        android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_reason_code\" />\n\n        <TextView\n            android:id=\"@+id/text_reason_code\"\n            android:singleLine=\"true\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n\n    <TableRow android:padding=\"2dip\">\n\n        <CheckBox\n            android:id=\"@+id/send_audio_msg\"\n            android:enabled=\"false\"\n            android:text=\"@string/label_send_audio_msg\" />\n    </TableRow>\n\n</TableLayout>"
  },
  {
    "path": "RI/res/layout/filetransfer_service_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n             android:layout_width=\"fill_parent\"\n             android:layout_height=\"wrap_content\"\n             android:padding=\"5dip\"\n             android:stretchColumns=\"1\">\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_ft_WarnSize\"/>\n\n        <TextView\n            android:id=\"@+id/ft_WarnSize\"\n            android:text=\"@string/number_dummy\"/>\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_ft_MaxSize\"/>\n\n        <TextView\n            android:id=\"@+id/ft_MaxSize\"\n            android:text=\"@string/number_dummy\"/>\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_MaxFileTransfers\"/>\n\n        <TextView\n            android:id=\"@+id/MaxFileTransfers\"\n            android:text=\"@string/number_dummy\"/>\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_max_audio_duration\"/>\n\n        <TextView\n            android:id=\"@+id/MaxAudioDuration\"\n            android:text=\"@string/number_dummy\"/>\n    </TableRow>\n\n    <TableRow\n        android:id=\"@+id/isAutoAccept\"\n        android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_ft_isAutoAccept\"/>\n\n        <CheckBox android:id=\"@+id/ft_isAutoAccept\"/>\n    </TableRow>\n\n    <TableRow\n        android:id=\"@+id/isAutoAcceptInRoaming\"\n        android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_ft_isAutoAcceptInRoaming\"/>\n\n        <CheckBox android:id=\"@+id/ft_isAutoAcceptInRoaming\"/>\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_GroupFileTransferSupported\"/>\n\n        <CheckBox\n            android:id=\"@+id/GroupFileTransferSupported\"\n            android:clickable=\"false\"\n            android:enabled=\"false\"/>\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_ft_ImageResizeOption\"/>\n\n        <Spinner android:id=\"@+id/ft_ImageResizeOption\"/>\n    </TableRow>\n\n</TableLayout>"
  },
  {
    "path": "RI/res/layout/fileupload_initiate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"5dip\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:padding=\"2dip\">\n\n        <CheckBox\n            android:id=\"@+id/file_thumb\"\n            android:text=\"@string/label_file_thumb\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_file\" />\n\n        <TextView\n            android:id=\"@+id/uri\"\n            android:singleLine=\"true\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_progress_status\" />\n\n        <TextView\n            android:id=\"@+id/progress_status\"\n            android:singleLine=\"true\"\n            android:textStyle=\"bold\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView android:text=\"@string/label_progress_bar\" />\n\n        <ProgressBar\n            android:id=\"@+id/progress_bar\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n    </TableRow>\n\n    <Button\n        android:id=\"@+id/select_btn\"\n        android:text=\"@string/label_select_file\" />\n\n    <Button\n        android:id=\"@+id/upload_btn\"\n        android:text=\"@string/label_upload\" />\n\n    <Button\n        android:id=\"@+id/show_btn\"\n        android:text=\"@string/label_show_upload\" />\n\n    <Button\n        android:id=\"@+id/show_icon_btn\"\n        android:text=\"@string/label_show_icon_upload\" />\n</TableLayout>"
  },
  {
    "path": "RI/res/layout/gchat_item_rcs_chat_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"2dp\">\n\n    <RelativeLayout\n        android:id=\"@+id/conv_item_chat_text_in\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:background=\"@drawable/msg_item_left\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/content_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignLeft=\"@+id/contact_text\"\n            android:layout_alignStart=\"@+id/contact_text\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\" />\n\n        <TextView\n            android:id=\"@+id/contact_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/content_text\"\n            android:singleLine=\"true\"\n            android:text=\"@string/contact_dummy\" />\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:layout_marginLeft=\"12dip\"\n        android:layout_marginStart=\"12dip\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\" />\n\n    <TextView\n        android:id=\"@+id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:layout_marginLeft=\"12dip\"\n        android:layout_marginStart=\"12dip\"\n        android:singleLine=\"true\"\n        android:text=\"@string/timestamp_dummy\" />\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/gchat_item_rcs_chat_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dp\">\n\n    <RelativeLayout\n        android:id=\"@+id/conv_item_chat_text_out\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:background=\"@drawable/msg_item_right\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/content_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:layout_marginEnd=\"12dp\"\n        android:layout_marginRight=\"12dp\"\n        android:drawablePadding=\"5dp\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n\n    <TextView\n        android:id=\"@+id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:layout_marginEnd=\"12dp\"\n        android:layout_marginRight=\"12dp\"\n        android:singleLine=\"true\"\n        android:text=\"@string/timestamp_dummy\"/>\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/gchat_item_rcs_file_transfer_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dp\">\n\n    <LinearLayout\n        android:id=\"@+id/conv_item_file_transfer_in\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:background=\"@drawable/talk_item_rcs_in\"\n        android:orientation=\"vertical\"\n        android:padding=\"5dp\">\n\n        <ImageView\n            android:id=\"@+id/file_image\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:src=\"@drawable/ri_filetransfer_off\"/>\n\n        <TextView\n            android:id=\"@+id/progress_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/contact_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/contact_dummy\"\n            android:textColor=\"@android:color/darker_gray\"/>\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:layout_marginLeft=\"12dip\"\n        android:layout_marginStart=\"12dip\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n\n    <TextView\n        android:id=\"@+id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:layout_marginLeft=\"12dip\"\n        android:layout_marginStart=\"12dip\"\n        android:singleLine=\"true\"\n        android:text=\"@string/timestamp_dummy\"/>\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/gchat_item_rcs_file_transfer_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:orientation=\"vertical\"\n                android:padding=\"2dip\">\n\n    <LinearLayout\n        android:id=\"@+id/conv_item_file_transfer_out\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:background=\"@drawable/talk_item_rcs_out\"\n        android:orientation=\"vertical\"\n        android:padding=\"5dp\">\n\n        <ImageView\n            android:id=\"@+id/file_image\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:src=\"@drawable/ri_filetransfer_off\"/>\n\n        <TextView\n            android:id=\"@+id/progress_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/contact_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/contact_dummy\"\n            android:textColor=\"@android:color/darker_gray\"/>\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:layout_marginRight=\"12dp\"\n        android:layout_marginEnd=\"12dp\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n\n    <TextView\n        android:id=\"@+id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:layout_marginRight=\"12dp\"\n        android:layout_marginEnd=\"12dp\"\n        android:singleLine=\"true\"\n        android:text=\"@string/timestamp_dummy\"/>\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/geoloc_display.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<fragment xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/map\"\n    android:name=\"com.google.android.gms.maps.MapFragment\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    class=\"com.google.android.gms.maps.SupportMapFragment\" />"
  },
  {
    "path": "RI/res/layout/geoloc_edit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <Button\n        android:id=\"@+id/select_geoloc_btn\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_select_geoloc\" />\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_location\" />\n\n    <EditText\n        android:id=\"@+id/location\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"text\"\n        android:lines=\"1\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_gsh_default_label\" />\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_latitude\" />\n\n    <EditText\n        android:id=\"@+id/latitude\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberDecimal|numberSigned\"\n        android:lines=\"1\"\n        android:maxLength=\"8\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_gsh_default_latitude\" />\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"5dip\"\n        android:text=\"@string/label_longitude\" />\n\n    <EditText\n        android:id=\"@+id/longitude\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"numberDecimal|numberSigned\"\n        android:lines=\"1\"\n        android:maxLength=\"8\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_gsh_default_longitude\" />\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_accuracy\" />\n\n    <EditText\n        android:id=\"@+id/accuracy\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"number\"\n        android:lines=\"1\"\n        android:maxLength=\"8\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_gsh_default_accuracy\" />\n\n    <Button\n        android:id=\"@+id/validate_btn\"\n        android:padding=\"2dip\"\n        android:text=\"@string/label_ok\" />\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/geoloc_sharing_initiate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"5dip\"\n    android:stretchColumns=\"1\">\n\n    <Spinner android:id=\"@+id/contact\" />\n\n    <TableRow android:paddingTop=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_position\" />\n\n        <TextView\n            android:id=\"@+id/position\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:paddingTop=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_status\" />\n\n        <TextView\n            android:id=\"@+id/progress_status\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:paddingTop=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_bar\" />\n\n        <ProgressBar\n            android:id=\"@+id/progress_bar\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n    </TableRow>\n\n    <Button\n        android:id=\"@+id/dial_btn\"\n        android:text=\"@string/label_dial\" />\n\n    <Button\n        android:id=\"@+id/select_btn\"\n        android:text=\"@string/label_select_location\" />\n\n    <Button\n        android:id=\"@+id/invite_btn\"\n        android:text=\"@string/label_initiate_sharing\" />\n</TableLayout>"
  },
  {
    "path": "RI/res/layout/geoloc_sharing_receive.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_contact\" />\n\n        <TextView\n            android:id=\"@+id/contact\"\n            android:singleLine=\"true\"\n            android:text=\"@string/contact_dummy\" />\n    </TableRow>\n\n    <TableRow android:paddingTop=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_position\" />\n\n        <TextView\n            android:id=\"@+id/position\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_status\" />\n\n        <TextView\n            android:id=\"@+id/progress_status\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_bar\" />\n\n        <ProgressBar\n            android:id=\"@+id/progress_bar\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/geoloc_show.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\" >\n\n    <Button\n        android:id=\"@+id/display_geoloc_btn\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:text=\"@string/label_display_geoloc\" />\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"10dip\"\n        android:stretchColumns=\"1\" >\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:weightSum=\"1\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"0\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:text=\"@string/label_contact_geoloc\" />\n\n            <TextView\n                android:id=\"@+id/contact\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"1\" />\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:weightSum=\"1\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"0\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:text=\"@string/label_location\" />\n\n            <TextView\n                android:id=\"@+id/location\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"1\"\n                android:text=\"@string/label_gsh_default_label\" />\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:weightSum=\"1\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"0\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:text=\"@string/label_latitude\" />\n\n            <TextView\n                android:id=\"@+id/latitude\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"1\"\n                android:text=\"@string/label_gsh_default_latitude\" />\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:weightSum=\"1\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"0\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:text=\"@string/label_longitude\" />\n\n            <TextView\n                android:id=\"@+id/longitude\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"1\"\n                android:text=\"@string/label_gsh_default_longitude\" />\n        </TableRow>\n\n        <TableRow\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:weightSum=\"1\" >\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"0\"\n                android:paddingLeft=\"10dp\"\n                android:paddingRight=\"10dp\"\n                android:text=\"@string/label_accuracy\" />\n\n            <TextView\n                android:id=\"@+id/accuracy\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_column=\"1\"\n                android:text=\"@string/label_gsh_default_accuracy\" />\n        </TableRow>\n    </TableLayout>\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/groupchat_event_view_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dip\">\n\n    <RelativeLayout\n        android:id=\"@+id/msg_item\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/status_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:singleLine=\"true\"\n            android:text=\"@string/label_state_unknown\"\n            android:textColor=\"@android:color/white\"/>\n\n        <TextView\n            android:id=\"@+id/contact_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/status_text\"\n            android:singleLine=\"true\"\n            android:text=\"@string/contact_dummy\"/>\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:singleLine=\"true\"\n        android:text=\"@string/timestamp_dummy\"/>\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/history_log_sharing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <Spinner\n        android:id=\"@+id/contact\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\" />\n\n    <FrameLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\" >\n\n        <ListView\n            android:id=\"@android:id/list\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:listSelector=\"@android:drawable/list_selector_background\"\n            android:scrollbarStyle=\"outsideOverlay\" />\n\n        <TextView\n            android:id=\"@android:id/empty\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:gravity=\"center\"\n            android:text=\"@string/label_history_log_empty\"\n            android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n    </FrameLayout>\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/image_sharing_initiate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dp\"\n    android:stretchColumns=\"1\">\n\n    <Spinner android:id=\"@+id/contact\" />\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_selected_img\" />\n\n        <TextView\n            android:id=\"@+id/uri\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_selected_size\" />\n\n        <TextView\n            android:id=\"@+id/size\"\n            android:singleLine=\"true\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_status\" />\n\n        <TextView\n            android:id=\"@+id/progress_status\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_bar\" />\n\n        <ProgressBar\n            android:id=\"@+id/progress_bar\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\" />\n    </TableRow>\n\n    <Button\n        android:id=\"@+id/dial_btn\"\n        android:text=\"@string/label_dial\" />\n\n    <Button\n        android:id=\"@+id/select_btn\"\n        android:text=\"@string/label_select_picture\" />\n\n    <Button\n        android:id=\"@+id/invite_btn\"\n        android:text=\"@string/label_initiate_sharing\" />\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/image_sharing_receive.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_contact\" />\n\n        <TextView\n            android:id=\"@+id/contact\"\n            android:singleLine=\"true\"\n            android:text=\"@string/contact_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_selected_size\" />\n\n        <TextView\n            android:id=\"@+id/size\"\n            android:singleLine=\"true\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_status\" />\n\n        <TextView\n            android:id=\"@+id/progress_status\"\n            android:singleLine=\"true\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_progress_bar\" />\n\n        <ProgressBar\n            android:id=\"@+id/progress_bar\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_marginRight=\"5dip\"\n            android:layout_marginEnd=\"5dip\"/>\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/intents_apps.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"5dip\"\n    android:stretchColumns=\"1\">\n\n    <Button\n        android:id=\"@+id/load_chat\"\n        android:text=\"@string/label_load_chat\" />\n\n    <Button\n        android:id=\"@+id/initiate_chat\"\n        android:text=\"@string/label_initiate_chat\" />\n\n    <Button\n        android:id=\"@+id/load_group_chat\"\n        android:text=\"@string/label_load_group_chat\" />\n\n    <Button\n        android:id=\"@+id/initiate_group_chat\"\n        android:text=\"@string/label_initiate_group_chat\" />\n\n    <Button\n        android:id=\"@+id/load_ft\"\n        android:text=\"@string/label_load_ft\" />\n\n    <Button\n        android:id=\"@+id/initiate_ft\"\n        android:text=\"@string/label_initiate_ft\" />\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/ri_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"10dip\" >\n\n    <ListView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"fill_parent\" />\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:id=\"@+id/wait_cnx_start\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center\"\n         >\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"5dip\"\n            android:text=\"@string/label_wait_cnx_start\" />\n\n        <ProgressBar\n            android:id=\"@android:id/progress\"\n            style=\"@android:style/Widget.ProgressBar.Horizontal\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"50dp\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/service_configuration.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_my_contact_id\" />\n\n        <TextView\n            android:id=\"@+id/label_my_contact_id\"\n            android:text=\"@string/contact_dummy\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_service_configuration_valid\" />\n\n        <CheckBox\n            android:id=\"@+id/label_service_configuration_valid\"\n            android:clickable=\"false\"\n            android:enabled=\"false\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_default_messaging_method\" />\n\n        <Spinner android:id=\"@+id/spinner_default_messaging_method\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_messaging_mode\" />\n\n        <TextView android:id=\"@+id/label_messaging_mode\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_my_display_name\" />\n\n        <EditText\n            android:id=\"@+id/text_my_display_name\"\n            android:inputType=\"text\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_min_battery_level\" />\n\n        <Spinner android:id=\"@+id/spinner_label_min_battery_level\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_service_activatation\" />\n\n        <TextView android:id=\"@+id/text_service_activation\" />\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/service_registration.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <TableRow\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_registration_status\" />\n\n        <TextView\n            android:id=\"@+id/registration_status\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/service_status.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_service_bound\" />\n\n        <TextView android:id=\"@+id/service_bound\" />\n    </TableRow>\n\n    <TableRow>\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_service_activated\" />\n\n        <TextView android:id=\"@+id/service_activated\" />\n    </TableRow>\n\n    <TableRow>\n\n        <TextView\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_service_started\" />\n\n        <TextView android:id=\"@+id/service_started\" />\n    </TableRow>\n\n    <Button\n        android:id=\"@+id/service_refresh_all\"\n        android:text=\"@string/label_refresh\" />\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/sharing_log_geoloc_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"5dp\">\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_contact\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_contact\"\n            android:text=\"@string/contact_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_state\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_state\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_reason\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_reason\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_dir\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_direction\"\n            android:text=\"@string/direction_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_date\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_date\"\n            android:text=\"@string/timestamp_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_mime\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_mime\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_content\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_content\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/sharing_log_image_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"5dp\">\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_contact\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_contact\"\n            android:text=\"@string/contact_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_state\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_state\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_reason\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_reason\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_dir\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_direction\"\n            android:text=\"@string/direction_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_date\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_date\"\n            android:text=\"@string/timestamp_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_filename\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_filename\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_file_size\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_size\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_transferred\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_transferred\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_mime\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_mime\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow\n        android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_file_uri\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_uri\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/sharing_log_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"?android:attr/listPreferredItemHeight\"\n    android:padding=\"5dip\">\n\n    <ImageView\n        android:id=\"@+id/call_type_icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_alignParentTop=\"true\"\n        android:src=\"@drawable/ri_incoming_call\" />\n\n    <TextView\n        android:id=\"@+id/date\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:singleLine=\"true\"\n        android:text=\"@string/timestamp_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n\n    <TextView\n        android:id=\"@+id/description\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignLeft=\"@id/date\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignStart=\"@id/date\"\n        android:ellipsize=\"marquee\"\n        android:singleLine=\"true\"\n        android:text=\"@string/text_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textStyle=\"bold\" />\n\n    <TextView\n        android:id=\"@+id/conversation_type\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@id/description\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_alignParentTop=\"true\"\n        android:ellipsize=\"marquee\"\n        android:singleLine=\"true\"\n        android:text=\"@string/text_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n    <TextView\n        android:id=\"@+id/contact_label\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"5dip\"\n        android:layout_marginRight=\"5dip\"\n        android:layout_toLeftOf=\"@id/call_type_icon\"\n        android:layout_toStartOf=\"@id/call_type_icon\"\n        android:ellipsize=\"marquee\"\n        android:singleLine=\"false\"\n        android:text=\"@string/contact_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textStyle=\"bold\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "RI/res/layout/sharing_log_video_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_margin=\"5dp\">\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_contact\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_contact\"\n            android:text=\"@string/contact_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_state\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_state\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_reason\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_reason\"\n            android:text=\"@string/text_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_dir\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_direction\"\n            android:text=\"@string/direction_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_date\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_date\"\n            android:text=\"@string/timestamp_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_duration\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_duration\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_height\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_height\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_width\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_width\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n\n    <TableRow android:layout_margin=\"2dp\">\n\n        <TextView\n            android:layout_marginRight=\"10dp\"\n            android:layout_marginEnd=\"10dp\"\n            android:text=\"@string/label_log_encoding\" />\n\n        <TextView\n            android:id=\"@+id/history_log_item_encoding\"\n            android:text=\"@string/number_dummy\" />\n    </TableRow>\n</TableLayout>\n"
  },
  {
    "path": "RI/res/layout/talk_item_rcs_chat_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dip\">\n\n    <RelativeLayout\n        android:id=\"@+id/conv_item_chat_text_in\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:background=\"@drawable/msg_item_left\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/content_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/timestamp_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/content_text\"\n            android:text=\"@string/timestamp_dummy\"\n            android:textColor=\"@android:color/darker_gray\"/>\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:layout_marginLeft=\"12dip\"\n        android:layout_marginStart=\"12dip\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/talk_item_rcs_chat_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dip\">\n\n    <RelativeLayout\n        android:id=\"@+id/conv_item_chat_text_out\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:background=\"@drawable/msg_item_right\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/content_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/timestamp_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/content_text\"\n            android:text=\"@string/timestamp_dummy\"\n            android:textColor=\"@android:color/darker_gray\"/>\n    </RelativeLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:layout_marginEnd=\"12dp\"\n        android:layout_marginRight=\"12dp\"\n        android:drawablePadding=\"5dp\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/talk_item_rcs_file_transfer_in.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dip\">\n\n    <LinearLayout\n        android:id=\"@+id/conv_item_file_transfer_in\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:background=\"@drawable/talk_item_rcs_in\"\n        android:orientation=\"vertical\"\n        android:padding=\"5dp\">\n\n        <ImageView\n            android:id=\"@+id/file_image\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:src=\"@drawable/ri_filetransfer_off\"/>\n\n        <TextView\n            android:id=\"@+id/progress_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/timestamp_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/timestamp_dummy\"\n            android:textColor=\"@android:color/darker_gray\"/>\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start\"\n        android:layout_marginLeft=\"12dip\"\n        android:layout_marginStart=\"12dip\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/talk_item_rcs_file_transfer_out.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"2dip\">\n\n    <LinearLayout\n        android:id=\"@+id/conv_item_file_transfer_out\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:background=\"@drawable/talk_item_rcs_out\"\n        android:orientation=\"vertical\"\n        android:padding=\"5dp\">\n\n        <ImageView\n            android:id=\"@+id/file_image\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:src=\"@drawable/ri_filetransfer_off\"/>\n\n        <TextView\n            android:id=\"@+id/progress_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/text_dummy\"\n            android:textColor=\"@android:color/black\"/>\n\n        <TextView\n            android:id=\"@+id/timestamp_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/timestamp_dummy\"\n            android:textColor=\"@android:color/darker_gray\"/>\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end\"\n        android:layout_marginEnd=\"12dp\"\n        android:layout_marginRight=\"12dp\"\n        android:drawablePadding=\"5dp\"\n        android:text=\"@string/label_state_unknown\"\n        android:textColor=\"@android:color/darker_gray\"/>\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/talk_log_group_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*******************************************************************************\n  ~  * Software Name : RCS IMS Stack\n  ~  *\n  ~  * Copyright (C) 2010 France Telecom S.A.\n  ~  *\n  ~  * Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  * you may not use this file except in compliance with the License.\n  ~  * You may obtain a copy of the License at\n  ~  *\n  ~  *      http://www.apache.org/licenses/LICENSE-2.0\n  ~  *\n  ~  * Unless required by applicable law or agreed to in writing, software\n  ~  * distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  * See the License for the specific language governing permissions and\n  ~  * limitations under the License.\n  ~  ******************************************************************************/\n  -->\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"5dip\">\n\n    <ImageView\n        android:id=\"@+id/avatar\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_marginLeft=\"10dip\"\n        android:layout_marginStart=\"10dip\"\n        android:src=\"@drawable/people\"></ImageView>\n\n    <TextView\n        android:id=\"@+id/subject_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"10dip\"\n        android:layout_marginLeft=\"10dip\"\n        android:layout_marginRight=\"10dip\"\n        android:layout_marginStart=\"10dip\"\n        android:layout_toEndOf=\"@id/avatar\"\n        android:layout_toLeftOf=\"@+id/timestamp_text\"\n        android:layout_toRightOf=\"@id/avatar\"\n        android:layout_toStartOf=\"@+id/timestamp_text\"\n        android:ellipsize=\"end\"\n        android:singleLine=\"true\"\n        android:text=\"@string/text_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textStyle=\"bold\" />\n\n    <TextView\n        android:id=\"@+id/content_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_below=\"@id/avatar\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginStart=\"5dip\"\n        android:layout_toLeftOf=\"@+id/status_text\"\n        android:layout_toStartOf=\"@+id/status_text\"\n        android:ellipsize=\"end\"\n        android:singleLine=\"true\"\n        android:text=\"@string/text_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_marginEnd=\"2dip\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"2dip\"\n        android:layout_marginStart=\"5dip\"\n        android:background=\"@drawable/counter_circle\"\n        android:text=\"@string/number_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textColor=\"@android:color/black\" />\n\n    <TextView\n        android:id=\"@id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_marginEnd=\"2dip\"\n        android:layout_marginRight=\"2dip\"\n        android:text=\"@string/timestamp_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textStyle=\"bold\" />\n\n</RelativeLayout>"
  },
  {
    "path": "RI/res/layout/talk_log_one_to_one_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n  ~ /*******************************************************************************\n  ~  * Software Name : RCS IMS Stack\n  ~  *\n  ~  * Copyright (C) 2010 France Telecom S.A.\n  ~  *\n  ~  * Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  * you may not use this file except in compliance with the License.\n  ~  * You may obtain a copy of the License at\n  ~  *\n  ~  *      http://www.apache.org/licenses/LICENSE-2.0\n  ~  *\n  ~  * Unless required by applicable law or agreed to in writing, software\n  ~  * distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  * See the License for the specific language governing permissions and\n  ~  * limitations under the License.\n  ~  ******************************************************************************/\n  -->\n\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"5dip\">\n\n    <ImageView\n        android:id=\"@+id/avatar\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_marginLeft=\"10dip\"\n        android:layout_marginStart=\"10dip\"\n        android:src=\"@drawable/person\"></ImageView>\n\n    <TextView\n        android:id=\"@+id/contact_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"10dip\"\n        android:layout_marginStart=\"10dip\"\n        android:layout_toEndOf=\"@id/avatar\"\n        android:layout_toRightOf=\"@id/avatar\"\n        android:text=\"@string/contact_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n\n    <TextView\n        android:id=\"@+id/content_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentLeft=\"true\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_below=\"@id/avatar\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginStart=\"5dip\"\n        android:layout_toLeftOf=\"@+id/status_text\"\n        android:layout_toStartOf=\"@+id/status_text\"\n        android:ellipsize=\"end\"\n        android:singleLine=\"true\"\n        android:text=\"@string/text_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n\n    <TextView\n        android:id=\"@+id/status_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_marginEnd=\"2dip\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"2dip\"\n        android:layout_marginStart=\"5dip\"\n        android:background=\"@drawable/counter_circle\"\n        android:text=\"@string/number_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textColor=\"@android:color/black\" />\n\n    <TextView\n        android:id=\"@id/timestamp_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_alignParentRight=\"true\"\n        android:layout_alignTop=\"@id/contact_text\"\n        android:layout_marginEnd=\"2dip\"\n        android:layout_marginRight=\"2dip\"\n        android:text=\"@string/timestamp_dummy\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textStyle=\"bold\" />\n\n</RelativeLayout>"
  },
  {
    "path": "RI/res/layout/utils_smiley_menu_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"?android:attr/listPreferredItemHeight\"\n    android:orientation=\"horizontal\"\n    android:padding=\"5dip\">\n\n    <ImageView\n        android:id=\"@+id/smiley_icon\"\n        android:layout_width=\"20dip\"\n        android:layout_height=\"20dip\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginLeft=\"4dip\"\n        android:layout_marginStart=\"4dip\" />\n\n    <TextView\n        android:id=\"@+id/smiley_name\"\n        android:layout_width=\"0dip\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginLeft=\"10dip\"\n        android:layout_marginStart=\"10dip\"\n        android:layout_weight=\"1\"\n        android:singleLine=\"true\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\"\n        android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n\n    <TextView\n        android:id=\"@+id/smiley_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginEnd=\"20dip\"\n        android:layout_marginRight=\"20dip\"\n        android:singleLine=\"true\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\"\n        android:textColor=\"?android:attr/textColorPrimaryInverse\" />\n\n</LinearLayout>"
  },
  {
    "path": "RI/res/layout/utils_spinner_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@android:id/text1\"\n    style=\"?android:attr/spinnerItemStyle\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:ellipsize=\"marquee\"\n    android:singleLine=\"true\"\n    android:textAppearance=\"?android:attr/textAppearanceLarge\" />\n"
  },
  {
    "path": "RI/res/layout/video_sharing_incoming.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"5dp\"\n        android:stretchColumns=\"1\">\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_contact\" />\n\n            <TextView\n                android:id=\"@+id/contact\"\n                android:singleLine=\"true\"\n                android:text=\"@string/contact_dummy\" />\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_video_format\" />\n\n            <TextView\n                android:id=\"@+id/video_format\"\n                android:singleLine=\"true\" />\n        </TableRow>\n\n    </TableLayout>\n\n    <com.gsma.rcs.ri.sharing.video.media.VideoSurfaceView\n        android:id=\"@+id/video_view\"\n        android:layout_width=\"176dp\"\n        android:layout_height=\"144dp\"\n        android:layout_gravity=\"center\"\n        android:layout_marginTop=\"5dp\" />\n</LinearLayout>\n"
  },
  {
    "path": "RI/res/layout/video_sharing_outgoing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dp\"\n    android:orientation=\"vertical\">\n\n    <Spinner\n        android:id=\"@+id/contact\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <TableLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:stretchColumns=\"1\">\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_contact\" />\n\n            <TextView\n                android:id=\"@+id/remote\"\n                android:singleLine=\"true\" />\n        </TableRow>\n\n        <TableRow android:layout_margin=\"2dp\">\n\n            <TextView\n                android:layout_marginLeft=\"5dip\"\n                android:layout_marginRight=\"5dip\"\n                android:text=\"@string/label_video_format\" />\n\n            <TextView\n                android:id=\"@+id/video_format\"\n                android:singleLine=\"true\" />\n        </TableRow>\n\n    </TableLayout>\n\n    <Button\n        android:id=\"@+id/dial_btn\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_dial\" />\n\n    <Button\n        android:id=\"@+id/invite_btn\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_initiate_sharing\" />\n\n    <Button\n        android:id=\"@+id/switch_cam_btn\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/label_switch_camera\" />\n\n    <com.gsma.rcs.ri.sharing.video.media.VideoSurfaceView\n        android:id=\"@+id/video_preview\"\n        android:layout_width=\"176dp\"\n        android:layout_height=\"144dp\"\n        android:layout_gravity=\"center\"\n        android:layout_marginTop=\"5dp\" />\n</LinearLayout>"
  },
  {
    "path": "RI/res/menu/menu_1to1_talk.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ /*******************************************************************************\n  ~  * Software Name : RCS IMS Stack\n  ~  *\n  ~  * Copyright (C) 2010 France Telecom S.A.\n  ~  *\n  ~  * Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~  * you may not use this file except in compliance with the License.\n  ~  * You may obtain a copy of the License at\n  ~  *\n  ~  *      http://www.apache.org/licenses/LICENSE-2.0\n  ~  *\n  ~  * Unless required by applicable law or agreed to in writing, software\n  ~  * distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~  * See the License for the specific language governing permissions and\n  ~  * limitations under the License.\n  ~  ******************************************************************************/\n  -->\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_send_geoloc\"\n        android:title=\"@string/menu_send_geoloc\"/>\n\n    <item\n        android:id=\"@+id/menu_send_rcs_file\"\n        android:title=\"@string/menu_send_file\"/>\n\n    <item\n        android:id=\"@+id/menu_delete_talk\"\n        android:title=\"@string/menu_delete_talk\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_1to1_talk_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/menu_delete_message\"\n        android:title=\"@string/menu_delete_message\" />\n    <item\n        android:id=\"@+id/menu_resend_message\"\n        android:title=\"@string/menu_resend_message\" />\n    <item\n        android:id=\"@+id/menu_display_content\"\n        android:title=\"@string/menu_display_content\" />\n    <item\n        android:id=\"@+id/menu_listen_content\"\n        android:title=\"@string/menu_listen_content\" />\n    <item\n        android:id=\"@+id/menu_view_detail\"\n        android:title=\"@string/menu_view_detail\" />\n</menu>\n"
  },
  {
    "path": "RI/res/menu/menu_ft.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_gchat_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/menu_delete_message\"\n        android:title=\"@string/menu_delete_message\" />\n    <item\n        android:id=\"@+id/menu_display_content\"\n        android:title=\"@string/menu_display_content\" />\n    <item\n        android:id=\"@+id/menu_listen_content\"\n        android:title=\"@string/menu_listen_content\" />\n    <item\n        android:id=\"@+id/menu_view_group_delivery\"\n        android:title=\"@string/menu_view_group_delivery\" />\n    <item\n        android:id=\"@+id/menu_view_detail\"\n        android:title=\"@string/menu_view_detail\" />\n</menu>\n"
  },
  {
    "path": "RI/res/menu/menu_geoloc_sharing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:icon=\"@drawable/ri_menu_close_sharing\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_group_chat.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:id=\"@+id/menu_insert_smiley\"\n        android:icon=\"@drawable/ri_menu_smiley\"\n        android:title=\"@string/menu_insert_smiley\"/>\n    <item\n        android:id=\"@+id/menu_participants\"\n        android:icon=\"@drawable/ri_menu_participants\"\n        android:title=\"@string/menu_participants\"/>\n    <item\n        android:id=\"@+id/menu_add_participant\"\n        android:icon=\"@drawable/ri_menu_add_participant\"\n        android:title=\"@string/menu_add_participant\"/>\n    <item\n        android:id=\"@+id/menu_quicktext\"\n        android:icon=\"@drawable/ri_menu_quicktext\"\n        android:title=\"@string/menu_quicktext\"/>\n    <item\n        android:id=\"@+id/menu_send_file\"\n        android:icon=\"@drawable/ri_menu_file_transfer\"\n        android:title=\"@string/menu_send_file\"/>\n    <item\n        android:id=\"@+id/menu_send_geoloc\"\n        android:icon=\"@drawable/ri_menu_send_geoloc\"\n        android:title=\"@string/menu_send_geoloc\"/>\n    <item\n        android:id=\"@+id/menu_showus_map\"\n        android:icon=\"@drawable/ri_menu_showus_map\"\n        android:title=\"@string/menu_showus_map\"/>\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:icon=\"@drawable/ri_menu_close_chat\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_historylog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_filter\"\n        android:icon=\"@drawable/ri_menu_filter\"\n        android:title=\"@string/label_history_log_menu_filter\" />\n\n    <item\n        android:id=\"@+id/menu_delete\"\n        android:title=\"@string/menu_sharing_delete\" />\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_image_sharing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:icon=\"@drawable/ri_menu_close_sharing\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_initiate_ft.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_record_audio\"\n        android:title=\"@string/menu_record_audio\"/>\n\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_log.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_clear_log\"\n        android:icon=\"@drawable/ri_menu_clear_log\"\n        android:title=\"@string/menu_clear_log\" />\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_log_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/menu_delete_message\"\n        android:title=\"@string/menu_delete_message\" />\n</menu>\n"
  },
  {
    "path": "RI/res/menu/menu_log_sharing_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/menu_sharing_delete\"\n        android:title=\"@string/menu_sharing_delete\" />\n\n    <item\n        android:id=\"@+id/menu_sharing_display\"\n        android:title=\"@string/menu_sharing_display\" />\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_mm_session.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:icon=\"@drawable/ri_menu_close_session\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/menu/menu_video_sharing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <item\n        android:id=\"@+id/menu_close_session\"\n        android:icon=\"@drawable/ri_menu_close_sharing\"\n        android:title=\"@string/menu_close_session\"/>\n\n</menu>"
  },
  {
    "path": "RI/res/values/filetotransfer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string-array name=\"select_filetotransfer\">\n        <item>Image from gallery</item>\n        <item>Text file from explorer</item>\n        <item>Audio from explorer</item>\n    </string-array>\n\n</resources>"
  },
  {
    "path": "RI/res/values/quicktexts.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string-array name=\"select_quicktext\">\n        <item>Hello</item>\n        <item>Hello everybody</item>\n        <item>How are you</item>\n        <item>I\\'m fine</item>\n        <item>Bye Bye</item>\n        <item>See you soon</item>\n        <item>Where are you?</item>\n        <item>I\\'ll get back to you</item>\n        <item>Urgent! Please reply…</item>\n        <item>Have a nice weekend</item>\n        <item>Thanks a lot</item>\n    </string-array>\n\n</resources>"
  },
  {
    "path": "RI/res/values/smileys.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!--\n         NOTE: if you change anything about this array, you must make the corresponding change\n         to the array DEFAULT_SMILEY_RES_IDS in MessageListItem.java and to default_smiley_names\n         below.\n    -->\n    <string-array name=\"default_smiley_texts\">\n        <item>:-)</item> <!-- 0: Happy -->\n        <item>:-(</item> <!-- 1: Sad -->\n        <item>;-)</item> <!-- 2: Winking -->\n        <item>:-P</item> <!-- 3: Tongue sticking out -->\n        <item>=-O</item> <!-- 4: Surprised -->\n        <item>:-*</item> <!-- 5: Kissing -->\n        <item>:O</item> <!-- 6: Yelling -->\n        <item>B-)</item> <!-- 7: Cool -->\n        <item>:-$</item> <!-- 8: Money mouth -->\n        <item>:-!</item> <!-- 9: Foot in mouth -->\n        <item>:-[</item> <!-- 10: Embarrassed -->\n        <item>O:-)</item> <!-- 11: Angel -->\n        <item>:-\\\\</item> <!-- 12: Undecided -->\n        <item>:\\'(</item> <!-- 13: Crying -->\n        <item>:-X</item> <!-- 14: Lips are sealed -->\n        <item>:-D</item> <!-- 15: Laughing -->\n        <item>o_O</item> <!-- 16: Confused -->\n    </string-array>\n\n    <!--\n         NOTE: if you change anything about this array, you must make the corresponding change\n         to the array DEFAULT_SMILEY_RES_IDS in MessageListItem.java and to default_smiley_texts\n         above.\n    -->\n    <string-array name=\"default_smiley_names\">\n        <item>Happy</item> <!-- 0: :-) -->\n        <item>Sad</item> <!-- 1: :-( -->\n        <item>Winking</item> <!-- 2: ;-) -->\n        <item>Tongue sticking out</item> <!-- 3: :-P -->\n        <item>Surprised</item> <!-- 4: =-O -->\n        <item>Kissing</item> <!-- 5: :-* -->\n        <item>Yelling</item> <!-- 6: :O -->\n        <item>Cool</item> <!-- 7: B-) -->\n        <item>Money mouth</item> <!-- 8: :-$ -->\n        <item>Foot in mouth</item> <!-- 9: :-! -->\n        <item>Embarrassed</item> <!-- 10: :-[ -->\n        <item>Angel</item> <!-- 11: O:-) -->\n        <item>Undecided</item> <!-- 12: :-\\\\ -->\n        <item>Crying</item> <!-- 13: :\\'( -->\n        <item>Lips are sealed</item> <!-- 14: :-X -->\n        <item>Laughing</item> <!-- 15: :-D -->\n        <item>Confused</item> <!-- 16: o_O -->\n    </string-array>\n\n</resources>"
  },
  {
    "path": "RI/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!-- Application -->\n    <string name=\"app_name\">RCS RI</string>\n    <string name=\"menu_about\">About</string>\n    <string name=\"label_ab_not_found\">The address book is not found, launch it manually from your device home screen.</string>\n    <string name=\"label_wait_cnx_start\">Initializing…</string>\n\n    <!-- Commons -->\n    <string name=\"label_service_not_available\">The service is not available. Please retry later.</string>\n    <string name=\"label_confirm_close\">Do you confirm ?\\nThis will close the session.</string>\n    <string name=\"menu_close_session\">Quit</string>\n    <string name=\"menu_clear_log\">Clear log</string>\n    <string name=\"label_file_size\">Size: %1$s</string>\n    <string name=\"label_command_in_progress\">Command in progress…</string>\n    <string name=\"label_session_not_found\">Session not found</string>\n    <string name=\"label_api_not_compatible\">API is not compatible</string>\n    <string name=\"label_ok\">OK</string>\n    <string name=\"label_cancel\">Cancel</string>\n    <string name=\"label_accept\">Accept</string>\n    <string name=\"label_decline\">Decline</string>\n    <string name=\"label_refresh\">Refresh</string>\n    <string name=\"label_from_args\">From: %s</string>\n    <string name=\"label_yes\">Yes</string>\n    <string name=\"label_no\">No</string>\n    <string name=\"label_db_failed\">Database access has failed</string>\n    <string name=\"label_log_empty\">No entry</string>\n    <string name=\"label_incoming\">incoming</string>\n    <string name=\"label_outgoing\">outgoing</string>\n    <string name=\"label_direction_unknown\">unknown direction</string>\n    <string name=\"label_state_unknown\">unknown</string>\n    <string name=\"label_state_delivered_at\">Delivered at %s</string>\n    <string name=\"label_state_displayed_at\">Displayed at %s</string>\n    <string name=\"label_status\">Status: %s</string>\n    <string name=\"label_reason_code_args\">Reason: %s</string>\n    <string name=\"label_reason_code\">Reason:</string>\n    <string name=\"label_filename\">File: %s</string>\n    <string name=\"label_progress_status\">Status:</string>\n    <string name=\"label_position\">Position:</string>\n    <string name=\"label_progress_bar\">Progress:</string>\n    <string name=\"label_file\">Selected file:</string>\n    <string name=\"label_size\">Size:</string>\n    <string name=\"label_contact\">Contact:</string>\n    <string name=\"label_duration\">Duration (sec):</string>\n    <string name=\"label_remote\">Remote contact:</string>\n    <string name=\"label_select_file\">Select file</string>\n    <string name=\"label_invalid_contacts\">Invalid list of participants</string>\n    <string name=\"error_api_permission_denied\">RCS API permission denied</string>\n    <string name=\"label_todo\">Feature not yet implemented</string>\n    <string name=\"error_not_registered\">Not registered to IMS</string>\n    <string name=\"text_dummy\">dummy text</string>\n    <string name=\"timestamp_dummy\">2016/01/02 03:00:00</string>\n    <string name=\"contact_dummy\">+33123456789</string>\n    <string name=\"extension_dummy\">ext.foo</string>\n    <string name=\"direction_dummy\">direction</string>\n    <string name=\"number_dummy\">0</string>\n    <string name=\"error_item_not_found\">No record found!</string>\n\n    <!-- About menu -->\n    <string name=\"label_about_title\">Reference Implementation</string>\n    <string name=\"label_about_app_version\">App release %s</string>\n\n    <!-- Contacts API -->\n    <string name=\"menu_contacts\">Contacts</string>\n    <string name=\"menu_address_book\">Native address book</string>\n    <string name=\"menu_list_rcs_contacts\">All RCS contacts</string>\n    <string name=\"menu_contact_vcard\">Contact visit card</string>\n    <string name=\"label_vcard\">Visit card:</string>\n    <string name=\"label_show_vcard\">Show card</string>\n    <string name=\"menu_blocking_contact\">Block contact</string>\n    <string name=\"label_block\">Block</string>\n    <string name=\"label_unblock\">Unblock</string>\n    <string name=\"label_contact_blocked\">%s has been blocked</string>\n    <string name=\"label_contact_unblocked\">%s has been unblocked</string>\n    <string name=\"label_is_blocked\">Is blocked:</string>\n    <string name=\"label_is_online\">On line:</string>\n    <string name=\"label_block_timestamp\">Blocking time:</string>\n\n    <!-- Capabilities menu -->\n    <string name=\"menu_capabilities\">Capabilities</string>\n    <string name=\"menu_my_capabilities\">My capabilities</string>\n    <string name=\"menu_capabilities_request\">Request capabilities</string>\n    <string name=\"menu_refresh_capabilities\">Refresh all capabilities</string>\n    <string name=\"menu_capabilities_log\">Capabilities log</string>\n    <string name=\"label_refresh_success\">Contacts will been refreshed in background</string>\n    <string name=\"label_capabilities\">Capabilities:</string>\n    <string name=\"label_refresh_all_capabilities\">This command permits to force an update of capabilities for each contact in the address book. This may take a long time if there is a lof of contacts.</string>\n    <string name=\"label_capabilities_video\">Video sharing</string>\n    <string name=\"label_capabilities_image\">Image sharing</string>\n    <string name=\"label_capabilities_ft\">File transfer</string>\n    <string name=\"label_capabilities_im\">IM session</string>\n    <string name=\"label_capabilities_extensions\">Extensions:</string>\n    <string name=\"label_request_in_background\">Request has been sent in background for %s</string>\n    <string name=\"label_capabilities_empty\">No capabilities</string>\n    <string name=\"label_contact_arg\">Contact %s</string>\n    <string name=\"label_capabilities_geolocation_push\">Geolocation push</string>\n    <string name=\"label_automata\">Automata:</string>\n    <string name=\"label_capabilities_timestamp\">Last refresh:</string>\n    <string name=\"label_no_capabilities\">No capabilities for %s</string>\n\n    <!-- Messaging menu -->\n    <string name=\"menu_messaging\">Messaging</string>\n    <string name=\"menu_file_transfer\">File transfer</string>\n    <string name=\"menu_chat\">Chat</string>\n    <string name=\"menu_messaging_log\">Messaging log</string>\n    <string name=\"menu_view_detail\">View details</string>\n    <string name=\"title_talk_1to1_view\">One to one conversation</string>\n\n    <!-- File transfer menu -->\n    <string name=\"menu_transfer_file\">Transfer a file</string>\n    <string name=\"title_recv_file_transfer\">File transfer invitation</string>\n    <string name=\"title_file_transfer\">File transfer</string>\n    <string name=\"label_transfer_failed\">Transfer failed (%1$s)</string>\n    <string name=\"label_transfer_aborted\">Transfer aborted (%1$s)</string>\n    <string name=\"label_transfer_cancelled\">File transfer session has been cancelled</string>\n    <string name=\"label_transfer_rejected\">Transfer rejected (%1$s)</string>\n    <string name=\"label_pause_transfer\">Pause</string>\n    <string name=\"label_resume_transfer\">Resume</string>\n    <string name=\"label_pause_failed\">Pause of File Transfer has failed</string>\n    <string name=\"label_resume_failed\">Resume of File Transfer has failed</string>\n    <string name=\"label_transfer_failed_too_big\">Transfer is aborted because file is too big</string>\n    <string name=\"label_transfer_failed_capacity_too_small\">Not enough free space on device storage for File Transfer</string>\n    <string name=\"label_transfer_session_has_expired\">Session has expired (timeout or any other error)</string>\n    <string name=\"label_ft_state_changed\">%1$s (%2$s)</string>\n    <string name=\"label_ft_from_size\">From: %1$s\\nSize: %2$s</string>\n    <string name=\"menu_ft_config\">File transfer configuration</string>\n    <string name=\"label_ft_WarnSize\">File size warning:</string>\n    <string name=\"label_ft_MaxSize\">Max file size:</string>\n    <string name=\"label_ft_isAutoAccept\">AA enabled:</string>\n    <string name=\"label_ft_isAutoAcceptInRoaming\">AA enabled in roaming:</string>\n    <string name=\"label_MaxFileTransfers\">Max file transfers:</string>\n    <string name=\"label_max_audio_duration\">Max audio file duration (msec):</string>\n    <string name=\"label_GroupFileTransferSupported\">Group supported:</string>\n    <string name=\"menu_file_transfer_config\">File transfer service configuration</string>\n    <string name=\"label_ft_ImageResizeOption\">Image resize option:</string>\n    <string name=\"label_expiration\">Expiration:</string>\n    <string name=\"label_expiration_args\">Expiration: %s</string>\n    <string name=\"label_ft_start_file_transfer\">Start transfer</string>\n    <string name=\"label_ft_filesize\">Size:</string>\n    <string name=\"label_ft_not_allowed\">Not allowed to transfer file(s)</string>\n    <string name=\"title_multi_file_transfer\">Multiple file transfer</string>\n    <string name=\"label_pause_ft_not_allowed\">Cannot pause HTTP file transfer</string>\n    <string name=\"label_resume_ft_not_allowed\">Cannot resume HTTP file transfer</string>\n\n    <!-- Chat menu -->\n    <string name=\"menu_initiate_chat\">Initiate single chat</string>\n    <string name=\"menu_initiate_group_chat\">Initiate group chat</string>\n    <string name=\"menu_chat_config\">Chat service configuration</string>\n    <string name=\"label_invite\">Invite</string>\n    <string name=\"title_recv_chat\">Chat from %s</string>\n    <string name=\"title_recv_group_chat\">Group chat from %s</string>\n    <string name=\"title_group_chat\">Group chat</string>\n    <string name=\"title_chat\">Chat with %s</string>\n    <string name=\"title_chat_exit\">Are you sure to quit the session?</string>\n    <string name=\"label_chat_aborted\">Chat session aborted (%1$s)</string>\n    <string name=\"label_chat_rejected\">Chat session rejected (%1$s)</string>\n    <string name=\"menu_insert_smiley\">Smiley</string>\n    <string name=\"menu_participants\">Participants</string>\n    <string name=\"menu_add_participant\">Add participant</string>\n    <string name=\"label_chat_failed\">Chat session failed (%1$s)</string>\n    <string name=\"label_contacts\">Contacts:</string>\n    <string name=\"label_contact_is_composing\">%1$s is typing…</string>\n    <string name=\"label_select_contacts\">Select contacts</string>\n    <string name=\"label_select_quicktext\">Quick text</string>\n    <string name=\"menu_quicktext\">Quick text</string>\n    <string name=\"label_subject\">Subject: </string>\n    <string name=\"label_subject_notif\">Subject: %s</string>\n    <string name=\"label_max_participants\">Can\\'t add participants: max number of participants is reached (max=%d)</string>\n    <string name=\"label_sharing_warn_size\">Do you confirm sending a file of %1$s ?</string>\n    <string name=\"label_me\">Me</string>\n    <string name=\"label_chat_empty\">No chat</string>\n    <string name=\"label_no_participant_found\">No participant found or available</string>\n    <string name=\"label_no_subject\">no subject</string>\n    <string name=\"label_no_contact\">&#8230;</string>\n    <string name=\"label_ft_thumb\">Thumbnail</string>\n    <string name=\"label_send_audio_msg\">Audio message</string>\n    <string name=\"menu_send_file\">Send file</string>\n    <string name=\"menu_delete_talk\">Delete all messages</string>\n    <string name=\"label_geoloc_msg\">Geoloc</string>\n    <string name=\"label_gc_from_subject\">From: %1$s\\nSubject: %2$s</string>\n    <string name=\"label_chat_send\">Send</string>\n    <string name=\"label_groupchat_event\">Contact has %1$s</string>\n    <string name=\"menu_chat_service_config\">Chat service configuration</string>\n    <string name=\"label_WarnSF\">Warning SF:</string>\n    <string name=\"label_IsComposingTimeout\">Composing timeout:</string>\n    <string name=\"label_MinGroupChatParticipants\">Min GC participants:</string>\n    <string name=\"label_MaxGroupChatParticipants\">MaX GC participants:</string>\n    <string name=\"label_MaxMsgLengthGroupChat\">Max GC msg length:</string>\n    <string name=\"label_GroupChatSubjectMaxLength\">Max GC subject length:</string>\n    <string name=\"label_MaxMsgLengthOneToOneChat\">Max 1to1 msg length:</string>\n    <string name=\"label_SmsFallback\">SMS Fallback:</string>\n    <string name=\"label_RespondToDisplayReports\">Reply to display reports:</string>\n    <string name=\"label_MaxGeolocLabelLength\">Max Geoloc label length:</string>\n    <string name=\"label_GeolocExpireTime\">Geoloc Expire Timeout:</string>\n    <string name=\"label_GroupChatSupported\">GC supported:</string>\n    <string name=\"label_NotAllowedToInitiateGroupChat\">Not allowed to initiate Group Chat</string>\n    <string name=\"title_undelivered_message\">Undelivered message(s)!</string>\n    <string name=\"label_undelivered_message\">%1$s did not receive your message(s)</string>\n    <string name=\"title_undelivered_filetransfer\">Undelivered file(s)!</string>\n    <string name=\"label_undelivered_filetransfer\">%1$s did not receive your file(s)</string>\n    <string name=\"menu_view_group_delivery\">View delivery information</string>\n\n    <!-- Sharing menu -->\n    <string name=\"menu_sharing\">Sharing</string>\n    <string name=\"menu_video_sharing\">Video sharing</string>\n    <string name=\"label_dial\">Dial</string>\n    <string name=\"label_sharing_aborted\">Sharing aborted (%1$s)</string>\n    <string name=\"label_sharing_failed\">Sharing failed (%1$s)</string>\n    <string name=\"label_sharing_rejected\">Sharing rejected (%1$s)</string>\n    <string name=\"menu_sharing_delete\">Delete</string>\n    <string name=\"menu_sharing_display\">Display</string>\n\n    <!-- Image sharing menu -->\n    <string name=\"menu_initiate_image_sharing\">Initiate image sharing</string>\n    <string name=\"label_select_picture\">Select picture</string>\n    <string name=\"label_selected_img\">Filename:</string>\n    <string name=\"label_selected_size\">Size:</string>\n    <string name=\"title_recv_image_sharing\">Image sharing invitation</string>\n    <string name=\"title_image_sharing\">Image sharing</string>\n    <string name=\"label_ish_state_changed\">ISH state %1$s (%2$s)</string>\n\n    <!-- Video sharing menu -->\n    <string name=\"menu_initiate_video_sharing\">Initiate video sharing</string>\n    <string name=\"label_initiate_sharing\">Invite</string>\n    <string name=\"title_recv_video_sharing\">Video sharing invitation</string>\n    <string name=\"title_video_sharing\">Video sharing</string>\n    <string name=\"label_vsh_state_changed\">VSH state %1$s (%2$s)</string>\n    <string name=\"label_switch_camera\">Switch camera</string>\n    <string name=\"label_video_format\">Format:</string>\n\n    <!-- Geoloc sharing menu -->\n    <string name=\"title_recv_geoloc_sharing\">Geoloc sharing invitation</string>\n    <string name=\"label_select_location\">Select location</string>\n    <string name=\"menu_initiate_geoloc_sharing\">Initiate geoloc sharing</string>\n    <string name=\"title_geoloc_sharing\">Geoloc sharing</string>\n    <string name=\"label_gsh_state_changed\">GSH state %1$s (%2$s)</string>\n    <string name=\"label_gsh_default_label\"/>\n    <string name=\"label_gsh_default_latitude\">0.0</string>\n    <string name=\"label_gsh_default_longitude\">0.0</string>\n    <string name=\"label_gsh_default_accuracy\">0</string>\n\n    <!-- MM session menu -->\n    <string name=\"menu_mm_session\">Multimedia session</string>\n    <string name=\"menu_initiate_messaging_session\">Initiate messaging session</string>\n    <string name=\"menu_messaging_sessions_list\">Current messaging sessions</string>\n    <string name=\"menu_initiate_streaming_session\">Initiate streaming session</string>\n    <string name=\"menu_streaming_sessions_list\">Current streaming sessions</string>\n    <string name=\"menu_instant_message\">Send instant message</string>\n    <string name=\"label_initiate_session\">Initiate session</string>\n    <string name=\"label_no_session\">No session</string>\n    <string name=\"label_service_id\">Service ID:</string>\n    <string name=\"label_session_canceled\">Session initiation has been canceled</string>\n    <string name=\"label_session_aborted\">Session aborted (%1$s)</string>\n    <string name=\"label_session_rejected\">Session rejected (%1$s)</string>\n    <string name=\"label_session_failed\">Session failed (%1$s)</string>\n    <string name=\"label_session_has_expired\">Session has expired</string>\n    <string name=\"title_recv_messaging_session\">Multimedia messaging invitation</string>\n    <string name=\"title_recv_streaming_session\">Multimedia streaming invitation</string>\n    <string name=\"title_messaging_session\">Messaging session</string>\n    <string name=\"title_streaming_session\">Streaming session</string>\n    <string name=\"title_instant_session\">Instant session</string>\n    <string name=\"label_session\">Session %s</string>\n    <string name=\"label_send_data\">Send data</string>\n    <string name=\"label_start\">Start RTP streaming</string>\n    <string name=\"label_stop\">Stop RTP streaming</string>\n    <string name=\"label_streaming_info\">To enable data streaming, both sides must send data. NAT binding is maintained by sending data periodically (1 packet per second).</string>\n    <string name=\"label_recv_data\">Receive data:</string>\n    <string name=\"label_mms_state_changed\">MMS state %1$s (%2$s)</string>\n    <string name=\"label_mm_from_id\">From: %1$s\\nService ID: %2$s</string>\n    <string name=\"label_rx_count\">RX :</string>\n    <string name=\"label_tx_count\">TX :</string>\n    <string name=\"label_send_message\">Send message</string>\n    <string name=\"label_recv_instant_messsage\">Instant multimedia message from %s:</string>\n    <string name=\"label_instant_message_sent\">Message has been sent!</string>\n    <!-- Geolocation push -->\n    <string name=\"label_select_geoloc\">Select from google map\\n(Internet connectivity required)</string>\n    <string name=\"menu_showus_map\">Show us in a map</string>\n    <string name=\"menu_send_geoloc\">Send geoloc</string>\n    <string name=\"title_display_geoloc\">Show a geoloc</string>\n    <string name=\"label_geolocation_msg\">Geolocation message</string>\n    <string name=\"label_location\">Label:</string>\n    <string name=\"label_contact_geoloc\">Contact:</string>\n    <string name=\"label_latitude\">Latitude:</string>\n    <string name=\"label_longitude\">Longitude:</string>\n    <string name=\"label_accuracy\">Accuracy:</string>\n    <string name=\"label_geoloc_not_found\">No geoloc info to display!</string>\n    <string name=\"label_display_geoloc\">Display via google map\\n(Internet connectivity required)</string>\n\n    <!-- Intents menu -->\n    <string name=\"menu_intents\">Intents</string>\n    <string name=\"menu_apps\">Applications</string>\n    <string name=\"label_load_chat\">Load a chat</string>\n    <string name=\"label_initiate_chat\">Start a chat</string>\n    <string name=\"label_load_group_chat\">Load a group chat</string>\n    <string name=\"label_initiate_group_chat\">Start a group chat</string>\n    <string name=\"label_load_ft\">Load a file transfer</string>\n    <string name=\"label_initiate_ft\">Start a file transfer</string>\n    <string name=\"label_intent_failed\">Intent not found</string>\n\n    <!-- Service menu -->\n    <string name=\"menu_service\">Service</string>\n    <string name=\"menu_service_status\">Service status</string>\n    <string name=\"notification_title_rcs_service\">RCS service</string>\n    <string name=\"menu_registration_status\">Registration status</string>\n    <string name=\"label_service_bound\">Service bound:</string>\n    <string name=\"label_service_activated\">Service activated:</string>\n    <string name=\"label_service_started\">Service started:</string>\n    <string name=\"error_service_activated\">Failed to read stack activation mode</string>\n    <string name=\"error_service_started\">Failed to read stack started status</string>\n    <string name=\"label_registration_status\">Service registered:</string>\n    <string name=\"menu_service_configuration\">Service configuration</string>\n    <string name=\"label_service_configuration_valid\">Configuration valid:</string>\n    <string name=\"label_default_messaging_method\">Messaging method:</string>\n    <string name=\"label_messaging_mode\">Messaging mode:</string>\n    <string name=\"label_my_display_name\">My display name:</string>\n    <string name=\"label_my_contact_id\">My contact identifier:</string>\n    <string name=\"label_min_battery_level\">Min battery level:</string>\n    <string name=\"label_service_activatation\">RCS stack activation:</string>\n    <string name=\"label_service_activate_unchangeable\">Unchangeable</string>\n    <string name=\"label_service_activate_changeable\">Changeable</string>\n    <string name=\"ims_connected\">Connected to RCS platform</string>\n    <string name=\"ims_disconnected\">Disconnected from RCS platform</string>\n    <string name=\"ims_battery_disconnected\">Disconnected from RCS platform (Battery low)</string>\n\n    <!-- File upload menu -->\n    <string name=\"menu_upload\">File upload</string>\n    <string name=\"title_initiate_upload\">File upload</string>\n    <string name=\"label_upload\">Upload</string>\n    <string name=\"label_file_thumb\">Thumbnail</string>\n    <string name=\"label_upload_failed\">File upload failed</string>\n    <string name=\"label_upload_aborted\">File upload aborted</string>\n    <string name=\"label_show_upload\">Show uploaded file</string>\n    <string name=\"label_show_icon_upload\">Show uploaded thumbnail</string>\n    <string name=\"label_upload_max_size\">File is too big. The max size authorised is %s</string>\n    <string name=\"label_upload_started\">STARTED</string>\n    <string name=\"label_upload_transferred\">TRANSFERRED</string>\n\n    <!-- Group delivery information menu -->\n    <string name=\"title_group_delivery_info\">Group delivery information</string>\n\n    <!-- Chat message menu -->\n    <string name=\"menu_delete_message\">Delete</string>\n    <string name=\"menu_resend_message\">Resend</string>\n    <string name=\"menu_display_content\">Display</string>\n    <string name=\"menu_listen_content\">Listen to</string>\n\n    <!-- HistoryLog  menu -->\n    <string name=\"label_log_id\">Id:</string>\n    <string name=\"label_log_chat_id\">Chat Id:</string>\n    <string name=\"label_log_contact\">Contact:</string>\n    <string name=\"label_log_content\">Content:</string>\n    <string name=\"label_log_date\">Date:</string>\n    <string name=\"label_log_date_sent\">Sent:</string>\n    <string name=\"label_log_date_delivered\">Delivered:</string>\n    <string name=\"label_log_date_displayed\">Displayed:</string>\n    <string name=\"label_log_date_file_expiration\">Expiration:</string>\n    <string name=\"label_log_date_icon_expiration\">Icon expiration:</string>\n    <string name=\"label_log_read_status\">Read:</string>\n    <string name=\"label_log_expired_delivery\">Expired delivery:</string>\n    <string name=\"label_log_dir\">Direction:</string>\n    <string name=\"label_log_duration\">Duration:</string>\n    <string name=\"label_log_encoding\">Encoding:</string>\n    <string name=\"label_log_file_size\">Size:</string>\n    <string name=\"label_log_filename\">Filename:</string>\n    <string name=\"label_log_height\">Height :</string>\n    <string name=\"label_log_mime\">Mime type:</string>\n    <string name=\"label_log_icon_mime\">Icon mime type:</string>\n    <string name=\"label_log_reason\">Reason:</string>\n    <string name=\"label_log_state\">State:</string>\n    <string name=\"label_log_transferred\">Transferred:</string>\n    <string name=\"label_log_file_uri\">File uri:</string>\n    <string name=\"label_log_icon_uri\">Icon uri:</string>\n    <string name=\"label_log_width\">Width :</string>\n    <string name=\"title_sharing_log_item\">History Log detail</string>\n    <string name=\"menu_log_sharing\">Sharing log</string>\n    <string name=\"label_sharing_log_menu_gsh\">Geoloc Share</string>\n    <string name=\"label_sharing_log_menu_ish\">Image Share</string>\n    <string name=\"label_sharing_log_menu_vsh\">Video Share</string>\n    <string name=\"label_sharing_log_contact_spinner_default_value\">No contact filter</string>\n    <string name=\"value_log_duration\">Duration: %1$s</string>\n    <string name=\"title_sharing_log_dialog_filter_logs\">Filter</string>\n\n    <string name=\"label_log_disposition\">Disposition:</string>\n\n    <string name=\"title_history_log_messaging\">Messaging Log</string>\n    <string name=\"title_sharing_log\">Sharing Log</string>\n    <string name=\"label_history_log_menu_filter\">Change filter</string>\n    <string name=\"label_history_log_empty\">Log is empty</string>\n    <string name=\"label_history_log_contact_spinner_default_value\">No contact filter</string>\n    <string name=\"label_ungranted_permission\">Below permissions are not granted!</string>\n    <string name=\"menu_record_audio\">Record audio</string>\n    <string name=\"label_play_record\">Play record</string>\n    <string name=\"label_start_record\">Start audio record</string>\n    <string name=\"label_stop_record\">Stop audio record</string>\n    <string name=\"label_audio_record\">Recorded file:</string>\n    <string name=\"max_audio_record_reached\">Maximum duration is reached!</string>\n\n    <string name=\"error_conversation_delete\">Delete conversation failed</string>\n    <string name=\"cannot_read_log\">Cannot read RCS history log</string>\n\n    <!-- States -->\n\n    <string-array name=\"file_transfer_states\">\n        <item>INVITED</item>\n        <item>ACCEPTING</item>\n        <item>REJECTED</item>\n        <item>QUEUED</item>\n        <item>INITIATING</item>\n        <item>STARTED</item>\n        <item>PAUSED</item>\n        <item>ABORTED</item>\n        <item>TRANSFERRED</item>\n        <item>FAILED</item>\n        <item>DELIVERED</item>\n        <item>DISPLAYED</item>\n    </string-array>\n    <string-array name=\"file_transfer_reason_codes\">\n        <item/>\n        <item>ABORTED_BY_USER</item>\n        <item>ABORTED_BY_REMOTE</item>\n        <item>ABORTED_BY_SYSTEM</item>\n        <item>ABORTED_BY_SECONDARY_DEVICE</item>\n        <item>REJECTED_BY_TIMEOUT</item>\n        <item>REJECTED_SPAM</item>\n        <item>REJECTED_LOW_SPACE</item>\n        <item>REJECTED_MAX_SIZE</item>\n        <item>REJECTED_MAX_FILE_TRANSFERS</item>\n        <item>REJECTED_BY_USER</item>\n        <item>REJECTED_BY_REMOTE</item>\n        <item>REJECTED_MEDIA_FAILED</item>\n        <item>REJECTED_BY_SYSTEM</item>\n        <item>PAUSED_BY_SYSTEM</item>\n        <item>PAUSED_BY_USER</item>\n        <item>FAILED_INITIATION</item>\n        <item>FAILED_DATA_TRANSFER</item>\n        <item>FAILED_SAVING</item>\n        <item>FAILED_DELIVERY</item>\n        <item>FAILED_DISPLAY</item>\n        <item>FAILED_NOT_ALLOWED_TO_SEND</item>\n    </string-array>\n    <string-array name=\"participant_statuses\">\n        <item>INVITE_QUEUED</item>\n        <item>INVITING</item>\n        <item>DISCONNECTED</item>\n        <item>INVITED</item>\n        <item>CONNECTED</item>\n        <item>DISCONNECTED</item>\n        <item>DEPARTED</item>\n        <item>FAILED</item>\n        <item>DECLINED</item>\n        <item>TIMEOUT</item>\n    </string-array>\n    <string-array name=\"delivery_statuses\">\n        <item>UNSUPPORTED</item>\n        <item>NOT_DELIVERED</item>\n        <item>DELIVERED</item>\n        <item>DISPLAYED</item>\n        <item>FAILED</item>\n    </string-array>\n    <string-array name=\"delivery_reason_codes\">\n        <item/>\n        <item>FAILED_DELIVERY</item>\n        <item>FAILED_DISPLAY</item>\n    </string-array>\n    <string-array name=\"group_chat_states\">\n        <item>INVITED</item>\n        <item>INITIATING</item>\n        <item>STARTED</item>\n        <item>ABORTED</item>\n        <item>FAILED</item>\n        <item>ACCEPTING</item>\n        <item>REJECTED</item>\n    </string-array>\n    <string-array name=\"group_chat_reason_codes\">\n        <item/>\n        <item>ABORTED_BY_USER</item>\n        <item>ABORTED_BY_REMOTE</item>\n        <item>ABORTED_BY_INACTIVITY</item>\n        <item>ABORTED_BY_SECONDARY_DEVICE</item>\n        <item>REJECTED_SPAM</item>\n        <item>REJECTED_MAX_CHATS</item>\n        <item>REJECTED_BY_REMOTE</item>\n        <item>REJECTED_BY_TIMEOUT</item>\n        <item>REJECTED_BY_SYSTEM</item>\n        <item>FAILED_INITIATION</item>\n    </string-array>\n    <string-array name=\"message_statuses\">\n        <item>REJECTED</item>\n        <item>QUEUED</item>\n        <item>SENDING</item>\n        <item>SENT</item>\n        <item>FAILED</item>\n        <item>DELIVERED</item>\n        <item>DISPLAY_REPORT_REQUESTED</item>\n        <item>RECEIVED</item>\n        <item>DISPLAYED</item>\n    </string-array>\n    <string-array name=\"message_reason_codes\">\n        <item/>\n        <item>FAILED_SEND</item>\n        <item>FAILED_DELIVERY</item>\n        <item>FAILED_DISPLAY</item>\n        <item>REJECTED_SPAM</item>\n    </string-array>\n    <string-array name=\"ish_states\">\n        <item>INVITED</item>\n        <item>INITIATING</item>\n        <item>STARTED</item>\n        <item>ABORTED</item>\n        <item>FAILED</item>\n        <item>TRANSFERRED</item>\n        <item>REJECTED</item>\n        <item>RINGING</item>\n        <item>ACCEPTING</item>\n    </string-array>\n    <string-array name=\"ish_reason_codes\">\n        <item/>\n        <item>ABORTED_BY_USER</item>\n        <item>ABORTED_BY_REMOTE</item>\n        <item>ABORTED_BY_SYSTEM</item>\n        <item>ABORTED_BY_SECONDARY_DEVICE</item>\n        <item>REJECTED_SPAM</item>\n        <item>REJECTED_BY_TIMEOUT</item>\n        <item>REJECTED_LOW_SPACE</item>\n        <item>REJECTED_ MAX_SIZE</item>\n        <item>REJECTED_MAX_SESSIONS</item>\n        <item>REJECTED_BY_USER</item>\n        <item>REJECTED_BY_REMOTE</item>\n        <item>REJECTED_BY_SYSTEM</item>\n        <item>FAILED_INITIATION</item>\n        <item>FAILED_SHARING</item>\n        <item>FAILED_SAVING</item>\n    </string-array>\n    <string-array name=\"vsh_states\">\n        <item>INVITED</item>\n        <item>INITIATING</item>\n        <item>STARTED</item>\n        <item>ABORTED</item>\n        <item>FAILED</item>\n        <item>REJECTED</item>\n        <item>RINGING</item>\n        <item>ACCEPTING</item>\n    </string-array>\n    <string-array name=\"vsh_reason_codes\">\n        <item/>\n        <item>ABORTED_BY_USER</item>\n        <item>ABORTED_BY_REMOTE</item>\n        <item>ABORTED_BY_SYSTEM</item>\n        <item>ABORTED_BY_SECONDARY_DEVICE</item>\n        <item>REJECTED_SPAM</item>\n        <item>REJECTED_MAX_SESSIONS</item>\n        <item>REJECTED_BY_USER</item>\n        <item>REJECTED_BY_REMOTE</item>\n        <item>REJECTED_BY_TIMEOUT</item>\n        <item>REJECTED_BY_SYSTEM</item>\n        <item>FAILED_INITIATION</item>\n        <item>FAILED_SHARING</item>\n    </string-array>\n    <string-array name=\"gsh_states\">\n        <item>INVITED</item>\n        <item>INITIATING</item>\n        <item>STARTED</item>\n        <item>ABORTED</item>\n        <item>FAILED</item>\n        <item>TRANSFERRED</item>\n        <item>REJECTED</item>\n        <item>RINGING</item>\n        <item>ACCEPTING</item>\n    </string-array>\n    <string-array name=\"gsh_reason_codes\">\n        <item/>\n        <item>ABORTED_BY_USER</item>\n        <item>ABORTED_BY_REMOTE</item>\n        <item>ABORTED_BY_SYSTEM</item>\n        <item>ABORTED_BY_SECONDARY_DEVICE</item>\n        <item>REJECTED_SPAM</item>\n        <item>REJECTED_MAX_SESSIONS</item>\n        <item>REJECTED_BY_USER</item>\n        <item>REJECTED_BY_REMOTE</item>\n        <item>REJECTED_BY_TIMEOUT</item>\n        <item>REJECTED_BY_SYSTEM</item>\n        <item>FAILED_INITIATION</item>\n        <item>FAILED_SHARING</item>\n    </string-array>\n    <string-array name=\"mms_states\">\n        <item>INVITED</item>\n        <item>INITIATING</item>\n        <item>STARTED</item>\n        <item>ABORTED</item>\n        <item>FAILED</item>\n        <item>REJECTED</item>\n        <item>RINGING</item>\n        <item>ACCEPTING</item>\n    </string-array>\n    <string-array name=\"mms_reason_codes\">\n        <item/>\n        <item>ABORTED_BY_USER</item>\n        <item>ABORTED_BY_REMOTE</item>\n        <item>ABORTED_BY_SYSTEM</item>\n        <item>REJECTED_BY_INACTIVITY</item>\n        <item>REJECTED_BY_USER</item>\n        <item>REJECTED_BY_REMOTE</item>\n        <item>REJECTED_BY_TIMEOUT</item>\n        <item>REJECTED_BY_SYSTEM</item>\n        <item>FAILED_INITIATION</item>\n        <item>FAILED_SESSION</item>\n        <item>FAILED_MEDIA</item>\n    </string-array>\n    <string-array name=\"group_chat_event\">\n        <item>JOINED</item>\n        <item>DEPARTED</item>\n    </string-array>\n    <string-array name=\"messaging_method\">\n        <item>Automatic</item>\n        <item>RCS</item>\n        <item>Non RCS</item>\n    </string-array>\n    <string-array name=\"minimum_battery_level\">\n        <item>Never stop</item>\n        <item>5 %</item>\n        <item>10 %</item>\n        <item>20 %</item>\n    </string-array>\n\n</resources>"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/AboutRI.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri;\n\nimport com.gsma.services.rcs.RcsService.Build;\n\nimport android.app.Activity;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\n/**\n * About the RI\n * \n * @author Jean-Marc AUFFRET\n */\npublic class AboutRI extends Activity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.app_about);\n\n        // Display application release\n        TextView releaseView = (TextView) findViewById(R.id.app_version);\n        releaseView.setText(getString(R.string.label_about_app_version, getAppVersion()));\n\n        // Display GSMA version\n        TextView gsmaView = (TextView) findViewById(R.id.gsma_version);\n        gsmaView.setText(getGsmaVersion());\n    }\n\n    /**\n     * Returns the application version from manifest file\n     *\n     * @return Application version or null if not found\n     */\n    private String getAppVersion() {\n        String version = null;\n        try {\n            PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);\n            version = info.versionName + \".\" + info.versionCode;\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        return version;\n    }\n\n    /**\n     * Returns the GSMA version\n     * \n     * @return String\n     */\n    private String getGsmaVersion() {\n        StringBuilder version = new StringBuilder(Build.API_CODENAME);\n        version.append(\" \");\n        switch (Build.API_VERSION) {\n            case Build.VERSION_CODES.BASE:\n                version.append(\"Albatros 2.0.\");\n                break;\n            case Build.VERSION_CODES.BLACKBIRD:\n                version.append(\"Blackbird 1.5.\");\n                break;\n            case Build.VERSION_CODES.CPR:\n                version.append(\"Crane Priority Release 1.6.\");\n                break;\n            default:\n                version.append(\"Unknown 0.0\");\n        }\n        version.append(Build.API_INCREMENTAL);\n        return version.toString();\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/DeviceBoot.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * On device boot starts the RCS service notification manager automatically\n * \n * @author Jean-Marc AUFFRET\n */\npublic class DeviceBoot extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {\n            context.startService(new Intent(context, RcsServiceNotifManager.class));\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/RI.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsListActivity;\nimport com.gsma.rcs.ri.capabilities.TestCapabilitiesApi;\nimport com.gsma.rcs.ri.contacts.TestContactsApi;\nimport com.gsma.rcs.ri.extension.TestMultimediaSessionApi;\nimport com.gsma.rcs.ri.intents.TestIntentApps;\nimport com.gsma.rcs.ri.messaging.TestMessagingApi;\nimport com.gsma.rcs.ri.service.TestServiceApi;\nimport com.gsma.rcs.ri.sharing.TestSharingApi;\nimport com.gsma.rcs.ri.upload.InitiateFileUpload;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.LinearLayout;\nimport android.widget.ListView;\nimport android.widget.ProgressBar;\n\n/**\n * RI application\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RI extends RcsListActivity {\n\n    private static final int PROGRESS_INIT_INCREMENT = 100;\n\n    private static final String LOGTAG = LogUtils.getTag(RI.class.getSimpleName());\n\n    public static String sChatIdOnForeground;\n\n    private ListView mListView;\n\n    private ProgressBar mProgressBar;\n\n    private LinearLayout mInitLayout;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        /* Set layout */\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.ri_list);\n\n        mListView = (ListView) findViewById(android.R.id.list);\n        mProgressBar = (ProgressBar) findViewById(android.R.id.progress);\n        mInitLayout = (LinearLayout) findViewById(R.id.wait_cnx_start);\n\n        /* Set items */\n        // @formatter:off\n        String[] items = {\n                getString(R.string.menu_contacts),\n                getString(R.string.menu_capabilities),\n                getString(R.string.menu_messaging),\n                getString(R.string.menu_sharing),\n                getString(R.string.menu_mm_session),\n                getString(R.string.menu_intents),\n                getString(R.string.menu_service),\n                getString(R.string.menu_upload),\n                getString(R.string.menu_about)\n        };\n        // @formatter:on\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n\n        ContactUtil contactUtil = ContactUtil.getInstance(this);\n        try {\n            /* The country code must be read to check that ContactUtil is ready to be used */\n            String cc = contactUtil.getMyCountryCode();\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"Country code is '\" + cc + \"'\");\n            }\n\n        } catch (RcsPermissionDeniedException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            /* We should not be allowed to continue if this exception occurs */\n            showMessageThenExit(R.string.error_api_permission_denied);\n        }\n        /*\n         * The initialization of the connection manager is delayed to avoid non response during\n         * application initialization after installation. The application waits until end of\n         * connection manager initialization.\n         */\n        if (!RiApplication.sCnxManagerStarted) {\n            new WaitForConnectionManagerStart()\n                    .execute(RiApplication.DELAY_FOR_STARTING_CNX_MANAGER);\n        } else {\n            mInitLayout.setVisibility(View.GONE);\n        }\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, TestContactsApi.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, TestCapabilitiesApi.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, TestMessagingApi.class));\n                break;\n\n            case 3:\n                startActivity(new Intent(this, TestSharingApi.class));\n                break;\n\n            case 4:\n                startActivity(new Intent(this, TestMultimediaSessionApi.class));\n                break;\n\n            case 5:\n                startActivity(new Intent(this, TestIntentApps.class));\n                break;\n\n            case 6:\n                startActivity(new Intent(this, TestServiceApi.class));\n                break;\n\n            case 7:\n                startActivity(new Intent(this, InitiateFileUpload.class));\n                break;\n\n            case 8:\n                startActivity(new Intent(this, AboutRI.class));\n                break;\n        }\n    }\n\n    private class WaitForConnectionManagerStart extends AsyncTask<Long, Integer, Void> {\n\n        @Override\n        protected void onPreExecute() {\n            mInitLayout.setVisibility(View.VISIBLE);\n            mListView.setVisibility(View.GONE);\n        }\n\n        @Override\n        protected void onProgressUpdate(Integer... progress) {\n            mProgressBar.setProgress(progress[0]);\n        }\n\n        @Override\n        protected Void doInBackground(Long... duration) {\n            long delay = (duration[0] / PROGRESS_INIT_INCREMENT);\n            for (int i = 0; i < PROGRESS_INIT_INCREMENT; i++) {\n                try {\n                    Thread.sleep(delay);\n                    publishProgress((int) (delay * (i + 1) * 100 / duration[0]));\n                    if (RiApplication.sCnxManagerStarted) {\n                        break;\n                    }\n                } catch (InterruptedException ignore) {\n                }\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(Void res) {\n            mInitLayout.setVisibility(View.GONE);\n            mListView.setVisibility(View.VISIBLE);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/RcsServiceNotifManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri;\n\nimport com.gsma.rcs.api.connection.utils.TimerUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.RcsServiceRegistrationListener;\nimport com.gsma.services.rcs.capability.CapabilityService;\n\nimport android.app.AlarmManager;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.graphics.BitmapFactory;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\n/**\n * Service manager that monitors the service availability and that displays the RCS status in the\n * notification bar\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RcsServiceNotifManager extends Service {\n    private static final String LOGTAG = LogUtils.getTag(RcsServiceNotifManager.class\n            .getSimpleName());\n\n    private final static int NOTIF_ID = 1000;\n\n    private RcsServiceStartupListener mStartupEventReceiver;\n\n    private RcsService mServiceApi;\n\n    private Context mCtx;\n\n    private PendingIntent mCnxIntent;\n\n    private int mRetryCount;\n\n    private AlarmManager mAlarmManager;\n\n    private static final String ACTION_VIEW_SETTINGS = \"com.gsma.services.rcs.action.VIEW_SETTINGS\";\n\n    private static final String ACTION_API_CONNECT = \"com.gsma.rcs.ri.ACTION_API_CONNECT\";\n\n    private static final long API_DELAY_TO_CONNECT = 5000;\n\n    private static final int MAX_RETRY_API_CNX = 4;\n\n    @Override\n    public void onCreate() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Service started\");\n        }\n        mCtx = this;\n        mCnxIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_API_CONNECT), 0);\n        mAlarmManager = (AlarmManager) mCtx.getSystemService(Context.ALARM_SERVICE);\n\n        notifyImsUnregistered(RcsServiceRegistration.ReasonCode.UNSPECIFIED);\n\n        mStartupEventReceiver = new RcsServiceStartupListener();\n        registerReceiver(mStartupEventReceiver, new IntentFilter(RcsService.ACTION_SERVICE_UP));\n\n        /* Register the broadcast receiver to pool periodically the API connections */\n        registerReceiver(new ReceiveTimerToReConnectApi(), new IntentFilter(ACTION_API_CONNECT));\n\n        mRetryCount = 0;\n        connectToService(this);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Service stopped\");\n        }\n        unregisterReceiver(mStartupEventReceiver);\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    private void connectToService(Context ctx) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Try to connect to service API\");\n        }\n        try {\n            if (!RcsServiceControl.getInstance(ctx).isServiceStarted()) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"RCS service not yet started\");\n                }\n                return;\n            }\n            mServiceApi = new CapabilityService(ctx, newRcsServiceListener());\n            mServiceApi.connect();\n\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, \"Cannot connect service API: \".concat(e.getMessage()));\n            mRetryCount++;\n            if (mRetryCount < MAX_RETRY_API_CNX) {\n                TimerUtils.setExactTimer(mAlarmManager, System.currentTimeMillis()\n                        + API_DELAY_TO_CONNECT, mCnxIntent);\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Set timer to retry API connection\");\n                }\n            } else {\n                Log.e(LOGTAG, \"Maximum attempts to connect API is reached\");\n            }\n        }\n    }\n\n    private class RcsServiceStartupListener extends BroadcastReceiver {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (!RcsService.ACTION_SERVICE_UP.equals(intent.getAction())) {\n                return;\n            }\n\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Service UP\");\n            }\n            mRetryCount = 0;\n            TimerUtils.setExactTimer(mAlarmManager, System.currentTimeMillis()\n                    + API_DELAY_TO_CONNECT, mCnxIntent);\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Set timer to connect API\");\n            }\n        }\n    }\n\n    private RcsServiceListener newRcsServiceListener() {\n        return new RcsServiceListener() {\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Service API disconnected\");\n                }\n                notifyImsUnregistered(RcsServiceRegistration.ReasonCode.CONNECTION_LOST);\n            }\n\n            @Override\n            public void onServiceConnected() {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Service API connected\");\n                }\n                try {\n                    mRetryCount = 0;\n                    mServiceApi.addEventListener(mRcsRegistrationListener);\n                    if (mServiceApi.isServiceRegistered()) {\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"IMS is registered\");\n                        }\n                        notifyImsRegistered();\n                    } else {\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"IMS is unregistered\");\n                        }\n                        RcsServiceRegistration.ReasonCode reason = mServiceApi\n                                .getServiceRegistrationReasonCode();\n                        notifyImsUnregistered(reason);\n                    }\n                } catch (RcsServiceException e) {\n                    if (LogUtils.isActive) {\n                        Log.w(LOGTAG, \"Cannot add RCS Service Registration Listener\", e);\n                    }\n                }\n            }\n        };\n    }\n\n    private RcsServiceRegistrationListener mRcsRegistrationListener = new RcsServiceRegistrationListener() {\n        @Override\n        public void onServiceUnregistered(RcsServiceRegistration.ReasonCode reason) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"IMS has been unregistered\");\n            }\n            notifyImsUnregistered(reason);\n        }\n\n        @Override\n        public void onServiceRegistered() {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"IMS has been registered\");\n            }\n            notifyImsRegistered();\n        }\n    };\n\n    private void notifyImsRegistered() {\n        addImsConnectionNotification(true, getString(R.string.ims_connected));\n    }\n\n    private void notifyImsUnregistered(RcsServiceRegistration.ReasonCode reason) {\n        String label;\n        if (RcsServiceRegistration.ReasonCode.BATTERY_LOW == reason) {\n            label = getString(R.string.ims_battery_disconnected);\n        } else {\n            label = getString(R.string.ims_disconnected);\n        }\n        addImsConnectionNotification(false, label);\n    }\n\n    private void addImsConnectionNotification(boolean connected, String label) {\n        Intent intent = new Intent(ACTION_VIEW_SETTINGS);\n        PendingIntent contentIntent = PendingIntent.getBroadcast(getApplicationContext(), 0,\n                intent, 0);\n        String title = this.getString(R.string.notification_title_rcs_service);\n        Notification notif = buildImsConnectionNotification(contentIntent, title, label, connected);\n        notif.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE;\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(NOTIF_ID, notif);\n    }\n\n    private Notification buildImsConnectionNotification(PendingIntent intent, String title,\n            String message, boolean connected) {\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(intent);\n        // With Android 5.0 Lollipop it is no longer possible to use colored icons in the\n        // notification area.\n        // Only large icon supports colors but only small icon can be shown in notification bar.\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            if (connected) {\n                notif.setLargeIcon(BitmapFactory.decodeResource(getResources(),\n                        R.drawable.ri_notif_on_icon_color));\n                notif.setSmallIcon(R.drawable.ri_notif_on_icon_white);\n            } else {\n                notif.setLargeIcon(BitmapFactory.decodeResource(getResources(),\n                        R.drawable.ri_notif_off_icon_color));\n                notif.setSmallIcon(R.drawable.ri_notif_off_icon_white);\n            }\n        } else {\n            if (connected) {\n                notif.setSmallIcon(R.drawable.ri_notif_on_icon_color);\n            } else {\n                notif.setSmallIcon(R.drawable.ri_notif_off_icon_color);\n            }\n        }\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(false);\n        notif.setOnlyAlertOnce(true);\n        notif.setContentTitle(title);\n        notif.setContentText(message);\n        return notif.build();\n    }\n\n    private class ReceiveTimerToReConnectApi extends BroadcastReceiver {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            new Thread() {\n                public void run() {\n                    try {\n                        connectToService(mCtx);\n                    } catch (RuntimeException e) {\n                        /*\n                         * Intentionally catch runtime exceptions as else it will abruptly end the\n                         * thread and eventually bring the whole system down, which is not intended.\n                         */\n                        Log.e(LOGTAG, \"Failed to pool connection to RCS service!\", e);\n                    }\n                }\n            }.start();\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/RiApplication.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceControl;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.Resources;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.util.Log;\n\nimport java.util.Arrays;\nimport java.util.EnumSet;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\n/**\n * This subclass of Application allows to get a resource content from a static context\n * \n * @author Philippe LEMORDANT\n */\npublic class RiApplication extends Application {\n\n    /**\n     * Delay (ms) before starting connection manager.\n     */\n    /* package private */static final long DELAY_FOR_STARTING_CNX_MANAGER = 1000;\n\n    private static Context mContext;\n\n    /**\n     * Array of participant statuses\n     */\n    public static String[] sParticipantStatuses;\n\n    /**\n     * Array of delivery statuses\n     */\n    public static String[] sDeliveryStatuses;\n\n    /**\n     * Array of delivery reason codes\n     */\n    public static String[] sDeliveryReasonCode;\n\n    /**\n     * Array of Group CHAT states\n     */\n    public static String[] sGroupChatStates;\n\n    /**\n     * Array of Group CHAT reason codes\n     */\n    public static String[] sGroupChatReasonCodes;\n\n    /**\n     * Array of message reason codes\n     */\n    public static String[] sMessageReasonCodes;\n\n    /**\n     * Array of message statuses\n     */\n    public static String[] sMessagesStatuses;\n\n    /**\n     * Array of file transfer states\n     */\n    public static String[] sFileTransferStates;\n\n    /**\n     * Array of file transfer reason codes\n     */\n    public static String[] sFileTransferReasonCodes;\n\n    /**\n     * Array of Image sharing states\n     */\n    public static String[] sImageSharingStates;\n\n    /**\n     * Array of Image sharing reason codes\n     */\n    public static String[] sImageSharingReasonCodes;\n\n    /**\n     * Array of Video sharing states\n     */\n    public static String[] sVideoSharingStates;\n\n    /**\n     * Array of Video sharing reason codes\n     */\n    public static String[] sVideoReasonCodes;\n\n    /**\n     * Array of Geolocation sharing states\n     */\n    public static String[] sGeolocSharingStates;\n\n    /**\n     * Array of Geolocation sharing reason codes\n     */\n    public static String[] sGeolocReasonCodes;\n\n    /**\n     * Array of MULTIMEDIA Messaging Session states\n     */\n    public static String[] sMultimediaStates;\n\n    /**\n     * Array of MULTIMEDIA Messaging Session codes\n     */\n    public static String[] sMultimediaReasonCodes;\n\n    /**\n     * Array of group chat events\n     */\n    public static String[] sGroupChatEvents;\n\n    private static Map<Direction, String> sDirectionToString;\n\n    private static RcsServiceControl mRcsServiceControl;\n\n    private static final String LOGTAG = LogUtils.getTag(RiApplication.class.getSimpleName());\n\n    /**\n     * Gets direction\n     * \n     * @param direction Direction\n     * @return String\n     */\n    public static String getDirection(Direction direction) {\n        return sDirectionToString.get(direction);\n    }\n\n    /* package private */static boolean sCnxManagerStarted = false;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mContext = getApplicationContext();\n        Resources resources = getResources();\n        sParticipantStatuses = convertForUI(resources.getStringArray(R.array.participant_statuses));\n        sDeliveryStatuses = convertForUI(resources.getStringArray(R.array.delivery_statuses));\n        sDeliveryReasonCode = convertForUI(resources.getStringArray(R.array.delivery_reason_codes));\n        sGroupChatStates = convertForUI(resources.getStringArray(R.array.group_chat_states));\n        sGroupChatReasonCodes = convertForUI(resources\n                .getStringArray(R.array.group_chat_reason_codes));\n        sMessageReasonCodes = convertForUI(resources.getStringArray(R.array.message_reason_codes));\n        sMessagesStatuses = convertForUI(resources.getStringArray(R.array.message_statuses));\n        sFileTransferStates = convertForUI(resources.getStringArray(R.array.file_transfer_states));\n        sFileTransferReasonCodes = convertForUI(resources\n                .getStringArray(R.array.file_transfer_reason_codes));\n        sImageSharingStates = convertForUI(resources.getStringArray(R.array.ish_states));\n        sImageSharingReasonCodes = convertForUI(resources.getStringArray(R.array.ish_reason_codes));\n        sVideoSharingStates = convertForUI(resources.getStringArray(R.array.vsh_states));\n        sVideoReasonCodes = convertForUI(resources.getStringArray(R.array.vsh_reason_codes));\n        sGeolocSharingStates = convertForUI(resources.getStringArray(R.array.gsh_states));\n        sGeolocReasonCodes = convertForUI(resources.getStringArray(R.array.gsh_reason_codes));\n        sMultimediaStates = convertForUI(resources.getStringArray(R.array.mms_states));\n        sMultimediaReasonCodes = convertForUI(resources.getStringArray(R.array.mms_reason_codes));\n        sGroupChatEvents = convertForUI(resources.getStringArray(R.array.group_chat_event));\n\n        sDirectionToString = new HashMap<>();\n        sDirectionToString.put(Direction.INCOMING, resources.getString(R.string.label_incoming));\n        sDirectionToString.put(Direction.OUTGOING, resources.getString(R.string.label_outgoing));\n        sDirectionToString.put(Direction.IRRELEVANT,\n                resources.getString(R.string.label_direction_unknown));\n\n        mRcsServiceControl = RcsServiceControl.getInstance(mContext);\n\n        /* Starts the RCS service notification manager */\n        startService(new Intent(this, RcsServiceNotifManager.class));\n\n        /* Do not execute the ConnectionManager on the main thread */\n        Handler mainThreadHandler = new Handler(Looper.getMainLooper());\n        final ConnectionManager cnxManager = ConnectionManager.createInstance(mContext,\n                mRcsServiceControl, EnumSet.allOf(RcsServiceName.class));\n        mainThreadHandler.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    cnxManager.start();\n                    sCnxManagerStarted = true;\n\n                } catch (RuntimeException e) {\n                    Log.e(LOGTAG, \"Failed to start connection manager!\", e);\n                }\n            }\n        }, DELAY_FOR_STARTING_CNX_MANAGER);\n    }\n\n    /**\n     * Convert to lower case and readable strings\n     * \n     * @param strings array of strings to be converted\n     * @return converted strings\n     */\n    private String[] convertForUI(String[] strings) {\n        List<String> stringList = Arrays.asList(strings);\n        for (int i = 0, l = stringList.size(); i < l; ++i) {\n            stringList.set(i, stringList.get(i).toLowerCase(Locale.getDefault()).replace('_', ' '));\n        }\n        return (String[]) stringList.toArray();\n    }\n\n    /**\n     * Gets the application context\n     * \n     * @return the application context\n     */\n    public static Context getAppContext() {\n        return mContext;\n    }\n\n    /**\n     * Gets the RCS service control singleton\n     * \n     * @return the RCS service control singleton\n     */\n    public static RcsServiceControl getRcsServiceControl() {\n        return mRcsServiceControl;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/capabilities/CapabilitiesList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.capabilities;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\n\nimport android.content.Context;\nimport android.content.pm.ActivityInfo;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.text.format.DateUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckBox;\nimport android.widget.CursorAdapter;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\n/**\n * List capabilities from the content provider\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class CapabilitiesList extends RcsActivity {\n\n    // @formatter:off\n    private static final String[] PROJECTION = new String[] {\n        CapabilitiesLog.BASECOLUMN_ID,\n        CapabilitiesLog.CONTACT,\n        CapabilitiesLog.CAPABILITY_IM_SESSION,\n        CapabilitiesLog.CAPABILITY_FILE_TRANSFER,\n        CapabilitiesLog.CAPABILITY_IMAGE_SHARE,\n        CapabilitiesLog.CAPABILITY_VIDEO_SHARE,\n        CapabilitiesLog.CAPABILITY_GEOLOC_PUSH,\n        CapabilitiesLog.CAPABILITY_EXTENSIONS,\n        CapabilitiesLog.AUTOMATA,\n        CapabilitiesLog.TIMESTAMP\n    };\n    // @formatter:on\n\n    private static final String SORT_ORDER = CapabilitiesLog.CONTACT + \" DESC\";\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.capabilities_list);\n\n        // Set list adapter\n        ListView view = (ListView) findViewById(android.R.id.list);\n        TextView emptyView = (TextView) findViewById(android.R.id.empty);\n        view.setEmptyView(emptyView);\n        CapabilitiesListAdapter adapter = createListAdapter();\n        view.setAdapter(adapter);\n    }\n\n    private CapabilitiesListAdapter createListAdapter() {\n        Cursor cursor = getContentResolver().query(CapabilitiesLog.CONTENT_URI, PROJECTION, null,\n                null, SORT_ORDER);\n        if (cursor == null) {\n            showMessageThenExit(R.string.label_db_failed);\n            return null;\n        }\n        return new CapabilitiesListAdapter(this, cursor);\n    }\n\n    /**\n     * List adapter\n     */\n    private class CapabilitiesListAdapter extends CursorAdapter {\n        private RcsContactUtil rcsDisplayName;\n\n        /**\n         * Constructor\n         * \n         * @param context Context\n         * @param c Cursor\n         */\n        public CapabilitiesListAdapter(Context context, Cursor c) {\n            // TODO use CursorLoader\n            super(context, c);\n            rcsDisplayName = RcsContactUtil.getInstance(context);\n        }\n\n        @Override\n        public View newView(Context context, Cursor cursor, ViewGroup parent) {\n            LayoutInflater inflater = LayoutInflater.from(context);\n            View view = inflater.inflate(R.layout.capabilities_list_item, parent, false);\n\n            CapabilitiesItemViewHolder holder = new CapabilitiesItemViewHolder(view, cursor);\n            view.setTag(holder);\n            return view;\n        }\n\n        @Override\n        public void bindView(View view, Context context, Cursor cursor) {\n            CapabilitiesItemViewHolder holder = (CapabilitiesItemViewHolder) view.getTag();\n\n            // Set display name from number\n            String number = cursor.getString(holder.columnContact);\n            String displayName = rcsDisplayName.getDisplayName(number);\n            holder.numberText.setText(getString(R.string.label_contact_arg, displayName));\n\n            holder.imBox\n                    .setChecked(cursor.getInt(holder.columnCapabilityIm) == CapabilitiesLog.SUPPORTED);\n            holder.ftBox\n                    .setChecked(cursor.getInt(holder.columnCapabilityFileTransfer) == CapabilitiesLog.SUPPORTED);\n            holder.ishBox\n                    .setChecked(cursor.getInt(holder.columnCapabilityImageSharing) == CapabilitiesLog.SUPPORTED);\n            holder.vshBox\n                    .setChecked(cursor.getInt(holder.columnCapabilityVideoSharing) == CapabilitiesLog.SUPPORTED);\n            holder.geolocBox\n                    .setChecked(cursor.getInt(holder.columnCapabilityGeolocPush) == CapabilitiesLog.SUPPORTED);\n            String exts = cursor.getString(holder.columnCapabilityExtensions);\n            if (exts != null) {\n                exts = exts.replace(';', '\\n');\n            }\n            holder.extsText.setText(exts);\n            holder.automataBox\n                    .setChecked(cursor.getInt(holder.columnAutomata) == CapabilitiesLog.SUPPORTED);\n            long lastRefresh = cursor.getLong(holder.columnTimestamp);\n            if (lastRefresh == -1) {\n                holder.lastRefreshText.setVisibility(View.GONE);\n            } else {\n                holder.lastRefreshText.setVisibility(View.VISIBLE);\n                holder.lastRefreshText.setText(DateUtils.getRelativeTimeSpanString(lastRefresh,\n                        System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                        DateUtils.FORMAT_ABBREV_RELATIVE));\n            }\n        }\n    }\n\n    /**\n     * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n     * findViewById() or getColumnIndex() on each row.\n     */\n    private class CapabilitiesItemViewHolder {\n        public TextView numberText;\n\n        public final CheckBox imBox;\n\n        public final CheckBox ftBox;\n\n        public final CheckBox ishBox;\n\n        public final CheckBox vshBox;\n\n        public final CheckBox geolocBox;\n\n        public final TextView extsText;\n\n        public final CheckBox automataBox;\n\n        public final TextView lastRefreshText;\n\n        public final int columnContact;\n\n        public final int columnCapabilityIm;\n\n        public final int columnCapabilityImageSharing;\n\n        public final int columnCapabilityFileTransfer;\n\n        public final int columnCapabilityVideoSharing;\n\n        public final int columnCapabilityGeolocPush;\n\n        public final int columnCapabilityExtensions;\n\n        public final int columnAutomata;\n\n        public final int columnTimestamp;\n\n        CapabilitiesItemViewHolder(View base, Cursor cursor) {\n            columnContact = cursor.getColumnIndexOrThrow(CapabilitiesLog.CONTACT);\n            columnCapabilityIm = cursor\n                    .getColumnIndexOrThrow(CapabilitiesLog.CAPABILITY_IM_SESSION);\n            columnCapabilityFileTransfer = cursor\n                    .getColumnIndexOrThrow(CapabilitiesLog.CAPABILITY_FILE_TRANSFER);\n            columnCapabilityImageSharing = cursor\n                    .getColumnIndexOrThrow(CapabilitiesLog.CAPABILITY_IMAGE_SHARE);\n            columnCapabilityVideoSharing = cursor\n                    .getColumnIndexOrThrow(CapabilitiesLog.CAPABILITY_VIDEO_SHARE);\n            columnCapabilityGeolocPush = cursor\n                    .getColumnIndexOrThrow(CapabilitiesLog.CAPABILITY_GEOLOC_PUSH);\n            columnCapabilityExtensions = cursor\n                    .getColumnIndexOrThrow(CapabilitiesLog.CAPABILITY_EXTENSIONS);\n            columnAutomata = cursor.getColumnIndexOrThrow(CapabilitiesLog.AUTOMATA);\n            columnTimestamp = cursor.getColumnIndexOrThrow(CapabilitiesLog.TIMESTAMP);\n\n            numberText = (TextView) base.findViewById(R.id.number);\n            imBox = (CheckBox) base.findViewById(R.id.im);\n            ftBox = (CheckBox) base.findViewById(R.id.file_transfer);\n            ishBox = (CheckBox) base.findViewById(R.id.image_sharing);\n            vshBox = (CheckBox) base.findViewById(R.id.video_sharing);\n            geolocBox = (CheckBox) base.findViewById(R.id.geoloc_push);\n            extsText = (TextView) base.findViewById(R.id.extensions);\n            automataBox = (CheckBox) base.findViewById(R.id.automata);\n            lastRefreshText = (TextView) base.findViewById(R.id.last_refresh);\n        }\n\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/capabilities/MyCapabilities.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.capabilities;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.capability.Capabilities;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.widget.CheckBox;\nimport android.widget.TextView;\n\n/**\n * My capabilities\n */\npublic class MyCapabilities extends RcsActivity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.capabilities_mine);\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CAPABILITY)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CAPABILITY);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        try {\n            // Get the current capabilities from the RCS contacts API\n            Capabilities capabilities = getCapabilityApi().getMyCapabilities();\n            // Set capabilities\n            CheckBox imageCSh = (CheckBox) findViewById(R.id.image_sharing);\n            imageCSh.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_IMAGE_SHARING));\n            CheckBox videoCSh = (CheckBox) findViewById(R.id.video_sharing);\n            videoCSh.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_VIDEO_SHARING));\n            CheckBox ft = (CheckBox) findViewById(R.id.file_transfer);\n            ft.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_FILE_TRANSFER));\n            CheckBox im = (CheckBox) findViewById(R.id.im);\n            im.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_IM));\n            CheckBox geolocationPush = (CheckBox) findViewById(R.id.geoloc_push);\n            geolocationPush.setChecked(capabilities\n                    .hasCapabilities(Capabilities.CAPABILITY_GEOLOC_PUSH));\n            TextView extensions = (TextView) findViewById(R.id.extensions);\n            extensions.setText(RequestCapabilities.getExtensions(capabilities));\n            CheckBox automata = (CheckBox) findViewById(R.id.automata);\n            automata.setChecked(capabilities.isAutomata());\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/capabilities/RequestAllCapabilities.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.capabilities;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\n\n/**\n * Request capabilities of all contacts\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class RequestAllCapabilities extends RcsActivity {\n\n    private OnClickListener mBtnSyncListener;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        intialize();\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.capabilities_refresh);\n\n        /* Set buttons callback */\n        Button refreshBtn = (Button) findViewById(R.id.refresh_btn);\n        refreshBtn.setOnClickListener(mBtnSyncListener);\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CAPABILITY)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CAPABILITY);\n    }\n\n    private void intialize() {\n        mBtnSyncListener = new OnClickListener() {\n            public void onClick(View v) {\n                try {\n                    /* Check if the service is available */\n                    try {\n                        if (!getCapabilityApi().isServiceRegistered()) {\n                            showMessage(R.string.error_not_registered);\n                            return;\n                        }\n                    } catch (RcsServiceNotAvailableException e) {\n                        showMessage(R.string.label_service_not_available);\n                        return;\n                    }\n\n                    /* Refresh all contacts */\n                    getCapabilityApi().requestAllContactsCapabilities();\n\n                    /* Display message */\n                    Utils.displayLongToast(RequestAllCapabilities.this,\n                            getString(R.string.label_refresh_success));\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/capabilities/RequestCapabilities.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.capabilities;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.capability.CapabilitiesListener;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.text.format.DateUtils;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Refresh capabilities of a given contact\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RequestCapabilities extends RcsActivity {\n\n    private final Handler mHandler = new Handler();\n\n    private MyCapabilitiesListener mCapabilitiesListener = new MyCapabilitiesListener();\n\n    private static final String EXTENSION_SEPARATOR = \"\\n\";\n\n    private static final String LOGTAG = LogUtils.getTag(RequestCapabilities.class.getSimpleName());\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n\n    private OnClickListener mBtnRefreshListener;\n\n    private OnItemSelectedListener mListenerContact;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initialize();\n        /* Set layout */\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.capabilities_request);\n\n        /* Set the contact selector */\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        mSpinner.setAdapter(ContactListAdapter.createContactListAdapter(this));\n        mSpinner.setOnItemSelectedListener(mListenerContact);\n\n        /* Set button callback */\n        Button refreshBtn = (Button) findViewById(R.id.refresh_btn);\n        refreshBtn.setOnClickListener(mBtnRefreshListener);\n\n        /* Update refresh button */\n        if (mSpinner.getAdapter().getCount() == 0) {\n            // Disable button if no contact available\n            refreshBtn.setEnabled(false);\n        } else {\n            refreshBtn.setEnabled(true);\n        }\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CAPABILITY)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CAPABILITY);\n        try {\n            getCapabilityApi().addCapabilitiesListener(mCapabilitiesListener);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (isServiceConnected(RcsServiceName.CAPABILITY)) {\n            // Remove image sharing listener\n            try {\n                getCapabilityApi().removeCapabilitiesListener(mCapabilitiesListener);\n\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    /**\n     * Capabilities event listener\n     */\n    private class MyCapabilitiesListener extends CapabilitiesListener {\n        /**\n         * Callback called when new capabilities are received for a given contact\n         * \n         * @param contact Contact\n         * @param capabilities Capabilities\n         */\n        public void onCapabilitiesReceived(final ContactId contact, final Capabilities capabilities) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onCapabilitiesReceived \" + contact);\n            }\n            final ContactId selectedContact = getSelectedContact();\n            if (!contact.equals(selectedContact)) {\n                // Discard capabilities if not for selected contact\n                return;\n            }\n            mHandler.post(new Runnable() {\n                public void run() {\n                    // Check if this intent concerns the current selected\n                    // contact\n                    if (contact.equals(selectedContact)) {\n                        // Update UI\n                        displayCapabilities(capabilities);\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * Returns the selected contact\n     * \n     * @return Contact\n     */\n    private ContactId getSelectedContact() {\n        // get selected phone number\n        ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n        return ContactUtil.formatContact(adapter.getSelectedNumber(mSpinner.getSelectedView()));\n    }\n\n    private void updateCapabilities(ContactId contact) {\n        // Display info\n        Utils.displayLongToast(RequestCapabilities.this,\n                getString(R.string.label_request_in_background, contact));\n        try {\n            Set<ContactId> contactSet = new HashSet<>();\n            contactSet.add(contact);\n            getCapabilityApi().requestContactCapabilities(contactSet);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void displayCapabilities(Capabilities capabilities) {\n        CheckBox imageCSh = (CheckBox) findViewById(R.id.image_sharing);\n        CheckBox videoCSh = (CheckBox) findViewById(R.id.video_sharing);\n        CheckBox ft = (CheckBox) findViewById(R.id.file_transfer);\n        CheckBox im = (CheckBox) findViewById(R.id.im);\n        CheckBox geoloc = (CheckBox) findViewById(R.id.geoloc_push);\n        TextView extensions = (TextView) findViewById(R.id.extensions);\n        TextView timestamp = (TextView) findViewById(R.id.last_refresh);\n        CheckBox automata = (CheckBox) findViewById(R.id.automata);\n\n        if (capabilities != null) {\n            // Set capabilities\n            imageCSh.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_IMAGE_SHARING));\n            videoCSh.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_VIDEO_SHARING));\n            ft.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_FILE_TRANSFER));\n            im.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_IM));\n            geoloc.setChecked(capabilities.hasCapabilities(Capabilities.CAPABILITY_GEOLOC_PUSH));\n        }\n        // Set extensions\n        extensions.setVisibility(View.VISIBLE);\n        extensions.setText(getExtensions(capabilities));\n        automata.setChecked((capabilities != null) && capabilities.isAutomata());\n        timestamp.setText((capabilities != null) ? DateUtils.getRelativeTimeSpanString(\n                capabilities.getTimestamp(), System.currentTimeMillis(),\n                DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE) : \"\");\n    }\n\n    /* package private */static String getExtensions(Capabilities capabilities) {\n        if (capabilities == null || capabilities.getSupportedExtensions().isEmpty()) {\n            return \"\";\n        }\n        StringBuilder extensions = new StringBuilder();\n        for (String capability : capabilities.getSupportedExtensions()) {\n            extensions.append(EXTENSION_SEPARATOR).append(capability);\n        }\n        return extensions.substring(EXTENSION_SEPARATOR.length());\n    }\n\n    private void initialize() {\n        mBtnRefreshListener = new OnClickListener() {\n            public void onClick(View v) {\n                // Check if the service is available\n                try {\n                    if (!getCapabilityApi().isServiceRegistered()) {\n                        showMessage(R.string.error_not_registered);\n                        return;\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                    return;\n                }\n                ContactId contact = getSelectedContact();\n                if (contact != null) {\n                    updateCapabilities(contact);\n                }\n            }\n        };\n\n        mListenerContact = new OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                CapabilityService capabilityApi = getCapabilityApi();\n                try {\n                    // Get selected contact\n                    ContactId contactId = getSelectedContact();\n\n                    // Get current capabilities\n                    Capabilities currentCapabilities = capabilityApi\n                            .getContactCapabilities(contactId);\n                    // Display default capabilities\n                    displayCapabilities(currentCapabilities);\n                    if (currentCapabilities == null) {\n                        Utils.displayLongToast(RequestCapabilities.this,\n                                getString(R.string.label_no_capabilities, contactId.toString()));\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> arg0) {\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/capabilities/TestCapabilitiesApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.capabilities;\n\nimport com.gsma.rcs.ri.R;\n\nimport android.app.ListActivity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * Capabilities API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestCapabilitiesApi extends ListActivity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        String[] items = {\n                getString(R.string.menu_my_capabilities),\n                getString(R.string.menu_capabilities_request),\n                getString(R.string.menu_refresh_capabilities),\n                getString(R.string.menu_capabilities_log)\n        };\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, MyCapabilities.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, RequestCapabilities.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, RequestAllCapabilities.class));\n                break;\n\n            case 3:\n                startActivity(new Intent(this, CapabilitiesList.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/contacts/BlockingContact.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.contacts;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.Spinner;\nimport android.widget.ToggleButton;\n\n/**\n * Block/unblock a contact\n * \n * @author Jean-Marc AUFFRET\n */\npublic class BlockingContact extends RcsActivity {\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n\n    private ToggleButton mToggleBtn;\n\n    private OnClickListener mToggleListener;\n\n    private OnItemSelectedListener mListenerContact;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initialize();\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.contacts_blocking);\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CONTACT);\n\n        // Set the contact selector\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        ContactListAdapter adapter = ContactListAdapter.createRcsContactListAdapter(this);\n        mSpinner.setAdapter(adapter);\n        mSpinner.setOnItemSelectedListener(mListenerContact);\n\n        // Set button callback\n        mToggleBtn = (ToggleButton) findViewById(R.id.block_btn);\n        mToggleBtn.setOnClickListener(mToggleListener);\n\n        // Update refresh button\n        if (mSpinner.getAdapter().getCount() == 0) {\n            // Disable button if no contact available\n            mToggleBtn.setEnabled(false);\n        } else {\n            mToggleBtn.setEnabled(true);\n        }\n    }\n\n    private void updateBlockingState(ContactId contactId) {\n        try {\n            RcsContact contact = getContactApi().getRcsContact(contactId);\n            mToggleBtn.setChecked(contact.isBlocked());\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private ContactId getSelectedContact() {\n        // get selected phone number\n        ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n        return ContactUtil.formatContact(adapter.getSelectedNumber(mSpinner.getSelectedView()));\n    }\n\n    private void initialize() {\n        mToggleListener = new OnClickListener() {\n            public void onClick(View view) {\n                try {\n                    ContactId contact = getSelectedContact();\n                    if (mToggleBtn.isChecked()) {\n                        // Block the contact\n                        getContactApi().blockContact(contact);\n                        Utils.displayToast(BlockingContact.this,\n                                getString(R.string.label_contact_blocked, contact.toString()));\n                    } else {\n                        // Unblock the contact\n                        getContactApi().unblockContact(contact);\n                        Utils.displayToast(BlockingContact.this,\n                                getString(R.string.label_contact_unblocked, contact.toString()));\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n\n        mListenerContact = new OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                ContactId contactId = getSelectedContact();\n                updateBlockingState(contactId);\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> arg0) {\n            }\n        };\n\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/contacts/ContactVCard.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.contacts;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.provider.ContactsContract;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.Button;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.io.File;\n\n/**\n * Display contact VCard\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ContactVCard extends RcsActivity {\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.contacts_vcard);\n\n        // Set the contact selector\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        mSpinner.setAdapter(ContactListAdapter.createContactListAdapter(this));\n        mSpinner.setOnItemSelectedListener(listenerContact);\n\n        // Set button callback\n        Button showBtn = (Button) findViewById(R.id.show_btn);\n        showBtn.setOnClickListener(btnShowListener);\n    }\n\n    /**\n     * Spinner contact listener\n     */\n    private OnItemSelectedListener listenerContact = new OnItemSelectedListener() {\n        @Override\n        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n            // Get selected contact\n            String contact = getSelectedContact();\n\n            // Update UI\n            displayVisitCard(contact);\n        }\n\n        @Override\n        public void onNothingSelected(AdapterView<?> arg0) {\n        }\n    };\n\n    /**\n     * Returns the selected contact\n     * \n     * @return Contact\n     */\n    private String getSelectedContact() {\n        // get selected phone number\n        ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n        return adapter.getSelectedNumber(mSpinner.getSelectedView());\n    }\n\n    /**\n     * Display the visit card\n     * \n     * @param contact Contact\n     */\n    private void displayVisitCard(String contact) {\n        try {\n            Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,\n                    Uri.encode(contact));\n            Uri vcard = ContactUtil.getInstance(this).getVCard(contactUri);\n            TextView vcardView = (TextView) findViewById(R.id.vcard);\n            vcardView.setText(vcard.getPath());\n        } catch (RcsGenericException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    /**\n     * Show button listener\n     */\n    private OnClickListener btnShowListener = new OnClickListener() {\n        public void onClick(View v) {\n            // Get filename\n            TextView vcardView = (TextView) findViewById(R.id.vcard);\n            String filename = vcardView.getText().toString();\n\n            // Show the transferred vCard\n            File file = new File(filename);\n            Uri uri = Uri.fromFile(file);\n            Intent intent = new Intent(Intent.ACTION_VIEW);\n            intent.setDataAndType(uri, \"text/plain\");\n            startActivity(intent);\n        }\n    };\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/contacts/RcsContactsList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.contacts;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsListActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.content.Context;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.text.format.DateUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.CheckBox;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * List of RCS contacts\n *\n * @author Philippe LEMORDANT\n * @author Jean-Marc AUFFRET\n */\npublic class RcsContactsList extends RcsListActivity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.contacts_rcs_list);\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CONTACT);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        updateList();\n    }\n\n    private void updateList() {\n        try {\n            Set<RcsContact> allContacts = getContactApi().getRcsContacts();\n            List<RcsContact> contacts = new ArrayList<>(allContacts);\n            if (contacts.size() > 0) {\n                ContactArrayAdapter adapter = new ContactArrayAdapter(this,\n                        R.layout.contact_list_item, contacts);\n                setListAdapter(adapter);\n            } else {\n                setListAdapter(null);\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private class ContactArrayAdapter extends ArrayAdapter<RcsContact> {\n\n        private final Context mCtx;\n        private final int mResourceRowLayout;\n        private final RcsContactUtil mRcsContactUtil;\n        private final LayoutInflater mInflater;\n\n        public ContactArrayAdapter(Context ctx, int resourceRowLayout, List<RcsContact> items) {\n            super(ctx, 0, items);\n            mCtx = ctx;\n            mResourceRowLayout = resourceRowLayout;\n            mInflater = LayoutInflater.from(mCtx);\n            mRcsContactUtil = RcsContactUtil.getInstance(mCtx);\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            final CapabilitiesItemViewHolder holder;\n            if (convertView == null) {\n                convertView = mInflater.inflate(mResourceRowLayout, parent, false);\n                holder = new CapabilitiesItemViewHolder(convertView);\n                convertView.setTag(holder);\n            } else {\n                holder = (CapabilitiesItemViewHolder) convertView.getTag();\n            }\n            RcsContact item = getItem(position);\n            if (item != null) {\n                String displayName = mRcsContactUtil.getDisplayName(item.getContactId());\n                holder.numberText.setText(getString(R.string.label_contact_arg, displayName));\n                Capabilities capa = item.getCapabilities();\n                holder.imBox.setChecked(capa.hasCapabilities(Capabilities.CAPABILITY_IM));\n                holder.ftBox\n                        .setChecked(capa.hasCapabilities(Capabilities.CAPABILITY_FILE_TRANSFER));\n                holder.ishBox.setChecked(capa\n                        .hasCapabilities(Capabilities.CAPABILITY_IMAGE_SHARING));\n                holder.vshBox.setChecked(capa\n                        .hasCapabilities(Capabilities.CAPABILITY_VIDEO_SHARING));\n                holder.geolocBox.setChecked(capa\n                        .hasCapabilities(Capabilities.CAPABILITY_GEOLOC_PUSH));\n                holder.extsText.setText(capa.getSupportedExtensions().toString());\n                holder.automataBox.setChecked(capa.isAutomata());\n                long lastRefresh = capa.getTimestamp();\n                if (lastRefresh == -1) {\n                    holder.lastRefreshText.setVisibility(View.GONE);\n                } else {\n                    holder.lastRefreshText.setVisibility(View.VISIBLE);\n                    holder.lastRefreshText.setText(DateUtils.getRelativeTimeSpanString(lastRefresh,\n                            System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                            DateUtils.FORMAT_ABBREV_RELATIVE));\n                }\n                holder.onLineBox.setChecked(item.isOnline());\n                boolean blocked = item.isBlocked();\n                holder.blockedBox.setChecked(blocked);\n                long blockingTime = item.getBlockingTimestamp();\n                if (!blocked) {\n                    holder.blockingTimeText.setVisibility(View.GONE);\n                } else {\n                    holder.blockingTimeText.setVisibility(View.VISIBLE);\n                    holder.blockingTimeText.setText(DateUtils.getRelativeTimeSpanString(\n                            blockingTime, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                            DateUtils.FORMAT_ABBREV_RELATIVE));\n                }\n            }\n            return convertView;\n        }\n    }\n\n    /**\n     * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n     * findViewById().\n     */\n    private class CapabilitiesItemViewHolder {\n        public final CheckBox onLineBox;\n        public final CheckBox blockedBox;\n        public final TextView blockingTimeText;\n        public final TextView numberText;\n        public final CheckBox imBox;\n        public final CheckBox ftBox;\n        public final CheckBox ishBox;\n        public final CheckBox vshBox;\n        public final CheckBox geolocBox;\n        public final TextView extsText;\n        public final CheckBox automataBox;\n        public final TextView lastRefreshText;\n\n        CapabilitiesItemViewHolder(View base) {\n            numberText = (TextView) base.findViewById(R.id.number);\n            imBox = (CheckBox) base.findViewById(R.id.im);\n            ftBox = (CheckBox) base.findViewById(R.id.file_transfer);\n            ishBox = (CheckBox) base.findViewById(R.id.image_sharing);\n            vshBox = (CheckBox) base.findViewById(R.id.video_sharing);\n            geolocBox = (CheckBox) base.findViewById(R.id.geoloc_push);\n            extsText = (TextView) base.findViewById(R.id.extensions);\n            automataBox = (CheckBox) base.findViewById(R.id.automata);\n            lastRefreshText = (TextView) base.findViewById(R.id.last_refresh);\n            onLineBox = (CheckBox) base.findViewById(R.id.is_online);\n            blockedBox = (CheckBox) base.findViewById(R.id.is_blocked);\n            blockingTimeText = (TextView) base.findViewById(R.id.block_timestamp);\n        }\n\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/contacts/TestContactsApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.contacts;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsListActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.provider.ContactsContract;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * CONTACTS API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestContactsApi extends RcsListActivity {\n\n    private static final String LOGTAG = LogUtils.getTag(TestContactsApi.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        String[] items = {\n                getString(R.string.menu_address_book), getString(R.string.menu_list_rcs_contacts),\n                getString(R.string.menu_contact_vcard), getString(R.string.menu_blocking_contact)\n        };\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                try {\n                    startActivity(new Intent(Intent.ACTION_VIEW)\n                            .setType(ContactsContract.Contacts.CONTENT_TYPE));\n\n                } catch (ActivityNotFoundException e1) {\n                    try {\n                        startActivity(new Intent(\"com.android.contacts.action.LIST_DEFAULT\"));\n\n                    } catch (ActivityNotFoundException e2) {\n                        Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e2));\n                        showMessage(R.string.label_ab_not_found);\n                    }\n                }\n                break;\n\n            case 1:\n                startActivity(new Intent(this, RcsContactsList.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, ContactVCard.class));\n                break;\n\n            case 3:\n                startActivity(new Intent(this, BlockingContact.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/InitiateMultimediaSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.Activity;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.Spinner;\n\n/**\n * Abstract class to initiate a multimedia session\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class InitiateMultimediaSession extends Activity {\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.extension_initiate_session);\n\n        // Set contact selector\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        mSpinner.setAdapter(ContactListAdapter.createContactListAdapter(this));\n\n        // Set buttons callback\n        Button initiateBtn = (Button) findViewById(R.id.initiate_btn);\n        initiateBtn.setOnClickListener(btnInitiateListener);\n\n        // Disable button if no contact available\n        if (mSpinner.getAdapter().getCount() == 0) {\n            initiateBtn.setEnabled(false);\n        }\n    }\n\n    /**\n     * Initiate button callback\n     */\n    private OnClickListener btnInitiateListener = new OnClickListener() {\n        public void onClick(View v) {\n            // get selected phone number\n            ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n            String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n            ContactId contact = ContactUtil.formatContact(phoneNumber);\n            // Initiate session\n            initiateSession(contact);\n            // Exit activity\n            finish();\n        }\n    };\n\n    /**\n     * Initiate session\n     * \n     * @param contact Remote contact\n     */\n    public abstract void initiateSession(ContactId contact);\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/InstantMessageReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.InstantMultimediaMessageIntent;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.Log;\n\n/**\n * Messaging session invitation receiver\n *\n * @author jmauffret\n */\npublic class InstantMessageReceiver extends BroadcastReceiver {\n    private static final String LOGTAG = LogUtils.getTag(InstantMessageReceiver.class\n            .getSimpleName());\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        String action = intent.getAction();\n        if (!InstantMultimediaMessageIntent.ACTION_NEW_INSTANT_MESSAGE.equals(action)) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Unknown action=\" + action);\n            }\n            return;\n        }\n\n        /* Display instant message content */\n        String content = new String(\n                intent.getByteArrayExtra(InstantMultimediaMessageIntent.EXTRA_CONTENT));\n        ContactId contact = intent.getParcelableExtra(InstantMultimediaMessageIntent.EXTRA_CONTACT);\n        String displayName = RcsContactUtil.getInstance(context).getDisplayName(contact);\n        Utils.displayLongToast(context,\n                context.getString(R.string.label_recv_instant_messsage, displayName) + \"\\n\"\n                        + content);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/MultiMediaSessionIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.extension.messaging.MessagingSessionView;\nimport com.gsma.rcs.ri.extension.streaming.StreamingSessionView;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSession;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSessionIntent;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSession;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSessionIntent;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.media.RingtoneManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\n/**\n * Process the MultiMedia Session invitation<br>\n * Purpose is to retrieve the contactId from the service to build the notification.\n * \n * @author YPLO6403\n */\npublic class MultiMediaSessionIntentService extends IntentService {\n\n    private String mSessionId;\n\n    private boolean mMultimediaMessagingSession = false;\n\n    private ConnectionManager mCnxManager;\n\n    private static final String LOGTAG = LogUtils.getTag(MultiMediaSessionIntentService.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     */\n    public MultiMediaSessionIntentService() {\n        super(\"MultiMediaSessionIntentService\");\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        /*\n         * We want this service to stop running if forced stop so return not sticky.\n         */\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n\n        if (MultimediaMessagingSessionIntent.ACTION_NEW_INVITATION.equals(action)) {\n            mMultimediaMessagingSession = true;\n        } else {\n            if (!MultimediaStreamingSessionIntent.ACTION_NEW_INVITATION.equals(action)) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Unknown action=\".concat(action));\n                }\n                return;\n            }\n        }\n        /* Since there is no provider associated to multimedia sessions, we must connect to the API */\n        mCnxManager = ConnectionManager.getInstance();\n        if (!mCnxManager.isServiceConnected(RcsServiceName.MULTIMEDIA)) {\n            return;\n        }\n        // Get invitation info\n        mSessionId = intent.getStringExtra(MultimediaMessagingSessionIntent.EXTRA_SESSION_ID);\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onHandleIntent sessionId=\".concat(mSessionId));\n        }\n        initiateSession(intent);\n    }\n\n    private void initiateSession(Intent intent) {\n        try {\n            if (mMultimediaMessagingSession) {\n                MultimediaMessagingSession mms = mCnxManager.getMultimediaSessionApi()\n                        .getMessagingSession(mSessionId);\n                if (mms != null) {\n                    addSessionInvitationNotification(intent, mms.getRemoteContact());\n                } else {\n                    if (LogUtils.isActive) {\n                        Log.w(LOGTAG, \"Cannot get messaging session for ID \".concat(mSessionId));\n                    }\n                }\n            } else {\n                MultimediaStreamingSession mss = mCnxManager.getMultimediaSessionApi()\n                        .getStreamingSession(mSessionId);\n                if (mss != null) {\n                    addSessionInvitationNotification(intent, mss.getRemoteContact());\n                } else {\n                    if (LogUtils.isActive) {\n                        Log.w(LOGTAG, \"Cannot get streaming session for ID \".concat(mSessionId));\n                    }\n                }\n            }\n        } catch (RcsServiceException e) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot get MM API\", e);\n            }\n        }\n    }\n\n    private void addSessionInvitationNotification(Intent intent, ContactId contact) {\n        /* Create pending intent */\n        Intent invitation = new Intent(intent);\n        String title;\n        if (mMultimediaMessagingSession) {\n            invitation.setClass(this, MessagingSessionView.class);\n            title = getString(R.string.title_recv_messaging_session);\n        } else {\n            invitation.setClass(this, StreamingSessionView.class);\n            title = getString(R.string.title_recv_streaming_session);\n        }\n        invitation.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        /*\n         * If the PendingIntent has the same operation, action, data, categories, components, and\n         * flags it will be replaced. Invitation should be notified individually so we use a random\n         * generator to provide a unique request code and reuse it for the notification.\n         */\n        int uniqueId = Utils.getUniqueIdForPendingIntent();\n        PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, invitation,\n                PendingIntent.FLAG_ONE_SHOT);\n\n        String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n\n        /* Create notification */\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(contentIntent);\n        notif.setSmallIcon(R.drawable.ri_notif_mm_session_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(title);\n        notif.setContentText(getString(R.string.label_from_args, displayName));\n\n        /* Send notification */\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(uniqueId, notif.build());\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/MultimediaSessionList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsListActivity;\nimport com.gsma.rcs.ri.R;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ListView;\n\n/**\n * Abstract list of multimedia sessions\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class MultimediaSessionList extends RcsListActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.extension_session_list);\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.MULTIMEDIA)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.MULTIMEDIA);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        updateList();\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        super.onListItemClick(l, v, position, id);\n        displaySession(position);\n    }\n\n    /**\n     * Display a session\n     * \n     * @param position position\n     */\n    public abstract void displaySession(int position);\n\n    /**\n     * Update the displayed list\n     */\n    public abstract void updateList();\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/SendInstantMessage.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.extension.messaging.MessagingSessionUtils;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.Spinner;\n\n/**\n * Send an instant multimedia message\n *\n * @author Jean-Marc AUFFRET\n */\npublic class SendInstantMessage extends RcsActivity {\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.extension_send_instant_message);\n\n        // Set contact selector\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        mSpinner.setAdapter(ContactListAdapter.createContactListAdapter(this));\n\n        // Set buttons callback\n        Button sendBtn = (Button) findViewById(R.id.send_btn);\n        sendBtn.setOnClickListener(btnSendListener);\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(ConnectionManager.RcsServiceName.MULTIMEDIA,\n                ConnectionManager.RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(ConnectionManager.RcsServiceName.MULTIMEDIA,\n                ConnectionManager.RcsServiceName.CONTACT);\n\n        // Disable button if no contact available\n        if (mSpinner.getAdapter().getCount() == 0) {\n            sendBtn.setEnabled(false);\n        }\n    }\n\n    /**\n     * Send button callback\n     */\n    private View.OnClickListener btnSendListener = new View.OnClickListener() {\n        public void onClick(View v) {\n            // get selected phone number\n            ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n            String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n            ContactId contact = ContactUtil.formatContact(phoneNumber);\n            // Initiate session\n            sendMessage(contact);\n        }\n    };\n\n    /**\n     * Send message to a remote contact\n     *\n     * @param contact Remote contact\n     */\n    public void sendMessage(ContactId contact) {\n        try {\n            String content = \"Hello world\";\n            getMultimediaSessionApi().sendInstantMultimediaMessage(\n                    MessagingSessionUtils.SERVICE_ID, contact, content.getBytes(),\n                    MessagingSessionUtils.SERVICE_CONTENT_TYPE);\n            Utils.displayToast(this, getString(R.string.label_instant_message_sent));\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/SessionInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Messaging session invitation receiver\n * \n * @author Jean-Marc AUFFRET\n */\npublic class SessionInvitationReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent invitation) {\n        invitation.setClass(context, MultiMediaSessionIntentService.class);\n        context.startService(invitation);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/TestMultimediaSessionApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.extension.messaging.InitiateMessagingSession;\nimport com.gsma.rcs.ri.extension.messaging.MessagingSessionList;\nimport com.gsma.rcs.ri.extension.streaming.InitiateStreamingSession;\nimport com.gsma.rcs.ri.extension.streaming.StreamingSessionList;\n\nimport android.app.ListActivity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * MM session API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestMultimediaSessionApi extends ListActivity {\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        String[] items = {\n                getString(R.string.menu_initiate_messaging_session),\n                getString(R.string.menu_messaging_sessions_list),\n                getString(R.string.menu_initiate_streaming_session),\n                getString(R.string.menu_streaming_sessions_list),\n                getString(R.string.menu_instant_message)\n\n        };\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, InitiateMessagingSession.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, MessagingSessionList.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, InitiateStreamingSession.class));\n                break;\n\n            case 3:\n                startActivity(new Intent(this, StreamingSessionList.class));\n                break;\n\n            case 4:\n                startActivity(new Intent(this, SendInstantMessage.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/messaging/InitiateMessagingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.messaging;\n\nimport com.gsma.rcs.ri.extension.InitiateMultimediaSession;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\nimport android.os.Parcelable;\n\n/**\n * Initiate messaging session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class InitiateMessagingSession extends InitiateMultimediaSession {\n\n    /**\n     * Initiate session\n     * \n     * @param contact Remote contact\n     */\n    public void initiateSession(ContactId contact) {\n        // Display session view\n        Intent intent = new Intent(InitiateMessagingSession.this, MessagingSessionView.class);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(MessagingSessionView.EXTRA_MODE, MessagingSessionView.MODE_OUTGOING);\n        intent.putExtra(MessagingSessionView.EXTRA_CONTACT, (Parcelable) contact);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/messaging/MessagingSessionList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.messaging;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.extension.MultimediaSessionList;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSession;\n\nimport android.content.Intent;\nimport android.widget.ArrayAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * List of messaging sessions in progress\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MessagingSessionList extends MultimediaSessionList {\n    /**\n     * List of sessions\n     */\n    private List<MultimediaMessagingSession> sessions = new ArrayList<>();\n\n    /**\n     * Display a session\n     * \n     * @param position position\n     */\n    public void displaySession(int position) {\n        try {\n            Intent intent = new Intent(this, MessagingSessionView.class);\n            String sessionId = sessions.get(position).getSessionId();\n            intent.putExtra(MessagingSessionView.EXTRA_MODE, MessagingSessionView.MODE_OPEN);\n            intent.putExtra(MessagingSessionView.EXTRA_SESSION_ID, sessionId);\n            startActivity(intent);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    /**\n     * Update the displayed list\n     */\n    public void updateList() {\n        try {\n            // Reset the list\n            sessions.clear();\n\n            // Get list of pending sessions\n            Set<MultimediaMessagingSession> currentSessions = getMultimediaSessionApi()\n                    .getMessagingSessions(MessagingSessionUtils.SERVICE_ID);\n            sessions = new ArrayList<>(currentSessions);\n            if (sessions.size() > 0) {\n                String[] items = new String[sessions.size()];\n                for (int i = 0; i < items.length; i++) {\n                    items[i] = getString(R.string.label_session, sessions.get(i).getSessionId());\n                }\n                setListAdapter(new ArrayAdapter<>(MessagingSessionList.this,\n                        android.R.layout.simple_list_item_1, items));\n            } else {\n                setListAdapter(null);\n            }\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/messaging/MessagingSessionUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.messaging;\n\n/**\n * Messaging service utils\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MessagingSessionUtils {\n    /**\n     * Service ID constant\n     */\n    public final static String SERVICE_ID = \"ext.messaging\";\n\n    /**\n     * Service content type\n     */\n    public final static String SERVICE_CONTENT_TYPE = \"plain/text\";\n\n    /**\n     * Service accept-type\n     */\n    public final static String[] SERVICE_ACCEPT_TYPE = {\n        \"plain/text\"\n    };\n\n    /**\n     * Service accept-wrapped-type\n     */\n    public final static String[] SERVICE_WRAPPED_ACCEPT_TYPE = {\n    // no wrapped here\n    };\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/messaging/MessagingSessionView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.messaging;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSession;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSessionIntent;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSessionListener;\nimport com.gsma.services.rcs.extension.MultimediaSession;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.extension.MultimediaSessionServiceConfiguration;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnCancelListener;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\n/**\n * Messaging session view\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class MessagingSessionView extends RcsActivity {\n    /**\n     * View mode: incoming session\n     */\n    public final static int MODE_INCOMING = 0;\n\n    /**\n     * View mode: outgoing session\n     */\n    public final static int MODE_OUTGOING = 1;\n\n    /**\n     * View mode: open session history\n     */\n    public final static int MODE_OPEN = 2;\n\n    /**\n     * Intent parameter: view mode\n     */\n    public final static String EXTRA_MODE = \"mode\";\n\n    /**\n     * Intent parameter: session ID\n     */\n    public final static String EXTRA_SESSION_ID = \"session_id\";\n\n    /**\n     * Intent parameter: contact\n     */\n    public final static String EXTRA_CONTACT = \"contact\";\n\n    private final Handler mHandler = new Handler();\n\n    private String mSessionId;\n\n    private ContactId mContact;\n\n    private String mServiceId = MessagingSessionUtils.SERVICE_ID;\n\n    private MultimediaMessagingSession mSession;\n\n    private Dialog mProgressDialog;\n\n    private android.view.View.OnClickListener mBtnSendListener;\n\n    private MultimediaMessagingSessionListener mServiceListener;\n\n    private OnClickListener mAcceptBtnListener;\n\n    private OnClickListener mDeclineBtnListener;\n\n    private static final String LOGTAG = LogUtils\n            .getTag(MessagingSessionView.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initialize();\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.extension_messaging_session_view);\n\n        /* Set buttons callback */\n        Button sendBtn = (Button) findViewById(R.id.send_btn);\n        sendBtn.setOnClickListener(mBtnSendListener);\n        sendBtn.setEnabled(false);\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.MULTIMEDIA, RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.MULTIMEDIA, RcsServiceName.CONTACT);\n        try {\n            getMultimediaSessionApi().addEventListener(mServiceListener);\n            initialiseMessagingSession(getIntent());\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (isServiceConnected(RcsServiceName.MULTIMEDIA)) {\n            try {\n                getMultimediaSessionApi().removeEventListener(mServiceListener);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    private void acceptInvitation() {\n        try {\n            mSession.acceptInvitation();\n            /*\n             * Wait for the SIP-ACK to allow the user to send message once session is established.\n             */\n            showProgressDialog();\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void rejectInvitation() {\n        try {\n            mSession.rejectInvitation();\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void initialiseMessagingSession(Intent intent) {\n        MultimediaSessionService sessionApi = getMultimediaSessionApi();\n        try {\n            MultimediaSessionServiceConfiguration config = sessionApi.getConfiguration();\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG,\n                        \"MessageMaxLength: \".concat(Integer.toString(config.getMessageMaxLength())));\n            }\n            int mode = intent.getIntExtra(MessagingSessionView.EXTRA_MODE, -1);\n            if (mode == MessagingSessionView.MODE_OUTGOING) {\n                /* Outgoing session: Check if the service is available. */\n                if (!sessionApi.isServiceRegistered()) {\n                    showMessageThenExit(R.string.error_not_registered);\n                    return;\n                }\n                mContact = intent.getParcelableExtra(MessagingSessionView.EXTRA_CONTACT);\n                startSession();\n                if (mSession == null) {\n                    return;\n                }\n\n            } else if (mode == MessagingSessionView.MODE_OPEN) {\n                /* Open existing session. */\n                mSessionId = intent.getStringExtra(MessagingSessionView.EXTRA_SESSION_ID);\n                mSession = sessionApi.getMessagingSession(mSessionId);\n                if (mSession == null) {\n                    showMessageThenExit(R.string.label_session_has_expired);\n                    return;\n                }\n                mContact = mSession.getRemoteContact();\n\n            } else {\n                /* Incoming session from its Intent */\n                mSessionId = intent\n                        .getStringExtra(MultimediaMessagingSessionIntent.EXTRA_SESSION_ID);\n                mSession = sessionApi.getMessagingSession(mSessionId);\n                if (mSession == null) {\n                    showMessageThenExit(R.string.label_session_has_expired);\n                    return;\n                }\n                mContact = mSession.getRemoteContact();\n                String from = RcsContactUtil.getInstance(this).getDisplayName(mContact);\n\n                /* Manual accept */\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.title_messaging_session);\n                builder.setMessage(getString(R.string.label_mm_from_id, from, mServiceId));\n                builder.setCancelable(false);\n                builder.setIcon(R.drawable.ri_notif_mm_session_icon);\n                builder.setPositiveButton(R.string.label_accept, mAcceptBtnListener);\n                builder.setNegativeButton(R.string.label_decline, mDeclineBtnListener);\n                registerDialog(builder.show());\n            }\n            /* Display session info */\n            TextView featureTagEdit = (TextView) findViewById(R.id.feature_tag);\n            featureTagEdit.setText(mServiceId);\n            String from = RcsContactUtil.getInstance(this).getDisplayName(mContact);\n            TextView contactEdit = (TextView) findViewById(R.id.contact);\n            contactEdit.setText(from);\n            Button sendBtn = (Button) findViewById(R.id.send_btn);\n\n            if (MultimediaSession.State.STARTED == mSession.getState()) {\n                sendBtn.setEnabled(true);\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void startSession() {\n        try {\n            mSession = getMultimediaSessionApi().initiateMessagingSession(mServiceId, mContact,\n                    MessagingSessionUtils.SERVICE_ACCEPT_TYPE,\n                    MessagingSessionUtils.SERVICE_WRAPPED_ACCEPT_TYPE);\n            mSessionId = mSession.getSessionId();\n            showProgressDialog();\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void showProgressDialog() {\n        mProgressDialog = showProgressDialog(getString(R.string.label_command_in_progress));\n        mProgressDialog.setOnCancelListener(new OnCancelListener() {\n            public void onCancel(DialogInterface dialog) {\n                Toast.makeText(MessagingSessionView.this,\n                        getString(R.string.label_session_canceled), Toast.LENGTH_SHORT).show();\n                quitSession();\n            }\n        });\n    }\n\n    private void hideProgressDialog() {\n        if (mProgressDialog != null && mProgressDialog.isShowing()) {\n            mProgressDialog.dismiss();\n            mProgressDialog = null;\n        }\n    }\n\n    private void quitSession() {\n        try {\n            if (mSession != null && RcsSessionUtil.isAllowedToAbortMultimediaSession(mSession)) {\n                mSession.abortSession();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mSession = null;\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            if (mSession != null) {\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        // Quit the session\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                                finish();\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n\n            } else {\n                finish();\n            }\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_mm_session, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void initialize() {\n        mBtnSendListener = new android.view.View.OnClickListener() {\n            private int i = 0;\n\n            public void onClick(View v) {\n                try {\n                    String data = \"data\".concat(String.valueOf(i++));\n                    mSession.sendMessage(data.getBytes(),\n                            MessagingSessionUtils.SERVICE_CONTENT_TYPE);\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n\n        mServiceListener = new MultimediaMessagingSessionListener() {\n\n            @Override\n            public void onStateChanged(ContactId contact, String sessionId,\n                    final MultimediaSession.State state, MultimediaSession.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" sessionId=\" + sessionId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current sessionId */\n                if (mSessionId == null || !mSessionId.equals(sessionId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sMultimediaReasonCodes[reasonCode.toInt()];\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        switch (state) {\n                            case STARTED:\n                                /* Session is established: hide progress dialog */\n                                hideProgressDialog();\n                                /* Activate the send button */\n                                Button sendBtn = (Button) findViewById(R.id.send_btn);\n                                sendBtn.setEnabled(true);\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_session_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_session_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_session_failed,\n                                        _reasonCode));\n                                break;\n\n                            default:\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG,\n                                            \"onStateChanged \"\n                                                    + getString(R.string.label_mms_state_changed,\n                                                            RiApplication.sMultimediaStates[state\n                                                                    .toInt()], _reasonCode));\n                                }\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onMessageReceived(ContactId contact, String sessionId, byte[] content) {\n                // Deprecated since TAPI 1.6\n            }\n\n            @Override\n            public void onMessageReceived(ContactId contact, String sessionId, byte[] content,\n                    String contentType) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessageReceived contact=\" + contact + \" sessionId=\"\n                            + sessionId);\n                }\n                /* Discard event if not for current sessionId */\n                if (mSessionId == null || !mSessionId.equals(sessionId)) {\n                    return;\n                }\n                final String data = new String(content);\n\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        /* Display received data */\n                        TextView txt = (TextView) MessagingSessionView.this\n                                .findViewById(R.id.recv_data);\n                        txt.setText(data);\n                    }\n                });\n            }\n\n            @Override\n            public void onMessagesFlushed(ContactId contact, String sessionId) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessagesFlushed contact=\" + contact + \" sessionId=\"\n                            + sessionId);\n                }\n            }\n        };\n\n        mAcceptBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                acceptInvitation();\n            }\n        };\n\n        mDeclineBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                rejectInvitation();\n                /* Exit activity */\n                finish();\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/streaming/InitiateStreamingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.streaming;\n\nimport com.gsma.rcs.ri.extension.InitiateMultimediaSession;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\nimport android.os.Parcelable;\n\n/**\n * Initiate streaming session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class InitiateStreamingSession extends InitiateMultimediaSession {\n\n    /**\n     * Initiate session\n     * \n     * @param contact Remote contact\n     */\n    public void initiateSession(ContactId contact) {\n        // Display session view\n        Intent intent = new Intent(InitiateStreamingSession.this, StreamingSessionView.class);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(StreamingSessionView.EXTRA_MODE, StreamingSessionView.MODE_OUTGOING);\n        intent.putExtra(StreamingSessionView.EXTRA_CONTACT, (Parcelable) contact);\n        startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/streaming/StreamingSessionList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.streaming;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.extension.MultimediaSessionList;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSession;\n\nimport android.content.Intent;\nimport android.widget.ArrayAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * List of streaming sessions in progress\n * \n * @author Jean-Marc AUFFRET\n */\npublic class StreamingSessionList extends MultimediaSessionList {\n    /**\n     * List of sessions\n     */\n    private List<MultimediaStreamingSession> sessions = new ArrayList<>();\n\n    /**\n     * Display a session\n     * \n     * @param position position\n     */\n    public void displaySession(int position) {\n        try {\n            Intent intent = new Intent(this, StreamingSessionView.class);\n            String sessionId = sessions.get(position).getSessionId();\n            intent.putExtra(StreamingSessionView.EXTRA_MODE, StreamingSessionView.MODE_OPEN);\n            intent.putExtra(StreamingSessionView.EXTRA_SESSION_ID, sessionId);\n            startActivity(intent);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    /**\n     * Update the displayed list\n     */\n    public void updateList() {\n        try {\n            // Reset the list\n            sessions.clear();\n\n            // Get list of pending sessions\n            Set<MultimediaStreamingSession> currentSessions = getMultimediaSessionApi()\n                    .getStreamingSessions(StreamingSessionUtils.SERVICE_ID);\n            sessions = new ArrayList<>(currentSessions);\n            if (sessions.size() > 0) {\n                String[] items = new String[sessions.size()];\n                for (int i = 0; i < items.length; i++) {\n                    items[i] = getString(R.string.label_session, sessions.get(i).getSessionId());\n                }\n                setListAdapter(new ArrayAdapter<>(StreamingSessionList.this,\n                        android.R.layout.simple_list_item_1, items));\n            } else {\n                setListAdapter(null);\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/streaming/StreamingSessionUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.streaming;\n\n/**\n * Streaming service utils\n * \n * @author Jean-Marc AUFFRET\n */\npublic class StreamingSessionUtils {\n    /**\n     * Service ID constant\n     */\n    public final static String SERVICE_ID = \"ext.streaming\";\n\n    /**\n     * Encoding\n     */\n    public final static String ENCODING = \"TEXT/1\";\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/extension/streaming/StreamingSessionView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.extension.streaming;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSession;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSessionIntent;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSessionListener;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnCancelListener;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Streaming session view\n *\n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class StreamingSessionView extends RcsActivity {\n\n    /**\n     * View mode: incoming session\n     */\n    public final static int MODE_INCOMING = 0;\n\n    /**\n     * View mode: outgoing session\n     */\n    public final static int MODE_OUTGOING = 1;\n\n    /**\n     * View mode: open session history\n     */\n    public final static int MODE_OPEN = 2;\n\n    /**\n     * Intent parameter: view mode\n     */\n    public final static String EXTRA_MODE = \"mode\";\n\n    /**\n     * Intent parameter: session ID\n     */\n    public final static String EXTRA_SESSION_ID = \"session_id\";\n\n    /**\n     * Intent parameter: contact\n     */\n    public final static String EXTRA_CONTACT = \"contact\";\n\n    private final Handler handler = new Handler();\n\n    private String mSessionId;\n\n    private ContactId mContact;\n\n    private String mServiceId = StreamingSessionUtils.SERVICE_ID;\n\n    private MultimediaStreamingSession mSession;\n\n    private Dialog mProgressDialog;\n\n    private android.view.View.OnClickListener mBtnStartStopListener;\n\n    private OnClickListener mAcceptBtnListener;\n\n    private OnClickListener mDeclineBtnListener;\n\n    private MultimediaStreamingSessionListener mServiceListener;\n\n    private boolean mStarted = false;\n\n    private Button mStartStopBtn;\n\n    private TextView mTxDataView;\n\n    private TextView mRxDataView;\n\n    private Integer mCounter = 0;\n\n    private ScheduledExecutorService mPeriodicWorker;\n\n    private Runnable mPeriodicRtpSendTask;\n\n    private MultimediaSessionService mSessionService;\n\n    private static final String LOGTAG = LogUtils\n            .getTag(StreamingSessionView.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initialize();\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.extension_streaming_session_view);\n\n        /* Set buttons callback */\n        mStartStopBtn = (Button) findViewById(R.id.start_stop_btn);\n        mStartStopBtn.setOnClickListener(mBtnStartStopListener);\n        mStartStopBtn.setEnabled(false);\n\n        mTxDataView = (TextView) findViewById(R.id.tx_data);\n        mRxDataView = (TextView) findViewById(R.id.rx_data);\n\n        mSessionService = getMultimediaSessionApi();\n        /* Register to API connection manager */\n        if (mSessionService == null\n                || !isServiceConnected(RcsServiceName.MULTIMEDIA, RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.MULTIMEDIA, RcsServiceName.CONTACT);\n        try {\n            mSessionService.addEventListener(mServiceListener);\n            initialiseStreamingSession(getIntent());\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (mSessionService != null && isServiceConnected(RcsServiceName.MULTIMEDIA)) {\n            try {\n                mSessionService.removeEventListener(mServiceListener);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n        if (mPeriodicWorker != null) {\n            mPeriodicWorker.shutdown();\n        }\n    }\n\n    private void acceptInvitation() {\n        try {\n            mSession.acceptInvitation();\n            /*\n             * Wait for the SIP-ACK to allow the user to send message once session is established.\n             */\n            showProgressDialog();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void rejectInvitation() {\n        try {\n            mSession.rejectInvitation();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void initialiseStreamingSession(Intent intent) {\n        try {\n            int mode = intent.getIntExtra(StreamingSessionView.EXTRA_MODE, -1);\n            if (mode == StreamingSessionView.MODE_OUTGOING) {\n                /* Outgoing session: Check if the service is available. */\n                if (!mSessionService.isServiceRegistered()) {\n                    showMessageThenExit(R.string.error_not_registered);\n                    return;\n                }\n                mContact = intent.getParcelableExtra(StreamingSessionView.EXTRA_CONTACT);\n                startSession();\n\n            } else if (mode == StreamingSessionView.MODE_OPEN) {\n                /* Open an existing session. */\n                mSessionId = intent.getStringExtra(StreamingSessionView.EXTRA_SESSION_ID);\n                mSession = mSessionService.getStreamingSession(mSessionId);\n                if (mSession == null) {\n                    showMessageThenExit(R.string.label_session_has_expired);\n                    return;\n                }\n                mContact = mSession.getRemoteContact();\n\n            } else {\n                /* Incoming session from its Intent. */\n                mSessionId = intent\n                        .getStringExtra(MultimediaStreamingSessionIntent.EXTRA_SESSION_ID);\n\n                mSession = mSessionService.getStreamingSession(mSessionId);\n                if (mSession == null) {\n                    showMessageThenExit(R.string.label_session_has_expired);\n                    return;\n                }\n                mContact = mSession.getRemoteContact();\n                String from = RcsContactUtil.getInstance(this).getDisplayName(mContact);\n\n                /* Manual accept */\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.title_streaming_session);\n                builder.setMessage(getString(R.string.label_mm_from_id, from, mServiceId));\n                builder.setCancelable(false);\n                builder.setIcon(R.drawable.ri_notif_mm_session_icon);\n                builder.setPositiveButton(R.string.label_accept, mAcceptBtnListener);\n                builder.setNegativeButton(R.string.label_decline, mDeclineBtnListener);\n                registerDialog(builder.show());\n            }\n\n            /* Display session info */\n            TextView featureTagEdit = (TextView) findViewById(R.id.feature_tag);\n            featureTagEdit.setText(mServiceId);\n            TextView contactEdit = (TextView) findViewById(R.id.contact);\n            String from = RcsContactUtil.getInstance(this).getDisplayName(mContact);\n            contactEdit.setText(from);\n            Button sendBtn = (Button) findViewById(R.id.send_btn);\n            if (mSession != null && MultimediaSession.State.STARTED == mSession.getState()) {\n                sendBtn.setEnabled(true);\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void startSession() {\n        try {\n            mSession = mSessionService.initiateStreamingSession(mServiceId, mContact,\n                    StreamingSessionUtils.ENCODING);\n            mSessionId = mSession.getSessionId();\n            showProgressDialog();\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void showProgressDialog() {\n        mProgressDialog = showProgressDialog(getString(R.string.label_command_in_progress));\n        mProgressDialog.setOnCancelListener(new OnCancelListener() {\n            public void onCancel(DialogInterface dialog) {\n                Toast.makeText(StreamingSessionView.this,\n                        getString(R.string.label_session_canceled), Toast.LENGTH_SHORT).show();\n                quitSession();\n            }\n        });\n    }\n\n    private void hideProgressDialog() {\n        if (mProgressDialog != null && mProgressDialog.isShowing()) {\n            mProgressDialog.dismiss();\n            mProgressDialog = null;\n        }\n    }\n\n    private void quitSession() {\n        try {\n            if (mSession != null && RcsSessionUtil.isAllowedToAbortMultimediaSession(mSession)) {\n                mSession.abortSession();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mSession = null;\n            /* Exit activity */\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            if (mSession != null) {\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                                // Exit activity\n                                finish();\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n\n            } else {\n                finish();\n            }\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_mm_session, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void initialize() {\n        mPeriodicRtpSendTask = new Runnable() {\n            public void run() {\n                if (mSession == null) {\n                    return;\n                }\n                mCounter++;\n                final String data = \"data\".concat(mCounter.toString());\n                try {\n                    mSession.sendPayload(data.getBytes());\n                    handler.post(new Runnable() {\n                        public void run() {\n                            /* Display Transmitted data */\n                            mTxDataView.setText(data);\n                        }\n                    });\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n\n            }\n        };\n        mBtnStartStopListener = new android.view.View.OnClickListener() {\n\n            public void onClick(View v) {\n                mStarted = !mStarted;\n                handler.post(new Runnable() {\n                    public void run() {\n                        mStartStopBtn\n                                .setText(mStarted ? R.string.label_stop : R.string.label_start);\n                    }\n                });\n                if (mStarted) {\n                    mPeriodicWorker = Executors.newSingleThreadScheduledExecutor();\n                    mPeriodicWorker.scheduleAtFixedRate(mPeriodicRtpSendTask, 0, 1,\n                            TimeUnit.SECONDS);\n                } else {\n                    mPeriodicWorker.shutdown();\n                    mPeriodicWorker = null;\n                }\n            }\n        };\n\n        mAcceptBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                acceptInvitation();\n            }\n        };\n\n        mDeclineBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                rejectInvitation();\n                /* Exit activity */\n                finish();\n            }\n        };\n\n        mServiceListener = new MultimediaStreamingSessionListener() {\n\n            @Override\n            public void onStateChanged(ContactId contact, String sessionId,\n                    final MultimediaSession.State state, MultimediaSession.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMultimediaStreamingStateChanged contact=\" + contact\n                            + \" sessionId=\" + sessionId + \" state=\" + state + \" reason=\"\n                            + reasonCode);\n                }\n                /* Discard event if not for current sessionId */\n                if (mSessionId == null || !mSessionId.equals(sessionId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sMultimediaReasonCodes[reasonCode.toInt()];\n                handler.post(new Runnable() {\n                    public void run() {\n\n                        switch (state) {\n                            case STARTED:\n                                /* Session is established: hide progress dialog. */\n                                hideProgressDialog();\n                                /* Activate sen button. */\n                                mStartStopBtn.setEnabled(true);\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_session_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_session_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_session_failed,\n                                        _reasonCode));\n                                break;\n\n                            default:\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG,\n                                            \"onMultimediaStreamingStateChanged \"\n                                                    + getString(R.string.label_mms_state_changed,\n                                                            RiApplication.sMultimediaStates[state\n                                                                    .toInt()], _reasonCode));\n                                }\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onPayloadReceived(ContactId contact, String sessionId, final byte[] content) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onNewMessage contact=\" + contact + \" sessionId=\" + sessionId);\n                }\n                if (mSessionId == null || !mSessionId.equals(sessionId)) {\n                    return;\n                }\n                handler.post(new Runnable() {\n                    public void run() {\n                        /* Display received data */\n                        mRxDataView.setText(new String(content));\n                    }\n                });\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/intents/TestIntentApps.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.intents;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\n\nimport android.content.ActivityNotFoundException;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\n\n/**\n * Call each Intents\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestIntentApps extends RcsActivity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.intents_apps);\n\n        // Set button callback\n        Button btn = (Button) findViewById(R.id.load_chat);\n        btn.setOnClickListener(btnListener);\n        btn = (Button) findViewById(R.id.load_ft);\n        btn.setOnClickListener(btnListener);\n        btn = (Button) findViewById(R.id.load_group_chat);\n        btn.setOnClickListener(btnListener);\n        btn = (Button) findViewById(R.id.initiate_ft);\n        btn.setOnClickListener(btnListener);\n        btn = (Button) findViewById(R.id.initiate_group_chat);\n        btn.setOnClickListener(btnListener);\n        btn = (Button) findViewById(R.id.initiate_chat);\n        btn.setOnClickListener(btnListener);\n    }\n\n    /**\n     * Button callback\n     */\n    private OnClickListener btnListener = new OnClickListener() {\n        public void onClick(View v) {\n            try {\n                if (v.getId() == R.id.load_chat) {\n                    Intent intent = new Intent(\n                            com.gsma.services.rcs.Intents.Chat.ACTION_VIEW_ONE_TO_ONE_CHAT);\n                    startActivity(intent);\n\n                } else if (v.getId() == R.id.initiate_chat) {\n                    Intent intent = new Intent(\n                            com.gsma.services.rcs.Intents.Chat.ACTION_SEND_ONE_TO_ONE_CHAT_MESSAGE);\n                    startActivity(intent);\n\n                } else if (v.getId() == R.id.load_group_chat) {\n                    Intent intent = new Intent(\n                            com.gsma.services.rcs.Intents.Chat.ACTION_VIEW_GROUP_CHAT);\n                    startActivity(intent);\n\n                } else if (v.getId() == R.id.initiate_group_chat) {\n                    Intent intent = new Intent(\n                            com.gsma.services.rcs.Intents.Chat.ACTION_INITIATE_GROUP_CHAT);\n                    startActivity(intent);\n\n                } else if (v.getId() == R.id.load_ft) {\n                    Intent intent = new Intent(\n                            com.gsma.services.rcs.Intents.FileTransfer.ACTION_VIEW_FILE_TRANSFER);\n                    startActivity(intent);\n\n                } else if (v.getId() == R.id.initiate_ft) {\n                    Intent intent = new Intent(\n                            com.gsma.services.rcs.Intents.FileTransfer.ACTION_INITIATE_ONE_TO_ONE_FILE_TRANSFER);\n                    startActivity(intent);\n                }\n\n            } catch (ActivityNotFoundException e) {\n                showMessageThenExit(R.string.label_intent_failed);\n            }\n\n        }\n    };\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/GroupDeliveryInfoList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.adapter.GroupDeliveryInfoCursorAdapter;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfoLog;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.util.Log;\nimport android.widget.ListView;\n\n/**\n * A list view of group chat delivery information where the data comes from a cursor.\n * \n * @author yplo6403\n */\npublic class GroupDeliveryInfoList extends FragmentActivity implements\n        LoaderManager.LoaderCallbacks<Cursor> {\n    /**\n     * Intent parameters\n     */\n    private static final String EXTRA_MESSAGE_ID = \"message_id\";\n\n    /**\n     * the message ID for which we view the delivery information\n     */\n    private String mMessageId;\n\n    /**\n     * The loader's unique ID. Loader IDs are specific to the Activity in which they reside.\n     */\n    private static final int LOADER_ID = 1;\n\n    // @formatter:off\n    private static final String[] PROJECTION = new String[] {\n        GroupDeliveryInfoLog.BASECOLUMN_ID,\n        GroupDeliveryInfoLog.CONTACT,\n        GroupDeliveryInfoLog.TIMESTAMP_DELIVERED,\n        GroupDeliveryInfoLog.TIMESTAMP_DISPLAYED,\n        GroupDeliveryInfoLog.STATUS,\n        GroupDeliveryInfoLog.REASON_CODE\n    };\n    // @formatter:on\n\n    private static final String WHERE_CLAUSE = GroupDeliveryInfoLog.ID + \"=?\";\n\n    /**\n     * The log tag for this class\n     */\n    private static final String LOGTAG = LogUtils.getTag(GroupDeliveryInfoList.class\n            .getSimpleName());\n\n    /**\n     * The adapter that binds data to the ListView\n     */\n    private GroupDeliveryInfoCursorAdapter mAdapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.delivery_info_list);\n        mMessageId = getIntent().getStringExtra(EXTRA_MESSAGE_ID);\n        // Initialize the adapter.\n        mAdapter = new GroupDeliveryInfoCursorAdapter(this);\n\n        // Associate the list adapter with the ListView.\n        ListView listView = (ListView) findViewById(android.R.id.list);\n        listView.setAdapter(mAdapter);\n        // Initialize the Loader with id and callbacks 'mCallbacks'.\n        getSupportLoaderManager().initLoader(LOADER_ID, null, this);\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onCreate\");\n        }\n    }\n\n    /**\n     * Start GroupDeliveryInfoList activity\n     * \n     * @param context The context\n     * @param messageId the message ID for which Group Delivery information list is requested\n     */\n    public static void startActivity(Context context, String messageId) {\n        Intent intent = new Intent(context, GroupDeliveryInfoList.class);\n        intent.putExtra(EXTRA_MESSAGE_ID, messageId);\n        context.startActivity(intent);\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle arg) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onCreateLoader \" + id);\n        }\n        // Create a new CursorLoader with the following query parameters.\n        return new CursorLoader(this, GroupDeliveryInfoLog.CONTENT_URI, PROJECTION, WHERE_CLAUSE,\n                new String[] {\n                    mMessageId\n                }, null);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onLoadFinished \" + loader.getId());\n        }\n        // A switch-case is useful when dealing with multiple Loaders/IDs\n        switch (loader.getId()) {\n            case LOADER_ID:\n                // The asynchronous load is complete and the data\n                // is now available for use. Only now can we associate\n                // the queried Cursor with the CursorAdapter.\n                mAdapter.swapCursor(cursor);\n                break;\n        }\n        // The listview now displays the queried data.\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onLoaderReset \" + loader.getId());\n        }\n        // For whatever reason, the Loader's data is now unavailable.\n        // Remove any references to the old data by replacing it with a null\n        // Cursor.\n        mAdapter.swapCursor(null);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/GroupTalkView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsFragmentActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RI;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.messaging.adapter.TalkCursorAdapter;\nimport com.gsma.rcs.ri.messaging.chat.ChatCursorObserver;\nimport com.gsma.rcs.ri.messaging.chat.ChatMessageLogView;\nimport com.gsma.rcs.ri.messaging.chat.ChatPendingIntentManager;\nimport com.gsma.rcs.ri.messaging.chat.IsComposingManager;\nimport com.gsma.rcs.ri.messaging.chat.IsComposingManager.INotifyComposing;\nimport com.gsma.rcs.ri.messaging.chat.group.SendGroupFile;\nimport com.gsma.rcs.ri.messaging.filetransfer.FileTransferLogView;\nimport com.gsma.rcs.ri.messaging.geoloc.DisplayGeoloc;\nimport com.gsma.rcs.ri.messaging.geoloc.EditGeoloc;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Smileys;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatLog.Message;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatMessage;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.chat.ChatServiceConfiguration;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChatIntent;\nimport com.gsma.services.rcs.chat.GroupChatListener;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.contact.RcsContact;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.GroupFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\n\nimport android.app.AlertDialog;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.text.Editable;\nimport android.text.InputFilter;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.util.Log;\nimport android.view.ContextMenu;\nimport android.view.ContextMenu.ContextMenuInfo;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.AdapterView.AdapterContextMenuInfo;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Group chat view\n */\npublic class GroupTalkView extends RcsFragmentActivity implements\n        LoaderManager.LoaderCallbacks<Cursor> {\n\n    /**\n     * The loader's unique ID. Loader IDs are specific to the Activity in which they reside.\n     */\n    private static final int LOADER_ID = 1;\n\n    private final static int SELECT_GEOLOCATION = 0;\n\n    // @formatter:off\n    private static final String[] PROJ_CHAT_MSG = new String[]{\n            HistoryLog.BASECOLUMN_ID,\n            HistoryLog.ID,\n            HistoryLog.PROVIDER_ID,\n            HistoryLog.MIME_TYPE,\n            HistoryLog.CONTENT,\n            HistoryLog.TIMESTAMP,\n            HistoryLog.STATUS,\n            HistoryLog.DIRECTION,\n            HistoryLog.CONTACT,\n            HistoryLog.EXPIRED_DELIVERY,\n            HistoryLog.FILENAME,\n            HistoryLog.FILESIZE,\n            HistoryLog.TRANSFERRED,\n            HistoryLog.REASON_CODE,\n            HistoryLog.READ_STATUS};\n    // @formatter:on\n\n    /**\n     * Query sort order\n     */\n    private final static String ORDER_CHAT_MSG = HistoryLog.TIMESTAMP + \" ASC\";\n\n    /**\n     * Intent parameters\n     */\n    private final static String EXTRA_PARTICIPANTS = \"participants\";\n    private final static String EXTRA_SUBJECT = \"subject\";\n    private final static String EXTRA_MODE = \"mode\";\n\n    private enum GroupChatMode {\n        INCOMING, OUTGOING, OPEN\n    }\n\n    private static final String WHERE_CLAUSE = HistoryLog.CHAT_ID + \"=?\";\n    private static final String LOGTAG = LogUtils.getTag(GroupTalkView.class.getSimpleName());\n    private static final String OPEN_GROUPCHAT = \"OPEN_GROUPCHAT\";\n    private static final String INTITIATE_GROUPCHAT = \"INTITIATE_GROUPCHAT\";\n\n    private Handler mHandler;\n    private EditText mComposeText;\n    private ChatService mChatService;\n    private FileTransferService mFileTransferService;\n    private Uri mUriHistoryProvider;\n    private IsComposingManager mComposingManager;\n    private TalkCursorAdapter mAdapter;\n    private ChatCursorObserver mObserver;\n    private boolean mChatListnerSet;\n    private String mSubject;\n    private String mChatId;\n    private GroupChat mGroupChat;\n    private Set<ContactId> mParticipants = new HashSet<>();\n    private GroupChatListener mChatListener;\n    private GroupFileTransferListener mFileTransferListener;\n    private boolean mFileTransferListenerSet;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.chat_view);\n        if (!isServiceConnected(ConnectionManager.RcsServiceName.CHAT,\n                ConnectionManager.RcsServiceName.CONTACT,\n                ConnectionManager.RcsServiceName.CAPABILITY,\n                ConnectionManager.RcsServiceName.FILE_TRANSFER)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(ConnectionManager.RcsServiceName.CHAT,\n                ConnectionManager.RcsServiceName.CONTACT,\n                ConnectionManager.RcsServiceName.CAPABILITY,\n                ConnectionManager.RcsServiceName.FILE_TRANSFER);\n        try {\n            initialize();\n            processIntent(getIntent());\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onCreate\");\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void initialize() throws RcsServiceNotAvailableException, RcsGenericException {\n        Button sendButton = (Button) findViewById(R.id.send_button);\n        sendButton.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                sendText();\n            }\n        });\n        mHandler = new Handler();\n        mChatListener = new GroupChatListener() {\n\n            @Override\n            public void onMessageStatusChanged(String chatId, String mimeType, String msgId,\n                    Content.Status status, Content.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.i(LOGTAG, \"onMessageStatusChanged chatId=\" + chatId + \" mime-type=\"\n                            + mimeType + \" msgId=\" + msgId + \" status=\" + status + \" reason=\"\n                            + reasonCode);\n                }\n            }\n\n            // Callback called when an Is-composing event has been received\n            public void onComposingEvent(String chatId, ContactId contact, boolean status) {\n                // Discard event if not for current chatId\n                if (!chatId.equals(mChatId)) {\n                    return;\n                }\n                displayComposingEvent(contact, status);\n            }\n\n            @Override\n            public void onParticipantStatusChanged(String chatId, ContactId contact,\n                    ParticipantStatus status) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onParticipantStatusChanged chatId=\" + chatId + \" contact=\"\n                            + contact + \" status=\" + status);\n                }\n            }\n\n            @Override\n            public void onMessageGroupDeliveryInfoChanged(String chatId, ContactId contact,\n                    String mimeType, String msgId, GroupDeliveryInfo.Status status,\n                    GroupDeliveryInfo.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessageGroupDeliveryInfoChanged chatId=\" + chatId\n                            + \" contact=\" + contact + \" msgId=\" + msgId + \" status=\" + status\n                            + \" reason=\" + reasonCode);\n                }\n            }\n\n            @Override\n            public void onStateChanged(String chatId, final GroupChat.State state,\n                    GroupChat.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged chatId=\" + chatId + \" state=\" + state\n                            + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current chatId */\n                if (mChatId == null || !mChatId.equals(chatId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sGroupChatReasonCodes[reasonCode.toInt()];\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        switch (state) {\n                            case STARTED:\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_chat_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_chat_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_chat_failed,\n                                        _reasonCode));\n                                break;\n\n                            default:\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(Set<String> chatIds) {\n                if (LogUtils.isActive) {\n                    Log.i(LOGTAG, \"onDeleted chatIds=\".concat(Arrays.toString(chatIds.toArray())));\n                }\n            }\n\n            @Override\n            public void onMessagesDeleted(String chatId, Set<String> msgIds) {\n                if (LogUtils.isActive) {\n                    Log.i(LOGTAG,\n                            \"onMessagesDeleted chatId=\" + chatId + \" msgIds=\"\n                                    + Arrays.toString(msgIds.toArray()));\n                }\n            }\n\n        };\n        mFileTransferListener = new GroupFileTransferListener() {\n            @Override\n            public void onStateChanged(String chatId, String transferId, FileTransfer.State state,\n                    FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged chatId=\" + chatId + \" transferId=\" + transferId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current chatId */\n                if (mChatId == null || !mChatId.equals(chatId)) {\n                    return;\n                }\n                if (FileTransfer.State.TRANSFERRED == state) {\n                    try {\n                        FileTransfer fileTransfer = mFileTransferService\n                                .getFileTransfer(transferId);\n                        if (fileTransfer == null) {\n                            return;\n                        }\n                        if (Utils.isAudioType(fileTransfer.getMimeType())\n                                && FileTransfer.Disposition.RENDER == fileTransfer.getDisposition()) {\n                            Utils.playAudio(GroupTalkView.this, fileTransfer.getFile());\n                            mFileTransferService.markFileTransferAsRead(transferId);\n                        }\n                    } catch (RcsPersistentStorageException | RcsServiceNotAvailableException\n                            | RcsGenericException e) {\n                        showException(e);\n                    }\n                }\n            }\n\n            @Override\n            public void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n                    GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onProgressUpdate(String chatId, String transferId, long currentSize,\n                    long totalSize) {\n            }\n\n            @Override\n            public void onDeleted(String chatId, Set<String> transferIds) {\n            }\n\n        };\n        mChatService = getChatApi();\n        mFileTransferService = getFileTransferApi();\n\n        HistoryUriBuilder uriBuilder = new HistoryUriBuilder(HistoryLog.CONTENT_URI);\n        uriBuilder.appendProvider(ChatLog.Message.HISTORYLOG_MEMBER_ID);\n        uriBuilder.appendProvider(FileTransferLog.HISTORYLOG_MEMBER_ID);\n        mUriHistoryProvider = uriBuilder.build();\n\n        mComposeText = (EditText) findViewById(R.id.userText);\n        ChatServiceConfiguration configuration = mChatService.getConfiguration();\n        // Set max label length\n        int maxMsgLength = configuration.getGroupChatMessageMaxLength();\n        if (maxMsgLength > 0) {\n            InputFilter[] filterArray = new InputFilter[1];\n            filterArray[0] = new InputFilter.LengthFilter(maxMsgLength);\n            mComposeText.setFilters(filterArray);\n        }\n        mComposingManager = new IsComposingManager(configuration.getIsComposingTimeout(),\n                getNotifyComposing());\n        mComposeText.addTextChangedListener(new TextWatcher() {\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                // Check if the text is not null.\n                // we do not wish to consider putting the edit text back to null\n                // (like when sending message), is having activity\n                if (!TextUtils.isEmpty(s)) {\n                    // Warn the composing manager that we have some activity\n                    if (mComposingManager != null) {\n                        mComposingManager.hasActivity();\n                    }\n                }\n            }\n\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n            }\n        });\n        mAdapter = new TalkCursorAdapter(this, false, mChatService, mFileTransferService);\n        ListView listView = (ListView) findViewById(android.R.id.list);\n        listView.setAdapter(mAdapter);\n        registerForContextMenu(listView);\n    }\n\n    private boolean processIntent(Intent intent) {\n        String action = intent.getAction();\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"processIntent: \" + action);\n        }\n        String oldChatId = mChatId;\n        try {\n            switch ((GroupChatMode) intent.getSerializableExtra(EXTRA_MODE)) {\n                case OUTGOING:\n                    /* Initiate a Group Chat: Get subject */\n                    mSubject = intent.getStringExtra(GroupTalkView.EXTRA_SUBJECT);\n                    updateGroupChatViewTitle(mSubject);\n                    /* Get the list of participants */\n                    ContactUtil contactUtil = ContactUtil.getInstance(this);\n                    List<String> contacts = intent\n                            .getStringArrayListExtra(GroupTalkView.EXTRA_PARTICIPANTS);\n                    if (contacts == null || contacts.isEmpty()) {\n                        showMessageThenExit(R.string.label_invalid_contacts);\n                        return false;\n                    }\n                    for (String contact : contacts) {\n                        mParticipants.add(contactUtil.formatContact(contact));\n                    }\n                    if (mParticipants.isEmpty()) {\n                        showMessageThenExit(R.string.label_invalid_contacts);\n                        return false;\n                    }\n                    return initiateGroupChat(oldChatId == null);\n\n                case OPEN:\n                    /* Open an existing session from the history log */\n                    mChatId = intent.getStringExtra(GroupChatIntent.EXTRA_CHAT_ID);\n                    mGroupChat = mChatService.getGroupChat(mChatId);\n                    if (mGroupChat == null) {\n                        if (LogUtils.isActive) {\n                            Log.e(LOGTAG, \"Groupchat not found for Id=\".concat(mChatId));\n                        }\n                        showMessageThenExit(R.string.label_session_not_found);\n                        return false;\n                    }\n                    ChatPendingIntentManager.getChatPendingIntentManager(this).clearNotification(\n                            mChatId);\n                    setCursorLoader(oldChatId == null);\n                    RI.sChatIdOnForeground = mChatId;\n                    mSubject = mGroupChat.getSubject();\n                    updateGroupChatViewTitle(mSubject);\n                    /* Set list of participants */\n                    mParticipants = mGroupChat.getParticipants().keySet();\n                    if (LogUtils.isActive) {\n                        Log.i(LOGTAG, \"processIntent chatId=\" + mChatId + \" subject='\" + mSubject\n                                + \"'\");\n                    }\n                    return true;\n\n                case INCOMING:\n                    String rxChatId = intent.getStringExtra(GroupChatIntent.EXTRA_CHAT_ID);\n                    if (GroupChatIntent.ACTION_NEW_GROUP_CHAT_MESSAGE.equals(action)) {\n                        String rxMsgId = intent.getStringExtra(GroupChatIntent.EXTRA_MESSAGE_ID);\n                        mChatService.markMessageAsRead(rxMsgId);\n                    }\n                    mChatId = rxChatId;\n                    mGroupChat = mChatService.getGroupChat(mChatId);\n                    if (mGroupChat == null) {\n                        showMessageThenExit(R.string.label_session_not_found);\n                        return false;\n                    }\n                    setCursorLoader(oldChatId == null);\n                    RI.sChatIdOnForeground = mChatId;\n                    ContactId contact = mGroupChat.getRemoteContact();\n                    mSubject = mGroupChat.getSubject();\n                    updateGroupChatViewTitle(mSubject);\n                    mParticipants = mGroupChat.getParticipants().keySet();\n                    /* Display accept/reject dialog */\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"New group chat for chatId \" + mChatId + \" state=\"\n                                + mGroupChat.getState());\n                    }\n                    if (GroupChat.State.INVITED == mGroupChat.getState()) {\n                        displayAcceptRejectDialog(contact);\n                    }\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"New group chat for chatId \".concat(mChatId));\n                    }\n                    return true;\n            }\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n        return false;\n    }\n\n    private void setCursorLoader(boolean firstLoad) {\n        if (firstLoad) {\n            /*\n             * Initialize the Loader with id '1' and callbacks 'mCallbacks'.\n             */\n            getSupportLoaderManager().initLoader(LOADER_ID, null, this);\n        } else {\n            /* We switched from one contact to another: reload history since */\n            getSupportLoaderManager().restartLoader(LOADER_ID, null, this);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onDestroy\");\n        }\n        if (mGroupChat != null) {\n            try {\n                mGroupChat.setComposingStatus(false);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n        super.onDestroy();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        RI.sChatIdOnForeground = mChatId;\n        if (mChatId != null) {\n            ChatPendingIntentManager.getChatPendingIntentManager(this).clearNotification(mChatId);\n        }\n        try {\n            if (mChatListener != null && mChatService != null && !mChatListnerSet) {\n                mChatService.addEventListener(mChatListener);\n                mChatListnerSet = true;\n            }\n            if (mFileTransferListener != null && mFileTransferService != null\n                    && !mFileTransferListenerSet) {\n                mFileTransferService.addEventListener(mFileTransferListener);\n                mFileTransferListenerSet = true;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        /* Replace the value of intent */\n        setIntent(intent);\n        processIntent(intent);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        RI.sChatIdOnForeground = null;\n        try {\n            if (mChatListener != null && mChatService != null && mChatListnerSet) {\n                mChatService.removeEventListener(mChatListener);\n                mChatListnerSet = false;\n            }\n            if (mFileTransferListener != null && mFileTransferService != null\n                    && mFileTransferListenerSet) {\n                mFileTransferService.removeEventListener(mFileTransferListener);\n                mFileTransferListenerSet = false;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n        switch (requestCode) {\n            case SELECT_GEOLOCATION:\n                Geoloc geoloc = data.getParcelableExtra(EditGeoloc.EXTRA_GEOLOC);\n                try {\n                    if (mGroupChat != null && geoloc != null) {\n                        mGroupChat.sendMessage(geoloc);\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n                break;\n        }\n    }\n\n    @Override\n    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\n        super.onCreateContextMenu(menu, v, menuInfo);\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.menu_gchat_item, menu);\n        menu.findItem(R.id.menu_display_content).setVisible(false);\n        menu.findItem(R.id.menu_listen_content).setVisible(false);\n        /* Get the list item position. */\n        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;\n        Cursor cursor = (Cursor) mAdapter.getItem(info.position);\n        int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n        Direction direction = Direction.valueOf(cursor.getInt(cursor\n                .getColumnIndexOrThrow(Message.DIRECTION)));\n        if (FileTransferLog.HISTORYLOG_MEMBER_ID == providerId) {\n            String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.MIME_TYPE));\n            if (Utils.isImageType(mimeType)) {\n                if (Direction.OUTGOING == direction) {\n                    menu.findItem(R.id.menu_display_content).setVisible(true);\n\n                } else {\n                    Long transferred = cursor.getLong(cursor\n                            .getColumnIndexOrThrow(HistoryLog.TRANSFERRED));\n                    Long size = cursor.getLong(cursor.getColumnIndexOrThrow(HistoryLog.FILESIZE));\n                    if (size.equals(transferred)) {\n                        menu.findItem(R.id.menu_display_content).setVisible(true);\n                    }\n                }\n            } else if (Utils.isAudioType(mimeType)) {\n                if (Direction.OUTGOING == direction) {\n                    menu.findItem(R.id.menu_listen_content).setVisible(true);\n\n                } else {\n                    Long transferred = cursor.getLong(cursor\n                            .getColumnIndexOrThrow(HistoryLog.TRANSFERRED));\n                    Long size = cursor.getLong(cursor.getColumnIndexOrThrow(HistoryLog.FILESIZE));\n                    if (size.equals(transferred)) {\n                        menu.findItem(R.id.menu_listen_content).setVisible(true);\n                    }\n                }\n            }\n        }\n        if (Direction.OUTGOING != direction) {\n            menu.findItem(R.id.menu_view_group_delivery).setVisible(false);\n        }\n    }\n\n    @Override\n    public boolean onContextItemSelected(MenuItem item) {\n        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();\n        Cursor cursor = (Cursor) (mAdapter.getItem(info.position));\n        int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n        String id = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onContextItemSelected Id=\".concat(id));\n        }\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_view_group_delivery:\n                    GroupDeliveryInfoList.startActivity(this, id);\n                    return true;\n\n                case R.id.menu_delete_message:\n                    if (ChatLog.Message.HISTORYLOG_MEMBER_ID == providerId) {\n                        mChatService.deleteMessage(id);\n                    } else {\n                        mFileTransferService.deleteFileTransfer(id);\n                    }\n                    return true;\n\n                case R.id.menu_view_detail:\n                    if (ChatLog.Message.HISTORYLOG_MEMBER_ID == providerId) {\n                        ChatMessageLogView.startActivity(this, id);\n                    } else {\n                        FileTransferLogView.startActivity(this, id);\n                    }\n                    return true;\n\n                case R.id.menu_display_content:\n                    if (FileTransferLog.HISTORYLOG_MEMBER_ID == providerId) {\n                        String file = cursor.getString(cursor\n                                .getColumnIndexOrThrow(HistoryLog.CONTENT));\n                        Utils.showPicture(this, Uri.parse(file));\n                        markFileTransferAsRead(cursor, id);\n                        return true;\n                    }\n                    break;\n\n                case R.id.menu_listen_content:\n                    if (FileTransferLog.HISTORYLOG_MEMBER_ID == providerId) {\n                        String file = cursor.getString(cursor\n                                .getColumnIndexOrThrow(HistoryLog.CONTENT));\n                        Utils.playAudio(this, Uri.parse(file));\n                        markFileTransferAsRead(cursor, id);\n                        return true;\n                    }\n                    break;\n            }\n            return super.onContextItemSelected(item);\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return true;\n    }\n\n    private void markFileTransferAsRead(Cursor cursor, String ftId) {\n        try {\n            RcsService.Direction dir = RcsService.Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(HistoryLog.DIRECTION)));\n            if (RcsService.Direction.INCOMING == dir) {\n                RcsService.ReadStatus status = RcsService.ReadStatus.valueOf(cursor.getInt(cursor\n                        .getColumnIndexOrThrow(HistoryLog.READ_STATUS)));\n                if (RcsService.ReadStatus.UNREAD == status) {\n                    mFileTransferService.markFileTransferAsRead(ftId);\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"Mark file transfer \" + ftId + \" as read\");\n                    }\n                }\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Cannot mark message as read: service not available\");\n            }\n        } catch (RcsGenericException | RcsPersistentStorageException e) {\n            Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    /**\n     * Update the view title\n     *\n     * @param subject the group chat subject or null\n     */\n    private void updateGroupChatViewTitle(String subject) {\n        if (!TextUtils.isEmpty(subject)) {\n            setTitle(getString(R.string.title_group_chat) + \" '\" + mSubject + \"'\");\n        }\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle arg) {\n        /* Create a new CursorLoader with the following query parameters. */\n        return new CursorLoader(this, mUriHistoryProvider, PROJ_CHAT_MSG, WHERE_CLAUSE,\n                new String[] {\n                    mChatId\n                }, ORDER_CHAT_MSG);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {\n        if (LOADER_ID != loader.getId()) {\n            return;\n        }\n        /*\n         * The asynchronous load is complete and the data is now available for use. Only now can we\n         * associate the queried Cursor with the CursorAdapter.\n         */\n        mAdapter.swapCursor(cursor);\n        /**\n         * Registering content observer for chat message and file transfer content URIs. When these\n         * content URIs will change, this will notify the loader to reload its data.\n         */\n        if (mObserver != null && !mObserver.getLoader().equals(loader)) {\n            ContentResolver resolver = getContentResolver();\n            resolver.unregisterContentObserver(mObserver);\n            resolver.unregisterContentObserver(mObserver);\n            mObserver = null;\n        }\n        if (mObserver == null) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onLoadFinished: register content observer\");\n            }\n            mObserver = new ChatCursorObserver(new Handler(), loader);\n            ContentResolver resolver = getContentResolver();\n            resolver.registerContentObserver(ChatLog.Message.CONTENT_URI, true, mObserver);\n            resolver.registerContentObserver(FileTransferLog.CONTENT_URI, true, mObserver);\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        /*\n         * For whatever reason, the Loader's data is now unavailable. Remove any references to the\n         * old data by replacing it with a null Cursor.\n         */\n        mAdapter.swapCursor(null);\n    }\n\n    /**\n     * Display notification to accept or reject invitation\n     *\n     * @param remote remote contact\n     */\n    private void displayAcceptRejectDialog(ContactId remote) {\n        /* Manual accept */\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.title_group_chat);\n        String from = RcsContactUtil.getInstance(this).getDisplayName(remote);\n        String topic = (TextUtils.isEmpty(mSubject)) ? getString(R.string.label_no_subject)\n                : mSubject;\n        String msg = getString(R.string.label_gc_from_subject, from, topic);\n        builder.setMessage(msg);\n        builder.setCancelable(false);\n        builder.setIcon(R.drawable.ri_notif_chat_icon);\n        builder.setPositiveButton(R.string.label_accept,\n                new android.content.DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        try {\n                            /* Accept the invitation */\n                            mGroupChat.openChat();\n                        } catch (RcsServiceException e) {\n                            showExceptionThenExit(e);\n                        }\n                    }\n                });\n        builder.setNegativeButton(R.string.label_decline,\n                new android.content.DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        /*\n                         * Let session die by timeout. Exit activity\n                         */\n                        finish();\n                    }\n                });\n        registerDialog(builder.show());\n    }\n\n    /**\n     * get a set of contact from a set of participant info\n     *\n     * @param setOfParticipant a set of participant info\n     * @return a set of contact\n     */\n    private Set<String> getSetOfParticipants(Map<ContactId, ParticipantStatus> setOfParticipant) {\n        Set<String> result = new HashSet<>();\n        if (setOfParticipant.size() != 0) {\n            for (ContactId contact : setOfParticipant.keySet()) {\n                // TODO consider status ?\n                result.add(contact.toString());\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Initiate the group chat and open a progress dialog waiting for the session to start\n     *\n     * @return True if successful\n     */\n    private boolean initiateGroupChat(boolean firstLoad) {\n        /* Initiate the group chat session in background */\n        try {\n            mGroupChat = mChatService.initiateGroupChat(new HashSet<>(mParticipants), mSubject);\n            mChatId = mGroupChat.getChatId();\n            setCursorLoader(firstLoad);\n            RI.sChatIdOnForeground = mChatId;\n            return true;\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return false;\n        }\n    }\n\n    /**\n     * Add participants to be invited in the session\n     */\n    private void addParticipants() {\n        /* Build list of available contacts not already in the conference */\n        Set<ContactId> availableParticipants = new HashSet<>();\n        try {\n            Set<RcsContact> contacts = getContactApi().getRcsContacts();\n            for (RcsContact rcsContact : contacts) {\n                ContactId contact = rcsContact.getContactId();\n                if (mGroupChat.isAllowedToInviteParticipant(contact)) {\n                    availableParticipants.add(contact);\n                }\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n            return;\n        }\n        /* Check if some participants are available */\n        if (availableParticipants.size() == 0) {\n            showMessage(R.string.label_no_participant_found);\n            return;\n        }\n        /* Display contacts */\n        final List<String> selectedParticipants = new ArrayList<>();\n        final CharSequence[] items = new CharSequence[availableParticipants.size()];\n        int i = 0;\n        for (ContactId contact : availableParticipants) {\n            items[i++] = contact.toString();\n        }\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.label_select_contacts);\n        builder.setCancelable(true);\n        builder.setMultiChoiceItems(items, null, new DialogInterface.OnMultiChoiceClickListener() {\n            public void onClick(DialogInterface dialog, int which, boolean isChecked) {\n                String c = (String) items[which];\n                if (isChecked) {\n                    selectedParticipants.add(c);\n                } else {\n                    selectedParticipants.remove(c);\n                }\n            }\n        });\n        builder.setNegativeButton(R.string.label_cancel, null);\n        builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n            public void onClick(DialogInterface dialog, int position) {\n                /* Add new participants in the session in background */\n                try {\n                    int max = mGroupChat.getMaxParticipants() - 1;\n                    int connected = mGroupChat.getParticipants().size();\n                    int limit = max - connected;\n                    if (selectedParticipants.size() > limit) {\n                        showMessage(R.string.label_max_participants);\n                        return;\n                    }\n                    Set<ContactId> contacts = new HashSet<>();\n                    ContactUtil contactUtils = ContactUtil.getInstance(GroupTalkView.this);\n                    for (String participant : selectedParticipants) {\n                        contacts.add(contactUtils.formatContact(participant));\n                    }\n                    /* Add participants */\n                    mGroupChat.inviteParticipants(contacts);\n\n                } catch (RcsServiceException e) {\n                    showException(e);\n                }\n            }\n        });\n        registerDialog(builder.show());\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_group_chat, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        MenuItem menuItemParticipants = menu.findItem(R.id.menu_participants);\n        MenuItem menuItemSendFile = menu.findItem(R.id.menu_send_file);\n        MenuItem menuItemLeave = menu.findItem(R.id.menu_close_session);\n        try {\n            if (mGroupChat != null) {\n                menuItemParticipants.setEnabled(mGroupChat.isAllowedToInviteParticipants());\n                menuItemLeave.setEnabled(mGroupChat.isAllowedToLeave());\n                FileTransferService fileTransferService = getFileTransferApi();\n                menuItemSendFile.setEnabled(fileTransferService\n                        .isAllowedToTransferFileToGroupChat(mChatId));\n            } else {\n                menuItemParticipants.setEnabled(false);\n                menuItemSendFile.setEnabled(false);\n                menuItemLeave.setEnabled(false);\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_insert_smiley:\n                    AlertDialog alert = Smileys.showSmileyDialog(this, mComposeText,\n                            getResources(), getString(R.string.menu_insert_smiley));\n                    registerDialog(alert);\n                    break;\n\n                case R.id.menu_participants:\n                    alert = Utils.showList(this, getString(R.string.menu_participants),\n                            getSetOfParticipants(mGroupChat.getParticipants()));\n                    registerDialog(alert);\n                    break;\n\n                case R.id.menu_add_participant:\n                    addParticipants();\n                    break;\n\n                case R.id.menu_quicktext:\n                    addQuickText();\n                    break;\n\n                case R.id.menu_send_file:\n                    SendGroupFile.startActivity(this, mChatId);\n                    break;\n\n                case R.id.menu_send_geoloc:\n                    getGeoLoc();\n                    break;\n\n                case R.id.menu_showus_map:\n                    DisplayGeoloc.showContactsOnMap(this, mGroupChat.getParticipants().keySet());\n                    break;\n\n                case R.id.menu_close_session:\n                    AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                    builder.setTitle(R.string.title_chat_exit);\n                    builder.setPositiveButton(R.string.label_ok,\n                            new DialogInterface.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int which) {\n                                    if (mGroupChat != null) {\n                                        try {\n                                            mGroupChat.leave();\n                                        } catch (RcsServiceException e) {\n                                            showExceptionThenExit(e);\n                                        }\n                                    }\n                                    GroupTalkView.this.finish();\n                                }\n                            });\n                    builder.setNegativeButton(R.string.label_cancel, null);\n                    builder.setCancelable(true);\n                    registerDialog(builder.show());\n                    break;\n            }\n\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return true;\n    }\n\n    /**\n     * Initiate a new Group Chat\n     *\n     * @param ctx context\n     * @param subject subject\n     * @param participants list of participants\n     */\n    public static void initiateGroupChat(Context ctx, String subject, ArrayList<String> participants) {\n        Intent intent = new Intent(ctx, GroupTalkView.class);\n        intent.setAction(INTITIATE_GROUPCHAT);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putStringArrayListExtra(GroupTalkView.EXTRA_PARTICIPANTS, participants);\n        intent.putExtra(GroupTalkView.EXTRA_MODE, GroupChatMode.OUTGOING);\n        intent.putExtra(GroupTalkView.EXTRA_SUBJECT, subject);\n        ctx.startActivity(intent);\n    }\n\n    /**\n     * Open a Group Chat\n     *\n     * @param ctx The context.\n     * @param chatId The chat ID.\n     */\n    public static void openGroupChat(Context ctx, String chatId) {\n        Intent intent = new Intent(ctx, GroupTalkView.class);\n        intent.setAction(OPEN_GROUPCHAT);\n        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(GroupTalkView.EXTRA_MODE, GroupChatMode.OPEN);\n        intent.putExtra(GroupChatIntent.EXTRA_CHAT_ID, chatId);\n        ctx.startActivity(intent);\n    }\n\n    /**\n     * Forge intent to notify Group Chat message\n     *\n     * @param ctx The context.\n     * @param newgroupChatMessage The original intent.\n     * @param chatId the chat ID\n     * @return intent\n     */\n    public static Intent forgeIntentNewMessage(Context ctx, Intent newgroupChatMessage,\n            String chatId) {\n        newgroupChatMessage.setClass(ctx, GroupTalkView.class);\n        newgroupChatMessage\n                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        newgroupChatMessage.putExtra(GroupTalkView.EXTRA_MODE, GroupChatMode.INCOMING);\n        newgroupChatMessage.putExtra(GroupChatIntent.EXTRA_CHAT_ID, chatId);\n        return newgroupChatMessage;\n    }\n\n    /**\n     * Forge intent to notify new Group Chat\n     *\n     * @param ctx The context.\n     * @param invitation The original intent.\n     * @return intent\n     */\n    public static Intent forgeIntentInvitation(Context ctx, Intent invitation) {\n        invitation.setClass(ctx, GroupTalkView.class);\n        invitation.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        invitation.putExtra(GroupTalkView.EXTRA_MODE, GroupChatMode.INCOMING);\n        return invitation;\n    }\n\n    private ChatMessage sendMessage(String message) throws RcsServiceException {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"sendTextMessage: \".concat(message));\n        }\n        return mGroupChat.sendMessage(message);\n    }\n\n    private INotifyComposing getNotifyComposing() {\n        return new INotifyComposing() {\n            public void setTypingStatus(boolean isTyping) {\n                try {\n                    if (mGroupChat != null) {\n                        mGroupChat.setComposingStatus(isTyping);\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"sendIsComposingEvent \".concat(String.valueOf(isTyping)));\n                        }\n                    }\n                } catch (RcsGenericException e) {\n                    showException(e);\n                }\n            }\n        };\n    }\n\n    private void displayComposingEvent(ContactId contact, final boolean status) {\n        final String from = RcsContactUtil.getInstance(this).getDisplayName(contact);\n        mHandler.post(new Runnable() {\n            public void run() {\n                TextView view = (TextView) findViewById(R.id.isComposingText);\n                if (status) {\n                    // Display is-composing notification\n                    view.setText(getString(R.string.label_contact_is_composing, from));\n                    view.setVisibility(View.VISIBLE);\n                } else {\n                    // Hide is-composing notification\n                    view.setVisibility(View.GONE);\n                }\n            }\n        });\n    }\n\n    private void sendText() {\n        String text = mComposeText.getText().toString();\n        if (!TextUtils.isEmpty(text)) {\n            try {\n                sendMessage(text);\n                mComposingManager.messageWasSent();\n                mComposeText.setText(null);\n            } catch (RcsServiceException e) {\n                showExceptionThenExit(e);\n            }\n        }\n    }\n\n    private void addQuickText() {\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.label_select_quicktext);\n        builder.setCancelable(true);\n        builder.setItems(R.array.select_quicktext, new DialogInterface.OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                String[] items = getResources().getStringArray(R.array.select_quicktext);\n                mComposeText.append(items[which]);\n            }\n        });\n        registerDialog(builder.show());\n    }\n\n    private void getGeoLoc() {\n        // Start a new activity to send a geolocation\n        startActivityForResult(new Intent(this, EditGeoloc.class), SELECT_GEOLOCATION);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/OneToOneTalkView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsFragmentActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RI;\nimport com.gsma.rcs.ri.messaging.adapter.TalkCursorAdapter;\nimport com.gsma.rcs.ri.messaging.chat.ChatCursorObserver;\nimport com.gsma.rcs.ri.messaging.chat.ChatMessageLogView;\nimport com.gsma.rcs.ri.messaging.chat.ChatPendingIntentManager;\nimport com.gsma.rcs.ri.messaging.chat.IsComposingManager;\nimport com.gsma.rcs.ri.messaging.chat.single.SendSingleFile;\nimport com.gsma.rcs.ri.messaging.chat.single.SingleChatIntentService;\nimport com.gsma.rcs.ri.messaging.filetransfer.FileTransferIntentService;\nimport com.gsma.rcs.ri.messaging.filetransfer.FileTransferLogView;\nimport com.gsma.rcs.ri.messaging.geoloc.EditGeoloc;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.chat.ChatServiceConfiguration;\nimport com.gsma.services.rcs.chat.OneToOneChat;\nimport com.gsma.services.rcs.chat.OneToOneChatIntent;\nimport com.gsma.services.rcs.chat.OneToOneChatListener;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\n\nimport android.app.AlertDialog;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Parcelable;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.text.Editable;\nimport android.text.InputFilter;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.util.Log;\nimport android.view.ContextMenu;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * One to one talk view : aggregates the RCS IM messages.\n *\n * @author Philippe LEMORDANT\n */\npublic class OneToOneTalkView extends RcsFragmentActivity implements\n        LoaderManager.LoaderCallbacks<Cursor> {\n\n    /**\n     * The loader's unique ID. Loader IDs are specific to the Activity in which they reside.\n     */\n    private static final int LOADER_ID = 1;\n\n    // @formatter:off\n    private static final String[] PROJECTION = new String[]{\n            HistoryLog.BASECOLUMN_ID,\n            HistoryLog.ID,\n            HistoryLog.PROVIDER_ID,\n            HistoryLog.MIME_TYPE,\n            HistoryLog.CONTENT,\n            HistoryLog.TIMESTAMP,\n            HistoryLog.STATUS,\n            HistoryLog.DIRECTION,\n            HistoryLog.CONTACT,\n            HistoryLog.EXPIRED_DELIVERY,\n            HistoryLog.FILENAME,\n            HistoryLog.FILESIZE,\n            HistoryLog.TRANSFERRED,\n            HistoryLog.REASON_CODE,\n            HistoryLog.READ_STATUS};\n    // @formatter:on\n\n    private final static String EXTRA_CONTACT = \"contact\";\n\n    private static final String LOGTAG = LogUtils.getTag(OneToOneTalkView.class.getSimpleName());\n    /**\n     * Chat_id is set to contact id for one to one chat and file transfer messages.\n     */\n    private static final String WHERE_CLAUSE = HistoryLog.CHAT_ID + \"=?\";\n    private final static String ORDER_ASC = HistoryLog.TIMESTAMP + \" ASC\";\n\n    private static final String OPEN_TALK = \"open_talk\";\n\n    private final static int SELECT_GEOLOCATION = 0;\n\n    /**\n     * The adapter that binds data to the ListView\n     */\n    private TalkCursorAdapter mAdapter;\n    private Uri mUriHistoryProvider;\n    private ContactId mContact;\n    private ChatCursorObserver mObserver;\n    private EditText mComposeText;\n    private ChatService mChatService;\n    private OneToOneChat mChat;\n    private FileTransferService mFileTransferService;\n    private OneToOneChatListener mChatListener;\n    private OneToOneFileTransferListener mFileTransferListener;\n    private Handler mHandler;\n    private AlertDialog mClearUndeliveredAlertDialog;\n    private DialogInterface.OnCancelListener mUndeliveredCancelListener;\n    /**\n     * Utility class to manage the is-composing status\n     */\n    private IsComposingManager mComposingManager;\n    private CapabilityService mCapabilityService;\n    private Context mCtx;\n\n    // @formatter:off\n    private static final Set<String> sAllowedIntentActions = new HashSet<>(Arrays.asList(\n            OneToOneChatIntent.ACTION_MESSAGE_DELIVERY_EXPIRED,\n            OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE,\n            FileTransferIntent.ACTION_FILE_TRANSFER_DELIVERY_EXPIRED,\n            OPEN_TALK));\n    // @formatter:on\n\n    private DialogInterface.OnClickListener mClearUndeliveredChat;\n    private DialogInterface.OnClickListener mClearUndeliveredFt;\n    private boolean mChatListenerSet;\n    private boolean mFileTransferListenerSet;\n\n    /**\n     * Forge intent to start XmsView activity\n     *\n     * @param context The context\n     * @param contact The contact ID\n     * @return intent\n     */\n    public static Intent forgeIntentToOpenConversation(Context context, ContactId contact) {\n        Intent intent = new Intent(context, OneToOneTalkView.class);\n        intent.setAction(OPEN_TALK);\n        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.putExtra(EXTRA_CONTACT, (Parcelable) contact);\n        return intent;\n    }\n\n    /**\n     * Forge intent to start OneToOneTalkView activity upon reception of a stack event\n     *\n     * @param ctx The context\n     * @param contact The contact ID\n     * @param intent intent\n     * @return intent\n     */\n    public static Intent forgeIntentOnStackEvent(Context ctx, ContactId contact, Intent intent) {\n        intent.setClass(ctx, OneToOneTalkView.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.putExtra(EXTRA_CONTACT, (Parcelable) contact);\n        return intent;\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.chat_view);\n        if (!isServiceConnected(ConnectionManager.RcsServiceName.CONTACT,\n                ConnectionManager.RcsServiceName.CHAT,\n                ConnectionManager.RcsServiceName.FILE_TRANSFER,\n                ConnectionManager.RcsServiceName.CAPABILITY)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(ConnectionManager.RcsServiceName.CONTACT,\n                ConnectionManager.RcsServiceName.CHAT,\n                ConnectionManager.RcsServiceName.FILE_TRANSFER,\n                ConnectionManager.RcsServiceName.CAPABILITY);\n        try {\n            initialize();\n            processIntent(getIntent());\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void sendText() {\n        final String text = mComposeText.getText().toString();\n        if (TextUtils.isEmpty(text)) {\n            return;\n        }\n        try {\n            if (mChat != null) {\n                mChat.sendMessage(text);\n            }\n            mComposeText.setText(null);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void initialize() throws RcsGenericException, RcsServiceNotAvailableException {\n        mCtx = this;\n        /* Set send button listener */\n        Button sendBtn = (Button) findViewById(R.id.send_button);\n        sendBtn.setOnClickListener(new View.OnClickListener() {\n\n            @Override\n            public void onClick(View v) {\n                sendText();\n            }\n        });\n        mHandler = new Handler();\n        mClearUndeliveredChat = new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                Set<String> msgIds = SingleChatIntentService.getUndelivered(mCtx, mContact);\n                if (!msgIds.isEmpty()) {\n                    try {\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"Clear delivery expiration for IDs=\" + msgIds);\n                        }\n                        mChatService.clearMessageDeliveryExpiration(msgIds);\n\n                    } catch (RcsServiceException e) {\n                        showException(e);\n                    } finally {\n                        mClearUndeliveredAlertDialog = null;\n                    }\n                }\n            }\n        };\n        mUndeliveredCancelListener = new DialogInterface.OnCancelListener() {\n            @Override\n            public void onCancel(DialogInterface dialog) {\n                mClearUndeliveredAlertDialog = null;\n            }\n        };\n        mClearUndeliveredFt = new DialogInterface.OnClickListener() {\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                try {\n                    Set<String> transferIds = FileTransferIntentService.getUndelivered(mCtx,\n                            mContact);\n                    if (!transferIds.isEmpty()) {\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"Clear delivery expiration for IDs=\" + transferIds);\n                        }\n                        mFileTransferService.clearFileTransferDeliveryExpiration(transferIds);\n                        mClearUndeliveredAlertDialog = null;\n                    }\n                } catch (RcsServiceException e) {\n                    showException(e);\n                } finally {\n                    mClearUndeliveredAlertDialog = null;\n                }\n            }\n        };\n\n        mChatListener = new OneToOneChatListener() {\n\n            /* Callback called when an Is-composing event has been received */\n            @Override\n            public void onComposingEvent(ContactId contact, boolean status) {\n                /* Discard event if not for current contact */\n                if (!contact.equals(mContact)) {\n                    return;\n                }\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onComposingEvent contact=\" + contact + \" status=\" + status);\n                }\n                displayComposingEvent(contact, status);\n            }\n\n            @Override\n            public void onMessageStatusChanged(ContactId contact, String mimeType, String msgId,\n                    ChatLog.Message.Content.Status status,\n                    ChatLog.Message.Content.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessageStatusChanged contact=\" + contact + \" mime-type=\"\n                            + mimeType + \" msgId=\" + msgId + \" status=\" + status);\n                }\n            }\n\n            @Override\n            public void onMessagesDeleted(ContactId contact, Set<String> msgIds) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessagesDeleted contact=\" + contact + \" for IDs=\" + msgIds);\n                }\n            }\n\n        };\n        mFileTransferListener = new OneToOneFileTransferListener() {\n            @Override\n            public void onStateChanged(ContactId contact, String transferId,\n                    FileTransfer.State state, FileTransfer.ReasonCode reasonCode) {\n                if (!contact.equals(mContact)) {\n                    return;\n                }\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" transferId=\" + transferId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                if (FileTransfer.State.TRANSFERRED == state) {\n                    try {\n                        FileTransfer fileTransfer = mFileTransferService\n                                .getFileTransfer(transferId);\n                        if (fileTransfer == null) {\n                            return;\n                        }\n                        if (Utils.isAudioType(fileTransfer.getMimeType())\n                                && FileTransfer.Disposition.RENDER == fileTransfer.getDisposition()) {\n                            Utils.playAudio(OneToOneTalkView.this, fileTransfer.getFile());\n                            mFileTransferService.markFileTransferAsRead(transferId);\n                        }\n                    } catch (RcsPersistentStorageException | RcsServiceNotAvailableException\n                            | RcsGenericException e) {\n                        showException(e);\n                    }\n                }\n            }\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String transferId, long currentSize,\n                    long totalSize) {\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> transferIds) {\n            }\n        };\n        mChatService = getChatApi();\n        mCapabilityService = getCapabilityApi();\n        mFileTransferService = getFileTransferApi();\n\n        HistoryUriBuilder uriBuilder = new HistoryUriBuilder(HistoryLog.CONTENT_URI);\n        uriBuilder.appendProvider(ChatLog.Message.HISTORYLOG_MEMBER_ID);\n        uriBuilder.appendProvider(FileTransferLog.HISTORYLOG_MEMBER_ID);\n        mUriHistoryProvider = uriBuilder.build();\n\n        mComposeText = (EditText) findViewById(R.id.userText);\n        ChatServiceConfiguration configuration = mChatService.getConfiguration();\n        // Set max label length\n        int maxMsgLength = configuration.getOneToOneChatMessageMaxLength();\n        if (maxMsgLength > 0) {\n            /* Set the message composer max length */\n            InputFilter[] filterArray = new InputFilter[1];\n            filterArray[0] = new InputFilter.LengthFilter(maxMsgLength);\n            mComposeText.setFilters(filterArray);\n        }\n        IsComposingManager.INotifyComposing iNotifyComposing = new IsComposingManager.INotifyComposing() {\n            public void setTypingStatus(boolean isTyping) {\n                try {\n                    if (mChat == null) {\n                        return;\n                    }\n                    mChat.setComposingStatus(isTyping);\n                    if (LogUtils.isActive) {\n                        Boolean _isTyping = isTyping;\n                        Log.d(LOGTAG, \"sendIsComposingEvent \".concat(_isTyping.toString()));\n                    }\n                } catch (RcsGenericException e) {\n                    showException(e);\n                }\n            }\n        };\n        /* Instantiate the composing manager */\n        mComposingManager = new IsComposingManager(configuration.getIsComposingTimeout(),\n                iNotifyComposing);\n        mComposeText.addTextChangedListener(new TextWatcher() {\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                // Check if the text is not null.\n                // we do not wish to consider putting the edit text back to null\n                // (like when sending message), is having activity\n                if (!TextUtils.isEmpty(s)) {\n                    // Warn the composing manager that we have some activity\n                    if (mComposingManager != null) {\n                        mComposingManager.hasActivity();\n                    }\n                }\n            }\n\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n            }\n        });\n\n        /* Initialize the adapter. */\n        mAdapter = new TalkCursorAdapter(this, true, mChatService, mFileTransferService);\n\n        /* Associate the list adapter with the ListView. */\n        ListView listView = (ListView) findViewById(android.R.id.list);\n        listView.setDivider(null);\n        listView.setAdapter(mAdapter);\n        registerForContextMenu(listView);\n    }\n\n    private boolean processIntent(Intent intent) {\n        String action = intent.getAction();\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"processIntent \" + action);\n        }\n        ContactId newContact = intent.getParcelableExtra(EXTRA_CONTACT);\n        if (newContact == null) {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"Cannot process intent: contact is null\");\n            }\n            return false;\n        }\n        if (action == null) {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"Cannot process intent: action is null\");\n            }\n            return false;\n        }\n        if (!sAllowedIntentActions.contains(action)) {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"Cannot process intent: unauthorized action \" + action);\n            }\n            return false;\n        }\n        try {\n            if (!newContact.equals(mContact)) {\n                /* Either it is the first conversation loading or switch to another conversation */\n                loadConversation(newContact);\n            }\n            /* Set activity title with display name */\n            String displayName = RcsContactUtil.getInstance(this).getDisplayName(mContact);\n            setTitle(getString(R.string.title_chat, displayName));\n            switch (action) {\n                case OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE:\n                    /*\n                     * Open chat to accept session if the parameter IM SESSION START is 0. Client\n                     * application is not aware of the one to one chat session state nor of the IM\n                     * session start mode so we call the method systematically.\n                     */\n                    mChat.openChat();\n                    break;\n\n                case OneToOneChatIntent.ACTION_MESSAGE_DELIVERY_EXPIRED:\n                    processUndeliveredMessages(displayName);\n                    break;\n\n                case FileTransferIntent.ACTION_FILE_TRANSFER_DELIVERY_EXPIRED:\n                    processUndeliveredFileTransfers(displayName);\n                    break;\n            }\n            return true;\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return false;\n        }\n    }\n\n    private void clearNotification() {\n        ChatPendingIntentManager pendingIntentManager = ChatPendingIntentManager\n                .getChatPendingIntentManager(this);\n        pendingIntentManager.clearNotification(mContact.toString());\n    }\n\n    private void loadConversation(ContactId newContact) throws RcsServiceNotAvailableException,\n            RcsGenericException, RcsPersistentStorageException {\n        boolean firstLoad = (mContact == null);\n        /* Save contact ID */\n        mContact = newContact;\n        clearNotification();\n        /*\n         * Open chat so that if the parameter IM SESSION START is 0 then the session is accepted\n         * now.\n         */\n        mChat = mChatService.getOneToOneChat(mContact);\n        setCursorLoader(firstLoad);\n        RI.sChatIdOnForeground = mContact.toString();\n        /* Request for capabilities ony if they are not available or expired */\n        requestCapabilities(mContact);\n    }\n\n    private void setCursorLoader(boolean firstLoad) {\n        if (firstLoad) {\n            /*\n             * Initialize the Loader with id '1' and callbacks 'mCallbacks'.\n             */\n            getSupportLoaderManager().initLoader(LOADER_ID, null, this);\n        } else {\n            /* We switched from one contact to another: reload history since */\n            getSupportLoaderManager().restartLoader(LOADER_ID, null, this);\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"--> onPause\");\n        }\n        super.onPause();\n        RI.sChatIdOnForeground = null;\n        try {\n            if (mChatListener != null && mChatService != null && mChatListenerSet) {\n                mChatService.removeEventListener(mChatListener);\n                mChatListenerSet = false;\n            }\n            if (mFileTransferListener != null && mFileTransferService != null\n                    && mFileTransferListenerSet) {\n                mFileTransferService.removeEventListener(mFileTransferListener);\n                mFileTransferListenerSet = false;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsGenericException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        /* Replace the value of intent */\n        setIntent(intent);\n        processIntent(intent);\n    }\n\n    @Override\n    protected void onResume() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"--> onResume\");\n        }\n        super.onResume();\n        if (mContact != null) {\n            RI.sChatIdOnForeground = mContact.toString();\n            clearNotification();\n        }\n        try {\n            if (mChatListener != null && mChatService != null && !mChatListenerSet) {\n                mChatService.addEventListener(mChatListener);\n                mChatListenerSet = true;\n            }\n            if (mFileTransferListener != null && mFileTransferService != null\n                    && !mFileTransferListenerSet) {\n                mFileTransferService.addEventListener(mFileTransferListener);\n                mFileTransferListenerSet = true;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsGenericException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_1to1_talk, menu);\n        return true;\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n        switch (requestCode) {\n            case SELECT_GEOLOCATION:\n                Geoloc geoloc = data.getParcelableExtra(EditGeoloc.EXTRA_GEOLOC);\n                try {\n                    if (mChat != null) {\n                        mChat.sendMessage(geoloc);\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n                break;\n        }\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_send_geoloc:\n                    /* Start a new activity to select a geolocation */\n                    startActivityForResult(new Intent(this, EditGeoloc.class), SELECT_GEOLOCATION);\n                    break;\n\n                case R.id.menu_send_rcs_file:\n                    SendSingleFile.startActivity(this, mContact);\n                    break;\n\n                case R.id.menu_delete_talk:\n                    mFileTransferService.deleteOneToOneFileTransfers(mContact);\n                    mChatService.deleteOneToOneChat(mContact);\n                    break;\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n        return true;\n    }\n\n    @Override\n    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {\n        super.onCreateContextMenu(menu, v, menuInfo);\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.menu_1to1_talk_item, menu);\n        menu.findItem(R.id.menu_resend_message).setVisible(false);\n        menu.findItem(R.id.menu_display_content).setVisible(false);\n        menu.findItem(R.id.menu_listen_content).setVisible(false);\n        /* Get the list item position */\n        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;\n        Cursor cursor = (Cursor) mAdapter.getItem(info.position);\n        /* Adapt the contextual menu according to the selected item */\n        int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n        String id = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        Direction direction = Direction.valueOf(cursor.getInt(cursor\n                .getColumnIndexOrThrow(HistoryLog.DIRECTION)));\n        try {\n            switch (providerId) {\n                case ChatLog.Message.HISTORYLOG_MEMBER_ID:\n                    if (Direction.OUTGOING == direction) {\n                        ChatLog.Message.Content.Status status = ChatLog.Message.Content.Status\n                                .valueOf(cursor.getInt(cursor\n                                        .getColumnIndexOrThrow(HistoryLog.STATUS)));\n                        if (ChatLog.Message.Content.Status.FAILED == status) {\n                            String number = cursor.getString(cursor\n                                    .getColumnIndexOrThrow(HistoryLog.CONTACT));\n                            if (number != null) {\n                                ContactId contact = ContactUtil.formatContact(number);\n                                OneToOneChat chat = mChatService.getOneToOneChat(contact);\n                                if (chat != null && chat.isAllowedToSendMessage()) {\n                                    menu.findItem(R.id.menu_resend_message).setVisible(true);\n                                }\n                            }\n                        }\n                    }\n                    break;\n\n                case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                    String mimeType = cursor.getString(cursor\n                            .getColumnIndexOrThrow(HistoryLog.MIME_TYPE));\n                    FileTransfer.State state = FileTransfer.State.valueOf(cursor.getInt(cursor\n                            .getColumnIndexOrThrow(HistoryLog.STATUS)));\n                    if (FileTransfer.State.FAILED == state) {\n                        FileTransfer transfer = mFileTransferService.getFileTransfer(id);\n                        if (transfer != null && transfer.isAllowedToResendTransfer()) {\n                            menu.findItem(R.id.menu_resend_message).setVisible(true);\n                        }\n                    } else if (Utils.isImageType(mimeType)) {\n                        if (Direction.OUTGOING == direction) {\n                            menu.findItem(R.id.menu_display_content).setVisible(true);\n\n                        } else if (Direction.INCOMING == direction) {\n                            Long transferred = cursor.getLong(cursor\n                                    .getColumnIndexOrThrow(HistoryLog.TRANSFERRED));\n                            Long size = cursor.getLong(cursor\n                                    .getColumnIndexOrThrow(HistoryLog.FILESIZE));\n                            if (size.equals(transferred)) {\n                                menu.findItem(R.id.menu_display_content).setVisible(true);\n                            }\n                        }\n                    } else if (Utils.isAudioType(mimeType)) {\n                        if (Direction.OUTGOING == direction) {\n                            menu.findItem(R.id.menu_listen_content).setVisible(true);\n\n                        } else if (Direction.INCOMING == direction) {\n                            Long transferred = cursor.getLong(cursor\n                                    .getColumnIndexOrThrow(HistoryLog.TRANSFERRED));\n                            Long size = cursor.getLong(cursor\n                                    .getColumnIndexOrThrow(HistoryLog.FILESIZE));\n                            if (size.equals(transferred)) {\n                                menu.findItem(R.id.menu_listen_content).setVisible(true);\n                            }\n                        }\n                    }\n                    break;\n\n                default:\n                    throw new IllegalArgumentException(\"Invalid provider ID=\" + providerId);\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            menu.findItem(R.id.menu_resend_message).setVisible(false);\n\n        } catch (RcsGenericException | RcsPersistentStorageException e) {\n            menu.findItem(R.id.menu_resend_message).setVisible(false);\n            showException(e);\n        }\n    }\n\n    @Override\n    public boolean onContextItemSelected(MenuItem item) {\n        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item\n                .getMenuInfo();\n        Cursor cursor = (Cursor) (mAdapter.getItem(info.position));\n        int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n        String id = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onContextItemSelected Id=\".concat(id));\n        }\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_delete_message:\n                    switch (providerId) {\n                        case ChatLog.Message.HISTORYLOG_MEMBER_ID:\n                            mChatService.deleteMessage(id);\n                            return true;\n                        case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                            mFileTransferService.deleteFileTransfer(id);\n                            return true;\n                    }\n                    break;\n\n                case R.id.menu_resend_message:\n                    switch (providerId) {\n                        case ChatLog.Message.HISTORYLOG_MEMBER_ID:\n                            OneToOneChat chat = mChatService.getOneToOneChat(mContact);\n                            if (chat != null) {\n                                chat.resendMessage(id);\n                            }\n                            return true;\n\n                        case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                            FileTransfer fileTransfer = mFileTransferService.getFileTransfer(id);\n                            if (fileTransfer != null) {\n                                fileTransfer.resendTransfer();\n                            }\n                            return true;\n                    }\n                    break;\n\n                case R.id.menu_display_content:\n                    switch (providerId) {\n                        case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                            String file = cursor.getString(cursor\n                                    .getColumnIndexOrThrow(HistoryLog.CONTENT));\n                            Utils.showPicture(this, Uri.parse(file));\n                            markFileTransferAsRead(cursor, id);\n                            return true;\n                    }\n                    break;\n\n                case R.id.menu_view_detail:\n                    switch (providerId) {\n                        case ChatLog.Message.HISTORYLOG_MEMBER_ID:\n                            ChatMessageLogView.startActivity(this, id);\n                            return true;\n                        case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                            FileTransferLogView.startActivity(this, id);\n                            return true;\n                    }\n                    break;\n\n                case R.id.menu_listen_content:\n                    if (FileTransferLog.HISTORYLOG_MEMBER_ID == providerId) {\n                        String file = cursor.getString(cursor\n                                .getColumnIndexOrThrow(HistoryLog.CONTENT));\n                        Utils.playAudio(this, Uri.parse(file));\n                        markFileTransferAsRead(cursor, id);\n                        return true;\n                    }\n                    break;\n            }\n            return super.onContextItemSelected(item);\n\n        } catch (RcsGenericException | RcsPermissionDeniedException | RcsPersistentStorageException e) {\n            showException(e);\n            return true;\n\n        } catch (RcsServiceNotAvailableException e) {\n            Utils.displayLongToast(this, getString(R.string.label_service_not_available));\n            return true;\n        }\n    }\n\n    private void markFileTransferAsRead(Cursor cursor, String ftId) {\n        try {\n            Direction dir = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(HistoryLog.DIRECTION)));\n            if (Direction.INCOMING == dir) {\n                RcsService.ReadStatus status = RcsService.ReadStatus.valueOf(cursor.getInt(cursor\n                        .getColumnIndexOrThrow(HistoryLog.READ_STATUS)));\n                if (RcsService.ReadStatus.UNREAD == status) {\n                    mFileTransferService.markFileTransferAsRead(ftId);\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"Mark file transfer \" + ftId + \" as read\");\n                    }\n                }\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Cannot mark message as read: service not available\");\n            }\n        } catch (RcsGenericException | RcsPersistentStorageException e) {\n            Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        /* Create a new CursorLoader with the following query parameters. */\n        return new CursorLoader(this, mUriHistoryProvider, PROJECTION, WHERE_CLAUSE, new String[] {\n            mContact.toString()\n        }, ORDER_ASC);\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {\n        if (LOADER_ID == loader.getId()) {\n            /*\n             * The asynchronous load is complete and the data is now available for use. Only now can\n             * we associate the queried Cursor with the CursorAdapter.\n             */\n            mAdapter.swapCursor(data);\n            /**\n             * Registering content observer for XMS message content URI. When this content URI will\n             * change, this will notify the loader to reload its data.\n             */\n            if (mObserver != null && !mObserver.getLoader().equals(loader)) {\n                ContentResolver resolver = getContentResolver();\n                resolver.unregisterContentObserver(mObserver);\n                mObserver = null;\n            }\n            if (mObserver == null) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onLoadFinished: register content observer\");\n                }\n                mObserver = new ChatCursorObserver(new Handler(), loader);\n                ContentResolver resolver = getContentResolver();\n                resolver.registerContentObserver(ChatLog.Message.CONTENT_URI, true, mObserver);\n                resolver.registerContentObserver(FileTransferLog.CONTENT_URI, true, mObserver);\n            }\n        }\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        /*\n         * For whatever reason, the Loader's data is now unavailable. Remove any references to the\n         * old data by replacing it with a null Cursor.\n         */\n        mAdapter.swapCursor(null);\n    }\n\n    private void displayComposingEvent(final ContactId contact, final boolean status) {\n        final String from = RcsContactUtil.getInstance(this).getDisplayName(contact);\n        // Execute on UI handler since callback is executed from service\n        mHandler.post(new Runnable() {\n            public void run() {\n                TextView view = (TextView) findViewById(R.id.isComposingText);\n                if (status) {\n                    // Display is-composing notification\n                    view.setText(getString(R.string.label_contact_is_composing, from));\n                    view.setVisibility(View.VISIBLE);\n                } else {\n                    // Hide is-composing notification\n                    view.setVisibility(View.GONE);\n                }\n            }\n        });\n    }\n\n    private void processUndeliveredFileTransfers(String displayName) throws RcsGenericException,\n            RcsServiceNotAvailableException, RcsPersistentStorageException,\n            RcsPermissionDeniedException {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"processUndeliveredFileTransfers: ask\");\n        }\n        /* Do not propose to clear undelivered if a dialog is already opened */\n        if (mClearUndeliveredAlertDialog == null) {\n            mClearUndeliveredAlertDialog = popUpDeliveryExpiration(this,\n                    getString(R.string.title_undelivered_filetransfer),\n                    getString(R.string.label_undelivered_filetransfer, displayName),\n                    mClearUndeliveredFt, null, mUndeliveredCancelListener);\n            registerDialog(mClearUndeliveredAlertDialog);\n        }\n    }\n\n    private void processUndeliveredMessages(String displayName) throws RcsGenericException,\n            RcsPersistentStorageException, RcsServiceNotAvailableException {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"processUndeliveredMessages: ask\");\n        }\n        /* Do not propose to clear undelivered if a dialog is already opened */\n        if (mClearUndeliveredAlertDialog == null) {\n            mClearUndeliveredAlertDialog = popUpDeliveryExpiration(this,\n                    getString(R.string.title_undelivered_message),\n                    getString(R.string.label_undelivered_message, displayName),\n                    mClearUndeliveredChat, null, mUndeliveredCancelListener);\n            registerDialog(mClearUndeliveredAlertDialog);\n        }\n    }\n\n    private AlertDialog popUpDeliveryExpiration(Context ctx, String title, String msg,\n            DialogInterface.OnClickListener onPositiveClickListener,\n            DialogInterface.OnClickListener onNegativeClickListener,\n            DialogInterface.OnCancelListener onCancelListener) {\n        AlertDialog.Builder builder = new AlertDialog.Builder(ctx);\n        builder.setMessage(msg);\n        builder.setTitle(title);\n        if (onNegativeClickListener != null) {\n            builder.setNegativeButton(R.string.label_cancel, onNegativeClickListener);\n        }\n        builder.setPositiveButton(R.string.label_ok, onPositiveClickListener);\n        builder.setOnCancelListener(onCancelListener);\n        return builder.show();\n    }\n\n    private void requestCapabilities(ContactId contact) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        try {\n            mCapabilityService.requestContactCapabilities(new HashSet<>(Collections\n                    .singletonList(contact)));\n\n        } catch (RcsServiceNotRegisteredException e) {\n            Log.w(LOGTAG, \"Cannot request capabilities: RCS not registered!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/TalkList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.adapter.TalkListArrayAdapter;\nimport com.gsma.rcs.ri.messaging.adapter.TalkListArrayItem;\nimport com.gsma.rcs.ri.messaging.chat.ChatPendingIntentManager;\nimport com.gsma.rcs.ri.messaging.filetransfer.multi.SendMultiFile;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChatIntent;\nimport com.gsma.services.rcs.chat.GroupChatListener;\nimport com.gsma.services.rcs.chat.OneToOneChatIntent;\nimport com.gsma.services.rcs.chat.OneToOneChatListener;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.GroupFileTransferListener;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.ContextMenu;\nimport android.view.ContextMenu.ContextMenuInfo;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.AdapterContextMenuInfo;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * List of conversations from the content provider: RCS chat + RCS file transfer\n *\n * @author Philippe LEMORDANT\n */\npublic class TalkList extends RcsActivity {\n\n    private TalkListArrayAdapter mAdapter;\n    private List<TalkListArrayItem> mMessageLogs;\n    private static final String LOGTAG = LogUtils.getTag(TalkList.class.getSimpleName());\n\n    private ChatService mChatService;\n    private FileTransferService mFileTransferService;\n    private boolean mOneToOneChatListenerSet;\n    private OneToOneChatListener mOneToOneChatListener;\n    private Context mCtx;\n    private boolean mFileTransferListenerSet;\n    private OneToOneFileTransferListener mOneToOneFileTransferListener;\n    private TalkListUpdate.TaskCompleted mUpdateTalkListListener;\n    private static boolean sActivityVisible;\n    private boolean mGroupChatListenerSet;\n    private GroupChatListener mGroupChatListener;\n    private GroupFileTransferListener mGroupFileTransferListener;\n    private boolean mGroupFileTransferListenerSet;\n    private boolean mTalkListOpenedToSendFile;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.chat_list);\n        initialize();\n        /*\n         * If action to launch activity is not null then activity is opened to transfer a file\n         */\n        mTalkListOpenedToSendFile = getIntent().getAction() != null;\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        String action = intent.getAction();\n        if (action == null) {\n            return;\n        }\n        switch (action) {\n            case GroupChatIntent.ACTION_NEW_INVITATION:\n            case GroupChatIntent.ACTION_NEW_GROUP_CHAT_MESSAGE:\n            case OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE:\n            case FileTransferIntent.ACTION_NEW_INVITATION:\n                /* Replace the value of intent */\n                setIntent(intent);\n                TalkListUpdate updateTalkList = new TalkListUpdate(this, mUpdateTalkListListener);\n                updateTalkList.execute();\n                break;\n\n            default:\n                throw new IllegalArgumentException(\"Invalid action=\" + action);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        sActivityVisible = true;\n        addServiceListeners();\n        updateView();\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        sActivityVisible = false;\n        removeServiceListeners();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_log, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_clear_log:\n                    /* Delete all messages */\n                    if (!isServiceConnected(RcsServiceName.CHAT, RcsServiceName.FILE_TRANSFER)) {\n                        showMessage(R.string.label_service_not_available);\n                        break;\n                    }\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"delete conversations\");\n                    }\n                    mChatService.deleteOneToOneChats();\n                    mChatService.deleteGroupChats();\n                    mFileTransferService.deleteOneToOneFileTransfers();\n                    mFileTransferService.deleteGroupFileTransfers();\n                    break;\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            showMessage(R.string.label_service_not_available);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n        return true;\n    }\n\n    @Override\n    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\n        super.onCreateContextMenu(menu, v, menuInfo);\n        MenuInflater inflater = getMenuInflater();\n        inflater.inflate(R.menu.menu_log_item, menu);\n    }\n\n    @Override\n    public boolean onContextItemSelected(MenuItem item) {\n        /* Get selected item */\n        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();\n        TalkListArrayItem message = mAdapter.getItem(info.position);\n        String chatId = message.getChatId();\n        ContactId contact = message.getContact();\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onContextItemSelected chatId=\".concat(chatId));\n        }\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_delete_message:\n                    if (!isServiceConnected(RcsServiceName.CHAT, RcsServiceName.FILE_TRANSFER)) {\n                        showMessage(R.string.error_conversation_delete);\n                        return true;\n                    }\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"Delete conversation for chatId=\".concat(chatId));\n                    }\n                    if (message.isGroupChat()) {\n                        mChatService.deleteGroupChat(chatId);\n                        mFileTransferService.deleteGroupFileTransfers(chatId);\n                    } else {\n                        mChatService.deleteOneToOneChat(contact);\n                        mFileTransferService.deleteOneToOneFileTransfers(contact);\n                    }\n                    return true;\n\n                default:\n                    return super.onContextItemSelected(item);\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return true;\n        }\n    }\n\n    private void updateView() {\n        if (sActivityVisible) {\n            TalkListUpdate updateTalkList = new TalkListUpdate(mCtx, mUpdateTalkListListener);\n            updateTalkList.execute();\n        }\n    }\n\n    private void initialize() {\n        mCtx = this;\n        mMessageLogs = new ArrayList<>();\n        mChatService = getChatApi();\n        mFileTransferService = getFileTransferApi();\n        ListView listView = (ListView) findViewById(android.R.id.list);\n        TextView emptyView = (TextView) findViewById(android.R.id.empty);\n        listView.setEmptyView(emptyView);\n        registerForContextMenu(listView);\n        mAdapter = new TalkListArrayAdapter(this, mMessageLogs);\n        listView.setAdapter(mAdapter);\n        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {\n            @Override\n            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {\n                TalkListArrayItem message = mAdapter.getItem(position);\n                boolean gchat = message.isGroupChat();\n                if (mTalkListOpenedToSendFile) {\n                    // Open multiple file transfer\n                    SendMultiFile.startActivity(TalkList.this, getIntent(), !gchat,\n                            message.getChatId());\n                    return;\n                }\n                if (gchat) {\n                    GroupTalkView.openGroupChat(mCtx, message.getChatId());\n                } else {\n                    startActivity(OneToOneTalkView.forgeIntentToOpenConversation(mCtx,\n                            message.getContact()));\n                }\n            }\n        });\n        mOneToOneFileTransferListener = new OneToOneFileTransferListener() {\n            @Override\n            public void onStateChanged(ContactId contact, String transferId,\n                    FileTransfer.State state, FileTransfer.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String transferId, long currentSize,\n                    long totalSize) {\n            }\n\n            @Override\n            public void onDeleted(final ContactId contact, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDeleted contact=\" + contact + \" FT IDs=\" + transferIds);\n                }\n                updateView();\n            }\n        };\n        mOneToOneChatListener = new OneToOneChatListener() {\n            @Override\n            public void onMessageStatusChanged(ContactId contact, String mimeType, String msgId,\n                    ChatLog.Message.Content.Status status,\n                    ChatLog.Message.Content.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onComposingEvent(ContactId contact, boolean status) {\n            }\n\n            @Override\n            public void onMessagesDeleted(final ContactId contact, Set<String> msgIds) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessagesDeleted contact=\" + contact + \" msg IDs=\" + msgIds);\n                }\n                updateView();\n            }\n        };\n        mGroupFileTransferListener = new GroupFileTransferListener() {\n            @Override\n            public void onStateChanged(String chatId, String transferId, FileTransfer.State state,\n                    FileTransfer.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n                    GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onProgressUpdate(String chatId, String transferId, long currentSize,\n                    long totalSize) {\n            }\n\n            @Override\n            public void onDeleted(String chatId, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDeleted ftIds=\" + transferIds);\n                }\n                updateView();\n            }\n        };\n        mGroupChatListener = new GroupChatListener() {\n            @Override\n            public void onStateChanged(String chatId, GroupChat.State state,\n                    GroupChat.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onComposingEvent(String chatId, ContactId contact, boolean status) {\n            }\n\n            @Override\n            public void onMessageStatusChanged(String chatId, String mimeType, String msgId,\n                    ChatLog.Message.Content.Status status,\n                    ChatLog.Message.Content.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onMessageGroupDeliveryInfoChanged(String chatId, ContactId contact,\n                    String mimeType, String msgId, GroupDeliveryInfo.Status status,\n                    GroupDeliveryInfo.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onParticipantStatusChanged(String chatId, ContactId contact,\n                    GroupChat.ParticipantStatus status) {\n            }\n\n            @Override\n            public void onDeleted(Set<String> chatIds) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDeleted chatIds=\" + chatIds);\n                }\n                updateView();\n            }\n\n            @Override\n            public void onMessagesDeleted(final String chatId, Set<String> msgIds) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onMessagesDeleted msgIds=\" + msgIds);\n                }\n                updateView();\n            }\n        };\n        mUpdateTalkListListener = new TalkListUpdate.TaskCompleted() {\n            @Override\n            public void onTaskComplete(Collection<TalkListArrayItem> talks) {\n                if (talks == null) {\n                    TalkList.this.showMessageThenExit(R.string.cannot_read_log);\n                    return;\n                }\n                mMessageLogs.clear();\n                mMessageLogs.addAll(talks);\n                /* Sort by descending timestamp */\n                Collections.sort(mMessageLogs);\n                mAdapter.notifyDataSetChanged();\n                ChatPendingIntentManager talkPendingIntentManager = ChatPendingIntentManager\n                        .getChatPendingIntentManager(mCtx);\n                for (TalkListArrayItem talk : talks) {\n                    if (talk.getUnreadCount() == 0) {\n                        /*\n                         * TODO check that if invitation is pending, there is always at least one\n                         * unread message (assertion may be false)\n                         */\n                        talkPendingIntentManager.clearNotification(talk.getChatId());\n                    }\n                }\n            }\n        };\n    }\n\n    /**\n     * Notify new conversation event\n     *\n     * @param ctx the context\n     * @param action the action intent\n     */\n    public static void notifyNewConversationEvent(Context ctx, String action) {\n        if (sActivityVisible) {\n            Intent intent = new Intent(ctx, TalkList.class);\n            intent.setAction(action);\n            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n            ctx.startActivity(intent);\n        }\n    }\n\n    private void addServiceListeners() {\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER, RcsServiceName.CHAT)) {\n            return;\n        }\n        try {\n            if (!mGroupChatListenerSet) {\n                mChatService.addEventListener(mGroupChatListener);\n                mGroupChatListenerSet = true;\n            }\n            if (!mOneToOneChatListenerSet) {\n                mChatService.addEventListener(mOneToOneChatListener);\n                mOneToOneChatListenerSet = true;\n            }\n            if (!mFileTransferListenerSet) {\n                mFileTransferService.addEventListener(mOneToOneFileTransferListener);\n                mFileTransferListenerSet = true;\n            }\n            if (!mGroupFileTransferListenerSet) {\n                mFileTransferService.addEventListener(mGroupFileTransferListener);\n                mGroupFileTransferListenerSet = true;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    private void removeServiceListeners() {\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER, RcsServiceName.CHAT)) {\n            return;\n        }\n        try {\n            if (mGroupChatListenerSet) {\n                mChatService.removeEventListener(mGroupChatListener);\n                mGroupChatListenerSet = false;\n            }\n            if (mOneToOneChatListenerSet) {\n                mChatService.removeEventListener(mOneToOneChatListener);\n                mOneToOneChatListenerSet = false;\n            }\n            if (mFileTransferListenerSet) {\n                mFileTransferService.removeEventListener(mOneToOneFileTransferListener);\n                mFileTransferListenerSet = false;\n            }\n            if (mGroupFileTransferListenerSet) {\n                mFileTransferService.removeEventListener(mGroupFileTransferListener);\n                mGroupFileTransferListenerSet = false;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/TalkListUpdate.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.ri.messaging.adapter.TalkListArrayItem;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.util.Log;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A class to update the talk list in background\n *\n * @author Philippe LEMORDANT\n */\npublic class TalkListUpdate extends AsyncTask<Void, Void, Collection<TalkListArrayItem>> {\n\n    // @formatter:off\n    private static final String[] PROJECTION = new String[]{\n            HistoryLog.BASECOLUMN_ID,\n            HistoryLog.ID,\n            HistoryLog.CHAT_ID,\n            HistoryLog.PROVIDER_ID,\n            HistoryLog.MIME_TYPE,\n            HistoryLog.CONTENT,\n            HistoryLog.FILENAME,\n            HistoryLog.TIMESTAMP,\n            HistoryLog.DIRECTION,\n            HistoryLog.CONTACT,\n            HistoryLog.READ_STATUS,\n            HistoryLog.STATUS\n    };\n    // @formatter:on\n\n    private final TaskCompleted mTaskCompleted;\n    private final Context mCtx;\n    private static final String LOGTAG = LogUtils.getTag(TalkListUpdate.class.getSimpleName());\n\n    public TalkListUpdate(Context ctx, TaskCompleted taskCompleted) {\n        mCtx = ctx;\n        mTaskCompleted = taskCompleted;\n    }\n\n    @Override\n    protected Collection<TalkListArrayItem> doInBackground(Void... params) {\n        try {\n            /*\n             * The MMS sending is performed in background because the API returns a message instance\n             * only once it is persisted and to persist MMS, the core stack computes the file icon\n             * for image attached files.\n             */\n            return queryHistoryLogAndRefreshView();\n\n        } catch (RuntimeException e) {\n            Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            return null;\n        }\n    }\n\n    @Override\n    protected void onPostExecute(Collection<TalkListArrayItem> result) {\n        if (mTaskCompleted != null) {\n            mTaskCompleted.onTaskComplete(result);\n        }\n    }\n\n    public interface TaskCompleted {\n        void onTaskComplete(Collection<TalkListArrayItem> result);\n    }\n\n    private boolean isUnread(int providerId, RcsService.Direction dir,\n            RcsService.ReadStatus readStatus, int status) {\n        switch (providerId) {\n            case ChatLog.GroupChat.HISTORYLOG_MEMBER_ID:\n                return false;\n\n            case ChatLog.Message.HISTORYLOG_MEMBER_ID:\n                return RcsService.Direction.INCOMING == dir\n                        && RcsService.ReadStatus.UNREAD == readStatus;\n\n            case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                if (RcsService.Direction.INCOMING != dir) {\n                    return false;\n                }\n                FileTransfer.State state = FileTransfer.State.valueOf(status);\n                switch (state) {\n                    case INVITED:\n                    case TRANSFERRED:\n                    case ACCEPTING:\n                    case PAUSED:\n                    case STARTED:\n                        return RcsService.ReadStatus.UNREAD == readStatus;\n                    default:\n                        /*\n                         * We consider that if the file transfer is rejected or failed then it\n                         * cannot be read but should not be considered as unread.\n                         */\n                        return false;\n                }\n        }\n        throw new IllegalArgumentException(\"Invalid provider ID=\" + providerId);\n    }\n\n    Collection<TalkListArrayItem> queryHistoryLogAndRefreshView() {\n        HistoryUriBuilder uriBuilder = new HistoryUriBuilder(HistoryLog.CONTENT_URI);\n        uriBuilder.appendProvider(ChatLog.GroupChat.HISTORYLOG_MEMBER_ID);\n        uriBuilder.appendProvider(ChatLog.Message.HISTORYLOG_MEMBER_ID);\n        uriBuilder.appendProvider(FileTransferLog.HISTORYLOG_MEMBER_ID);\n        Uri mUriHistoryProvider = uriBuilder.build();\n        Map<String, TalkListArrayItem> dataMap = new HashMap<>();\n        Cursor cursor = null;\n        try {\n            cursor = mCtx.getContentResolver().query(mUriHistoryProvider, PROJECTION, null, null,\n                    null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query History Log\");\n            }\n            int columnTimestamp = cursor.getColumnIndexOrThrow(HistoryLog.TIMESTAMP);\n            int columnProviderId = cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID);\n            int columnDirection = cursor.getColumnIndexOrThrow(HistoryLog.DIRECTION);\n            int columnChatId = cursor.getColumnIndexOrThrow(HistoryLog.CHAT_ID);\n            int columnContact = cursor.getColumnIndexOrThrow(HistoryLog.CONTACT);\n            int columnContent = cursor.getColumnIndexOrThrow(HistoryLog.CONTENT);\n            int columnMimeType = cursor.getColumnIndexOrThrow(HistoryLog.MIME_TYPE);\n            int columnReadStatus = cursor.getColumnIndexOrThrow(HistoryLog.READ_STATUS);\n            int columnFilename = cursor.getColumnIndexOrThrow(HistoryLog.FILENAME);\n            int columnStatus = cursor.getColumnIndexOrThrow(HistoryLog.STATUS);\n            while (cursor.moveToNext()) {\n                long timestamp = cursor.getLong(columnTimestamp);\n                String chatId = cursor.getString(columnChatId);\n                String phoneNumber = cursor.getString(columnContact);\n                ContactId contact = null;\n                if (phoneNumber != null) {\n                    contact = ContactUtil.formatContact(phoneNumber);\n                }\n                RcsService.Direction dir = RcsService.Direction.valueOf(cursor\n                        .getInt(columnDirection));\n                RcsService.ReadStatus readStatus = RcsService.ReadStatus.valueOf(cursor\n                        .getInt(columnReadStatus));\n                TalkListArrayItem item = dataMap.get(chatId);\n                int providerId = cursor.getInt(columnProviderId);\n                int status = cursor.getInt(columnStatus);\n                boolean unread = isUnread(providerId, dir, readStatus, status);\n                int unreadCount = unread ? 1 : 0;\n                if (item != null) {\n                    /* Is it the newest item ? */\n                    if (timestamp < item.getTimestamp()) {\n                        /*\n                         * it is not the newest item then increment unread count of newest one then\n                         * read next\n                         */\n                        if (unread) {\n                            item.incrementUnreadCount();\n                        }\n                        continue;\n                    }\n                    unreadCount += item.getUnreadCount();\n                }\n                String content;\n                if (FileTransferLog.HISTORYLOG_MEMBER_ID != providerId) {\n                    /* There is not body text message for RCS file transfer */\n                    content = cursor.getString(columnContent);\n                } else {\n                    content = cursor.getString(columnFilename);\n                }\n                String mimeType = cursor.getString(columnMimeType);\n                if (ChatLog.GroupChat.HISTORYLOG_MEMBER_ID == providerId) {\n                    if (item != null) {\n                        item.setSubject(content);\n                    } else {\n                        item = new TalkListArrayItem(chatId, contact, timestamp, dir, null,\n                                mimeType, unreadCount);\n                        item.setSubject(content);\n                    }\n                } else if (item != null) {\n                    String subject = item.getSubject();\n                    item = new TalkListArrayItem(chatId, contact, timestamp, dir, content,\n                            mimeType, unreadCount);\n                    item.setSubject(subject);\n                } else {\n                    item = new TalkListArrayItem(chatId, contact, timestamp, dir, content,\n                            mimeType, unreadCount);\n                }\n                dataMap.put(chatId, item);\n            }\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n        return dataMap.values();\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/TestMessagingApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.chat.TestChatApi;\nimport com.gsma.rcs.ri.messaging.filetransfer.TestFileTransferApi;\n\nimport android.app.ListActivity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * Messaging API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestMessagingApi extends ListActivity {\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        // @formatter:off\n        String[] items = {\n                getString(R.string.menu_file_transfer),\n                getString(R.string.menu_chat),\n                getString(R.string.menu_messaging_log)\n        };\n        // @formatter:on\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, TestFileTransferApi.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, TestChatApi.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, TalkList.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/BasicViewHolder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.database.Cursor;\nimport android.view.View;\nimport android.widget.TextView;\n\n/**\n * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n * findViewById() or getColumnIndex() on each row.\n */\npublic class BasicViewHolder {\n    protected final int mColumnContactIdx;\n    protected final TextView mStatusText;\n    protected final TextView mTimestampText;\n    protected final int mColumnDirectionIdx;\n    protected final int mColumnTimestampIdx;\n    protected final TextView mContactText;\n    protected final int mColumnStatusIdx;\n    protected final int mColumnReasonCodeIdx;\n    protected final int mColumnMimetypeIdx;\n    protected final int mColumnReadStatusIdx;\n    protected final int mColumnIdIdx;\n\n    /**\n     * Constructor\n     *\n     * @param base view\n     * @param cursor cursor\n     */\n    public BasicViewHolder(View base, Cursor cursor) {\n        /* Save column indexes */\n        mColumnDirectionIdx = cursor.getColumnIndexOrThrow(HistoryLog.DIRECTION);\n        mColumnTimestampIdx = cursor.getColumnIndexOrThrow(HistoryLog.TIMESTAMP);\n        mColumnStatusIdx = cursor.getColumnIndexOrThrow(HistoryLog.STATUS);\n        mColumnMimetypeIdx = cursor.getColumnIndexOrThrow(HistoryLog.MIME_TYPE);\n        mColumnReasonCodeIdx = cursor.getColumnIndexOrThrow(HistoryLog.REASON_CODE);\n        mColumnContactIdx = cursor.getColumnIndexOrThrow(HistoryLog.CONTACT);\n        mColumnReadStatusIdx = cursor.getColumnIndexOrThrow(HistoryLog.READ_STATUS);\n        mColumnIdIdx = cursor.getColumnIndexOrThrow(HistoryLog.ID);\n        /* Save children views */\n        mStatusText = (TextView) base.findViewById(R.id.status_text);\n        mTimestampText = (TextView) base.findViewById(R.id.timestamp_text);\n        mContactText = (TextView) base.findViewById(R.id.contact_text);\n    }\n\n    public TextView getStatusText() {\n        return mStatusText;\n    }\n\n    public TextView getTimestampText() {\n        return mTimestampText;\n    }\n\n    public TextView getContactText() {\n        return mContactText;\n    }\n\n    public int getColumnDirectionIdx() {\n        return mColumnDirectionIdx;\n    }\n\n    public int getColumnTimestampIdx() {\n        return mColumnTimestampIdx;\n    }\n\n    public int getColumnStatusIdx() {\n        return mColumnStatusIdx;\n    }\n\n    public int getColumnMimetypeIdx() {\n        return mColumnMimetypeIdx;\n    }\n\n    public int getColumnReasonCodeIdx() {\n        return mColumnReasonCodeIdx;\n    }\n\n    public int getColumnContactIdx() {\n        return mColumnContactIdx;\n    }\n\n    public int getColumnReadStatusIdx() {\n        return mColumnReadStatusIdx;\n    }\n\n    public int getColumnIdIdx() {\n        return mColumnIdIdx;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/GroupDeliveryInfoCursorAdapter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfoLog;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.support.v4.widget.CursorAdapter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Locale;\n\n/**\n * @author YPLO6403\n */\npublic class GroupDeliveryInfoCursorAdapter extends CursorAdapter {\n\n    private LayoutInflater mInflater;\n\n    private final static SimpleDateFormat df = new SimpleDateFormat(\"yy-MM-dd HH:mm:ss\",\n            Locale.getDefault());\n\n    private Context mContext;\n\n    /**\n     * Constructor\n     * \n     * @param context The context\n     */\n    public GroupDeliveryInfoCursorAdapter(Context context) {\n        super(context, null, 0);\n        mInflater = LayoutInflater.from(context);\n        mContext = context;\n    }\n\n    @Override\n    public View newView(Context context, Cursor cursor, ViewGroup parent) {\n        final View view = mInflater.inflate(R.layout.delivery_info_item, parent, false);\n        // Save columns indexes and children views in cache\n        view.setTag(new ViewHolder(view, cursor));\n        return view;\n    }\n\n    @Override\n    public void bindView(View view, Context context, Cursor cursor) {\n        final ViewHolder holder = (ViewHolder) view.getTag();\n\n        // Set the deliver date/time field\n        long timestampDeliver = cursor.getLong(holder.columnTimestampDeliver);\n        // Set the deliver date/time field\n        long timestampDisplay = cursor.getLong(holder.columnTimestampDisplay);\n        // Set the status text\n        GroupDeliveryInfo.Status status = GroupDeliveryInfo.Status.valueOf(cursor\n                .getInt(holder.columnStatus));\n        // Set the reason text\n        GroupDeliveryInfo.ReasonCode reason = GroupDeliveryInfo.ReasonCode.valueOf(cursor\n                .getInt(holder.columnReason));\n        // Set the display name\n        String number = cursor.getString(holder.columnContact);\n        String displayName = RcsContactUtil.getInstance(mContext).getDisplayName(number);\n        holder.contactText.setText(mContext.getString(R.string.label_from_args, displayName));\n\n        if (timestampDeliver == 0) {\n            holder.deliverText.setVisibility(View.GONE);\n        } else {\n            holder.deliverText.setVisibility(View.VISIBLE);\n            holder.deliverText.setText(mContext.getString(R.string.label_state_delivered_at,\n                    df.format(timestampDeliver)));\n        }\n        /* Display information is only applicable to file transfers */\n        if (timestampDisplay == 0) {\n            holder.displayText.setVisibility(View.GONE);\n        } else {\n            holder.displayText.setVisibility(View.VISIBLE);\n            holder.displayText.setText(mContext.getString(R.string.label_state_displayed_at,\n                    df.format(timestampDisplay)));\n        }\n\n        String _status = mContext.getString(R.string.label_status,\n                RiApplication.sDeliveryStatuses[status.toInt()]);\n        holder.statusText.setText(_status);\n        if (reason != GroupDeliveryInfo.ReasonCode.UNSPECIFIED) {\n            holder.reasonText.setVisibility(View.VISIBLE);\n            String _reason = mContext.getString(R.string.label_reason_code_args,\n                    RiApplication.sDeliveryReasonCode[reason.toInt()]);\n            holder.reasonText.setText(_reason);\n        } else {\n            holder.reasonText.setVisibility(View.GONE);\n        }\n\n    }\n\n    /**\n     * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n     * findViewById() or getColumnIndex() on each row.\n     */\n    private class ViewHolder {\n        TextView statusText;\n\n        TextView reasonText;\n\n        TextView deliverText;\n\n        TextView displayText;\n\n        TextView contactText;\n\n        int columnContact;\n\n        int columnTimestampDeliver;\n\n        int columnTimestampDisplay;\n\n        int columnStatus;\n\n        int columnReason;\n\n        /**\n         * Constructor\n         * \n         * @param base the view\n         * @param cursor cursor\n         */\n        ViewHolder(View base, Cursor cursor) {\n            columnContact = cursor.getColumnIndexOrThrow(GroupDeliveryInfoLog.CONTACT);\n            columnTimestampDeliver = cursor\n                    .getColumnIndexOrThrow(GroupDeliveryInfoLog.TIMESTAMP_DELIVERED);\n            columnTimestampDisplay = cursor\n                    .getColumnIndexOrThrow(GroupDeliveryInfoLog.TIMESTAMP_DISPLAYED);\n            columnStatus = cursor.getColumnIndexOrThrow(GroupDeliveryInfoLog.STATUS);\n            columnReason = cursor.getColumnIndexOrThrow(GroupDeliveryInfoLog.REASON_CODE);\n            statusText = (TextView) base.findViewById(R.id.status);\n            contactText = (TextView) base.findViewById(R.id.contact);\n            deliverText = (TextView) base.findViewById(R.id.deliver);\n            displayText = (TextView) base.findViewById(R.id.display);\n            reasonText = (TextView) base.findViewById(R.id.reason);\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/RcsChatInViewHolder.java",
    "content": "/*\n * ******************************************************************************\n *  * Software Name : RCS IMS Stack\n *  *\n *  * Copyright (C) 2010-2016 Orange.\n *  *\n *  * Licensed under the Apache License, Version 2.0 (the \"License\");\n *  * you may not use this file except in compliance with the License.\n *  * You may obtain a copy of the License at\n *  *\n *  *      http://www.apache.org/licenses/LICENSE-2.0\n *  *\n *  * Unless required by applicable law or agreed to in writing, software\n *  * distributed under the License is distributed on an \"AS IS\" BASIS,\n *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  * See the License for the specific language governing permissions and\n *  * limitations under the License.\n *  *****************************************************************************\n */\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.database.Cursor;\nimport android.view.View;\nimport android.widget.TextView;\n\n/**\n * Created by yplo6403 on 01/12/2015.\n */\npublic class RcsChatInViewHolder extends BasicViewHolder {\n\n    private final TextView mContentText;\n\n    private final int mColumnContentIdx;\n\n    public RcsChatInViewHolder(View view, Cursor cursor) {\n        super(view, cursor);\n        /* Save column indexes */\n        mColumnContentIdx = cursor.getColumnIndexOrThrow(HistoryLog.CONTENT);\n        /* Save children views */\n        mContentText = (TextView) view.findViewById(R.id.content_text);\n    }\n\n    public TextView getContentText() {\n        return mContentText;\n    }\n\n    public int getColumnContentIdx() {\n        return mColumnContentIdx;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/RcsChatOutViewHolder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.database.Cursor;\nimport android.view.View;\n\npublic class RcsChatOutViewHolder extends RcsChatInViewHolder {\n    private final int mColumnExpiredDeliveryIdx;\n\n    public RcsChatOutViewHolder(View view, Cursor cursor) {\n        super(view, cursor);\n        /* Save column indexes */\n        mColumnExpiredDeliveryIdx = cursor.getColumnIndexOrThrow(HistoryLog.EXPIRED_DELIVERY);\n    }\n\n    public int getColumnExpiredDeliveryIdx() {\n        return mColumnExpiredDeliveryIdx;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/RcsFileTransferInViewHolder.java",
    "content": "/*\n * ******************************************************************************\n *  * Software Name : RCS IMS Stack\n *  *\n *  * Copyright (C) 2010-2016 Orange.\n *  *\n *  * Licensed under the Apache License, Version 2.0 (the \"License\");\n *  * you may not use this file except in compliance with the License.\n *  * You may obtain a copy of the License at\n *  *\n *  *      http://www.apache.org/licenses/LICENSE-2.0\n *  *\n *  * Unless required by applicable law or agreed to in writing, software\n *  * distributed under the License is distributed on an \"AS IS\" BASIS,\n *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  * See the License for the specific language governing permissions and\n *  * limitations under the License.\n *  *****************************************************************************\n */\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.database.Cursor;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\n/**\n * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n * findViewById() or getColumnIndex() on each row.\n */\npublic class RcsFileTransferInViewHolder extends BasicViewHolder {\n    private final TextView mProgressText;\n    private final ImageView mFileImageView;\n\n    private final int mColumnContentIdx;\n    private final int mColumnFilenameIdx;\n    private final int mColumnFilesizeIdx;\n    private final int mColumnTransferredIdx;\n    private final int mColumnContactIdx;\n\n    /**\n     * Constructor\n     *\n     * @param base view\n     * @param cursor cursor\n     */\n    RcsFileTransferInViewHolder(View base, Cursor cursor) {\n        super(base, cursor);\n        /* Save column indexes */\n        mColumnContentIdx = cursor.getColumnIndexOrThrow(HistoryLog.CONTENT);\n        mColumnFilenameIdx = cursor.getColumnIndexOrThrow(HistoryLog.FILENAME);\n        mColumnFilesizeIdx = cursor.getColumnIndexOrThrow(HistoryLog.FILESIZE);\n        mColumnTransferredIdx = cursor.getColumnIndexOrThrow(HistoryLog.TRANSFERRED);\n        mColumnContactIdx = cursor.getColumnIndexOrThrow(HistoryLog.CONTACT);\n        /* Save children views */\n        mProgressText = (TextView) base.findViewById(R.id.progress_text);\n        mFileImageView = (ImageView) base.findViewById(R.id.file_image);\n    }\n\n    public int getColumnContentIdx() {\n        return mColumnContentIdx;\n    }\n\n    public TextView getProgressText() {\n        return mProgressText;\n    }\n\n    public ImageView getFileImageView() {\n        return mFileImageView;\n    }\n\n    public int getColumnFilenameIdx() {\n        return mColumnFilenameIdx;\n    }\n\n    public int getColumnFilesizeIdx() {\n        return mColumnFilesizeIdx;\n    }\n\n    public int getColumnTransferredIdx() {\n        return mColumnTransferredIdx;\n    }\n\n    public int getColumnContactIdx() {\n        return mColumnContactIdx;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/RcsFileTransferOutViewHolder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.database.Cursor;\nimport android.view.View;\n\n/**\n * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n * findViewById() or getColumnIndex() on each row.\n */\npublic class RcsFileTransferOutViewHolder extends RcsFileTransferInViewHolder {\n    private final int mColumnExpiredDeliveryIdx;\n\n    /**\n     * Constructor\n     *\n     * @param base view\n     * @param cursor cursor\n     */\n    RcsFileTransferOutViewHolder(View base, Cursor cursor) {\n        super(base, cursor);\n        /* Save column indexes */\n        mColumnExpiredDeliveryIdx = cursor.getColumnIndexOrThrow(HistoryLog.EXPIRED_DELIVERY);\n    }\n\n    public int getColumnExpiredDeliveryIdx() {\n        return mColumnExpiredDeliveryIdx;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/TalkCursorAdapter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.BitmapCache;\nimport com.gsma.rcs.ri.utils.BitmapLoader;\nimport com.gsma.rcs.ri.utils.BitmapLoader.BitmapCacheInfo;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.ImageBitmapLoader;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.SmileyParser;\nimport com.gsma.rcs.ri.utils.Smileys;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.BitmapFactory.Options;\nimport android.net.Uri;\nimport android.support.v4.util.LruCache;\nimport android.support.v4.widget.CursorAdapter;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.text.format.DateUtils;\nimport android.util.Log;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout.LayoutParams;\nimport android.widget.TextView;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class TalkCursorAdapter extends CursorAdapter {\n\n    private static final String LOGTAG = LogUtils.getTag(TalkCursorAdapter.class.getName());\n\n    private static final int MAX_IMAGE_HEIGHT = 100;\n    private static final int MAX_IMAGE_WIDTH = 100;\n    private static final int VIEW_TYPE_RCS_CHAT_IN = 0;\n    private static final int VIEW_TYPE_RCS_CHAT_OUT = 1;\n    private static final int VIEW_TYPE_RCS_FILE_TRANSFER_IN = 2;\n    private static final int VIEW_TYPE_RCS_FILE_TRANSFER_OUT = 3;\n    private static final int VIEW_TYPE_RCS_GROUP_CHAT_EVENT = 4;\n    private final ChatService mChatService;\n    private final FileTransferService mFileTransferService;\n    private BitmapCache bitmapCache;\n    private final Activity mActivity;\n    private Map<ContactId, String> mContactIdDisplayNameMap;\n    private final LayoutParams mImageParams;\n    private final LayoutParams mImageParamsDefault;\n    private LayoutInflater mInflater;\n    private final boolean mSingleChat;\n    private Smileys mSmileyResources;\n\n    /**\n     * Constructor\n     *\n     * @param activity The activity\n     * @param singleChat True if single chat\n     * @param chatService the chat service\n     * @param fileTransferService the file transfer service\n     */\n    public TalkCursorAdapter(Activity activity, boolean singleChat, ChatService chatService,\n            FileTransferService fileTransferService) {\n        super(activity, null, 0);\n        mContactIdDisplayNameMap = new HashMap<>();\n        mActivity = activity;\n        mInflater = LayoutInflater.from(activity);\n        int size100Dp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100.0f,\n                mContext.getResources().getDisplayMetrics());\n        mImageParams = new LayoutParams(size100Dp, size100Dp);\n        Options opt = new Options();\n        opt.inJustDecodeBounds = true;\n        BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.ri_filetransfer_off, opt);\n        mImageParamsDefault = new LayoutParams(opt.outWidth * 2, opt.outHeight * 2);\n        bitmapCache = BitmapCache.getInstance();\n        mSmileyResources = new Smileys(activity);\n        mSingleChat = singleChat;\n        mChatService = chatService;\n        mFileTransferService = fileTransferService;\n    }\n\n    @Override\n    public View newView(Context context, Cursor cursor, ViewGroup parent) {\n        int viewType = getItemViewType(cursor);\n        switch (viewType) {\n            case VIEW_TYPE_RCS_CHAT_IN:\n                View view = mInflater.inflate(mSingleChat ? R.layout.talk_item_rcs_chat_in\n                        : R.layout.gchat_item_rcs_chat_in, parent, false);\n                view.setTag(new RcsChatInViewHolder(view, cursor));\n                return view;\n\n            case VIEW_TYPE_RCS_CHAT_OUT:\n                view = mInflater.inflate(mSingleChat ? R.layout.talk_item_rcs_chat_out\n                        : R.layout.gchat_item_rcs_chat_out, parent, false);\n                view.setTag(new RcsChatOutViewHolder(view, cursor));\n                return view;\n\n            case VIEW_TYPE_RCS_FILE_TRANSFER_IN:\n                view = mInflater.inflate(mSingleChat ? R.layout.talk_item_rcs_file_transfer_in\n                        : R.layout.gchat_item_rcs_file_transfer_in, parent, false);\n                view.setTag(new RcsFileTransferInViewHolder(view, cursor));\n                return view;\n\n            case VIEW_TYPE_RCS_FILE_TRANSFER_OUT:\n                view = mInflater.inflate(mSingleChat ? R.layout.talk_item_rcs_file_transfer_out\n                        : R.layout.gchat_item_rcs_file_transfer_out, parent, false);\n                view.setTag(new RcsFileTransferOutViewHolder(view, cursor));\n                return view;\n\n            case VIEW_TYPE_RCS_GROUP_CHAT_EVENT:\n                view = mInflater.inflate(R.layout.groupchat_event_view_item, parent, false);\n                view.setTag(new BasicViewHolder(view, cursor));\n                return view;\n            default:\n                throw new IllegalArgumentException(\"Invalid view type: '\" + viewType + \"'!\");\n        }\n    }\n\n    private void bindRemoteContact(View view, Context ctx, Cursor cursor) {\n        BasicViewHolder holder = (BasicViewHolder) view.getTag();\n        String displayName = null;\n        if (Direction.OUTGOING != Direction.valueOf(cursor.getInt(holder.getColumnDirectionIdx()))) {\n            String number = cursor.getString(holder.getColumnContactIdx());\n            if (number != null) {\n                ContactId contact = ContactUtil.formatContact(number);\n                if (mContactIdDisplayNameMap.containsKey(contact)) {\n                    displayName = mContactIdDisplayNameMap.get(contact);\n                } else {\n                    displayName = RcsContactUtil.getInstance(ctx).getDisplayName(contact);\n                    mContactIdDisplayNameMap.put(contact, displayName);\n                }\n            }\n            holder.getContactText().setText(displayName);\n        }\n    }\n\n    @Override\n    public void bindView(View view, Context ctx, Cursor cursor) {\n        if (!mSingleChat) {\n            bindRemoteContact(view, ctx, cursor);\n        }\n        int viewType = getItemViewType(cursor);\n        switch (viewType) {\n            case VIEW_TYPE_RCS_CHAT_IN:\n                bindRcsChatInView(view, cursor);\n                break;\n            case VIEW_TYPE_RCS_CHAT_OUT:\n                bindRcsChatOutView(view, cursor);\n                break;\n            case VIEW_TYPE_RCS_FILE_TRANSFER_IN:\n                bindRcsFileTransferInView(view, cursor);\n                break;\n            case VIEW_TYPE_RCS_FILE_TRANSFER_OUT:\n                bindRcsFileTransferOutView(view, cursor);\n                break;\n            case VIEW_TYPE_RCS_GROUP_CHAT_EVENT:\n                bindRcsGroupChatEvent(view, cursor);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Invalid view type: '\" + viewType + \"'!\");\n        }\n    }\n\n    public int getItemViewType(Cursor cursor) {\n        int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n        Direction direction = Direction.valueOf(cursor.getInt(cursor\n                .getColumnIndexOrThrow(HistoryLog.DIRECTION)));\n        String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.MIME_TYPE));\n        switch (providerId) {\n            case ChatLog.Message.HISTORYLOG_MEMBER_ID:\n                switch (mimeType) {\n                    case ChatLog.Message.MimeType.GROUPCHAT_EVENT:\n                        return VIEW_TYPE_RCS_GROUP_CHAT_EVENT;\n\n                    case ChatLog.Message.MimeType.GEOLOC_MESSAGE:\n                    case ChatLog.Message.MimeType.TEXT_MESSAGE:\n                        if (Direction.INCOMING == direction) {\n                            return VIEW_TYPE_RCS_CHAT_IN;\n                        }\n                        return VIEW_TYPE_RCS_CHAT_OUT;\n                }\n                throw new IllegalArgumentException(\"Invalid mime type: '\" + mimeType + \"'!\");\n\n            case FileTransferLog.HISTORYLOG_MEMBER_ID:\n                if (Direction.INCOMING == direction) {\n                    return VIEW_TYPE_RCS_FILE_TRANSFER_IN;\n                }\n                return VIEW_TYPE_RCS_FILE_TRANSFER_OUT;\n        }\n        throw new IllegalArgumentException(\"Invalid provider ID: '\" + providerId + \"'!\");\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return getItemViewType((Cursor) getItem(position));\n    }\n\n    @Override\n    public int getViewTypeCount() {\n        return 5;\n    }\n\n    private void bindRcsGroupChatEvent(View view, Cursor cursor) {\n        BasicViewHolder holder = (BasicViewHolder) view.getTag();\n        holder.getTimestampText().setText(\n                DateUtils.getRelativeTimeSpanString(cursor.getLong(holder.getColumnTimestampIdx()),\n                        System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                        DateUtils.FORMAT_ABBREV_RELATIVE));\n        String event = RiApplication.sGroupChatEvents[cursor.getInt(holder.getColumnStatusIdx())];\n        holder.getStatusText().setText(mActivity.getString(R.string.label_groupchat_event, event));\n    }\n\n    private void bindRcsFileTransferOutView(View view, Cursor cursor) {\n        RcsFileTransferOutViewHolder holder = (RcsFileTransferOutViewHolder) view.getTag();\n        holder.getTimestampText().setText(\n                DateUtils.getRelativeTimeSpanString(cursor.getLong(holder.getColumnTimestampIdx()),\n                        System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                        DateUtils.FORMAT_ABBREV_RELATIVE));\n        String mimeType = cursor.getString(holder.getColumnMimetypeIdx());\n        StringBuilder sb = new StringBuilder(cursor.getString(holder.getColumnFilenameIdx()));\n        long filesize = cursor.getLong(holder.getColumnFilesizeIdx());\n        long transferred = cursor.getLong(holder.getColumnTransferredIdx());\n        final ImageView imageView = holder.getFileImageView();\n        imageView.setOnClickListener(null);\n        imageView.setLayoutParams(mImageParamsDefault);\n        imageView.setImageResource(R.drawable.ri_filetransfer_on);\n        if (filesize != transferred) {\n            holder.getProgressText().setText(\n                    sb.append(\" : \").append(Utils.getProgressLabel(transferred, filesize))\n                            .toString());\n        } else {\n            holder.getProgressText().setText(\n                    sb.append(\" (\").append(FileUtils.humanReadableByteCount(filesize, true))\n                            .append(\")\").toString());\n        }\n        final Uri file = Uri.parse(cursor.getString(holder.getColumnContentIdx()));\n        if (Utils.isImageType(mimeType)) {\n            String filePath = FileUtils.getPath(mContext, file);\n            Bitmap imageBitmap = null;\n            if (filePath != null) {\n                LruCache<String, BitmapCacheInfo> memoryCache = bitmapCache.getMemoryCache();\n                BitmapCacheInfo bitmapCacheInfo = memoryCache.get(filePath);\n                if (bitmapCacheInfo == null) {\n                    ImageBitmapLoader loader = new ImageBitmapLoader(mContext, memoryCache,\n                            MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT, new BitmapLoader.SetViewCallback() {\n                                @Override\n                                public void loadView(BitmapCacheInfo cacheInfo) {\n                                    imageView.setImageBitmap(cacheInfo.getBitmap());\n                                    imageView.setLayoutParams(mImageParams);\n                                }\n                            });\n                    loader.execute(filePath);\n                } else {\n                    imageBitmap = bitmapCacheInfo.getBitmap();\n                }\n                if (imageBitmap != null) {\n                    imageView.setImageBitmap(imageBitmap);\n                    imageView.setLayoutParams(mImageParams);\n                }\n                imageView.setOnClickListener(new View.OnClickListener() {\n\n                    @Override\n                    public void onClick(View v) {\n                        Utils.showPicture(mActivity, file);\n                    }\n                });\n            }\n        } else if (Utils.isAudioType(mimeType)) {\n            imageView.setImageResource(R.drawable.headphone);\n            imageView.setOnClickListener(new View.OnClickListener() {\n\n                @Override\n                public void onClick(View v) {\n                    Utils.playAudio(mActivity, file);\n                }\n            });\n        }\n        holder.getStatusText().setText(getRcsFileTransferStatus(cursor, holder));\n        boolean undeliveredExpiration = cursor.getInt(holder.getColumnExpiredDeliveryIdx()) == 1;\n        holder.getStatusText().setCompoundDrawablesWithIntrinsicBounds(\n                undeliveredExpiration ? R.drawable.chat_view_undelivered : 0, 0, 0, 0);\n    }\n\n    private void bindRcsFileTransferInView(View view, Cursor cursor) {\n        final RcsFileTransferInViewHolder holder = (RcsFileTransferInViewHolder) view.getTag();\n        holder.getTimestampText().setText(\n                DateUtils.getRelativeTimeSpanString(cursor.getLong(holder.getColumnTimestampIdx()),\n                        System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                        DateUtils.FORMAT_ABBREV_RELATIVE));\n        String mimeType = cursor.getString(holder.getColumnMimetypeIdx());\n        StringBuilder sb = new StringBuilder(cursor.getString(holder.getColumnFilenameIdx()));\n        long filesize = cursor.getLong(holder.getColumnFilesizeIdx());\n        long transferred = cursor.getLong(holder.getColumnTransferredIdx());\n        final ImageView imageView = holder.getFileImageView();\n        imageView.setOnClickListener(null);\n        imageView.setLayoutParams(mImageParamsDefault);\n        imageView.setImageResource(R.drawable.ri_filetransfer_off);\n        if (filesize != transferred) {\n            holder.getProgressText().setText(\n                    sb.append(\" : \").append(Utils.getProgressLabel(transferred, filesize))\n                            .toString());\n        } else {\n            imageView.setImageResource(R.drawable.ri_filetransfer_on);\n            final Uri file = Uri.parse(cursor.getString(holder.getColumnContentIdx()));\n            final RcsService.ReadStatus readStatus = RcsService.ReadStatus.valueOf(cursor\n                    .getInt(holder.getColumnReadStatusIdx()));\n            final String id = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n            if (Utils.isImageType(mimeType)) {\n                final String filePath = FileUtils.getPath(mContext, file);\n                if (filePath != null) {\n                    LruCache<String, BitmapCacheInfo> memoryCache = bitmapCache.getMemoryCache();\n                    BitmapCacheInfo bitmapCacheInfo = memoryCache.get(filePath);\n                    if (bitmapCacheInfo == null) {\n                        ImageBitmapLoader loader = new ImageBitmapLoader(mContext, memoryCache,\n                                MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT,\n                                new BitmapLoader.SetViewCallback() {\n                                    @Override\n                                    public void loadView(BitmapCacheInfo cacheInfo) {\n                                        imageView.setImageBitmap(cacheInfo.getBitmap());\n                                        imageView.setLayoutParams(mImageParams);\n                                    }\n                                });\n                        loader.execute(filePath);\n                    } else {\n                        Bitmap imageBitmap = bitmapCacheInfo.getBitmap();\n                        imageView.setImageBitmap(imageBitmap);\n                        imageView.setLayoutParams(mImageParams);\n                    }\n                    imageView.setOnClickListener(new View.OnClickListener() {\n\n                        @Override\n                        public void onClick(View v) {\n                            Utils.showPicture(mActivity, file);\n                            markFileTransferAsRead(id, readStatus);\n                        }\n                    });\n                }\n            } else if (Utils.isAudioType(mimeType)) {\n                imageView.setImageResource(R.drawable.headphone);\n                imageView.setOnClickListener(new View.OnClickListener() {\n\n                    @Override\n                    public void onClick(View v) {\n                        Utils.playAudio(mActivity, file);\n                        markFileTransferAsRead(id, readStatus);\n                    }\n                });\n            }\n            holder.getProgressText().setText(\n                    sb.append(\" (\").append(FileUtils.humanReadableByteCount(filesize, true))\n                            .append(\")\").toString());\n        }\n        holder.getStatusText().setText(getRcsFileTransferStatus(cursor, holder));\n    }\n\n    private void markFileTransferAsRead(String ftId, RcsService.ReadStatus readStatus) {\n        try {\n            if (RcsService.ReadStatus.UNREAD == readStatus) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Mark file transfer \" + ftId + \" as read\");\n                }\n                mFileTransferService.markFileTransferAsRead(ftId);\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Cannot mark message as read: service not available\");\n            }\n        } catch (RcsGenericException | RcsPersistentStorageException e) {\n            Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    private RcsChatInViewHolder bindRcsChatView(View view, Cursor cursor) {\n        RcsChatInViewHolder holder = (RcsChatInViewHolder) view.getTag();\n        holder.getTimestampText().setText(\n                DateUtils.getRelativeTimeSpanString(cursor.getLong(holder.getColumnTimestampIdx()),\n                        System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                        DateUtils.FORMAT_ABBREV_RELATIVE));\n        String mimeType = cursor.getString(holder.getColumnMimetypeIdx());\n        TextView contentText = holder.getContentText();\n        String data = cursor.getString(holder.getColumnContentIdx());\n        if (MimeType.TEXT_MESSAGE.equals(mimeType)) {\n            contentText.setText(formatMessageWithSmiley(data));\n        } else {\n            contentText.setText(formatGeolocation(mContext, new Geoloc(data)));\n        }\n        holder.getStatusText().setText(getRcsChatStatus(cursor, holder));\n        return holder;\n    }\n\n    private void bindRcsChatOutView(View view, Cursor cursor) {\n        RcsChatOutViewHolder holder = (RcsChatOutViewHolder) bindRcsChatView(view, cursor);\n        boolean undeliveredExpiration = cursor.getInt(holder.getColumnExpiredDeliveryIdx()) == 1;\n        holder.getStatusText().setCompoundDrawablesWithIntrinsicBounds(\n                undeliveredExpiration ? R.drawable.chat_view_undelivered : 0, 0, 0, 0);\n    }\n\n    private void bindRcsChatInView(View view, Cursor cursor) {\n        RcsChatInViewHolder holder = bindRcsChatView(view, cursor);\n        // Only mark message as read when actually displayed on screen\n        markChatMessageAsRead(cursor, holder);\n    }\n\n    private void markChatMessageAsRead(Cursor cursor, RcsChatInViewHolder holder) {\n        try {\n            RcsService.ReadStatus readStatus = RcsService.ReadStatus.valueOf(cursor.getInt(holder\n                    .getColumnReadStatusIdx()));\n            if (RcsService.ReadStatus.UNREAD == readStatus) {\n                String msgId = cursor.getString(holder.getColumnIdIdx());\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Mark message \" + msgId + \" as read\");\n                }\n                mChatService.markMessageAsRead(msgId);\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Cannot mark message as read: service not available\");\n            }\n        } catch (RcsGenericException | RcsPersistentStorageException e) {\n            Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    private String getRcsFileTransferStatus(Cursor cursor, RcsFileTransferInViewHolder holder) {\n        FileTransfer.State state = FileTransfer.State.valueOf((int) cursor.getLong(holder\n                .getColumnStatusIdx()));\n        StringBuilder status = new StringBuilder(RiApplication.sFileTransferStates[state.toInt()]);\n        ReasonCode reason = ReasonCode\n                .valueOf((int) cursor.getLong(holder.getColumnReasonCodeIdx()));\n        if (ReasonCode.UNSPECIFIED != reason) {\n            status.append(\" / \");\n            status.append(RiApplication.sFileTransferReasonCodes[reason.toInt()]);\n        }\n        return status.toString();\n    }\n\n    private String getRcsChatStatus(Cursor cursor, RcsChatInViewHolder holder) {\n        ChatLog.Message.Content.Status state = ChatLog.Message.Content.Status.valueOf((int) cursor\n                .getLong(holder.getColumnStatusIdx()));\n        StringBuilder status = new StringBuilder(RiApplication.sMessagesStatuses[state.toInt()]);\n        Content.ReasonCode reason = Content.ReasonCode.valueOf((int) cursor.getLong(holder\n                .getColumnReasonCodeIdx()));\n        if (Content.ReasonCode.UNSPECIFIED != reason) {\n            status.append(\" / \");\n            status.append(RiApplication.sMessageReasonCodes[reason.toInt()]);\n        }\n        return status.toString();\n    }\n\n    /**\n     * Format geolocation\n     *\n     * @param context context\n     * @param geoloc The geolocation\n     * @return a formatted text\n     */\n    public static String formatGeolocation(Context context, Geoloc geoloc) {\n        StringBuilder result = new StringBuilder(context.getString(R.string.label_geolocation_msg))\n                .append(\"\\n\");\n        String label = geoloc.getLabel();\n        if (label != null) {\n            result.append(context.getString(R.string.label_location)).append(\" \").append(label)\n                    .append(\"\\n\");\n        }\n        return result.append(context.getString(R.string.label_latitude)).append(\" \")\n                .append(geoloc.getLatitude()).append(\"\\n\")\n                .append(context.getString(R.string.label_longitude)).append(\" \")\n                .append(geoloc.getLongitude()).append(\"\\n\")\n                .append(context.getString(R.string.label_accuracy)).append(\" \")\n                .append(geoloc.getAccuracy()).toString();\n    }\n\n    private CharSequence formatMessageWithSmiley(String txt) {\n        SpannableStringBuilder buf = new SpannableStringBuilder();\n        if (!TextUtils.isEmpty(txt)) {\n            SmileyParser smileyParser = new SmileyParser(txt, mSmileyResources);\n            smileyParser.parse();\n            buf.append(smileyParser.getSpannableString(mContext));\n        }\n        return buf;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/TalkListArrayAdapter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.text.format.DateUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport java.util.List;\n\n/**\n * Conversation cursor adapter\n */\npublic class TalkListArrayAdapter extends ArrayAdapter<TalkListArrayItem> {\n\n    private final RcsContactUtil mRcsContactUtil;\n    private final LayoutInflater mInflater;\n    private final Context mCtx;\n\n    private static final int VIEW_TYPE_1TO1_CHAT = 0;\n    private static final int VIEW_TYPE_GROUP_CHAT = 1;\n\n    public TalkListArrayAdapter(Context context, List<TalkListArrayItem> messageLogs) {\n        super(context, R.layout.chat_list, messageLogs);\n        mCtx = context;\n        mRcsContactUtil = RcsContactUtil.getInstance(context);\n        mInflater = ((Activity) context).getLayoutInflater();\n    }\n\n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        if (convertView == null) {\n            int viewType = getItemViewType(position);\n            if (VIEW_TYPE_1TO1_CHAT == viewType) {\n                convertView = mInflater.inflate(R.layout.talk_log_one_to_one_item, parent, false);\n                convertView.setTag(new TalkListArrayItem.ViewHolderOneToOne(convertView));\n            } else {\n                convertView = mInflater.inflate(R.layout.talk_log_group_item, parent, false);\n                convertView.setTag(new TalkListArrayItem.ViewHolderGroup(convertView));\n            }\n        }\n        bindView(convertView, position);\n        return convertView;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        TalkListArrayItem item = getItem(position);\n        return item.isGroupChat() ? VIEW_TYPE_GROUP_CHAT : VIEW_TYPE_1TO1_CHAT;\n    }\n\n    @Override\n    public int getViewTypeCount() {\n        return 2;\n    }\n\n    public void bindView(View view, int position) {\n        TalkListArrayItem item = getItem(position);\n        int viewType = getItemViewType(position);\n        TalkListArrayItem.ViewHolder holder = (TalkListArrayItem.ViewHolder) view.getTag();\n        setTimestamp(holder, item.getTimestamp());\n        String content = item.getContent();\n        if (ChatLog.Message.MimeType.GEOLOC_MESSAGE.equals(item.getMimeType())) {\n            content = TalkCursorAdapter.formatGeolocation(mCtx, new Geoloc(item.getContent()));\n        }\n        setContent(holder, content);\n        setStatus(holder, item.getUnreadCount());\n        switch (viewType) {\n            case VIEW_TYPE_1TO1_CHAT:\n                bindViewOneToOneTalk(item, (TalkListArrayItem.ViewHolderOneToOne) holder);\n                break;\n\n            case VIEW_TYPE_GROUP_CHAT:\n                bindViewGroupChat(item, (TalkListArrayItem.ViewHolderGroup) holder);\n                break;\n\n            default:\n                throw new IllegalArgumentException(\"Invalid view type: '\" + viewType + \"'!\");\n        }\n    }\n\n    private void bindViewGroupChat(TalkListArrayItem item, TalkListArrayItem.ViewHolderGroup holder) {\n        holder.getSubjectText().setText(item.getSubject());\n    }\n\n    private void bindViewOneToOneTalk(TalkListArrayItem item,\n            TalkListArrayItem.ViewHolderOneToOne holder) {\n        ImageView avatar = holder.getAvatarImage();\n        ContactId contact = item.getContact();\n        Bitmap photo = mRcsContactUtil.getPhotoFromContactId(contact);\n        if (photo != null) {\n            avatar.setImageBitmap(photo);\n        } else {\n            avatar.setImageResource(R.drawable.person);\n        }\n        setContact(holder, item.getContact());\n    }\n\n    private void setContent(TalkListArrayItem.ViewHolder holder, String content) {\n        holder.getContentText().setText(content != null ? content : \"\");\n    }\n\n    private void setTimestamp(TalkListArrayItem.ViewHolder holder, long timestamp) {\n        /* Set the date/time field by mixing relative and absolute times */\n        holder.getTimestampText().setText(\n                DateUtils.getRelativeTimeSpanString(timestamp, System.currentTimeMillis(),\n                        DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE));\n    }\n\n    private void setStatus(TalkListArrayItem.ViewHolder holder, int unReads) {\n        TextView statusText = holder.getStatusText();\n        if (unReads == 0) {\n            statusText.setVisibility(View.INVISIBLE);\n        } else {\n            statusText.setVisibility(View.VISIBLE);\n            String countUnReads = Integer.valueOf(unReads).toString();\n            if (unReads <= 9) {\n                countUnReads = \" \".concat(countUnReads);\n            }\n            statusText.setText(countUnReads);\n        }\n    }\n\n    private void setContact(TalkListArrayItem.ViewHolderOneToOne holder, ContactId contact) {\n        String displayName = mRcsContactUtil.getDisplayName(contact);\n        holder.getContactText().setText(displayName);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/adapter/TalkListArrayItem.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.adapter;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\n/**\n * Created by yplo6403 on 12/01/2016.\n */\npublic class TalkListArrayItem implements Comparable<TalkListArrayItem> {\n\n    private final long mTimestamp;\n    private final RcsService.Direction mDirection;\n    private String mSubject;\n    private final String mChatId;\n    private final ContactId mContact;\n    private String mContent;\n    private final String mMimeType;\n    private int mUnreadCount;\n\n    /**\n     * Constructor for XMS and RCS chat information\n     *\n     * @param chatId the chat ID\n     * @param contact the contact ID\n     * @param timestamp the timestamp\n     * @param direction the direction\n     * @param content the content\n     * @param mimeType the mime type\n     * @param unreadCount the read status\n     */\n    public TalkListArrayItem(String chatId, ContactId contact, long timestamp,\n            RcsService.Direction direction, String content, String mimeType, int unreadCount) {\n        mChatId = chatId;\n        mContact = contact;\n        mTimestamp = timestamp;\n        mDirection = direction;\n        mContent = content;\n        mMimeType = mimeType;\n        mUnreadCount = unreadCount;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public RcsService.Direction getDirection() {\n        return mDirection;\n    }\n\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    public void setContent(String content) {\n        mContent = content;\n    }\n\n    public String getContent() {\n        return mContent;\n    }\n\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    public String getChatId() {\n        return mChatId;\n    }\n\n    public String getSubject() {\n        return mSubject;\n    }\n\n    public void setSubject(String subject) {\n        mSubject = subject;\n    }\n\n    @Override\n    public int compareTo(TalkListArrayItem another) {\n        if (another == null) {\n            throw new NullPointerException(\"Cannot compare to null\");\n        }\n        return Long.valueOf(another.getTimestamp()).compareTo(mTimestamp);\n    }\n\n    public int getUnreadCount() {\n        return mUnreadCount;\n    }\n\n    public void incrementUnreadCount() {\n        mUnreadCount++;\n    }\n\n    public boolean isGroupChat() {\n        return mContact == null || !mChatId.equals(mContact.toString());\n    }\n\n    static public class ViewHolder {\n\n        private final TextView mStatusText;\n        private final TextView mTimestampText;\n        private final TextView mContentText;\n        private final ImageView mAvatarImage;\n\n        ViewHolder(View view) {\n            mAvatarImage = (ImageView) view.findViewById(R.id.avatar);\n            mStatusText = (TextView) view.findViewById(R.id.status_text);\n            mTimestampText = (TextView) view.findViewById(R.id.timestamp_text);\n            mContentText = (TextView) view.findViewById(R.id.content_text);\n        }\n\n        public TextView getStatusText() {\n            return mStatusText;\n        }\n\n        public TextView getTimestampText() {\n            return mTimestampText;\n        }\n\n        public TextView getContentText() {\n            return mContentText;\n        }\n\n        public ImageView getAvatarImage() {\n            return mAvatarImage;\n        }\n\n    }\n\n    static public class ViewHolderOneToOne extends ViewHolder {\n\n        private final TextView mContactText;\n\n        public ViewHolderOneToOne(View view) {\n            super(view);\n            mContactText = (TextView) view.findViewById(R.id.contact_text);\n        }\n\n        public TextView getContactText() {\n            return mContactText;\n        }\n    }\n\n    static public class ViewHolderGroup extends ViewHolder {\n\n        private final TextView mSubjectText;\n\n        public ViewHolderGroup(View view) {\n            super(view);\n            mSubjectText = (TextView) view.findViewById(R.id.subject_text);\n        }\n\n        public TextView getSubjectText() {\n            return mSubjectText;\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/ChatCursorObserver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport android.database.ContentObserver;\nimport android.database.Cursor;\nimport android.os.Handler;\nimport android.support.v4.content.Loader;\n\n/**\n * A content observer which holds the cursor loader in order to notify change on it.\n * \n * @author yplo6403\n */\npublic class ChatCursorObserver extends ContentObserver {\n\n    final private Loader<Cursor> mLoader;\n\n    public ChatCursorObserver(Handler handler, Loader<Cursor> loader) {\n        super(handler);\n        mLoader = loader;\n    }\n\n    public Loader<Cursor> getLoader() {\n        return mLoader;\n    }\n\n    @Override\n    public boolean deliverSelfNotifications() {\n        return true;\n    }\n\n    @Override\n    public void onChange(boolean selfChange) {\n        if (null != mLoader) {\n            mLoader.onContentChanged();\n        }\n        super.onChange(selfChange);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/ChatMessageDAO.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatLog.Message;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\n\n/**\n * CHAT Message Data Object\n * \n * @author YPLO6403\n */\npublic class ChatMessageDAO {\n\n    private final String mMsgId;\n    private final ContactId mContact;\n    private final String mChatId;\n    private final Message.Content.Status mStatus;\n    private final Message.GroupChatEvent.Status mChatEvent;\n    private final Message.Content.ReasonCode mReasonCode;\n    private final ReadStatus mReadStatus;\n    private final Direction mDirection;\n    private final String mMimeType;\n    private final String mContent;\n    private final long mTimestamp;\n    private final long mTimestampSent;\n    private final long mTimestampDelivered;\n    private final long mTimestampDisplayed;\n    private static ContentResolver sContentResolver;\n    private final boolean mExpiredDelivery;\n\n    public Message.Content.Status getStatus() {\n        return mStatus;\n    }\n\n    public Message.GroupChatEvent.Status getChatEvent() {\n        return mChatEvent;\n    }\n\n    public ReadStatus getReadStatus() {\n        return mReadStatus;\n    }\n\n    public long getTimestampSent() {\n        return mTimestampSent;\n    }\n\n    public long getTimestampDelivered() {\n        return mTimestampDelivered;\n    }\n\n    public long getTimestampDisplayed() {\n        return mTimestampDisplayed;\n    }\n\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    public String getChatId() {\n        return mChatId;\n    }\n\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public String getContent() {\n        return mContent;\n    }\n\n    public Message.Content.ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    public boolean isExpiredDelivery() {\n        return mExpiredDelivery;\n    }\n\n    @Override\n    public String toString() {\n        return \"ChatMessageDAO [msgId=\" + mMsgId + \", contact=\" + mContact + \", chatId=\" + mChatId\n                + \", direction=\" + mDirection + \", mimeType=\" + mMimeType + \", body='\" + mContent\n                + \"']\";\n    }\n\n    private ChatMessageDAO(String msgId, ContactId contact, String chatId, Status status,\n            GroupChatEvent.Status chatEvent, ReasonCode reasonCode, ReadStatus readStatus,\n            Direction direction, String mimeType, String content, long timestamp,\n            long timestampSent, long timestampDelivered, long timestampDisplayed,\n            boolean expiredDelivery) {\n        mMsgId = msgId;\n        mContact = contact;\n        mChatId = chatId;\n        mStatus = status;\n        mChatEvent = chatEvent;\n        mReasonCode = reasonCode;\n        mReadStatus = readStatus;\n        mDirection = direction;\n        mMimeType = mimeType;\n        mContent = content;\n        mTimestamp = timestamp;\n        mTimestampSent = timestampSent;\n        mTimestampDelivered = timestampDelivered;\n        mTimestampDisplayed = timestampDisplayed;\n        mExpiredDelivery = expiredDelivery;\n    }\n\n    /**\n     * Gets instance of chat message from RCS provider\n     * \n     * @param ctx the context\n     * @param msgId the message ID\n     * @return instance or null if entry not found\n     */\n    public static ChatMessageDAO getChatMessageDAO(Context ctx, String msgId) {\n        if (sContentResolver == null) {\n            sContentResolver = ctx.getContentResolver();\n        }\n        Cursor cursor = null;\n        try {\n            cursor = sContentResolver.query(\n                    Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, msgId), null, null, null,\n                    null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query chat message ID=\" + msgId);\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(ChatLog.Message.CHAT_ID));\n            String contact = cursor\n                    .getString(cursor.getColumnIndexOrThrow(ChatLog.Message.CONTACT));\n            ContactId contactId = null;\n            if (contact != null) {\n                contactId = ContactUtil.formatContact(contact);\n            }\n\n            String mimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.MIME_TYPE));\n            String content = null;\n            int status = cursor.getInt(cursor.getColumnIndexOrThrow(ChatLog.Message.STATUS));\n            GroupChatEvent.Status chatEvent = null;\n            ReasonCode reasonCode = null;\n            Message.Content.Status contentStatus;\n            if (Message.MimeType.GROUPCHAT_EVENT.equals(mimeType)) {\n                chatEvent = GroupChatEvent.Status.valueOf(status);\n                contentStatus = null;\n            } else {\n                content = cursor.getString(cursor.getColumnIndexOrThrow(ChatLog.Message.CONTENT));\n                contentStatus = Message.Content.Status.valueOf(status);\n                reasonCode = Message.Content.ReasonCode.valueOf(cursor.getInt(cursor\n                        .getColumnIndexOrThrow(ChatLog.Message.REASON_CODE)));\n            }\n            ReadStatus readStatus = ReadStatus.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.READ_STATUS)));\n            Direction dir = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.DIRECTION)));\n            long timestamp = cursor\n                    .getLong(cursor.getColumnIndexOrThrow(ChatLog.Message.TIMESTAMP));\n            long timestampSent = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.TIMESTAMP_SENT));\n            long timestampDelivered = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.TIMESTAMP_DELIVERED));\n            long timestampDisplayed = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.TIMESTAMP_DISPLAYED));\n            boolean expiredDelivery = cursor.getInt(cursor\n                    .getColumnIndexOrThrow(Message.EXPIRED_DELIVERY)) == 1;\n            return new ChatMessageDAO(msgId, contactId, chatId, contentStatus, chatEvent,\n                    reasonCode, readStatus, dir, mimeType, content, timestamp, timestampSent,\n                    timestampDelivered, timestampDisplayed, expiredDelivery);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/ChatMessageLogView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * A class to view the persisted information for chat message<br>\n * Created by Philippe LEMORDANT.\n */\npublic class ChatMessageLogView extends RcsActivity {\n    private static final String EXTRA_MESSAGE_ID = \"id\";\n    private String mMessageId;\n    private TextView mTxtViewChatId;\n    private TextView mTxtViewContact;\n    private TextView mTxtViewContent;\n    private TextView mTxtViewDate;\n    private TextView mTxtViewDir;\n    private TextView mTxtViewMime;\n    private TextView mTxtViewReason;\n    private TextView mTxtViewState;\n    private TextView mTxtViewDateSent;\n    private TextView mTxtViewDateDelivered;\n    private TextView mTxtViewDateDisplayed;\n    private TextView mTxtViewRead;\n    private TextView mTxtViewExpiredDelivery;\n\n    private static DateFormat sDateFormat;\n    private TextView mTxtViewId;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.chat_message_log_item);\n        mMessageId = getIntent().getStringExtra(EXTRA_MESSAGE_ID);\n        initialize();\n    }\n\n    private void initialize() {\n        mTxtViewId = (TextView) findViewById(R.id.history_log_item_id);\n        mTxtViewChatId = (TextView) findViewById(R.id.history_log_item_chat_id);\n        mTxtViewContact = (TextView) findViewById(R.id.history_log_item_contact);\n        mTxtViewState = (TextView) findViewById(R.id.history_log_item_state);\n        mTxtViewReason = (TextView) findViewById(R.id.history_log_item_reason);\n        mTxtViewDir = (TextView) findViewById(R.id.history_log_item_direction);\n        mTxtViewDate = (TextView) findViewById(R.id.history_log_item_date);\n        mTxtViewMime = (TextView) findViewById(R.id.history_log_item_mime);\n        mTxtViewContent = (TextView) findViewById(R.id.history_log_item_content);\n        mTxtViewDateSent = (TextView) findViewById(R.id.history_log_item_date_sent);\n        mTxtViewDateDelivered = (TextView) findViewById(R.id.history_log_item_date_delivered);\n        mTxtViewDateDisplayed = (TextView) findViewById(R.id.history_log_item_date_displayed);\n        mTxtViewRead = (TextView) findViewById(R.id.history_log_item_read_status);\n        mTxtViewExpiredDelivery = (TextView) findViewById(R.id.history_log_item_expired_delivery);\n    }\n\n    private String getDateFromDb(long timestamp) {\n        if (0 == timestamp) {\n            return \"\";\n        }\n        if (sDateFormat == null) {\n            sDateFormat = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\", Locale.getDefault());\n        }\n        return sDateFormat.format(new Date(timestamp));\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        ChatMessageDAO dao = ChatMessageDAO.getChatMessageDAO(this, mMessageId);\n        if (dao == null) {\n            showMessageThenExit(R.string.error_item_not_found);\n            return;\n        }\n        mTxtViewId.setText(mMessageId);\n        mTxtViewChatId.setText(dao.getChatId());\n        ContactId contact = dao.getContact();\n        if (contact != null) {\n            mTxtViewContact.setText(contact.toString());\n        } else {\n            mTxtViewContact.setText(\"\");\n        }\n        String mime = dao.getMimeType();\n        if (ChatLog.Message.MimeType.GROUPCHAT_EVENT.equals(mime)) {\n            mTxtViewState.setText(RiApplication.sGroupChatEvents[dao.getChatEvent().toInt()]);\n            mTxtViewContent.setText(\"\");\n            mTxtViewReason.setText(\"\");\n        } else {\n            mTxtViewState.setText(RiApplication.sMessagesStatuses[dao.getStatus().toInt()]);\n            mTxtViewReason.setText(RiApplication.sMessageReasonCodes[dao.getReasonCode().toInt()]);\n            mTxtViewContent.setText(dao.getContent());\n        }\n        mTxtViewDir.setText(RiApplication.getDirection(dao.getDirection()));\n        mTxtViewDate.setText(getDateFromDb(dao.getTimestamp()));\n        mTxtViewDateSent.setText(getDateFromDb(dao.getTimestampSent()));\n        mTxtViewDateDelivered.setText(getDateFromDb(dao.getTimestampDelivered()));\n        mTxtViewDateDisplayed.setText(getDateFromDb(dao.getTimestampDisplayed()));\n        mTxtViewRead.setText(dao.getReadStatus().toString());\n        mTxtViewExpiredDelivery.setText(Boolean.toString(dao.isExpiredDelivery()));\n        mTxtViewMime.setText(mime);\n    }\n\n    /**\n     * Start activity to view details of chat message record\n     *\n     * @param context the context\n     * @param messageId the message ID\n     */\n    public static void startActivity(Context context, String messageId) {\n        Intent intent = new Intent(context, ChatMessageLogView.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(EXTRA_MESSAGE_ID, messageId);\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/ChatPendingIntentManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.rcs.ri.RI;\nimport com.gsma.rcs.ri.utils.Utils;\n\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.LruCache;\n\n/**\n * There should only have 1 pending intent for a given chat conversation.<br>\n * If the conversation is already on the foreground, the pending intent is useless and the activity\n * is (re)started.\n * \n * @author Philippe LEMORDANT\n */\npublic class ChatPendingIntentManager {\n\n    private static volatile ChatPendingIntentManager sChatPendingIntentManager;\n\n    private final IForegroundInfo mForegroundInfo;\n\n    private static final int MAX_CHAT_HAVING_PENDING_MESSAGE = 10;\n\n    /*\n     * A cache of notification ID associated with each chat conversation having pending message. The\n     * key is the chat ID and the value is the notification ID.\n     */\n    private final LruCache<String, Integer> mPendingNotificationIdCache;\n\n    private final NotificationManager mNotifManager;\n\n    private final Context mCtx;\n\n    public interface IForegroundInfo {\n        boolean isConversationOnForeground(String chatId);\n    }\n\n    private ChatPendingIntentManager(Context ctx, IForegroundInfo foregroundInfo) {\n        mCtx = ctx;\n        mForegroundInfo = foregroundInfo;\n        mNotifManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);\n        mPendingNotificationIdCache = new LruCache<String, Integer>(MAX_CHAT_HAVING_PENDING_MESSAGE) {\n\n            @Override\n            protected void entryRemoved(boolean evicted, String key, Integer oldValue,\n                    Integer newValue) {\n                super.entryRemoved(evicted, key, oldValue, newValue);\n                if (evicted) {\n                    mNotifManager.cancel(oldValue);\n                }\n            }\n        };\n    }\n\n    /**\n     * Try to continue chat conversation\n     * \n     * @param continueChat the intent to continue the chat conversation\n     * @param chatId the chat ID\n     * @return the unique ID to be used to create the pending intent if chat conversation is not on\n     *         foreground or null if continuing the conversation succeeded\n     */\n    public Integer tryContinueChatConversation(Intent continueChat, String chatId) {\n        if (mForegroundInfo.isConversationOnForeground(chatId)) {\n            /*\n             * Do not display notification if activity is on foreground for this chatId\n             */\n            Integer pendingIntentId = mPendingNotificationIdCache.get(chatId);\n            if (pendingIntentId != null) {\n                mPendingNotificationIdCache.remove(chatId);\n                mNotifManager.cancel(pendingIntentId);\n            }\n            /* This will trigger onNewIntent for the target activity */\n            mCtx.startActivity(continueChat);\n            return null;\n        }\n        Integer uniquePendingIntentId = mPendingNotificationIdCache.get(chatId);\n        if (uniquePendingIntentId == null) {\n            /*\n             * If the PendingIntent has the same operation, action, data, categories, components,\n             * and flags it will be replaced. Invitation should be notified individually so we use a\n             * random generator to provide a unique request code and reuse it for the notification.\n             */\n            uniquePendingIntentId = Utils.getUniqueIdForPendingIntent();\n            mPendingNotificationIdCache.put(chatId, uniquePendingIntentId);\n        }\n        return uniquePendingIntentId;\n    }\n\n    public void postNotification(Integer id, Notification notification) {\n        mNotifManager.notify(id, notification);\n    }\n\n    public void clearNotification(String chatId) {\n        Integer pendingIntentId = mPendingNotificationIdCache.get(chatId);\n        if (pendingIntentId != null) {\n            mPendingNotificationIdCache.remove(chatId);\n            mNotifManager.cancel(pendingIntentId);\n        }\n    }\n\n    /**\n     * Gets Chat pending intent manager\n     * \n     * @param ctx the context\n     * @return the instance\n     */\n    public static ChatPendingIntentManager getChatPendingIntentManager(Context ctx) {\n        /* \"Double-Checked Locking\" idiom for singleton creation */\n        if (sChatPendingIntentManager != null) {\n            return sChatPendingIntentManager;\n        }\n        synchronized (ChatPendingIntentManager.class) {\n            if (sChatPendingIntentManager == null) {\n                sChatPendingIntentManager = new ChatPendingIntentManager(\n                        ctx.getApplicationContext(),\n                        new ChatPendingIntentManager.IForegroundInfo() {\n\n                            @Override\n                            public boolean isConversationOnForeground(String chatId) {\n                                return RI.sChatIdOnForeground != null\n                                        && chatId.equals(RI.sChatIdOnForeground);\n                            }\n                        });\n            }\n            return sChatPendingIntentManager;\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/ChatServiceConfigActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.chat.ChatServiceConfiguration;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.CheckBox;\nimport android.widget.TextView;\n\nimport java.util.Locale;\n\n/**\n * Display/update the chat service configuration\n * \n * @author Philippe LEMORDANT\n */\npublic class ChatServiceConfigActivity extends RcsActivity {\n\n    private ChatServiceConfiguration mConfig;\n\n    private CheckBox mRespondToDisplayReports;\n\n    private static final String LOGTAG = LogUtils.getTag(ChatServiceConfigActivity.class\n            .getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.chat_service_config);\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.CHAT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        try {\n            mConfig = getChatApi().getConfiguration();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CHAT);\n        mRespondToDisplayReports = (CheckBox) findViewById(R.id.RespondToDisplayReports);\n        mRespondToDisplayReports.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Boolean enable = mRespondToDisplayReports.isChecked();\n                try {\n                    mConfig.setRespondToDisplayReports(enable);\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"onClick RespondToDisplayReports \".concat(enable.toString()));\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n\n            }\n\n        });\n\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        try {\n            displayChatServiceConfig();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void displayChatServiceConfig() throws RcsServiceException {\n        Locale local = Locale.getDefault();\n        CheckBox checkBox = (CheckBox) findViewById(R.id.WarnSF);\n        checkBox.setChecked(mConfig.isChatWarnSF());\n\n        TextView textView = (TextView) findViewById(R.id.IsComposingTimeout);\n        textView.setText(String.format(local, \"%d\", mConfig.getIsComposingTimeout()));\n\n        textView = (TextView) findViewById(R.id.MinGroupChatParticipants);\n        textView.setText(String.format(local, \"%d\", mConfig.getGroupChatMinParticipants()));\n\n        textView = (TextView) findViewById(R.id.MaxGroupChatParticipants);\n        textView.setText(String.format(local, \"%d\", mConfig.getGroupChatMaxParticipants()));\n\n        textView = (TextView) findViewById(R.id.MaxMsgLengthGroupChat);\n        textView.setText(String.format(local, \"%d\", mConfig.getGroupChatMessageMaxLength()));\n\n        textView = (TextView) findViewById(R.id.GroupChatSubjectMaxLength);\n        textView.setText(String.format(local, \"%d\", mConfig.getGroupChatSubjectMaxLength()));\n\n        textView = (TextView) findViewById(R.id.MaxMsgLengthOneToOneChat);\n        textView.setText(String.format(local, \"%d\", mConfig.getOneToOneChatMessageMaxLength()));\n\n        checkBox = (CheckBox) findViewById(R.id.SmsFallback);\n        checkBox.setChecked(mConfig.isSmsFallback());\n\n        mRespondToDisplayReports.setChecked(mConfig.isRespondToDisplayReportsEnabled());\n\n        textView = (TextView) findViewById(R.id.MaxGeolocLabelLength);\n        textView.setText(String.format(local, \"%d\", mConfig.getGeolocLabelMaxLength()));\n\n        textView = (TextView) findViewById(R.id.GeolocExpireTime);\n        textView.setText(String.format(local, \"%d\", mConfig.getGeolocExpirationTime()));\n\n        checkBox = (CheckBox) findViewById(R.id.GroupChatSupported);\n        checkBox.setChecked(mConfig.isGroupChatSupported());\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/ISendFile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\n\nimport android.net.Uri;\n\n/**\n * @author Philippe LEMORDANT\n */\npublic interface ISendFile {\n\n    /**\n     * Initialize\n     */\n    void initialize();\n\n    /**\n     * Transfer file\n     * \n     * @param file Uri of file to transfer\n     * @param disposition the file disposition\n     * @param fileIcon File icon option. If true, the stack tries to attach fileicon.\n     * @return True if file transfer is successful\n     */\n    boolean transferFile(Uri file, FileTransfer.Disposition disposition, boolean fileIcon);\n\n    /**\n     * Add file transfer event listener\n     * \n     * @param fileTransferService the file transfer service\n     */\n    void addFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException;\n\n    /**\n     * Remove file transfer event listener\n     * \n     * @param fileTransferService the file transfer service\n     */\n    void removeFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException;\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/IsComposingManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport android.os.Handler;\nimport android.os.Message;\n\n/**\n * Utility class to handle is_typing timers (see RFC3994)\n */\npublic class IsComposingManager {\n    // Idle time out (in ms)\n    private long idleTimeOut = 0;\n\n    // Active state refresh interval (in ms)\n    private final static int ACTIVE_STATE_REFRESH = 60 * 1000;\n\n    // Clock handler\n    private ClockHandler handler = new ClockHandler();\n\n    // Is composing state\n    private boolean isComposing = false;\n\n    // Event IDs\n    private final static int IS_STARTING_COMPOSING = 1;\n\n    private final static int IS_STILL_COMPOSING = 2;\n\n    private final static int MESSAGE_WAS_SENT = 3;\n\n    private final static int ACTIVE_MESSAGE_NEEDS_REFRESH = 4;\n\n    private final static int IS_IDLE = 5;\n\n    private INotifyComposing mNotifyComposing;\n\n    /**\n     * Constructor\n     * \n     * @param timeout the composing timeout\n     * @param notifyComposing interface to notify isComposing status\n     */\n    public IsComposingManager(long timeout, INotifyComposing notifyComposing) {\n        idleTimeOut = timeout;\n        mNotifyComposing = notifyComposing;\n    }\n\n    /**\n     * Interface to notify isComposing status\n     */\n    public interface INotifyComposing {\n        /**\n         * @param status typing status\n         */\n        void setTypingStatus(boolean status);\n    }\n\n    // Clock handler class\n    private class ClockHandler extends Handler {\n        public void handleMessage(Message msg) {\n            switch (msg.what) {\n                case IS_STARTING_COMPOSING: {\n                    // Send a typing status \"active\"\n                    mNotifyComposing.setTypingStatus(true);\n\n                    // In IDLE_TIME_OUT we will need to send a is-idle status\n                    // message\n                    handler.sendEmptyMessageDelayed(IS_IDLE, idleTimeOut);\n\n                    // In ACTIVE_STATE_REFRESH we will need to send an active\n                    // status message refresh\n                    handler.sendEmptyMessageDelayed(ACTIVE_MESSAGE_NEEDS_REFRESH,\n                            ACTIVE_STATE_REFRESH);\n                    break;\n                }\n                case IS_STILL_COMPOSING: {\n                    // Cancel the IS_IDLE messages in queue, if there was one\n                    handler.removeMessages(IS_IDLE);\n\n                    // In IDLE_TIME_OUT we will need to send a is-idle status\n                    // message\n                    handler.sendEmptyMessageDelayed(IS_IDLE, idleTimeOut);\n                    break;\n                }\n                case MESSAGE_WAS_SENT: {\n                    // We are now going to idle state\n                    hasNoActivity();\n\n                    // Cancel the IS_IDLE messages in queue, if there was one\n                    handler.removeMessages(IS_IDLE);\n\n                    // Cancel the ACTIVE_MESSAGE_NEEDS_REFRESH messages in\n                    // queue, if there was one\n                    handler.removeMessages(ACTIVE_MESSAGE_NEEDS_REFRESH);\n                    break;\n                }\n                case ACTIVE_MESSAGE_NEEDS_REFRESH: {\n                    // We have to refresh the \"active\" state\n                    mNotifyComposing.setTypingStatus(true);\n\n                    // In ACTIVE_STATE_REFRESH we will need to send an active\n                    // status message refresh\n                    handler.sendEmptyMessageDelayed(ACTIVE_MESSAGE_NEEDS_REFRESH,\n                            ACTIVE_STATE_REFRESH);\n                    break;\n                }\n                case IS_IDLE: {\n                    // End of typing\n                    hasNoActivity();\n\n                    // Send a typing status \"idle\"\n                    mNotifyComposing.setTypingStatus(false);\n\n                    // Cancel the ACTIVE_MESSAGE_NEEDS_REFRESH messages in\n                    // queue, if there was one\n                    handler.removeMessages(ACTIVE_MESSAGE_NEEDS_REFRESH);\n                    break;\n                }\n            }\n        }\n    }\n\n    /**\n     * Edit text has activity\n     */\n    public void hasActivity() {\n        // We have activity on the edit text\n        if (!isComposing) {\n            // If we were not already in isComposing state\n            handler.sendEmptyMessage(IS_STARTING_COMPOSING);\n            isComposing = true;\n        } else {\n            // We already were composing\n            handler.sendEmptyMessage(IS_STILL_COMPOSING);\n        }\n    }\n\n    /**\n     * Edit text has no activity anymore\n     */\n    public void hasNoActivity() {\n        isComposing = false;\n    }\n\n    /**\n     * The message was sent\n     */\n    public void messageWasSent() {\n        handler.sendEmptyMessage(MESSAGE_WAS_SENT);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/SendFile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.filetransfer.AudioMessageRecordActivity;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\n/**\n * Send file\n * \n * @author Philippe LEMORDANT\n */\npublic abstract class SendFile extends RcsActivity implements ISendFile {\n\n    private final static int RC_SELECT_IMAGE = 0;\n    private final static int RC_SELECT_AUDIO = 1;\n    private final static int RC_RECORD_AUDIO = 2;\n\n    /**\n     * UI handler\n     */\n    protected final Handler mHandler = new Handler();\n    protected String mTransferId;\n    protected String mFilename;\n    private Uri mFile;\n    protected long mFilesize = -1;\n    protected FileTransfer mFileTransfer;\n    protected Button mResumeBtn;\n    protected Button mPauseBtn;\n    private Button mInviteBtn;\n    private Button mSelectBtn;\n    protected FileTransferService mFileTransferService;\n    private CheckBox mCheckThumNail;\n    private CheckBox mCheckAudio;\n\n    private static final String LOGTAG = LogUtils.getTag(SendFile.class.getSimpleName());\n    protected TextView mStatusView;\n    protected ProgressBar mProgressBar;\n    private TextView mUriEdit;\n    private TextView mSizeEdit;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.chat_send_file);\n\n        initialize();\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CHAT, RcsServiceName.FILE_TRANSFER,\n                RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n\n        } else {\n            startMonitorServices(RcsServiceName.CHAT, RcsServiceName.FILE_TRANSFER,\n                    RcsServiceName.CONTACT);\n            mFileTransferService = getFileTransferApi();\n            try {\n                addFileTransferEventListener(mFileTransferService);\n\n            } catch (RcsServiceException e) {\n                showExceptionThenExit(e);\n            }\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (mFileTransferService != null && isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            try {\n                removeFileTransferEventListener(mFileTransferService);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    private void initiateTransfer() {\n        transferFile(mFile, mCheckAudio.isChecked() ? FileTransfer.Disposition.RENDER\n                : FileTransfer.Disposition.ATTACH, mCheckThumNail.isChecked());\n        /* Hide buttons */\n        mInviteBtn.setVisibility(View.INVISIBLE);\n        mSelectBtn.setVisibility(View.INVISIBLE);\n        /* Disable checkboxes */\n        mCheckThumNail.setEnabled(false);\n        mCheckAudio.setEnabled(false);\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n        switch (requestCode) {\n            case RC_SELECT_IMAGE:\n            case RC_SELECT_AUDIO:\n                if (data != null && data.getData() != null) {\n                    displayFileInfo(data);\n                    boolean imageFile = RC_SELECT_IMAGE == requestCode;\n                    boolean audioFile = !imageFile;\n                    mCheckThumNail.setChecked(imageFile);\n                    mCheckThumNail.setEnabled(imageFile);\n                    mCheckAudio.setEnabled(audioFile);\n                    mCheckAudio.setChecked(audioFile);\n                }\n                break;\n\n            case RC_RECORD_AUDIO:\n                displayFileInfo(data);\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Created audio file:\" + mFile);\n                }\n                mInviteBtn.setEnabled(true);\n                mCheckAudio.setEnabled(true);\n                mCheckThumNail.setEnabled(false);\n                mCheckThumNail.setChecked(false);\n                break;\n        }\n    }\n\n    /**\n     * Display a alert dialog to select the kind of file to transfer\n     */\n    private void selectDocument() {\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.label_select_file);\n        builder.setCancelable(true);\n        builder.setItems(R.array.select_filetotransfer, new DialogInterface.OnClickListener() {\n\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                if (RC_SELECT_IMAGE == which) {\n                    FileUtils.openFile(SendFile.this, \"image/*\", RC_SELECT_IMAGE);\n                    return;\n                }\n                FileUtils.openFile(SendFile.this, \"audio/*\", RC_SELECT_AUDIO);\n            }\n        });\n        registerDialog(builder.show());\n    }\n\n    private void displayFileInfo(Intent data) {\n        mFile = data.getData();\n        /* Display the selected filename attribute */\n        mFilename = FileUtils.getFileName(this, mFile);\n        mFilesize = FileUtils.getFileSize(this, mFile);\n        mSizeEdit.setText(FileUtils.humanReadableByteCount(mFilesize, true));\n        mUriEdit.setText(mFilename);\n        mInviteBtn.setEnabled(true);\n    }\n\n    /**\n     * Show the transfer progress\n     * \n     * @param currentSize Current size transferred\n     * @param totalSize Total size to be transferred\n     */\n    protected void updateProgressBar(long currentSize, long totalSize) {\n        mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n        double position = ((double) currentSize / (double) totalSize) * 100.0;\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mFileTransfer != null\n                    && RcsSessionUtil.isAllowedToAbortFileTransferSession(mFileTransfer)) {\n                mFileTransfer.abortTransfer();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mFileTransfer = null;\n            /* Exit activity */\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        try {\n            if (KeyEvent.KEYCODE_BACK == keyCode) {\n                if (mFileTransfer == null\n                        || !RcsSessionUtil.isAllowedToAbortFileTransferSession(mFileTransfer)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                                /* Exit activity */\n                                finish();\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_initiate_ft, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        MenuItem item = menu.findItem(R.id.menu_record_audio);\n        item.setVisible(mFileTransfer == null);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_record_audio:\n                startActivityForResult(new Intent(this, AudioMessageRecordActivity.class),\n                        RC_RECORD_AUDIO);\n                break;\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    @Override\n    public void initialize() {\n        mUriEdit = (TextView) findViewById(R.id.uri);\n        mUriEdit.setText(\"\");\n        mSizeEdit = (TextView) findViewById(R.id.size);\n        mSizeEdit.setText(\"\");\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mStatusView.setText(\"\");\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n        OnClickListener btnInviteListener = new OnClickListener() {\n            public void onClick(View v) {\n                long warnSize = 0;\n                try {\n                    warnSize = mFileTransferService.getConfiguration().getWarnSize();\n                } catch (RcsServiceException e) {\n                    showException(e);\n                }\n\n                if (warnSize > 0 && mFilesize >= warnSize) {\n                    // Display a warning message\n                    AlertDialog.Builder builder = new AlertDialog.Builder(SendFile.this);\n                    builder.setMessage(getString(R.string.label_sharing_warn_size,\n                            FileUtils.humanReadableByteCount(mFilesize, true)));\n                    builder.setCancelable(false);\n                    builder.setPositiveButton(R.string.label_yes,\n                            new DialogInterface.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int position) {\n                                    initiateTransfer();\n                                }\n                            });\n                    builder.setNegativeButton(R.string.label_no, null);\n                    registerDialog(builder.show());\n\n                } else {\n                    initiateTransfer();\n                }\n            }\n        };\n        mInviteBtn = (Button) findViewById(R.id.invite_btn);\n        mInviteBtn.setOnClickListener(btnInviteListener);\n        mInviteBtn.setEnabled(false);\n\n        OnClickListener btnSelectListener = new OnClickListener() {\n            public void onClick(View v) {\n                /**\n                 * Display a alert dialog to select the kind of file to transfer\n                 */\n\n                selectDocument();\n            }\n        };\n        mSelectBtn = (Button) findViewById(R.id.select_btn);\n        mSelectBtn.setOnClickListener(btnSelectListener);\n\n        OnClickListener btnPauseListener = new OnClickListener() {\n            public void onClick(View v) {\n                try {\n                    if (mFileTransfer.isAllowedToPauseTransfer()) {\n                        mFileTransfer.pauseTransfer();\n                    } else {\n                        mPauseBtn.setEnabled(false);\n                        showMessage(R.string.label_pause_ft_not_allowed);\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        mPauseBtn = (Button) findViewById(R.id.pause_btn);\n        mPauseBtn.setOnClickListener(btnPauseListener);\n        mPauseBtn.setEnabled(false);\n\n        OnClickListener btnResumeListener = new OnClickListener() {\n            public void onClick(View v) {\n                try {\n                    if (mFileTransfer.isAllowedToResumeTransfer()) {\n                        mFileTransfer.resumeTransfer();\n                    } else {\n                        mResumeBtn.setEnabled(false);\n                        showMessage(R.string.label_resume_ft_not_allowed);\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        mResumeBtn = (Button) findViewById(R.id.resume_btn);\n        mResumeBtn.setOnClickListener(btnResumeListener);\n        mResumeBtn.setEnabled(false);\n\n        mCheckThumNail = (CheckBox) findViewById(R.id.ft_thumb);\n        mCheckThumNail.setEnabled(false);\n\n        mCheckAudio = (CheckBox) findViewById(R.id.send_audio_msg);\n        mCheckAudio.setEnabled(false);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/TestChatApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat;\n\nimport com.gsma.rcs.api.connection.utils.RcsListActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.chat.group.InitiateGroupChat;\nimport com.gsma.rcs.ri.messaging.chat.single.InitiateSingleChat;\nimport com.gsma.rcs.ri.messaging.geoloc.DisplayGeoloc;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.database.Cursor;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Chat API\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class TestChatApi extends RcsListActivity {\n\n    private static final String[] PROJECTION = new String[] {\n        CapabilitiesLog.CONTACT\n    };\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        // @formatter:off\n        String[] items = {\n                getString(R.string.menu_initiate_chat), \n                getString(R.string.menu_initiate_group_chat),\n                getString(R.string.menu_chat_service_config),\n                getString(R.string.menu_showus_map),\n        };\n        // @formatter:on\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, InitiateSingleChat.class));\n                break;\n\n            case 1:\n                /* Check if Group chat initialization is allowed */\n                ChatService chatService = getChatApi();\n                try {\n                    if (chatService.isAllowedToInitiateGroupChat()) {\n                        startActivity(new Intent(this, InitiateGroupChat.class));\n                    } else {\n                        showMessage(R.string.label_NotAllowedToInitiateGroupChat);\n                    }\n                } catch (RcsServiceNotAvailableException e) {\n                    showMessage(R.string.label_service_not_available);\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n                break;\n\n            case 2:\n                startActivity(new Intent(this, ChatServiceConfigActivity.class));\n                break;\n\n            case 3:\n                Set<ContactId> contacts = new HashSet<>();\n                Cursor cursor = null;\n                try {\n                    cursor = getContentResolver().query(CapabilitiesLog.CONTENT_URI, PROJECTION,\n                            null, null, null);\n                    if (cursor == null) {\n                        showMessageThenExit(R.string.label_db_failed);\n                        return;\n                    }\n                    if (!cursor.moveToFirst()) {\n                        showMessage(getString(R.string.label_geoloc_not_found));\n                        return;\n                    }\n                    int contactColumIdx = cursor.getColumnIndexOrThrow(CapabilitiesLog.CONTACT);\n                    do {\n                        String contact = cursor.getString(contactColumIdx);\n                        contacts.add(ContactUtil.formatContact(contact));\n                    } while (cursor.moveToNext());\n                    DisplayGeoloc.showContactsOnMap(this, contacts);\n\n                } finally {\n                    if (cursor != null) {\n                        cursor.close();\n                    }\n                }\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/group/GroupChatDAO.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.group;\n\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\n\n/**\n * Group CHAT Data Object\n * \n * @author YPLO6403\n */\npublic class GroupChatDAO {\n\n    private final String mChatId;\n\n    private final Direction mDirection;\n\n    private final ContactId mContact;\n\n    private final String mParticipants;\n\n    private final GroupChat.State mState;\n\n    private final String mSubject;\n\n    private final long mTimestamp;\n\n    private static ContentResolver sContentResolver;\n\n    private final GroupChat.ReasonCode mReasonCode;\n\n    public GroupChat.State getState() {\n        return mState;\n    }\n\n    public String getChatId() {\n        return mChatId;\n    }\n\n    public String getParticipants() {\n        return mParticipants;\n    }\n\n    public String getSubject() {\n        return mSubject;\n    }\n\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public GroupChat.ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    private GroupChatDAO(String chatId, ContactId contact, Direction direction,\n            String participants, State state, String subject, long timestamp, ReasonCode reasonCode) {\n        mChatId = chatId;\n        mContact = contact;\n        mDirection = direction;\n        mParticipants = participants;\n        mState = state;\n        mSubject = subject;\n        mTimestamp = timestamp;\n        mReasonCode = reasonCode;\n    }\n\n    @Override\n    public String toString() {\n        return \"GroupChatDAO [chatId=\" + mChatId + \", direction=\" + mDirection + \", state=\"\n                + mState + \", subject=\" + mSubject + \", participants=\" + mParticipants + \"]\";\n    }\n\n    /**\n     * Gets instance of Group Chat from RCS provider\n     * \n     * @param ctx The context\n     * @param chatId The chat ID\n     * @return instance or null if entry not found\n     */\n    public static GroupChatDAO getGroupChatDao(Context ctx, String chatId) {\n        if (sContentResolver == null) {\n            sContentResolver = ctx.getContentResolver();\n        }\n        Cursor cursor = null;\n        try {\n            cursor = sContentResolver.query(\n                    Uri.withAppendedPath(ChatLog.GroupChat.CONTENT_URI, chatId), null, null, null,\n                    null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query group chat ID\" + chatId);\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            String subject = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.SUBJECT));\n            State state = GroupChat.State.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.STATE)));\n            Direction dir = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.DIRECTION)));\n            long timestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.TIMESTAMP));\n            String participants = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.PARTICIPANTS));\n            ReasonCode reasonCode = GroupChat.ReasonCode.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.REASON_CODE)));\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ChatLog.GroupChat.CONTACT));\n            ContactId contactId = null;\n            if (contact != null) {\n                contactId = ContactUtil.formatContact(contact);\n            }\n            return new GroupChatDAO(chatId, contactId, dir, participants, state, subject,\n                    timestamp, reasonCode);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    /**\n     * Checks if chatId is a group chat Id\n     * \n     * @param chatId the chat ID\n     * @param contact The contact\n     * @return True chatId is a group chat Id\n     */\n    public static boolean isGroupChat(String chatId, ContactId contact) {\n        return (contact == null) || !chatId.equals(contact.toString());\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/group/GroupChatIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.group;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.GroupTalkView;\nimport com.gsma.rcs.ri.messaging.TalkList;\nimport com.gsma.rcs.ri.messaging.chat.ChatMessageDAO;\nimport com.gsma.rcs.ri.messaging.chat.ChatPendingIntentManager;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChatIntent;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.media.RingtoneManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.text.TextUtils;\nimport android.util.Log;\n\n/**\n * File transfer intent service\n * \n * @author Philippe LEMORDANT\n */\npublic class GroupChatIntentService extends IntentService {\n\n    private ChatPendingIntentManager mChatPendingIntentManager;\n\n    private static final String LOGTAG = LogUtils.getTag(GroupChatIntentService.class\n            .getSimpleName());\n\n    /**\n     * Creates an IntentService.\n     */\n    public GroupChatIntentService() {\n        super(\"GroupChatIntentService\");\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mChatPendingIntentManager = ChatPendingIntentManager.getChatPendingIntentManager(this);\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        // We want this service to stop running if forced stop\n        // so return not sticky.\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n        if (GroupChatIntent.ACTION_NEW_GROUP_CHAT_MESSAGE.equals(action)) {\n            // Gets message ID from the incoming Intent\n            String messageId = intent.getStringExtra(GroupChatIntent.EXTRA_MESSAGE_ID);\n            if (messageId == null) {\n                if (LogUtils.isActive) {\n                    Log.e(LOGTAG, \"Cannot read message ID\");\n                }\n                return;\n            }\n            String mimeType = intent.getStringExtra(GroupChatIntent.EXTRA_MIME_TYPE);\n            if (mimeType == null) {\n                if (LogUtils.isActive) {\n                    Log.e(LOGTAG, \"Cannot read message mime-type\");\n                }\n                return;\n            }\n            handleNewGroupChatMessage(intent, messageId);\n\n        } else if (GroupChatIntent.ACTION_NEW_INVITATION.equals(action)) {\n            /* Gets chat ID from the incoming Intent */\n            String chatId = intent.getStringExtra(GroupChatIntent.EXTRA_CHAT_ID);\n            if (chatId != null) {\n                handleNewGroupChatInvitation(intent, chatId);\n            }\n\n        } else {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Unknown action \".concat(action));\n            }\n        }\n    }\n\n    private void handleNewGroupChatInvitation(Intent invitation, String chatId) {\n        /* Get Chat from provider */\n        GroupChatDAO groupChatDAO = GroupChatDAO.getGroupChatDao(this, chatId);\n        if (groupChatDAO == null) {\n            Log.e(LOGTAG, \"Cannot find group chat with ID=\".concat(chatId));\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Group chat invitation =\".concat(groupChatDAO.toString()));\n        }\n        /* Check if it's a spam */\n        if (groupChatDAO.getReasonCode() == GroupChat.ReasonCode.REJECTED_SPAM) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Do nothing on a spam\");\n            }\n            return;\n        }\n        forwardGCInvitation2UI(invitation, chatId, groupChatDAO);\n        TalkList.notifyNewConversationEvent(this, GroupChatIntent.ACTION_NEW_INVITATION);\n    }\n\n    private void handleNewGroupChatMessage(Intent newGroupChatMessage, String messageId) {\n        /* Get ChatMessage from provider */\n        ChatMessageDAO messageDAO = ChatMessageDAO.getChatMessageDAO(this, messageId);\n        if (messageDAO == null) {\n            Log.e(LOGTAG, \"Cannot find group chat message with ID=\".concat(messageId));\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Group chat message =\".concat(messageDAO.toString()));\n        }\n        forwardGCMessage2UI(newGroupChatMessage, messageDAO);\n        TalkList.notifyNewConversationEvent(this, GroupChatIntent.ACTION_NEW_GROUP_CHAT_MESSAGE);\n    }\n\n    private void forwardGCMessage2UI(Intent newGroupChatMessage, ChatMessageDAO message) {\n        String chatId = message.getChatId();\n        Intent intent = GroupTalkView.forgeIntentNewMessage(this, newGroupChatMessage, chatId);\n        String content = message.getContent();\n        Integer uniqueId = mChatPendingIntentManager.tryContinueChatConversation(intent, chatId);\n        if (uniqueId != null) {\n            PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT);\n            /* Create notification */\n            ContactId contact = message.getContact();\n            String mimeType = message.getMimeType();\n            String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n            String title = getString(R.string.title_recv_chat, displayName);\n\n            String msg;\n            if (ChatLog.Message.MimeType.GEOLOC_MESSAGE.equals(mimeType)) {\n                msg = getString(R.string.label_geoloc_msg);\n\n            } else if (ChatLog.Message.MimeType.TEXT_MESSAGE.equals(mimeType)) {\n                msg = content;\n\n            } else {\n                /* If the GC message does not convey user content then discards */\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"Discard message of type '\" + mimeType + \"' for chatId \" + chatId);\n                }\n                return;\n            }\n            Notification notif = buildNotification(contentIntent, title, msg);\n            /* Send notification */\n            mChatPendingIntentManager.postNotification(uniqueId, notif);\n        }\n    }\n\n    private void forwardGCInvitation2UI(Intent invitation, String chatId, GroupChatDAO groupChat) {\n        /* Create pending intent */\n        Intent intent = GroupTalkView.forgeIntentInvitation(this, invitation);\n        /*\n         * If the PendingIntent has the same operation, action, data, categories, components, and\n         * flags it will be replaced. Invitation should be notified individually so we use a random\n         * generator to provide a unique request code and reuse it for the notification.\n         */\n        Integer uniqueId = mChatPendingIntentManager.tryContinueChatConversation(intent, chatId);\n        if (uniqueId != null) {\n            PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT);\n            /* Create notification */\n            String title = getString(R.string.title_group_chat);\n            /* Try to retrieve display name of remote contact */\n            String displayName = RcsContactUtil.getInstance(this).getDisplayName(\n                    groupChat.getContact());\n            if (displayName != null) {\n                title = getString(R.string.title_recv_group_chat, displayName);\n            }\n            String subject = groupChat.getSubject();\n            if (TextUtils.isEmpty(subject)) {\n                subject = \"<\" + getString(R.string.label_no_subject) + \">\";\n            }\n            String msg = getString(R.string.label_subject_notif, subject);\n            Notification notif = buildNotification(contentIntent, title, msg);\n            /* Send notification */\n            mChatPendingIntentManager.postNotification(uniqueId, notif);\n        } else {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"Received invitation for an existing group chat conversation chatId=\"\n                        + chatId + \"!\");\n            }\n        }\n    }\n\n    private Notification buildNotification(PendingIntent invitation, String title, String message) {\n        // Create notification\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(invitation);\n        notif.setSmallIcon(R.drawable.ri_notif_chat_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(title);\n        notif.setContentText(message);\n        return notif.build();\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/group/GroupChatInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.group;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Group chat invitation receiver\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GroupChatInvitationReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, GroupChatIntentService.class);\n        context.startService(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/group/GroupChatMessageReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.group;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Group chat message receiver\n * \n * @author YPLO6403\n */\npublic class GroupChatMessageReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, GroupChatIntentService.class);\n        context.startService(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/group/InitiateGroupChat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.group;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.GroupTalkView;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.util.SparseBooleanArray;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.ListView;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Initiate group chat\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class InitiateGroupChat extends RcsActivity implements OnItemClickListener {\n\n    private ArrayList<String> mParticipants;\n\n    private ListView mContactList;\n\n    private List<ContactId> mAllowedContactIds;\n\n    private Button mInviteBtn;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.chat_initiate_group);\n\n        if (!getChatApi().isServiceConnected()) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        mContactList = (ListView) findViewById(R.id.contacts);\n\n        /* Check if Group chat initialization is allowed */\n        ContactService contactService = getContactApi();\n        ChatService chatService = getChatApi();\n        try {\n            Set<RcsContact> rcsContacts = contactService.getRcsContacts();\n            mAllowedContactIds = new ArrayList<>();\n            List<String> allowedContacts = new ArrayList<>();\n            for (RcsContact rcsContact : rcsContacts) {\n                ContactId contact = rcsContact.getContactId();\n                if (chatService.isAllowedToInitiateGroupChat(contact)) {\n                    mAllowedContactIds.add(contact);\n                    if (rcsContact.getDisplayName() != null) {\n                        allowedContacts.add(rcsContact.getDisplayName() + \" (\"\n                                + rcsContact.getContactId() + \")\");\n                    } else {\n                        allowedContacts.add(contact.toString());\n                    }\n\n                }\n            }\n            if (allowedContacts.size() > 0) {\n                String[] contacts = allowedContacts.toArray(new String[allowedContacts.size()]);\n                ArrayAdapter<String> adapter = new ArrayAdapter<>(this,\n                        android.R.layout.simple_list_item_multiple_choice, contacts);\n                mContactList.setAdapter(adapter);\n                mContactList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);\n                mContactList.setOnItemClickListener(this);\n                for (int i = 0; i < mContactList.getCount(); i++) {\n                    mContactList.setItemChecked(i, false);\n                }\n\n                // Set button callback\n                mInviteBtn = (Button) findViewById(R.id.invite_btn);\n                mInviteBtn.setOnClickListener(btnInviteListener);\n                mInviteBtn.setEnabled(false);\n            } else {\n                showMessage(R.string.label_no_participant_found);\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    /**\n     * Invite button listener\n     */\n    private OnClickListener btnInviteListener = new OnClickListener() {\n        public void onClick(View v) {\n            // Get subject\n            EditText subjectTxt = (EditText) findViewById(R.id.subject);\n            String subject = subjectTxt.getText().toString();\n            GroupTalkView.initiateGroupChat(InitiateGroupChat.this, subject, mParticipants);\n            // Exit activity\n            finish();\n        }\n    };\n\n    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {\n        /* Build list of participant numbers */\n        SparseBooleanArray checkedArray = mContactList.getCheckedItemPositions();\n        mParticipants = new ArrayList<>();\n        for (int i = 0; i < checkedArray.size(); i++) {\n            if (checkedArray.get(i)) {\n                mParticipants.add(mAllowedContactIds.get(i).toString());\n            }\n        }\n        /* Disable the invite button if no contact selected */\n        if (mParticipants.size() == 0) {\n            mInviteBtn.setEnabled(false);\n        } else {\n            mInviteBtn.setEnabled(true);\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/group/SendGroupFile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.group;\n\nimport static com.gsma.rcs.ri.utils.FileUtils.takePersistableContentUriPermission;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.messaging.chat.SendFile;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.GroupFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.util.Log;\n\nimport java.util.Set;\n\n/**\n * Send file to group\n * \n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic class SendGroupFile extends SendFile {\n\n    private final static String EXTRA_CHAT_ID = \"chat_id\";\n\n    private String mChatId;\n\n    private static final String LOGTAG = LogUtils.getTag(SendGroupFile.class.getSimpleName());\n\n    private GroupFileTransferListener mFileTransferListener;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mChatId = getIntent().getStringExtra(EXTRA_CHAT_ID);\n    }\n\n    /**\n     * Start SendGroupFile activity\n     * \n     * @param context The context\n     * @param chatId The chat ID\n     */\n    public static void startActivity(Context context, String chatId) {\n        Intent intent = new Intent(context, SendGroupFile.class);\n        intent.putExtra(EXTRA_CHAT_ID, chatId);\n        context.startActivity(intent);\n    }\n\n    @Override\n    public boolean transferFile(Uri file, FileTransfer.Disposition disposition, boolean fileIcon) {\n        try {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"transferFile filename=\" + mFilename + \" size=\" + mFilesize\n                        + \" chatId=\" + mChatId);\n            }\n            /* Only take persistable permission for content Uris */\n            takePersistableContentUriPermission(this, file);\n            /* Initiate transfer */\n            mFileTransfer = mFileTransferService.transferFileToGroupChat(mChatId, file,\n                    disposition, fileIcon);\n            if (mFileTransfer != null) {\n                mTransferId = mFileTransfer.getTransferId();\n                return true;\n            }\n            Log.e(LOGTAG, \"Cannot transfer file: not found\");\n            return false;\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return false;\n        }\n    }\n\n    @Override\n    public void addFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        fileTransferService.addEventListener(mFileTransferListener);\n    }\n\n    @Override\n    public void removeFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        fileTransferService.removeEventListener(mFileTransferListener);\n    }\n\n    @Override\n    public void initialize() {\n        super.initialize();\n        mFileTransferListener = new GroupFileTransferListener() {\n\n            @Override\n            public void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n                    GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDeliveryInfoChanged chatId=\" + chatId + \" contact=\" + contact\n                            + \" trasnferId=\" + transferId + \" state=\" + status + \" reason=\"\n                            + reasonCode);\n                }\n            }\n\n            @Override\n            public void onProgressUpdate(String chatId, String transferId, final long currentSize,\n                    final long totalSize) {\n                /* Discard event if not for current transferId */\n                if (mTransferId == null || !mTransferId.equals(transferId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(String chatId, String transferId,\n                    final FileTransfer.State state, final FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged chatId=\" + chatId + \" transferId=\" + transferId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current transferId */\n                if (mTransferId == null || !mTransferId.equals(transferId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sFileTransferReasonCodes[reasonCode\n                        .toInt()];\n                final String _state = RiApplication.sFileTransferStates[state.toInt()];\n                mHandler.post(new Runnable() {\n\n                    public void run() {\n                        if (mFileTransfer != null) {\n                            try {\n                                mResumeBtn.setEnabled(mFileTransfer.isAllowedToResumeTransfer());\n\n                            } catch (RcsServiceException e) {\n                                mResumeBtn.setEnabled(false);\n                                showException(e);\n                            }\n                            try {\n                                mPauseBtn.setEnabled(mFileTransfer.isAllowedToPauseTransfer());\n\n                            } catch (RcsServiceException e) {\n                                mPauseBtn.setEnabled(false);\n                                showException(e);\n                            }\n                        }\n                        switch (state) {\n                            case STARTED:\n                                //$FALL-THROUGH$\n                            case TRANSFERRED:\n                                /* Display transfer state started */\n                                mStatusView.setText(_state);\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_transfer_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_transfer_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_transfer_failed,\n                                        _reasonCode));\n                                break;\n\n                            default:\n                                mStatusView.setText(_state);\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(String chatId, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted chatId=\" + chatId + \" transferIds=\" + transferIds);\n                }\n            }\n\n        };\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/single/InitiateSingleChat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.single;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.OneToOneTalkView;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.capability.CapabilitiesListener;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.AdapterView;\nimport android.widget.Button;\nimport android.widget.Spinner;\n\nimport java.util.Collections;\nimport java.util.HashSet;\n\n/**\n * Initiate chat\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class InitiateSingleChat extends RcsActivity {\n\n    private static final String LOGTAG = LogUtils.getTag(InitiateSingleChat.class.getSimpleName());\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n    private ChatService mChatService;\n    private CapabilityService mCapabilityService;\n    private Button mInviteBtn;\n    private CapabilitiesListener mCapabilitiesListener;\n    private Handler mHandler;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.chat_initiate_single);\n        initialize();\n\n        if (!getChatApi().isServiceConnected()) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(ConnectionManager.RcsServiceName.CAPABILITY);\n        try {\n            getCapabilityApi().addCapabilitiesListener(mCapabilitiesListener);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (isServiceConnected(ConnectionManager.RcsServiceName.CAPABILITY)\n                && mCapabilityService != null) {\n            try {\n                mCapabilityService.removeCapabilitiesListener(mCapabilitiesListener);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    private void initialize() {\n        mChatService = getChatApi();\n        mHandler = new Handler();\n        mCapabilityService = getCapabilityApi();\n        mCapabilitiesListener = new CapabilitiesListener() {\n            @Override\n            public void onCapabilitiesReceived(ContactId contact, Capabilities capabilities) {\n                if (contact.equals(getSelectedContact())\n                        && capabilities.hasCapabilities(Capabilities.CAPABILITY_IM)) {\n                    mHandler.post(new Runnable() {\n                        @Override\n                        public void run() {\n                            mInviteBtn.setEnabled(true);\n                        }\n                    });\n                }\n            }\n        };\n\n        OnClickListener btnInviteListener = new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                startActivity(OneToOneTalkView.forgeIntentToOpenConversation(\n                        InitiateSingleChat.this, getSelectedContact()));\n                finish();\n            }\n        };\n        mInviteBtn = (Button) findViewById(R.id.invite_btn);\n        mInviteBtn.setOnClickListener(btnInviteListener);\n        mInviteBtn.setEnabled(false);\n        /* Set contact selector */\n        AdapterView.OnItemSelectedListener mListenerContact = new AdapterView.OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                try {\n                    ContactId contact = getSelectedContact();\n                    if (mChatService.getOneToOneChat(contact).isAllowedToSendMessage()) {\n                        mInviteBtn.setEnabled(true);\n                        return;\n                    }\n                    mInviteBtn.setEnabled(false);\n                    mCapabilityService.requestContactCapabilities(new HashSet<>(Collections\n                            .singletonList(contact)));\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n\n            }\n        };\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        mSpinner.setAdapter(ContactListAdapter.createContactListAdapter(this));\n        mSpinner.setOnItemSelectedListener(mListenerContact);\n    }\n\n    private ContactId getSelectedContact() {\n        /* get selected phone number */\n        ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n        String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n        return ContactUtil.formatContact(phoneNumber);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/single/SendSingleFile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.single;\n\nimport static com.gsma.rcs.ri.utils.FileUtils.takePersistableContentUriPermission;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.messaging.chat.SendFile;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.util.Log;\n\nimport java.util.Set;\n\n/**\n * Send file to contact\n * \n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic class SendSingleFile extends SendFile {\n\n    private final static String EXTRA_CONTACT = \"contact\";\n\n    private ContactId mContact;\n\n    private static final String LOGTAG = LogUtils.getTag(SendSingleFile.class.getSimpleName());\n\n    private OneToOneFileTransferListener mFileTransferListener;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mContact = getIntent().getParcelableExtra(EXTRA_CONTACT);\n    }\n\n    /**\n     * Start SendFile activity\n     * \n     * @param context The context\n     * @param contact The contact ID\n     */\n    public static void startActivity(Context context, ContactId contact) {\n        Intent intent = new Intent(context, SendSingleFile.class);\n        intent.putExtra(EXTRA_CONTACT, (Parcelable) contact);\n        context.startActivity(intent);\n    }\n\n    @Override\n    public boolean transferFile(Uri file, FileTransfer.Disposition dispo, boolean fileicon) {\n        try {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"transferFile filename=\" + mFilename + \" size=\" + mFilesize);\n            }\n            /* Only take persistable permission for content Uris */\n            takePersistableContentUriPermission(this, file);\n            /* Initiate transfer */\n            mFileTransfer = mFileTransferService.transferFile(mContact, file, dispo, fileicon);\n            if (mFileTransfer != null) {\n                mTransferId = mFileTransfer.getTransferId();\n                return true;\n            }\n            Log.e(LOGTAG, \"Cannot transfer file: not found\");\n            return false;\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return false;\n        }\n    }\n\n    @Override\n    public void addFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        fileTransferService.addEventListener(mFileTransferListener);\n    }\n\n    @Override\n    public void removeFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        fileTransferService.removeEventListener(mFileTransferListener);\n    }\n\n    @Override\n    public void initialize() {\n        super.initialize();\n        mFileTransferListener = new OneToOneFileTransferListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String transferId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current transferId */\n                if (mTransferId == null || !mTransferId.equals(transferId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(ContactId contact, String transferId,\n                    final FileTransfer.State state, final FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" transferId=\" + transferId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current transferId */\n                if (mTransferId == null || !mTransferId.equals(transferId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sFileTransferReasonCodes[reasonCode\n                        .toInt()];\n                final String _state = RiApplication.sFileTransferStates[state.toInt()];\n                mHandler.post(new Runnable() {\n\n                    public void run() {\n                        if (mFileTransfer != null) {\n                            try {\n                                mResumeBtn.setEnabled(mFileTransfer.isAllowedToResumeTransfer());\n\n                            } catch (RcsServiceException e) {\n                                showExceptionThenExit(e);\n                            }\n                            try {\n                                mPauseBtn.setEnabled(mFileTransfer.isAllowedToPauseTransfer());\n                            } catch (RcsServiceException e) {\n                                showExceptionThenExit(e);\n                            }\n                        }\n                        switch (state) {\n                            case STARTED:\n                                //$FALL-THROUGH$\n                            case TRANSFERRED:\n                                /* Display transfer state started */\n                                mStatusView.setText(_state);\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_transfer_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_transfer_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_transfer_failed,\n                                        _reasonCode));\n                                break;\n\n                            default:\n                                mStatusView.setText(_state);\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" transferIds=\" + transferIds);\n                }\n            }\n\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/single/SingleChatIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.single;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.OneToOneTalkView;\nimport com.gsma.rcs.ri.messaging.TalkList;\nimport com.gsma.rcs.ri.messaging.chat.ChatMessageDAO;\nimport com.gsma.rcs.ri.messaging.chat.ChatPendingIntentManager;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.OneToOneChatIntent;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.media.RingtoneManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Single chat intent service\n * \n * @author Philippe LEMORDANT\n */\npublic class SingleChatIntentService extends IntentService {\n\n    private static final String[] PROJ_UNDELIVERED_MSG = new String[] {\n        ChatLog.Message.MESSAGE_ID\n    };\n    private static final String SEL_UNDELIVERED_MESSAGES = ChatLog.Message.CHAT_ID + \"=? AND \"\n            + ChatLog.Message.EXPIRED_DELIVERY + \"='1'\";\n\n    private ChatPendingIntentManager mChatPendingIntentManager;\n\n    private static final String LOGTAG = LogUtils.getTag(SingleChatIntentService.class\n            .getSimpleName());\n\n    /**\n     * Creates an IntentService.\n     */\n    public SingleChatIntentService() {\n        super(\"SingleChatIntentService\");\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mChatPendingIntentManager = ChatPendingIntentManager.getChatPendingIntentManager(this);\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        /* We want this service to stop running if forced stop so return not sticky. */\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n        String msgId = intent.getStringExtra(OneToOneChatIntent.EXTRA_MESSAGE_ID);\n        if (msgId == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read message ID\");\n            }\n            return;\n        }\n        switch (action) {\n            case OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE:\n                handleNewOneToOneChatMessage(intent, msgId);\n                break;\n\n            case OneToOneChatIntent.ACTION_MESSAGE_DELIVERY_EXPIRED:\n                handleUndeliveredMessage(intent, msgId);\n                break;\n\n            default:\n                Log.e(LOGTAG, \"Unknown action \".concat(action));\n                break;\n        }\n    }\n\n    private void handleUndeliveredMessage(Intent intent, String msgId) {\n        ContactId contact = intent.getParcelableExtra(OneToOneChatIntent.EXTRA_CONTACT);\n        if (contact == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read contact for message ID=\".concat(msgId));\n            }\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Undelivered message ID=\" + msgId + \" for contact \" + contact);\n        }\n        forwardUndeliveredMessage2UI(intent, contact);\n    }\n\n    /**\n     * Handle new one to one chat message\n     * \n     * @param messageIntent intent with chat message\n     */\n    private void handleNewOneToOneChatMessage(Intent messageIntent, String msgId) {\n        String mimeType = messageIntent.getStringExtra(OneToOneChatIntent.EXTRA_MIME_TYPE);\n        if (mimeType == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read message mime-type\");\n            }\n            return;\n        }\n        /* Read message from provider */\n        ChatMessageDAO msgDAO = ChatMessageDAO.getChatMessageDAO(this, msgId);\n        if (msgDAO == null) {\n            Log.e(LOGTAG, \"Cannot find group chat message with ID=\".concat(msgId));\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"One to one chat message \".concat(msgDAO.toString()));\n        }\n        forwardSingleChatMessage2UI(messageIntent, msgDAO);\n    }\n\n    /**\n     * Forward one to one chat message to view activity\n     * \n     * @param messageIntent intent\n     * @param message the chat message DAO\n     */\n    private void forwardSingleChatMessage2UI(Intent messageIntent, ChatMessageDAO message) {\n        ContactId contact = message.getContact();\n        String content = message.getContent();\n        Intent intent = OneToOneTalkView.forgeIntentOnStackEvent(this, contact, messageIntent);\n        Integer uniqueId = mChatPendingIntentManager.tryContinueChatConversation(intent,\n                message.getChatId());\n        if (uniqueId != null) {\n            PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT);\n            String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n            String title = getString(R.string.title_recv_chat, displayName);\n            String mimeType = message.getMimeType();\n            String msg;\n            switch (mimeType) {\n                case ChatLog.Message.MimeType.GEOLOC_MESSAGE:\n                    msg = getString(R.string.label_geoloc_msg);\n                    break;\n\n                case ChatLog.Message.MimeType.TEXT_MESSAGE:\n                    msg = content;\n                    break;\n\n                default:\n                    if (LogUtils.isActive) {\n                        Log.e(LOGTAG, \"Discard message type '\".concat(mimeType));\n                    }\n                    return;\n            }\n            Notification notif = buildNotification(contentIntent, title, msg);\n            mChatPendingIntentManager.postNotification(uniqueId, notif);\n            TalkList.notifyNewConversationEvent(this,\n                    OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE);\n        }\n    }\n\n    private void forwardUndeliveredMessage2UI(Intent undeliveredMessageIntent, ContactId contact) {\n        Intent intent = OneToOneTalkView.forgeIntentOnStackEvent(this, contact,\n                undeliveredMessageIntent);\n        Integer uniqueId = mChatPendingIntentManager.tryContinueChatConversation(intent,\n                contact.toString());\n        if (uniqueId != null) {\n            PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT);\n            String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n            String title = getString(R.string.title_undelivered_message);\n            String msg = getString(R.string.label_undelivered_message, displayName);\n            Notification notif = buildNotification(contentIntent, title, msg);\n            mChatPendingIntentManager.postNotification(uniqueId, notif);\n        }\n    }\n\n    /**\n     * Generate a notification\n     * \n     * @param invitation invitation\n     * @param title title\n     * @param message message\n     * @return the notification\n     */\n    private Notification buildNotification(PendingIntent invitation, String title, String message) {\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(invitation);\n        notif.setSmallIcon(R.drawable.ri_notif_chat_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(title);\n        notif.setContentText(message);\n        return notif.build();\n    }\n\n    /**\n     * Get set of undelivered messages\n     *\n     * @param ctx The context\n     * @param contact The contact\n     * @return set of undelivered messages\n     */\n    public static Set<String> getUndelivered(Context ctx, ContactId contact) {\n        Set<String> messageIds = new HashSet<>();\n        Cursor cursor = null;\n        try {\n            cursor = ctx.getContentResolver().query(ChatLog.Message.CONTENT_URI,\n                    PROJ_UNDELIVERED_MSG, SEL_UNDELIVERED_MESSAGES, new String[] {\n                        contact.toString()\n                    }, null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query undelivered message for contact=\" + contact);\n            }\n            if (!cursor.moveToFirst()) {\n                return messageIds;\n            }\n            int messageIdColumnIdx = cursor.getColumnIndexOrThrow(ChatLog.Message.MESSAGE_ID);\n            do {\n                messageIds.add(cursor.getString(messageIdColumnIdx));\n            } while (cursor.moveToNext());\n            return messageIds;\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/single/SingleChatInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.single;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * CHAT invitation receiver\n * \n * @author YPLO6403\n */\npublic class SingleChatInvitationReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, SingleChatIntentService.class);\n        context.startService(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/chat/single/UndeliveredMessageReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.chat.single;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Undelivered message receiver\n * \n * @author YPLO6403\n */\npublic class UndeliveredMessageReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, SingleChatIntentService.class);\n        context.startService(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/AudioMediaPlayer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.ri.utils.LogUtils;\n\nimport android.content.Context;\nimport android.media.MediaPlayer;\nimport android.net.Uri;\nimport android.util.Log;\n\nimport java.io.IOException;\n\n/**\n * AudioMediaPlayer class can be used to control playback of audio files and streams.\n *\n * @author Sandrine Lacharme on 12/01/2016.\n */\npublic class AudioMediaPlayer extends MediaPlayer {\n\n    private static final String LOGTAG = LogUtils.getTag(AudioRecorder.class.getSimpleName());\n    private final Uri mFile;\n    private final Context mCtx;\n    private final IAudioPlayerListener mListener;\n\n    /**\n     * Constructor\n     */\n    public AudioMediaPlayer(Context ctx, Uri file, IAudioPlayerListener listener) {\n        super();\n        mCtx = ctx;\n        mFile = file;\n        mListener = listener;\n    }\n\n    /**\n     * Start playing an audio file\n     */\n    public void startPlay() throws IOException {\n        setDataSource(mCtx, mFile);\n        prepareAsync();\n        setOnPreparedListener(new MediaPlayer.OnPreparedListener() {\n            @Override\n            public void onPrepared(MediaPlayer mp) {\n                setVolume(1.0f, 1.0f);\n                mp.start();\n            }\n        });\n        setOnCompletionListener(new MediaPlayer.OnCompletionListener() {\n            @Override\n            public void onCompletion(MediaPlayer mp) {\n                mp.reset();\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onCompletion\");\n                }\n                mListener.onCompletion();\n            }\n        });\n    }\n\n    /**\n     * Stop playing an audio file and reset the peripheral\n     */\n    public void stopPlay() {\n        stop();\n        reset();\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"stopPlay\");\n        }\n    }\n\n    /**\n     * Gets audio file duration\n     * \n     * @param ctx the context\n     * @param file the file Uri\n     * @return the duration (msec)\n     */\n    public static long getDuration(Context ctx, Uri file) {\n        MediaPlayer mp = MediaPlayer.create(ctx, file);\n        if (mp == null) {\n            return -1;\n        }\n        int duration = mp.getDuration();\n        mp.release();\n        return duration;\n    }\n\n    /**\n     * Interface to notify AudioPlayer events\n     */\n    public interface IAudioPlayerListener {\n        /**\n         * Called when record is played\n         */\n        void onCompletion();\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/AudioMessageRecordActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.media.MediaScannerConnection;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Locale;\n\n/**\n * @author Philippe LEMORDANT\n * @author Sandrine LACHARME\n */\npublic class AudioMessageRecordActivity extends RcsActivity {\n\n    private static final String LOGTAG = LogUtils.getTag(AudioRecorder.class.getName());\n    private Button mBtnPlay;\n    private Button mBtnStop;\n    private Button mBtnRecord;\n    private TextView mTextUri;\n    private TextView mTextSize;\n    private TextView mTextDuration;\n    private boolean mRecording;\n    private boolean mPlaying;\n    private RcsActivity mThisActivity;\n    private AudioMediaPlayer mAudioPlayer;\n    private AudioRecorder mAudioRecorder;\n    private Uri mFile;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.audio_msg_record);\n\n        initialize();\n\n        startMonitorServices(ConnectionManager.RcsServiceName.FILE_TRANSFER);\n        /** Register to API manager */\n        if (!isServiceConnected(ConnectionManager.RcsServiceName.FILE_TRANSFER)) {\n            showMessageThenExit(R.string.label_service_not_available);\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (mAudioPlayer != null) {\n            mAudioPlayer.release();\n        }\n        if (mAudioRecorder != null) {\n            mAudioRecorder.stopRecord();\n            mAudioRecorder.release();\n        }\n    }\n\n    private boolean deleteAudioRecord(Uri file) {\n        File fileToDelete = new File(file.getPath());\n        return !fileToDelete.exists() || fileToDelete.delete();\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode && mAudioRecorder != null) {\n            mAudioRecorder.stopRecord();\n            mFile = mAudioRecorder.getFile();\n            if (mFile != null) {\n                MediaScannerConnection.scanFile(mThisActivity, new String[] {\n                    mFile.getPath()\n                }, null, null);\n                Intent in = new Intent();\n                in.setData(mFile);\n                setResult(Activity.RESULT_OK, in);\n                mThisActivity.finish();\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    private void displayAudioFileInfo() {\n        mTextUri.setText(FileUtils.getFileName(mThisActivity, mFile));\n        long duration = AudioMediaPlayer.getDuration(mThisActivity, mFile) / 1000L;\n        mTextDuration.setText(String.format(Locale.getDefault(), \"%d\", duration));\n        long size = FileUtils.getFileSize(mThisActivity, mFile);\n        mTextSize.setText(FileUtils.humanReadableByteCount(size, true));\n        if (LogUtils.isActive) {\n            Log.w(LOGTAG, \"Audio recorded file='\" + mFile + \"' duration(sec)=\" + duration\n                    + \" size=\" + size);\n        }\n    }\n\n    private void initialize() {\n        mThisActivity = this;\n        mBtnPlay = (Button) findViewById(R.id.buttonPlay);\n        mBtnStop = (Button) findViewById(R.id.buttonStop);\n        mBtnRecord = (Button) findViewById(R.id.buttonRecord);\n        mTextDuration = (TextView) findViewById(R.id.duration);\n        mTextUri = (TextView) findViewById(R.id.uri);\n        mTextSize = (TextView) findViewById(R.id.size);\n        mBtnStop.setEnabled(false);\n        mBtnPlay.setEnabled(false);\n        mBtnRecord.setEnabled(true);\n\n        AudioRecorder.IAudioMessageRecordListener listenerRecorder = new AudioRecorder.IAudioMessageRecordListener() {\n\n            @Override\n            public void onMaxDurationReached() {\n                mBtnStop.setEnabled(false);\n                mBtnRecord.setEnabled(true);\n                mBtnPlay.setEnabled(true);\n                mRecording = false;\n                mThisActivity.showMessage(R.string.max_audio_record_reached);\n                mFile = mAudioRecorder.getFile();\n                displayAudioFileInfo();\n            }\n\n        };\n        try {\n            FileTransferServiceConfiguration config = getFileTransferApi().getConfiguration();\n            mAudioRecorder = new AudioRecorder(config.getMaxAudioMessageDuration(),\n                    listenerRecorder);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return;\n        }\n        mBtnRecord.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                try {\n                    if (mFile != null) {\n                        deleteAudioRecord(mFile);\n                    }\n                    mBtnStop.setEnabled(true);\n                    mBtnPlay.setEnabled(false);\n                    mBtnRecord.setEnabled(false);\n\n                    mTextUri.setText(\"\");\n                    mTextDuration.setText(\"\");\n                    mTextSize.setText(\"\");\n\n                    mAudioRecorder.launchRecord();\n                    mRecording = true;\n                    mPlaying = false;\n\n                } catch (IOException e) {\n                    mThisActivity.showExceptionThenExit(e);\n                }\n            }\n        });\n\n        mBtnStop.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                mBtnStop.setEnabled(false);\n                mBtnRecord.setEnabled(true);\n                mBtnPlay.setEnabled(true);\n                if (mRecording) {\n                    mRecording = false;\n                    mAudioRecorder.stopRecord();\n                    mFile = mAudioRecorder.getFile();\n                    displayAudioFileInfo();\n                    return;\n                }\n                if (mPlaying) {\n                    mPlaying = false;\n                    mAudioPlayer.stopPlay();\n                }\n            }\n        });\n\n        final AudioMediaPlayer.IAudioPlayerListener listenerPlayer = new AudioMediaPlayer.IAudioPlayerListener() {\n\n            @Override\n            public void onCompletion() {\n                mBtnStop.setEnabled(false);\n                mBtnRecord.setEnabled(true);\n                mBtnPlay.setEnabled(true);\n                mPlaying = false;\n            }\n        };\n\n        mBtnPlay.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                mBtnStop.setEnabled(true);\n                mBtnRecord.setEnabled(false);\n                mBtnPlay.setEnabled(false);\n                mPlaying = true;\n                try {\n                    mAudioPlayer = new AudioMediaPlayer(mThisActivity, mFile, listenerPlayer);\n                    mAudioPlayer.startPlay();\n\n                } catch (IOException e) {\n                    mThisActivity.showExceptionThenExit(e);\n                }\n            }\n\n        });\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/AudioRecorder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.ri.utils.LogUtils;\n\nimport android.media.MediaRecorder;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.IOException;\n\npublic class AudioRecorder extends MediaRecorder {\n\n    private static final String LOGTAG = LogUtils.getTag(AudioRecorder.class.getSimpleName());\n\n    private static final String AUDIO_FILE_DIR = \"/ri/audios\";\n    private static final String AUDIO_FILE_EXTENSION = \".mp4\";\n    private static final String AUDIO_FILE_PREFIX = \"audio_\";\n\n    private final long mMaxAudioDuration;\n    private final IAudioMessageRecordListener mListener;\n    private Uri mFile;\n    private MediaRecorder mCurrentRecord;\n    private boolean mStartRecording;\n\n    /**\n     * Constructor\n     *\n     * @param maxAudioDuration maximum duration\n     * @param listener callback\n     */\n    public AudioRecorder(long maxAudioDuration, IAudioMessageRecordListener listener) {\n        mMaxAudioDuration = maxAudioDuration;\n        mListener = listener;\n    }\n\n    private MediaRecorder createMediaRecorder() {\n        MediaRecorder record = new MediaRecorder();\n        mFile = createAudioUri();\n        record.setAudioSource(AudioSource.VOICE_COMMUNICATION);\n        record.setOutputFormat(OutputFormat.DEFAULT);\n        record.setAudioEncoder(AudioEncoder.AMR_WB);\n        record.setOutputFile(mFile.getPath());\n        record.setMaxDuration((int) mMaxAudioDuration);\n        record.setOnInfoListener(new OnInfoListener() {\n            @Override\n            public void onInfo(MediaRecorder mr, int what, int extra) {\n                if (MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED == what) {\n                    mStartRecording = false;\n                    mr.stop();\n                    mr.reset();\n                    mListener.onMaxDurationReached();\n                }\n            }\n        });\n        return record;\n    }\n\n    /**\n     * Launches audio recording\n     * \n     * @throws IOException\n     */\n    public void launchRecord() throws IOException {\n        mCurrentRecord = createMediaRecorder();\n        mCurrentRecord.prepare();\n        mCurrentRecord.start();\n        mStartRecording = true;\n    }\n\n    /**\n     * Stops audio recording\n     */\n    public void stopRecord() {\n        if (mCurrentRecord != null) {\n            if (mStartRecording) {\n                mStartRecording = false;\n                mCurrentRecord.stop();\n                mCurrentRecord.reset();\n            }\n        }\n    }\n\n    /**\n     * Generates a random filename for audio file\n     */\n    private Uri createAudioUri() {\n        File audio = new File(getAudioDirectory() + \"/\" + AUDIO_FILE_PREFIX\n                + System.currentTimeMillis() + AUDIO_FILE_EXTENSION);\n        Uri result = Uri.fromFile(audio);\n        if (LogUtils.isActive) {\n            Log.w(LOGTAG, \"Audio file Uri=\".concat(result.toString()));\n        }\n        return result;\n    }\n\n    public Uri getFile() {\n        return mFile;\n    }\n\n    /**\n     * Interface to notify AudioMessageRecord events\n     */\n    public interface IAudioMessageRecordListener {\n        /**\n         * Called when max duration is reached\n         */\n        void onMaxDurationReached();\n    }\n\n    /**\n     * Get sent audio root directory\n     *\n     * @return Path of audio directory\n     */\n    private String getAudioDirectory() {\n        File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath()\n                .concat(AUDIO_FILE_DIR));\n        if (!directory.exists()) {\n            directory.mkdirs();\n        }\n        return directory.getPath();\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/FileTransferDAO.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * File transfer Data Object\n * \n * @author Philippe LEMORDANT\n */\npublic class FileTransferDAO implements Parcelable {\n\n    private final String mTransferId;\n    private final ContactId mContact;\n    private final Uri mFile;\n    private final String mFilename;\n    private final String mChatId;\n    private final String mMimeType;\n    private final FileTransfer.State mState;\n    private final ReadStatus mReadStatus;\n    private final Direction mDirection;\n    private final long mTimestamp;\n    private final long mTimestampSent;\n    private final long mTimestampDelivered;\n    private final long mTimestampDisplayed;\n    private final long mSizeTransferred;\n    private final long mSize;\n    private final Uri mThumbnail;\n    private final long mFileExpiration;\n    private final long mFileIconExpiration;\n    private final FileTransfer.ReasonCode mReasonCode;\n    private static ContentResolver sContentResolver;\n    private final FileTransfer.Disposition mDisposition;\n    private final String mIconMimeType;\n    private final boolean mExpiredDelivery;\n\n    public String getIconMimeType() {\n        return mIconMimeType;\n    }\n\n    public FileTransfer.State getState() {\n        return mState;\n    }\n\n    public ReadStatus getReadStatus() {\n        return mReadStatus;\n    }\n\n    public long getTimestampSent() {\n        return mTimestampSent;\n    }\n\n    public long getTimestampDelivered() {\n        return mTimestampDelivered;\n    }\n\n    public long getTimestampDisplayed() {\n        return mTimestampDisplayed;\n    }\n\n    public long getSizeTransferred() {\n        return mSizeTransferred;\n    }\n\n    public String getTransferId() {\n        return mTransferId;\n    }\n\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    public Uri getFile() {\n        return mFile;\n    }\n\n    public String getFilename() {\n        return mFilename;\n    }\n\n    public String getChatId() {\n        return mChatId;\n    }\n\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public long getSize() {\n        return mSize;\n    }\n\n    public Uri getThumbnail() {\n        return mThumbnail;\n    }\n\n    public FileTransfer.Disposition getDisposition() {\n        return mDisposition;\n    }\n\n    /**\n     * Returns the time when the file on the content server is no longer valid to download.\n     * \n     * @return time\n     */\n    public long getFileExpiration() {\n        return mFileExpiration;\n    }\n\n    /**\n     * Returns the time when the file icon on the content server is no longer valid to download.\n     * \n     * @return time\n     */\n    public long getFileIconExpiration() {\n        return mFileIconExpiration;\n    }\n\n    public FileTransfer.ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    private FileTransferDAO(FileTransfer.Disposition disposition, String transferId,\n            ContactId contact, Uri file, String filename, String chatId, String mimeType,\n            FileTransfer.State state, ReadStatus readStatus, Direction direction, long timestamp,\n            long timestampSent, long timestampDelivered, long timestampDisplayed,\n            long sizeTransferred, long size, Uri thumbnail, long fileExpiration,\n            long fileIconExpiration, FileTransfer.ReasonCode reasonCode, boolean expiredDelivery,\n            String iconMimeType) {\n        mDisposition = disposition;\n        mTransferId = transferId;\n        mContact = contact;\n        mFile = file;\n        mFilename = filename;\n        mChatId = chatId;\n        mMimeType = mimeType;\n        mState = state;\n        mReadStatus = readStatus;\n        mDirection = direction;\n        mTimestamp = timestamp;\n        mTimestampSent = timestampSent;\n        mTimestampDelivered = timestampDelivered;\n        mTimestampDisplayed = timestampDisplayed;\n        mSizeTransferred = sizeTransferred;\n        mSize = size;\n        mThumbnail = thumbnail;\n        mFileExpiration = fileExpiration;\n        mFileIconExpiration = fileIconExpiration;\n        mReasonCode = reasonCode;\n        mExpiredDelivery = expiredDelivery;\n        mIconMimeType = iconMimeType;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     */\n    public FileTransferDAO(Parcel source) {\n        mTransferId = source.readString();\n        boolean containsContactId = source.readInt() != 0;\n        if (containsContactId) {\n            mContact = ContactId.CREATOR.createFromParcel(source);\n        } else {\n            mContact = null;\n        }\n        boolean containsFile = source.readInt() != 0;\n        if (containsFile) {\n            mFile = Uri.parse(source.readString());\n        } else {\n            mFile = null;\n        }\n        mFilename = source.readString();\n        mChatId = source.readString();\n        mMimeType = source.readString();\n        mState = FileTransfer.State.valueOf(source.readInt());\n        mReadStatus = ReadStatus.valueOf(source.readInt());\n        mDirection = Direction.valueOf(source.readInt());\n        mTimestamp = source.readLong();\n        mTimestampSent = source.readLong();\n        mTimestampDelivered = source.readLong();\n        mTimestampDisplayed = source.readLong();\n        mSizeTransferred = source.readLong();\n        mSize = source.readLong();\n        boolean containsThumbnail = source.readInt() != 0;\n        if (containsThumbnail) {\n            mThumbnail = Uri.parse(source.readString());\n        } else {\n            mThumbnail = null;\n        }\n        mReasonCode = FileTransfer.ReasonCode.valueOf(source.readInt());\n        mFileExpiration = source.readLong();\n        mFileIconExpiration = source.readLong();\n        mExpiredDelivery = source.readInt() == 1;\n        boolean containsIconMimeType = source.readInt() != 0;\n        if (containsIconMimeType) {\n            mIconMimeType = source.readString();\n        } else {\n            mIconMimeType = null;\n        }\n        mDisposition = FileTransfer.Disposition.valueOf(source.readInt());\n    }\n\n    @Override\n    public String toString() {\n        return \"FileTransferDAO [ftId=\" + mTransferId + \", contact=\" + mContact + \", filename=\"\n                + mFilename + \", chatId=\" + mChatId + \", mimeType=\" + mMimeType + \", state=\"\n                + mState + \", size=\" + mSize + \", expiration=\" + mFileExpiration + \", thumbnail=\"\n                + mThumbnail + \", iconExpiration=\" + mFileIconExpiration + \"]\";\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mTransferId);\n        if (mContact != null) {\n            dest.writeInt(1);\n            mContact.writeToParcel(dest, flags);\n        } else {\n            dest.writeInt(0);\n        }\n        if (mFile != null) {\n            dest.writeInt(1);\n            dest.writeString(mFile.toString());\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeString(mFilename);\n        dest.writeString(mChatId);\n        dest.writeString(mMimeType);\n        dest.writeInt(mState.toInt());\n        dest.writeInt(mReadStatus.toInt());\n        dest.writeInt(mDirection.toInt());\n        dest.writeLong(mTimestamp);\n        dest.writeLong(mTimestampSent);\n        dest.writeLong(mTimestampDelivered);\n        dest.writeLong(mTimestampDisplayed);\n        dest.writeLong(mSizeTransferred);\n        dest.writeLong(mSize);\n        if (mThumbnail != null) {\n            dest.writeInt(1);\n            dest.writeString(mThumbnail.toString());\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeInt(mReasonCode.toInt());\n        dest.writeLong(mFileExpiration);\n        dest.writeLong(mFileIconExpiration);\n        dest.writeInt(mExpiredDelivery ? 1 : 0);\n        if (mIconMimeType != null) {\n            dest.writeInt(1);\n            dest.writeString(mIconMimeType);\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeInt(mDisposition.toInt());\n    }\n\n    public static final Parcelable.Creator<FileTransferDAO> CREATOR = new Parcelable.Creator<FileTransferDAO>() {\n        @Override\n        public FileTransferDAO createFromParcel(Parcel in) {\n            return new FileTransferDAO(in);\n        }\n\n        @Override\n        public FileTransferDAO[] newArray(int size) {\n            return new FileTransferDAO[size];\n        }\n    };\n\n    /**\n     * Gets instance of File Transfer from RCS provider\n     * \n     * @param context the context\n     * @param fileTransferId the file tr ansfer ID\n     * @return instance or null if entry not found\n     */\n    public static FileTransferDAO getFileTransferDAO(final Context context,\n            final String fileTransferId) {\n        if (sContentResolver == null) {\n            sContentResolver = context.getContentResolver();\n        }\n        Cursor cursor = null;\n        try {\n            cursor = sContentResolver.query(\n                    Uri.withAppendedPath(FileTransferLog.CONTENT_URI, fileTransferId), null, null,\n                    null, null);\n            if (cursor == null) {\n                throw new SQLException(\n                        \"Failed to find Filetransfer with ID: \".concat(fileTransferId));\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.CHAT_ID));\n            String number = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.CONTACT));\n            ContactId contact = null;\n            if (number != null) {\n                contact = ContactUtil.formatContact(number);\n            }\n            Uri file = Uri.parse(cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILE)));\n            String filename = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILENAME));\n            String mimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.MIME_TYPE));\n            FileTransfer.State state = FileTransfer.State.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.STATE)));\n            ReadStatus readStatus = ReadStatus.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.READ_STATUS)));\n            Direction direction = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.DIRECTION)));\n            long timestamp = cursor\n                    .getLong(cursor.getColumnIndexOrThrow(FileTransferLog.TIMESTAMP));\n            long timestampSent = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_SENT));\n            long timestampDelivered = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DELIVERED));\n            long timestampDisplayed = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DISPLAYED));\n            long sizeTransferred = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TRANSFERRED));\n            long size = cursor.getLong(cursor.getColumnIndexOrThrow(FileTransferLog.FILESIZE));\n            FileTransfer.Disposition disposition = FileTransfer.Disposition.valueOf(cursor\n                    .getInt(cursor.getColumnIndexOrThrow(FileTransferLog.DISPOSITION)));\n            String fileIcon = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON));\n            Uri thumbnail = null;\n            if (fileIcon != null) {\n                thumbnail = Uri.parse(fileIcon);\n            }\n            FileTransfer.ReasonCode reasonCode = FileTransfer.ReasonCode.valueOf(cursor\n                    .getInt(cursor.getColumnIndexOrThrow(FileTransferLog.REASON_CODE)));\n            long fileExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILE_EXPIRATION));\n            long fileIconExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_EXPIRATION));\n            boolean expiredDelivery = cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.EXPIRED_DELIVERY)) == 1;\n            String iconMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_MIME_TYPE));\n            return new FileTransferDAO(disposition, fileTransferId, contact, file, filename,\n                    chatId, mimeType, state, readStatus, direction, timestamp, timestampSent,\n                    timestampDelivered, timestampDisplayed, sizeTransferred, size, thumbnail,\n                    fileExpiration, fileIconExpiration, reasonCode, expiredDelivery, iconMimeType);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public boolean isOneToOne() {\n        return mContact != null && mContact.toString().equals(mChatId);\n    }\n\n    public boolean isExpiredDelivery() {\n        return mExpiredDelivery;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/FileTransferIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.messaging.OneToOneTalkView;\nimport com.gsma.rcs.ri.messaging.TalkList;\nimport com.gsma.rcs.ri.messaging.chat.ChatPendingIntentManager;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.media.RingtoneManager;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * File transfer intent service\n * \n * @author Philippe LEMORDANT\n */\npublic class FileTransferIntentService extends IntentService {\n\n    private static final String LOGTAG = LogUtils.getTag(FileTransferIntentService.class.getName());\n    private final static String[] PROJ_UNDELIVERED_FT = new String[] {\n        FileTransferLog.FT_ID\n    };\n\n    private static final String SEL_UNDELIVERED_FTS = FileTransferLog.CHAT_ID + \"=? AND \"\n            + FileTransferLog.EXPIRED_DELIVERY + \"='1'\";\n\n    /**\n     * Constructor\n     */\n    public FileTransferIntentService() {\n        super(\"FileTransferIntentService\");\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        /*\n         * We want this service to stop running if forced stop so return not sticky.\n         */\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n        String transferId = intent.getStringExtra(FileTransferIntent.EXTRA_TRANSFER_ID);\n        if (transferId == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read transfer ID\");\n            }\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onHandleIntent file transfer with ID \".concat(transferId));\n        }\n        switch (action) {\n            case FileTransferIntent.ACTION_FILE_TRANSFER_DELIVERY_EXPIRED:\n                handleUndeliveredFileTransfer(intent, transferId);\n                break;\n            case FileTransferIntent.ACTION_NEW_INVITATION:\n                handleFileTransferInvitation(intent, transferId);\n                break;\n            case FileTransferIntent.ACTION_RESUME:\n                handleFileTransferResume(intent, transferId);\n                break;\n            default:\n                Log.e(LOGTAG, \"Unknown action \".concat(action));\n        }\n    }\n\n    private void handleFileTransferResume(Intent intent, String transferId) {\n        FileTransferDAO ftDao = FileTransferDAO.getFileTransferDAO(this, transferId);\n        if (ftDao != null) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onHandleIntent file transfer resume with ID \".concat(transferId));\n            }\n            if (Direction.INCOMING == ftDao.getDirection()) {\n                startActivity(ReceiveFileTransfer.forgeResumeIntent(this, ftDao, intent));\n            } else {\n                startActivity(InitiateFileTransfer.forgeResumeIntent(this, ftDao, intent));\n            }\n        }\n    }\n\n    private void handleFileTransferInvitation(Intent intent, String transferId) {\n        FileTransferDAO ftDao = FileTransferDAO.getFileTransferDAO(this, transferId);\n        if (ftDao != null) {\n            if (FileTransfer.State.REJECTED == ftDao.getState()) {\n                Log.e(LOGTAG, \"File transfer already rejected. Id=\".concat(transferId));\n                return;\n            }\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"File Transfer invitation filename=\" + ftDao.getFilename() + \" size=\"\n                        + ftDao.getSize());\n            }\n            forwardFileTransferInvitationToUi(intent, ftDao);\n        }\n    }\n\n    /**\n     * Forward file transfer invitation to UI\n     * \n     * @param invitation Intent invitation\n     * @param ftDao the file transfer data object\n     */\n    private void forwardFileTransferInvitationToUi(Intent invitation, FileTransferDAO ftDao) {\n        ContactId contact = ftDao.getContact();\n        if (ftDao.getContact() == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"forwardFileTransferInvitationToUi failed: cannot parse contact\");\n            }\n            return;\n        }\n        Intent intent = ReceiveFileTransfer.forgeInvitationIntent(this, ftDao, invitation);\n        /*\n         * If the PendingIntent has the same operation, action, data, categories, components, and\n         * flags it will be replaced. Invitation should be notified individually so we use a random\n         * generator to provide a unique request code and reuse it for the notification.\n         */\n        int uniqueId = Utils.getUniqueIdForPendingIntent();\n        PendingIntent pi = PendingIntent.getActivity(this, uniqueId, intent,\n                PendingIntent.FLAG_ONE_SHOT);\n\n        String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n        String title = getString(R.string.title_recv_file_transfer);\n        String message = getString(R.string.label_from_args, displayName);\n\n        /* Send notification */\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        Notification notif = buildNotification(pi, title, message);\n        notificationManager.notify(uniqueId, notif);\n        TalkList.notifyNewConversationEvent(this, FileTransferIntent.ACTION_NEW_INVITATION);\n    }\n\n    private void handleUndeliveredFileTransfer(Intent intent, String transferId) {\n        ContactId contact = intent.getParcelableExtra(FileTransferIntent.EXTRA_CONTACT);\n        if (contact == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read contact for ftId=\".concat(transferId));\n            }\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Undelivered file transfer ID=\" + transferId + \" for contact \" + contact);\n        }\n        forwardUndeliveredFileTransferToUi(intent, contact);\n    }\n\n    private void forwardUndeliveredFileTransferToUi(Intent undeliveredIntent, ContactId contact) {\n        Intent intent = OneToOneTalkView.forgeIntentOnStackEvent(this, contact, undeliveredIntent);\n        ChatPendingIntentManager pendingIntentmanager = ChatPendingIntentManager\n                .getChatPendingIntentManager(this);\n        Integer uniqueId = pendingIntentmanager.tryContinueChatConversation(intent,\n                contact.toString());\n        if (uniqueId != null) {\n            PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                    PendingIntent.FLAG_UPDATE_CURRENT);\n            String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n            String title = getString(R.string.title_undelivered_filetransfer);\n            String msg = getString(R.string.label_undelivered_filetransfer, displayName);\n            Notification notif = buildNotification(contentIntent, title, msg);\n            pendingIntentmanager.postNotification(uniqueId, notif);\n        }\n    }\n\n    /**\n     * Generate a notification\n     * \n     * @param pendingIntent pending intent\n     * @param title title\n     * @param message message\n     * @return the notification\n     */\n    private Notification buildNotification(PendingIntent pendingIntent, String title, String message) {\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(pendingIntent);\n        notif.setSmallIcon(R.drawable.ri_notif_file_transfer_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(title);\n        notif.setContentText(message);\n        return notif.build();\n    }\n\n    /**\n     * Get set of undelivered file transfers\n     *\n     * @param ctx The context\n     * @param contact The contact\n     * @return set of undelivered file transfers\n     */\n    public static Set<String> getUndelivered(Context ctx, ContactId contact) {\n        Set<String> ids = new HashSet<>();\n        Cursor cursor = null;\n        try {\n            cursor = ctx.getContentResolver().query(FileTransferLog.CONTENT_URI,\n                    PROJ_UNDELIVERED_FT, SEL_UNDELIVERED_FTS, new String[] {\n                        contact.toString()\n                    }, null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query undelivered file transfers for contact=\"\n                        + contact);\n            }\n            if (!cursor.moveToFirst()) {\n                return ids;\n            }\n            int idColumnIdx = cursor.getColumnIndexOrThrow(FileTransferLog.FT_ID);\n            do {\n                ids.add(cursor.getString(idColumnIdx));\n            } while (cursor.moveToNext());\n            return ids;\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/FileTransferInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * File transfer invitation receiver\n * \n * @author YPLO6403\n */\npublic class FileTransferInvitationReceiver extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, FileTransferIntentService.class);\n        context.startService(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/FileTransferLogView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * A class to view the persisted information for chat message<br>\n * Created by Philippe LEMORDANT.\n */\npublic class FileTransferLogView extends RcsActivity {\n    private static final String EXTRA_FT_ID = \"id\";\n    private String mFileTransferId;\n    private TextView mTxtViewChatId;\n    private TextView mTxtViewContact;\n    private TextView mTxtViewDate;\n    private TextView mTxtViewDir;\n    private TextView mTxtViewFileSize;\n    private TextView mTxtViewFilename;\n    private TextView mTxtViewMime;\n    private TextView mTxtViewReason;\n    private TextView mTxtViewState;\n    private TextView mTxtViewTransferred;\n    private TextView mTxtViewUri;\n    private TextView mTxtViewDateSent;\n    private TextView mTxtViewDateDelivered;\n    private TextView mTxtViewDateDisplayed;\n    private TextView mTxtViewRead;\n    private TextView mTxtViewExpiredDelivery;\n    private static DateFormat sDateFormat;\n    private TextView mTxtViewFileExpiration;\n    private TextView mTxtViewIconExpiration;\n    private TextView mTxtViewIconUri;\n    private TextView mTxtViewIconMime;\n    private TextView mTxtViewId;\n    private TextView mTxtViewDisposition;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.filetransfer_log_item);\n        initialize();\n        mFileTransferId = getIntent().getStringExtra(EXTRA_FT_ID);\n    }\n\n    private void initialize() {\n        mTxtViewId = (TextView) findViewById(R.id.history_log_item_id);\n        mTxtViewChatId = (TextView) findViewById(R.id.history_log_item_chat_id);\n        mTxtViewContact = (TextView) findViewById(R.id.history_log_item_contact);\n        mTxtViewState = (TextView) findViewById(R.id.history_log_item_state);\n        mTxtViewReason = (TextView) findViewById(R.id.history_log_item_reason);\n        mTxtViewDir = (TextView) findViewById(R.id.history_log_item_direction);\n        mTxtViewDate = (TextView) findViewById(R.id.history_log_item_date);\n        mTxtViewMime = (TextView) findViewById(R.id.history_log_item_mime);\n        mTxtViewFilename = (TextView) findViewById(R.id.history_log_item_filename);\n        mTxtViewFileSize = (TextView) findViewById(R.id.history_log_item_size);\n        mTxtViewUri = (TextView) findViewById(R.id.history_log_item_uri);\n        mTxtViewTransferred = (TextView) findViewById(R.id.history_log_item_transferred);\n        mTxtViewDateSent = (TextView) findViewById(R.id.history_log_item_date_sent);\n        mTxtViewDateDelivered = (TextView) findViewById(R.id.history_log_item_date_delivered);\n        mTxtViewDateDisplayed = (TextView) findViewById(R.id.history_log_item_date_displayed);\n        mTxtViewRead = (TextView) findViewById(R.id.history_log_item_read_status);\n        mTxtViewExpiredDelivery = (TextView) findViewById(R.id.history_log_item_expired_delivery);\n        mTxtViewFileExpiration = (TextView) findViewById(R.id.history_log_item_date_file_expiration);\n        mTxtViewIconExpiration = (TextView) findViewById(R.id.history_log_item_date_icon_expiration);\n        mTxtViewIconUri = (TextView) findViewById(R.id.history_log_item_icon);\n        mTxtViewIconMime = (TextView) findViewById(R.id.history_log_item_icon_mime);\n        mTxtViewDisposition = (TextView) findViewById(R.id.history_log_item_disposition);\n    }\n\n    private String getDateFromDb(long timestamp) {\n        if (0 == timestamp) {\n            return \"\";\n        }\n        if (sDateFormat == null) {\n            sDateFormat = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\", Locale.getDefault());\n        }\n        return sDateFormat.format(new Date(timestamp));\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        FileTransferDAO dao = FileTransferDAO.getFileTransferDAO(this, mFileTransferId);\n        if (dao == null) {\n            showMessageThenExit(R.string.error_item_not_found);\n            return;\n        }\n        mTxtViewId.setText(mFileTransferId);\n        mTxtViewChatId.setText(dao.getChatId());\n        ContactId contact = dao.getContact();\n        if (contact != null) {\n            mTxtViewContact.setText(contact.toString());\n        } else {\n            mTxtViewContact.setText(\"\");\n        }\n        mTxtViewState.setText(RiApplication.sFileTransferStates[dao.getState().toInt()]);\n        mTxtViewReason.setText(RiApplication.sFileTransferReasonCodes[dao.getReasonCode().toInt()]);\n        mTxtViewDir.setText(RiApplication.getDirection(dao.getDirection()));\n        mTxtViewDate.setText(getDateFromDb(dao.getTimestamp()));\n        mTxtViewDateSent.setText(getDateFromDb(dao.getTimestampSent()));\n        mTxtViewDateDelivered.setText(getDateFromDb(dao.getTimestampDelivered()));\n        mTxtViewDateDisplayed.setText(getDateFromDb(dao.getTimestampDisplayed()));\n        mTxtViewRead.setText(dao.getReadStatus().toString());\n        mTxtViewExpiredDelivery.setText(Boolean.toString(dao.isExpiredDelivery()));\n        mTxtViewMime.setText(dao.getMimeType());\n        mTxtViewFilename.setText(dao.getFilename());\n        mTxtViewFileSize.setText(String.valueOf(dao.getSize()));\n        mTxtViewUri.setText(dao.getFile().toString());\n        mTxtViewTransferred.setText(String.valueOf(dao.getSizeTransferred()));\n        mTxtViewFileExpiration.setText(getDateFromDb(dao.getFileExpiration()));\n        mTxtViewIconExpiration.setText(getDateFromDb(dao.getFileIconExpiration()));\n        mTxtViewIconUri.setText(dao.getThumbnail() == null ? \"\" : dao.getThumbnail().toString());\n        mTxtViewIconMime\n                .setText(dao.getIconMimeType() == null ? \"\" : dao.getThumbnail().toString());\n        mTxtViewDisposition.setText(dao.getDisposition().toString());\n    }\n\n    /**\n     * Start activity to view details of file transfer record\n     *\n     * @param context the context\n     * @param fileTransferId the file transfer ID\n     */\n    public static void startActivity(Context context, String fileTransferId) {\n        Intent intent = new Intent(context, FileTransferLogView.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(EXTRA_FT_ID, fileTransferId);\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/FileTransferResumeReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * File transfer resume receiver\n * \n * @author YPLO6403\n */\npublic class FileTransferResumeReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, FileTransferIntentService.class);\n        context.startService(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/FileTransferServiceConfigActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CheckBox;\nimport android.widget.Spinner;\nimport android.widget.TableRow;\nimport android.widget.TextView;\n\nimport java.util.Locale;\n\n/**\n * Display/update the chat service configuration\n * \n * @author Philippe LEMORDANT\n */\npublic class FileTransferServiceConfigActivity extends RcsActivity {\n\n    private FileTransferServiceConfiguration mConfig;\n\n    private Spinner mSpinnerImageResizeOption;\n\n    private CheckBox mCheckBoxIsAutoAccept;\n\n    private CheckBox mCheckBoxIsAutoAcceptInRoaming;\n\n    private static final String LOGTAG = LogUtils.getTag(FileTransferServiceConfigActivity.class\n            .getSimpleName());\n\n    private final static String[] ImageResizeOptionTab = new String[] {\n            ImageResizeOption.ALWAYS_RESIZE.toString(), ImageResizeOption.ALWAYS_ASK.toString(),\n            ImageResizeOption.NEVER_RESIZE.toString()\n    };\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.filetransfer_service_config);\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        try {\n            mConfig = getFileTransferApi().getConfiguration();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return;\n        }\n        startMonitorServices(RcsServiceName.FILE_TRANSFER);\n\n        mSpinnerImageResizeOption = (Spinner) findViewById(R.id.ft_ImageResizeOption);\n        ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(this,\n                android.R.layout.simple_spinner_item, ImageResizeOptionTab);\n        dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        mSpinnerImageResizeOption.setAdapter(dataAdapter);\n        mSpinnerImageResizeOption.setOnItemSelectedListener(new OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parentView, View selectedItemView,\n                    int position, long id) {\n                ImageResizeOption newOption = ImageResizeOption.valueOf(mSpinnerImageResizeOption\n                        .getSelectedItemPosition());\n                try {\n                    ImageResizeOption oldOption = mConfig.getImageResizeOption();\n                    if (!oldOption.equals(newOption)) {\n                        mConfig.setImageResizeOption(newOption);\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"onClick ImageResizeOption\".concat(newOption.toString()));\n\n                        }\n                    }\n                } catch (RcsServiceException e) {\n                    showException(e);\n                }\n\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parentView) {\n            }\n        });\n\n        mCheckBoxIsAutoAccept = (CheckBox) findViewById(R.id.ft_isAutoAccept);\n        mCheckBoxIsAutoAccept.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Boolean autoAccept = mCheckBoxIsAutoAccept.isChecked();\n                try {\n                    mConfig.setAutoAccept(autoAccept);\n                    TableRow tableRow = (TableRow) findViewById(R.id.isAutoAcceptInRoaming);\n                    if (autoAccept) {\n                        tableRow.setVisibility(View.VISIBLE);\n                        mCheckBoxIsAutoAcceptInRoaming.setChecked(mConfig\n                                .isAutoAcceptInRoamingEnabled());\n                    } else {\n                        tableRow.setVisibility(View.GONE);\n                    }\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"onClick isAutoAccept \".concat(autoAccept.toString()));\n                    }\n                } catch (RcsServiceException e) {\n                    showException(e);\n                }\n\n            }\n\n        });\n\n        mCheckBoxIsAutoAcceptInRoaming = (CheckBox) findViewById(R.id.ft_isAutoAcceptInRoaming);\n        mCheckBoxIsAutoAcceptInRoaming.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Boolean autoAcceptInRoaming = mCheckBoxIsAutoAcceptInRoaming.isChecked();\n                try {\n                    mConfig.setAutoAcceptInRoaming(autoAcceptInRoaming);\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"onClick isAutoAcceptInRoaming \".concat(autoAcceptInRoaming\n                                .toString()));\n                    }\n                } catch (RcsServiceException e) {\n                    showException(e);\n                }\n\n            }\n\n        });\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        try {\n            displayFileTransferServiceConfig();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void displayFileTransferServiceConfig() throws RcsServiceException {\n        Locale local = Locale.getDefault();\n        TextView textView = (TextView) findViewById(R.id.ft_WarnSize);\n        textView.setText(String.format(local, \"%d\", mConfig.getWarnSize()));\n\n        textView = (TextView) findViewById(R.id.ft_MaxSize);\n        textView.setText(String.format(local, \"%d\", mConfig.getMaxSize()));\n\n        textView = (TextView) findViewById(R.id.MaxAudioDuration);\n        textView.setText(String.format(local, \"%d\", mConfig.getMaxAudioMessageDuration()));\n\n        if (mConfig.isAutoAcceptModeChangeable()) {\n            TableRow tableRow = (TableRow) findViewById(R.id.isAutoAccept);\n            tableRow.setVisibility(View.VISIBLE);\n            boolean autoAcceptEnabled = mConfig.isAutoAcceptEnabled();\n            mCheckBoxIsAutoAccept.setChecked(autoAcceptEnabled);\n            tableRow = (TableRow) findViewById(R.id.isAutoAcceptInRoaming);\n            if (autoAcceptEnabled) {\n                tableRow.setVisibility(View.VISIBLE);\n                mCheckBoxIsAutoAcceptInRoaming.setChecked(mConfig.isAutoAcceptInRoamingEnabled());\n            } else {\n                tableRow.setVisibility(View.GONE);\n            }\n        } else {\n            TableRow tableRow = (TableRow) findViewById(R.id.isAutoAccept);\n            tableRow.setVisibility(View.GONE);\n            tableRow = (TableRow) findViewById(R.id.isAutoAcceptInRoaming);\n            tableRow.setVisibility(View.GONE);\n        }\n\n        textView = (TextView) findViewById(R.id.MaxFileTransfers);\n        textView.setText(String.format(local, \"%d\", mConfig.getMaxFileTransfers()));\n\n        CheckBox checkBox = (CheckBox) findViewById(R.id.GroupFileTransferSupported); // TODO\n        checkBox.setChecked(true);\n\n        mSpinnerImageResizeOption.setSelection(mConfig.getImageResizeOption().toInt());\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/InitiateFileTransfer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport static com.gsma.rcs.ri.utils.FileUtils.takePersistableContentUriPermission;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.text.format.DateUtils;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.ProgressBar;\nimport android.widget.Spinner;\nimport android.widget.TableRow;\nimport android.widget.TextView;\n\nimport java.util.Set;\n\n/**\n * Initiate file transfer\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class InitiateFileTransfer extends RcsActivity {\n\n    private final static int RC_SELECT_IMAGE = 0;\n    private final static int RC_SELECT_TEXT_FILE = 1;\n    private final static int RC_SELECT_AUDIO = 2;\n    private final static int RC_RECORD_AUDIO = 3;\n\n    private static final String BUNDLE_FTDAO_ID = \"ftdao\";\n\n    private static final String LOGTAG = LogUtils.getTag(InitiateFileTransfer.class.getName());\n\n    /**\n     * UI handler\n     */\n    private final Handler mHandler = new Handler();\n    private String mFilename;\n    private Uri mFile;\n    private long mFilesize = -1;\n    private FileTransfer mFileTransfer;\n    private String mFileTransferId;\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n    private Button mResumeBtn;\n    private Button mPauseBtn;\n    private Button mInviteBtn;\n    private Button mSelectBtn;\n    private OneToOneFileTransferListener mFileTransferListener;\n    private FileTransferService mFileTransferService;\n    private TextView mUriTextView;\n    private TextView mSizeTextView;\n    private CheckBox mIconCheckBox;\n    private CheckBox mAudioMessageCheckBox;\n    private TextView mStatusView;\n    private ProgressBar mProgressBar;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        Intent intent = getIntent();\n        boolean resuming = FileTransferIntent.ACTION_RESUME.equals(intent.getAction());\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.filetransfer_initiate);\n        intitialize();\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.FILE_TRANSFER);\n        mFileTransferService = getFileTransferApi();\n        try {\n            mFileTransferService.addEventListener(mFileTransferListener);\n            if (resuming) {\n                /* Get resuming info */\n                FileTransferDAO ftdao = (FileTransferDAO) (intent.getExtras()\n                        .getSerializable(BUNDLE_FTDAO_ID));\n                if (ftdao == null) {\n                    if (LogUtils.isActive) {\n                        Log.e(LOGTAG, \"onCreate cannot read File Transfer resuming info\");\n                    }\n                    finish();\n                    return;\n                }\n                ContactId remoteContact = ftdao.getContact();\n                mFileTransferId = ftdao.getTransferId();\n                mFilename = ftdao.getFilename();\n                mFilesize = ftdao.getSize();\n                ArrayAdapter<String> adapter = new ArrayAdapter<>(this,\n                        android.R.layout.simple_spinner_item, new String[] {\n                            remoteContact.toString()\n                        });\n                mSpinner.setAdapter(adapter);\n                mSizeTextView.setText(FileUtils.humanReadableByteCount(mFilesize, true));\n                mUriTextView.setText(mFilename);\n                /* Check if session still exists */\n                if (mFileTransferService.getFileTransfer(mFileTransferId) == null) {\n                    /* Session not found or expired */\n                    showMessageThenExit(R.string.label_transfer_session_has_expired);\n                    return;\n                }\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onCreate (file=\" + mFilename + \") (size=\" + mFilesize\n                            + \") (contact=\" + remoteContact + \")\");\n                }\n            } else {\n                mSpinner.setAdapter(ContactListAdapter.createRcsContactListAdapter(this));\n                /* Enable button if contact available */\n                if (mSpinner.getAdapter().getCount() != 0) {\n                    mSelectBtn.setEnabled(true);\n                }\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onCreate\");\n                }\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onDestroy\");\n        }\n        super.onDestroy();\n        if (mFileTransferService != null && isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            // Remove file transfer listener\n            try {\n                mFileTransferService.removeEventListener(mFileTransferListener);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    private void initiateTransfer(ContactId remote) {\n        /* Get thumbnail option */\n        boolean tryToSendFileicon = mIconCheckBox.isChecked();\n        String mimeType = getContentResolver().getType(mFile);\n        if (tryToSendFileicon && mimeType != null && !mimeType.startsWith(\"image\")) {\n            tryToSendFileicon = false;\n        }\n        try {\n            FileTransfer.Disposition dispo = (mAudioMessageCheckBox.isChecked()) ? FileTransfer.Disposition.RENDER\n                    : FileTransfer.Disposition.ATTACH;\n            /* Only take persistable permission for content Uris */\n            takePersistableContentUriPermission(this, mFile);\n            /* Initiate transfer */\n            mFileTransfer = mFileTransferService.transferFile(remote, mFile, dispo,\n                    tryToSendFileicon);\n            if (mFileTransfer != null) {\n                mFileTransferId = mFileTransfer.getTransferId();\n            } else {\n                Log.e(LOGTAG, \"Cannot initiate transfer: ID not found\");\n                return;\n            }\n            /* Disable UI */\n            mSpinner.setEnabled(false);\n            /* Hide buttons */\n            mInviteBtn.setVisibility(View.INVISIBLE);\n            mSelectBtn.setVisibility(View.INVISIBLE);\n            mIconCheckBox.setEnabled(false);\n            mAudioMessageCheckBox.setEnabled(false);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    /**\n     * Display a alert dialog to select the kind of file to transfer\n     */\n    private void selectDocument() {\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.label_select_file);\n        builder.setCancelable(true);\n        builder.setItems(R.array.select_filetotransfer, new DialogInterface.OnClickListener() {\n\n            @Override\n            public void onClick(DialogInterface dialog, int which) {\n                if (RC_SELECT_IMAGE == which) {\n                    FileUtils.openFile(InitiateFileTransfer.this, \"image/*\", RC_SELECT_IMAGE);\n                    return;\n                }\n                if (RC_SELECT_TEXT_FILE == which) {\n                    FileUtils\n                            .openFile(InitiateFileTransfer.this, \"text/plain\", RC_SELECT_TEXT_FILE);\n                    return;\n                }\n                FileUtils.openFile(InitiateFileTransfer.this, \"audio/*\", RC_SELECT_AUDIO);\n            }\n        });\n\n        registerDialog(builder.show());\n    }\n\n    private void displaySelectedFileInfo() {\n        /*\n         * Display file info and the selected filename attribute.\n         */\n        mFilename = FileUtils.getFileName(this, mFile);\n        mFilesize = FileUtils.getFileSize(this, mFile);\n        mSizeTextView.setText(FileUtils.humanReadableByteCount(mFilesize, true));\n        mUriTextView.setText(mFilename);\n        if (LogUtils.isActive) {\n            Log.i(LOGTAG, \"Select file \" + mFilename + \" of size \" + mFilesize);\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK || data == null) {\n            return;\n        }\n        switch (requestCode) {\n            case RC_SELECT_IMAGE:\n            case RC_SELECT_TEXT_FILE:\n            case RC_SELECT_AUDIO:\n                if (data.getData() == null) {\n                    return;\n                }\n                mFile = data.getData();\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Selected file uri:\".concat(mFile.toString()));\n                }\n                displaySelectedFileInfo();\n                mInviteBtn.setEnabled(true);\n                if (RC_SELECT_AUDIO == requestCode) {\n                    mAudioMessageCheckBox.setEnabled(true);\n                    mIconCheckBox.setEnabled(false);\n                    mIconCheckBox.setChecked(false);\n                } else {\n                    mIconCheckBox.setEnabled(true);\n                    mAudioMessageCheckBox.setChecked(false);\n                    mAudioMessageCheckBox.setEnabled(false);\n                }\n                break;\n\n            case RC_RECORD_AUDIO:\n                mFile = data.getData();\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Created audio file:\" + mFile);\n                }\n                displaySelectedFileInfo();\n                mInviteBtn.setEnabled(true);\n                mAudioMessageCheckBox.setEnabled(true);\n                mIconCheckBox.setEnabled(false);\n                mIconCheckBox.setChecked(false);\n                break;\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n        double position = ((double) currentSize / (double) totalSize) * 100.0;\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"quitSession\");\n        }\n        try {\n            if (mFileTransfer != null\n                    && RcsSessionUtil.isAllowedToAbortFileTransferSession(mFileTransfer)) {\n                mFileTransfer.abortTransfer();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mFileTransfer = null;\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        try {\n            if (KeyEvent.KEYCODE_BACK == keyCode) {\n                if (mFileTransfer == null\n                        || !RcsSessionUtil.isAllowedToAbortFileTransferSession(mFileTransfer)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                                /* Exit activity */\n                                finish();\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_initiate_ft, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        MenuItem item = menu.findItem(R.id.menu_record_audio);\n        item.setVisible(mFileTransfer == null);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_record_audio:\n                startActivityForResult(new Intent(this, AudioMessageRecordActivity.class),\n                        RC_RECORD_AUDIO);\n                break;\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void displayFileExpiration(long fileExpiration) {\n        if (FileTransferLog.UNKNOWN_EXPIRATION == fileExpiration) {\n            return;\n        }\n        TableRow expirationTableRow = (TableRow) findViewById(R.id.expiration);\n        expirationTableRow.setVisibility(View.VISIBLE);\n        TextView expirationView = (TextView) findViewById(R.id.value_expiration);\n        CharSequence expirationDate = DateUtils.getRelativeTimeSpanString(fileExpiration,\n                System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS,\n                DateUtils.FORMAT_ABBREV_RELATIVE);\n        expirationView.setText(expirationDate);\n    }\n\n    private void intitialize() {\n        OnClickListener btnInviteListener = new OnClickListener() {\n            public void onClick(View v) {\n                ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n                String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n                final ContactId remote = ContactUtil.formatContact(phoneNumber);\n\n                long warnSize;\n                try {\n                    warnSize = mFileTransferService.getConfiguration().getWarnSize();\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                    return;\n                }\n                if ((warnSize > 0) && (mFilesize >= warnSize)) {\n                    // Display a warning message\n                    AlertDialog.Builder builder = new AlertDialog.Builder(InitiateFileTransfer.this);\n                    builder.setMessage(getString(R.string.label_sharing_warn_size, mFilesize));\n                    builder.setCancelable(false);\n                    builder.setPositiveButton(R.string.label_yes,\n                            new DialogInterface.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int position) {\n                                    initiateTransfer(remote);\n                                }\n                            });\n                    builder.setNegativeButton(R.string.label_no, null);\n                    registerDialog(builder.show());\n\n                } else {\n                    initiateTransfer(remote);\n                }\n            }\n        };\n        OnClickListener btnSelectListener = new OnClickListener() {\n            public void onClick(View v) {\n                selectDocument();\n            }\n        };\n        OnClickListener btnPauseListener = new OnClickListener() {\n            public void onClick(View v) {\n                try {\n                    if (mFileTransfer.isAllowedToPauseTransfer()) {\n                        mFileTransfer.pauseTransfer();\n                    } else {\n                        mPauseBtn.setEnabled(false);\n                        showMessage(R.string.label_pause_ft_not_allowed);\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        OnClickListener btnResumeListener = new OnClickListener() {\n            public void onClick(View v) {\n                try {\n                    if (mFileTransfer.isAllowedToResumeTransfer()) {\n                        mFileTransfer.resumeTransfer();\n\n                    } else {\n                        mResumeBtn.setEnabled(false);\n                        showMessage(R.string.label_resume_ft_not_allowed);\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        /* Set contact selector */\n        mSpinner = (Spinner) findViewById(R.id.contact);\n\n        /* Set buttons callback */\n        mInviteBtn = (Button) findViewById(R.id.invite_btn);\n        mInviteBtn.setOnClickListener(btnInviteListener);\n        mInviteBtn.setEnabled(false);\n        mSelectBtn = (Button) findViewById(R.id.select_btn);\n        mSelectBtn.setOnClickListener(btnSelectListener);\n        mSelectBtn.setEnabled(false);\n\n        mPauseBtn = (Button) findViewById(R.id.pause_btn);\n        mPauseBtn.setOnClickListener(btnPauseListener);\n        mPauseBtn.setEnabled(false);\n\n        mResumeBtn = (Button) findViewById(R.id.resume_btn);\n        mResumeBtn.setOnClickListener(btnResumeListener);\n        mResumeBtn.setEnabled(false);\n\n        mUriTextView = (TextView) findViewById(R.id.uri);\n        mUriTextView.setText(\"\");\n        mSizeTextView = (TextView) findViewById(R.id.size);\n        mSizeTextView.setText(\"\");\n\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mStatusView.setText(\"\");\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n\n        mIconCheckBox = (CheckBox) findViewById(R.id.ft_thumb);\n\n        mAudioMessageCheckBox = (CheckBox) findViewById(R.id.send_audio_msg);\n\n        TableRow expiration = (TableRow) findViewById(R.id.expiration);\n        expiration.setVisibility(View.GONE);\n\n        mFileTransferListener = new OneToOneFileTransferListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String transferId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current transferId */\n                if (InitiateFileTransfer.this.mFileTransferId == null\n                        || !InitiateFileTransfer.this.mFileTransferId.equals(transferId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(ContactId contact, String transferId,\n                    final FileTransfer.State state, final FileTransfer.ReasonCode reasonCode) {\n                /* Discard event if not for current transferId */\n                if (InitiateFileTransfer.this.mFileTransferId == null\n                        || !InitiateFileTransfer.this.mFileTransferId.equals(transferId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sFileTransferReasonCodes[reasonCode\n                        .toInt()];\n                final String _state = RiApplication.sFileTransferStates[state.toInt()];\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" transferId=\" + transferId\n                            + \" state=\" + _state + \" reason=\" + _reasonCode);\n                }\n                mHandler.post(new Runnable() {\n\n                    public void run() {\n                        if (mFileTransfer != null) {\n                            try {\n                                mResumeBtn.setEnabled(mFileTransfer.isAllowedToResumeTransfer());\n\n                            } catch (RcsServiceException e) {\n                                mResumeBtn.setEnabled(false);\n                                showException(e);\n                            }\n                            try {\n                                mPauseBtn.setEnabled(mFileTransfer.isAllowedToPauseTransfer());\n\n                            } catch (RcsServiceException e) {\n                                mPauseBtn.setEnabled(false);\n                                showException(e);\n                            }\n                        }\n                        switch (state) {\n                            case STARTED:\n                                /* Display session status */\n                                mStatusView.setText(_state);\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_transfer_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_transfer_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_transfer_failed,\n                                        _reasonCode));\n                                break;\n\n                            case TRANSFERRED:\n                                /* Display transfer progress */\n                                mStatusView.setText(_state);\n\n                                try {\n                                    displayFileExpiration(mFileTransfer.getFileExpiration());\n                                    Uri fileIconUri = mFileTransfer.getFileIcon();\n                                    long fileIconExpiration = mFileTransfer.getFileIconExpiration();\n                                    if (LogUtils.isActive) {\n                                        Log.d(LOGTAG, \"File transferred icon uri= \" + fileIconUri\n                                                + \" expiration=\" + fileIconExpiration);\n                                    }\n                                } catch (RcsServiceException e) {\n                                    showException(e);\n                                }\n                                break;\n\n                            default:\n                                mStatusView.setText(_state);\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG, \"onStateChanged \".concat(getString(\n                                            R.string.label_ft_state_changed, _state, _reasonCode)));\n                                }\n                        }\n                    }\n\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" transferIds=\" + transferIds);\n                }\n            }\n        };\n    }\n\n    /**\n     * Forge intent to resume Originating File Transfer\n     * \n     * @param ctx The context\n     * @param ftDao The FileTransfer DAO\n     * @param resume intent\n     * @return intent\n     */\n    public static Intent forgeResumeIntent(Context ctx, FileTransferDAO ftDao, Intent resume) {\n        resume.setClass(ctx, InitiateFileTransfer.class);\n        resume.addFlags(Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_ACTIVITY_NEW_TASK);\n        /* Save FileTransferDAO into intent */\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(BUNDLE_FTDAO_ID, ftDao);\n        resume.putExtras(bundle);\n        return resume;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/ReceiveFileTransfer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.GroupFileTransferListener;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.messaging.chat.group.GroupChatDAO;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.GroupFileTransferListener;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.os.StatFs;\nimport android.provider.MediaStore;\nimport android.text.format.DateUtils;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport java.io.IOException;\nimport java.util.Set;\n\n/**\n * Received file transfer\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class ReceiveFileTransfer extends RcsActivity {\n\n    private static final String LOGTAG = LogUtils.getTag(ReceiveFileTransfer.class.getSimpleName());\n    private static final String VCARD_MIME_TYPE = \"text/x-vcard\";\n    private static final String BUNDLE_FTDAO_ID = \"ftdao\";\n\n    /**\n     * UI mHandler\n     */\n    private final Handler mHandler = new Handler();\n    private FileTransfer mFileTransfer;\n    private FileTransferDAO mFtDao;\n    private boolean mGroupFileTransfer = false;\n    private String mTransferId;\n    private Button mPauseBtn;\n    private Button mResumeBtn;\n    private OnClickListener mDeclineBtnListener;\n    private OnClickListener mAcceptBtnListener;\n    private OneToOneFileTransferListener mFileTransferListener;\n    private GroupFileTransferListener mGroupFtListener;\n    private FileTransferService mFileTransferService;\n    private ProgressBar mProgressBar;\n    private TextView mStatusView;\n    private TextView mSizeTextView;\n    private TextView mFilenameTextView;\n    private TextView mExpirationTextView;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.filetransfer_receive);\n        initialize();\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER, RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n        } else {\n            startMonitorServices(RcsServiceName.FILE_TRANSFER, RcsServiceName.CONTACT);\n            mFileTransferService = getFileTransferApi();\n            if (!processIntent(getIntent(), false)) {\n                return;\n            }\n            try {\n                if (mGroupFileTransfer) {\n                    mFileTransferService.addEventListener(mGroupFtListener);\n                } else {\n                    mFileTransferService.addEventListener(mFileTransferListener);\n                }\n            } catch (RcsServiceException e) {\n                showExceptionThenExit(e);\n            }\n        }\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        processIntent(intent, true);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        if (mFileTransferService != null && isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            /* Remove service listener */\n            try {\n                if (mGroupFileTransfer) {\n                    mFileTransferService.removeEventListener(mGroupFtListener);\n                } else {\n                    mFileTransferService.removeEventListener(mFileTransferListener);\n                }\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    boolean processIntent(Intent intent, boolean newIntent) {\n        mFtDao = intent.getExtras().getParcelable(BUNDLE_FTDAO_ID);\n        if (mFtDao == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"processIntent cannot read File Transfer invitation (newIntent=\"\n                        + newIntent + \")\");\n            }\n            finish();\n            return false;\n        }\n        /* Get the file transfer session */\n        mTransferId = mFtDao.getTransferId();\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"processIntent (newIntent=\" + newIntent + \") \" + mFtDao);\n        }\n        ContactId contact = mFtDao.getContact();\n        /* Get invitation info */\n        boolean resuming = FileTransferIntent.ACTION_RESUME.equals(intent.getAction());\n        mGroupFileTransfer = GroupChatDAO.isGroupChat(mFtDao.getChatId(), contact);\n\n        String from = RcsContactUtil.getInstance(this).getDisplayName(contact);\n        TextView fromTextView = (TextView) findViewById(R.id.from);\n        fromTextView.setText(getString(R.string.label_from_args, from));\n\n        String size = getString(R.string.label_file_size,\n                FileUtils.humanReadableByteCount(mFtDao.getSize(), true));\n        mSizeTextView.setText(size);\n        mFilenameTextView.setText(getString(R.string.label_filename, mFtDao.getFilename()));\n\n        long fileExpiration = mFtDao.getFileExpiration();\n        if (fileExpiration != FileTransferLog.UNKNOWN_EXPIRATION) {\n            CharSequence expiration = DateUtils.getRelativeTimeSpanString(\n                    mFtDao.getFileExpiration(), System.currentTimeMillis(),\n                    DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);\n            mExpirationTextView.setText(getString(R.string.label_expiration_args, expiration));\n        } else {\n            mExpirationTextView.setVisibility(View.GONE);\n        }\n        try {\n            mFileTransfer = mFileTransferService.getFileTransfer(mTransferId);\n            if (mFileTransfer == null) {\n                if (FileTransfer.State.TRANSFERRED == mFtDao.getState()) {\n                    displayTransferredFile();\n                    return false;\n\n                } else {\n                    String reasonCode = RiApplication.sFileTransferReasonCodes[mFtDao\n                            .getReasonCode().toInt()];\n                    if (LogUtils.isActive) {\n                        Log.e(LOGTAG,\n                                \"Transfer ID=\" + mTransferId + \" failed state=\" + mFtDao.getState()\n                                        + \" reason=\" + reasonCode);\n                    }\n                    showMessageThenExit(getString(R.string.label_transfer_failed, reasonCode));\n                    return false;\n\n                }\n\n            }\n            /* Do not consider acceptance if resuming */\n            if (resuming) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"processIntent resuming \".concat(mTransferId));\n                }\n                return true;\n            }\n            FileTransfer.State state = mFileTransfer.getState();\n            /* Check if not already accepted by the stack */\n            if (FileTransfer.State.INVITED != state) {\n                /* File Transfer is auto accepted by the stack. Check capacity */\n                isCapacityOk(mFtDao.getSize());\n\n                if (FileTransfer.State.TRANSFERRED == state) {\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"processIntent file is transferred \".concat(mTransferId));\n                    }\n                    displayTransferredFile();\n                    return false;\n                }\n\n            } else {\n                /* File Transfer must be accepted/rejected by user */\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Wait for user acceptance (transferId=\" + mTransferId + \")\");\n                }\n                // @formatter:off\n\n                // The following code is intentionally commented to test the\n                // CORE.\n                // UI should check the file size to cancel if it is too big.\n                // if (isCapacityOk(fileSize) == false) {\n                // rejectInvitation();\n                // return;\n                // }\n\n                // @formatter:on\n\n                /* Manual accept */\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                View titleView = getLayoutInflater().inflate(R.layout.filetransfer_custom_title,\n                        null);\n                builder.setCustomTitle(titleView);\n                builder.setMessage(getString(R.string.label_ft_from_size, from,\n                        FileUtils.humanReadableByteCount(mFtDao.getSize(), true)));\n                builder.setCancelable(false);\n                /* Make sure progress bar is at the beginning */\n                mProgressBar.setProgress(0);\n                ImageView iconView = (ImageView) titleView\n                        .findViewById(R.id.filetransfer_alert_title_icon);\n                if (mFtDao.getThumbnail() != null) {\n                    try {\n                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),\n                                mFtDao.getThumbnail());\n                        iconView.setImageBitmap(bitmap);\n\n                    } catch (IOException e) {\n                        showException(e);\n                    }\n                } else {\n                    if (VCARD_MIME_TYPE.equals(mFtDao.getMimeType())) {\n                        iconView.setImageResource(R.drawable.ri_contact_card_icon);\n                    } else {\n                        iconView.setImageResource(R.drawable.ri_notif_file_transfer_icon);\n                    }\n                }\n                builder.setPositiveButton(R.string.label_accept, mAcceptBtnListener);\n                builder.setNegativeButton(R.string.label_decline, mDeclineBtnListener);\n                registerDialog(builder.show());\n            }\n            return true;\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n        return false;\n    }\n\n    private void acceptInvitation() {\n        try {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Accept invitation (transferId=\" + mTransferId + \")\");\n            }\n            mFileTransfer.acceptInvitation();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void rejectInvitation() {\n        try {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Reject invitation (transferId=\" + mTransferId + \")\");\n            }\n            mFileTransfer.rejectInvitation();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n        double position = ((double) currentSize / (double) totalSize) * 100.0;\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mFileTransfer != null\n                    && RcsSessionUtil.isAllowedToAbortFileTransferSession(mFileTransfer)) {\n                mFileTransfer.abortTransfer();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mFileTransfer = null;\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        try {\n            if (KeyEvent.KEYCODE_BACK == keyCode) {\n                if (mFileTransfer == null\n                        || !RcsSessionUtil.isAllowedToAbortFileTransferSession(mFileTransfer)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                                /* Exit activity */\n                                finish();\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_ft, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    /**\n     * Check whether file size exceeds the limit\n     * \n     * @param size Size of file\n     * @return {@code true} if file size limit is exceeded, otherwise {@code false}\n     */\n    private boolean isFileSizeExceeded(long size) {\n        try {\n            long maxSize = mFileTransferService.getConfiguration().getMaxSize();\n            return (maxSize > 0 && size > maxSize);\n\n        } catch (RcsServiceException e) {\n            showException(e);\n            return false;\n        }\n    }\n\n    /**\n     * Get available space in external storage, only if external storage is ready to write\n     * \n     * @return Available space in bytes, otherwise <code>-1</code>\n     */\n    @SuppressWarnings(\"deprecation\")\n    private static long getExternalStorageFreeSpace() {\n        long freeSpace = -1;\n        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {\n            StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());\n            long blockSize = stat.getBlockSize();\n            long availableBlocks = stat.getAvailableBlocks();\n            freeSpace = blockSize * availableBlocks;\n        }\n        return freeSpace;\n    }\n\n    private enum FileCapacity {\n        OK, FILE_TOO_BIG, STORAGE_TOO_SMALL\n    }\n\n    /**\n     * Check if file capacity is acceptable\n     * \n     * @param fileSize file size in bytes\n     * @return FileSharingError or null if file capacity is acceptable\n     */\n    private FileCapacity isFileCapacityAcceptable(long fileSize) {\n        if (isFileSizeExceeded(fileSize)) {\n            return FileCapacity.FILE_TOO_BIG;\n        }\n        long freeSpage = getExternalStorageFreeSpace();\n        boolean storageIsTooSmall = (freeSpage > 0) && fileSize > freeSpage;\n        if (storageIsTooSmall) {\n            return FileCapacity.STORAGE_TOO_SMALL;\n        }\n        return FileCapacity.OK;\n    }\n\n    /**\n     * Check if file size is less than maximum or then free space on disk\n     * \n     * @param fileSize file size in bytes\n     * @return boolean\n     */\n    private boolean isCapacityOk(long fileSize) {\n        FileCapacity capacity = isFileCapacityAcceptable(fileSize);\n        switch (capacity) {\n            case FILE_TOO_BIG:\n                showMessageThenExit(R.string.label_transfer_failed_too_big);\n                return false;\n\n            case STORAGE_TOO_SMALL:\n                showMessageThenExit(R.string.label_transfer_failed_capacity_too_small);\n                return false;\n\n            default:\n                return true;\n        }\n    }\n\n    /**\n     * Update UI on file transfer state change\n     * \n     * @param transferId transfer ID\n     * @param state new FT state\n     * @param reasonCode reason code\n     */\n    private void onTransferStateChangedUpdateUI(String transferId, final FileTransfer.State state,\n            final FileTransfer.ReasonCode reasonCode) {\n        final String _reasonCode = RiApplication.sFileTransferReasonCodes[reasonCode.toInt()];\n        final String _state = RiApplication.sFileTransferStates[state.toInt()];\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"TransferStateChanged transferId=\" + transferId + \" state=\" + state\n                    + \" reason=\" + reasonCode);\n        }\n        mHandler.post(new Runnable() {\n\n            public void run() {\n                if (mFileTransfer != null) {\n                    try {\n                        mResumeBtn.setEnabled(mFileTransfer.isAllowedToResumeTransfer());\n                    } catch (RcsServiceException e) {\n                        mResumeBtn.setEnabled(false);\n                        showException(e);\n                    }\n                    try {\n                        mPauseBtn.setEnabled(mFileTransfer.isAllowedToPauseTransfer());\n                    } catch (RcsServiceException e) {\n                        mPauseBtn.setEnabled(false);\n                        showException(e);\n                    }\n                }\n                switch (state) {\n                    case ABORTED:\n                        showMessageThenExit(getString(R.string.label_transfer_aborted, _reasonCode));\n                        break;\n\n                    case FAILED:\n                        showMessageThenExit(getString(R.string.label_transfer_failed, _reasonCode));\n                        break;\n\n                    case REJECTED:\n                        showMessageThenExit(getString(R.string.label_transfer_rejected, _reasonCode));\n                        break;\n\n                    case TRANSFERRED:\n                        displayTransferredFile();\n                        break;\n\n                    default:\n                        mStatusView.setText(_state);\n                }\n            }\n        });\n    }\n\n    private void displayTransferredFile() {\n        mStatusView.setText(RiApplication.sFileTransferStates[FileTransfer.State.TRANSFERRED\n                .toInt()]);\n        /* Make sure progress bar is at the end */\n        mProgressBar.setProgress(mProgressBar.getMax());\n\n        try {\n            mFileTransferService.markFileTransferAsRead(mTransferId);\n        } catch (RcsServiceNotAvailableException ignore) {\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n        String mimeType = mFtDao.getMimeType();\n        if (VCARD_MIME_TYPE.equals(mimeType)) {\n            // Show the transferred vCard\n            Intent intent = new Intent(Intent.ACTION_VIEW);\n            intent.setDataAndType(mFtDao.getFile(), VCARD_MIME_TYPE);\n            startActivity(intent);\n\n        } else if (Utils.isImageType(mimeType)) {\n            /* Show the transferred image */\n            Utils.showPicture(this, mFtDao.getFile());\n\n        } else if (Utils.isAudioType(mimeType)\n                && FileTransfer.Disposition.RENDER == mFtDao.getDisposition()) {\n            Utils.playAudio(this, mFtDao.getFile());\n        }\n    }\n\n    private void onTransferProgressUpdateUI(final long currentSize, final long totalSize) {\n        mHandler.post(new Runnable() {\n            public void run() {\n                updateProgressBar(currentSize, totalSize);\n            }\n        });\n    }\n\n    private void initialize() {\n        mGroupFtListener = new GroupFileTransferListener() {\n\n            @Override\n            public void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n                    GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDeliveryInfoChanged contact=\" + contact + \" transferId=\"\n                            + transferId + \" state=\" + status + \" reason=\" + reasonCode);\n                }\n            }\n\n            @Override\n            public void onProgressUpdate(String chatId, String transferId, long currentSize,\n                    long totalSize) {\n                /* Discard event if not for current transferId */\n                if (!mFtDao.getTransferId().equals(transferId)) {\n                    return;\n                }\n                onTransferProgressUpdateUI(currentSize, totalSize);\n            }\n\n            @Override\n            public void onStateChanged(String chatId, String transferId, FileTransfer.State state,\n                    FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged chatId=\" + chatId + \" transferId=\" + transferId);\n                }\n                /* Discard event if not for current transferId */\n                if (!mFtDao.getTransferId().equals(transferId)) {\n                    return;\n                }\n                onTransferStateChangedUpdateUI(transferId, state, reasonCode);\n            }\n\n            @Override\n            public void onDeleted(String chatId, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted chatId=\" + chatId + \" transferIds=\" + transferIds);\n                }\n            }\n        };\n        mAcceptBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                acceptInvitation();\n            }\n        };\n\n        mDeclineBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                rejectInvitation();\n                /* Exit activity */\n                finish();\n            }\n        };\n\n        View.OnClickListener btnPauseListener = new View.OnClickListener() {\n            @Override\n            public void onClick(View arg0) {\n                try {\n                    if (mFileTransfer.isAllowedToPauseTransfer()) {\n                        mFileTransfer.pauseTransfer();\n                    } else {\n                        mPauseBtn.setEnabled(false);\n                        showMessage(R.string.label_pause_ft_not_allowed);\n                    }\n                } catch (RcsPermissionDeniedException e) {\n                    Utils.displayToast(ReceiveFileTransfer.this,\n                            getString(R.string.label_pause_failed));\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n\n        View.OnClickListener btnResumeListener = new View.OnClickListener() {\n            @Override\n            public void onClick(View arg0) {\n                try {\n                    if (mFileTransfer.isAllowedToResumeTransfer()) {\n                        mFileTransfer.resumeTransfer();\n                    } else {\n                        mResumeBtn.setEnabled(false);\n                        showMessage(R.string.label_resume_ft_not_allowed);\n                    }\n                } catch (RcsPermissionDeniedException e) {\n                    Utils.displayToast(ReceiveFileTransfer.this,\n                            getString(R.string.label_resume_failed));\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        mFileTransferListener = new OneToOneFileTransferListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String transferId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current transferId */\n                if (!mFtDao.getTransferId().equals(transferId)) {\n                    return;\n                }\n                onTransferProgressUpdateUI(currentSize, totalSize);\n            }\n\n            @Override\n            public void onStateChanged(ContactId contact, String transferId,\n                    final FileTransfer.State state, FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" transferId=\" + transferId);\n                }\n                /* Discard event if not for current transferId */\n                if (!mFtDao.getTransferId().equals(transferId)) {\n                    return;\n                }\n                onTransferStateChangedUpdateUI(transferId, state, reasonCode);\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" transferIds=\" + transferIds);\n                }\n            }\n        };\n        /* Set pause and resume button */\n        mPauseBtn = (Button) findViewById(R.id.pause_btn);\n        mPauseBtn.setOnClickListener(btnPauseListener);\n        mPauseBtn.setEnabled(false);\n        mResumeBtn = (Button) findViewById(R.id.resume_btn);\n        mResumeBtn.setOnClickListener(btnResumeListener);\n        mResumeBtn.setEnabled(false);\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mStatusView.setText(\"\");\n        mSizeTextView = (TextView) findViewById(R.id.image_size);\n        mSizeTextView.setText(\"\");\n        mFilenameTextView = (TextView) findViewById(R.id.image_filename);\n        mFilenameTextView.setText(\"\");\n        mExpirationTextView = (TextView) findViewById(R.id.expiration);\n        mExpirationTextView.setText(\"\");\n    }\n\n    /**\n     * Forge invitation intent to start ReceiveFileTransfer activity\n     * \n     * @param ctx The context\n     * @param ftDao The FileTransfer DAO\n     * @param invitation intent\n     * @return intent\n     */\n    public static Intent forgeInvitationIntent(Context ctx, FileTransferDAO ftDao, Intent invitation) {\n        invitation.setClass(ctx, ReceiveFileTransfer.class);\n        invitation.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);\n        /* Save FileTransferDAO into intent */\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(BUNDLE_FTDAO_ID, ftDao);\n        invitation.putExtras(bundle);\n        return invitation;\n    }\n\n    /**\n     * Forge resume intent to start ReceiveFileTransfer activity\n     * \n     * @param ctx The context\n     * @param ftDao The FileTransfer DAO\n     * @param resume intent\n     * @return intent\n     */\n    public static Intent forgeResumeIntent(Context ctx, FileTransferDAO ftDao, Intent resume) {\n        resume.setClass(ctx, ReceiveFileTransfer.class);\n        resume.addFlags(Intent.FLAG_FROM_BACKGROUND | Intent.FLAG_ACTIVITY_NEW_TASK);\n        /* Save FileTransferDAO into intent */\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(BUNDLE_FTDAO_ID, ftDao);\n        resume.putExtras(bundle);\n        return resume;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/TestFileTransferApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport com.gsma.rcs.ri.R;\n\nimport android.app.ListActivity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * File transfer API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestFileTransferApi extends ListActivity {\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        String[] items = {\n                getString(R.string.menu_transfer_file),\n                getString(R.string.menu_file_transfer_config)\n        };\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, InitiateFileTransfer.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, FileTransferServiceConfigActivity.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/UndeliveredFileReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Undelivered message receiver\n * \n * @author YPLO6403\n */\npublic class UndeliveredFileReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, FileTransferIntentService.class);\n        context.startService(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/multi/FileTransferProperties.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer.multi;\n\nimport android.net.Uri;\n\n/**\n * FileTransferProperties\n */\npublic class FileTransferProperties {\n\n    private final Uri mUri;\n    private final String mMimeType;\n    private boolean mFileIcon;\n    private boolean mAudioMessage;\n    private final String mFilename;\n    private final long mSize;\n    private String mStatus;\n    private int mProgress;\n    private String mReasonCode;\n\n    /**\n     * Default constructor\n     *\n     * @param uri the file URI\n     * @param filename the file name\n     * @param size the file size\n     * @param mimeType the mime type\n     */\n    public FileTransferProperties(Uri uri, String filename, long size, String mimeType) {\n        mUri = uri;\n        mFilename = filename;\n        mSize = size;\n        mMimeType = mimeType;\n    }\n\n    /**\n     * Gets the file URI\n     *\n     * @return the file URI\n     */\n    public Uri getUri() {\n        return mUri;\n    }\n\n    /**\n     * Gets the file icon flag\n     *\n     * @return the file icon flag\n     */\n    public boolean isFileicon() {\n        return mFileIcon;\n    }\n\n    /**\n     * Sets file icon flag\n     *\n     * @param fileicon the file icon flag\n     */\n    public void setFileicon(boolean fileicon) {\n        mFileIcon = fileicon;\n    }\n\n    /**\n     * @return the FileName\n     */\n    public String getFilename() {\n        return mFilename;\n    }\n\n    /**\n     * Gets the file transfer status\n     *\n     * @return the Status\n     */\n    public String getStatus() {\n        return mStatus;\n    }\n\n    /**\n     * Sets the file transfer status\n     *\n     * @param status the status\n     */\n    public void setStatus(String status) {\n        mStatus = status;\n    }\n\n    /**\n     * Gets the file transfer progress (in percentage)\n     *\n     * @return the file transfer progress\n     */\n    public int getProgress() {\n        return mProgress;\n    }\n\n    /**\n     * Sets the file transfer progress (in percentage)\n     *\n     * @param progress the file transfer progress\n     */\n    public void setProgress(int progress) {\n        mProgress = progress;\n    }\n\n    /**\n     * Gets the file size\n     *\n     * @return the size\n     */\n    public long getSize() {\n        return mSize;\n    }\n\n    /**\n     * Gets the reason code\n     *\n     * @return the reason code\n     */\n    public String getReasonCode() {\n        return mReasonCode;\n    }\n\n    /**\n     * Sets the reason code\n     *\n     * @param reasonCode the reason code\n     */\n    public void setReasonCode(String reasonCode) {\n        mReasonCode = reasonCode;\n    }\n\n    /**\n     * Gets the mime type\n     *\n     * @return the mime type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    /**\n     * Gets the audio message flag\n     *\n     * @return the audio message flag\n     */\n    public boolean isAudioMessage() {\n        return mAudioMessage;\n    }\n\n    /**\n     * Sets the audio message flag\n     *\n     * @param audioMessage the audio message flag\n     */\n    public void setAudioMessage(boolean audioMessage) {\n        mAudioMessage = audioMessage;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/multi/ISendMultiFile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer.multi;\n\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\n\nimport java.util.List;\n\n/**\n * @author Philippe LEMORDANT\n */\npublic interface ISendMultiFile {\n\n    /**\n     * Initialize\n     */\n    void initialize();\n\n    /**\n     * Transfers list of files\n     * \n     * @param files to transfer\n     * @return boolean\n     */\n    boolean transferFiles(List<FileTransferProperties> files);\n\n    /**\n     * Adds file transfer event listener\n     * \n     * @param fileTransferService file transfer service\n     * @throws RcsServiceException\n     */\n    void addFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException;\n\n    /**\n     * Removes file transfer event listener\n     * \n     * @param fileTransferService file transfer service\n     * @throws RcsServiceException\n     */\n    void removeFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException;\n\n    /**\n     * Checks if it is possible to initiate file transfer to group chat or single contact.\n     * \n     * @param chatId the chat ID or contact ID in single chat\n     * @return True if it is possible to initiate file transfer to group chat or single contact.\n     * @throws RcsServiceException\n     */\n    boolean checkPermissionToSendFile(String chatId) throws RcsServiceException;\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/multi/SendMultiFile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer.multi;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnCancelListener;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.ListView;\nimport android.widget.ProgressBar;\nimport android.widget.TableRow;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * SendMultiFile\n * \n * @author Philippe LEMORDANT\n */\npublic abstract class SendMultiFile extends RcsActivity implements ISendMultiFile {\n\n    private static final String LOGTAG = LogUtils.getTag(SendMultiFile.class.getSimpleName());\n\n    private final static String EXTRA_CHAT_ID = \"chat_id\";\n\n    protected String mChatId;\n    /**\n     * UI Handler\n     */\n    protected final Handler mHandler = new Handler();\n    /**\n     * The list of file transfer IDs\n     */\n    protected List<String> mTransferIds;\n    /**\n     * The list of files to transfer\n     */\n    protected List<FileTransferProperties> mFiles;\n    /**\n     * A flag to only add listener once and to remove only if previously added\n     */\n    protected boolean mFileTransferListenerAdded = false;\n    protected Set<FileTransfer> mFileTransfers;\n    private ProgressDialog mProgressDialog;\n    protected FileTransferAdapter mFileTransferAdapter;\n    protected FileTransferService mFileTransferService;\n    private boolean mInvited;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        initialize();\n        mTransferIds = new ArrayList<>();\n        if (!parseIntent(getIntent())) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onCreate invalid intent\");\n            }\n            finish();\n            return;\n        }\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.filetransfer_send_multi_file);\n        ListView listView = (ListView) findViewById(android.R.id.list);\n        mFileTransferAdapter = new FileTransferAdapter(this,\n                R.layout.filetransfer_send_multi_file_item,\n                mFiles.toArray(new FileTransferProperties[mFiles.size()]));\n        listView.setAdapter(mFileTransferAdapter);\n        mFileTransfers = new HashSet<>();\n        /* Set start button */\n        Button startButton = (Button) findViewById(R.id.ft_start_btn);\n        startButton.setVisibility(View.GONE);\n        startButton.setOnClickListener(new OnClickListener() {\n            public void onClick(View v) {\n                // TODO check warn size\n                initiateTransfer();\n            }\n        });\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CHAT, RcsServiceName.FILE_TRANSFER,\n                RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n\n        } else {\n            startMonitorServices(RcsServiceName.CHAT, RcsServiceName.FILE_TRANSFER,\n                    RcsServiceName.CONTACT);\n            mFileTransferService = getFileTransferApi();\n            try {\n                Boolean authorized = checkPermissionToSendFile(mChatId);\n                if (authorized) {\n                    startButton.setVisibility(View.VISIBLE);\n                    addFileTransferEventListener(mFileTransferService);\n\n                } else {\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"Not allowed to transfer file to \".concat(mChatId));\n                    }\n                    startButton.setVisibility(View.INVISIBLE);\n                    showMessage(R.string.label_ft_not_allowed);\n                }\n            } catch (RcsServiceException e) {\n                showExceptionThenExit(e);\n            }\n        }\n    }\n\n    private boolean parseIntent(Intent intent) {\n        mChatId = intent.getStringExtra(EXTRA_CHAT_ID);\n        String action = intent.getAction();\n        // Here we get data from the event.\n        if (Intent.ACTION_SEND.equals(action)) {\n            mFiles = new ArrayList<>();\n            // Handle normal one file or text sharing.\n            Uri uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);\n            String fileName = FileUtils.getFileName(this, uri);\n            long fileSize = FileUtils.getFileSize(this, uri);\n            String mimeType = FileUtils.getMimeType(this, uri);\n            mFiles.add(new FileTransferProperties(uri, fileName, fileSize, mimeType));\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Transfer single file \" + fileName + \" (size=\" + fileSize + \")\");\n            }\n            return true;\n        }\n        if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {\n            // Handle multiple file sharing.\n            ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);\n            if (uris != null) {\n                mFiles = new ArrayList<>();\n                StringBuilder files = new StringBuilder(\"Transfer multiple files [\");\n                String loopDelim = \"\";\n                for (Uri uri : uris) {\n                    String fileName = FileUtils.getFileName(this, uri);\n                    long fileSize = FileUtils.getFileSize(this, uri);\n                    String mimeType = FileUtils.getMimeType(this, uri);\n                    mFiles.add(new FileTransferProperties(uri, fileName, fileSize, mimeType));\n                    files.append(loopDelim);\n                    files.append(fileName);\n                    files.append(\"(\");\n                    files.append(fileSize);\n                    files.append(\")\");\n                    loopDelim = \",\";\n                }\n                files.append(\"]\");\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, files.toString());\n                }\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            try {\n                removeFileTransferEventListener(mFileTransferService);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    private void initiateTransfer() {\n        if (transferFiles(mFiles)) {\n            mProgressDialog = showProgressDialog(getString(R.string.label_command_in_progress));\n            mProgressDialog.setOnCancelListener(new OnCancelListener() {\n                public void onCancel(DialogInterface dialog) {\n                    hideProgressDialog();\n                    if (!isThereAnyOnGoingSession()) {\n                        finish();\n                    }\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"onKeyDown abort on going sessions\");\n                    }\n                    AlertDialog.Builder builder = new AlertDialog.Builder(SendMultiFile.this);\n                    builder.setTitle(R.string.label_confirm_close);\n                    builder.setPositiveButton(R.string.label_ok,\n                            new DialogInterface.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int which) {\n                                    Toast.makeText(SendMultiFile.this,\n                                            getString(R.string.label_transfer_cancelled),\n                                            Toast.LENGTH_SHORT).show();\n                                    quitSession();\n                                }\n                            });\n                    builder.setNegativeButton(R.string.label_cancel,\n                            new DialogInterface.OnClickListener() {\n                                public void onClick(DialogInterface dialog, int which) {\n                                    /* Exit activity */\n                                    finish();\n                                }\n                            });\n                    builder.setCancelable(true);\n                    registerDialog(builder.show());\n                }\n            });\n            /* Hide start button */\n            Button inviteBtn = (Button) findViewById(R.id.ft_start_btn);\n            inviteBtn.setVisibility(View.GONE);\n            mInvited = true;\n        }\n    }\n\n    /**\n     * Hide progress dialog\n     */\n    protected void hideProgressDialog() {\n        if (mProgressDialog != null && mProgressDialog.isShowing()) {\n            mProgressDialog.dismiss();\n            mProgressDialog = null;\n        }\n    }\n\n    /**\n     * Show the transfer progress\n     * \n     * @param position of the item whose data we want within the adapter's data set.\n     * @param currentSize Current size transferred\n     * @param totalSize Total size to be transferred\n     */\n    protected void updateProgressBar(Integer position, long currentSize, long totalSize) {\n        FileTransferProperties prop = mFileTransferAdapter.getItem(position);\n        prop.setStatus(Utils.getProgressLabel(currentSize, totalSize));\n        double progress = ((double) currentSize / (double) totalSize) * 100.0;\n        prop.setProgress((int) progress);\n        mFileTransferAdapter.notifyDataSetChanged();\n    }\n\n    private void quitSession() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"quitSession\");\n        }\n        try {\n            if (mFileTransfers != null) {\n                for (FileTransfer fileTransfer : mFileTransfers) {\n                    if (RcsSessionUtil.isAllowedToAbortFileTransferSession(fileTransfer)) {\n                        fileTransfer.abortTransfer();\n                    }\n                }\n                mFileTransfers.clear();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mFileTransfers = null;\n            /* Exit activity */\n            finish();\n        }\n    }\n\n    private boolean isThereAnyOnGoingSession() {\n        if (mFileTransfers == null) {\n            return false;\n        }\n        try {\n            for (FileTransfer fileTransfer : mFileTransfers) {\n                if (RcsSessionUtil.isAllowedToAbortFileTransferSession(fileTransfer)) {\n                    return true;\n                }\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_ft, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    /**\n     * Start activity\n     * \n     * @param context The context\n     * @param intent The original intent (with action SEND or SEND_MULTIPLE).\n     * @param isSingleChat True if file(s) is(are) sent over a single chat.\n     * @param chatId The chat ID.\n     */\n    public static void startActivity(Context context, Intent intent, boolean isSingleChat,\n            String chatId) {\n        if (isSingleChat) {\n            intent.setClass(context, SendMultiFileSingleChat.class);\n        } else {\n            intent.setClass(context, SendMultiFileGroupChat.class);\n        }\n        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.putExtra(EXTRA_CHAT_ID, chatId);\n        context.startActivity(intent);\n    }\n\n    /**\n     * FileTransfer adapter\n     */\n    protected class FileTransferAdapter extends ArrayAdapter<FileTransferProperties> {\n\n        private Context mContext;\n        private int mLayoutResourceId;\n        private FileTransferProperties[] mFileTransferViewItems;\n\n        /**\n         * Constructor\n         * \n         * @param context The context.\n         * @param layoutResourceId the layout resource ID.\n         * @param filetransferViewItems the list of file transfer view items.\n         */\n        public FileTransferAdapter(Context context, int layoutResourceId,\n                FileTransferProperties[] filetransferViewItems) {\n            super(context, layoutResourceId, filetransferViewItems);\n            mContext = context;\n            mLayoutResourceId = layoutResourceId;\n            mFileTransferViewItems = filetransferViewItems;\n        }\n\n        private class ViewHolder {\n            TextView mUri;\n            TextView mSize;\n            TextView mProgressStatus;\n            TableRow mReasonCodeTableRow;\n            TextView mReasonCodeText;\n            CheckBox mFileIcon;\n            CheckBox mAudiomsg;\n            ProgressBar mProgressBar;\n\n            ViewHolder(View view) {\n                mUri = (TextView) view.findViewById(R.id.uri);\n                mSize = (TextView) view.findViewById(R.id.filesize);\n                mProgressStatus = (TextView) view.findViewById(R.id.progress_status);\n                mFileIcon = (CheckBox) view.findViewById(R.id.ft_thumb);\n                mProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar);\n                mReasonCodeTableRow = (TableRow) view.findViewById(R.id.row_reason_code);\n                mReasonCodeText = (TextView) view.findViewById(R.id.text_reason_code);\n                mAudiomsg = (CheckBox) view.findViewById(R.id.send_audio_msg);\n            }\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();\n            ViewHolder viewHolder;\n            if (convertView == null) {\n                convertView = inflater.inflate(mLayoutResourceId, parent, false);\n                viewHolder = new ViewHolder(convertView);\n                convertView.setTag(viewHolder);\n            } else {\n                viewHolder = (ViewHolder) convertView.getTag();\n            }\n\n            final FileTransferProperties item = mFileTransferViewItems[position];\n            viewHolder.mUri.setText(item.getFilename());\n            viewHolder.mSize.setText(FileUtils.humanReadableByteCount(item.getSize(), true));\n            viewHolder.mProgressStatus.setText(item.getStatus());\n            String mimeType = item.getMimeType();\n            viewHolder.mAudiomsg.setEnabled(false);\n            viewHolder.mAudiomsg.setChecked(item.isAudioMessage());\n            viewHolder.mFileIcon.setEnabled(false);\n            viewHolder.mFileIcon.setChecked(item.isFileicon());\n            if (!mInvited) {\n                if (Utils.isImageType(mimeType)) {\n                    viewHolder.mFileIcon.setEnabled(true);\n                    viewHolder.mFileIcon.setOnClickListener(new View.OnClickListener() {\n                        public void onClick(View v) {\n                            CheckBox cb = (CheckBox) v;\n                            item.setFileicon(cb.isChecked());\n                        }\n                    });\n                } else if (Utils.isAudioType(mimeType)) {\n                    viewHolder.mAudiomsg.setEnabled(true);\n                    viewHolder.mAudiomsg.setOnClickListener(new View.OnClickListener() {\n                        public void onClick(View v) {\n                            CheckBox cb = (CheckBox) v;\n                            item.setAudioMessage(cb.isChecked());\n                        }\n                    });\n                }\n            }\n            viewHolder.mProgressBar.setProgress(item.getProgress());\n            if (item.getReasonCode() == null) {\n                viewHolder.mReasonCodeTableRow.setVisibility(View.GONE);\n            } else {\n                viewHolder.mReasonCodeTableRow.setVisibility(View.VISIBLE);\n                viewHolder.mReasonCodeText.setText(item.getReasonCode());\n            }\n            return convertView;\n        }\n    }\n\n    private boolean isFileTransferFinished(FileTransfer fileTransfer) throws RcsServiceException {\n        switch (fileTransfer.getState()) {\n            case STARTED:\n            case QUEUED:\n            case PAUSED:\n            case INITIATING:\n                return false;\n            default:\n                return true;\n        }\n    }\n\n    protected void closeDialogIfMultipleFileTransferIsFinished() {\n        if (mFileTransfers == null) {\n            return;\n        }\n        try {\n            for (FileTransfer fileTransfer : mFileTransfers) {\n                if (!isFileTransferFinished(fileTransfer)) {\n                    /* There is one ongoing file transfer -> exit */\n                    return;\n                }\n            }\n            /* There is no ongoing file transfer -> hide progress dialog */\n            hideProgressDialog();\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/multi/SendMultiFileGroupChat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer.multi;\n\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.GroupFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.util.Log;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * SendMultiFileGroupChat\n * \n * @author Philippe LEMORDANT\n */\npublic class SendMultiFileGroupChat extends SendMultiFile implements ISendMultiFile {\n\n    private static final String LOGTAG = LogUtils.getTag(SendMultiFileGroupChat.class\n            .getSimpleName());\n\n    private GroupFileTransferListener mFtListener;\n\n    @Override\n    public boolean transferFiles(List<FileTransferProperties> filesToTransfer) {\n        try {\n            for (FileTransferProperties fileToTransfer : filesToTransfer) {\n                /* Initiate transfer */\n                FileTransfer fileTransfer = mFileTransferService.transferFileToGroupChat(mChatId,\n                        fileToTransfer.getUri(),\n                        fileToTransfer.isAudioMessage() ? FileTransfer.Disposition.RENDER\n                                : FileTransfer.Disposition.ATTACH, fileToTransfer.isFileicon());\n                if (fileTransfer == null) {\n                    Log.e(LOGTAG, \"Cannot transfer file: ID not found!\");\n                    return false;\n                }\n                String fileTransferId = fileTransfer.getTransferId();\n                mTransferIds.add(fileTransferId);\n                mFileTransfers.add(fileTransfer);\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Transfer file '\" + fileToTransfer.getFilename() + \"' to chatId=\"\n                            + mChatId + \" icon=\" + fileToTransfer.isFileicon() + \" fileTransferId=\"\n                            + fileTransferId);\n                }\n            }\n            return true;\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return false;\n        }\n    }\n\n    @Override\n    public void addFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        if (!mFileTransferListenerAdded) {\n            fileTransferService.addEventListener(mFtListener);\n            mFileTransferListenerAdded = true;\n        }\n    }\n\n    @Override\n    public void removeFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        if (mFileTransferListenerAdded) {\n            fileTransferService.removeEventListener(mFtListener);\n            mFileTransferListenerAdded = false;\n        }\n    }\n\n    @Override\n    public boolean checkPermissionToSendFile(String chatId) throws RcsServiceException {\n        return mFileTransferService.isAllowedToTransferFileToGroupChat(chatId);\n    }\n\n    @Override\n    public void initialize() {\n        mFtListener = new GroupFileTransferListener() {\n\n            @Override\n            public void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n                    GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDeliveryInfoChanged chatId=\" + chatId + \" contact=\" + contact\n                            + \" transferId=\" + transferId + \" state=\" + status + \" reason=\"\n                            + reasonCode);\n                }\n            }\n\n            @Override\n            public void onProgressUpdate(String chatId, final String transferId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current transferId */\n                if (!mTransferIds.contains(transferId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(mTransferIds.indexOf(transferId), currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(String chatId, final String transferId,\n                    final FileTransfer.State state, FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged chatId=\" + chatId + \" transferId=\" + transferId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current transferId */\n                if (!mTransferIds.contains(transferId)) {\n                    return;\n                }\n\n                final String _reasonCode;\n                if (FileTransfer.ReasonCode.UNSPECIFIED == reasonCode) {\n                    _reasonCode = null;\n                } else {\n                    _reasonCode = RiApplication.sFileTransferReasonCodes[reasonCode.toInt()];\n                }\n                final String _state = RiApplication.sFileTransferStates[state.toInt()];\n                final FileTransferProperties prop = mFileTransferAdapter.getItem(mTransferIds\n                        .indexOf(transferId));\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        prop.setStatus(_state);\n                        prop.setReasonCode(_reasonCode);\n                        mFileTransferAdapter.notifyDataSetChanged();\n                        closeDialogIfMultipleFileTransferIsFinished();\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(String chatId, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted chatId=\" + chatId + \" transferIds=\" + transferIds);\n                }\n            }\n\n        };\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/filetransfer/multi/SendMultiFileSingleChat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.filetransfer.multi;\n\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener;\n\nimport android.util.Log;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * SendMultiFileSingleChat\n * \n * @author Philippe LEMORDANT\n */\npublic class SendMultiFileSingleChat extends SendMultiFile implements ISendMultiFile {\n\n    private static final String LOGTAG = LogUtils.getTag(SendMultiFileSingleChat.class\n            .getSimpleName());\n\n    private OneToOneFileTransferListener mFtListener;\n\n    @Override\n    public boolean transferFiles(List<FileTransferProperties> filesToTransfer) {\n        try {\n            ContactId contact = ContactUtil.getInstance(this).formatContact(mChatId);\n            for (FileTransferProperties fileToTransfer : filesToTransfer) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Transfer file '\" + fileToTransfer.getFilename()\n                            + \"' to contact=\" + contact + \" icon=\" + fileToTransfer.isFileicon());\n                }\n                FileTransfer fileTransfer = mFileTransferService.transferFile(contact,\n                        fileToTransfer.getUri(),\n                        fileToTransfer.isAudioMessage() ? FileTransfer.Disposition.RENDER\n                                : FileTransfer.Disposition.ATTACH, fileToTransfer.isFileicon());\n                if (fileTransfer == null) {\n                    Log.e(LOGTAG, \"Cannot transfer file: ID not found!\");\n                    return false;\n                }\n                mFileTransfers.add(fileTransfer);\n                mTransferIds.add(fileTransfer.getTransferId());\n            }\n            return true;\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return false;\n        }\n    }\n\n    @Override\n    public void addFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        if (!mFileTransferListenerAdded) {\n            fileTransferService.addEventListener(mFtListener);\n            mFileTransferListenerAdded = true;\n        }\n    }\n\n    @Override\n    public void removeFileTransferEventListener(FileTransferService fileTransferService)\n            throws RcsServiceException {\n        if (mFileTransferListenerAdded) {\n            fileTransferService.removeEventListener(mFtListener);\n            mFileTransferListenerAdded = false;\n        }\n    }\n\n    @Override\n    public boolean checkPermissionToSendFile(String chatId) throws RcsServiceException {\n        ContactId contact = ContactUtil.getInstance(this).formatContact(mChatId);\n        return mFileTransferService.isAllowedToTransferFile(contact);\n    }\n\n    @Override\n    public void initialize() {\n        mFtListener = new OneToOneFileTransferListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, final String transferId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current transferId */\n                if (!mTransferIds.contains(transferId)) {\n                    return;\n                }\n                // if (LogUtils.isActive) {\n                // Log.d(LOGTAG,\n                // \"onProgressUpdate contact \" + contact + \" transferId:\" + transferId\n                // + \" (size=\" + currentSize + \") (total=\" + totalSize + \") \"\n                // + mTransferIds.size());\n                // }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(mTransferIds.indexOf(transferId), currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(ContactId contact, String transferId,\n                    final FileTransfer.State state, FileTransfer.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" transferId=\" + transferId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current transferId */\n                if (!mTransferIds.contains(transferId)) {\n                    return;\n                }\n                final String _reasonCode;\n                if (FileTransfer.ReasonCode.UNSPECIFIED == reasonCode) {\n                    _reasonCode = null;\n                } else {\n                    _reasonCode = RiApplication.sFileTransferReasonCodes[reasonCode.toInt()];\n                }\n                final String _state = RiApplication.sFileTransferStates[state.toInt()];\n                final FileTransferProperties prop = mFileTransferAdapter.getItem(mTransferIds\n                        .indexOf(transferId));\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        prop.setStatus(_state);\n                        prop.setReasonCode(_reasonCode);\n                        mFileTransferAdapter.notifyDataSetChanged();\n                        closeDialogIfMultipleFileTransferIsFinished();\n                    }\n\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> transferIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" transferIds=\" + transferIds);\n                }\n            }\n\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/geoloc/DisplayGeoloc.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.geoloc;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport com.google.android.gms.maps.CameraUpdateFactory;\nimport com.google.android.gms.maps.GoogleMap;\nimport com.google.android.gms.maps.OnMapReadyCallback;\nimport com.google.android.gms.maps.SupportMapFragment;\nimport com.google.android.gms.maps.model.BitmapDescriptor;\nimport com.google.android.gms.maps.model.BitmapDescriptorFactory;\nimport com.google.android.gms.maps.model.CameraPosition;\nimport com.google.android.gms.maps.model.LatLng;\nimport com.google.android.gms.maps.model.Marker;\nimport com.google.android.gms.maps.model.MarkerOptions;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * Display geoloc on a Google map v2\n *\n * @author yplo6403\n */\npublic class DisplayGeoloc extends FragmentActivity implements OnMapReadyCallback {\n    /**\n     * Intent parameters: geolocation\n     */\n    public final static String EXTRA_GEOLOC = \"geoloc\";\n\n    private HashMap<String, Geoloc> mMapContactGeoloc;\n\n    private static BitmapDescriptor sMarkerIcon;\n\n    private static final int LARGE_ZOOM = 12;\n    private static final int SMALL_ZOOM = 4;\n\n    private final static String QUERY_SORT_ORDER = Message.TIMESTAMP + \" DESC\";\n\n    private final static String QUERY_WHERE_CLAUSE = Message.MIME_TYPE + \"='\"\n            + Message.MimeType.GEOLOC_MESSAGE + \"' AND \" + Message.DIRECTION + \" = \"\n            + Direction.OUTGOING.toInt();\n\n    private final static String[] QUERY_PROJECTION = new String[] {\n        Message.CONTENT\n    };\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.geoloc_display);\n        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()\n                .findFragmentById(R.id.map);\n        mapFragment.getMapAsync(this);\n\n        /* Get geoloc value from intent */\n        mMapContactGeoloc = (HashMap<String, Geoloc>) getIntent()\n                .getSerializableExtra(EXTRA_GEOLOC);\n        if (sMarkerIcon == null) {\n            sMarkerIcon = BitmapDescriptorFactory.fromResource(R.drawable.ri_map_icon);\n        }\n    }\n\n    @Override\n    public void onMapReady(GoogleMap map) {\n        boolean singleEntry = (mMapContactGeoloc.size() == 1);\n        LatLng latLng = null;\n        LatLng myPosition = null;\n        for (Entry<String, Geoloc> entry : mMapContactGeoloc.entrySet()) {\n            Geoloc geoloc = entry.getValue();\n            latLng = new LatLng(geoloc.getLatitude(), geoloc.getLongitude());\n            String contact = entry.getKey();\n            MarkerOptions options = new MarkerOptions().position(latLng).title(contact)\n                    .icon(sMarkerIcon);\n            if (contact.equals(getString(R.string.label_me))) {\n                myPosition = latLng;\n            }\n            Marker marker = map.addMarker(options);\n            if (singleEntry) {\n                marker.showInfoWindow();\n            }\n        }\n        LatLng target = latLng;\n        int zoom = SMALL_ZOOM;\n        if (singleEntry && latLng != null) {\n            zoom = LARGE_ZOOM;\n        } else if (myPosition != null) {\n            target = myPosition;\n        }\n        CameraPosition cameraPosition = new CameraPosition.Builder().target(target).zoom(zoom)\n                .build();\n        map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));\n    }\n\n    private static Geoloc getLastGeoloc(Context ctx, ContactId contact) {\n        Cursor cursor = null;\n        String where = Message.CONTACT + \"='\" + contact.toString() + \"' AND \" + Message.MIME_TYPE\n                + \"='\" + Message.MimeType.GEOLOC_MESSAGE + \"' AND \" + Message.DIRECTION + \" = \"\n                + Direction.INCOMING.toInt();\n        try {\n            cursor = ctx.getContentResolver().query(Message.CONTENT_URI, QUERY_PROJECTION, where,\n                    null, QUERY_SORT_ORDER);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query last geoloc for contact \" + contact);\n            }\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            String content = cursor.getString(cursor.getColumnIndexOrThrow(Message.CONTENT));\n            return new Geoloc(content);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    private static Geoloc getMyLastGeoloc(Context ctx) {\n        Cursor cursor = null;\n        try {\n            cursor = ctx.getContentResolver().query(Message.CONTENT_URI, QUERY_PROJECTION,\n                    QUERY_WHERE_CLAUSE, null, QUERY_SORT_ORDER);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query my last geoloc\");\n            }\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            String content = cursor.getString(cursor.getColumnIndexOrThrow(Message.CONTENT));\n            return new Geoloc(content);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    /**\n     * Show geolocation for a set of contacts\n     * \n     * @param ctx context\n     * @param contacts set of contacts\n     */\n    public static void showContactsOnMap(Context ctx, Set<ContactId> contacts) {\n        HashMap<String, Geoloc> mapContactGeoloc = new HashMap<>();\n        RcsContactUtil rcsContactUtil = RcsContactUtil.getInstance(ctx);\n        for (ContactId contact : contacts) {\n            Geoloc geoloc = getLastGeoloc(ctx, contact);\n            if (geoloc != null) {\n                mapContactGeoloc.put(rcsContactUtil.getDisplayName(contact), geoloc);\n            }\n        }\n        Geoloc myGeoloc = getMyLastGeoloc(ctx);\n        if (myGeoloc != null) {\n            mapContactGeoloc.put(ctx.getString(R.string.label_me), myGeoloc);\n        }\n        if (mapContactGeoloc.isEmpty()) {\n            Utils.displayLongToast(ctx, ctx.getString(R.string.label_geoloc_not_found));\n            return;\n        }\n        Intent intent = new Intent(ctx, DisplayGeoloc.class);\n        intent.putExtra(DisplayGeoloc.EXTRA_GEOLOC, mapContactGeoloc);\n        ctx.startActivity(intent);\n    }\n\n    /**\n     * Show geolocation for a one contact\n     * \n     * @param ctx context\n     * @param contact The contact\n     */\n    public static void showContactOnMap(Context ctx, ContactId contact) {\n        Set<ContactId> set = new HashSet<>();\n        set.add(contact);\n        showContactsOnMap(ctx, set);\n    }\n\n    /**\n     * Show geolocation for a contact\n     * \n     * @param ctx The context\n     * @param contact The contact\n     * @param geoloc The geolocation\n     */\n    public static void showContactOnMap(Context ctx, ContactId contact, Geoloc geoloc) {\n        HashMap<String, Geoloc> mapContactGeoloc = new HashMap<>();\n        String displayName = RcsContactUtil.getInstance(ctx).getDisplayName(contact);\n        mapContactGeoloc.put(displayName, geoloc);\n        Intent intent = new Intent(ctx, DisplayGeoloc.class);\n        intent.putExtra(DisplayGeoloc.EXTRA_GEOLOC, mapContactGeoloc);\n        ctx.startActivity(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/geoloc/EditGeoloc.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.geoloc;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.chat.ChatServiceConfiguration;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.location.Criteria;\nimport android.location.Location;\nimport android.location.LocationManager;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.support.v4.app.ActivityCompat;\nimport android.text.InputFilter;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.EditText;\n\n/**\n * Geoloc info editor\n */\npublic class EditGeoloc extends RcsActivity {\n    /**\n     * Intent parameters\n     */\n    public final static String EXTRA_GEOLOC = \"geoloc\";\n\n    private EditText mLocationEdit;\n\n    private EditText mLatitudeEdit;\n\n    private EditText mLongitudeEdit;\n\n    private EditText mAccuracyEdit;\n\n    private final static int REQUEST_CODE_SELECT_GEOLOC = 0;\n\n    private long geolocExpirationTime = 0;\n\n    private int geolocLabelMaxLength = 0;\n\n    private static final String LOGTAG = LogUtils.getTag(EditGeoloc.class.getSimpleName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.geoloc_edit);\n        /* Create editors */\n        mLocationEdit = (EditText) findViewById(R.id.location);\n        mLatitudeEdit = (EditText) findViewById(R.id.latitude);\n        mLongitudeEdit = (EditText) findViewById(R.id.longitude);\n        mAccuracyEdit = (EditText) findViewById(R.id.accuracy);\n\n        /* Set button callback */\n        Button validateBtn = (Button) findViewById(R.id.validate_btn);\n        validateBtn.setOnClickListener(btnValidateListener);\n\n        Button selectBtn = (Button) findViewById(R.id.select_geoloc_btn);\n        selectBtn.setOnClickListener(btnSelectListener);\n\n        // Display my current location\n        setMyLocation();\n\n        // Register to API connection manager\n        if (isServiceConnected(RcsServiceName.CHAT)) {\n            try {\n                ChatServiceConfiguration configuration = getChatApi().getConfiguration();\n                geolocExpirationTime = configuration.getGeolocExpirationTime();\n                geolocLabelMaxLength = configuration.getGeolocLabelMaxLength();\n\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n        if (geolocLabelMaxLength > 0) {\n            InputFilter maxLengthFilter = new InputFilter.LengthFilter(geolocLabelMaxLength);\n            mLocationEdit.setFilters(new InputFilter[] {\n                maxLengthFilter\n            });\n        }\n    }\n\n    /**\n     * Set the location of the device\n     */\n    protected void setMyLocation() {\n        LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);\n        Criteria criteria = new Criteria();\n        String bestProvider = lm.getBestProvider(criteria, false);\n        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED\n                && ActivityCompat.checkSelfPermission(this,\n                        Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {\n            return;\n        }\n        Location lastKnownLoc = lm.getLastKnownLocation(bestProvider);\n        if (lastKnownLoc != null) {\n            mLatitudeEdit.setText(String.valueOf(lastKnownLoc.getLatitude()));\n            mLongitudeEdit.setText(String.valueOf(lastKnownLoc.getLongitude()));\n            mAccuracyEdit.setText(String.valueOf(lastKnownLoc.getAccuracy()));\n        }\n        super.onResume();\n    }\n\n    /**\n     * Validate button listener\n     */\n    private OnClickListener btnValidateListener = new OnClickListener() {\n        public void onClick(View v) {\n            String lat = mLatitudeEdit.getText().toString().trim();\n            if (lat.length() == 0) {\n                mLatitudeEdit.setText(\"0.0\");\n            }\n            String lon = mLongitudeEdit.getText().toString().trim();\n            if (lon.length() == 0) {\n                mLongitudeEdit.setText(\"0.0\");\n            }\n            String acc = mAccuracyEdit.getText().toString().trim();\n            if (acc.length() == 0) {\n                mAccuracyEdit.setText(\"0\");\n            }\n            long expiration = System.currentTimeMillis() + geolocExpirationTime;\n            Geoloc geoloc = new Geoloc(mLocationEdit.getText().toString(), Double.parseDouble(lat),\n                    Double.parseDouble(lon), expiration, Float.parseFloat(acc));\n            Intent in = new Intent();\n            in.putExtra(EXTRA_GEOLOC, (Parcelable) geoloc);\n            setResult(-1, in);\n            finish();\n        }\n    };\n\n    /**\n     * Select geolocation button listener\n     */\n    private OnClickListener btnSelectListener = new OnClickListener() {\n        public void onClick(View v) {\n            // Start a new activity to send a geolocation\n            Intent geolocSelectIntent = new Intent(EditGeoloc.this, SelectGeoloc.class);\n            startActivityForResult(geolocSelectIntent, REQUEST_CODE_SELECT_GEOLOC);\n        }\n    };\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n        switch (requestCode) {\n            case REQUEST_CODE_SELECT_GEOLOC:\n                Geoloc geoloc = data.getParcelableExtra(EXTRA_GEOLOC);\n                mLatitudeEdit.setText(String.valueOf(geoloc.getLatitude()));\n                mLongitudeEdit.setText(String.valueOf(geoloc.getLongitude()));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/geoloc/SelectGeoloc.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.geoloc;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.Geoloc;\n\nimport com.google.android.gms.maps.GoogleMap;\nimport com.google.android.gms.maps.GoogleMap.OnMapClickListener;\nimport com.google.android.gms.maps.OnMapReadyCallback;\nimport com.google.android.gms.maps.SupportMapFragment;\nimport com.google.android.gms.maps.model.LatLng;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.support.v4.app.FragmentActivity;\n\n/**\n * Select a geoloc from a map\n */\npublic class SelectGeoloc extends FragmentActivity implements OnMapReadyCallback,\n        OnMapClickListener {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.geoloc_display);\n        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()\n                .findFragmentById(R.id.map);\n        mapFragment.getMapAsync(this);\n    }\n\n    @Override\n    public void onMapReady(GoogleMap map) {\n        map.setOnMapClickListener(this);\n    }\n\n    @Override\n    public void onMapClick(LatLng point) {\n        Geoloc geoloc = new Geoloc(null, point.latitude, point.longitude, 0, 0);\n        Intent intent = getIntent();\n        intent.putExtra(DisplayGeoloc.EXTRA_GEOLOC, (Parcelable) geoloc);\n        setResult(RESULT_OK, intent);\n        finish();\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/messaging/geoloc/ShowGeoloc.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.messaging.geoloc;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.TextView;\n\n/**\n * Activity to show Geoloc\n */\npublic class ShowGeoloc extends Activity {\n    /**\n     * Intent parameters\n     */\n    public final static String EXTRA_GEOLOC = \"geoloc\";\n    public final static String EXTRA_CONTACT = \"contact\";\n\n    private Geoloc mGeoloc;\n\n    private ContactId mContact;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.geoloc_show);\n\n        mGeoloc = getIntent().getParcelableExtra(EXTRA_GEOLOC);\n        mContact = getIntent().getParcelableExtra(EXTRA_CONTACT);\n\n        TextView contactText = (TextView) findViewById(R.id.contact);\n        contactText.setText(mContact.toString());\n\n        TextView locationText = (TextView) findViewById(R.id.location);\n        locationText.setText(mGeoloc.getLabel());\n\n        TextView latitudeText = (TextView) findViewById(R.id.latitude);\n        latitudeText.setText(Double.toString(mGeoloc.getLatitude()));\n\n        TextView longitudeText = (TextView) findViewById(R.id.longitude);\n        longitudeText.setText(Double.toString(mGeoloc.getLongitude()));\n\n        TextView accuracyText = (TextView) findViewById(R.id.accuracy);\n        accuracyText.setText(Float.toString(mGeoloc.getAccuracy()));\n\n        Button displayBtn = (Button) findViewById(R.id.display_geoloc_btn);\n        displayBtn.setOnClickListener(mBtnDisplayListener);\n    }\n\n    private OnClickListener mBtnDisplayListener = new OnClickListener() {\n        public void onClick(View v) {\n            DisplayGeoloc.showContactOnMap(ShowGeoloc.this, mContact, mGeoloc);\n        }\n    };\n\n    public static void ShowGeolocForContact(Context ctx, ContactId contact, Geoloc geoloc) {\n        Intent intent = new Intent(ctx, ShowGeoloc.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.putExtra(EXTRA_GEOLOC, (Parcelable) geoloc);\n        intent.putExtra(EXTRA_CONTACT, (Parcelable) contact);\n        ctx.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/permissions/PermissionsActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.permissions;\n\nimport com.gsma.rcs.api.connection.utils.RcsListActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RI;\nimport com.gsma.rcs.ri.utils.LogUtils;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.util.Log;\nimport android.widget.ArrayAdapter;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * A class to request permissions\n * \n * @author Philippe LEMORDANT\n */\npublic class PermissionsActivity extends RcsListActivity {\n\n    /**\n     * List of permissions needed for service. Just need to ask one permission per dangerous group. <br>\n     * READ_SMS is not asked since not required after Lollipop.\n     */\n    // @formatter:off\n    private static final Set<String> sAllPermissionsList = new HashSet<>(Arrays.asList(\n            Manifest.permission.READ_CONTACTS,\n            Manifest.permission.ACCESS_FINE_LOCATION,\n            Manifest.permission.CAMERA,\n            Manifest.permission.CALL_PHONE,\n            Manifest.permission.WRITE_EXTERNAL_STORAGE,\n            android.Manifest.permission.RECORD_AUDIO));\n    // @formatter:on\n\n    private static final int MY_PERMISSION_REQUEST_ALL = 5428;\n\n    private static final String LOGTAG = LogUtils.getTag(PermissionsActivity.class.getSimpleName());\n    private static final String PERMISSION_ASKED = \"permission_asked\";\n    private Set<String> notGrantedPermissions;\n    private boolean mAskingPermission;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.ask_permissions);\n        notGrantedPermissions = getNotGrantedPermissions();\n        if (savedInstanceState != null) {\n            mAskingPermission = savedInstanceState.getBoolean(PERMISSION_ASKED);\n            if (!notGrantedPermissions.isEmpty()) {\n                if (!mAskingPermission) {\n                    mAskingPermission = true;\n                    ActivityCompat\n                            .requestPermissions(this, notGrantedPermissions\n                                    .toArray(new String[notGrantedPermissions.size()]),\n                                    MY_PERMISSION_REQUEST_ALL);\n                }\n                displayUngrantedPermissions();\n            } else {\n                startActivity(new Intent(this, RI.class));\n                finish();\n            }\n\n        } else {\n            if (notGrantedPermissions.isEmpty()) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"All permissions are granted\");\n                }\n                startActivity(new Intent(this, RI.class));\n                finish();\n            } else {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Permission to be asked: \" + notGrantedPermissions);\n                    askPermissions();\n                }\n            }\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        // Make sure to call the super method so that the variables of our views are saved\n        super.onSaveInstanceState(outState);\n        // Save our own variable now\n        outState.putBoolean(PERMISSION_ASKED, mAskingPermission);\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,\n            @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (MY_PERMISSION_REQUEST_ALL == requestCode) {\n            mAskingPermission = false;\n            notGrantedPermissions = new HashSet<>();\n            for (int i = 0; i < permissions.length; i++) {\n                if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {\n                    String unGrantedPermission = permissions[i];\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"Permission Denied: \" + unGrantedPermission);\n                    }\n                    notGrantedPermissions.add(unGrantedPermission);\n                }\n            }\n            if (!notGrantedPermissions.isEmpty()) {\n                displayUngrantedPermissions();\n            } else {\n                startActivity(new Intent(this, RI.class));\n                finish();\n            }\n        }\n    }\n\n    private void askPermissions() {\n        if (notGrantedPermissions.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            // only ask permissions once.\n            if (!mAskingPermission) {\n                mAskingPermission = true;\n                displayUngrantedPermissions();\n                requestPermissions(\n                        notGrantedPermissions.toArray(new String[notGrantedPermissions.size()]),\n                        MY_PERMISSION_REQUEST_ALL);\n            }\n        } else {\n            startActivity(new Intent(this, RI.class));\n            finish();\n        }\n    }\n\n    private Set<String> getNotGrantedPermissions() {\n        Set<String> permissionsToAsk = new HashSet<>();\n        for (String permission : PermissionsActivity.sAllPermissionsList) {\n            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this,\n                    permission)) {\n                permissionsToAsk.add(permission);\n            }\n        }\n        return permissionsToAsk;\n    }\n\n    private void displayUngrantedPermissions() {\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,\n                notGrantedPermissions.toArray(new String[notGrantedPermissions.size()])));\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/service/RegistrationStatus.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.service;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.RcsServiceRegistrationListener;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.widget.TextView;\n\n/**\n * Display and monitor the registration status\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class RegistrationStatus extends RcsActivity {\n\n    private final Handler mHandler = new Handler();\n\n    private MyRegistrationListener registrationListener = new MyRegistrationListener();\n\n    private static final String LOGTAG = LogUtils.getTag(RegistrationStatus.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.service_registration);\n\n        // Display registration status by default\n        displayRegistrationStatus(false);\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.CAPABILITY)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CAPABILITY);\n        try {\n            getCapabilityApi().addEventListener(registrationListener);\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (isServiceConnected(RcsServiceName.CAPABILITY)) {\n            try {\n                getCapabilityApi().removeEventListener(registrationListener);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        try {\n            displayRegistrationStatus(getCapabilityApi().isServiceRegistered());\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private class MyRegistrationListener extends RcsServiceRegistrationListener {\n        // Service is registered to the network platform\n        public void onServiceRegistered() {\n            mHandler.post(new Runnable() {\n                public void run() {\n                    displayRegistrationStatus(true);\n                }\n            });\n        }\n\n        // Service is unregistered from the network platform\n        public void onServiceUnregistered(RcsServiceRegistration.ReasonCode reason) {\n            mHandler.post(new Runnable() {\n                public void run() {\n                    displayRegistrationStatus(false);\n                }\n            });\n        }\n    }\n\n    private void displayRegistrationStatus(boolean status) {\n        TextView statusTxt = (TextView) findViewById(R.id.registration_status);\n        statusTxt.setText(String.valueOf(status));\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/service/ServiceConfigurationActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.service;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.CommonServiceConfiguration;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\n\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.util.SparseArray;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ArrayAdapter;\nimport android.widget.CheckBox;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Service configuration\n * \n * @author LEMORDANT Philippe\n */\npublic class ServiceConfigurationActivity extends RcsActivity {\n\n    private static final String LOGTAG = LogUtils.getTag(ServiceConfigurationActivity.class\n            .getSimpleName());\n\n    private Spinner mSpinnerDefMessaginMethod;\n    private Spinner mSpinnerMinBatteryLevel;\n    private TextView mTextEditDisplayName;\n    private CheckBox mCheckBoxIsConfigValid;\n    private TextView mTextEditMessagingUX;\n    private TextView mTextEditContactId;\n    private TextView mTextRcsServiceActivation;\n\n    private CommonServiceConfiguration mConfiguration;\n\n    private String mIntialDisplayName;\n\n    private RcsServiceControl mRcsServiceControl;\n\n    private static SparseArray<MinimumBatteryLevel> sPosToMinimumBatteryLevel = new SparseArray<>();\n    private static Map<MinimumBatteryLevel, Integer> sMinimumBatteryLevelToPos = new HashMap<>();\n    static {\n        int order = 0;\n        for (MinimumBatteryLevel entry : MinimumBatteryLevel.values()) {\n            sPosToMinimumBatteryLevel.put(order, entry);\n            sMinimumBatteryLevelToPos.put(entry, order++);\n        }\n    }\n\n    private MinimumBatteryLevel getMinimumBatteryLevelFromSpinnerPosition(int position) {\n        return sPosToMinimumBatteryLevel.get(position);\n    }\n\n    private int getSpinnerPositionFromMinimumBatteryLevel(MinimumBatteryLevel level) {\n        return sMinimumBatteryLevelToPos.get(level);\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        mRcsServiceControl = RiApplication.getRcsServiceControl();\n\n        /* Set layout */\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.service_configuration);\n\n        mCheckBoxIsConfigValid = (CheckBox) findViewById(R.id.label_service_configuration_valid);\n        mTextEditMessagingUX = (TextView) findViewById(R.id.label_messaging_mode);\n        mTextEditContactId = (TextView) findViewById(R.id.label_my_contact_id);\n        mTextEditDisplayName = (TextView) findViewById(R.id.text_my_display_name);\n        mTextRcsServiceActivation = (TextView) findViewById(R.id.text_service_activation);\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.CONTACT);\n        try {\n            mConfiguration = getContactApi().getCommonConfiguration();\n            mIntialDisplayName = mConfiguration.getMyDisplayName();\n            if (mIntialDisplayName == null) {\n                mIntialDisplayName = \"\";\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n            return;\n        }\n\n        String[] messagingMethods = getResources().getStringArray(R.array.messaging_method);\n        mSpinnerDefMessaginMethod = (Spinner) findViewById(R.id.spinner_default_messaging_method);\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(this,\n                android.R.layout.simple_spinner_item, messagingMethods);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        mSpinnerDefMessaginMethod.setAdapter(adapter);\n\n        mSpinnerDefMessaginMethod.setOnItemSelectedListener(new OnItemSelectedListener() {\n\n            @Override\n            public void onItemSelected(AdapterView<?> parentView, View selectedItemView,\n                    int position, long id) {\n                MessagingMethod method = MessagingMethod.valueOf(mSpinnerDefMessaginMethod\n                        .getSelectedItemPosition());\n                try {\n                    MessagingMethod oldMethod = mConfiguration.getDefaultMessagingMethod();\n                    if (!oldMethod.equals(method)) {\n                        mConfiguration.setDefaultMessagingMethod(method);\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG,\n                                    \"onClick DefaultMessagingMethod \".concat(method.toString()));\n                        }\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parentView) {\n            }\n        });\n\n        String[] batteryLevels = getResources().getStringArray(R.array.minimum_battery_level);\n        mSpinnerMinBatteryLevel = (Spinner) findViewById(R.id.spinner_label_min_battery_level);\n        adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, batteryLevels);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        mSpinnerMinBatteryLevel.setAdapter(adapter);\n\n        mSpinnerMinBatteryLevel.setOnItemSelectedListener(new OnItemSelectedListener() {\n\n            @Override\n            public void onItemSelected(AdapterView<?> parentView, View selectedItemView,\n                    int position, long id) {\n                MinimumBatteryLevel level = getMinimumBatteryLevelFromSpinnerPosition(mSpinnerMinBatteryLevel\n                        .getSelectedItemPosition());\n                try {\n                    MinimumBatteryLevel oldLevel = mConfiguration.getMinimumBatteryLevel();\n                    if (!oldLevel.equals(level)) {\n                        mConfiguration.setMinimumBatteryLevel(level);\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"onClick MinimumBatteryLevel \".concat(level.toString()));\n                        }\n                    }\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parentView) {\n            }\n        });\n        startMonitorServices(RcsServiceName.CONTACT);\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onCreate\");\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        String newDisplayName = mTextEditDisplayName.getText().toString();\n        if (mIntialDisplayName != null && !mIntialDisplayName.equals(newDisplayName)) {\n            setDisplayName(newDisplayName);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (isExiting()) {\n            return;\n        }\n        displayServiceConfiguration();\n    }\n\n    private void displayServiceConfiguration() {\n        try {\n            mCheckBoxIsConfigValid.setChecked(mConfiguration.isConfigValid());\n            mSpinnerDefMessaginMethod.setSelection(mConfiguration.getDefaultMessagingMethod()\n                    .toInt());\n            mSpinnerMinBatteryLevel\n                    .setSelection(getSpinnerPositionFromMinimumBatteryLevel(mConfiguration\n                            .getMinimumBatteryLevel()));\n            mTextEditMessagingUX.setText(mConfiguration.getMessagingUX().name());\n            mTextEditDisplayName.setText(mConfiguration.getMyDisplayName());\n            mTextEditContactId.setText(mConfiguration.getMyContactId().toString());\n            boolean rcsServiceActivationchangeable = mRcsServiceControl\n                    .isActivationModeChangeable();\n            if (rcsServiceActivationchangeable) {\n                mTextRcsServiceActivation\n                        .setText(getString(R.string.label_service_activate_changeable));\n            } else {\n                mTextRcsServiceActivation\n                        .setText(getString(R.string.label_service_activate_unchangeable));\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n    }\n\n    private void setDisplayName(String newDisplayName) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Refresh display name to \".concat(newDisplayName));\n        }\n        try {\n            mConfiguration.setMyDisplayName(newDisplayName);\n        } catch (RcsServiceException e) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Exception occurred\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/service/ServiceStatus.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.service;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.capability.CapabilityService;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.TextView;\n\n/**\n * Display and monitor the service status\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ServiceStatus extends RcsActivity implements RcsServiceListener {\n\n    private RcsService mApi;\n\n    private RcsServiceControl mRcsServiceControl;\n\n    private TextView mServiceBound;\n\n    private TextView mServiceActivated;\n\n    private TextView mServiceStarted;\n\n    private static final String LOGTAG = LogUtils.getTag(ServiceStatus.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        mRcsServiceControl = RiApplication.getRcsServiceControl();\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.service_status);\n\n        mServiceBound = (TextView) findViewById(R.id.service_bound);\n        mServiceActivated = (TextView) findViewById(R.id.service_activated);\n        mServiceStarted = (TextView) findViewById(R.id.service_started);\n        Button serviceActivationRefresh = (Button) findViewById(R.id.service_refresh_all);\n        serviceActivationRefresh.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                displayServiceActivation();\n                displayServiceStarted();\n            }\n\n        });\n\n        // Display service status by default\n        displayServiceBinding(false);\n\n        displayServiceActivation();\n\n        displayServiceStarted();\n\n        // Register service up event listener\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(RcsService.ACTION_SERVICE_UP);\n        registerReceiver(serviceUpListener, intentFilter);\n\n        // Instantiate API\n        mApi = new CapabilityService(getApplicationContext(), this);\n\n        // Connect API\n        try {\n            mApi.connect();\n        } catch (RcsPermissionDeniedException e) {\n            mApi = null;\n            showMessageThenExit(R.string.label_api_not_compatible);\n        }\n    }\n\n    private void displayServiceActivation() {\n        try {\n            mServiceActivated.setText(Boolean.toString(mRcsServiceControl.isActivated()));\n        } catch (RcsGenericException e) {\n            Log.e(LOGTAG, \"Failed to read service activation status\", e);\n            mServiceActivated.setText(getString(R.string.error_service_activated));\n        }\n    }\n\n    private void displayServiceStarted() {\n        try {\n            mServiceStarted.setText(Boolean.toString(mRcsServiceControl.isServiceStarted()));\n        } catch (RcsGenericException e) {\n            Log.e(LOGTAG, \"Failed to read service started\", e);\n            mServiceActivated.setText(getString(R.string.error_service_started));\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        // Unregister service up event listener\n        try {\n            unregisterReceiver(serviceUpListener);\n        } catch (IllegalArgumentException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n        if (mApi != null) {\n            // Disconnect API\n            mApi.disconnect();\n        }\n    }\n\n    /**\n     * Callback called when service is connected. This method is called when the service is well\n     * connected to the RCS service (binding procedure successful): this means the methods of the\n     * API may be used.\n     */\n    public void onServiceConnected() {\n        // Display service binding status\n        displayServiceBinding(true);\n    }\n\n    /**\n     * Callback called when service has been disconnected. This method is called when the service is\n     * disconnected from the RCS service (e.g. service deactivated).\n     * \n     * @param error Error\n     */\n    public void onServiceDisconnected(ReasonCode error) {\n        // Display service binding status\n        displayServiceBinding(false);\n    }\n\n    /**\n     * Display service status\n     * \n     * @param status Status\n     */\n    private void displayServiceBinding(boolean status) {\n        mServiceBound.setText(String.valueOf(status));\n    }\n\n    /**\n     * RCS service up event listener\n     */\n    private BroadcastReceiver serviceUpListener = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, final Intent intent) {\n            // Retry a connection to the service\n            try {\n                mApi.connect();\n            } catch (RcsPermissionDeniedException e) {\n                mApi = null;\n                showMessageThenExit(R.string.label_api_not_compatible);\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/service/TestServiceApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.service;\n\nimport com.gsma.rcs.ri.R;\n\nimport android.app.ListActivity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * Service API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestServiceApi extends ListActivity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        String[] items = {\n                getString(R.string.menu_service_status),\n                getString(R.string.menu_registration_status),\n                getString(R.string.menu_service_configuration)\n        };\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, ServiceStatus.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, RegistrationStatus.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, ServiceConfigurationActivity.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/SharingListView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsFragmentActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.sharing.geoloc.GeolocSharingLogView;\nimport com.gsma.rcs.ri.sharing.image.ImageSharingLogView;\nimport com.gsma.rcs.ri.sharing.video.VideoSharingLogView;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\nimport com.gsma.services.rcs.sharing.image.ImageSharingListener;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingListener;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.app.AlertDialog.Builder;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.pm.ActivityInfo;\nimport android.content.res.Resources;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.LoaderManager;\nimport android.support.v4.content.CursorLoader;\nimport android.support.v4.content.Loader;\nimport android.support.v4.widget.CursorAdapter;\nimport android.text.TextUtils;\nimport android.text.format.DateUtils;\nimport android.util.Log;\nimport android.view.ContextMenu;\nimport android.view.ContextMenu.ContextMenuInfo;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.AdapterView.AdapterContextMenuInfo;\nimport android.widget.AdapterView.OnItemClickListener;\nimport android.widget.AdapterView.OnItemSelectedListener;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\n\n/**\n * A class to view the sharing logs\n */\npublic class SharingListView extends RcsFragmentActivity implements\n        LoaderManager.LoaderCallbacks<Cursor> {\n    /**\n     * The loader's unique ID. Loader IDs are specific to the Activity in which they reside.\n     */\n    private static final int LOADER_ID = 1;\n\n    // @formatter:off\n    private static final String[] PROJECTION = {\n            HistoryLog.BASECOLUMN_ID,\n            HistoryLog.ID,\n            HistoryLog.PROVIDER_ID,\n            HistoryLog.CONTACT,\n            HistoryLog.TIMESTAMP,\n            HistoryLog.DIRECTION,\n            HistoryLog.STATUS,\n            HistoryLog.FILENAME,\n            HistoryLog.DURATION,\n            HistoryLog.CONTENT,\n            HistoryLog.MIME_TYPE,\n            HistoryLog.TRANSFERRED,\n            HistoryLog.FILESIZE\n    };\n    // @formatter:on\n\n    private static final String LOGTAG = LogUtils.getTag(SharingListView.class.getName());\n\n    private static final int MAX_LENGTH_DESCRIPTION = 30;\n    private static final String SORT_BY = \"timestamp DESC\";\n    private static final String WHERE_CLAUSE_WITH_CONTACT = \"contact=?\";\n    /**\n     * Associate the providers name menu with providerIds defined in HistoryLog\n     */\n    private static final TreeMap<Integer, String> sProviders = new TreeMap<>();\n\n    private boolean[] mCheckedProviders;\n    private AlertDialog mFilterAlertDialog;\n    private List<String> mFilterMenuItems;\n    private GeolocSharingListener mGeolocSharingListener;\n    private boolean mGeolocSharingListenerSet;\n    private GeolocSharingService mGeolocSharingService;\n    private final Handler mHandler = new Handler();\n    private ImageSharingListener mImageSharingListener;\n    private boolean mImageSharingListenerSet;\n    private ImageSharingService mImageSharingService;\n    private List<Integer> mProviderIds;\n    private SharingLogAdapter mAdapter;\n    private Spinner mSpinner;\n    private VideoSharingListener mVideoSharingListener;\n    private boolean mVideoSharingListenerSet;\n    private VideoSharingService mVideoSharingService;\n\n    private class ViewHolder {\n\n        private final int mColumnContactIdx;\n        private final int mColumnTimestampIdx;\n        private final int mColumnStatusIdx;\n        private final int mColumnDirectionIdx;\n        private final TextView mTypeView;\n        private final TextView mContactView;\n        private final TextView mDescriptionView;\n        private final TextView mDateView;\n        private final ImageView mDirectionIconImageView;\n        private final int mColumnProviderIdIdx;\n        private final int mColumnFilenameIdx;\n        private final int mColumnDurationIdx;\n        private final int mColumnContentIdx;\n\n        public ViewHolder(View view, Cursor cursor) {\n            mColumnProviderIdIdx = cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID);\n            mColumnContactIdx = cursor.getColumnIndexOrThrow(HistoryLog.CONTACT);\n            mColumnTimestampIdx = cursor.getColumnIndexOrThrow(HistoryLog.TIMESTAMP);\n            mColumnDirectionIdx = cursor.getColumnIndexOrThrow(HistoryLog.DIRECTION);\n            mColumnStatusIdx = cursor.getColumnIndexOrThrow(HistoryLog.STATUS);\n            mColumnFilenameIdx = cursor.getColumnIndexOrThrow(HistoryLog.FILENAME);\n            mColumnDurationIdx = cursor.getColumnIndexOrThrow(HistoryLog.DURATION);\n            mColumnContentIdx = cursor.getColumnIndexOrThrow(HistoryLog.CONTENT);\n\n            mTypeView = (TextView) view.findViewById(R.id.conversation_type);\n            mContactView = (TextView) view.findViewById(R.id.contact_label);\n            mDescriptionView = (TextView) view.findViewById(R.id.description);\n            mDateView = (TextView) view.findViewById(R.id.date);\n            mDirectionIconImageView = (ImageView) view.findViewById(R.id.call_type_icon);\n        }\n\n        public int getColumnProviderIdIdx() {\n            return mColumnProviderIdIdx;\n        }\n\n        public int getColumnContactIdx() {\n            return mColumnContactIdx;\n        }\n\n        public int getColumnTimestampIdx() {\n            return mColumnTimestampIdx;\n        }\n\n        public int getColumnStatusIdx() {\n            return mColumnStatusIdx;\n        }\n\n        public int getColumnDirectionIdx() {\n            return mColumnDirectionIdx;\n        }\n\n        public TextView getTypeView() {\n            return mTypeView;\n        }\n\n        public TextView getContactView() {\n            return mContactView;\n        }\n\n        public TextView getDescriptionView() {\n            return mDescriptionView;\n        }\n\n        public TextView getDateView() {\n            return mDateView;\n        }\n\n        public ImageView getDirectionIconImageView() {\n            return mDirectionIconImageView;\n        }\n\n        public int getColumnFilenameIdx() {\n            return mColumnFilenameIdx;\n        }\n\n        public int getColumnDurationIdx() {\n            return mColumnDurationIdx;\n        }\n\n        public int getColumnContentIdx() {\n            return mColumnContentIdx;\n        }\n    }\n\n    private class SharingLogAdapter extends CursorAdapter {\n        private final LayoutInflater mInflater;\n        private final RcsContactUtil mRcsContactUtil;\n        private Drawable mDrawableIncoming;\n        private Drawable mDrawableIncomingFailed;\n        private Drawable mDrawableOutgoing;\n        private Drawable mDrawableOutgoingFailed;\n\n        public SharingLogAdapter(Activity activity) {\n            super(activity, null, 0);\n            mRcsContactUtil = RcsContactUtil.getInstance(activity);\n            mInflater = LayoutInflater.from(SharingListView.this);\n            Resources resources = activity.getResources();\n            mDrawableIncomingFailed = resources.getDrawable(R.drawable.ri_incoming_call_failed);\n            mDrawableOutgoingFailed = resources.getDrawable(R.drawable.ri_outgoing_call_failed);\n            mDrawableIncoming = resources.getDrawable(R.drawable.ri_incoming_call);\n            mDrawableOutgoing = resources.getDrawable(R.drawable.ri_outgoing_call);\n        }\n\n        @Override\n        public int getItemViewType(int position) {\n            return 1;\n        }\n\n        @Override\n        public int getViewTypeCount() {\n            return 1;\n        }\n\n        @Override\n        public View newView(Context context, Cursor cursor, ViewGroup parent) {\n            View view = mInflater.inflate(R.layout.sharing_log_list, parent, false);\n            view.setTag(new ViewHolder(view, cursor));\n            return view;\n        }\n\n        @Override\n        public void bindView(View view, Context context, Cursor cursor) {\n            ViewHolder holder = (ViewHolder) view.getTag();\n\n            // Set contact number\n            String phone = cursor.getString(holder.getColumnContactIdx());\n            ContactId contact = ContactUtil.formatContact(phone);\n            holder.getContactView().setText(mRcsContactUtil.getDisplayName(contact));\n\n            // Set the date/time field by mixing relative and absolute times\n            long date = cursor.getLong(holder.getColumnTimestampIdx());\n            holder.getDateView().setText(\n                    DateUtils.getRelativeTimeSpanString(date, System.currentTimeMillis(),\n                            DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE));\n\n            // Set the status text and destination icon\n            int status = cursor.getInt(holder.getColumnStatusIdx());\n            Direction dir = Direction.valueOf(cursor.getInt(holder.getColumnDirectionIdx()));\n            switch (dir) {\n                case INCOMING:\n                    if (status != State.FAILED.toInt()\n                            && status != VideoSharing.State.FAILED.toInt()\n                            && status != GeolocSharing.State.FAILED.toInt()) {\n                        holder.getDirectionIconImageView().setImageDrawable(mDrawableIncoming);\n                    } else {\n                        holder.getDirectionIconImageView()\n                                .setImageDrawable(mDrawableIncomingFailed);\n                    }\n                    break;\n\n                case OUTGOING:\n                    if (status != State.FAILED.toInt()\n                            && status != VideoSharing.State.FAILED.toInt()\n                            && status != GeolocSharing.State.FAILED.toInt()) {\n                        holder.getDirectionIconImageView().setImageDrawable(mDrawableOutgoing);\n                    } else {\n                        holder.getDirectionIconImageView()\n                                .setImageDrawable(mDrawableOutgoingFailed);\n                    }\n                    break;\n            }\n            int providerId = cursor.getInt(holder.getColumnProviderIdIdx());\n            switch (providerId) {\n                case ImageSharingLog.HISTORYLOG_MEMBER_ID:\n                    holder.getTypeView().setText(R.string.label_sharing_log_menu_ish);\n                    String filename = cursor.getString(holder.getColumnFilenameIdx());\n                    holder.getDescriptionView().setText(\n                            TextUtils.isEmpty(filename) ? \"\" : truncateString(filename,\n                                    MAX_LENGTH_DESCRIPTION));\n                    break;\n\n                case VideoSharingLog.HISTORYLOG_MEMBER_ID:\n                    holder.getTypeView().setText(R.string.label_sharing_log_menu_vsh);\n                    long duration = cursor.getLong(holder.getColumnDurationIdx());\n                    holder.getDescriptionView().setText(\n                            getString(R.string.value_log_duration,\n                                    DateUtils.formatElapsedTime(duration / 1000L)));\n                    break;\n\n                case GeolocSharingLog.HISTORYLOG_MEMBER_ID:\n                    holder.getTypeView().setText(R.string.label_sharing_log_menu_gsh);\n                    String content = cursor.getString(holder.getColumnContentIdx());\n                    holder.getDescriptionView().setText(\n                            TextUtils.isEmpty(content) ? \"\" : truncateString(content,\n                                    MAX_LENGTH_DESCRIPTION));\n                default:\n            }\n        }\n    }\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.history_log_sharing);\n        initialize();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        queryHistoryLogAndRefreshView();\n    }\n\n    private void initialize() {\n        final Runnable updateUi = new Runnable() {\n            @Override\n            public void run() {\n                queryHistoryLogAndRefreshView();\n            }\n        };\n        mImageSharingService = getImageSharingApi();\n        mImageSharingListener = new ImageSharingListener() {\n            @Override\n            public void onStateChanged(ContactId contact, String sharingId, State state,\n                    ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String sharingId, long currentSize,\n                    long totalSize) {\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                Log.d(SharingListView.LOGTAG, \"onDeleted contact=\" + contact + \" for sharing IDs=\"\n                        + Arrays.toString(sharingIds.toArray()));\n                mHandler.post(updateUi);\n            }\n        };\n        mVideoSharingService = getVideoSharingApi();\n        mVideoSharingListener = new VideoSharingListener() {\n            @Override\n            public void onStateChanged(ContactId contact, String sharingId,\n                    VideoSharing.State state, VideoSharing.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                Log.d(SharingListView.LOGTAG, \"onDeleted contact=\" + contact + \" for sharing IDs=\"\n                        + Arrays.toString(sharingIds.toArray()));\n                mHandler.post(updateUi);\n            }\n        };\n        mGeolocSharingService = getGeolocSharingApi();\n        mGeolocSharingListener = new GeolocSharingListener() {\n            @Override\n            public void onStateChanged(ContactId contact, String sharingId,\n                    GeolocSharing.State state, GeolocSharing.ReasonCode reasonCode) {\n            }\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String sharingId, long currentSize,\n                    long totalSize) {\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                Log.d(SharingListView.LOGTAG, \"onDeleted contact=\" + contact + \" for sharing IDs=\"\n                        + Arrays.toString(sharingIds.toArray()));\n                mHandler.post(updateUi);\n            }\n        };\n        mAdapter = new SharingLogAdapter(this);\n        ListView listView = (ListView) findViewById(android.R.id.list);\n        listView.setEmptyView(findViewById(android.R.id.empty));\n        listView.setAdapter(mAdapter);\n        registerForContextMenu(listView);\n\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        mSpinner.setAdapter(ContactListAdapter.createContactListAdapter(this,\n                getString(R.string.label_sharing_log_contact_spinner_default_value)));\n        mSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {\n                /* Call when an item is selected so also at the start of the activity to initialize */\n                queryHistoryLogAndRefreshView();\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n            }\n        });\n        listView.setOnItemClickListener(getOnItemClickListener());\n\n        sProviders.put(ImageSharingLog.HISTORYLOG_MEMBER_ID,\n                getString(R.string.label_sharing_log_menu_ish));\n        sProviders.put(VideoSharingLog.HISTORYLOG_MEMBER_ID,\n                getString(R.string.label_sharing_log_menu_vsh));\n        sProviders.put(GeolocSharingLog.HISTORYLOG_MEMBER_ID,\n                getString(R.string.label_sharing_log_menu_gsh));\n        setProviders(sProviders);\n\n        setCursorLoader(true);\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        try {\n            if (mImageSharingService != null && mImageSharingListenerSet) {\n                mImageSharingService.removeEventListener(mImageSharingListener);\n            }\n            if (mVideoSharingService != null && mVideoSharingListenerSet) {\n                mVideoSharingService.removeEventListener(mVideoSharingListener);\n            }\n            if (mGeolocSharingService != null && mGeolocSharingListenerSet) {\n                mGeolocSharingService.removeEventListener(mGeolocSharingListener);\n            }\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        new MenuInflater(getApplicationContext()).inflate(R.menu.menu_historylog, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_filter:\n                Builder builder = new Builder(this);\n                builder.setTitle(R.string.title_sharing_log_dialog_filter_logs);\n                builder.setMultiChoiceItems(\n                        mFilterMenuItems.toArray(new CharSequence[mFilterMenuItems.size()]),\n                        mCheckedProviders, new DialogInterface.OnMultiChoiceClickListener() {\n                            public void onClick(DialogInterface dialog, int which, boolean isChecked) {\n                                mCheckedProviders[which] = isChecked;\n                            }\n                        });\n                builder.setPositiveButton(R.string.label_ok, new OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        mFilterAlertDialog.dismiss();\n                        queryHistoryLogAndRefreshView();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel, new OnClickListener() {\n                    @Override\n                    public void onClick(DialogInterface dialog, int which) {\n                        mFilterAlertDialog.dismiss();\n                    }\n                });\n                mFilterAlertDialog = builder.show();\n                registerDialog(mFilterAlertDialog);\n                break;\n\n            case R.id.menu_delete:\n                if (!isServiceConnected(RcsServiceName.IMAGE_SHARING, RcsServiceName.VIDEO_SHARING,\n                        RcsServiceName.GEOLOC_SHARING)) {\n                    showMessage(R.string.label_service_not_available);\n                    break;\n                }\n                Log.d(LOGTAG, \"delete all image sharing sessions\");\n                try {\n                    if (!mImageSharingListenerSet) {\n                        mImageSharingService.addEventListener(mImageSharingListener);\n                        mImageSharingListenerSet = true;\n                    }\n                    mImageSharingService.deleteImageSharings();\n                    if (!mVideoSharingListenerSet) {\n                        mVideoSharingService.addEventListener(mVideoSharingListener);\n                        mVideoSharingListenerSet = true;\n                    }\n                    mVideoSharingService.deleteVideoSharings();\n                    if (!mGeolocSharingListenerSet) {\n                        mGeolocSharingService.addEventListener(mGeolocSharingListener);\n                        mGeolocSharingListenerSet = true;\n                    }\n                    mGeolocSharingService.deleteGeolocSharings();\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n\n                }\n                break;\n        }\n        return true;\n    }\n\n    @Override\n    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {\n        super.onCreateContextMenu(menu, v, menuInfo);\n        getMenuInflater().inflate(R.menu.menu_log_sharing_item, menu);\n        menu.findItem(R.id.menu_sharing_display).setVisible(false);\n        // Get the list item position\n        AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;\n        Cursor cursor = (Cursor) mAdapter.getItem(info.position);\n        Direction dir = Direction.valueOf(cursor.getInt(cursor\n                .getColumnIndexOrThrow(HistoryLog.DIRECTION)));\n        String mimeType = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.MIME_TYPE));\n        if (mimeType != null && Utils.isImageType(mimeType)) {\n            if (Direction.INCOMING == dir) {\n                Long transferred = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(HistoryLog.TRANSFERRED));\n                Long fileSize = cursor.getLong(cursor.getColumnIndexOrThrow(HistoryLog.FILESIZE));\n                if (fileSize.equals(transferred)) {\n                    menu.findItem(R.id.menu_sharing_display).setVisible(true);\n                    return;\n                }\n                return;\n            }\n            menu.findItem(R.id.menu_sharing_display).setVisible(true);\n        }\n    }\n\n    @Override\n    public boolean onContextItemSelected(MenuItem item) {\n        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();\n        Cursor cursor = (Cursor) mAdapter.getItem(info.position);\n        int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n        String sharingId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onContextItemSelected sharing ID=\".concat(sharingId));\n        }\n        try {\n            switch (item.getItemId()) {\n                case R.id.menu_sharing_delete:\n                    Log.d(LOGTAG, \"Delete sharing ID=\".concat(sharingId));\n                    switch (providerId) {\n                        case ImageSharingLog.HISTORYLOG_MEMBER_ID:\n                            if (!mImageSharingListenerSet) {\n                                mImageSharingService.addEventListener(mImageSharingListener);\n                                mImageSharingListenerSet = true;\n                            }\n                            mImageSharingService.deleteImageSharing(sharingId);\n                            return true;\n\n                        case VideoSharingLog.HISTORYLOG_MEMBER_ID:\n                            if (!mVideoSharingListenerSet) {\n                                mVideoSharingService.addEventListener(mVideoSharingListener);\n                                mVideoSharingListenerSet = true;\n                            }\n                            mVideoSharingService.deleteVideoSharing(sharingId);\n                            return true;\n                        case GeolocSharingLog.HISTORYLOG_MEMBER_ID:\n                            if (!mGeolocSharingListenerSet) {\n                                mGeolocSharingService.addEventListener(mGeolocSharingListener);\n                                mGeolocSharingListenerSet = true;\n                            }\n                            mGeolocSharingService.deleteGeolocSharing(sharingId);\n                            return true;\n                        default:\n                            return true;\n                    }\n                case R.id.menu_sharing_display:\n                    Utils.showPicture(this, Uri.parse(cursor.getString(cursor\n                            .getColumnIndexOrThrow(HistoryLog.CONTENT))));\n                    return true;\n\n                default:\n                    return super.onContextItemSelected(item);\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            showMessage(R.string.label_service_not_available);\n            return true;\n\n        } catch (RcsGenericException e2) {\n            showExceptionThenExit(e2);\n            return true;\n        }\n    }\n\n    private OnItemClickListener getOnItemClickListener() {\n        return new OnItemClickListener() {\n\n            @Override\n            public void onItemClick(AdapterView<?> parent, View v, int pos, long id) {\n                Cursor cursor = (Cursor) mAdapter.getItem(pos);\n                int providerId = cursor\n                        .getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n                String sharingId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n                switch (providerId) {\n                    case ImageSharingLog.HISTORYLOG_MEMBER_ID:\n                        ImageSharingLogView.startActivity(SharingListView.this, sharingId);\n                        break;\n                    case VideoSharingLog.HISTORYLOG_MEMBER_ID:\n                        VideoSharingLogView.startActivity(SharingListView.this, sharingId);\n                        break;\n                    case GeolocSharingLog.HISTORYLOG_MEMBER_ID:\n                        GeolocSharingLogView.startActivity(SharingListView.this, sharingId);\n                        break;\n                    default:\n                }\n            }\n        };\n    }\n\n    private String getSelectedContact() {\n        MatrixCursor cursor = (MatrixCursor) mSpinner.getSelectedItem();\n        String contact = cursor.getString(1);\n        if (getString(R.string.label_history_log_contact_spinner_default_value).equals(contact)) {\n            return contact;\n        }\n        return ContactUtil.formatContact(contact).toString();\n    }\n\n    /**\n     * A method called to query the history log and refresh view\n     */\n    private void queryHistoryLogAndRefreshView() {\n        Cursor cursor = null;\n        List<Integer> selectedProviderIds = getSelectedProviderIds();\n        String contact = getSelectedContact();\n        if (!selectedProviderIds.isEmpty()) {\n            if (getString(R.string.label_sharing_log_contact_spinner_default_value).equals(contact)) {\n                /*\n                 * No contact is selected\n                 */\n                Uri uri = createSharingLogUri(selectedProviderIds);\n                cursor = getContentResolver().query(uri, PROJECTION, null, null, SORT_BY);\n            } else {\n                Uri uri = createSharingLogUri(selectedProviderIds);\n                cursor = getContentResolver().query(uri, PROJECTION, WHERE_CLAUSE_WITH_CONTACT,\n                        new String[] {\n                            contact\n                        }, SORT_BY);\n            }\n        }\n        mAdapter.changeCursor(cursor);\n    }\n\n    /**\n     * Truncate a string\n     *\n     * @param in string to truncate\n     * @param maxLength maximum length\n     * @return truncated string\n     */\n    private String truncateString(String in, int maxLength) {\n        if (in.length() > maxLength) {\n            in = in.substring(0, maxLength).concat(\"...\");\n        }\n        return \"\\\"\" + in + \"\\\"\";\n    }\n\n    /**\n     * Sets the providers\n     *\n     * @param providers ordered map of providers IDs associated with their name\n     */\n    private void setProviders(TreeMap<Integer, String> providers) {\n        mProviderIds = new ArrayList<>();\n        mFilterMenuItems = new ArrayList<>();\n        for (Entry<Integer, String> entry : providers.entrySet()) {\n            mFilterMenuItems.add(entry.getValue());\n            mProviderIds.add(entry.getKey());\n        }\n        /* Upon setting, all providers are checked True */\n        mCheckedProviders = new boolean[providers.size()];\n        for (int i = 0; i < mCheckedProviders.length; i++) {\n            mCheckedProviders[i] = true;\n        }\n    }\n\n    /**\n     * Gets the list of selected providers IDs\n     *\n     * @return the list of selected providers IDs\n     */\n    private List<Integer> getSelectedProviderIds() {\n        List<Integer> providers = new ArrayList<>();\n        for (int i = 0; i < mCheckedProviders.length; i++) {\n            if (mCheckedProviders[i]) {\n                providers.add(mProviderIds.get(i));\n            }\n        }\n        return providers;\n    }\n\n    /**\n     * Create History URI from list of provider IDs\n     *\n     * @param providerIds list of provider IDs\n     * @return Uri\n     */\n    private Uri createSharingLogUri(List<Integer> providerIds) {\n        HistoryUriBuilder uriBuilder = new HistoryUriBuilder(HistoryLog.CONTENT_URI);\n        for (Integer providerId : providerIds) {\n            uriBuilder.appendProvider(providerId);\n        }\n        return uriBuilder.build();\n    }\n\n    private void setCursorLoader(boolean firstLoad) {\n        if (firstLoad) {\n            // Initialize the Loader with id '1' and callbacks 'mCallbacks'.\n            getSupportLoaderManager().initLoader(LOADER_ID, null, this);\n        } else {\n            // We switched from one contact to another: reload history since.\n            getSupportLoaderManager().restartLoader(LOADER_ID, null, this);\n        }\n    }\n\n    @Override\n    public Loader<Cursor> onCreateLoader(int id, Bundle args) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onCreateLoader \" + id);\n        }\n        List<Integer> selectedProviderIds = getSelectedProviderIds();\n        String contact = getSelectedContact();\n        if (!selectedProviderIds.isEmpty()) {\n            Uri uri = createSharingLogUri(selectedProviderIds);\n            // Create a new CursorLoader with the following query parameters.\n            if (getString(R.string.label_sharing_log_contact_spinner_default_value).equals(contact)) {\n                // No contact is selected\n                return new CursorLoader(this, uri, PROJECTION, null, null, SORT_BY);\n            }\n            return new CursorLoader(this, uri, PROJECTION, WHERE_CLAUSE_WITH_CONTACT, new String[] {\n                contact\n            }, SORT_BY);\n        }\n        return null;\n    }\n\n    @Override\n    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onLoadFinished \" + loader.getId());\n        }\n        // A switch-case is useful when dealing with multiple Loaders/IDs\n        switch (loader.getId()) {\n            case LOADER_ID:\n                // The asynchronous load is complete and the data\n                // is now available for use. Only now can we associate\n                // the queried Cursor with the CursorAdapter.\n                mAdapter.swapCursor(cursor);\n                break;\n        }\n        // The listview now displays the queried data.\n    }\n\n    @Override\n    public void onLoaderReset(Loader<Cursor> loader) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onLoaderReset \" + loader.getId());\n        }\n        // For whatever reason, the Loader's data is now unavailable.\n        // Remove any references to the old data by replacing it with a null\n        // Cursor.\n        mAdapter.swapCursor(null);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/TestSharingApi.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.sharing.geoloc.InitiateGeolocSharing;\nimport com.gsma.rcs.ri.sharing.image.InitiateImageSharing;\nimport com.gsma.rcs.ri.sharing.video.OutgoingVideoSharing;\n\nimport android.app.ListActivity;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\n\n/**\n * Sharing API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TestSharingApi extends ListActivity {\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Set layout\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n\n        // Set items\n        // @formatter:off\n        String[] items = {\n                getString(R.string.menu_initiate_image_sharing),\n                getString(R.string.menu_initiate_video_sharing),\n                getString(R.string.menu_initiate_geoloc_sharing),\n                getString(R.string.menu_log_sharing)\n        };\n        // @formatter:on\n\n        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items));\n    }\n\n    @Override\n    protected void onListItemClick(ListView l, View v, int position, long id) {\n        switch (position) {\n            case 0:\n                startActivity(new Intent(this, InitiateImageSharing.class));\n                break;\n\n            case 1:\n                startActivity(new Intent(this, OutgoingVideoSharing.class));\n                break;\n\n            case 2:\n                startActivity(new Intent(this, InitiateGeolocSharing.class));\n                break;\n\n            case 3:\n                startActivity(new Intent(this, SharingListView.class));\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/geoloc/GeolocSharingDAO.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.geoloc;\n\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\n\n/**\n * Geolocation sharing Data Object\n * \n * @author Philippe LEMORDANT\n */\npublic class GeolocSharingDAO {\n\n    private final String mSharingId;\n\n    private final ContactId mContact;\n\n    private final State mState;\n\n    private final ReasonCode mReasonCode;\n\n    private final Direction mDirection;\n\n    private final String mMimeType;\n\n    private final String mContent;\n\n    private final long mTimestamp;\n\n    private static ContentResolver sContentResolver;\n\n    private GeolocSharingDAO(String sharingId, ContactId contact, State state,\n            ReasonCode reasonCode, Direction dir, String mimeType, String content, long timestamp) {\n        mSharingId = sharingId;\n        mContact = contact;\n        mState = state;\n        mReasonCode = reasonCode;\n        mDirection = dir;\n        mMimeType = mimeType;\n        mContent = content;\n        mTimestamp = timestamp;\n    }\n\n    public String getSharingId() {\n        return mSharingId;\n    }\n\n    public GeolocSharing.State getState() {\n        return mState;\n    }\n\n    public String getContent() {\n        return mContent;\n    }\n\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    /**\n     * Gets instance of chat message from RCS provider\n     * \n     * @param ctx the context\n     * @param sharingId the sharing ID\n     * @return instance or null if entry not found\n     */\n    public static GeolocSharingDAO getGeolocSharing(Context ctx, String sharingId) {\n        if (sContentResolver == null) {\n            sContentResolver = ctx.getContentResolver();\n        }\n        Cursor cursor = null;\n        try {\n            cursor = sContentResolver.query(\n                    Uri.withAppendedPath(GeolocSharingLog.CONTENT_URI, sharingId), null, null,\n                    null, null);\n            if (cursor == null) {\n                throw new SQLException(\"Query failed!\");\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.CONTACT));\n            ContactId contactId = null;\n            if (contact != null) {\n                contactId = ContactUtil.formatContact(contact);\n            }\n            String mimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.MIME_TYPE));\n            String content = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.CONTENT));\n            State state = State.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.STATE)));\n            Direction dir = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.DIRECTION)));\n            long timestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.TIMESTAMP));\n            ReasonCode reasonCode = ReasonCode.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(GeolocSharingLog.REASON_CODE)));\n            return new GeolocSharingDAO(sharingId, contactId, state, reasonCode, dir, mimeType,\n                    content, timestamp);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/geoloc/GeolocSharingIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.geoloc;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingIntent;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.media.RingtoneManager;\nimport android.os.Bundle;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\n/**\n * Geoloc sharing intent service\n * \n * @author YPLO6403\n */\npublic class GeolocSharingIntentService extends IntentService {\n\n    private static final String LOGTAG = LogUtils.getTag(GeolocSharingIntentService.class\n            .getSimpleName());\n\n    static final String BUNDLE_GSH_ID = \"bundle_gsh\";\n\n    /**\n     * Creates an IntentService.\n     */\n    public GeolocSharingIntentService() {\n        super(\"GeolocSharingIntentService\");\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        /*\n         * We want this service to stop running if forced stop so return not sticky.\n         */\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n        /* Check action from incoming intent */\n        if (!GeolocSharingIntent.ACTION_NEW_INVITATION.equals(action)) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Unknown action \".concat(action));\n            }\n            return;\n        }\n        /* Gets data from the incoming Intent */\n        String sharingId = intent.getStringExtra(GeolocSharingIntent.EXTRA_SHARING_ID);\n        if (sharingId == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read sharing ID\");\n            }\n            return;\n        }\n        GeolocSharingDAO gshSharing = GeolocSharingDAO.getGeolocSharing(this, sharingId);\n        if (gshSharing == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot get geoloc sharing for \".concat(sharingId));\n            }\n            return;\n        }\n        ContactId contact = gshSharing.getContact();\n        if (contact == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot get contact sharing for \".concat(sharingId));\n            }\n            return;\n        }\n        /* Save contact into intent */\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(BUNDLE_GSH_ID, contact);\n        intent.putExtras(bundle);\n        /* Display invitation notification */\n        addGeolocSharingInvitationNotification(intent, contact);\n    }\n\n    /**\n     * Add geoloc share notification\n     * \n     * @param invitation intent\n     */\n    private void addGeolocSharingInvitationNotification(Intent invitation, ContactId contact) {\n        /* Create pending intent */\n        Intent intent = new Intent(invitation);\n        intent.setClass(this, ReceiveGeolocSharing.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        /*\n         * If the PendingIntent has the same operation, action, data, categories, components, and\n         * flags it will be replaced. Invitation should be notified individually so we use a random\n         * generator to provide a unique request code and reuse it for the notification.\n         */\n        int uniqueId = Utils.getUniqueIdForPendingIntent();\n        PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                PendingIntent.FLAG_ONE_SHOT);\n\n        String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n        String title = getString(R.string.title_recv_geoloc_sharing);\n\n        /* Create notification */\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(contentIntent);\n        notif.setSmallIcon(R.drawable.ri_notif_csh_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(title);\n        notif.setContentText(getString(R.string.label_from_args, displayName));\n\n        /* Send notification */\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(uniqueId, notif.build());\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/geoloc/GeolocSharingInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.geoloc;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Geoloc sharing invitation receiver\n * \n * @author vfml3370\n */\npublic class GeolocSharingInvitationReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, GeolocSharingIntentService.class);\n        context.startService(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/geoloc/GeolocSharingLogView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.geoloc;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * A class to view the persisted information for geolocation sharing.<br>\n * Created by Philippe LEMORDANT.\n */\npublic class GeolocSharingLogView extends RcsActivity {\n\n    private static final String EXTRA_SHARING_ID = \"id\";\n    private String mSharingId;\n    private TextView mTxtViewContact;\n    private TextView mTxtViewContent;\n    private TextView mTxtViewDate;\n    private TextView mTxtViewDir;\n    private TextView mTxtViewMime;\n    private TextView mTxtViewReason;\n    private TextView mTxtViewState;\n    private SimpleDateFormat sDateFormat;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.sharing_log_geoloc_item);\n        mSharingId = getIntent().getStringExtra(EXTRA_SHARING_ID);\n        initialize();\n    }\n\n    private void initialize() {\n        mTxtViewContact = (TextView) findViewById(R.id.history_log_item_contact);\n        mTxtViewState = (TextView) findViewById(R.id.history_log_item_state);\n        mTxtViewReason = (TextView) findViewById(R.id.history_log_item_reason);\n        mTxtViewDir = (TextView) findViewById(R.id.history_log_item_direction);\n        mTxtViewDate = (TextView) findViewById(R.id.history_log_item_date);\n        mTxtViewMime = (TextView) findViewById(R.id.history_log_item_mime);\n        mTxtViewContent = (TextView) findViewById(R.id.history_log_item_content);\n    }\n\n    private String getDateFromDb(long timestamp) {\n        if (0 == timestamp) {\n            return \"\";\n        }\n        if (sDateFormat == null) {\n            sDateFormat = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\", Locale.getDefault());\n        }\n        return sDateFormat.format(new Date(timestamp));\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        GeolocSharingDAO dao = GeolocSharingDAO.getGeolocSharing(this, mSharingId);\n        if (dao == null) {\n            showMessageThenExit(R.string.error_item_not_found);\n            return;\n        }\n        mTxtViewContact.setText(dao.getContact().toString());\n        mTxtViewState.setText(RiApplication.sGeolocSharingStates[dao.getState().toInt()]);\n        mTxtViewReason.setText(RiApplication.sGeolocReasonCodes[dao.getReasonCode().toInt()]);\n        mTxtViewDir.setText(RiApplication.getDirection(dao.getDirection()));\n        mTxtViewDate.setText(getDateFromDb(dao.getTimestamp()));\n        mTxtViewMime.setText(dao.getMimeType());\n        mTxtViewContent.setText(String.valueOf(dao.getContent()));\n    }\n\n    /**\n     * Start activity to view details of geolocation sharing record\n     * \n     * @param context the context\n     * @param sharingId the sharing ID\n     */\n    public static void startActivity(Context context, String sharingId) {\n        Intent intent = new Intent(context, GeolocSharingLogView.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(EXTRA_SHARING_ID, sharingId);\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/geoloc/InitiateGeolocSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.geoloc;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.messaging.geoloc.EditGeoloc;\nimport com.gsma.rcs.ri.messaging.geoloc.ShowGeoloc;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.ActivityCompat;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.ProgressBar;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.util.Set;\n\n/**\n * Initiate geoloc sharing\n *\n * @author vfml3370\n * @author Philippe LEMORDANT\n */\npublic class InitiateGeolocSharing extends RcsActivity {\n    /**\n     * Activity result constants\n     */\n    private final static int SELECT_GEOLOCATION = 0;\n\n    /**\n     * UI handler\n     */\n    private final Handler mHandler = new Handler();\n    private Geoloc mGeoloc;\n    private GeolocSharing mGeolocSharing;\n    private String mSharingId;\n\n    private static final String LOGTAG = LogUtils.getTag(InitiateGeolocSharing.class.getName());\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n    private GeolocSharingListener mListener;\n    private GeolocSharingService mGeolocSharingService;\n    private Button mInviteBtn;\n    private ProgressBar mProgressBar;\n    private Button mSelectBtn;\n    private TextView mStatusView;\n    private Button mDialBtn;\n    private TextView mPositionView;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.geoloc_sharing_initiate);\n        initialize();\n        if (!isServiceConnected(RcsServiceName.GEOLOC_SHARING)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.GEOLOC_SHARING);\n        try {\n            mGeolocSharingService.addEventListener(mListener);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (mGeolocSharingService != null && isServiceConnected(RcsServiceName.GEOLOC_SHARING)) {\n            try {\n                mGeolocSharingService.removeEventListener(mListener);\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK) {\n            return;\n        }\n        switch (requestCode) {\n            case SELECT_GEOLOCATION:\n                /* Get selected geoloc */\n                mGeoloc = data.getParcelableExtra(EditGeoloc.EXTRA_GEOLOC);\n                mPositionView.setText(mGeoloc.toString());\n                /* Enable invite button */\n                mInviteBtn.setEnabled(true);\n                break;\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        double position = 0.0d;\n        if (totalSize != 0) {\n            mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n            position = (((double) currentSize) / ((double) totalSize)) * 100.0d;\n        } else {\n            mStatusView.setText(\"\");\n        }\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mGeolocSharing != null && GeolocSharing.State.STARTED == mGeolocSharing.getState()) {\n                mGeolocSharing.abortSharing();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mGeolocSharing = null;\n            /* Exit activity */\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            quitSession();\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_geoloc_sharing, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void initialize() {\n        mGeolocSharingService = getGeolocSharingApi();\n\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        ContactListAdapter adapter = ContactListAdapter.createRcsContactListAdapter(this);\n        mSpinner.setAdapter(adapter);\n\n        OnClickListener btnInviteListener = new OnClickListener() {\n            public void onClick(View v) {\n                // Check if the service is available\n                try {\n                    if (!mGeolocSharingService.isServiceRegistered()) {\n                        showMessage(R.string.error_not_registered);\n                        return;\n                    }\n                    // get selected phone number\n                    ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n                    String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n                    ContactId contact = ContactUtil.formatContact(phoneNumber);\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"share geoloc=\" + mGeoloc + \" contact=\" + contact);\n                    }\n                    mGeolocSharing = mGeolocSharingService.shareGeoloc(contact, mGeoloc);\n                    mSharingId = mGeolocSharing.getSharingId();\n                    mSpinner.setEnabled(false);\n                    mInviteBtn.setVisibility(View.INVISIBLE);\n                    mSelectBtn.setVisibility(View.INVISIBLE);\n                    mDialBtn.setVisibility(View.INVISIBLE);\n\n                } catch (RcsServiceNotAvailableException e) {\n                    showMessage(R.string.label_service_not_available);\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        mInviteBtn = (Button) findViewById(R.id.invite_btn);\n        mInviteBtn.setOnClickListener(btnInviteListener);\n        mInviteBtn.setEnabled(false);\n\n        OnClickListener btnSelectListener = new OnClickListener() {\n            public void onClick(View v) {\n                // Start a new activity to send a geolocation\n                startActivityForResult(new Intent(InitiateGeolocSharing.this, EditGeoloc.class),\n                        SELECT_GEOLOCATION);\n            }\n        };\n        mSelectBtn = (Button) findViewById(R.id.select_btn);\n        mSelectBtn.setOnClickListener(btnSelectListener);\n        mSelectBtn.setEnabled(false);\n\n        OnClickListener btnDialListener = new OnClickListener() {\n            public void onClick(View v) {\n                // get selected phone number\n                ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n                String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n\n                // Initiate a GSM call before to be able to share content\n                Intent intent = new Intent(Intent.ACTION_CALL);\n                intent.setData(Uri.parse(\"tel:\".concat(phoneNumber)));\n                if (ActivityCompat.checkSelfPermission(InitiateGeolocSharing.this,\n                        Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {\n                    return;\n                }\n                startActivity(intent);\n            }\n        };\n        mDialBtn = (Button) findViewById(R.id.dial_btn);\n        mDialBtn.setOnClickListener(btnDialListener);\n        mDialBtn.setEnabled(false);\n\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mPositionView = (TextView) findViewById(R.id.position);\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n        updateProgressBar(0, 0);\n        mPositionView.setText(\"\");\n\n        if (adapter == null || adapter.getCount() != 0) {\n            mDialBtn.setEnabled(true);\n            mSelectBtn.setEnabled(true);\n        }\n        mListener = new GeolocSharingListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String sharingId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current sharingId */\n                if (InitiateGeolocSharing.this.mSharingId == null\n                        || !InitiateGeolocSharing.this.mSharingId.equals(sharingId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(final ContactId contact, String sharingId,\n                    final GeolocSharing.State state, GeolocSharing.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" sharingId=\" + sharingId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current sharingId */\n                if (InitiateGeolocSharing.this.mSharingId == null\n                        || !InitiateGeolocSharing.this.mSharingId.equals(sharingId)) {\n                    return;\n                }\n                final String _state = RiApplication.sGeolocSharingStates[state.toInt()];\n                final String _reasonCode = RiApplication.sGeolocReasonCodes[reasonCode.toInt()];\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        TextView statusView = (TextView) findViewById(R.id.progress_status);\n                        switch (state) {\n                            case STARTED:\n                                // Display session status\n                                statusView.setText(_state);\n                                break;\n\n                            case ABORTED:\n                                showMessageThenExit(getString(R.string.label_sharing_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                showMessageThenExit(getString(R.string.label_sharing_rejected,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                showMessageThenExit(getString(R.string.label_sharing_failed,\n                                        _reasonCode));\n                                break;\n\n                            case TRANSFERRED:\n                                /* Display transfer progress */\n                                statusView.setText(_state);\n                                /* Make sure progress bar is at the end */\n                                ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);\n                                progressBar.setProgress(progressBar.getMax());\n\n                                ShowGeoloc.ShowGeolocForContact(InitiateGeolocSharing.this,\n                                        contact, mGeoloc);\n                                break;\n\n                            default:\n                                statusView.setText(getString(R.string.label_gsh_state_changed,\n                                        _state, _reasonCode));\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" sharingIds=\" + sharingIds);\n                }\n            }\n\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/geoloc/ReceiveGeolocSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.geoloc;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.messaging.geoloc.ShowGeoloc;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingIntent;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport java.util.Set;\n\n/**\n * Receive geoloc sharing\n * \n * @author vfml3370\n * @author yplo6403\n */\npublic class ReceiveGeolocSharing extends RcsActivity {\n    /**\n     * UI handler\n     */\n    private final Handler mHandler = new Handler();\n    private String mSharingId;\n    private ContactId mRemoteContact;\n\n    /**\n     * Geoloc sharing session\n     */\n    private GeolocSharing mGeolocSharing;\n    private Geoloc mGeoloc;\n\n    private static final String LOGTAG = LogUtils.getTag(ReceiveGeolocSharing.class.getName());\n\n    private GeolocSharingListener mListener;\n    private OnClickListener mAcceptBtnListener;\n    private OnClickListener mDeclineBtnListener;\n    private ProgressBar mProgressBar;\n    private boolean mSessionListenerSet;\n    private TextView mStatusView;\n    private TextView mPositionView;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.geoloc_sharing_receive);\n\n        initialize();\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.GEOLOC_SHARING, RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.GEOLOC_SHARING, RcsServiceName.CONTACT);\n        processIntent(getIntent());\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (!mSessionListenerSet || !isServiceConnected(RcsServiceName.GEOLOC_SHARING)) {\n            return;\n        }\n        try {\n            getGeolocSharingApi().removeEventListener(mListener);\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        setIntent(intent);\n        processIntent(intent);\n    }\n\n    private void processIntent(Intent invitation) {\n        mSharingId = invitation.getStringExtra(GeolocSharingIntent.EXTRA_SHARING_ID);\n        mRemoteContact = invitation.getParcelableExtra(GeolocSharingIntentService.BUNDLE_GSH_ID);\n        initiateGeolocSharing();\n    }\n\n    private void initiateGeolocSharing() {\n        GeolocSharingService gshApi = getGeolocSharingApi();\n        try {\n            // Get the geoloc sharing\n            mGeolocSharing = gshApi.getGeolocSharing(mSharingId);\n            if (mGeolocSharing == null) {\n                // Session not found or expired\n                showMessageThenExit(R.string.label_session_not_found);\n                return;\n            }\n            mSessionListenerSet = true;\n            gshApi.addEventListener(mListener);\n\n            /* Display sharing infos */\n            String from = RcsContactUtil.getInstance(this).getDisplayName(mRemoteContact);\n            TextView fromTextView = (TextView) findViewById(R.id.contact);\n            fromTextView.setText(from);\n            mPositionView = (TextView) findViewById(R.id.position);\n            mProgressBar.setProgress(0);\n            mPositionView.setText(\"\");\n\n            /* Display accept/reject dialog */\n            AlertDialog.Builder builder = new AlertDialog.Builder(this);\n            builder.setTitle(R.string.title_geoloc_sharing);\n            builder.setMessage(getString(R.string.label_from_args, from));\n            builder.setCancelable(false);\n            builder.setIcon(R.drawable.ri_notif_gsh_icon);\n            builder.setPositiveButton(R.string.label_accept, mAcceptBtnListener);\n            builder.setNegativeButton(R.string.label_decline, mDeclineBtnListener);\n            registerDialog(builder.show());\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void acceptInvitation() {\n        try {\n            mGeolocSharing.acceptInvitation();\n        } catch (RcsGenericException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void rejectInvitation() {\n        try {\n            mGeolocSharing.rejectInvitation();\n        } catch (RcsGenericException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n        double position = ((double) currentSize / (double) totalSize) * 100.0d;\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mGeolocSharing != null && GeolocSharing.State.STARTED == mGeolocSharing.getState()) {\n                mGeolocSharing.abortSharing();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        } finally {\n            mGeolocSharing = null;\n            /* Exit activity */\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            quitSession();\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_image_sharing, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void initialize() {\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mListener = new GeolocSharingListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String sharingId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current sharingId */\n                if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(final ContactId contact, final String sharingId,\n                    final GeolocSharing.State state, GeolocSharing.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact.toString() + \" sharingId=\"\n                            + sharingId + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current sharingId */\n                if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sGeolocReasonCodes[reasonCode.toInt()];\n                final String _state = RiApplication.sGeolocSharingStates[state.toInt()];\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        switch (state) {\n                            case ABORTED:\n                                String msg = getString(R.string.label_sharing_aborted, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case FAILED:\n                                msg = getString(R.string.label_sharing_failed, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case TRANSFERRED:\n                                /* Display transfer progress */\n                                mStatusView.setText(_state);\n                                /* Make sure progress bar is at the end */\n                                mProgressBar.setProgress(mProgressBar.getMax());\n\n                                /* Show the shared geoloc */\n                                try {\n                                    mGeoloc = mGeolocSharing.getGeoloc();\n                                    mPositionView.setText(mGeoloc.toString());\n                                    ShowGeoloc.ShowGeolocForContact(ReceiveGeolocSharing.this,\n                                            contact, mGeoloc);\n                                } catch (RcsServiceException e) {\n                                    if (LogUtils.isActive) {\n                                        Log.d(LOGTAG, \"onStateChanged failed to get geoloc for \"\n                                                .concat(sharingId));\n                                    }\n                                }\n                                break;\n\n                            default:\n                                mStatusView.setText(_state);\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG, \"onStateChanged \".concat(getString(\n                                            R.string.label_gsh_state_changed, _state, _reasonCode)));\n                                }\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" sharingIds=\" + sharingIds);\n                }\n            }\n\n        };\n        mAcceptBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                acceptInvitation();\n            }\n        };\n        mDeclineBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                rejectInvitation();\n                finish();\n            }\n        };\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/image/ImageSharingDAO.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.image;\n\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * Image Sharing Data Object\n *\n * @author YPLO6403\n */\npublic class ImageSharingDAO implements Parcelable {\n\n    private final String mSharingId;\n\n    private final ContactId mContact;\n\n    private final Uri mFile;\n\n    private final String mFilename;\n\n    private final String mMimeType;\n\n    private final ImageSharing.State mState;\n\n    private final Direction mDirection;\n\n    private final long mTimestamp;\n\n    private final long mSizeTransferred;\n\n    private final long mSize;\n\n    private final ImageSharing.ReasonCode mReasonCode;\n\n    private static ContentResolver sContentResolver;\n\n    private ImageSharingDAO(String sharingId, ContactId contact, Uri file, String filename,\n            String mimeType, ImageSharing.State state, Direction direction, long timestamp,\n            long sizeTransferred, long size, ImageSharing.ReasonCode reasonCode) {\n        mSharingId = sharingId;\n        mContact = contact;\n        mFile = file;\n        mFilename = filename;\n        mMimeType = mimeType;\n        mState = state;\n        mDirection = direction;\n        mTimestamp = timestamp;\n        mSizeTransferred = sizeTransferred;\n        mSize = size;\n        mReasonCode = reasonCode;\n    }\n\n    /**\n     * Constructor\n     *\n     * @param source Parcelable source\n     */\n    public ImageSharingDAO(Parcel source) {\n        mSharingId = source.readString();\n        boolean containsContactId = source.readInt() != 0;\n        if (containsContactId) {\n            mContact = ContactId.CREATOR.createFromParcel(source);\n        } else {\n            mContact = null;\n        }\n        boolean containsFile = source.readInt() != 0;\n        if (containsFile) {\n            mFile = Uri.parse(source.readString());\n        } else {\n            mFile = null;\n        }\n        mFilename = source.readString();\n        mMimeType = source.readString();\n        mState = ImageSharing.State.valueOf(source.readInt());\n        mDirection = Direction.valueOf(source.readInt());\n        mTimestamp = source.readLong();\n        mSizeTransferred = source.readLong();\n        mSize = source.readLong();\n        mReasonCode = ImageSharing.ReasonCode.valueOf(source.readInt());\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mSharingId);\n        if (mContact != null) {\n            dest.writeInt(1);\n            mContact.writeToParcel(dest, flags);\n        } else {\n            dest.writeInt(0);\n        }\n        if (mFile != null) {\n            dest.writeInt(1);\n            dest.writeString(mFile.toString());\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeString(mFilename);\n        dest.writeString(mMimeType);\n        dest.writeInt(mState.toInt());\n        dest.writeInt(mDirection.toInt());\n        dest.writeLong(mTimestamp);\n        dest.writeLong(mSizeTransferred);\n        dest.writeLong(mSize);\n        dest.writeInt(mReasonCode.toInt());\n    }\n\n    /**\n     * Gets state\n     *\n     * @return state\n     */\n    public ImageSharing.State getState() {\n        return mState;\n    }\n\n    /**\n     * Gets transferred size\n     *\n     * @return size\n     */\n    public long getSizeTransferred() {\n        return mSizeTransferred;\n    }\n\n    /**\n     * Gets sharing ID\n     *\n     * @return sharingId\n     */\n    public String getSharingId() {\n        return mSharingId;\n    }\n\n    /**\n     * Gets remote contact\n     *\n     * @return contact\n     */\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    /**\n     * Gets file URI\n     *\n     * @return file URI\n     */\n    public Uri getFile() {\n        return mFile;\n    }\n\n    /**\n     * Gets file name\n     *\n     * @return file name\n     */\n    public String getFilename() {\n        return mFilename;\n    }\n\n    /**\n     * Gets mime type\n     *\n     * @return mime type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    /**\n     * Gets date of the sharing\n     *\n     * @return time stamp\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Gets size\n     *\n     * @return size\n     */\n    public long getSize() {\n        return mSize;\n    }\n\n    /**\n     * Gets reason code\n     *\n     * @return reason code\n     */\n    public ImageSharing.ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    /**\n     * Gets instance of Image sharing from RCS provider\n     *\n     * @param ctx the context\n     * @param sharingId the sharing ID\n     * @return instance or null if entry not found\n     */\n    public static ImageSharingDAO getImageSharingDAO(Context ctx, String sharingId) {\n        if (sContentResolver == null) {\n            sContentResolver = ctx.getContentResolver();\n        }\n        Cursor cursor = null;\n        try {\n            cursor = sContentResolver.query(\n                    Uri.withAppendedPath(ImageSharingLog.CONTENT_URI, sharingId), null, null, null,\n                    null);\n            if (cursor == null) {\n                throw new SQLException(\"Query failed!\");\n            }\n            if (!cursor.moveToFirst()) {\n                throw new SQLException(\"Failed to find Image Sharing with ID: \".concat(sharingId));\n            }\n            String number = cursor.getString(cursor.getColumnIndexOrThrow(ImageSharingLog.CONTACT));\n            ContactId contact = ContactUtil.formatContact(number);\n            Uri file = Uri.parse(cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.FILE)));\n            String filename = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.FILENAME));\n            String mimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.MIME_TYPE));\n            ImageSharing.State state = ImageSharing.State.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.STATE)));\n            Direction dir = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.DIRECTION)));\n            long timestamp = cursor\n                    .getLong(cursor.getColumnIndexOrThrow(ImageSharingLog.TIMESTAMP));\n            long sizeTransferred = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.TRANSFERRED));\n            long size = cursor.getLong(cursor.getColumnIndexOrThrow(ImageSharingLog.FILESIZE));\n            ImageSharing.ReasonCode reason = ImageSharing.ReasonCode.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ImageSharingLog.REASON_CODE)));\n            return new ImageSharingDAO(sharingId, contact, file, filename, mimeType, state, dir,\n                    timestamp, sizeTransferred, size, reason);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    @Override\n    public String toString() {\n        return \"ImageSharingDAO [sharingId=\" + mSharingId + \", contact=\" + mContact + \", file=\"\n                + mFile + \", filename=\" + mFilename + \", mimeType=\" + mMimeType + \", state=\"\n                + mState + \", size=\" + mSize + \"]\";\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * public CREATOR field that generates instances of Parcelable class from a ImageSharingDAO.\n     */\n    public static final Parcelable.Creator<ImageSharingDAO> CREATOR = new Parcelable.Creator<ImageSharingDAO>() {\n        @Override\n        public ImageSharingDAO createFromParcel(Parcel in) {\n            return new ImageSharingDAO(in);\n        }\n\n        @Override\n        public ImageSharingDAO[] newArray(int size) {\n            return new ImageSharingDAO[size];\n        }\n    };\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/image/ImageSharingIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.image;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingIntent;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.media.RingtoneManager;\nimport android.os.Bundle;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\n/**\n * Image sharing intent service\n * \n * @author YPLO6403\n */\npublic class ImageSharingIntentService extends IntentService {\n\n    private static final String LOGTAG = LogUtils.getTag(ImageSharingIntentService.class\n            .getSimpleName());\n\n    static final String BUNDLE_ISHDAO_ID = \"ishdao\";\n\n    /**\n     * Creates an IntentService.\n     */\n    public ImageSharingIntentService() {\n        super(\"ImageSharingIntentService\");\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        // We want this service to stop running if forced stop\n        // so return not sticky.\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n        // Check action from incoming intent\n        if (!ImageSharingIntent.ACTION_NEW_INVITATION.equals(action)) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Unknown action \".concat(action));\n            }\n            return;\n        }\n        // Gets data from the incoming Intent\n        String sharingId = intent.getStringExtra(ImageSharingIntent.EXTRA_SHARING_ID);\n        if (sharingId == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read sharing ID\");\n            }\n            return;\n        }\n        // Get Image sharing from provider\n        ImageSharingDAO ishDao = ImageSharingDAO.getImageSharingDAO(this, sharingId);\n        if (ishDao == null) {\n            return;\n        }\n        // Save ImageSharingDAO into intent\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(BUNDLE_ISHDAO_ID, ishDao);\n        intent.putExtras(bundle);\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"ISH invitation \".concat(ishDao.toString()));\n        }\n        if (ImageSharing.State.INVITED == ishDao.getState()) {\n            addImageSharingInvitationNotification(intent, ishDao);\n        }\n    }\n\n    /**\n     * Add image share notification\n     * \n     * @param invitation Intent invitation\n     * @param ishDao the image sharing data object\n     */\n    private void addImageSharingInvitationNotification(Intent invitation, ImageSharingDAO ishDao) {\n        ContactId contact = ishDao.getContact();\n        if (contact == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"addImageSharingInvitationNotification failed: cannot parse contact\");\n            }\n            return;\n        }\n        /* Create pending intent */\n        Intent intent = new Intent(invitation);\n        intent.setClass(this, ReceiveImageSharing.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        /*\n         * If the PendingIntent has the same operation, action, data, categories, components, and\n         * flags it will be replaced. Invitation should be notified individually so we use a random\n         * generator to provide a unique request code and reuse it for the notification.\n         */\n        int uniqueId = Utils.getUniqueIdForPendingIntent();\n        PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                PendingIntent.FLAG_ONE_SHOT);\n\n        String displayName = RcsContactUtil.getInstance(this).getDisplayName(contact);\n        String title = getString(R.string.title_recv_image_sharing);\n\n        /* Create notification */\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(contentIntent);\n        notif.setSmallIcon(R.drawable.ri_notif_csh_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(title);\n        notif.setContentText(getString(R.string.label_from_args, displayName));\n\n        /* Send notification */\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(uniqueId, notif.build());\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/image/ImageSharingInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.image;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Image sharing invitation receiver\n * \n * @author YPLO6403\n */\npublic class ImageSharingInvitationReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, ImageSharingIntentService.class);\n        context.startService(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/image/ImageSharingLogView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.image;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * A class to view the persisted information for image sharing<br>\n * Created by Philippe LEMORDANT.\n */\npublic class ImageSharingLogView extends RcsActivity {\n    private static final String EXTRA_SHARING_ID = \"id\";\n    private String mSharingId;\n    private TextView mTxtViewContact;\n    private TextView mTxtViewDate;\n    private TextView mTxtViewDir;\n    private TextView mTxtViewFileSize;\n    private TextView mTxtViewFilename;\n    private TextView mTxtViewMime;\n    private TextView mTxtViewReason;\n    private TextView mTxtViewState;\n    private TextView mTxtViewTransferred;\n    private TextView mTxtViewUri;\n    private SimpleDateFormat sDateFormat;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.sharing_log_image_item);\n        mSharingId = getIntent().getStringExtra(EXTRA_SHARING_ID);\n        initialize();\n    }\n\n    private void initialize() {\n        mTxtViewContact = (TextView) findViewById(R.id.history_log_item_contact);\n        mTxtViewState = (TextView) findViewById(R.id.history_log_item_state);\n        mTxtViewReason = (TextView) findViewById(R.id.history_log_item_reason);\n        mTxtViewDir = (TextView) findViewById(R.id.history_log_item_direction);\n        mTxtViewDate = (TextView) findViewById(R.id.history_log_item_date);\n        mTxtViewMime = (TextView) findViewById(R.id.history_log_item_mime);\n        mTxtViewFilename = (TextView) findViewById(R.id.history_log_item_filename);\n        mTxtViewFileSize = (TextView) findViewById(R.id.history_log_item_size);\n        mTxtViewUri = (TextView) findViewById(R.id.history_log_item_uri);\n        mTxtViewTransferred = (TextView) findViewById(R.id.history_log_item_transferred);\n    }\n\n    private String getDateFromDb(long timestamp) {\n        if (0 == timestamp) {\n            return \"\";\n        }\n        if (sDateFormat == null) {\n            sDateFormat = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\", Locale.getDefault());\n        }\n        return sDateFormat.format(new Date(timestamp));\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        ImageSharingDAO dao = ImageSharingDAO.getImageSharingDAO(this, mSharingId);\n        if (dao == null) {\n            showMessageThenExit(R.string.error_item_not_found);\n            return;\n        }\n        mTxtViewContact.setText(dao.getContact().toString());\n        mTxtViewState.setText(RiApplication.sImageSharingStates[dao.getState().toInt()]);\n        mTxtViewReason.setText(RiApplication.sImageSharingReasonCodes[dao.getReasonCode().toInt()]);\n        mTxtViewDir.setText(RiApplication.getDirection(dao.getDirection()));\n        mTxtViewDate.setText(getDateFromDb(dao.getTimestamp()));\n        mTxtViewMime.setText(dao.getMimeType());\n        mTxtViewFilename.setText(dao.getFilename());\n        mTxtViewFileSize.setText(String.valueOf(dao.getSize()));\n        mTxtViewUri.setText(dao.getFile().toString());\n        mTxtViewTransferred.setText(String.valueOf(dao.getSizeTransferred()));\n    }\n\n    /**\n     * Start activity to view details of image sharing record\n     * \n     * @param context the context\n     * @param sharingId the sharing ID\n     */\n    public static void startActivity(Context context, String sharingId) {\n        Intent intent = new Intent(context, ImageSharingLogView.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(EXTRA_SHARING_ID, sharingId);\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/image/InitiateImageSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.image;\n\nimport static com.gsma.rcs.ri.utils.FileUtils.takePersistableContentUriPermission;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingListener;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\n\nimport android.Manifest;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.ActivityCompat;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.ProgressBar;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.util.Set;\n\n/**\n * Initiate image sharing\n *\n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class InitiateImageSharing extends RcsActivity {\n\n    private static final String LOGTAG = LogUtils.getTag(InitiateImageSharing.class.getName());\n\n    /**\n     * Activity result constants\n     */\n    private final static int SELECT_IMAGE = 0;\n\n    /**\n     * UI handler\n     */\n    private final Handler mHandler = new Handler();\n\n    private String mFilename;\n    private Uri mFile;\n    private long mFilesize = -1;\n    private ImageSharing mImageSharing;\n    private String mSharingId;\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n    private ImageSharingListener mIshListener;\n    private Button mDialBtn;\n    private Button mInviteBtn;\n    private ProgressBar mProgressBar;\n    private Button mSelectBtn;\n    private TextView mStatusView;\n    private TextView mFilenameView;\n    private ImageSharingService mImageSharingService;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.image_sharing_initiate);\n        initialize();\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.IMAGE_SHARING)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.IMAGE_SHARING);\n        try {\n            mImageSharingService.addEventListener(mIshListener);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (!isServiceConnected(RcsServiceName.IMAGE_SHARING)) {\n            return;\n        }\n        try {\n            getImageSharingApi().removeEventListener(mIshListener);\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (RESULT_OK != resultCode || SELECT_IMAGE != requestCode) {\n            return;\n        }\n        if (data != null && data.getData() != null) {\n            // Get selected photo URI\n            mFile = data.getData();\n            // Display the selected filename attribute\n            mFilename = FileUtils.getFileName(this, mFile);\n            mFilesize = FileUtils.getFileSize(this, mFile);\n            mFilenameView.setText(mFilename);\n            TextView sizeView = (TextView) findViewById(R.id.size);\n            sizeView.setText(FileUtils.humanReadableByteCount(mFilesize, true));\n            mInviteBtn.setEnabled(true);\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        double position = 0.0d;\n        if (totalSize != 0) {\n            mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n            position = (((double) currentSize) / ((double) totalSize)) * 100.0d;\n        } else {\n            mStatusView.setText(\"\");\n        }\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mImageSharing != null\n                    && RcsSessionUtil.isAllowedToAbortImageSharingSession(mImageSharing)) {\n                mImageSharing.abortSharing();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mImageSharing = null;\n            // Exit activity\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            try {\n                if (mImageSharing == null\n                        || !RcsSessionUtil.isAllowedToAbortImageSharingSession(mImageSharing)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n\n            } catch (RcsServiceException e) {\n                showException(e);\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_image_sharing, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void initialize() {\n        mImageSharingService = getImageSharingApi();\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        ContactListAdapter adapter = ContactListAdapter.createRcsContactListAdapter(this);\n        mSpinner.setAdapter(adapter);\n\n        OnClickListener btnInviteListener = new OnClickListener() {\n            public void onClick(View v) {\n                // Check if the service is available\n                try {\n                    if (!mImageSharingService.isServiceRegistered()) {\n                        showMessage(R.string.error_not_registered);\n                        return;\n                    }\n                    // Get the remote contact\n                    ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n                    String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n                    final ContactId remote = ContactUtil.formatContact(phoneNumber);\n                    if (LogUtils.isActive) {\n                        Log.d(LOGTAG, \"shareImage image=\" + mFilename + \" size=\" + mFilesize);\n                    }\n                    /* Only take persistable permission for content Uris */\n                    takePersistableContentUriPermission(InitiateImageSharing.this, mFile);\n                    // Initiate sharing\n                    mImageSharing = mImageSharingService.shareImage(remote, mFile);\n                    mSharingId = mImageSharing.getSharingId();\n                    // Disable UI\n                    mSpinner.setEnabled(false);\n                    // Hide buttons\n                    mInviteBtn.setVisibility(View.INVISIBLE);\n                    mSelectBtn.setVisibility(View.INVISIBLE);\n                    mDialBtn.setVisibility(View.INVISIBLE);\n\n                } catch (RcsServiceNotAvailableException e) {\n                    showMessage(R.string.label_service_not_available);\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n        mInviteBtn = (Button) findViewById(R.id.invite_btn);\n        mInviteBtn.setOnClickListener(btnInviteListener);\n        mInviteBtn.setEnabled(false);\n\n        OnClickListener btnSelectListener = new OnClickListener() {\n            public void onClick(View v) {\n                FileUtils.openFile(InitiateImageSharing.this, \"image/*\", SELECT_IMAGE);\n            }\n        };\n        mSelectBtn = (Button) findViewById(R.id.select_btn);\n        mSelectBtn.setOnClickListener(btnSelectListener);\n        mSelectBtn.setEnabled(false);\n\n        OnClickListener btnDialListener = new OnClickListener() {\n            public void onClick(View v) {\n                // get selected phone number\n                ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n                String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n\n                // Initiate a GSM call before to be able to share content\n                Intent intent = new Intent(Intent.ACTION_CALL);\n                intent.setData(Uri.parse(\"tel:\".concat(phoneNumber)));\n                if (ActivityCompat.checkSelfPermission(InitiateImageSharing.this,\n                        Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {\n                    return;\n                }\n                startActivity(intent);\n            }\n        };\n        mDialBtn = (Button) findViewById(R.id.dial_btn);\n        mDialBtn.setOnClickListener(btnDialListener);\n        mDialBtn.setEnabled(false);\n\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n        mFilenameView = (TextView) findViewById(R.id.uri);\n        updateProgressBar(0, 0);\n        mFilenameView.setText(\"\");\n        if (adapter == null || adapter.getCount() != 0) {\n            mDialBtn.setEnabled(true);\n            mSelectBtn.setEnabled(true);\n        }\n\n        mIshListener = new ImageSharingListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String sharingId,\n                    final long currentSize, final long totalSize) {\n                // Discard event if not for current sharingId\n                if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                    return;\n                }\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        // Display sharing progress\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(ContactId contact, String sharingId,\n                    final ImageSharing.State state, ImageSharing.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" sharingId=\" + sharingId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                // Discard event if not for current sharingId\n                if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sImageSharingReasonCodes[reasonCode\n                        .toInt()];\n                final String _state = RiApplication.sImageSharingStates[state.toInt()];\n                mHandler.post(new Runnable() {\n                    public void run() {\n                        TextView statusView = (TextView) findViewById(R.id.progress_status);\n                        switch (state) {\n                            case STARTED:\n                                statusView.setText(_state);\n                                break;\n\n                            case ABORTED:\n                                String msg = getString(R.string.label_sharing_aborted, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case REJECTED:\n                                msg = getString(R.string.label_sharing_rejected, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case FAILED:\n                                msg = getString(R.string.label_sharing_failed, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case TRANSFERRED:\n                                statusView.setText(_state);\n                                break;\n\n                            default:\n                                statusView.setText(_state);\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG,\n                                            \"onStateChanged \"\n                                                    + getString(R.string.label_ish_state_changed,\n                                                            _state, _reasonCode));\n                                }\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" sharingIds=\" + sharingIds);\n                }\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/image/ReceiveImageSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.image;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingIntent;\nimport com.gsma.services.rcs.sharing.image.ImageSharingListener;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport java.util.Set;\n\n/**\n * Receive image sharing\n *\n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class ReceiveImageSharing extends RcsActivity {\n    /**\n     * UI handler\n     */\n    private final Handler handler = new Handler();\n\n    private ImageSharing mImageSharing;\n\n    /**\n     * The Image Sharing Data Object\n     */\n    private ImageSharingDAO mIshDao;\n\n    private static final String LOGTAG = LogUtils.getTag(ReceiveImageSharing.class.getName());\n\n    private ImageSharingListener mListener;\n\n    private OnClickListener mAcceptBtnListener;\n\n    private OnClickListener mDeclineBtnListener;\n    private ProgressBar mProgressBar;\n    private boolean mSessionListenerSet;\n    private TextView mStatusView;\n    private String mSharingId;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.image_sharing_receive);\n        intitialize();\n\n        /* Register to API connection manager */\n        if (!isServiceConnected(RcsServiceName.IMAGE_SHARING, RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.IMAGE_SHARING, RcsServiceName.CONTACT);\n        processIntent(getIntent());\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (!mSessionListenerSet || !isServiceConnected(RcsServiceName.IMAGE_SHARING)) {\n            return;\n        }\n        try {\n            getImageSharingApi().removeEventListener(mListener);\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        setIntent(intent);\n        processIntent(intent);\n    }\n\n    private void processIntent(Intent invitation) {\n        mSharingId = invitation.getStringExtra(ImageSharingIntent.EXTRA_SHARING_ID);\n        mIshDao = invitation.getParcelableExtra(ImageSharingIntentService.BUNDLE_ISHDAO_ID);\n        initiateImageSharing();\n    }\n\n    private void initiateImageSharing() {\n        ImageSharingService ishApi = getImageSharingApi();\n        try {\n            /* Get the image sharing */\n            mImageSharing = ishApi.getImageSharing(mSharingId);\n            if (mImageSharing == null) {\n                // Session not found or expired\n                showMessageThenExit(R.string.label_session_not_found);\n                return;\n            }\n            mSessionListenerSet = true;\n            ishApi.addEventListener(mListener);\n\n            /* Display sharing infos */\n            String from = RcsContactUtil.getInstance(this).getDisplayName(mIshDao.getContact());\n            TextView fromTextView = (TextView) findViewById(R.id.contact);\n            fromTextView.setText(from);\n\n            String size = FileUtils.humanReadableByteCount(mIshDao.getSize(), true);\n            TextView sizeTxt = (TextView) findViewById(R.id.size);\n            sizeTxt.setText(size);\n\n            updateProgressBar(0, mIshDao.getSize());\n\n            /* Display accept/reject dialog */\n            AlertDialog.Builder builder = new AlertDialog.Builder(this);\n            builder.setTitle(R.string.title_image_sharing);\n            builder.setMessage(getString(R.string.label_ft_from_size, from, size));\n            builder.setCancelable(false);\n            builder.setIcon(R.drawable.ri_notif_csh_icon);\n            builder.setPositiveButton(R.string.label_accept, mAcceptBtnListener);\n            builder.setNegativeButton(R.string.label_decline, mDeclineBtnListener);\n            registerDialog(builder.show());\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void acceptInvitation() {\n        try {\n            mImageSharing.acceptInvitation();\n        } catch (RcsGenericException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void rejectInvitation() {\n        try {\n            mImageSharing.rejectInvitation();\n        } catch (RcsGenericException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        mStatusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n        double position = ((double) currentSize / (double) totalSize) * 100.0d;\n        mProgressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mImageSharing != null && ImageSharing.State.STARTED == mImageSharing.getState()) {\n                mImageSharing.abortSharing();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mImageSharing = null;\n            /* Exit activity */\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            try {\n                if (mImageSharing == null\n                        || !RcsSessionUtil.isAllowedToAbortImageSharingSession(mImageSharing)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n\n            } catch (RcsServiceException e) {\n                showException(e);\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_image_sharing, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void intitialize() {\n        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);\n        mStatusView = (TextView) findViewById(R.id.progress_status);\n        mListener = new ImageSharingListener() {\n\n            @Override\n            public void onProgressUpdate(ContactId contact, String sharingId,\n                    final long currentSize, final long totalSize) {\n                /* Discard event if not for current sharingId */\n                if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                    return;\n                }\n                handler.post(new Runnable() {\n                    public void run() {\n                        /* Display sharing progress */\n                        updateProgressBar(currentSize, totalSize);\n                    }\n                });\n            }\n\n            @Override\n            public void onStateChanged(ContactId contact, String sharingId,\n                    final ImageSharing.State state, ImageSharing.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact.toString() + \" sharingId=\"\n                            + sharingId + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                /* Discard event if not for current sharingId */\n                if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                    return;\n                }\n                final String _reasonCode = RiApplication.sImageSharingReasonCodes[reasonCode\n                        .toInt()];\n                final String _state = RiApplication.sImageSharingStates[state.toInt()];\n                handler.post(new Runnable() {\n                    public void run() {\n\n                        switch (state) {\n                            case ABORTED:\n                                String msg = getString(R.string.label_sharing_aborted, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case FAILED:\n                                msg = getString(R.string.label_sharing_failed, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case REJECTED:\n                                msg = getString(R.string.label_sharing_rejected, _reasonCode);\n                                mStatusView.setText(msg);\n                                showMessageThenExit(msg);\n                                break;\n\n                            case TRANSFERRED:\n                                // Display transfer progress\n                                mStatusView.setText(_state);\n                                // Make sure progress bar is at the end\n                                mProgressBar.setProgress(mProgressBar.getMax());\n\n                                // Show the shared image\n                                Utils.showPicture(ReceiveImageSharing.this, mIshDao.getFile());\n                                break;\n\n                            default:\n                                // Display session status\n                                mStatusView.setText(_state);\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG, \"onStateChanged \".concat(getString(\n                                            R.string.label_ish_state_changed, _state, _reasonCode)));\n                                }\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" sharingIds=\" + sharingIds);\n                }\n            }\n        };\n\n        mAcceptBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                acceptInvitation();\n            }\n        };\n\n        mDeclineBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                rejectInvitation();\n                finish();\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/IncomingVideoSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License ats\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.sharing.video.media.TerminatingVideoPlayer;\nimport com.gsma.rcs.ri.sharing.video.media.VideoPlayerListener;\nimport com.gsma.rcs.ri.sharing.video.media.VideoSurfaceView;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoDescriptor;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingListener;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\n\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.res.Configuration;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.SurfaceHolder;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.widget.FrameLayout;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport java.util.Set;\n\n/**\n * Receive video sharing\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class IncomingVideoSharing extends RcsActivity implements VideoPlayerListener {\n\n    /**\n     * UI handler\n     */\n    private final Handler handler = new Handler();\n\n    private VideoSharing mVideoSharing;\n\n    /**\n     * The Video Sharing Data Object\n     */\n    private VideoSharingDAO mVshDao;\n\n    /**\n     * Video renderer<br>\n     * Note: this field is intentionally static\n     */\n    private static TerminatingVideoPlayer mVideoRenderer;\n\n    /**\n     * Video width\n     */\n    private int mVideoWidth = H264Config.QCIF_WIDTH;\n\n    /**\n     * Video height\n     */\n    private int mVideoHeight = H264Config.QCIF_HEIGHT;\n\n    /**\n     * Live video preview\n     */\n    private VideoSurfaceView mVideoView;\n\n    private static final String SAVE_VIDEO_SHARING_DAO = \"videoSharingDao\";\n\n    private static final String SAVE_WAIT_USER_ACCEPT = \"waitUserAccept\";\n\n    private boolean mWaitForUseAcceptance = true;\n\n    private AlertDialog mAcceptDeclineDialog;\n\n    private OnClickListener mAcceptBtnListener;\n\n    private OnClickListener mDeclineBtnListener;\n\n    private VideoSharingListener mVshListener;\n\n    private static final String LOGTAG = LogUtils\n            .getTag(IncomingVideoSharing.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        // Set layout\n        setContentView(R.layout.video_sharing_incoming);\n\n        initialize();\n        // Always on window\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);\n\n        // Saved datas\n        if (savedInstanceState == null) {\n            // Get invitation info\n            mVshDao = getIntent().getExtras().getParcelable(\n                    VideoSharingIntentService.BUNDLE_VSHDAO_ID);\n        } else {\n            mVshDao = savedInstanceState.getParcelable(SAVE_VIDEO_SHARING_DAO);\n            mWaitForUseAcceptance = savedInstanceState.getBoolean(SAVE_WAIT_USER_ACCEPT);\n        }\n        if (mVshDao == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"onCreate cannot read Video Sharing invitation\");\n            }\n            finish();\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onCreate \".concat(mVshDao.toString()));\n        }\n        // Create the live video view\n        mVideoView = (VideoSurfaceView) findViewById(R.id.video_view);\n        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {\n            mVideoView.setAspectRatio(mVideoWidth, mVideoHeight);\n        } else {\n            mVideoView.setAspectRatio(mVideoHeight, mVideoWidth);\n        }\n        SurfaceHolder surface = mVideoView.getHolder();\n        surface.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);\n        surface.setKeepScreenOn(true);\n\n        if (mVideoRenderer == null) {\n            // Instantiate the renderer\n            mVideoRenderer = new TerminatingVideoPlayer(mVideoView, this);\n        } else {\n            mVideoRenderer.setSurface(mVideoView);\n        }\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.VIDEO_SHARING, RcsServiceName.CONTACT)) {\n            showMessageThenExit(R.string.label_service_not_available);\n        } else {\n            startMonitorServices(RcsServiceName.VIDEO_SHARING, RcsServiceName.CONTACT);\n            startOrRestartVideoSharing();\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (mAcceptDeclineDialog != null) {\n            mAcceptDeclineDialog.cancel();\n            mAcceptDeclineDialog = null;\n        }\n        if (isFinishing()) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onDestroy reset video renderer\");\n            }\n            mVideoRenderer = null;\n        }\n        if (isServiceConnected(RcsServiceName.VIDEO_SHARING)) {\n            // Remove video sharing listener\n            try {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onDestroy Remove listener\");\n                }\n                getVideoSharingApi().removeEventListener(mVshListener);\n\n            } catch (RcsServiceException e) {\n                Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            }\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putParcelable(SAVE_VIDEO_SHARING_DAO, mVshDao);\n        outState.putBoolean(SAVE_WAIT_USER_ACCEPT, mWaitForUseAcceptance);\n    }\n\n    private void startOrRestartVideoSharing() {\n        VideoSharingService vshApi = getVideoSharingApi();\n        try {\n            mVideoSharing = vshApi.getVideoSharing(mVshDao.getSharingId());\n            if (mVideoSharing == null) {\n                // Session not found or expired\n                showMessageThenExit(R.string.label_session_not_found);\n                return;\n\n            }\n            vshApi.addEventListener(mVshListener);\n\n            ContactId remote = mVshDao.getContact();\n            // Display sharing information\n            String from = RcsContactUtil.getInstance(this).getDisplayName(remote);\n            TextView fromTextView = (TextView) findViewById(R.id.contact);\n            fromTextView.setText(from);\n\n            if (mWaitForUseAcceptance) {\n                showReceiveNotification(from);\n            } else {\n                displayVideoFormat();\n            }\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void showReceiveNotification(String from) {\n        // User alert\n        // Display accept/reject dialog\n        AlertDialog.Builder builder = new AlertDialog.Builder(this);\n        builder.setTitle(R.string.title_video_sharing);\n        builder.setMessage(getString(R.string.label_from_args, from));\n        builder.setCancelable(false);\n        builder.setIcon(R.drawable.ri_notif_csh_icon);\n        builder.setPositiveButton(R.string.label_accept, mAcceptBtnListener);\n        builder.setNegativeButton(R.string.label_decline, mDeclineBtnListener);\n        mAcceptDeclineDialog = builder.show();\n        registerDialog(mAcceptDeclineDialog);\n    }\n\n    private void acceptInvitation() {\n        try {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"acceptInvitation\");\n            }\n            mVideoSharing.acceptInvitation(mVideoRenderer);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void rejectInvitation() {\n        try {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"rejectInvitation\");\n            }\n            mVideoSharing.rejectInvitation();\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    private void quitSession() {\n        try {\n            if (mVideoSharing != null && VideoSharing.State.STARTED == mVideoSharing.getState()) {\n                mVideoSharing.abortSharing();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mVideoSharing = null;\n            // Exit activity\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            try {\n                if (mVideoSharing == null\n                        || !RcsSessionUtil.isAllowedToAbortVideoSharingSession(mVideoSharing)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n\n            } catch (RcsServiceException e) {\n                showException(e);\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_video_sharing, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    private void displayVideoFormat() {\n        try {\n            VideoDescriptor videoDescriptor = mVideoSharing.getVideoDescriptor();\n            String format = mVideoSharing.getVideoEncoding() + \" \" + videoDescriptor.getWidth()\n                    + \"x\" + videoDescriptor.getHeight();\n            TextView fmtView = (TextView) findViewById(R.id.video_format);\n            fmtView.setVisibility(View.VISIBLE);\n            fmtView.setText(format);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    /*-------------------------- Video player callbacks ------------------*/\n\n    @Override\n    public void onPlayerOpened() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerOpened\");\n        }\n    }\n\n    @Override\n    public void onPlayerStarted() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerStarted\");\n        }\n    }\n\n    @Override\n    public void onPlayerStopped() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerStopped\");\n        }\n    }\n\n    @Override\n    public void onPlayerClosed() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerClosed\");\n        }\n    }\n\n    @Override\n    public void onPlayerError() {\n        // TODO\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerError\");\n        }\n    }\n\n    @Override\n    public void onPlayerResized(int width, int height) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerResized \" + width + \"x\" + height);\n        }\n        mVideoView.setAspectRatio(width, height);\n\n        LinearLayout l = (LinearLayout) mVideoView.getParent();\n        l.setLayoutParams(new FrameLayout.LayoutParams(width, height));\n    }\n\n    private void initialize() {\n        mAcceptBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                mAcceptDeclineDialog = null;\n                mWaitForUseAcceptance = false;\n                acceptInvitation();\n            }\n        };\n\n        mDeclineBtnListener = new OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                mAcceptDeclineDialog = null;\n                mWaitForUseAcceptance = false;\n                rejectInvitation();\n                // Exit activity\n                finish();\n            }\n        };\n\n        mVshListener = new VideoSharingListener() {\n\n            @Override\n            public void onStateChanged(ContactId contact, String sharingId,\n                    final VideoSharing.State state, VideoSharing.ReasonCode reasonCode) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" sharingId=\" + sharingId\n                            + \" state=\" + state + \" reason=\" + reasonCode);\n                }\n                // Discard event if not for current sharingId\n                if (mVshDao == null || !mVshDao.getSharingId().equals(sharingId)) {\n                    return;\n\n                }\n                final String _reasonCode = RiApplication.sVideoReasonCodes[reasonCode.toInt()];\n                handler.post(new Runnable() {\n                    public void run() {\n                        switch (state) {\n                            case STARTED:\n                                displayVideoFormat();\n\n                                // Start the renderer\n                                mVideoRenderer.open();\n                                mVideoRenderer.start();\n                                break;\n\n                            case ABORTED:\n                                // Stop the renderer\n                                mVideoRenderer.stop();\n                                mVideoRenderer.close();\n\n                                // Display session status\n                                showMessageThenExit(getString(R.string.label_sharing_aborted,\n                                        _reasonCode));\n                                break;\n\n                            case FAILED:\n                                // Stop the renderer\n                                mVideoRenderer.stop();\n                                mVideoRenderer.close();\n\n                                // Session is failed: exit\n                                showMessageThenExit(getString(R.string.label_sharing_failed,\n                                        _reasonCode));\n                                break;\n\n                            case REJECTED:\n                                // Stop the renderer\n                                mVideoRenderer.stop();\n                                mVideoRenderer.close();\n\n                                // Session is rejected: exit\n                                showMessageThenExit(getString(R.string.label_sharing_rejected,\n                                        _reasonCode));\n                                break;\n\n                            default:\n                                if (LogUtils.isActive) {\n                                    Log.d(LOGTAG, \"onStateChanged \".concat(getString(\n                                            R.string.label_vsh_state_changed,\n                                            RiApplication.sVideoSharingStates[state.toInt()],\n                                            _reasonCode)));\n                                }\n                        }\n                    }\n                });\n            }\n\n            @Override\n            public void onDeleted(ContactId contact, Set<String> sharingIds) {\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" sharingIds=\" + sharingIds);\n                }\n            }\n\n        };\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/OutgoingVideoSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.rcs.ri.sharing.video.media.OriginatingVideoPlayer;\nimport com.gsma.rcs.ri.sharing.video.media.VideoPlayerListener;\nimport com.gsma.rcs.ri.sharing.video.media.VideoSurfaceView;\nimport com.gsma.rcs.ri.utils.ContactListAdapter;\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoDescriptor;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingListener;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.CameraOptions;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.Orientation;\n\nimport android.Manifest;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.graphics.PixelFormat;\nimport android.hardware.Camera;\nimport android.hardware.Camera.Parameters;\nimport android.hardware.Camera.Size;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.support.v4.app.ActivityCompat;\nimport android.util.Log;\nimport android.view.Display;\nimport android.view.KeyEvent;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.Surface;\nimport android.view.SurfaceHolder;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.view.WindowManager;\nimport android.widget.Button;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.lang.reflect.Method;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Initiate video sharing.\n *\n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class OutgoingVideoSharing extends RcsActivity implements VideoPlayerListener,\n        SurfaceHolder.Callback {\n\n    /**\n     * UI handler\n     */\n    private final Handler handler = new Handler();\n\n    /**\n     * Video sharing\n     */\n    private VideoSharing mVideoSharing;\n\n    /**\n     * Video sharing Id\n     */\n    private String mSharingId;\n\n    /**\n     * Video player<br>\n     * Note: this field is intentionally static\n     */\n    private static OriginatingVideoPlayer mVideoPlayer;\n\n    /**\n     * Camera of the device\n     */\n    private Camera mCamera;\n\n    /**\n     * Opened camera id\n     */\n    private CameraOptions mOpenedCameraId = CameraOptions.FRONT;\n\n    /**\n     * Camera preview started flag\n     */\n    private boolean mCameraPreviewRunning = false;\n\n    /**\n     * Video width\n     */\n    private int mVideoWidth = H264Config.QCIF_WIDTH;\n\n    /**\n     * Video height\n     */\n    private int mVideoHeight = H264Config.QCIF_HEIGHT;\n\n    /**\n     * Number of cameras\n     */\n    private int mNbfCameras = 1;\n\n    /**\n     * Live video preview\n     */\n    private VideoSurfaceView mVideoView;\n\n    /**\n     * Video surface holder\n     */\n    private SurfaceHolder mSurface;\n\n    /**\n     * Spinner for contact selection\n     */\n    private Spinner mSpinner;\n\n    private Button mInviteBtn;\n\n    private Button mDialBtn;\n\n    private Button mSwitchCamBtn;\n\n    private ContactId mContact;\n\n    /**\n     * Session is started and video format is then negotiated.\n     */\n    private boolean mStarted = false;\n\n    /**\n     * Preview surface view is created\n     */\n    private boolean mIsSurfaceCreated;\n\n    private static final String LOGTAG = LogUtils\n            .getTag(OutgoingVideoSharing.class.getSimpleName());\n\n    private static final String SAVE_SHARING_ID = \"sharingId\";\n\n    private static final String SAVE_VIDEO_HEIGHT = \"videoHeight\";\n\n    private static final String SAVE_VIDEO_WIDTH = \"videoWidth\";\n\n    private static final String SAVE_NB_OF_CAMERAS = \"numberOfCameras\";\n\n    private static final String SAVE_OPENED_CAMERA_ID = \"openedCameraId\";\n\n    /**\n     * We save the remote contact into the activity bundle.<br>\n     * This information could also be retrieved from session instance.\n     */\n    private static final String SAVE_REMOTE_CONTACT = \"remoteContact\";\n\n    /**\n     * We save this information into the activity bundle.<br>\n     * This information could also be retrieved from session instance state.\n     */\n    private static final String SAVE_STARTED = \"started\";\n\n    /*\n     * (non-Javadoc)\n     * @see android.app.Activity#onCreate(android.os.Bundle)\n     */\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        // Always on window\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);\n        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);\n\n        // Set layout\n        setContentView(R.layout.video_sharing_outgoing);\n\n        // Set the contact selector\n        mSpinner = (Spinner) findViewById(R.id.contact);\n        ContactListAdapter adapter = ContactListAdapter.createRcsContactListAdapter(this);\n        mSpinner.setAdapter(adapter);\n\n        // Saved datas\n        if (savedInstanceState == null) {\n            mNbfCameras = getNumberOfCameras();\n        } else {\n            mSharingId = savedInstanceState.getString(SAVE_SHARING_ID);\n            mNbfCameras = savedInstanceState.getInt(SAVE_NB_OF_CAMERAS);\n            mVideoHeight = savedInstanceState.getInt(SAVE_VIDEO_HEIGHT);\n            mVideoWidth = savedInstanceState.getInt(SAVE_VIDEO_WIDTH);\n            mOpenedCameraId = CameraOptions.convert(savedInstanceState\n                    .getInt(SAVE_OPENED_CAMERA_ID));\n            mContact = savedInstanceState.getParcelable(SAVE_REMOTE_CONTACT);\n            mStarted = savedInstanceState.getBoolean(SAVE_STARTED);\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Sharing ID \" + mSharingId + \" Nb of cameras=\" + mNbfCameras\n                    + \" active camera=\" + mOpenedCameraId);\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Resolution: \" + mVideoWidth + \"x\" + mVideoHeight);\n        }\n\n        // Set button callback\n        mInviteBtn = (Button) findViewById(R.id.invite_btn);\n        mInviteBtn.setOnClickListener(btnInviteListener);\n        mDialBtn = (Button) findViewById(R.id.dial_btn);\n        mDialBtn.setOnClickListener(btnDialListener);\n        mSwitchCamBtn = (Button) findViewById(R.id.switch_cam_btn);\n\n        // Disable button if no contact available\n        if (adapter == null || adapter.getCount() == 0) {\n            mDialBtn.setEnabled(false);\n            mInviteBtn.setEnabled(false);\n        }\n\n        // Get camera info\n        if (mNbfCameras > 1) {\n            boolean backAvailable = checkCameraSize(CameraOptions.BACK);\n            boolean frontAvailable = checkCameraSize(CameraOptions.FRONT);\n            if (frontAvailable && backAvailable) {\n                mSwitchCamBtn.setOnClickListener(btnSwitchCamListener);\n            } else if (frontAvailable) {\n                mOpenedCameraId = CameraOptions.FRONT;\n                mSwitchCamBtn.setVisibility(View.INVISIBLE);\n            } else if (backAvailable) {\n                mOpenedCameraId = CameraOptions.BACK;\n                mSwitchCamBtn.setVisibility(View.INVISIBLE);\n            } else {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"No camera available for encoding\");\n                }\n            }\n        } else {\n            if (checkCameraSize(CameraOptions.FRONT)) {\n                mSwitchCamBtn.setVisibility(View.INVISIBLE);\n            } else {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"No camera available for encoding\");\n                }\n            }\n        }\n\n        // Create the live video view\n        mVideoView = (VideoSurfaceView) findViewById(R.id.video_preview);\n        mVideoView.setAspectRatio(mVideoWidth, mVideoHeight);\n        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {\n            mVideoView.setAspectRatio(mVideoWidth, mVideoHeight);\n\n        } else {\n            mVideoView.setAspectRatio(mVideoHeight, mVideoWidth);\n        }\n\n        mSurface = mVideoView.getHolder();\n        mSurface.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);\n        mSurface.setKeepScreenOn(true);\n        mSurface.addCallback(this);\n\n        // Check if session in progress\n        if (mSharingId != null) {\n            // Sharing in progress\n            mDialBtn.setVisibility(View.GONE);\n            mInviteBtn.setVisibility(View.GONE);\n            mSpinner.setVisibility(View.GONE);\n            mSwitchCamBtn.setEnabled((mNbfCameras > 1));\n            handler.post(continueOutgoingSessionRunnable);\n            displayRemoteContact();\n        } else {\n            // Sharing not yet initiated\n            mDialBtn.setVisibility(View.VISIBLE);\n            mInviteBtn.setVisibility(View.VISIBLE);\n            mSwitchCamBtn.setEnabled(false);\n\n            boolean canInitiate = true;\n            if (adapter == null || adapter.getCount() == 0) {\n                canInitiate = false;\n            }\n            mDialBtn.setEnabled(canInitiate);\n            mInviteBtn.setEnabled(canInitiate);\n        }\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.VIDEO_SHARING)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.VIDEO_SHARING);\n\n        // Add service listener\n        try {\n            VideoSharingService vshService = getVideoSharingApi();\n            if (mSharingId != null) {\n                // Sharing is in progress: get sharing session\n                mVideoSharing = vshService.getVideoSharing(mSharingId);\n                if (mStarted) {\n                    displayVideoFormat();\n                }\n            }\n            vshService.addEventListener(vshListener);\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onCreate video sharing\");\n            }\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    protected void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putString(SAVE_SHARING_ID, mSharingId);\n        outState.putInt(SAVE_VIDEO_HEIGHT, mVideoHeight);\n        outState.putInt(SAVE_VIDEO_WIDTH, mVideoWidth);\n        outState.putInt(SAVE_NB_OF_CAMERAS, mNbfCameras);\n        outState.putInt(SAVE_OPENED_CAMERA_ID, mOpenedCameraId.getValue());\n        outState.putParcelable(SAVE_REMOTE_CONTACT, mContact);\n        outState.putBoolean(SAVE_STARTED, mStarted);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (!isServiceConnected(RcsServiceName.VIDEO_SHARING)) {\n            return;\n        }\n        try {\n            getVideoSharingApi().removeEventListener(vshListener);\n\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n        closeCamera();\n    }\n\n    /**\n     * Dial button listener\n     */\n    // TODO initialize\n    private OnClickListener btnDialListener = new OnClickListener() {\n        public void onClick(View v) {\n\n            // get selected phone number\n            ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n            String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n\n            // Initiate a GSM call before to be able to share content\n            Intent intent = new Intent(Intent.ACTION_CALL);\n            intent.setData(Uri.parse(\"tel:\".concat(phoneNumber)));\n            if (ActivityCompat.checkSelfPermission(OutgoingVideoSharing.this,\n                    Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {\n                return;\n            }\n            startActivity(intent);\n        }\n    };\n\n    /**\n     * Invite button listener\n     */\n    private OnClickListener btnInviteListener = new OnClickListener() {\n        public void onClick(View v) {\n            // Check if the service is available\n            try {\n                if (!getVideoSharingApi().isServiceRegistered()) {\n                    showMessage(R.string.label_service_not_available);\n                    return;\n                }\n            } catch (RcsServiceException e) {\n                showExceptionThenExit(e);\n            }\n\n            // Get the remote contact\n            ContactListAdapter adapter = (ContactListAdapter) mSpinner.getAdapter();\n            String phoneNumber = adapter.getSelectedNumber(mSpinner.getSelectedView());\n\n            mContact = ContactUtil.formatContact(phoneNumber);\n\n            new Thread() {\n                public void run() {\n                    try {\n                        // Create the video player\n                        mVideoPlayer = new OriginatingVideoPlayer(OutgoingVideoSharing.this);\n\n                        // Open the camera\n                        openCamera();\n\n                        // Initiate sharing\n                        mVideoSharing = getVideoSharingApi().shareVideo(mContact, mVideoPlayer);\n                        mSharingId = mVideoSharing.getSharingId();\n\n                    } catch (final RcsServiceException e) {\n                        // Free the camera\n                        closeCamera();\n\n                        handler.post(new Runnable() {\n                            public void run() {\n                                showExceptionThenExit(e);\n                            }\n                        });\n                    }\n                }\n            }.start();\n\n            mSwitchCamBtn.setEnabled(true);\n\n            // Hide buttons\n            mInviteBtn.setVisibility(View.GONE);\n            mDialBtn.setVisibility(View.GONE);\n            mSpinner.setVisibility(View.GONE);\n            displayRemoteContact();\n        }\n    };\n\n    /**\n     * Switch camera button listener\n     */\n    private View.OnClickListener btnSwitchCamListener = new View.OnClickListener() {\n        public void onClick(View v) {\n            // Switch camera\n            switchCamera();\n        }\n    };\n\n    private void quitSession() {\n        try {\n            if (mVideoSharing != null && VideoSharing.State.STARTED == mVideoSharing.getState()) {\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Abort sharing\");\n                }\n                mVideoSharing.abortSharing();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mVideoSharing = null;\n            // Exit activity\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Back key pressed\");\n            }\n            try {\n                if (mVideoSharing == null\n                        || !RcsSessionUtil.isAllowedToAbortVideoSharingSession(mVideoSharing)) {\n                    finish();\n                    return true;\n                }\n                AlertDialog.Builder builder = new AlertDialog.Builder(this);\n                builder.setTitle(R.string.label_confirm_close);\n                builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                    public void onClick(DialogInterface dialog, int which) {\n                        quitSession();\n                    }\n                });\n                builder.setNegativeButton(R.string.label_cancel,\n                        new DialogInterface.OnClickListener() {\n                            public void onClick(DialogInterface dialog, int which) {\n                            }\n                        });\n                builder.setCancelable(true);\n                registerDialog(builder.show());\n                return true;\n\n            } catch (RcsServiceException e) {\n                showException(e);\n            }\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        MenuInflater inflater = new MenuInflater(getApplicationContext());\n        inflater.inflate(R.menu.menu_video_sharing, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.menu_close_session:\n                quitSession();\n                break;\n        }\n        return true;\n    }\n\n    /*-------------------------- Camera methods ------------------*/\n\n    /**\n     * Open the camera\n     */\n    private synchronized void openCamera() {\n        if (mCamera != null) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Already opened camera\");\n            }\n            return;\n\n        }\n        openCamera(mOpenedCameraId);\n        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {\n            mVideoView.setAspectRatio(mVideoWidth, mVideoHeight);\n        } else {\n            mVideoView.setAspectRatio(mVideoHeight, mVideoWidth);\n        }\n        // Start camera\n        mCamera.setPreviewCallback(mVideoPlayer);\n        startCameraPreview();\n    }\n\n    /**\n     * Close the camera\n     */\n    private synchronized void closeCamera() {\n        if (mCamera == null) {\n            return;\n\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Close camera\");\n        }\n        mCamera.setPreviewCallback(null);\n        if (mCameraPreviewRunning) {\n            mCameraPreviewRunning = false;\n            mCamera.stopPreview();\n        }\n        mCamera.release();\n        mCamera = null;\n    }\n\n    /**\n     * Switch the camera\n     */\n    private synchronized void switchCamera() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Switch camera\");\n        }\n        closeCamera();\n        // Open the other camera\n        if (mOpenedCameraId.getValue() == CameraOptions.BACK.getValue()) {\n            mOpenedCameraId = CameraOptions.FRONT;\n        } else {\n            mOpenedCameraId = CameraOptions.BACK;\n        }\n\n        openCamera();\n    }\n\n    /**\n     * Check if good camera sizes are available for encoder. Must be used only before open camera.\n     *\n     * @param cameraId the camera ID\n     * @return false if the camera don't have the good preview size for the encoder\n     */\n    boolean checkCameraSize(CameraOptions cameraId) {\n        boolean sizeAvailable = false;\n        Camera camera = null;\n        Method method = getCameraOpenMethod();\n        if (method != null) {\n            try {\n                camera = (Camera) method.invoke(camera, new Object[] {\n                    cameraId.getValue()\n                });\n            } catch (Exception e) {\n                camera = Camera.open();\n            }\n        } else {\n            camera = Camera.open();\n        }\n        if (camera == null) {\n            return false;\n\n        }\n        // Check common sizes\n        Parameters param = camera.getParameters();\n        List<Camera.Size> sizes = param.getSupportedPreviewSizes();\n        for (Camera.Size size : sizes) {\n            if ((size.width == H264Config.QVGA_WIDTH && size.height == H264Config.QVGA_HEIGHT)\n                    || (size.width == H264Config.CIF_WIDTH && size.height == H264Config.CIF_HEIGHT)\n                    || (size.width == H264Config.VGA_WIDTH && size.height == H264Config.VGA_HEIGHT)) {\n                sizeAvailable = true;\n                break;\n            }\n        }\n\n        // Release camera\n        camera.release();\n\n        return sizeAvailable;\n    }\n\n    /**\n     * Start the camera preview\n     */\n    private void startCameraPreview() {\n        if (mCamera == null) {\n            return;\n\n        }\n        // Camera settings\n        Camera.Parameters p = mCamera.getParameters();\n        p.setPreviewFormat(PixelFormat.YCbCr_420_SP);\n\n        // Orientation\n        Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();\n        switch (display.getRotation()) {\n            case Surface.ROTATION_0:\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"ROTATION_0\");\n                }\n                if (mOpenedCameraId == CameraOptions.FRONT) {\n                    mVideoPlayer.setOrientation(Orientation.ROTATE_90_CCW);\n                } else {\n                    mVideoPlayer.setOrientation(Orientation.ROTATE_90_CW);\n                }\n                mCamera.setDisplayOrientation(90);\n                break;\n\n            case Surface.ROTATION_90:\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"ROTATION_90\");\n                }\n                mVideoPlayer.setOrientation(Orientation.NONE);\n                break;\n\n            case Surface.ROTATION_180:\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"ROTATION_180\");\n                }\n                if (mOpenedCameraId == CameraOptions.FRONT) {\n                    mVideoPlayer.setOrientation(Orientation.ROTATE_90_CW);\n                } else {\n                    mVideoPlayer.setOrientation(Orientation.ROTATE_90_CCW);\n                }\n                mCamera.setDisplayOrientation(270);\n                break;\n\n            case Surface.ROTATION_270:\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"ROTATION_270\");\n                }\n                if (mOpenedCameraId == CameraOptions.FRONT) {\n                    mVideoPlayer.setOrientation(Orientation.ROTATE_180);\n                } else {\n                    mVideoPlayer.setOrientation(Orientation.ROTATE_180);\n                }\n                mCamera.setDisplayOrientation(180);\n                break;\n        }\n\n        // Check if preview size is supported\n        if (isPreviewSizeSupported(p, mVideoWidth, mVideoHeight)) {\n            // Use the existing size without resizing\n            p.setPreviewSize(mVideoWidth, mVideoHeight);\n            // TODO videoPlayer.activateResizing(videoWidth, videoHeight); //\n            // same size = no\n            // resizing\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"Camera preview initialized with size \" + mVideoWidth + \"x\"\n                        + mVideoHeight);\n            }\n        } else {\n            // Check if can use a other known size (QVGA, CIF or VGA)\n            int w = 0;\n            int h = 0;\n            for (Camera.Size size : p.getSupportedPreviewSizes()) {\n                w = size.width;\n                h = size.height;\n                if ((w == H264Config.QVGA_WIDTH && h == H264Config.QVGA_HEIGHT)\n                        || (w == H264Config.CIF_WIDTH && h == H264Config.CIF_HEIGHT)\n                        || (w == H264Config.VGA_WIDTH && h == H264Config.VGA_HEIGHT)) {\n                    break;\n                }\n            }\n\n            if (w != 0) {\n                p.setPreviewSize(w, h);\n                // TODO does not work if default sizes are not supported like\n                // for Samsung S5 mini\n                // mVideoPlayer.activateResizing(w, h);\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Camera preview initialized with size \" + w + \"x\" + h\n                            + \" with a resizing to \" + mVideoWidth + \"x\" + mVideoHeight);\n                }\n            } else {\n                // The camera don't have known size, we can't use it\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Camera preview can't be initialized with size \" + mVideoWidth\n                            + \"x\" + mVideoHeight);\n                }\n                Toast.makeText(this,\n                        getString(R.string.label_session_failed, \"Camera is not compatible\"),\n                        Toast.LENGTH_SHORT).show();\n                quitSession();\n                return;\n\n            }\n        }\n\n        // Set camera parameters\n        mCamera.setParameters(p);\n        try {\n            mCamera.setPreviewDisplay(mVideoView.getHolder());\n            mCamera.startPreview();\n            mCameraPreviewRunning = true;\n        } catch (Exception e) {\n            mCamera = null;\n        }\n    }\n\n    /**\n     * Get Camera \"open\" Method\n     *\n     * @return Method\n     */\n    private Method getCameraOpenMethod() {\n        ClassLoader classLoader = OutgoingVideoSharing.class.getClassLoader();\n        try {\n            Class<?> cameraClass = classLoader.loadClass(\"android.hardware.Camera\");\n            try {\n                return cameraClass.getMethod(\"open\", new Class[] {\n                    int.class\n                });\n            } catch (NoSuchMethodException ignored) {\n            }\n        } catch (ClassNotFoundException ignored) {\n        }\n        return null;\n    }\n\n    /**\n     * Open the camera\n     *\n     * @param cameraId Camera ID\n     */\n    private void openCamera(CameraOptions cameraId) {\n        Method method = getCameraOpenMethod();\n        if (mNbfCameras > 1 && method != null) {\n            try {\n                int hCamId = 0;\n                if (cameraId == CameraOptions.FRONT) {\n                    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();\n                    for (int id = 0; id < mNbfCameras; id++) {\n                        Camera.getCameraInfo(id, cameraInfo);\n                        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {\n                            hCamId = id;\n                            break;\n                        }\n                    }\n                }\n                mCamera = (Camera) method.invoke(mCamera, new Object[] {\n                    hCamId\n                });\n                mOpenedCameraId = cameraId;\n            } catch (Exception e) {\n                mCamera = Camera.open();\n                mOpenedCameraId = CameraOptions.BACK;\n            }\n        } else {\n            mCamera = Camera.open();\n            mOpenedCameraId = CameraOptions.BACK;\n        }\n        if (mVideoPlayer != null) {\n            mVideoPlayer.setCameraId(mOpenedCameraId.getValue());\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Open camera \".concat(mOpenedCameraId.toString()));\n        }\n    }\n\n    /**\n     * Get Camera \"numberOfCameras\" Method\n     *\n     * @return Method\n     */\n    private Method getCameraNumberOfCamerasMethod() {\n        ClassLoader classLoader = OutgoingVideoSharing.class.getClassLoader();\n        try {\n            Class<?> cameraClass = classLoader.loadClass(\"android.hardware.Camera\");\n            try {\n                return cameraClass.getMethod(\"getNumberOfCameras\", (Class[]) null);\n            } catch (NoSuchMethodException ignored) {\n            }\n        } catch (ClassNotFoundException ignored) {\n        }\n        return null;\n    }\n\n    /**\n     * Get number of cameras\n     *\n     * @return number of cameras\n     */\n    private int getNumberOfCameras() {\n        Method method = getCameraNumberOfCamerasMethod();\n        if (method != null) {\n            try {\n                return (Integer) method.invoke(null, (Object[]) null);\n            } catch (Exception e) {\n                return 1;\n            }\n        } else {\n            return 1;\n        }\n    }\n\n    /*-------------------------- Session callbacks ------------------*/\n\n    /**\n     * Video sharing listener\n     */\n    private VideoSharingListener vshListener = new VideoSharingListener() {\n        @Override\n        public void onStateChanged(ContactId contact, String sharingId,\n                final VideoSharing.State state, VideoSharing.ReasonCode reasonCode) {\n            // Discard event if not for current sharingId\n            if (mSharingId == null || !mSharingId.equals(sharingId)) {\n                return;\n            }\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onStateChanged contact=\" + contact + \" sharingId=\" + sharingId\n                        + \" state=\" + state + \" reason=\" + reasonCode);\n            }\n            final String _reasonCode = RiApplication.sVideoReasonCodes[reasonCode.toInt()];\n            handler.post(new Runnable() {\n                public void run() {\n                    switch (state) {\n                        case STARTED:\n                            mStarted = true;\n                            displayVideoFormat();\n\n                            // Start the player\n                            mVideoPlayer.open();\n                            mVideoPlayer.start();\n\n                            // Update camera button\n                            Button switchCamBtn = (Button) findViewById(R.id.switch_cam_btn);\n                            switchCamBtn.setEnabled(true);\n\n                            // Session is established : hide progress dialog\n                            break;\n\n                        case ABORTED:\n                            // Stop the player\n                            mVideoPlayer.stop();\n                            mVideoPlayer.close();\n\n                            // Release the camera\n                            closeCamera();\n\n                            // Display message info and exit\n                            showMessageThenExit(getString(R.string.label_sharing_aborted,\n                                    _reasonCode));\n                            break;\n\n                        case REJECTED:\n                            // Release the camera\n                            closeCamera();\n\n                            showMessageThenExit(getString(R.string.label_sharing_rejected,\n                                    _reasonCode));\n                            break;\n\n                        case FAILED:\n                            // Stop the player\n                            mVideoPlayer.stop();\n                            mVideoPlayer.close();\n\n                            // Release the camera\n                            closeCamera();\n\n                            // Display error info and exit\n                            showMessageThenExit(getString(R.string.label_sharing_failed,\n                                    _reasonCode));\n                            break;\n\n                        default:\n                            if (LogUtils.isActive) {\n                                Log.d(LOGTAG, \"onStateChanged \".concat(getString(\n                                        R.string.label_vsh_state_changed,\n                                        RiApplication.sVideoSharingStates[state.toInt()],\n                                        _reasonCode)));\n                            }\n                    }\n                }\n            });\n        }\n\n        @Override\n        public void onDeleted(ContactId contact, Set<String> sharingIds) {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"onDeleted contact=\" + contact + \" sharingIds=\" + sharingIds);\n            }\n        }\n    };\n\n    /*-------------------------- Video player callbacks ------------------*/\n\n    /**\n     * Callback called when the player is opened\n     */\n    public void onPlayerOpened() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerOpened\");\n        }\n    }\n\n    /**\n     * Callback called when the player is started\n     */\n    public void onPlayerStarted() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerStarted\");\n        }\n    }\n\n    /**\n     * Callback called when the player is stopped\n     */\n    public void onPlayerStopped() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerStopped\");\n        }\n    }\n\n    /**\n     * Callback called when the player is closed\n     */\n    public void onPlayerClosed() {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerClosed\");\n        }\n    }\n\n    /**\n     * Callback called when the player has failed\n     */\n    public void onPlayerError() {\n        // TODO\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerError\");\n        }\n    }\n\n    /**\n     * Callback called when the player has been resized\n     */\n    public void onPlayerResized(int width, int height) {\n        // TODO\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onPlayerResized\");\n        }\n    }\n\n    /**\n     * Check if preview size is supported\n     *\n     * @param parameters Camera parameters\n     * @param width width\n     * @param height height\n     * @return True if supported\n     */\n    private boolean isPreviewSizeSupported(Parameters parameters, int width, int height) {\n        List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();\n        for (Size size : sizes) {\n            if (size.width == width && size.height == height) {\n                return true;\n\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void surfaceCreated(SurfaceHolder holder) {\n        mIsSurfaceCreated = true;\n    }\n\n    @Override\n    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {\n        mIsSurfaceCreated = true;\n    }\n\n    @Override\n    public void surfaceDestroyed(SurfaceHolder holder) {\n        mIsSurfaceCreated = false;\n    }\n\n    /**\n     * Runnable to continue outgoing session.<br>\n     * Note: the surface view be created to display preview.\n     */\n    private Runnable continueOutgoingSessionRunnable = new Runnable() {\n        private int delay = 0;\n\n        @Override\n        public void run() {\n            if (mIsSurfaceCreated) {\n                // Open camera only once surface is created\n                openCamera();\n            } else {\n                delay += 200;\n                handler.removeCallbacks(this);\n                if (delay < 2000) {\n                    if (LogUtils.isActive) {\n                        Log.e(LOGTAG, \"Delaying continue Outgoing\");\n                    }\n                    handler.postDelayed(this, delay);\n                }\n            }\n        }\n    };\n\n    /**\n     * Display video format\n     */\n    private void displayVideoFormat() {\n        try {\n            VideoDescriptor videoDescriptor = mVideoSharing.getVideoDescriptor();\n            String format = mVideoSharing.getVideoEncoding() + \" \" + videoDescriptor.getWidth()\n                    + \"x\" + videoDescriptor.getHeight();\n            TextView fmtView = (TextView) findViewById(R.id.video_format);\n            fmtView.setText(format);\n\n        } catch (RcsPersistentStorageException | RcsGenericException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    /**\n     * Display remote contact\n     */\n    private void displayRemoteContact() {\n        TextView fromTextView = (TextView) findViewById(R.id.remote);\n        String displayName = RcsContactUtil.getInstance(this).getDisplayName(mContact);\n        fromTextView.setText(displayName);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/VideoSharingDAO.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video;\n\nimport com.gsma.rcs.ri.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.format.DateUtils;\n\n/**\n * Video Sharing Data Object\n * \n * @author YPLO6403\n */\npublic class VideoSharingDAO implements Parcelable {\n\n    private final String mSharingId;\n\n    private final ContactId mContact;\n\n    private final VideoSharing.State mState;\n\n    private final VideoSharing.ReasonCode mReasonCode;\n\n    private final Direction mDirection;\n\n    private final long mTimestamp;\n\n    private final long mDuration;\n\n    private final int mHeight;\n\n    private final int mWidth;\n\n    private final String mVideoEncoding;\n\n    private static ContentResolver sContentResolver;\n\n    private VideoSharingDAO(String sharingId, ContactId contact, VideoSharing.State state,\n            VideoSharing.ReasonCode reasonCode, Direction direction, long timestamp, long duration,\n            int height, int width, String videoEncoding) {\n        mSharingId = sharingId;\n        mContact = contact;\n        mState = state;\n        mReasonCode = reasonCode;\n        mDirection = direction;\n        mTimestamp = timestamp;\n        mDuration = duration;\n        mHeight = height;\n        mWidth = width;\n        mVideoEncoding = videoEncoding;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     */\n    public VideoSharingDAO(Parcel source) {\n        mSharingId = source.readString();\n        boolean containsContactId = source.readInt() != 0;\n        if (containsContactId) {\n            mContact = ContactId.CREATOR.createFromParcel(source);\n        } else {\n            mContact = null;\n        }\n        mState = VideoSharing.State.valueOf(source.readInt());\n        mDirection = Direction.valueOf(source.readInt());\n        mTimestamp = source.readLong();\n        mDuration = source.readLong();\n        mHeight = source.readInt();\n        mWidth = source.readInt();\n        mVideoEncoding = source.readString();\n        mReasonCode = VideoSharing.ReasonCode.valueOf(source.readInt());\n    }\n\n    /**\n     * Gets state\n     * \n     * @return state\n     */\n    public VideoSharing.State getState() {\n        return mState;\n    }\n\n    /**\n     * Gets reason code\n     * \n     * @return reason code\n     */\n    public VideoSharing.ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    /**\n     * Gets sharing ID\n     * \n     * @return sharingId\n     */\n    public String getSharingId() {\n        return mSharingId;\n    }\n\n    /**\n     * Gets remote contact\n     * \n     * @return contact\n     */\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    /**\n     * Gets date of the sharing\n     * \n     * @return time stamp\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Gets duration\n     * \n     * @return duration\n     */\n    public long getDuration() {\n        return mDuration;\n    }\n\n    /**\n     * Gets height\n     * \n     * @return height\n     */\n    public int getHeight() {\n        return mHeight;\n    }\n\n    /**\n     * Gets width\n     * \n     * @return width\n     */\n    public int getWidth() {\n        return mWidth;\n    }\n\n    /**\n     * Gets video encoding name (e.g. H264).\n     * \n     * @return video encoding\n     */\n    public String getVideoEncoding() {\n        return mVideoEncoding;\n    }\n\n    @Override\n    public String toString() {\n        return \"VideoSharingDAO [sharingId=\" + mSharingId + \", contact=\" + mContact + \", state=\"\n                + mState + \", duration=\" + DateUtils.formatElapsedTime(mDuration / 1000) + \"]\";\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mSharingId);\n        if (mContact != null) {\n            dest.writeInt(1);\n            mContact.writeToParcel(dest, flags);\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeInt(mState.toInt());\n        dest.writeInt(mDirection.toInt());\n        dest.writeLong(mTimestamp);\n        dest.writeLong(mDuration);\n        dest.writeInt(mHeight);\n        dest.writeInt(mWidth);\n        dest.writeString(mVideoEncoding);\n        dest.writeInt(mReasonCode.toInt());\n    }\n\n    /**\n     * public CREATOR field that generates instances of Parcelable class from a VideoSharingDAO.\n     */\n    public static final Parcelable.Creator<VideoSharingDAO> CREATOR = new Parcelable.Creator<VideoSharingDAO>() {\n        @Override\n        public VideoSharingDAO createFromParcel(Parcel in) {\n            return new VideoSharingDAO(in);\n        }\n\n        @Override\n        public VideoSharingDAO[] newArray(int size) {\n            return new VideoSharingDAO[size];\n        }\n    };\n\n    /**\n     * Gets instance of Video sharing from RCS provider\n     * \n     * @param context the context\n     * @param sharingId the sharing ID\n     * @return instance or null if entry not found\n     */\n    public static VideoSharingDAO getVideoSharingDAO(Context context, String sharingId) {\n        if (sContentResolver == null) {\n            sContentResolver = context.getContentResolver();\n        }\n        Cursor cursor = null;\n        try {\n            cursor = sContentResolver.query(\n                    Uri.withAppendedPath(VideoSharingLog.CONTENT_URI, sharingId), null, null, null,\n                    null);\n            if (cursor == null) {\n                throw new SQLException(\"Query failed!\");\n            }\n            if (!cursor.moveToFirst()) {\n                throw new SQLException(\"Failed to find Video Sharing with ID: \".concat(sharingId));\n            }\n            String number = cursor.getString(cursor.getColumnIndexOrThrow(VideoSharingLog.CONTACT));\n            ContactId contact = ContactUtil.formatContact(number);\n            VideoSharing.State state = VideoSharing.State.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(VideoSharingLog.STATE)));\n            Direction dir = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(VideoSharingLog.DIRECTION)));\n            long timestamp = cursor\n                    .getLong(cursor.getColumnIndexOrThrow(VideoSharingLog.TIMESTAMP));\n            long duration = cursor.getLong(cursor.getColumnIndexOrThrow(VideoSharingLog.DURATION));\n            int height = cursor.getInt(cursor.getColumnIndexOrThrow(VideoSharingLog.HEIGHT));\n            int width = cursor.getInt(cursor.getColumnIndexOrThrow(VideoSharingLog.WIDTH));\n            String videoEncoding = cursor.getString(cursor\n                    .getColumnIndexOrThrow(VideoSharingLog.VIDEO_ENCODING));\n            VideoSharing.ReasonCode reason = VideoSharing.ReasonCode.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(VideoSharingLog.REASON_CODE)));\n            return new VideoSharingDAO(sharingId, contact, state, reason, dir, timestamp, duration,\n                    height, width, videoEncoding);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/VideoSharingIntentService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsContactUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingIntent;\n\nimport android.app.IntentService;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.media.RingtoneManager;\nimport android.os.Bundle;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\n/**\n * Video sharing intent service\n * \n * @author YPLO6403\n */\npublic class VideoSharingIntentService extends IntentService {\n\n    private static final String LOGTAG = LogUtils.getTag(VideoSharingIntentService.class\n            .getSimpleName());\n\n    static final String BUNDLE_VSHDAO_ID = \"vshdao\";\n\n    /**\n     * Constructor\n     */\n    public VideoSharingIntentService() {\n        super(\"VideoSharingIntentService\");\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        super.onStartCommand(intent, flags, startId);\n        // We want this service to stop running if forced stop\n        // so return not sticky.\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    protected void onHandleIntent(Intent intent) {\n        String action;\n        if ((action = intent.getAction()) == null) {\n            return;\n        }\n        // Check action from incoming intent\n        if (!VideoSharingIntent.ACTION_NEW_INVITATION.equals(action)) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Unknown action \".concat(action));\n            }\n            return;\n        }\n        // Gets data from the incoming Intent\n        String sharingId = intent.getStringExtra(VideoSharingIntent.EXTRA_SHARING_ID);\n        if (sharingId == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"Cannot read sharing ID\");\n            }\n            return;\n        }\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"onHandleIntent video sharing with ID \".concat(sharingId));\n        }\n        // Get Video Sharing from provider\n        VideoSharingDAO vshDao = VideoSharingDAO.getVideoSharingDAO(this, sharingId);\n        if (vshDao == null) {\n            return;\n        }\n        // Save VideoSharingDAO into intent\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(BUNDLE_VSHDAO_ID, vshDao);\n        intent.putExtras(bundle);\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Video sharing invitation \".concat(vshDao.toString()));\n        }\n        if (VideoSharing.State.INVITED == vshDao.getState()) {\n            addVideoSharingInvitationNotification(intent, vshDao);\n        }\n    }\n\n    /**\n     * Add video share notification\n     * \n     * @param invitation Intent invitation\n     * @param vshDao the video sharing data object\n     */\n    public void addVideoSharingInvitationNotification(Intent invitation, VideoSharingDAO vshDao) {\n        if (vshDao.getContact() == null) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"VideoSharingInvitationReceiver failed: cannot parse contact\");\n            }\n            return;\n        }\n        /* Create pending intent */\n        Intent intent = new Intent(invitation);\n        intent.setClass(this, IncomingVideoSharing.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        /*\n         * If the PendingIntent has the same operation, action, data, categories, components, and\n         * flags it will be replaced. Invitation should be notified individually so we use a random\n         * generator to provide a unique request code and reuse it for the notification.\n         */\n        int uniqueId = Utils.getUniqueIdForPendingIntent();\n        PendingIntent contentIntent = PendingIntent.getActivity(this, uniqueId, intent,\n                PendingIntent.FLAG_ONE_SHOT);\n\n        String displayName = RcsContactUtil.getInstance(this).getDisplayName(vshDao.getContact());\n        String notifTitle = getString(R.string.title_recv_video_sharing);\n\n        /* Create notification */\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(contentIntent);\n        notif.setSmallIcon(R.drawable.ri_notif_csh_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n        notif.setContentTitle(notifTitle);\n        notif.setContentText(getString(R.string.label_from_args, displayName));\n\n        /* Send notification */\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(uniqueId, notif.build());\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/VideoSharingInvitationReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Video sharing invitation receiver\n * \n * @author YPLO6403\n */\npublic class VideoSharingInvitationReceiver extends BroadcastReceiver {\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        intent.setClass(context, VideoSharingIntentService.class);\n        context.startService(intent);\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/VideoSharingLogView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video;\n\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.RiApplication;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.format.DateUtils;\nimport android.widget.TextView;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\n\n/**\n * A class to view the persisted information for video sharing <br>\n * Created by Philippe LEMORDANT.\n */\npublic class VideoSharingLogView extends RcsActivity {\n    private static final String EXTRA_SHARING_ID = \"id\";\n    private String mSharingId;\n    private TextView mTxtViewContact;\n    private TextView mTxtViewDate;\n    private TextView mTxtViewDir;\n    private TextView mTxtViewDuration;\n    private TextView mTxtViewEncoding;\n    private TextView mTxtViewHeight;\n    private TextView mTxtViewReason;\n    private TextView mTxtViewState;\n    private TextView mTxtViewWidth;\n    private SimpleDateFormat sDateFormat;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.sharing_log_video_item);\n        initialize();\n        mSharingId = getIntent().getStringExtra(EXTRA_SHARING_ID);\n    }\n\n    private void initialize() {\n        mTxtViewContact = (TextView) findViewById(R.id.history_log_item_contact);\n        mTxtViewState = (TextView) findViewById(R.id.history_log_item_state);\n        mTxtViewReason = (TextView) findViewById(R.id.history_log_item_reason);\n        mTxtViewDir = (TextView) findViewById(R.id.history_log_item_direction);\n        mTxtViewDate = (TextView) findViewById(R.id.history_log_item_date);\n        mTxtViewDuration = (TextView) findViewById(R.id.history_log_item_duration);\n        mTxtViewHeight = (TextView) findViewById(R.id.history_log_item_height);\n        mTxtViewWidth = (TextView) findViewById(R.id.history_log_item_width);\n        mTxtViewEncoding = (TextView) findViewById(R.id.history_log_item_encoding);\n    }\n\n    private String getDateFromDb(long timestamp) {\n        if (0 == timestamp) {\n            return \"\";\n        }\n        if (sDateFormat == null) {\n            sDateFormat = new SimpleDateFormat(\"yyyy/MM/dd HH:mm:ss\", Locale.getDefault());\n        }\n        return sDateFormat.format(new Date(timestamp));\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        VideoSharingDAO dao = VideoSharingDAO.getVideoSharingDAO(this, mSharingId);\n        if (dao == null) {\n            showMessageThenExit(R.string.error_item_not_found);\n            return;\n        }\n        mTxtViewContact.setText(dao.getContact().toString());\n        mTxtViewState.setText(RiApplication.sVideoSharingStates[dao.getState().toInt()]);\n        mTxtViewReason.setText(RiApplication.sVideoReasonCodes[dao.getReasonCode().toInt()]);\n        mTxtViewDir.setText(RiApplication.getDirection(dao.getDirection()));\n        mTxtViewDate.setText(getDateFromDb(dao.getTimestamp()));\n        mTxtViewDuration.setText(DateUtils.formatElapsedTime(dao.getDuration() / 1000));\n        mTxtViewHeight.setText(String.valueOf(dao.getHeight()));\n        mTxtViewWidth.setText(String.valueOf(dao.getWidth()));\n        mTxtViewEncoding.setText(dao.getVideoEncoding());\n    }\n\n    /**\n     * Start activity to view details of video sharing record\n     *\n     * @param context the context\n     * @param sharingId the sharing ID\n     */\n    public static void startActivity(Context context, String sharingId) {\n        Intent intent = new Intent(context, VideoSharingLogView.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        intent.putExtra(EXTRA_SHARING_ID, sharingId);\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/media/FifoBuffer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video.media;\n\nimport java.util.Vector;\n\n/**\n * FIFO buffer\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FifoBuffer {\n    /**\n     * Number of objects in the buffer\n     */\n    private int nbObjects = 0;\n\n    /**\n     * Buffer of objects\n     */\n    private Vector<Object> fifo = new Vector<>();\n\n    /**\n     * Add an object in the buffer\n     * \n     * @param obj Message\n     */\n    public synchronized void addObject(Object obj) {\n        fifo.addElement(obj);\n        nbObjects++;\n        notifyAll();\n    }\n\n    /**\n     * Read an object in the buffer. This is a blocking method until an object is read.\n     * \n     * @return Object\n     */\n    public synchronized Object getObject() {\n        Object obj = null;\n        if (nbObjects == 0) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n                // Nothing to do\n            }\n        }\n        if (nbObjects != 0) {\n            obj = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            nbObjects--;\n            notifyAll();\n        }\n        return obj;\n    }\n\n    /**\n     * Read an object in the buffer. This is a blocking method until a timeout occurs or an object\n     * is read.\n     * \n     * @param timeout Timeout\n     * @return Message\n     */\n    public synchronized Object getObject(int timeout) {\n        Object obj = null;\n        if (nbObjects == 0) {\n            try {\n                wait(timeout);\n            } catch (InterruptedException e) {\n                // Nothing to do\n            }\n        }\n        if (nbObjects != 0) {\n            obj = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            nbObjects--;\n            notifyAll();\n        }\n        return obj;\n    }\n\n    /**\n     * Close the buffer\n     */\n    public synchronized void close() {\n        // Free the semaphore\n        this.notifyAll();\n    }\n\n    /**\n     * Get FIFO size\n     * \n     * @return size of the FIFO\n     */\n    public int size() {\n        return fifo.size();\n    }\n\n    /**\n     * clean FIFO\n     * \n     * @param size\n     */\n    public void clean(int size) {\n        if (fifo.size() > size) {\n            while (size > 0) {\n                fifo.removeElementAt(0);\n                nbObjects--;\n                size--;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/media/OriginatingVideoPlayer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video.media;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.ri.utils.DatagramConnection;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.NetworkRessourceManager;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\nimport com.gsma.services.rcs.sharing.video.VideoPlayer;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.RtpException;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.RtpUtils;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.VideoRtpSender;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.encoder.NativeH264Encoder;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.encoder.NativeH264EncoderParams;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264Profile1b;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.CameraOptions;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.H264VideoFormat;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.Orientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaException;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.VideoSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\n\nimport android.hardware.Camera;\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport java.io.IOException;\n\n/**\n * Live RTP video player based on H264 QCIF format\n */\npublic class OriginatingVideoPlayer extends VideoPlayer implements Camera.PreviewCallback,\n        RtpStreamListener {\n    /**\n     * Default video codec\n     */\n    private VideoCodec mDefaultVideoCodec;\n\n    /**\n     * Is player opened\n     */\n    private boolean mOpened = false;\n\n    /**\n     * Is player started\n     */\n    private boolean mStarted = false;\n\n    private int mLocalRtpPort;\n\n    /**\n     * RTP sender session\n     */\n    private VideoRtpSender mRtpSender;\n\n    /**\n     * RTP media input\n     */\n    private MediaRtpInput mRtpInput;\n\n    /**\n     * Video start time\n     */\n    private long mVideoStartTime = 0L;\n\n    /**\n     * Temporary connection to reserve the port\n     */\n    private DatagramConnection mTemporaryConnection;\n\n    /**\n     * NAL SPS\n     */\n    private byte[] mSps = new byte[0];\n\n    /**\n     * NAL PPS\n     */\n    private byte[] mPps = new byte[0];\n\n    /**\n     * Timestamp increment\n     */\n    private int mTimestampInc;\n\n    private long mTimeStamp = 0;\n\n    /**\n     * NAL initialization\n     */\n    private boolean mNalInit = false;\n\n    /**\n     * NAL repeat\n     */\n    private int mNalRepeat = 0;\n\n    /**\n     * NAL repeat MAX value\n     */\n    private static final int NALREPEATMAX = 20;\n\n    /**\n     * Scaling factor for encoding\n     */\n    private float mScaleFactor = 1;\n\n    /**\n     * Mirroring (horizontal and vertival) for encoding\n     */\n    private boolean mMirroring = false;\n\n    private Orientation mOrientation = Orientation.NONE;\n\n    private int mOrientationHeaderId = RtpUtils.RTP_DEFAULT_EXTENSION_ID;\n\n    private int mCameraId = CameraOptions.BACK.getValue();\n\n    private FrameProcess mFrameProcess;\n\n    private FrameBuffer mFrameBuffer = new FrameBuffer();\n\n    private VideoPlayerListener mEventListener;\n\n    private String mRemoteHost;\n\n    private int mRemotePort;\n\n    private static final String LOGTAG = LogUtils.getTag(OriginatingVideoPlayer.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param eventListener Player event listener\n     */\n    public OriginatingVideoPlayer(VideoPlayerListener eventListener) {\n        // Set event listener\n        mEventListener = eventListener;\n\n        // Set the local RTP port\n        mLocalRtpPort = NetworkRessourceManager.generateLocalRtpPort();\n        reservePort(mLocalRtpPort);\n\n        // Set the default media codec\n        mDefaultVideoCodec = new VideoCodec(H264Config.CODEC_NAME, H264VideoFormat.PAYLOAD,\n                H264Config.CLOCK_RATE, 15, 96000, H264Config.QCIF_WIDTH, H264Config.QCIF_HEIGHT,\n                H264Config.CODEC_PARAM_PROFILEID + \"=\" + H264Profile1b.BASELINE_PROFILE_ID + \";\"\n                        + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=\"\n                        + JavaPacketizer.H264_ENABLED_PACKETIZATION_MODE);\n    }\n\n    /**\n     * Set the remote info\n     * \n     * @param codec Video codec\n     * @param remoteHost Remote RTP host\n     * @param remotePort Remote RTP port\n     * @param orientationHeaderId Orientation header extension ID. The extension ID is a value\n     *            between 1 and 15 arbitrarily chosen by the sender, as defined in RFC5285\n     */\n    public void setRemoteInfo(VideoCodec codec, String remoteHost, int remotePort,\n            int orientationHeaderId) {\n        // Set the video codec\n        mDefaultVideoCodec = codec;\n\n        // Set remote host and port\n        mRemoteHost = remoteHost;\n        mRemotePort = remotePort;\n\n        // Set the orientation ID\n        mOrientationHeaderId = orientationHeaderId;\n    }\n\n    /**\n     * Returns the local RTP port\n     * \n     * @return Port\n     */\n    public int getLocalRtpPort() {\n        return mLocalRtpPort;\n    }\n\n    /**\n     * Returns the list of codecs supported by the player\n     * \n     * @return List of codecs\n     */\n    public VideoCodec[] getSupportedCodecs() {\n        VideoCodec[] list = new VideoCodec[1];\n        list[0] = mDefaultVideoCodec;\n        return list;\n    }\n\n    /**\n     * Returns the current codec\n     * \n     * @return Codec\n     */\n    public VideoCodec getCodec() {\n        return mDefaultVideoCodec;\n    }\n\n    /**\n     * Opens the player and prepares resources\n     */\n    public synchronized void open() {\n        if (mOpened) {\n            // Already opened\n            return;\n        }\n\n        // Init video encoder\n        try {\n            mTimestampInc = (int) (90000 / mDefaultVideoCodec.getFrameRate());\n            NativeH264EncoderParams nativeH264EncoderParams = new NativeH264EncoderParams();\n\n            // Codec dimensions\n            nativeH264EncoderParams.setFrameWidth(mDefaultVideoCodec.getWidth());\n            nativeH264EncoderParams.setFrameHeight(mDefaultVideoCodec.getHeight());\n            nativeH264EncoderParams.setFrameRate(mDefaultVideoCodec.getFrameRate());\n            nativeH264EncoderParams.setBitRate(mDefaultVideoCodec.getBitRate());\n\n            // Codec profile and level\n            nativeH264EncoderParams.setProfilesAndLevel(mDefaultVideoCodec.getParameters());\n\n            // Codec settings optimization\n            nativeH264EncoderParams.setEncMode(NativeH264EncoderParams.ENCODING_MODE_STREAMING);\n            nativeH264EncoderParams.setSceneDetection(false);\n            nativeH264EncoderParams.setIFrameInterval(15);\n\n            int result = NativeH264Encoder.InitEncoder(nativeH264EncoderParams);\n            if (result != 0) {\n                // Encoder init has failed\n                mEventListener.onPlayerError();\n                return;\n            }\n        } catch (UnsatisfiedLinkError e) {\n            // Native encoder not found\n            mEventListener.onPlayerError();\n            return;\n        }\n\n        // Init the RTP layer\n        try {\n            releasePort();\n            mRtpSender = new VideoRtpSender(new H264VideoFormat(), mLocalRtpPort);\n            mRtpInput = new MediaRtpInput();\n            mRtpInput.open();\n            mRtpSender.prepareSession(mRtpInput, mRemoteHost, mRemotePort, this);\n\n        } catch (RtpException e) {\n            // RTP failure\n            Log.d(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            mEventListener.onPlayerError();\n            return;\n        }\n\n        // Player is opened\n        mOpened = true;\n        mEventListener.onPlayerOpened();\n    }\n\n    /**\n     * Closes the player and deallocates resources\n     */\n    public synchronized void close() {\n        if (!mOpened) {\n            // Already closed\n            return;\n        }\n        // Close the RTP layer\n        mRtpInput.close();\n        mRtpSender.stopSession();\n\n        try {\n            // Close the video encoder\n            NativeH264Encoder.DeinitEncoder();\n        } catch (UnsatisfiedLinkError e) {\n            Log.d(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n\n        // Player is closed\n        mOpened = false;\n        mEventListener.onPlayerClosed();\n    }\n\n    /**\n     * Starts the player\n     */\n    public synchronized void start() {\n        if (!mOpened) {\n            // Player not opened\n            return;\n        }\n\n        if (mStarted) {\n            // Already started\n            return;\n        }\n\n        // Init NAL\n        if (!initNAL()) {\n            return;\n        }\n        mNalInit = false;\n\n        mTimeStamp = 0;\n        mNalInit = false;\n        mNalRepeat = 0;\n\n        // Start RTP layer\n        mRtpSender.startSession();\n\n        // Player is started\n        mVideoStartTime = SystemClock.uptimeMillis();\n        mStarted = true;\n        mFrameProcess = new FrameProcess((int) mDefaultVideoCodec.getFrameRate());\n        mFrameProcess.start();\n        mEventListener.onPlayerStarted();\n    }\n\n    /**\n     * Stops the player\n     */\n    public synchronized void stop() {\n        if (!mOpened) {\n            // Player not opened\n            return;\n        }\n\n        if (!mStarted) {\n            // Already stopped\n            return;\n        }\n\n        // Player is stopped\n        mVideoStartTime = 0L;\n        mStarted = false;\n        mFrameProcess.interrupt();\n        mEventListener.onPlayerStopped();\n    }\n\n    /*---------------------------------------------------------------------*/\n\n    /**\n     * Reserve a port.\n     * \n     * @param port Port to reserve\n     */\n    private void reservePort(int port) {\n        if (mTemporaryConnection == null) {\n            try {\n                mTemporaryConnection = NetworkRessourceManager.createDatagramConnection();\n                mTemporaryConnection.open(port);\n\n            } catch (IOException e) {\n                mTemporaryConnection = null;\n            }\n        }\n    }\n\n    /**\n     * Release the reserved port.\n     */\n    private void releasePort() {\n        if (mTemporaryConnection != null) {\n            try {\n                mTemporaryConnection.close();\n            } catch (IOException e) {\n                mTemporaryConnection = null;\n            }\n        }\n    }\n\n    /**\n     * Return the video start time\n     * \n     * @return Milliseconds\n     */\n    public long getVideoStartTime() {\n        return mVideoStartTime;\n    }\n\n    /**\n     * Init sps and pps\n     * \n     * @return true if done\n     */\n    private boolean initNAL() {\n        boolean ret = initOneNAL();\n        if (ret) {\n            ret = initOneNAL();\n        }\n        return ret;\n    }\n\n    /**\n     * Init sps or pps\n     * \n     * @return true if done\n     */\n    private boolean initOneNAL() {\n        byte[] nal = NativeH264Encoder.getNAL();\n        if ((nal != null) && (nal.length > 0)) {\n            int type = (nal[0] & 0x1f);\n            if (type == JavaPacketizer.AVC_NALTYPE_SPS) {\n                mSps = nal;\n                return true;\n            } else if (type == JavaPacketizer.AVC_NALTYPE_PPS) {\n                mPps = nal;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Get video width\n     * \n     * @return Width\n     */\n    public int getVideoWidth() {\n        if (mDefaultVideoCodec == null) {\n            return H264Config.VIDEO_WIDTH;\n        } else {\n            return mDefaultVideoCodec.getWidth();\n        }\n    }\n\n    /**\n     * Get video height\n     * \n     * @return Height\n     */\n    public int getVideoHeight() {\n        if (mDefaultVideoCodec == null) {\n            return H264Config.VIDEO_HEIGHT;\n        } else {\n            return mDefaultVideoCodec.getHeight();\n        }\n    }\n\n    /**\n     * Set extension header orientation id\n     * \n     * @param headerId extension header orientation id\n     */\n    public void setOrientationHeaderId(int headerId) {\n        this.mOrientationHeaderId = headerId;\n    }\n\n    /**\n     * Set video orientation\n     * \n     * @param orientation\n     */\n    public void setOrientation(Orientation orientation) {\n        mOrientation = orientation;\n    }\n\n    /**\n     * Set camera ID\n     * \n     * @param cameraId Camera ID\n     */\n    public void setCameraId(int cameraId) {\n        this.mCameraId = cameraId;\n    }\n\n    /**\n     * Set the mirroring value\n     * \n     * @param mirroring New mirroring value\n     */\n    public void setMirroring(boolean mirroring) {\n        this.mMirroring = mirroring;\n    }\n\n    /**\n     * Notify RTP aborted\n     */\n    public void rtpStreamAborted() {\n        // RTP failure\n        mEventListener.onPlayerError();\n    }\n\n    /**\n     * Preview frame from the camera\n     * \n     * @param data Frame\n     * @param camera Camera\n     */\n    public void onPreviewFrame(byte[] data, Camera camera) {\n        if (!mStarted) {\n            return;\n        }\n        mFrameBuffer.setData(data);\n    };\n\n    /**\n     * encode a buffer and add in RTP input\n     * \n     * @param data\n     */\n    private void encode(byte[] data) {\n        // Send SPS/PPS if necessary\n        mNalRepeat++;\n        if (mNalRepeat > NALREPEATMAX) {\n            mNalInit = false;\n            mNalRepeat = 0;\n        }\n        if (!mNalInit) {\n            mRtpInput.addFrame(mSps, mTimeStamp);\n            mTimeStamp += mTimestampInc;\n\n            mRtpInput.addFrame(mPps, mTimeStamp);\n            mTimeStamp += mTimestampInc;\n\n            mNalInit = true;\n        }\n\n        // Encode frame\n        byte[] encoded;\n        if (mFrameBuffer.dataSrcWidth != 0 && mFrameBuffer.dataSrcHeight != 0) {\n            encoded = NativeH264Encoder.ResizeAndEncodeFrame(data, mTimeStamp, mMirroring,\n                    mFrameBuffer.dataSrcWidth, mFrameBuffer.dataSrcHeight);\n        } else {\n            encoded = NativeH264Encoder.EncodeFrame(data, mTimeStamp, mMirroring,\n                    mFrameBuffer.dataScaleFactor);\n        }\n        int encodeResult = NativeH264Encoder.getLastEncodeStatus();\n        if ((encodeResult == 0) && (encoded.length > 0)) {\n            VideoOrientation videoOrientation = null;\n            if (mOrientationHeaderId > 0) {\n                videoOrientation = new VideoOrientation(mOrientationHeaderId,\n                        CameraOptions.convert(mCameraId), mOrientation);\n            }\n            mRtpInput.addFrame(encoded, mTimeStamp, videoOrientation);\n            mTimeStamp += mTimestampInc;\n        }\n    }\n\n    /**\n     * Frame process\n     */\n    private class FrameProcess extends Thread {\n\n        /**\n         * Time between two frame\n         */\n        private int interframe = 1000 / 15;\n\n        /**\n         * Constructor\n         * \n         * @param framerate\n         */\n        public FrameProcess(int framerate) {\n            super();\n            interframe = 1000 / framerate;\n        }\n\n        @Override\n        public void run() {\n            byte[] frameData = null;\n            while (mStarted) {\n                long time = System.currentTimeMillis();\n\n                // Encode\n                frameData = mFrameBuffer.getData();\n                if (frameData != null) {\n                    encode(frameData);\n                }\n\n                // Sleep between frames if necessary\n                long delta = System.currentTimeMillis() - time;\n                if (delta < interframe) {\n                    try {\n                        Thread.sleep((interframe - delta) - (((interframe - delta) * 10) / 100));\n                    } catch (InterruptedException e) {\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Frame buffer\n     */\n    private class FrameBuffer {\n        /**\n         * Data\n         */\n        private byte[] data = null;\n\n        /**\n         * Scaling factor for encoding\n         */\n        public float dataScaleFactor = 1;\n\n        /**\n         * Source Width - used for resizing\n         */\n        public int dataSrcWidth = 0;\n\n        /**\n         * Source Height - used for resizing\n         */\n        public int dataSrcHeight = 0;\n\n        /**\n         * Get the data\n         * \n         * @return data\n         */\n        public synchronized byte[] getData() {\n            return data;\n        }\n\n        /**\n         * Set the data\n         * \n         * @param data\n         */\n        public synchronized void setData(byte[] data) {\n            this.data = data;\n\n            // Update resizing / scaling values\n            this.dataScaleFactor = mScaleFactor;\n            this.dataSrcWidth = mDefaultVideoCodec.getWidth();\n            this.dataSrcHeight = mDefaultVideoCodec.getHeight();\n        }\n    }\n\n    /**\n     * Media RTP input\n     */\n    private static class MediaRtpInput implements MediaInput {\n        /**\n         * Received frames\n         */\n        private FifoBuffer fifo = null;\n\n        /**\n         * Constructor\n         */\n        public MediaRtpInput() {\n        }\n\n        /**\n         * Add a new video frame\n         * \n         * @param data Data\n         * @param timestamp Timestamp\n         * @param videoOrientation\n         * @param marker Marker bit\n         */\n        public void addFrame(byte[] data, long timestamp, VideoOrientation videoOrientation) {\n            if (fifo != null) {\n                VideoSample sample = new VideoSample(data, timestamp, videoOrientation);\n                fifo.addObject(sample);\n            }\n        }\n\n        /**\n         * Add a new video frame\n         * \n         * @param data Data\n         * @param timestamp Timestamp\n         * @param marker Marker bit\n         */\n        public void addFrame(byte[] data, long timestamp) {\n            addFrame(data, timestamp, null);\n        }\n\n        /**\n         * Open the player\n         */\n        public void open() {\n            fifo = new FifoBuffer();\n        }\n\n        /**\n         * Close the player\n         */\n        public void close() {\n            if (fifo != null) {\n                fifo.close();\n                fifo = null;\n            }\n        }\n\n        /**\n         * Read a media sample (blocking method)\n         * \n         * @return Media sample\n         * @throws MediaException\n         */\n        public VideoSample readSample() throws MediaException {\n            if (fifo != null) {\n                return (VideoSample) fifo.getObject();\n            } else {\n                throw new MediaException(\"Media input not opened\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/media/TerminatingVideoPlayer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video.media;\n\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.ri.utils.DatagramConnection;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.NetworkRessourceManager;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\nimport com.gsma.services.rcs.sharing.video.VideoPlayer;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.DummyPacketGenerator;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.RtpException;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.VideoRtpReceiver;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.decoder.NativeH264Decoder;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264Profile1b;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.CameraOptions;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.H264VideoFormat;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.Orientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.VideoSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\n\nimport android.graphics.Bitmap;\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport java.io.IOException;\n\n/**\n * Live video RTP renderer based on H264 QCIF format\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TerminatingVideoPlayer extends VideoPlayer implements RtpStreamListener {\n\n    private VideoCodec mDefaultVideoCodec;\n\n    private int mLocalRtpPort;\n\n    /**\n     * RTP receiver session\n     */\n    private VideoRtpReceiver mRtpReceiver;\n\n    /**\n     * RTP dummy packet generator\n     */\n    private DummyPacketGenerator mRtpDummySender;\n\n    /**\n     * RTP media output\n     */\n    private MediaRtpOutput mRtpOutput;\n\n    /**\n     * Is player opened\n     */\n    private boolean mOpened = false;\n\n    /**\n     * Is player started\n     */\n    private boolean mStarted = false;\n\n    private long mVideoStartTime = 0L;\n\n    /**\n     * Video surface\n     */\n    private VideoSurface mSurface;\n\n    /**\n     * Temporary connection to reserve the port\n     */\n    private DatagramConnection mTemporaryConnection;\n\n    private int mOrientationHeaderId = -1;\n\n    private VideoPlayerListener mEventListener;\n\n    private String mRemoteHost;\n\n    private int mRemotePort;\n\n    private static final String LOGTAG = LogUtils.getTag(TerminatingVideoPlayer.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param surface Surface view\n     * @param eventListener Player event listener\n     */\n    public TerminatingVideoPlayer(VideoSurfaceView surface, VideoPlayerListener eventListener) {\n        // Set surface view\n        mSurface = surface;\n\n        // Set event listener\n        mEventListener = eventListener;\n\n        // Set the local RTP port\n        mLocalRtpPort = NetworkRessourceManager.generateLocalRtpPort();\n        reservePort(mLocalRtpPort);\n\n        // Set the default media codec\n        mDefaultVideoCodec = new VideoCodec(H264Config.CODEC_NAME, H264VideoFormat.PAYLOAD,\n                H264Config.CLOCK_RATE, 15, 96000, H264Config.QCIF_WIDTH, H264Config.QCIF_HEIGHT,\n                H264Config.CODEC_PARAM_PROFILEID + \"=\" + H264Profile1b.BASELINE_PROFILE_ID + \";\"\n                        + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=\"\n                        + JavaPacketizer.H264_ENABLED_PACKETIZATION_MODE);\n    }\n\n    /**\n     * Set the remote info\n     * \n     * @param codec Video codec\n     * @param remoteHost Remote RTP host\n     * @param remotePort Remote RTP port\n     * @param orientationHeaderId Orientation header extension ID. The extension ID is a value\n     *            between 1 and 15 arbitrarily chosen by the sender, as defined in RFC5285\n     */\n    public void setRemoteInfo(VideoCodec codec, String remoteHost, int remotePort,\n            int orientationHeaderId) {\n        // Set the video codec\n        mDefaultVideoCodec = codec;\n\n        // Set remote host and port\n        mRemoteHost = remoteHost;\n        mRemotePort = remotePort;\n\n        // Set the orientation ID\n        mOrientationHeaderId = orientationHeaderId;\n    }\n\n    /**\n     * Returns the list of codecs supported by the player\n     * \n     * @return List of codecs\n     */\n    public VideoCodec[] getSupportedCodecs() {\n        VideoCodec[] list = new VideoCodec[1];\n        list[0] = mDefaultVideoCodec;\n        return list;\n    }\n\n    /**\n     * Returns the current codec\n     * \n     * @return Codec\n     */\n    public VideoCodec getCodec() {\n        return mDefaultVideoCodec;\n    }\n\n    /**\n     * Opens the player and prepares resources\n     */\n    public synchronized void open() {\n        if (mOpened) {\n            // Already opened\n            return;\n        }\n\n        try {\n            // Init the video decoder\n            int result = NativeH264Decoder.InitDecoder();\n            if (result != 0) {\n                // Decoder init failed\n                mEventListener.onPlayerError();\n                return;\n            }\n\n            // Init the RTP layer\n            releasePort();\n            mRtpReceiver = new VideoRtpReceiver(mLocalRtpPort);\n            mRtpDummySender = new DummyPacketGenerator();\n            mRtpOutput = new MediaRtpOutput();\n            mRtpOutput.open();\n            mRtpReceiver.prepareSession(mRemoteHost, mRemotePort, mOrientationHeaderId, mRtpOutput,\n                    new H264VideoFormat(), this);\n            mRtpDummySender.prepareSession(mRemoteHost, mRemotePort, mRtpReceiver.getInputStream());\n            mRtpDummySender.startSession();\n        } catch (RtpException e) {\n            // RTP failed\n            mEventListener.onPlayerError();\n            return;\n        }\n\n        // Player is opened\n        mOpened = true;\n        mEventListener.onPlayerOpened();\n    }\n\n    /**\n     * Closes the player and deallocates resources\n     */\n    public synchronized void close() {\n        if (!mOpened) {\n            // Already closed\n            return;\n        }\n\n        // Close the RTP layer\n        mRtpOutput.close();\n        mRtpReceiver.stopSession();\n        mRtpDummySender.stopSession();\n\n        try {\n            // Close the video decoder\n            NativeH264Decoder.DeinitDecoder();\n        } catch (UnsatisfiedLinkError e) {\n            Log.d(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n\n        // Player is closed\n        mOpened = false;\n        mEventListener.onPlayerClosed();\n    }\n\n    /**\n     * Starts the player\n     */\n    public synchronized void start() {\n        if (!mOpened) {\n            // Player not opened\n            return;\n        }\n\n        if (mStarted) {\n            // Already started\n            return;\n        }\n\n        // Start RTP layer\n        mRtpReceiver.startSession();\n\n        // Player is started\n        mVideoStartTime = SystemClock.uptimeMillis();\n        mStarted = true;\n        mEventListener.onPlayerStarted();\n    }\n\n    /**\n     * Stops the player\n     */\n    public synchronized void stop() {\n        if (!mStarted) {\n            return;\n        }\n\n        // Stop RTP layer\n        if (mRtpReceiver != null) {\n            mRtpReceiver.stopSession();\n        }\n        if (mRtpDummySender != null) {\n            mRtpDummySender.stopSession();\n        }\n        if (mRtpOutput != null) {\n            mRtpOutput.close();\n        }\n\n        // Force black screen\n        mSurface.clearImage();\n\n        // Player is stopped\n        mStarted = false;\n        mVideoStartTime = 0L;\n        mEventListener.onPlayerStopped();\n    }\n\n    /*---------------------------------------------------------------------*/\n\n    /**\n     * Return the video start time\n     * \n     * @return Milliseconds\n     */\n    public long getVideoStartTime() {\n        return mVideoStartTime;\n    }\n\n    /**\n     * Returns the local RTP port\n     * \n     * @return Port\n     */\n    public int getLocalRtpPort() {\n        return mLocalRtpPort;\n    }\n\n    /**\n     * Reserve a port\n     * \n     * @param port Port to reserve\n     */\n    private void reservePort(int port) {\n        if (mTemporaryConnection == null) {\n            try {\n                mTemporaryConnection = NetworkRessourceManager.createDatagramConnection();\n                mTemporaryConnection.open(port);\n            } catch (IOException e) {\n                mTemporaryConnection = null;\n            }\n        }\n    }\n\n    /**\n     * Release the reserved port.\n     */\n    private void releasePort() {\n        if (mTemporaryConnection != null) {\n            try {\n                mTemporaryConnection.close();\n            } catch (IOException e) {\n                mTemporaryConnection = null;\n            }\n        }\n    }\n\n    /**\n     * Is player opened\n     * \n     * @return Boolean\n     */\n    public boolean isOpened() {\n        return mOpened;\n    }\n\n    /**\n     * Is player started\n     * \n     * @return Boolean\n     */\n    public boolean isStarted() {\n        return mStarted;\n    }\n\n    /**\n     * Notify RTP aborted\n     */\n    public void rtpStreamAborted() {\n        mEventListener.onPlayerError();\n    }\n\n    /**\n     * Set the video orientation\n     * \n     * @param orientation Video orientation value (see urn:3gpp:video-orientation)\n     */\n    public void setOrientation(int orientation) {\n        this.mOrientationHeaderId = orientation;\n    }\n\n    /**\n     * Media RTP output\n     */\n    private class MediaRtpOutput implements MediaOutput {\n        /**\n         * Bitmap frame\n         */\n        private Bitmap rgbFrame = null;\n\n        /**\n         * Video orientation\n         */\n        private VideoOrientation videoOrientation = new VideoOrientation(CameraOptions.BACK,\n                Orientation.NONE);\n\n        /**\n         * Frame dimensions Just 2 - width and height\n         */\n        private int decodedFrameDimensions[] = new int[2];\n\n        /**\n         * Constructor\n         */\n        public MediaRtpOutput() {\n            // Init rgbFrame with a default size\n            rgbFrame = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);\n        }\n\n        /**\n         * Open the renderer\n         */\n        public void open() {\n            // Nothing to do\n        }\n\n        /**\n         * Close the renderer\n         */\n        public void close() {\n        }\n\n        /**\n         * Write a media sample\n         * \n         * @param sample Sample\n         */\n        public void writeSample(MediaSample sample) {\n            mRtpDummySender.incomingStarted();\n\n            // Init orientation\n            VideoOrientation orientation = ((VideoSample) sample).getVideoOrientation();\n            if (orientation != null) {\n                this.videoOrientation = orientation;\n            }\n\n            int[] decodedFrame = NativeH264Decoder.DecodeAndConvert(sample.getData(),\n                    videoOrientation.getOrientation().getValue(), decodedFrameDimensions);\n            if (NativeH264Decoder.getLastDecodeStatus() == 0) {\n                if ((mSurface != null) && (decodedFrame.length > 0)) {\n                    // Init RGB frame with the decoder dimensions\n                    if ((rgbFrame.getWidth() != decodedFrameDimensions[0])\n                            || (rgbFrame.getHeight() != decodedFrameDimensions[1])) {\n                        rgbFrame = Bitmap.createBitmap(decodedFrameDimensions[0],\n                                decodedFrameDimensions[1], Bitmap.Config.RGB_565);\n                        mEventListener.onPlayerResized(decodedFrameDimensions[0],\n                                decodedFrameDimensions[1]);\n                    }\n\n                    // Set data in image\n                    rgbFrame.setPixels(decodedFrame, 0, decodedFrameDimensions[0], 0, 0,\n                            decodedFrameDimensions[0], decodedFrameDimensions[1]);\n                    mSurface.setImage(rgbFrame);\n                }\n            }\n        }\n    }\n\n    /**\n     * Set the surface\n     * \n     * @param surface\n     */\n    public void setSurface(VideoSurface surface) {\n        this.mSurface = surface;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/media/VideoPlayerListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video.media;\n\n/**\n * This interface offers callback methods on video player events\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface VideoPlayerListener {\n    /**\n     * Callback called when the player is opened\n     */\n    public void onPlayerOpened();\n\n    /**\n     * Callback called when the player is started\n     */\n    public void onPlayerStarted();\n\n    /**\n     * Callback called when the player is stopped\n     */\n    public void onPlayerStopped();\n\n    /**\n     * Callback called when the player is closed\n     */\n    public void onPlayerClosed();\n\n    /**\n     * Callback called when the player has failed\n     */\n    public void onPlayerError();\n\n    /**\n     * Callback called when the player has been resized\n     */\n    public void onPlayerResized(int width, int height);\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/media/VideoSurface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video.media;\n\nimport android.graphics.Bitmap;\n\n/**\n * Video Surface interface\n * \n * @author Deutsche Telekom\n */\npublic interface VideoSurface {\n    /**\n     * Set image from a bitmap\n     * \n     * @param bmp Bitmap\n     */\n    public void setImage(Bitmap bmp);\n\n    /**\n     * Clears the image\n     */\n    public void clearImage();\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/sharing/video/media/VideoSurfaceView.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.sharing.video.media;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.util.AttributeSet;\nimport android.view.SurfaceHolder;\nimport android.view.SurfaceView;\n\n/**\n * Video surface view\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoSurfaceView extends SurfaceView implements VideoSurface {\n    /**\n     * No aspect ratio\n     */\n    public static final float NO_RATIO = 0.0f;\n\n    /**\n     * Display area aspect ratio\n     */\n    private float aspectRatio = NO_RATIO;\n\n    /**\n     * Surface has been created state\n     */\n    private boolean surfaceCreated = false;\n\n    /**\n     * Surface holder\n     */\n    private SurfaceHolder holder;\n\n    /**\n     * Constructor\n     * \n     * @param context Context\n     */\n    public VideoSurfaceView(Context context) {\n        super(context);\n\n        init();\n    }\n\n    /**\n     * Constructor\n     * \n     * @param context Context\n     * @param attrs Attributes\n     */\n    public VideoSurfaceView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        init();\n    }\n\n    /**\n     * Constructor\n     * \n     * @param context Context\n     * @param attrs Attributes\n     * @param defStyle Style\n     */\n    public VideoSurfaceView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        init();\n    }\n\n    /**\n     * Set aspect ration according to desired width and height\n     * \n     * @param width Width\n     * @param height Height\n     */\n    public void setAspectRatio(int width, int height) {\n        setAspectRatio((float) width / (float) height);\n    }\n\n    /**\n     * Set aspect ratio\n     * \n     * @param ratio Ratio\n     */\n    public void setAspectRatio(float ratio) {\n        if (aspectRatio != ratio) {\n            aspectRatio = ratio;\n            requestLayout();\n            invalidate();\n        }\n    }\n\n    /**\n     * Ensure aspect ratio\n     * \n     * @param widthMeasureSpec Width\n     * @param heightMeasureSpec Heigh\n     */\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (aspectRatio != NO_RATIO) {\n            int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);\n            int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);\n\n            int width = widthSpecSize;\n            int height = heightSpecSize;\n\n            if (width > 0 && height > 0) {\n                float defaultRatio = ((float) width) / ((float) height);\n                if (defaultRatio < aspectRatio) {\n                    // Need to reduce height\n                    height = (int) (width / aspectRatio);\n                } else if (defaultRatio > aspectRatio) {\n                    width = (int) (height * aspectRatio);\n                }\n                width = Math.min(width, widthSpecSize);\n                height = Math.min(height, heightSpecSize);\n                setMeasuredDimension(width, height);\n                return;\n            }\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    /**\n     * Set image from a bitmap\n     * \n     * @param bmp Bitmap\n     */\n    public void setImage(Bitmap bmp) {\n        if (surfaceCreated) {\n            Canvas canvas = null;\n            try {\n                synchronized (holder) {\n                    canvas = holder.lockCanvas();\n                }\n            } finally {\n                if (canvas != null) {\n                    // First clear screen\n                    canvas.drawARGB(255, 0, 0, 0);\n\n                    // Then draw bmp\n                    canvas.drawBitmap(bmp, null, canvas.getClipBounds(), null);\n                    holder.unlockCanvasAndPost(canvas);\n                }\n            }\n        }\n    }\n\n    public void clearImage() {\n        if (surfaceCreated) {\n            Canvas canvas = null;\n            try {\n                synchronized (holder) {\n                    canvas = holder.lockCanvas();\n                }\n            } finally {\n                if (canvas != null) {\n                    // Clear screen\n                    canvas.drawARGB(255, 0, 0, 0);\n\n                    holder.unlockCanvasAndPost(canvas);\n                }\n            }\n        }\n    }\n\n    /**\n     * Init the view\n     */\n    private void init() {\n        // Get a surface holder\n        holder = this.getHolder();\n        holder.addCallback(surfaceCallback);\n    }\n\n    /**\n     * Surface holder callback\n     */\n    private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {\n        public void surfaceChanged(SurfaceHolder _holder, int format, int w, int h) {\n        }\n\n        public void surfaceCreated(SurfaceHolder _holder) {\n            surfaceCreated = true;\n        }\n\n        public void surfaceDestroyed(SurfaceHolder _holder) {\n            surfaceCreated = false;\n        }\n    };\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/upload/InitiateFileUpload.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.upload;\n\nimport static com.gsma.rcs.ri.utils.FileUtils.takePersistableContentUriPermission;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsActivity;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.FileUtils;\nimport com.gsma.rcs.ri.utils.LogUtils;\nimport com.gsma.rcs.ri.utils.RcsSessionUtil;\nimport com.gsma.rcs.ri.utils.Utils;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.upload.FileUpload;\nimport com.gsma.services.rcs.upload.FileUploadInfo;\nimport com.gsma.services.rcs.upload.FileUploadListener;\n\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.KeyEvent;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\n/**\n * Initiate file upload\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class InitiateFileUpload extends RcsActivity {\n    /**\n     * Activity result constants\n     */\n    private final static int SELECT_IMAGE = 0;\n\n    private final Handler mHandler = new Handler();\n\n    private Uri mFile;\n\n    /**\n     * Selected filesize (kB)\n     */\n    private long mFilesize = -1;\n\n    private FileUpload mUpload;\n\n    private String mUploadId;\n\n    private MyFileUploadListener mUploadListener = new MyFileUploadListener();\n\n    private boolean mUploadThumbnail = false;\n\n    private Button mShowThumbnailBtn;\n\n    private Button mShowBtn;\n\n    private Button mUploadBtn;\n\n    private Button mSelectBtn;\n\n    private OnClickListener mBtnUploadListener;\n\n    private OnClickListener mBtnSelectListener;\n\n    private OnClickListener mBtnShowListener;\n\n    private OnClickListener mBtnShowThumbnailListener;\n\n    private static final String LOGTAG = LogUtils.getTag(InitiateFileUpload.class.getSimpleName());\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        initialize();\n\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.fileupload_initiate);\n\n        // Set buttons callback\n        mUploadBtn = (Button) findViewById(R.id.upload_btn);\n        mUploadBtn.setOnClickListener(mBtnUploadListener);\n        mUploadBtn.setEnabled(false);\n\n        mShowBtn = (Button) findViewById(R.id.show_btn);\n        mShowBtn.setOnClickListener(mBtnShowListener);\n        mShowBtn.setEnabled(false);\n\n        mShowThumbnailBtn = (Button) findViewById(R.id.show_icon_btn);\n        mShowThumbnailBtn.setOnClickListener(mBtnShowThumbnailListener);\n        mShowThumbnailBtn.setEnabled(false);\n\n        mSelectBtn = (Button) findViewById(R.id.select_btn);\n        mSelectBtn.setOnClickListener(mBtnSelectListener);\n\n        // Register to API connection manager\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            showMessageThenExit(R.string.label_service_not_available);\n            return;\n        }\n        startMonitorServices(RcsServiceName.FILE_UPLOAD);\n        try {\n            getFileUploadApi().addEventListener(mUploadListener);\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            return;\n        }\n        try {\n            getFileUploadApi().removeEventListener(mUploadListener);\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n    }\n\n    @Override\n    public void onActivityResult(int requestCode, int resultCode, Intent data) {\n        if (resultCode != RESULT_OK || data == null || data.getData() == null) {\n            return;\n        }\n        mFile = data.getData();\n        TextView uriEdit = (TextView) findViewById(R.id.uri);\n        switch (requestCode) {\n            case SELECT_IMAGE:\n                /* Display file info */\n                mFilesize = FileUtils.getFileSize(this, mFile);\n                uriEdit.setText(FileUtils.humanReadableByteCount(mFilesize, true));\n                /* Enable upload button */\n                mUploadBtn.setEnabled(true);\n                break;\n        }\n    }\n\n    /**\n     * File upload event listener\n     */\n    private class MyFileUploadListener extends FileUploadListener {\n        /**\n         * Callback called when the upload state changes\n         * \n         * @param uploadId ID of upload\n         * @param state State of upload\n         */\n        @Override\n        public void onStateChanged(String uploadId, final FileUpload.State state) {\n            // Discard event if not for current uploadId\n            if (mUploadId == null || !mUploadId.equals(uploadId)) {\n                return;\n            }\n            mHandler.post(new Runnable() {\n                public void run() {\n                    TextView statusView = (TextView) findViewById(R.id.progress_status);\n                    if (state == FileUpload.State.STARTED) {\n                        // Display session status\n                        statusView.setText(getString(R.string.label_upload_started));\n                    } else if (state == FileUpload.State.FAILED) {\n                        // Display sharing status\n                        showMessageThenExit(R.string.label_upload_failed);\n\n                    } else if (state == FileUpload.State.ABORTED) {\n                        // Display sharing status\n                        showMessageThenExit(R.string.label_upload_aborted);\n\n                    } else if (state == FileUpload.State.TRANSFERRED) {\n                        // Display sharing status\n                        statusView.setText(getString(R.string.label_upload_transferred));\n                        try {\n                            Uri file = mUpload.getFile();\n                            FileUpload.State state = mUpload.getState();\n                            String id = mUpload.getUploadId();\n                            FileUploadInfo fileInfo = mUpload.getUploadInfo();\n                            if (LogUtils.isActive) {\n                                Log.i(LOGTAG, \"FileUpload transferred (id=\" + id + \") uri=\" + file\n                                        + \") (state=\" + state + \") (info=\" + fileInfo + \")\");\n                            }\n                        } catch (RcsServiceException e) {\n                            showExceptionThenExit(e);\n                        }\n\n                    }\n                }\n            });\n\n        }\n\n        @Override\n        public void onProgressUpdate(String uploadId, final long currentSize, final long totalSize) {\n            mHandler.post(new Runnable() {\n                public void run() {\n                    updateProgressBar(currentSize, totalSize);\n                }\n            });\n        }\n\n        @Override\n        public void onUploaded(String uploadId, final FileUploadInfo info) {\n            mHandler.post(new Runnable() {\n                public void run() {\n                    mShowBtn.setEnabled(true);\n                    mShowThumbnailBtn.setEnabled(mUploadThumbnail);\n                }\n            });\n        }\n    }\n\n    private void updateProgressBar(long currentSize, long totalSize) {\n        TextView statusView = (TextView) findViewById(R.id.progress_status);\n        ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);\n        statusView.setText(Utils.getProgressLabel(currentSize, totalSize));\n        double position = ((double) currentSize / (double) totalSize) * 100.0;\n        progressBar.setProgress((int) position);\n    }\n\n    private void quitSession() {\n        try {\n            if (mUpload != null && RcsSessionUtil.isAllowedToAbortFileUploadSession(mUpload)) {\n                mUpload.abortUpload();\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n\n        } finally {\n            mUpload = null;\n            finish();\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        if (KeyEvent.KEYCODE_BACK == keyCode) {\n            quitSession();\n            return true;\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    private void initialize() {\n        mBtnUploadListener = new OnClickListener() {\n            public void onClick(View v) {\n                try {\n                    // Check max size\n                    long maxSize = 0;\n                    try {\n                        maxSize = getFileUploadApi().getConfiguration().getMaxSize();\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG,\n                                    \"FileUpload max size=\".concat(Long.valueOf(maxSize).toString()));\n                        }\n                    } catch (RcsServiceException e) {\n                        showException(e);\n                    }\n                    if ((maxSize > 0) && (mFilesize >= maxSize)) {\n                        // Display an error\n                        showMessage(getString(R.string.label_upload_max_size, maxSize));\n                        return;\n                    }\n\n                    // Get thumbnail option\n                    CheckBox ftThumb = (CheckBox) findViewById(R.id.file_thumb);\n                    mUploadThumbnail = ftThumb.isChecked();\n\n                    /* Only take persistable permission for content Uris */\n                    takePersistableContentUriPermission(InitiateFileUpload.this, mFile);\n\n                    // Initiate upload\n                    mUpload = getFileUploadApi().uploadFile(mFile, mUploadThumbnail);\n                    mUploadId = mUpload.getUploadId();\n\n                    // Hide buttons\n                    mUploadBtn.setVisibility(View.GONE);\n                    mSelectBtn.setVisibility(View.GONE);\n\n                } catch (RcsServiceException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n\n        mBtnSelectListener = new OnClickListener() {\n            public void onClick(View v) {\n                FileUtils.openFile(InitiateFileUpload.this, \"image/*\", SELECT_IMAGE);\n            }\n        };\n\n        mBtnShowListener = new OnClickListener() {\n            public void onClick(View v) {\n                /* Show uploaded file */\n                try {\n                    Intent intent = new Intent(Intent.ACTION_VIEW);\n                    intent.setData(mUpload.getUploadInfo().getFile());\n                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    startActivity(intent);\n                } catch (RcsGenericException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n\n        mBtnShowThumbnailListener = new OnClickListener() {\n            public void onClick(View v) {\n                /* Show uploaded thumbnail */\n                try {\n                    Intent intent = new Intent(Intent.ACTION_VIEW);\n                    intent.setData(mUpload.getUploadInfo().getFileIcon());\n                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    startActivity(intent);\n\n                } catch (RcsGenericException e) {\n                    showExceptionThenExit(e);\n                }\n            }\n        };\n\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/AndroidDatagramConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\n\n/**\n * Android datagram server connection\n * \n * @author Jean-Marc AUFFRET\n */\npublic class AndroidDatagramConnection implements DatagramConnection {\n    /**\n     * Datagram connection\n     */\n    private DatagramSocket connection = null;\n\n    /**\n     * Datagram Packet\n     */\n    private DatagramPacket packet = null;\n\n    /**\n     * Connection timeout\n     */\n    private int timeout = 0;\n\n    /**\n     * Constructor\n     */\n    public AndroidDatagramConnection() {\n        packet = new DatagramPacket(new byte[DatagramConnection.DEFAULT_DATAGRAM_SIZE],\n                DatagramConnection.DEFAULT_DATAGRAM_SIZE);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param timeout SO Timeout\n     */\n    public AndroidDatagramConnection(int timeout) {\n        this();\n        this.timeout = timeout;\n    }\n\n    /**\n     * Open the datagram connection\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException {\n        connection = new DatagramSocket();\n        connection.setSoTimeout(timeout);\n    }\n\n    /**\n     * Open the datagram connection\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException {\n        connection = new DatagramSocket(port);\n        connection.setSoTimeout(timeout);\n    }\n\n    /**\n     * Close the datagram connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (connection != null) {\n            connection.close();\n            connection = null;\n        }\n    }\n\n    /**\n     * Receive data with a specific buffer size\n     * \n     * @return Byte array\n     * @throws IOException\n     */\n    public byte[] receive() throws IOException {\n        if (connection != null) {\n            packet.setLength(DatagramConnection.DEFAULT_DATAGRAM_SIZE);\n            connection.receive(packet);\n\n            int packetLength = packet.getLength();\n            byte[] data = new byte[packetLength];\n            System.arraycopy(packet.getData(), 0, data, 0, packetLength);\n            return data;\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n\n    /**\n     * Send data\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @param data Data as byte array\n     * @throws IOException\n     */\n    public void send(String remoteAddr, int remotePort, byte[] data) throws IOException {\n        if (data == null) {\n            return;\n        }\n\n        if (connection != null) {\n            InetAddress address = InetAddress.getByName(remoteAddr);\n            DatagramPacket packet = new DatagramPacket(data, data.length, address, remotePort);\n            connection.send(packet);\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n\n    /**\n     * Returns the local address\n     * \n     * @return Address\n     * @throws IOException\n     */\n    public String getLocalAddress() throws IOException {\n        if ((connection != null) && (connection.getLocalAddress() != null)) {\n            return connection.getLocalAddress().getHostAddress();\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n\n    /**\n     * Returns the local port\n     * \n     * @return Port\n     * @throws IOException\n     */\n    public int getLocalPort() throws IOException {\n        if (connection != null) {\n            return connection.getLocalPort();\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/BitmapCache.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport android.support.v4.util.LruCache;\n\n/**\n * Created by yplo6403 on 07/12/2015.\n */\npublic class BitmapCache {\n\n    private static volatile BitmapCache sInstance;\n    private LruCache<String, BitmapLoader.BitmapCacheInfo> mMemoryCache;\n\n    private BitmapCache() {\n        /*\n         * Get max available VM memory, exceeding this amount will throw an OutOfMemory exception.\n         * Stored in kilobytes as LruCache takes an int in its constructor.\n         */\n        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);\n\n        /* Use 1/8th of the available memory for this memory cache. */\n        final int cacheSize = maxMemory / 8;\n\n        mMemoryCache = new LruCache<String, BitmapLoader.BitmapCacheInfo>(cacheSize) {\n\n            /**\n             * Measure item size in kilobytes rather than units which is more practical for a bitmap\n             * cache\n             */\n            @Override\n            protected int sizeOf(String key, BitmapLoader.BitmapCacheInfo bitmapCacheInfo) {\n                /*\n                 * The cache size will be measured in kilobytes rather than number of items.\n                 */\n                return bitmapCacheInfo.getBitmap().getByteCount() / 1024;\n            }\n        };\n    }\n\n    public static BitmapCache getInstance() {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (BitmapCache.class) {\n            if (sInstance == null) {\n                sInstance = new BitmapCache();\n            }\n            return sInstance;\n        }\n    }\n\n    public LruCache<String, BitmapLoader.BitmapCacheInfo> getMemoryCache() {\n        return mMemoryCache;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/BitmapLoader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.os.AsyncTask;\nimport android.support.v4.util.LruCache;\nimport android.util.Log;\n\n/**\n * @author yplo6403\n *         <p/>\n *         A class to create bitmap and to store it cache asynchronously.\n */\npublic abstract class BitmapLoader extends AsyncTask<String, Void, BitmapLoader.BitmapCacheInfo> {\n\n    private static final String LOGTAG = LogUtils.getTag(BitmapLoader.class.getSimpleName());\n\n    protected LruCache<String, BitmapCacheInfo> mMemoryCache;\n    protected SetViewCallback mCallback;\n    protected Context mCtx;\n    protected int mPixelMaxSizeWidth;\n    protected int mPixelMaxSizeHeight;\n\n    public BitmapLoader(Context ctx, LruCache<String, BitmapCacheInfo> memoryCache,\n            int pixelMaxSizeWidth, int pixelMaxSizeHeight, SetViewCallback callback) {\n        super();\n        mCtx = ctx;\n        mMemoryCache = memoryCache;\n        mCallback = callback;\n        mPixelMaxSizeWidth = pixelMaxSizeWidth;\n        mPixelMaxSizeHeight = pixelMaxSizeHeight;\n    }\n\n    @Override\n    protected void onPostExecute(BitmapCacheInfo result) {\n        if (result != null) {\n            if (LogUtils.isActive) {\n                Log.d(LOGTAG, \"onPostExecute build bitmap for:\" + result.getFilename());\n            }\n            if (mCallback != null) {\n                if (result.getBitmap() != null)\n                    mCallback.loadView(result);\n            }\n        }\n    }\n\n    public interface SetViewCallback {\n        void loadView(final BitmapCacheInfo cacheInfo);\n    }\n\n    /**\n     * @author yplo6403\n     *         <p/>\n     *         This inner class creates a bitmap for the bitmap and store it with its associated\n     *         filename\n     */\n    public class BitmapCacheInfo {\n        private final String mFilename;\n        private final Bitmap mBitmap;\n\n        public BitmapCacheInfo(String filename, Bitmap bitmap) {\n            mFilename = filename;\n            mBitmap = bitmap;\n        }\n\n        public Bitmap getBitmap() {\n            return mBitmap;\n        }\n\n        public String getFilename() {\n            return mFilename;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/ContactListAdapter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.database.SQLException;\nimport android.provider.ContactsContract.CommonDataKinds.Phone;\nimport android.provider.ContactsContract.Contacts;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CursorAdapter;\nimport android.widget.TextView;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Contact list adapter\n */\npublic class ContactListAdapter extends CursorAdapter {\n\n    private static final String[] PROJECTION_PHONE = new String[] {\n            Phone._ID, Phone.NUMBER, Phone.LABEL, Phone.TYPE, Phone.CONTACT_ID\n    };\n\n    private static final String[] PROJECTION_CONTACT = new String[] {\n        Contacts.DISPLAY_NAME\n    };\n\n    private static final String WHERE_CLAUSE_PHONE = Phone.NUMBER + \"!='null'\";\n\n    private static final String WHERE_CLAUSE_CONTACT = Contacts._ID + \"=?\";\n\n    private static final String LOGTAG = LogUtils.getTag(ContactListAdapter.class.getSimpleName());\n\n    /**\n     * Create a contact selector based on the native address book\n     * \n     * @param context the context\n     * @return List adapter\n     */\n    public static ContactListAdapter createContactListAdapter(Context context) {\n        return createContactListAdapter(context, null);\n    }\n\n    /**\n     * Create a contact selector based on the native address book. This selector adds a default\n     * value to allow no contact selection\n     * \n     * @param context the context\n     * @param defaultValue default value for no contact selection\n     * @return List adapter\n     */\n    public static ContactListAdapter createContactListAdapter(Context context, String defaultValue) {\n        ContentResolver content = context.getContentResolver();\n        Cursor cursor = null;\n        try {\n            cursor = content.query(Phone.CONTENT_URI, PROJECTION_PHONE, WHERE_CLAUSE_PHONE, null,\n                    null);\n            if (cursor == null) {\n                throw new SQLException(\"Query failed!\");\n            }\n            Set<ContactId> treatedNumbers = new HashSet<>();\n            MatrixCursor matrix = new MatrixCursor(PROJECTION_PHONE);\n            if (defaultValue != null) {\n                matrix.addRow(new Object[] {\n                        -1, defaultValue, \"\", -1, -1\n                });\n            }\n            int columnIdxId = cursor.getColumnIndexOrThrow(Phone._ID);\n            int columIdxLabel = cursor.getColumnIndexOrThrow(Phone.LABEL);\n            int columnIdxType = cursor.getColumnIndexOrThrow(Phone.TYPE);\n            int columnIdxContactId = cursor.getColumnIndexOrThrow(Phone.CONTACT_ID);\n            int columnIdxNumber = cursor.getColumnIndexOrThrow(Phone.NUMBER);\n            while (cursor.moveToNext()) {\n                String phoneNumber = cursor.getString(columnIdxNumber);\n                if (!ContactUtil.isValidContact(phoneNumber)) {\n                    /* Not a valid phone number: skip it */\n                    continue;\n                }\n                ContactId contact = ContactUtil.formatContact(phoneNumber);\n                /* Filter number already treated */\n                if (!treatedNumbers.contains(contact)) {\n                    matrix.addRow(new Object[] {\n                            cursor.getLong(columnIdxId), contact.toString(),\n                            cursor.getString(columIdxLabel), cursor.getInt(columnIdxType),\n                            cursor.getLong(columnIdxContactId)\n                    });\n                    treatedNumbers.add(contact);\n                }\n            }\n            return new ContactListAdapter(context, matrix);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    /**\n     * Create a contact selector with RCS capable contacts\n     * \n     * @param context the context\n     * @return List adapter or null if failure\n     */\n    public static ContactListAdapter createRcsContactListAdapter(Context context) {\n        ContentResolver content = context.getContentResolver();\n        Cursor cursor = null;\n        ConnectionManager apiConnectionManager = ConnectionManager.getInstance();\n        MatrixCursor matrix = new MatrixCursor(PROJECTION_PHONE);\n        ContactService contactsApi = apiConnectionManager.getContactApi();\n        try {\n            // Get the set of RCS contacts\n            Set<RcsContact> rcsContacts = contactsApi.getRcsContacts();\n            // Is there any RCS contacts ?\n            if (rcsContacts != null && !rcsContacts.isEmpty()) {\n                Set<ContactId> rcsContactIds = new HashSet<>();\n                for (RcsContact rcsContact : rcsContacts) {\n                    rcsContactIds.add(rcsContact.getContactId());\n                }\n                // Query all phone numbers\n                cursor = content.query(Phone.CONTENT_URI, PROJECTION_PHONE, WHERE_CLAUSE_PHONE,\n                        null, null);\n                if (cursor == null) {\n                    throw new SQLException(\"Query failed!\");\n                }\n                Set<ContactId> treatedContactIDs = new HashSet<>();\n                int columnIdxId = cursor.getColumnIndexOrThrow(Phone._ID);\n                int columIdxLabel = cursor.getColumnIndexOrThrow(Phone.LABEL);\n                int columnIdxType = cursor.getColumnIndexOrThrow(Phone.TYPE);\n                int columnIdxContactId = cursor.getColumnIndexOrThrow(Phone.CONTACT_ID);\n                int columnIdxNumber = cursor.getColumnIndexOrThrow(Phone.NUMBER);\n                while (cursor.moveToNext()) {\n                    // Keep a trace of already treated row\n                    String phoneNumber = cursor.getString(columnIdxNumber);\n                    if (!ContactUtil.isValidContact(phoneNumber)) {\n                        /* Not a valid phone number: skip it */\n                        continue;\n                    }\n                    ContactId contact = ContactUtil.formatContact(phoneNumber);\n                    // If this number is RCS and not already in the list,\n                    // take it\n                    if (rcsContactIds.contains(contact) && !treatedContactIDs.contains(contact)) {\n                        matrix.addRow(new Object[] {\n                                cursor.getLong(columnIdxId), contact.toString(),\n                                cursor.getString(columIdxLabel), cursor.getInt(columnIdxType),\n                                cursor.getLong(columnIdxContactId)\n                        });\n                        treatedContactIDs.add(contact);\n                    }\n                }\n            }\n            return new ContactListAdapter(context, matrix);\n\n        } catch (RcsServiceNotAvailableException e) {\n            return null;\n\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n            return null;\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param context Context\n     * @param c Cursor\n     */\n    private ContactListAdapter(Context context, Cursor c) {\n        super(context, c);\n    }\n\n    @Override\n    public View newView(Context context, Cursor cursor, ViewGroup parent) {\n        LayoutInflater inflater = LayoutInflater.from(context);\n        TextView view = (TextView) inflater.inflate(R.layout.utils_spinner_item, parent, false);\n        view.setTag(new ViewHolder(cursor));\n        return view;\n    }\n\n    @Override\n    public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {\n        LayoutInflater inflater = LayoutInflater.from(context);\n        TextView view = (TextView) inflater.inflate(android.R.layout.simple_dropdown_item_1line,\n                parent, false);\n        view.setTag(new ViewHolder(cursor));\n        return view;\n    }\n\n    @Override\n    public void bindView(View view, Context context, Cursor cursor) {\n        final ViewHolder holder = (ViewHolder) view.getTag();\n        ((TextView) view).setText(formatText(context, cursor, holder));\n        // Put the number in tag so it can be retrieved easily\n        holder.number = cursor.getString(holder.columnNumber);\n    }\n\n    /**\n     * Format the item to be displayed. The user name + label is displayed if not null, else the\n     * phone number is used\n     * \n     * @param context Context\n     * @param c Cursor\n     * @param holder the holder of column indexes\n     * @return the formated text\n     */\n    private String formatText(Context context, Cursor c, ViewHolder holder) {\n        // Get phone label\n        String label = c.getString(holder.columnLabel);\n        if (label == null) {\n            // Label is not custom, get the string corresponding to the phone\n            // type\n            int type = c.getInt(holder.columnType);\n            label = context.getString(Phone.getTypeLabelResource(type));\n        }\n\n        String name = null;\n        String[] selectionArgs = new String[] {\n            Long.toString(c.getLong(holder.columnContactId))\n        };\n        // Get contact name from contact id\n        Cursor personCursor = context.getContentResolver().query(Contacts.CONTENT_URI,\n                PROJECTION_CONTACT, WHERE_CLAUSE_CONTACT, selectionArgs, null);\n        if (personCursor == null) {\n            throw new SQLException(\"Query failed!\");\n        }\n        if (personCursor.moveToFirst()) {\n            name = personCursor.getString(holder.columnID);\n        }\n        personCursor.close();\n        if (name == null) {\n            // Return \"phone number\"\n            return c.getString(holder.columnNumber);\n        } else {\n            // Return \"name (phone label)\"\n            return name + \" (\" + label + \")\";\n        }\n    }\n\n    /**\n     * A ViewHolder class keeps references to children views to avoid unnecessary calls to\n     * getColumnIndex() on each row.\n     */\n    private class ViewHolder {\n        int columnID;\n\n        int columnNumber;\n\n        int columnLabel;\n\n        int columnType;\n\n        int columnContactId;\n\n        // Store number to get it upon selection\n        String number;\n\n        ViewHolder(Cursor cursor) {\n            columnID = cursor.getColumnIndexOrThrow(Phone._ID);\n            columnNumber = cursor.getColumnIndexOrThrow(Phone.NUMBER);\n            columnLabel = cursor.getColumnIndexOrThrow(Phone.LABEL);\n            columnType = cursor.getColumnIndexOrThrow(Phone.TYPE);\n            columnContactId = cursor.getColumnIndexOrThrow(Phone.CONTACT_ID);\n            number = cursor.getString(columnNumber);\n        }\n    }\n\n    /**\n     * Get the selected phone number\n     * \n     * @param view the view\n     * @return the phone number\n     */\n    public String getSelectedNumber(View view) {\n        final ViewHolder holder = (ViewHolder) view.getTag();\n        return holder.number;\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/ContactUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.rcs.ri.RiApplication;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.Log;\n\n/**\n * @author yplo6403\n */\npublic class ContactUtil {\n\n    private static final String LOGTAG = LogUtils.getTag(ContactUtil.class.getSimpleName());\n    private static volatile com.gsma.services.rcs.contact.ContactUtil mContactUtil;\n\n    /**\n     * Formats the given contact to uniquely represent a RCS contact phone number.\n     * \n     * @param contact the contact phone number\n     * @return the ContactId\n     */\n    public static ContactId formatContact(String contact) {\n        synchronized (ContactUtil.class) {\n            if (mContactUtil == null) {\n                mContactUtil = com.gsma.services.rcs.contact.ContactUtil.getInstance(RiApplication\n                        .getAppContext());\n            }\n        }\n        try {\n            return mContactUtil.formatContact(contact);\n        } catch (RcsPermissionDeniedException e) {\n            /*\n             * This exception should not occur since RI application cannot be started if country\n             * code cannot be resolved.\n             */\n            String errorMessage = \"Failed to convert phone number '\" + contact\n                    + \"' into contactId!\";\n            throw new IllegalStateException(errorMessage, e);\n        }\n    }\n\n    /**\n     * Verifies the validity of a contact number.\n     * \n     * @param number the contact number\n     * @return True if the given contact has the syntax of valid RCS ContactId.\n     */\n    public static boolean isValidContact(String number) {\n        synchronized (ContactUtil.class) {\n            if (mContactUtil == null) {\n                mContactUtil = com.gsma.services.rcs.contact.ContactUtil.getInstance(RiApplication\n                        .getAppContext());\n            }\n        }\n        try {\n            return mContactUtil.isValidContact(number);\n        } catch (RcsPermissionDeniedException e) {\n            /*\n             * This exception should not occur since RI application cannot be started if country\n             * code cannot be resolved.\n             */\n            String errorMessage = \"Failed to validate phone number '\" + number + \"'!\";\n            Log.e(LOGTAG, errorMessage);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/DatagramConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport java.io.IOException;\n\n/**\n * Datagram connection\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface DatagramConnection {\n    /**\n     * Default datagram packet size\n     */\n    int DEFAULT_DATAGRAM_SIZE = 4096 * 8;\n\n    /**\n     * Open the datagram connection\n     * \n     * @throws IOException\n     */\n    void open() throws IOException;\n\n    /**\n     * Open the datagram connection\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    void open(int port) throws IOException;\n\n    /**\n     * Close the datagram connection\n     * \n     * @throws IOException\n     */\n    void close() throws IOException;\n\n    /**\n     * Send data\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @param data Data as byte array\n     * @throws IOException\n     */\n    void send(String remoteAddr, int remotePort, byte[] data) throws IOException;\n\n    /**\n     * Receive data\n     * \n     * @return Byte array\n     * @throws IOException\n     */\n    byte[] receive() throws IOException;\n\n    /**\n     * Returns the local address\n     * \n     * @return Address\n     * @throws IOException\n     */\n    String getLocalAddress() throws IOException;\n\n    /**\n     * Returns the local port\n     * \n     * @return Port\n     * @throws IOException\n     */\n    int getLocalPort() throws IOException;\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/FileUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport android.app.Activity;\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.media.MediaMetadataRetriever;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.provider.BaseColumns;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.provider.OpenableColumns;\nimport android.webkit.MimeTypeMap;\n\nimport java.io.File;\nimport java.util.Locale;\n\npublic class FileUtils {\n\n    private static final String[] PROJECTION_DATA = {\n        MediaStore.MediaColumns.DATA\n    };\n\n    private static final String SELECTION_ID = BaseColumns._ID + \"=?\";\n\n    public static String getPath(final Context context, final Uri uri) {\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            // DocumentProvider\n            if (DocumentsContract.isDocumentUri(context, uri)) {\n                // ExternalStorageProvider\n                if (isExternalStorageDocument(uri)) {\n                    String docId = DocumentsContract.getDocumentId(uri);\n                    String[] split = docId.split(\":\");\n                    String type = split[0];\n                    if (\"primary\".equalsIgnoreCase(type)) {\n                        return Environment.getExternalStorageDirectory() + \"/\" + split[1];\n                    }\n\n                } else if (isDownloadsDocument(uri)) { // DownloadsProvider\n                    String id = DocumentsContract.getDocumentId(uri);\n                    Uri contentUri = ContentUris.withAppendedId(\n                            Uri.parse(\"content://downloads/public_downloads\"), Long.valueOf(id));\n                    return getDataColumn(context, contentUri, null, null);\n\n                } else if (isMediaDocument(uri)) { // MediaProvider\n                    String docId = DocumentsContract.getDocumentId(uri);\n                    String[] split = docId.split(\":\");\n                    String type = split[0];\n                    Uri contentUri = null;\n                    switch (type) {\n                        case \"image\":\n                            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;\n                            break;\n                        case \"video\":\n                            contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;\n                            break;\n                        case \"audio\":\n                            contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;\n                            break;\n                    }\n\n                    String[] selectionArgs = new String[] {\n                        split[1]\n                    };\n                    return getDataColumn(context, contentUri, SELECTION_ID, selectionArgs);\n                }\n            }\n        }\n        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {\n            /* MediaStore (and general) */\n            // Return the remote address\n            if (isGooglePhotosUri(uri)) {\n                return uri.getLastPathSegment();\n            }\n            return getDataColumn(context, uri, null, null);\n\n        } else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(uri.getScheme())) {\n            /* File */\n            return uri.getPath();\n        }\n        return null;\n    }\n\n    /**\n     * Get the value of the data column for this Uri. This is useful for MediaStore Uris, and other\n     * file-based ContentProviders.\n     *\n     * @param context The context.\n     * @param uri The Uri to query.\n     * @param selection (Optional) Filter used in the query.\n     * @param selectionArgs (Optional) Selection arguments used in the query.\n     * @return The value of the _data column, which is typically a file path.\n     */\n    private static String getDataColumn(Context context, Uri uri, String selection,\n            String[] selectionArgs) {\n        Cursor cursor = null;\n        try {\n            cursor = context.getContentResolver().query(uri, PROJECTION_DATA, selection,\n                    selectionArgs, null);\n            if (cursor == null) {\n                throw new SQLException(\"Failed to query URI=\" + uri);\n            }\n            if (cursor.moveToFirst()) {\n                return cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA));\n            }\n            return null;\n        } finally {\n            if (cursor != null)\n                cursor.close();\n        }\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is ExternalStorageProvider.\n     */\n    private static boolean isExternalStorageDocument(Uri uri) {\n        return \"com.android.externalstorage.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is DownloadsProvider.\n     */\n    private static boolean isDownloadsDocument(Uri uri) {\n        return \"com.android.providers.downloads.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is MediaProvider.\n     */\n    private static boolean isMediaDocument(Uri uri) {\n        return \"com.android.providers.media.documents\".equals(uri.getAuthority());\n    }\n\n    /**\n     * @param uri The Uri to check.\n     * @return Whether the Uri authority is <span class=\"IL_AD\" id=\"IL_AD3\">Google</span> Photos.\n     */\n    private static boolean isGooglePhotosUri(Uri uri) {\n        return \"com.google.android.apps.photos.content\".equals(uri.getAuthority());\n    }\n\n    /**\n     * Fetch the file name from URI\n     *\n     * @param context Context\n     * @param file URI\n     * @return fileName String\n     */\n    public static String getFileName(Context context, Uri file) {\n        String scheme = file.getScheme();\n        switch (scheme) {\n            case ContentResolver.SCHEME_FILE:\n                return file.getLastPathSegment();\n\n            case ContentResolver.SCHEME_CONTENT:\n                Cursor cursor = null;\n                try {\n                    cursor = context.getContentResolver().query(file, null, null, null, null);\n                    if (cursor == null) {\n                        throw new SQLException(\"Failed to query file \" + file);\n                    }\n                    if (cursor.moveToFirst()) {\n                        return cursor.getString(cursor\n                                .getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));\n                    } else {\n                        throw new IllegalArgumentException(\n                                \"Error in retrieving file name from the URI\");\n                    }\n                } finally {\n                    if (cursor != null) {\n                        cursor.close();\n                    }\n                }\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI scheme\");\n        }\n    }\n\n    /**\n     * Fetch the file size from URI\n     *\n     * @param ctx Context\n     * @param file URI\n     * @return fileSize long\n     * @throws IllegalArgumentException\n     */\n    public static long getFileSize(Context ctx, Uri file) throws IllegalArgumentException {\n        String scheme = file.getScheme();\n        switch (scheme) {\n            case ContentResolver.SCHEME_FILE:\n                File f = new File(file.getPath());\n                return f.length();\n\n            case ContentResolver.SCHEME_CONTENT:\n                Cursor cursor = null;\n                try {\n                    cursor = ctx.getContentResolver().query(file, null, null, null, null);\n                    if (cursor == null) {\n                        throw new SQLException(\"Failed to query file \" + file);\n                    }\n                    if (cursor.moveToFirst()) {\n                        return Long.valueOf(cursor.getString(cursor\n                                .getColumnIndexOrThrow(OpenableColumns.SIZE)));\n                    } else {\n                        throw new IllegalArgumentException(\n                                \"Error in retrieving file size form the URI\");\n                    }\n                } finally {\n                    if (cursor != null) {\n                        cursor.close();\n                    }\n                }\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI scheme\");\n        }\n    }\n\n    private static String getMimeTypeFromFile(Context ctx, Uri file) {\n        MediaMetadataRetriever mmr = null;\n        try {\n            mmr = new MediaMetadataRetriever();\n            mmr.setDataSource(ctx, file);\n            return mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE);\n\n        } finally {\n            if (mmr != null) {\n                mmr.release();\n            }\n        }\n    }\n\n    /**\n     * Gets the mime-type from file Uri\n     *\n     * @param ctx the context\n     * @param file the file Uri\n     * @return the mime-type\n     */\n    public static String getMimeType(Context ctx, Uri file) {\n        String scheme = file.getScheme();\n        if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {\n            return ctx.getContentResolver().getType(file);\n        }\n        if (ContentResolver.SCHEME_FILE.equals(scheme)) {\n            String path = file.getPath();\n            if (path == null) {\n                throw new RuntimeException(\"Invalid file path for Uri='\" + file + \"'!\");\n            }\n            String extension = MimeTypeMap.getFileExtensionFromUrl(path);\n            if (extension != null) {\n                String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(\n                        extension.toLowerCase(Locale.getDefault()));\n                if (result == null) {\n                    throw new IllegalArgumentException(\"Invalid mime type for extension='\"\n                            + extension + \"'!\");\n                }\n                if (Utils.isVideoType(result)) {\n                    /*\n                     * Warning: Audio and Video files share the same extensions so we need to\n                     * retrieve mime type directly from file.\n                     */\n                    String mimeTypeFromMediaFile = getMimeTypeFromFile(ctx, file);\n                    if (mimeTypeFromMediaFile != null) {\n                        return mimeTypeFromMediaFile;\n                    }\n                }\n                return result;\n            }\n            throw new IllegalArgumentException(\"Invalid extension for URI='\" + file + \"'!\");\n        }\n        throw new IllegalArgumentException(\"Unsupported URI scheme '\" + scheme + \"'!\");\n    }\n\n    private static Intent forgeIntentToOpenFile() {\n        Intent intent;\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {\n            intent = new Intent(Intent.ACTION_GET_CONTENT, null);\n        } else {\n            intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);\n        }\n        intent.addCategory(Intent.CATEGORY_OPENABLE);\n        return intent;\n    }\n\n    /**\n     * Open file\n     *\n     * @param activity the activity\n     * @param mimeType the mime type\n     * @param action the action\n     */\n    public static void openFile(Activity activity, String mimeType, int action) {\n        Intent intent = forgeIntentToOpenFile();\n        intent.setType(mimeType);\n        activity.startActivityForResult(intent, action);\n    }\n\n    public static void openFiles(Activity activity, String[] mimeTypes, int action) {\n        Intent intent = forgeIntentToOpenFile();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            intent.setType(\"*/*\");\n            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);\n            intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);\n        } else {\n            intent.setType(mimeTypes[0]);\n        }\n        activity.startActivityForResult(intent, action);\n    }\n\n    /**\n     * Saves the read/write permission for later use by the stack.\n     *\n     * @param file Uri of file to transfer\n     */\n    public static void takePersistableContentUriPermission(Context context, Uri file) {\n        if (!(ContentResolver.SCHEME_CONTENT.equals(file.getScheme()))) {\n            return;\n        }\n        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {\n            ContentResolver contentResolver = context.getContentResolver();\n            contentResolver.takePersistableUriPermission(file,\n                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n        }\n    }\n\n    /**\n     * Converts byte size into human readable format\n     *\n     * @param bytes number of bytes to display\n     * @param si True is binary units or SI units else.\n     * @return String\n     */\n    public static String humanReadableByteCount(long bytes, boolean si) {\n        int unit = si ? 1000 : 1024;\n        if (bytes < unit)\n            return bytes + \" B\";\n        int exp = (int) (Math.log(bytes) / Math.log(unit));\n        String pre = (si ? \"kMGTPE\" : \"KMGTPE\").charAt(exp - 1) + (si ? \"\" : \"i\");\n        return String.format(Locale.getDefault(), \"%.1f %sB\", bytes / Math.pow(unit, exp), pre);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/ImageBitmapLoader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.rcs.ri.R;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.support.v4.util.LruCache;\nimport android.util.Log;\n\n/**\n * @author yplo6403\n *         <p/>\n *         A class to create Image bitmap and to store it in cache asynchronously.\n */\npublic class ImageBitmapLoader extends BitmapLoader {\n    private static final String LOGTAG = LogUtils.getTag(ImageBitmapLoader.class.getSimpleName());\n\n    private static Bitmap defaultImageBitmap;\n\n    /**\n     * @param memoryCache the map to save the image bitmap descriptor\n     * @param callback the callback to be executed once the bitmap is built\n     */\n    public ImageBitmapLoader(Context ctx, LruCache<String, BitmapCacheInfo> memoryCache,\n            int pixelMaxSizeWidth, int pixelMaxSizeHeight, SetViewCallback callback) {\n        super(ctx, memoryCache, pixelMaxSizeWidth, pixelMaxSizeHeight, callback);\n    }\n\n    @Override\n    protected BitmapCacheInfo doInBackground(String... params) {\n        String imagePath = params[0];\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"doInBackground build bitmap for image:\" + imagePath);\n        }\n        try {\n            BitmapCacheInfo defaultResult;\n            if (defaultImageBitmap == null) {\n                defaultImageBitmap = BitmapFactory.decodeResource(mCtx.getResources(),\n                        R.drawable.video_file);\n            }\n            if (defaultImageBitmap != null) {\n                defaultResult = new BitmapCacheInfo(imagePath, defaultImageBitmap);\n                mMemoryCache.put(imagePath, defaultResult);\n            }\n            Bitmap imageBitmap = ImageUtils.getImageBitmap2Display(imagePath, mPixelMaxSizeWidth,\n                    mPixelMaxSizeHeight);\n            if (imageBitmap != null) {\n                BitmapCacheInfo bitmapCacheInfo = new BitmapCacheInfo(imagePath, imageBitmap);\n                // Store the bitmap and path for an eventual later use\n                if (imageBitmap.getHeight() != 1 && imageBitmap.getWidth() != 1) {\n                    mMemoryCache.put(imagePath, bitmapCacheInfo);\n                    return bitmapCacheInfo;\n                }\n            }\n            return null;\n\n        } catch (OutOfMemoryError oome) {\n            if (LogUtils.isActive) {\n                Log.e(LOGTAG, \"OOME while getting bitmap for image: \" + imagePath);\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/ImageUtils.java",
    "content": "/*\n * ******************************************************************************\n *  * Software Name : RCS IMS Stack\n *  *\n *  * Copyright (C) 2010-2016 Orange.\n *  *\n *  * Licensed under the Apache License, Version 2.0 (the \"License\");\n *  * you may not use this file except in compliance with the License.\n *  * You may obtain a copy of the License at\n *  *\n *  *      http://www.apache.org/licenses/LICENSE-2.0\n *  *\n *  * Unless required by applicable law or agreed to in writing, software\n *  * distributed under the License is distributed on an \"AS IS\" BASIS,\n *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  * See the License for the specific language governing permissions and\n *  * limitations under the License.\n *  *****************************************************************************\n */\n\npackage com.gsma.rcs.ri.utils;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Matrix;\nimport android.media.ExifInterface;\nimport android.util.Log;\n\nimport java.io.IOException;\n\npublic class ImageUtils {\n\n    private static final String LOGTAG = LogUtils.getTag(ImageUtils.class.getName());\n\n    /**\n     * Get the image bitmap from Image filename. If required, the image resolution is reduced and\n     * rotation is performed.\n     *\n     * @param imageFilename the image filename\n     * @return the bitmap\n     */\n    public static Bitmap getImageBitmap2Display(String imageFilename) {\n        BitmapFactory.Options options = readImageOptions(imageFilename);\n        if (options.outHeight > options.outWidth) {\n            return getImageBitmap2Display(imageFilename, 256, 128);// if landscape\n        }\n        return getImageBitmap2Display(imageFilename, 128, 256);// if portrait\n    }\n\n    private static BitmapFactory.Options readImageOptions(String imageFilename) {\n        /*\n         * Read the dimensions and type of the image data prior to construction (and memory\n         * allocation) of the bitmap\n         */\n        BitmapFactory.Options options = new BitmapFactory.Options();\n        options.inJustDecodeBounds = true;\n        /* Decode image just to display dimension */\n        BitmapFactory.decodeFile(imageFilename, options);\n        return options;\n    }\n\n    public static Bitmap getImageBitmap2Display(String imageFilename, int reqWidth, int reqHeight) {\n        BitmapFactory.Options options = readImageOptions(imageFilename);\n        /* Calculate the reduction factor */\n        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);\n        options.inJustDecodeBounds = false;\n        int loopCount = 1;\n        for (; loopCount++ <= 4;) {\n            try {\n                if (LogUtils.isActive) {\n                    Log.i(LOGTAG, \"bitmap: \" + imageFilename + \" Sample factor: \"\n                            + options.inSampleSize);\n                }\n                /* Rotate image is orientation is not 0 degree */\n                Bitmap bitmapTmp = BitmapFactory.decodeFile(imageFilename, options);\n                if (bitmapTmp == null) {\n                    return null;\n                }\n                int degree = getExifOrientation(imageFilename);\n                if (degree == 0) {\n                    return bitmapTmp;\n                }\n                return rotateBitmap(bitmapTmp, degree);\n\n            } catch (OutOfMemoryError e) {\n                /*\n                 * If an OutOfMemoryError occurred, we continue with for loop and next inSampleSize\n                 * value\n                 */\n                if (LogUtils.isActive) {\n                    Log.w(LOGTAG, \"OutOfMemoryError: options.inSampleSize= \" + options.inSampleSize);\n                }\n                options.inSampleSize++;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Calculate the sub-sampling factor to load image on screen Image will be sized to be the\n     * smallest possible, keeping it bigger than requested size. No resize factor will be applied if\n     * one or both dimensions are smallest than requested. If width and height are both bigger than\n     * requested, ensure final image will have both dimensions larger than or equal to the requested\n     * height and width\n     * <p/>\n     * A requested dimension set to 1 pixel will let its size to adapt with no constraints.\n     *\n     * @param options contains the raw height and width of image\n     * @param reqWidth the target width\n     * @param reqHeight the target height\n     * @return the sub-sampling factor\n     */\n    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,\n            int reqHeight) {\n        /* Raw height and width of image */\n        final int height = options.outHeight;\n        final int width = options.outWidth;\n        int inSampleSize = 1;\n\n        if (height > reqHeight || width > reqWidth) {\n\n            final int halfHeight = height / 2;\n            final int halfWidth = width / 2;\n\n            /*\n             * Calculate the largest inSampleSize value that is a power of 2 and keeps both height\n             * and width larger than the requested height and width.\n             */\n            while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {\n                inSampleSize *= 2;\n            }\n        }\n        return inSampleSize;\n    }\n\n    /**\n     * Read the EXIF data from a given file to know the corresponding rotation, if any\n     *\n     * @param filename The filename\n     * @return rotation in degree\n     */\n    private static int getExifOrientation(String filename) {\n        // Also check if the image has to be rotated by reading metadata\n        try {\n            ExifInterface exif = new ExifInterface(filename);\n            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);\n            if (orientation != -1) {\n                // We only recognize a subset of orientation tag values.\n                switch (orientation) {\n                    case ExifInterface.ORIENTATION_ROTATE_90:\n                        return 90;\n                    case ExifInterface.ORIENTATION_ROTATE_180:\n                        return 180;\n                    case ExifInterface.ORIENTATION_ROTATE_270:\n                        return 270;\n                }\n            }\n            return 0;\n        } catch (IOException ex) {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG, \"Cannot read exif\", ex);\n            }\n            return 0;\n        }\n    }\n\n    /**\n     * Rotates the bitmap by the specified degree If a new bitmap is created, the original bitmap is\n     * recycled.\n     *\n     * @param b bitmap\n     * @param degrees number of degree to rotate\n     * @return bitmap\n     */\n    private static Bitmap rotateBitmap(Bitmap b, int degrees) {\n        if (LogUtils.isActive) {\n            Log.d(LOGTAG, \"Rotate bitmap degrees: \" + degrees);\n        }\n        Matrix m = new Matrix();\n        m.setRotate(degrees, (float) b.getWidth() / 2, (float) b.getHeight() / 2);\n        try {\n            Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);\n            if (b != b2) {\n                b.recycle();\n                b = b2;\n            }\n            return b;\n        } catch (OutOfMemoryError ex) {\n            if (LogUtils.isActive) {\n                // We have no memory to rotate. Return the original bitmap.\n                Log.w(LOGTAG, \"OutOfMemoryError: cannot rotate image\");\n            }\n            System.gc();\n            return b;\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/LogUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\n/**\n * @author yplo6403\n */\npublic class LogUtils {\n\n    /**\n     * Flag {@code isActive} to disable or enable log\n     */\n    public static final boolean isActive = true;\n\n    /**\n     * Utility routine to forge log tag of the RI client application\n     * \n     * @param classname the class name\n     * @return the log tag\n     */\n    public static String getTag(final String classname) {\n        return \"[RI][\" + classname + \"]\";\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/NetworkRessourceManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport java.io.IOException;\n\n/**\n * Network ressource manager\n * \n * @author Jean-Marc AUFFRET\n */\npublic class NetworkRessourceManager {\n    /**\n     * Default RTP port base\n     */\n    public static final int DEFAULT_LOCAL_RTP_PORT_BASE = 5000;\n\n    /**\n     * Generate a default free RTP port number\n     * \n     * @return Local RTP port\n     */\n    public static synchronized int generateLocalRtpPort() {\n        return generateLocalUdpPort(DEFAULT_LOCAL_RTP_PORT_BASE);\n    }\n\n    /**\n     * Generate a free UDP port number from a specific port base\n     * \n     * @param portBase UDP port base\n     * @return Local UDP port\n     */\n    private static int generateLocalUdpPort(int portBase) {\n        int resp = -1;\n        int port = portBase;\n        while ((resp == -1) && (port < Integer.MAX_VALUE)) {\n            if (isLocalUdpPortFree(port)) {\n                // Free UDP port found\n                resp = port;\n            } else {\n                // +2 needed for RTCP port\n                port += 2;\n            }\n        }\n        return resp;\n    }\n\n    /**\n     * Test if the given local UDP port is really free (not used by other applications)\n     * \n     * @param port Port to check\n     * @return Boolean\n     */\n    private static boolean isLocalUdpPortFree(int port) {\n        try {\n            DatagramConnection conn = NetworkRessourceManager.createDatagramConnection();\n            conn.open(port);\n            conn.close();\n            return true;\n\n        } catch (IOException e) {\n            return false;\n        }\n    }\n\n    /**\n     * Create a datagram connection\n     * \n     * @return Datagram connection\n     */\n    public static DatagramConnection createDatagramConnection() {\n        return new AndroidDatagramConnection();\n    }\n\n    /**\n     * Create a datagram connection with a specific SO timeout\n     * \n     * @param timeout SO timeout\n     * @return Datagram connection\n     */\n    public static DatagramConnection createDatagramConnection(int timeout) {\n        return new AndroidDatagramConnection(timeout);\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/RcsContactUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.ri.R;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.net.Uri;\nimport android.provider.ContactsContract;\nimport android.support.v4.util.LruCache;\nimport android.util.Log;\n\nimport java.io.InputStream;\n\n/**\n * Utilities to manage the RCS display name\n * \n * @author Philippe LEMORDANT\n */\npublic class RcsContactUtil {\n\n    private static final int MAX_DISPLAY_NAME_IN_CACHE = 200;\n    private static final String LOGTAG = LogUtils.getTag(RcsContactUtil.class.getSimpleName());\n\n    private static volatile RcsContactUtil sInstance;\n    private final ContentResolver mResolver;\n    private ContactService mService;\n    private final String mDefaultDisplayName;\n    private LruCache<ContactId, String> mDisplayNameAndroidCache;\n    private LruCache<ContactId, Bitmap> mPhotoContactCache;\n\n    private static final String[] PROJ_DISPLAY_NAME = new String[] {\n        ContactsContract.PhoneLookup.DISPLAY_NAME\n    };\n\n    private static final String[] PROJ_CONTACT_ID = new String[] {\n        ContactsContract.PhoneLookup._ID\n    };\n\n    /**\n     * Constructor\n     * \n     * @param context the context\n     */\n    private RcsContactUtil(Context context) {\n        mService = ConnectionManager.getInstance().getContactApi();\n        mResolver = context.getContentResolver();\n        mDefaultDisplayName = context.getString(R.string.label_no_contact);\n        mDisplayNameAndroidCache = new LruCache<>(MAX_DISPLAY_NAME_IN_CACHE);\n        mPhotoContactCache = new LruCache<>(MAX_DISPLAY_NAME_IN_CACHE);\n    }\n\n    /**\n     * Get an instance of RcsDisplayName.\n     * \n     * @param context the context\n     * @return the singleton instance.\n     */\n    public static RcsContactUtil getInstance(Context context) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (RcsContactUtil.class) {\n            if (sInstance == null) {\n                sInstance = new RcsContactUtil(context);\n            }\n            return sInstance;\n        }\n    }\n\n    private String getDisplayNameFromAddressBook(ContactId contact) {\n        /* First try to get it from cache */\n        String displayName = mDisplayNameAndroidCache.get(contact);\n        if (displayName != null) {\n            return displayName;\n        }\n        /* Not found in cache: query the Android address book */\n        Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,\n                Uri.encode(contact.toString()));\n        Cursor cursor = null;\n        try {\n            cursor = mResolver.query(uri, PROJ_DISPLAY_NAME, null, null, null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query display name for contact=\" + contact);\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            displayName = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ContactsContract.PhoneLookup.DISPLAY_NAME));\n            /* Insert in cache */\n            mDisplayNameAndroidCache.put(contact, displayName);\n            return displayName;\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    /**\n     * Returns display name which can be displayed on UI\n     * \n     * @param contact the contact\n     * @return the display name\n     */\n    public String getDisplayName(ContactId contact) {\n        if (contact == null) {\n            return mDefaultDisplayName;\n        }\n        String displayName = getDisplayNameFromAddressBook(contact);\n        if (displayName != null) {\n            /*\n             * Contact exists in Android Address Book: returns the AB display name.\n             */\n            return displayName;\n        }\n        try {\n            if (mService == null) {\n                mService = ConnectionManager.getInstance().getContactApi();\n            }\n            RcsContact rcsContact = mService.getRcsContact(contact);\n            if (rcsContact == null) {\n                /*\n                 * Contact is not RCS: returns the phone number.\n                 */\n                return contact.toString();\n            }\n            displayName = rcsContact.getDisplayName();\n            if (displayName == null) {\n                return contact.toString();\n            } else {\n                return displayName;\n            }\n        } catch (RcsServiceNotAvailableException ignore) {\n\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        }\n        /* By default display name is set to the MSISDN */\n        return contact.toString();\n    }\n\n    /**\n     * get RCS display in a String which can be displayed on UI\n     * \n     * @param number the phone number\n     * @return the name which can be displayed on UI\n     */\n    public String getDisplayName(String number) {\n        if (number == null) {\n            return mDefaultDisplayName;\n        }\n        if (!ContactUtil.isValidContact(number)) {\n            return number;\n        }\n        ContactId contact = ContactUtil.formatContact(number);\n        return getDisplayName(contact);\n    }\n\n    /**\n     * Gets the photo of a contact, or null if no photo is present\n     * \n     * @param contact the contact ID\n     * @return an Bitmap of the photo, or null if no photo is present\n     */\n    public Bitmap getPhotoFromContactId(ContactId contact) {\n        /* First try to get it from cache */\n        Bitmap photo = mPhotoContactCache.get(contact);\n        if (photo != null) {\n            return photo;\n        }\n        Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,\n                Uri.encode(contact.toString()));\n        Cursor cursor = null;\n        try {\n            cursor = mResolver.query(contactUri, PROJ_CONTACT_ID, null, null, null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query photo for contact=\" + contact);\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            long contactId = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ContactsContract.PhoneLookup._ID));\n            InputStream photoInputStream = ContactsContract.Contacts.openContactPhotoInputStream(\n                    mResolver,\n                    ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId));\n            if (photoInputStream != null) {\n                photo = BitmapFactory.decodeStream(photoInputStream);\n                /* Insert in cache */\n                mPhotoContactCache.put(contact, photo);\n                return photo;\n            }\n            return null;\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/RcsSessionUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.extension.MultimediaSession;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.upload.FileUpload;\n\n/**\n * @author LEMORDANT Philippe\n */\npublic class RcsSessionUtil {\n\n    /**\n     * Checks if file transfer session can be aborted\n     * \n     * @param fileTransfer file transfer session\n     * @return True if file transfer session can be aborted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    static public boolean isAllowedToAbortFileTransferSession(FileTransfer fileTransfer)\n            throws RcsPersistentStorageException, RcsGenericException {\n        switch (fileTransfer.getState()) {\n            case STARTED:\n            case QUEUED:\n            case PAUSED:\n            case INITIATING:\n            case ACCEPTING:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * Checks if geoloc sharing session can be aborted\n     * \n     * @param geolocSharing geoloc sharing session\n     * @return True if geoloc sharing session can be aborted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    static public boolean isAllowedToAbortGeolocSharingSession(GeolocSharing geolocSharing)\n            throws RcsPersistentStorageException, RcsGenericException {\n        switch (geolocSharing.getState()) {\n            case STARTED:\n            case INITIATING:\n            case ACCEPTING:\n            case RINGING:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * Checks if image sharing session can be aborted\n     * \n     * @param imageSharing image sharing session\n     * @return True if image sharing session can be aborted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    static public boolean isAllowedToAbortImageSharingSession(ImageSharing imageSharing)\n            throws RcsPersistentStorageException, RcsGenericException {\n        switch (imageSharing.getState()) {\n            case STARTED:\n            case INITIATING:\n            case ACCEPTING:\n            case RINGING:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * Checks if video sharing session can be aborted\n     * \n     * @param videoSharing video sharing session\n     * @return True if image sharing session can be aborted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    static public boolean isAllowedToAbortVideoSharingSession(VideoSharing videoSharing)\n            throws RcsPersistentStorageException, RcsGenericException {\n        switch (videoSharing.getState()) {\n            case STARTED:\n            case INITIATING:\n            case ACCEPTING:\n            case RINGING:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * Checks if multimedia session can be aborted\n     * \n     * @param multimediaSession multimedia session\n     * @return True if multimedia session can be aborted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    static public boolean isAllowedToAbortMultimediaSession(MultimediaSession multimediaSession)\n            throws RcsPersistentStorageException, RcsGenericException {\n        switch (multimediaSession.getState()) {\n            case STARTED:\n            case INITIATING:\n            case ACCEPTING:\n            case RINGING:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    /**\n     * Checks if upload session can be aborted\n     * \n     * @param session upload session\n     * @return True if upload session can be aborted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    static public boolean isAllowedToAbortFileUploadSession(FileUpload session)\n            throws RcsPersistentStorageException, RcsGenericException {\n        switch (session.getState()) {\n            case STARTED:\n            case INITIATING:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/SmileyParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport android.content.Context;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.style.ImageSpan;\n\nimport java.util.ArrayList;\n\n/**\n * Parses a text message typed by the user looking for smileys.\n */\npublic class SmileyParser extends AbstractMessageParser {\n\n    private Smileys mRes;\n\n    public SmileyParser(String text, Smileys res) {\n        super(text, true, // smileys\n                false, // acronyms\n                false, // formatting\n                false, // urls\n                false, // music\n                false // me text\n        );\n        mRes = res;\n    }\n\n    @Override\n    protected Resources getResources() {\n        return mRes;\n    }\n\n    /**\n     * Retrieves the parsed text as a spannable string object.\n     * \n     * @param context the context for fetching smiley resources.\n     * @return the spannable string as CharSequence.\n     */\n    public CharSequence getSpannableString(Context context) {\n        SpannableStringBuilder builder = new SpannableStringBuilder();\n\n        if (getPartCount() == 0) {\n            return \"\";\n        }\n\n        // should have only one part since we parse smiley only\n        Part part = getPart(0);\n        ArrayList<Token> tokens = part.getTokens();\n        int len = tokens.size();\n        for (int i = 0; i < len; i++) {\n            Token token = tokens.get(i);\n            int start = builder.length();\n            builder.append(token.getRawText());\n            if (token.getType() == AbstractMessageParser.Token.Type.SMILEY) {\n                int resid = mRes.getSmileyRes(token.getRawText());\n                if (resid != -1) {\n                    builder.setSpan(new ImageSpan(context, resid), start, builder.length(),\n                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n                }\n            }\n        }\n        return builder;\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/Smileys.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.rcs.ri.R;\nimport com.gsma.rcs.ri.utils.AbstractMessageParser.TrieNode;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.res.Resources;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\nimport android.widget.EditText;\nimport android.widget.ImageView;\nimport android.widget.SimpleAdapter;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Resources for smiley parser.\n */\npublic class Smileys implements AbstractMessageParser.Resources {\n    private HashMap<String, Integer> mSmileyToRes = new HashMap<>();\n\n    private static final int[] DEFAULT_SMILEY_RES_IDS = {\n            R.drawable.ri_smiley_happy, // 0\n            R.drawable.ri_smiley_sad, // 1\n            R.drawable.ri_smiley_winking, // 2\n            R.drawable.ri_smiley_tongue_sticking_out, // 3\n            R.drawable.ri_smiley_surprised, // 4\n            R.drawable.ri_smiley_kissing, // 5\n            R.drawable.ri_smiley_yelling, // 6\n            R.drawable.ri_smiley_cool, // 7\n            R.drawable.ri_smiley_money_mouth, // 8\n            R.drawable.ri_smiley_foot_in_mouth, // 9\n            R.drawable.ri_smiley_embarrassed, // 10\n            R.drawable.ri_smiley_angel, // 11\n            R.drawable.ri_smiley_undecided, // 12\n            R.drawable.ri_smiley_crying, // 13\n            R.drawable.ri_smiley_lips_are_sealed, // 14\n            R.drawable.ri_smiley_laughing, // 15\n            R.drawable.ri_smiley_wtf\n    // 16\n    };\n\n    private static final int DEFAULT_SMILEY_TEXTS = R.array.default_smiley_texts;\n\n    private static final int DEFAULT_SMILEY_NAMES = R.array.default_smiley_names;\n\n    /**\n     * Constructor\n     * \n     * @param context context\n     */\n    public Smileys(Context context) {\n        String[] smilies = context.getResources().getStringArray(DEFAULT_SMILEY_TEXTS);\n        int[] smileyResIds = DEFAULT_SMILEY_RES_IDS;\n\n        for (int i = 0; i < smilies.length; i++) {\n            TrieNode.addToTrie(smileys, smilies[i], \"\");\n            mSmileyToRes.put(smilies[i], smileyResIds[i]);\n        }\n    }\n\n    /**\n     * Looks up the resource id of a given smiley.\n     * \n     * @param smiley The smiley to look up.\n     * @return the resource id of the specified smiley, or -1 if no resource id is associated with\n     *         it.\n     */\n    public int getSmileyRes(String smiley) {\n        Integer i = mSmileyToRes.get(smiley);\n        if (i == null) {\n            return -1;\n        }\n        return i;\n    }\n\n    private final TrieNode smileys = new TrieNode();\n\n    public Set<String> getSchemes() {\n        return null;\n    }\n\n    public TrieNode getDomainSuffixes() {\n        return null;\n    }\n\n    public TrieNode getSmileys() {\n        return smileys;\n    }\n\n    public TrieNode getAcronyms() {\n        return null;\n    }\n\n    /**\n     * Show a list of smileys\n     * \n     * @param context context\n     * @param textEdit text edit\n     * @param resources resources\n     * @param title title\n     * @return the dialog\n     */\n    public static AlertDialog showSmileyDialog(Context context, final EditText textEdit,\n            final Resources resources, String title) {\n        int[] icons = DEFAULT_SMILEY_RES_IDS;\n        String[] names = resources.getStringArray(DEFAULT_SMILEY_NAMES);\n        final String[] texts = resources.getStringArray(DEFAULT_SMILEY_TEXTS);\n\n        final int N = names.length;\n\n        List<Map<String, ?>> entries = new ArrayList<>();\n        for (int i = 0; i < N; i++) {\n            // We might have different ASCII for the same icon, skip it if\n            // the icon is already added.\n            boolean added = false;\n            for (int j = 0; j < i; j++) {\n                if (icons[i] == icons[j]) {\n                    added = true;\n                    break;\n                }\n            }\n            if (!added) {\n                HashMap<String, Object> entry = new HashMap<>();\n                entry.put(\"icon\", icons[i]);\n                entry.put(\"name\", names[i]);\n                entry.put(\"text\", texts[i]);\n                entries.add(entry);\n            }\n        }\n\n        final SimpleAdapter a = new SimpleAdapter(context, entries,\n                R.layout.utils_smiley_menu_item, new String[] {\n                        \"icon\", \"name\", \"text\"\n                }, new int[] {\n                        R.id.smiley_icon, R.id.smiley_name, R.id.smiley_text\n                });\n        SimpleAdapter.ViewBinder viewBinder = new SimpleAdapter.ViewBinder() {\n            public boolean setViewValue(View view, Object data, String textRepresentation) {\n                if (view instanceof ImageView) {\n                    Drawable img = resources.getDrawable((Integer) data);\n                    ((ImageView) view).setImageDrawable(img);\n                    return true;\n                }\n                return false;\n            }\n        };\n        a.setViewBinder(viewBinder);\n\n        AlertDialog.Builder b = new AlertDialog.Builder(context);\n        b.setTitle(title);\n        b.setCancelable(true);\n        b.setAdapter(a, new DialogInterface.OnClickListener() {\n            public final void onClick(DialogInterface dialog, int which) {\n                @SuppressWarnings(\"unchecked\")\n                HashMap<String, Object> item = (HashMap<String, Object>) a.getItem(which);\n                textEdit.append((String) item.get(\"text\"));\n            }\n        });\n        return b.show();\n    }\n\n}\n"
  },
  {
    "path": "RI/src/com/gsma/rcs/ri/utils/Utils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.ri.utils;\n\nimport com.gsma.rcs.ri.R;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.widget.Toast;\n\nimport java.util.Locale;\nimport java.util.Random;\nimport java.util.Set;\n\n/**\n * Utility functions\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class Utils {\n\n    private static final Random sPendingIntentIdGenerator = new Random();\n\n    /**\n     * Gets a unique ID for pending intent\n     * \n     * @return unique ID for pending intent\n     */\n    public static int getUniqueIdForPendingIntent() {\n        return sPendingIntentIdGenerator.nextInt();\n    }\n\n    /**\n     * Display a toast\n     * \n     * @param ctx Context\n     * @param message Message to be displayed\n     */\n    public static void displayToast(Context ctx, String message) {\n        Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show();\n    }\n\n    /**\n     * Display a long toast\n     * \n     * @param ctx Context\n     * @param message Message to be displayed\n     */\n    public static void displayLongToast(Context ctx, String message) {\n        Toast.makeText(ctx, message, Toast.LENGTH_LONG).show();\n    }\n\n    /**\n     * Shows a picture\n     * \n     * @param activity Activity\n     * @param uri Picture to be displayed\n     */\n    public static void showPicture(final Activity activity, Uri uri) {\n        Intent intent = new Intent();\n        intent.setAction(android.content.Intent.ACTION_VIEW);\n        intent.setDataAndType(uri, \"image/*\");\n        activity.startActivity(intent);\n    }\n\n    /**\n     * Checks if mime type is an image type\n     *\n     * @param mime MIME type\n     * @return True if mime type is an image type\n     */\n    public static boolean isImageType(String mime) {\n        return mime.toLowerCase(Locale.getDefault()).startsWith(\"image/\");\n    }\n\n    /**\n     * Checks if mime type is an audio type\n     *\n     * @param mime MIME type\n     * @return True if mime type is an audio type\n     */\n    public static boolean isAudioType(String mime) {\n        return mime.toLowerCase(Locale.getDefault()).startsWith(\"audio/\");\n    }\n\n    /**\n     * Checks if mime type is an video type\n     *\n     * @param mime MIME type\n     * @return True if mime type is an video type\n     */\n    public static boolean isVideoType(String mime) {\n        return mime.toLowerCase(Locale.getDefault()).startsWith(\"video/\");\n    }\n\n    /**\n     * Plays audio document\n     * \n     * @param activity Activity\n     * @param uri Uri of audio file to be played\n     */\n    public static void playAudio(final Activity activity, Uri uri) {\n        Intent intent = new Intent();\n        intent.setAction(android.content.Intent.ACTION_VIEW);\n        intent.setDataAndType(uri, \"audio/\");\n        activity.startActivity(intent);\n    }\n\n    /**\n     * Show an info with a specific title\n     * \n     * @param activity Activity\n     * @param title Title of the dialog\n     * @param items List of items\n     * @return dialog\n     */\n    public static AlertDialog showList(Activity activity, String title, Set<String> items) {\n        CharSequence[] chars = items.toArray(new CharSequence[items.size()]);\n        AlertDialog.Builder builder = new AlertDialog.Builder(activity);\n        builder.setTitle(title);\n        builder.setCancelable(false);\n        builder.setPositiveButton(R.string.label_ok, null);\n        builder.setItems(chars, null);\n        return builder.show();\n    }\n\n    /**\n     * Gets the label to show the progress status\n     * \n     * @param currentSize Current size in bytes transferred\n     * @param totalSize Total size in bytes to be transferred\n     * @return progress label\n     */\n    public static String getProgressLabel(long currentSize, long totalSize) {\n        StringBuilder value = new StringBuilder();\n        value.append(FileUtils.humanReadableByteCount(currentSize, true));\n        if (totalSize != 0) {\n            value.append('/');\n            value.append(FileUtils.humanReadableByteCount(totalSize, true));\n        }\n        return value.toString();\n    }\n\n}\n"
  },
  {
    "path": "SDK/concepts.jd",
    "content": "page.title=Concepts\nhome=true\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Concepts</h1></p>\n\t\t\t<p><span>The joyn API permits to build new joyn applications on top of the native ones. The joyn API for Android terminal uses the Android concepts.</span></p>\n\t\t\t<p><span>The joyn API offers the following features:</span></p>\n\t\t\t<p></p>\n\t\t\t<ul class=\"list-concepts-1\">\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>Core joyn features:</span></p>\n\t\t\t\t\t<ul class=\"list-concepts-2\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/capability/package-summary.html\">Capability API:</a></span> <span>this API exposes classes/methods to manage the supported capabilities of the contacts of the native address book and the capabilities locally supported by the device.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/contacts/package-summary.html\">Contacts API:</a></span> <span>this API exposes classes/methods to read joyn infos (presence, capabilities) of the contacts of the native address book.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/package-summary.html\">Chat API:</a></span> <span>this API exposes classes/methods for using the single chat and the group chat services.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/ft/package-summary.html\">File transfer API :</a></span> <span>this API exposes classes/methods to transfer files in real time.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/ish/package-summary.html\">Image sharing API :</a></span> <span>this API exposes classes/methods to share an image (pre-recorded or live) during a CS call.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/vsh/package-summary.html\">Video sharing API:</a></span> <span>this API exposes all classes/methods to share a live video stream during a CS call.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/Intents.html\">Intents API:</a></span> <span>this API exposes Intents which permits to link your application with native joyn applications.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>Extended joyn features: this API permits to build new services on top of core joyn services.</span></p>\n\t\t\t\t\t<ul class=\"list-concepts-2\">\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/capability/package-summary.html\">New capability API :</a></span> <span>this API exposes methods to define and to discover dynamically new capabilities.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p><span ><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">MultiMedia session API :</a></span> <span>this API exposes classes/methods to create new multimedia application. The media is implemented in the application side and is independant from the joyn API.</span></p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<p></p>\n\t\t\t</br>\n\t\t\t\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<div class=\"guide-block\">\t\n\t\t\t\t<h2>Architecture</h2>\n\t\t\t\t<p><span>The joyn services are implemented via an Android service which runs in background on the device and which offers a joyn API interface for third party applications. Several applications may be connected at the same time to the the single joyn service by using a local client/server model. Several services may be used at a time.</span></p>\n\t\t\t\t<p><span>The joyn API uses the following Android concepts:</span></p>\n\t\t\t\t<ul >\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p><span>Android <a href=\"http://developer.android.com/reference/android/content/Intent.html\">Intents</a> </span></p>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p><span>Android <a href=\"http://developer.android.com/guide/topics/providers/content-providers.html\">Content Providers</a></span></p>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p><span><a href=\"http://developer.android.com/guide/components/aidl.html\">AIDL</a> interfaces</span></p>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<p></p>\n\t\t\t\t<div style=\"width:700px;margin:auto;\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/concepts_1.png\" width=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>Intents</h2>\n\t\t\t\t<p><a href=\"http://developer.android.com/reference/android/content/Intent.html\">Intents</a> are used to broadcast incoming invitations to applications (eg. file transfer invitation, multimedia session invitation, new chat message, .etc). Then it’s up to the application to catch the Intent and to display a popup or any UI associated to the incoming event.</p>\t\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>Content providers</h2>\n\t\t\t\t<p><a href=\"http://developer.android.com/guide/topics/providers/content-providers.html\">Content providers</a> are used to store logs persistently (eg. chat history, rich call log).</p>\t\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>AIDL interfaces</h2>\n\t\t\t\t<p><a href=\"http://developer.android.com/guide/components/aidl.html\">AIDL interfaces</a> are used to implement the entry point of each service API and to manage sessions dynamically (initiate, accept/reject, terminate). An AIDL interface permits also to receive session events thanks to callback methods.</p>\t\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>API connection</h2>\n\t\t\t\t<p>Prior to requesting a service API, an application should connect to the service API : this is the binding procedure between the client side and the server side of the API.</p>\n\t\t\t\t<p>When the binding has been done with success then the application can use API methods. Under Android, the binding procedure is asynchronous, so the API connection events are send to the application via callback method (see listener JoynServiceListener).</p>\t\n\t\t\t\t<p>See the following sequence diagram :</p>\t\t\n\t\t\t\t<p></p>\n\t\t\t\t<div style=\"width:700px;margin:auto;\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/concepts_2.png\" width=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t\t</br>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/demos.jd",
    "content": "page.title=Home\nhome=true\n@jd:body\n<script type=\"text/javascript\">\n    $('.slideshow-container').dacSlideshow({\n        auto: true,\n        btnPrev: '.slideshow-prev',\n        btnNext: '.slideshow-next'\n    });\n</script>\n<div class=\"background-sdk\">\n\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\t\n\t\t\t<div style=\"display:inline-block\">\n\t\t\t\t<div style=\"display:inline-block;float:left;\"><h1 style=\"border:0;\">Applications demonstrating joyn APIs</h1></div>\n\t\t\t\t<a  class=\"dl-btn\" href=\"{@docRoot}index.html\">Home</a>\n\t\t\t</div>\n\t\t\t<div id=\"mycarousel\" class=\"jcarousel-skin-tango\">\t\n\t\t\t\t<div class=\"jcarousel-control\" >\t\t\t\t\t\n\t\t\t\t\t<ul >\t\n\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<h2 class=\"demo-title\">Chat Application</h2>\n\t\t\t\t\t\t\t<iframe frameborder=\"0\" width=\"160\" height=\"90\" src=\"//www.dailymotion.com/embed/video/k2EOEbeoEPZ87k3SqZZ\" class=\"video-frame-carousel\"></iframe>\n\t\t\t\t\t\t\t<div class=\"demo-text\">This chat application demonstrates instant messaging and file transfer using joyn APIs.</br></br>Take a look at the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/package-summary.html\">chat API</a> documentation and see how you can further enhance your instant messaging experience.</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<h2 class=\"demo-title\">Deezer App</h2>\n\t\t\t\t\t\t\t<iframe frameborder=\"0\" width=\"160\" height=\"90\" src=\"//www.dailymotion.com/embed/video/k65awxJFmFbghS3SoSq\" class=\"video-frame-carousel\"></iframe>\n\t\t\t\t\t\t\t<div class=\"demo-text\">This application demonstrates how you can integrate share functionalities with your existing application.</br></br> Using joyn <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session API</a> you can send custom messages to any of your contacts.</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<h2 class=\"demo-title\">Popup Application</h2>\n\t\t\t\t\t\t\t<iframe frameborder=\"0\" width=\"160\" height=\"90\" src=\"//www.dailymotion.com/embed/video/k5YBvROqkbZH0O3Sp38\" class=\"video-frame-carousel\"></iframe>\n\t\t\t\t\t\t\t<div class=\"demo-text\">This applications shows how to use real time messaging in a fun and useful way.</br></br>Popup application uses <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session API</a> custom messaging to send text and image so you never miss that coffee break you've been waiting for.</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<h2 class=\"demo-title\">Whiteboard App</h2>\n\t\t\t\t\t\t\t<iframe frameborder=\"0\" width=\"480\" height=\"270\" src=\"//www.dailymotion.com/embed/video/x15d0cz\" class=\"video-frame-carousel\"></iframe>\n\t\t\t\t\t\t\t<div class=\"demo-text\">Whiteboard application demonstrates real time communications with joyn APIs.</br></br>Make cooperative drawings with contacts from your address book using <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session API</a>.</div>\n\t\t\t\t\t\t</li>\n\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<h2 class=\"demo-title\">LiveSharing App</h2>\n\t\t\t\t\t\t\t<iframe frameborder=\"0\" width=\"480\" height=\"270\" src=\"//www.dailymotion.com/embed/video/x15d0aj\" class=\"video-frame-carousel\"></iframe>\n\t\t\t\t\t\t\t<div class=\"demo-text\">Live browsing shows how you can share your browsing experience in real time with one of your contacts.</br></br>Using <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session API</a> browser events are sent in real time to your contacts and replicated on their application.</div>\n\t\t\t\t\t\t</li>\t\t\t\t\t\t\n\t\t\t\t\t</ul>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn left\" id=\"1\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"2\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"3\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"4\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn right\" id=\"5\"><div></div></a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t</br>\n\t\t\n\t\t<div class=\"content-body \" style=\"display:inline-block;margin:30px 5%;width:90%\">\n\t\t\t<div class=\"demo_box\" style=\"float:left\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"{@docRoot}getStarted.html\">Get Started</a></b></p>\n\t\t\t\t</div>\t\n\t\t\t\t<div>\n\t\t\t\t\t<p>Learn how to get joyn up and running on an Android device.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"demo_box\" style=\"float:right\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"https://rcsjta.googlecode.com/git/joyn-sdk-{@sdkCurrentVersion}.zip\">Get latest SDK</a></b></p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tThe latest version is {@sdkCurrentVersion}\t</br>\t\t\t\t\n\t\t\t\t\t\t<a style=\"color:#006699;text-decoration:underline;font-size:14px\"href=\"{@docRoot}releases/joyn-sdk-{@sdkCurrentVersion}.txt\">release note</a>.\n\t\t\t\t\t</p>\t\n\t\t\t\t\t\n\t\t\t\t</div>\t\n\t\t\t</div>\n\t\t\t<div class=\"demo_box\" style=\"float:right\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"{@docRoot}javadoc/index.html\">SDK Reference</a></b></p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tFull documentation for joyn terminal APIs.\n\t\t\t\t\t</p>\n\t\t\t\t\t\n\t\t\t\t</div>\t\n\t\t\t</div>\n\t\t\t<div  style=\"float:right\" class=\"demo_box\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"{@docRoot}concepts.html\">Concepts</a></b></p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<p>\n\t\t\t\t\tDiscover the concepts used in the joyn APIs.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\t\n\t\t\t</div>\n\t\t</div>\n\t</div>\t\n</div>\t"
  },
  {
    "path": "SDK/download/index.jd",
    "content": "page.title=Downloads\ndoc.type=download\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;background-repeat: no-repeat;background-position: center;background-position-y: bottom;\">\n\t\t<div class=\"intro center\" >\t\n\t\t\t<p><h1>Downloads</h1></p>\n\t\t\t<p><span>The SDK is delivered as a ZIP file which may be deployed anywhere in a local directory on your PC.</span></p>\n\t\t\t<p></p>\n\t\t\t<p><span>The SDK contains:</span></p>\n\t\t\t<p></p>\n\t\t\t<ul>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>A complete Javadoc.</span></p>\n\t\t\t\t</li>\n\t\t\t\t\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>Source code samples.</span></p>\n\t\t\t\t</li>\n\t\t\t\t\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>Tutorials.</span></p>\n\t\t\t\t</li>\n\t\t\t\t\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>Tools: a standalone RCS service if your device is not natively joyn compliant, a Reference Implementation (RI) which allows you to test the joyn features.</span></p>\n\t\t\t\t</li>\n\t\t\t\t\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The joyn API library: this is the JAR file which allows you to implement your joyn app.</span></p>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<p></p>\n\t\t\t<p><span>Download the latest SDK release from here:</span></p>\n\t\t\t<p><span style=\"margin-left:30px\"><a href=\"https://rcsjta.googlecode.com/git/joyn-sdk-{@sdkCurrentVersion}.zip\">joyn SDK {@sdkCurrentVersion}</a><span style=\"margin-left:30px\"><a href=\"{@docRoot}releases/joyn-sdk-{@sdkCurrentVersion}.txt\">README</a></span></p>\n\t\t</div>\n\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\n\t\t<div class=\"content-body center\">\n\t\t\t\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/getStarted.jd",
    "content": "page.title=Get Started\nhome=true\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"background: rgb(249, 249, 249);padding:0;border:0;\">\n\t\t<div class=\"intro center\" style=\"padding: 10px 10%;border: 1px solid #eaeaea;background: #fff;border-bottom:0;margin:0;\">\n\t\t\t<p><h1>Lets get started ...</h1></p>\n\t\t\t<p><span>The joyn android terminal SDK regroups all the knowledge needed to develop joyn apps. But before getting down to business, let's take some time and make sure you have everything you need to get started in the best of ways.</span></p>\n\t\t</div>\n\t\t<div >\n\t\t\t<div class=\"step_header getStarted\" style=\"margin-top: 0;\">\n\t\t\t\t<p><h2><span class=\"h_num\">1</span>Install and prerequisites</h2></p>\n\t\t\t\t<p>Eclipse, Android SDK and ADT</p>\n\t\t\t\t<p><a id=\"show1\" onclick=\"showStep(this,'hide1','step1');\">show</a></p>\n\t\t\t\t<p><a id=\"hide1\" style=\"display:none;\" onClick=\"hideStep(this,'show1','step1');\">hide</a></p>\n\t\t\t\t<div id=\"step1\" class=\"step_content\" style=\"display:none;\">\n\t\t\t\t\t<p>The required version for the Android SDK is at least 2.3 (Gingerbread).</p>\n\t\t\t\t\t<p>There are two ways to install Eclipse, Android SDK and ADT.</p>\t\t\t\t\t\n\t\t\t\t\t<p><h3>Solution 1 : </h3></p>\n\t\t\t\t\t<p>Go to <a target=\"_blank\" href=\"http://developer.android.com/sdk/index.html\">Android Developers website</a> and download the latest version of the ADT bundle for windows. Unzip the bundle and launch Eclipse. Create a new workspace if needed. </p>\n\t\t\t\t\t<p>That's it!<p> \n\t\t\t\t\t<p><h3>Solution 2 : </h3></p>\n\t\t\t\t\t<p>If you wish to download each component separately or you wish to add ADT plugin to a pre-installed version of Eclipse, follow these steps</p>\t\t\t\t\t\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p>Download the latest version of <a target=\"_blank\" href=\"http://www.eclipse.org/downloads/\">Eclipse</a> </p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p>Follow the instructions on the <a target=\"_blank\" href=\"http://developer.android.com/sdk/installing/index.html\">Android Developers website</a> \n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t\n\t\t\t<div class=\"step_header getStarted\">\n\t\t\t\t<p><h2><span class=\"h_num\">2</span>Install the joyn SDK</h2></p>\n\t\t\t\t<p>Download and install the latest joyn SDK on your PC.</p>\n\t\t\t\t<p><a id=\"show2\" onclick=\"showStep(this,'hide2','step2');\">show</a></p>\n\t\t\t\t<p><a id=\"hide2\" style=\"display:none;\" onClick=\"hideStep(this,'show2','step2');\">hide</a></p>\n\t\t\t\t<div id=\"step2\" class=\"step_content\" style=\"display:none;\">\n\t\t\t\t\t\t<p>You can donwload directly our SDK from <a  href=\"https://rcsjta.googlecode.com/git/joyn-sdk-{@sdkCurrentVersion}.zip\">here</a></p>\t\n\t\t\t\t\t\t<p>You can also visit our <a href=\"{@docRoot}download/index.html\">Downloads</a> page where you will find more information about the latest release and a link to the latest version.</p>\n\t\t\t\t\t\t<p>Once you have download the ZIP file, all you need to do is Unzip the package to a directory of your choice.\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"step_header getStarted\">\n\t\t\t\t<p><h2><span class=\"h_num\">3</span>Install and configure the joyn service on your Android terminal</h2></p>\n\t\t\t\t<p>Install joyn services and configure stack if not pre-installed on device</p>\n\t\t\t\t<p><a id=\"show3\" onclick=\"showStep(this,'hide3','step3');\">show</a></p>\n\t\t\t\t<p><a id=\"hide3\" style=\"display:none;\" onClick=\"hideStep(this,'show3','step3');\">hide</a></p>\n\t\t\t\t<div id=\"step3\" class=\"step_content\" style=\"display:none;\">\n\t\t\t\t\t\t<p>If your device is not natively joyn, you must install the standalone joyn services and configure it.</p>\n\t\t\t\t\t\t<p>You can get the standalone joyn service application from <a href=\"{@docRoot}tools/joyn-core.apk\">here</a>.</p>\n\t\t\t\t\t\t<p>There is also a dedicated <a href=\"{@docRoot}tools/installJoynServices.html\">guide</a> explaining the installation and configuration of these services.</p>\t\t\t\t\t\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"step_header getStarted\">\n\t\t\t\t<p><h2><span class=\"h_num\">4</span>Import sample projects</h2></p>\n\t\t\t\t<p>Import and configure sample projects</p>\n\t\t\t\t<p><a id=\"show4\" onclick=\"showStep(this,'hide4','step4');\">show</a></p>\n\t\t\t\t<p><a id=\"hide4\" style=\"display:none;\" onClick=\"hideStep(this,'show4','step4');\">hide</a></p>\n\t\t\t\t<div id=\"step4\" class=\"step_content\" style=\"display:none;\">\t\t\t\n\t\t\t\t\t\t<p>First open Eclipse IDE.</p>\n\t\t\t\t\t\t<p>Open the <b>file</b> menu and click <b>import</b>.</p>\n\t\t\t\t\t\t<div style=\"width:700px;margin:auto;\">\n\t\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_sample_1.png\" width=\"100%\"/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t\t\t<p>Now click on <b>Android</b>, then select <b>Existing Android Code Into Workspace</b>. Click <b>Next &gt;</b>.</p>\n\t\t\t\t\t\t<div style=\"width:350px;margin:auto;\">\n\t\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_sample_2.png\" width=\"100%\"/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t\t\t<p>Click on <b>Browse...</b>, navigate to the directory where you unziped the sdk and select the <b>sample_projects</b> folder.</p>\n\t\t\t\t\t\t<p>A list of projects present in the folder should appear. You can select all the projects or just one if you wish.</p>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<div style=\"width:450px;margin:auto;\">\n\t\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_sample_3.png\" width=\"100%\"/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t\t\t<p>Select <b>Copy projects into workspace</b> (If the projects are already present under your workspace directory, do not select). </p>\n\t\t\t\t\t\t<p>Finally, click on <b>Finish</b>.</p>\n\t\t\t\t\t\t<p>You will have to add the joyn-API JAR to the project's build path (if this is not already the case). You will find the JAR file in the <b>libs</b> folder of the SDK. Copy it to a new folder in your project and add to build path.</p>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"step_header getStarted\">\n\t\t\t\t<p><h2><span class=\"h_num\">5</span>Run a sample project</h2></p>\n\t\t\t\t<p>Try out a joyn sample application on your terminal</p>\n\t\t\t\t<p><a id=\"show5\" onclick=\"showStep(this,'hide5','step5');\">show</a></p>\n\t\t\t\t<p><a id=\"hide5\" style=\"display:none;\" onClick=\"hideStep(this,'show5','step5');\">hide</a></p>\n\t\t\t\t<div id=\"step5\" class=\"step_content\" style=\"display:none;\">\t\t\t\t\t\n\t\t\t\t\t\t<p>The easiest way to install and run an application on your terminal is to use Eclipse.</p>\n\t\t\t\t\t\t<P>Connect your device via USB and make sure <b>Android debug</b> is activated.</p>\n\t\t\t\t\t\t<p>In Eclipse, right-click on your project, go to <b>Run As</b> then <b>Android Application</b>.</p>\n\t\t\t\t\t\t<div style=\"width:400px;margin:auto;\">\n\t\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_sample_4.png\" width=\"100%\"/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t\t\t<p>A popup should appear with a list of available devices. Select the device you wish to install on and click <b>Ok</b>.</p>\n\t\t\t\t\t\t<div style=\"width:350px;margin:auto;\">\n\t\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_sample_5.png\" width=\"100%\"/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t\t\t<p>The application should automatically launch on your device.</p>\n\t\t\t\t\t\t<p></p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"step_header getStarted\">\n\t\t\t\t<p><h2><span class=\"h_num\">6</span>Nearly there</h2></p>\n\t\t\t\t<p>Before you start coding, have a look at the different <a href=\"{@docRoot}concepts.html\">concepts</a> behind joyn APIs.</p>\n\t\t\t\t<p>There are also a number of <a href=\"{@docRoot}tutorials/index.html\">tutorials</a> and <a href=\"{@docRoot}samples/index.html\">samples</a> that can help you kick-start your application development.</p>\n\t\t\t</div>\n\t\t\t<div class=\"step_header getStarted\">\n\t\t\t\t<p><h2><span class=\"h_num\" style=\"top:20px;left: 80px;\"><img src=\"{@docRoot}assets/images/rcs_notif_icon.png\" height=\"100%\"/></span>Have fun</h2></p>\n\t\t\t\t<p>and if you have any questions don't hesitate to <a href=\"mailto:jeanmarc.auffret@orange.com\">contact</a> us.</p>\n\t\t\t</div>\n\t\t</div>\n\t\t\n\t</div>\n</div>"
  },
  {
    "path": "SDK/index.jd",
    "content": "page.title=Home\nhome=true\n@jd:body\n<script type=\"text/javascript\">\n    $('.slideshow-container').dacSlideshow({\n        auto: true,\n        btnPrev: '.slideshow-prev',\n        btnNext: '.slideshow-next'\n    });\n</script>\n<div class=\"background-sdk\">\n\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\t\n\t\t\t<div style=\"display:inline-block;\"\">\n\t\t\t\t<div style=\"display:inline-block;float:left;\"><h1 style=\"border:0;\">Welcome to the joyn SDK for Android terminals</h1></div>\n\t\t\t\t<a  class=\"dl-btn\" href=\"{@docRoot}demos.html\">Demos</a>\n\t\t\t</div>\n\t\t\t<div id=\"mycarousel\" class=\"jcarousel-skin-tango\">\t\n\t\t\t\t<div class=\"jcarousel-control\" >\t\t\t\t\t\n\t\t\t\t\t<ul >\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<span>\t\t\t\t\n\t\t\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/app_icon.png\" height=\"30\" width=\"33\" style=\"float:left;margin-top: 0px;margin-right: 5px;\"/>\n\t\t\t\t\t\t\t\t<p><span style=\"text-decoration:underline\"><a target=\"_blank\" href=\"http://www.joynus.com/\" style=\"color:#333\">joyn™</a></span> is a certification trade mark of the GSMA (GSM Association) for RCS (Rich Communication Suite) which is an industry standard that is being adopted across the world by mobile operators. RCS is a set of new communication services to improve traditional communications with real times services.</p>\n\t\t\t\t\t\t\t\t<p>This SDK offers the first implementation of the joyn API which is under standardization with <a style=\"text-decoration:underline\" href=\"http://www.gsma.com/rcs\">GSMA</a> and where Orange is the main contributor with several OEMs (Samsung, Qualcomm, Ericsson, Sony, HTC ...).</p>\n\t\t\t\t\t\t\t\t<div style=\"margin-bottom: 3%;\">\n\t\t\t\t\t\t\t\t\t<iframe width=\"336\" height=\"189\" class=\"video-frame\" src=\"//www.youtube.com/embed/fu1XFZ2rqiM\" frameborder=\"0\" allowfullscreen></iframe>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<p><b>Enhance your app with joyn rich communication APIs. </b>joyn APIs leverage the device address book to encourage social recommendation from your phone numbers ; provide <b>rich messaging</b> with chat, file transfer and group chat ; provide <b>rich call</b> experience with image and live video sharing during voice calls ; share your <b>geolocation</b> with your contacts; and offer the possibility to <b>create your new joyn services</b>.</p>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\t\t\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<span>\t\n\t\t\t\t\t\t\t\t<p><h2>Capabilities discovery</h2></p>\n\t\t\t\t\t\t\t\t<p>Discover which services are supported by your contacts before do use them.</p>\n\t\t\t\t\t\t\t\t<img class=\"home-img\" src=\"{@docRoot}assets-sdk/images/home-capa.png\"/>\n\t\t\t\t\t\t\t\t<p style=\"margin:75px 20px 0 0;\">\n\t\t\t\t\t\t\t\t\tWhen installing a joyn application on a device, a contact gains the capabilities associated with the application. joyn APIs provide you with the capabilities associated with each contact of your native address book. \n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tOf course you can discover the core capabilities of joyn (chat, file transfer, .etc), but you can also declare and exchange new capabilities. \n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tHave a look at the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/capability/package-summary.html\">Capability API</a> to see how to implement these features in your application.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\t\t\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<span>\t\n\t\t\t\t\t\t\t\t<p><h2>Rich messaging</h2></p>\n\t\t\t\t\t\t\t\t<p>Add the real time instant messaging experience in your application.</p>\n\t\t\t\t\t\t\t\t<img class=\"home-img\" src=\"{@docRoot}assets-sdk/images/home-rm.png\"/>\n\t\t\t\t\t\t\t\t<p style=\"margin:105px 20px 0 0;\">\n\t\t\t\t\t\t\t\t\tMay it be point-to-point or group conversations, sending messages (text or geoloc) with delivery reports and transfering files in real time to one or several contacts.\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tAdding messaging features to games, social media or any application is simplified. \n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\tHave a look at the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/package-summary.html\">Chat API</a> and <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/ft/package-summary.html\">File transfer API</a> to see how to implement these features in your application.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\t\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<span>\t\n\t\t\t\t\t\t\t\t<p><h2>Rich call</h2></p>\n\t\t\t\t\t\t\t\t<p>Share in real time images, videos and locations during your phone calls.</p>\n\t\t\t\t\t\t\t\t<img class=\"home-img\" src=\"{@docRoot}assets-sdk/images/home-share.png\"/>\n\t\t\t\t\t\t\t\t<p style=\"margin:105px 20px 0 0;\">\n\t\t\t\t\t\t\t\t\tWith joyn APIs it is possible to share images, live videos and geolocations during a phone call. Take a live photo or film your favourite event, share it in real time and continue to comment it by phone.\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\tHave a look at the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/ish/package-summary.html\">Image sharing API</a>, <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/vsh/package-summary.html\">Video sharing API</a> and <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/gsh/package-summary.html\">Geoloc sharing API</a> to see how to implement these features in your application.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<span>\t\n\t\t\t\t\t\t\t\t<p><h2>Geolocalisation</h2></p>\n\t\t\t\t\t\t\t\t<p>Share your geolocation with your contacts.</p>\n\t\t\t\t\t\t\t\t<img class=\"home-img\" src=\"{@docRoot}assets-sdk/images/home-geo.png\"/>\n\t\t\t\t\t\t\t\t<p style=\"margin:105px 20px 0 0;\">\n\t\t\t\t\t\t\t\t\tShare your geolocation with your contacts via a chat or during a rich call.\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\tHave a look at the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/package-summary.html\">Chat API</a> and <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/gsh/package-summary.html\">Geoloc sharing API</a> to see how to implement these features in your application.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\t\t\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<span>\t\n\t\t\t\t\t\t\t\t<p><h2>New multimedia services</h2></p>\n\t\t\t\t\t\t\t\t<p>With the Multimedia Session API concept you can create new joyn services from your application. The API offers the way to initiate the new communication channel between contacts, then it's up to the application to implement the media corresponding to its service (gaming, music, video, ..., any data).\n\t\t\t\t\t\t\t\t<img class=\"home-img\" src=\"{@docRoot}assets-sdk/images/home-multi.png\"/>\n\t\t\t\t\t\t\t\t<p style=\"margin:105px 20px 0 0;\">\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\t</br>\n\t\t\t\t\t\t\t\t\tHave a look at our dedicated <a href=\"{@docRoot}/tutorials/multiApp.html\">tutorial</a> to better grasp the potential of the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session API</a>.</p>\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</li>\t\n\t\t\t\t\t</ul>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"1\"><div style=\"margin-left:285px\"></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"2\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"3\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"4\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"5\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn right\" id=\"6\"><div></div></a>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t</br>\n\t\t\n\t\t<div class=\"content-body \" style=\"display:inline-block;margin:30px 5%;width:90%\">\n\t\t\t<div class=\"demo_box\" style=\"float:left\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"{@docRoot}getStarted.html\">Get Started</a></b></p>\n\t\t\t\t</div>\t\n\t\t\t\t<div>\n\t\t\t\t\t<p>Learn how to get joyn up and running on an Android device.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"demo_box\" style=\"float:right\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"https://rcsjta.googlecode.com/git/joyn-sdk-{@sdkCurrentVersion}.zip\">Get latest SDK</a></b></p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tThe latest version is {@sdkCurrentVersion}\t</br>\t\t\t\t\n\t\t\t\t\t\t<a style=\"color:#006699;text-decoration:underline;font-size:14px\"href=\"{@docRoot}releases/joyn-sdk-{@sdkCurrentVersion}.txt\">release note</a>.\n\t\t\t\t\t</p>\t\n\t\t\t\t\t\n\t\t\t\t</div>\t\n\t\t\t</div>\n\t\t\t<div class=\"demo_box\" style=\"float:right\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"{@docRoot}javadoc/index.html\">SDK Reference</a></b></p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<p>\n\t\t\t\t\t\tFull documentation for joyn terminal APIs.\n\t\t\t\t\t</p>\n\t\t\t\t\t\n\t\t\t\t</div>\t\n\t\t\t</div>\n\t\t\t<div  style=\"float:right\" class=\"demo_box\">\n\t\t\t\t<div>\n\t\t\t\t\t<p><b><a href=\"{@docRoot}concepts.html\">Concepts</a></b></p>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<p>\n\t\t\t\t\tDiscover the concepts used in the joyn APIs.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\t\n\t\t\t</div>\n\t\t</div>\n\t</div>\t\n</div>\t"
  },
  {
    "path": "SDK/overview.jd",
    "content": "page.title=RCS Overview\ndoc.type=overview\n@jd:body\n\n<p>Start coding with our API documentation.</p>\n\n<p>See also the <a href=\"./../concepts.html\" >API concepts</a> and the <a target=\"_blank\" href=\"http://www.gsma.com/rcs/specifications\">joyn documentation</a> from GSMA.</p>\n"
  },
  {
    "path": "SDK/releases/Albatros.jd",
    "content": "page.title=API version Albatros\ndoc.type=apilevel\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t<p><h1>API version Albatros</h1></p>\n\t\t<span><p>joyn Albatros is the first release implementing the RCS-e 1.2.2 specification.</p></span>\n\t\t<span><p>See <a href=\"http://www.gsma.com/rcs/v1-2-joyn-hot-fixes-user-experience-guidelines\" target=\"_blank\">Product specification</a></p></span>\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/releases/Blackbird.jd",
    "content": "page.title=API version Blackbird\ndoc.type=apilevel\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t<p><h1>API version Blackbird</h1></p>\n\t\t<span><p>joyn Blackbird is based on RCS 5.0 and 5.1 specifications which include the RCS-e 1.2.2 specification, the Hot Fixes Implementation Guidelines 3.0 and the Hot Fixes UX Guidelines 2.2.</p></span>\n\t\t<span><p>Blackbird release introduces the following new features:</p></span>\n\t\t<ul>\t\n\t\t\t<li>\n\t\t\t\t<span>Geolocation (send geoloc, show us in a map, geolocation sharing during a call).</span>\t\n\t\t\t</li>\n\t\t\t<li>\n\t\t\t\t<span>File transfer enhancements (vCard, thumbnail, delivery report, pause & resume, file to group).</span>\t\t\n\t\t\t</li>\n\t\t\t<li>\n\t\t\t\t<span>IP voice & video call.</span>\t\n\t\t\t</li>\t\n\t\t\t<li>\n\t\t\t\t<span>Video sharing orientation management.</span>\t\n\t\t\t</li>\n\t\t</ul>\n\t\t<span><p>See <a href=\"http://www.gsma.com/rcs/joyn-blackbird-pdd\" target=\"_blank\">Product specification</a></p></span>\n\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/releases/Crane.jd",
    "content": "page.title=API version Crane\ndoc.type=apilevel\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t<p><h1>API version Crane</h1></p>\n\t\t<span><p>joyn Crane is based on RCS 5.2 specification.</p></span>\n\t\t<span><p>Crane release introduces the following new features:</p></span>\n\t\t<ul>\t\n\t\t\t<li>\n\t\t\t\t<span>Automata capability which indicates if the remote is an automata or not.</span>\t\n\t\t\t</li>\n\t\t\t<li>\n\t\t\t\t<span>Multimedia Session API which permits to create new multimedia services.</span>\t\t\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<span><p>Note: Crane specification not yet published by GSMA.</a></p></span>\n\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/releases/albatros.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"Intents\"\n type=\"com.gsma.services.rcs.Intents\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Client\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_CLIENT_GET_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;.client.action.GET_STATUS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_SETTINGS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_SETTINGS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CLIENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;client&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynContactFormatException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynContactFormatException\"\n type=\"com.gsma.services.rcs.JoynContactFormatException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService\"\n type=\"com.gsma.services.rcs.JoynService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GSMA_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.GSMA_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.GSMA_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.GSMA_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"RCSE_BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"RCSE_HOTFIXES_1_2\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.VERSION_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.VERSION_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CONNECTION_LOST\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SERVICE_DISABLED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceConfiguration\"\n type=\"com.gsma.services.rcs.JoynServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getUserDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isServiceActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n</class>\n<class name=\"JoynServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceException\"\n type=\"com.gsma.services.rcs.JoynServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<interface name=\"JoynServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n</interface>\n<class name=\"JoynServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.JoynServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.JoynServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceRegistrationListener\"\n extends=\"com.gsma.services.rcs.IJoynServiceRegistrationListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynUtils\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynUtils\"\n type=\"com.gsma.services.rcs.JoynUtils\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getJoynClients\"\n return=\"java.util.List&lt;android.content.pm.ResolveInfo&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isJoynClientActivated\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n<parameter name=\"receiverResult\" type=\"android.content.BroadcastReceiver\">\n</parameter>\n</method>\n<method name=\"loadJoynClientSettings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"Capabilities\"\n type=\"com.gsma.services.rcs.capability.Capabilities\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"imageSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"videoSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"imSession\" type=\"boolean\">\n</parameter>\n<parameter name=\"fileTransfer\" type=\"boolean\">\n</parameter>\n<parameter name=\"extensions\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</constructor>\n<constructor name=\"Capabilities\"\n type=\"com.gsma.services.rcs.capability.Capabilities\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"com.gsma.services.rcs.capability.ICapabilitiesListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesLog\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<field name=\"EXTENSION_BASE_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;+g.3gpp.iari-ref&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTENSION_PREFIX_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;urn%3Aurn-7%3A3gpp-application.ims.iari.rcse&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatIntent\"\n type=\"com.gsma.services.rcs.chat.ChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;message&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatListener\"\n extends=\"com.gsma.services.rcs.chat.IChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatListener\"\n type=\"com.gsma.services.rcs.chat.ChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog\"\n type=\"com.gsma.services.rcs.chat.ChatLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.GroupChat\"\n type=\"com.gsma.services.rcs.chat.ChatLog.GroupChat\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BODY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;body&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sender&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_CHAT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Direction\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"IRRELEVANT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.Message.Status.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.Content\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.Content\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BLOCKED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TO_SEND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD_REPORT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status.System\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.System\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.System\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACCEPTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BUSY\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISCONNECTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GONE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"JOINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Type\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Type\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Type\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SYSTEM\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"ChatMessage\"\n type=\"com.gsma.services.rcs.chat.ChatMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"messageId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remote\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"receiptAt\" type=\"java.util.Date\">\n</parameter>\n<parameter name=\"displayedReportRequested\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"ChatMessage\"\n type=\"com.gsma.services.rcs.chat.ChatMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getReceiptDate\"\n return=\"java.util.Date\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedReportRequested\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatFor\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.Chat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChatFor\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.GroupChat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"openSingleChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejoinGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"restartGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatServiceConfiguration\"\n type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSF\" type=\"boolean\">\n</parameter>\n<parameter name=\"chatTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"isComposingTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"maxGroupChatParticipants\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthSingleChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthGroupChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxChat\" type=\"int\">\n</parameter>\n<parameter name=\"smsFallback\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptSingleChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptGroupChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"displayedDeliveryReport\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"ChatServiceConfiguration\"\n type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMaxParticipantsNumber\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxChatSessions\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSingleChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedDeliveryReport\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGroupChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"state\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"quitConversation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChat.Direction\"\n type=\"com.gsma.services.rcs.chat.GroupChat.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CHAT_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_NOT_FOUND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CLOSED_BY_USER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatIntent\"\n type=\"com.gsma.services.rcs.chat.GroupChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"com.gsma.services.rcs.chat.IGroupChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onParticipantDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantJoined\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contactDisplayname\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantLeft\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSessionAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSessionError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSessionStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewChatListener\"\n extends=\"com.gsma.services.rcs.chat.INewChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewChatListener\"\n type=\"com.gsma.services.rcs.chat.NewChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewGroupChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onNewSingleChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contacts\"\n>\n<class name=\"ContactsProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsProvider\"\n type=\"com.gsma.services.rcs.contacts.ContactsProvider\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactsService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsService\"\n type=\"com.gsma.services.rcs.contacts.ContactsService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getJoynContact\"\n return=\"com.gsma.services.rcs.contacts.JoynContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"JoynContact\"\n type=\"com.gsma.services.rcs.contacts.JoynContact\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"registered\" type=\"boolean\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</constructor>\n<constructor name=\"JoynContact\"\n type=\"com.gsma.services.rcs.contacts.JoynContact\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ft\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransfer.Direction\"\n type=\"com.gsma.services.rcs.ft.FileTransfer.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFER_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferIntent\"\n type=\"com.gsma.services.rcs.ft.FileTransferIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ft.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.IFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferListener\"\n type=\"com.gsma.services.rcs.ft.FileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onFileTransferred\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onTransferAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onTransferError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onTransferProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onTransferStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferLog\"\n type=\"com.gsma.services.rcs.ft.FileTransferLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.ft.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransferFor\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfers\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ft.FileTransfer&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"FileTransferServiceConfiguration\"\n type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n<parameter name=\"autoAcceptMode\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"FileTransferServiceConfiguration\"\n type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewFileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.INewFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewFileTransferListener\"\n type=\"com.gsma.services.rcs.ft.NewFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewFileTransfer\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ish\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharing.Direction\"\n type=\"com.gsma.services.rcs.ish.ImageSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingIntent\"\n type=\"com.gsma.services.rcs.ish.ImageSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ish.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.IImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onImageShared\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingLog\"\n type=\"com.gsma.services.rcs.ish.ImageSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.ish.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageShares\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ish.ImageSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharingFor\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"ImageSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.INewImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.NewImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewImageSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.vsh\"\n>\n<class name=\"NewVideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.INewVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewVideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewVideoSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.vsh.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"clockRate\" type=\"int\">\n</parameter>\n<parameter name=\"frameRate\" type=\"int\">\n</parameter>\n<parameter name=\"bitRate\" type=\"int\">\n</parameter>\n<parameter name=\"width\" type=\"int\">\n</parameter>\n<parameter name=\"height\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.vsh.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayload\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoPlayerListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayerListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayerListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayerListener\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayerListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPlayerClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRenderer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRenderer\"\n type=\"com.gsma.services.rcs.vsh.VideoRenderer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoRendererListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoRendererListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRendererListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRendererListener\"\n type=\"com.gsma.services.rcs.vsh.VideoRendererListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onRendererClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.vsh.VideoRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoFormat\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharing.Direction\"\n type=\"com.gsma.services.rcs.vsh.VideoSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingIntent\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.vsh.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FORMAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;format&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingLog\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharingFor\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.VideoSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.vsh.VideoPlayer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"maxTime\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"VideoSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n</api>"
  },
  {
    "path": "SDK/releases/blackbird.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"JoynContactFormatException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynContactFormatException\"\n type=\"com.gsma.services.rcs.JoynContactFormatException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService\"\n type=\"com.gsma.services.rcs.JoynService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GSMA_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.GSMA_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.GSMA_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.GSMA_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"RCSE_BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"RCSE_HOTFIXES_1_2\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.VERSION_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.VERSION_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CONNECTION_LOST\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SERVICE_DISABLED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceConfiguration\"\n type=\"com.gsma.services.rcs.JoynServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getUserDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isServiceActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n</class>\n<class name=\"JoynServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceException\"\n type=\"com.gsma.services.rcs.JoynServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<interface name=\"JoynServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n</interface>\n<class name=\"JoynServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.JoynServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.JoynServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceRegistrationListener\"\n extends=\"com.gsma.services.rcs.IJoynServiceRegistrationListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynUtils\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynUtils\"\n type=\"com.gsma.services.rcs.JoynUtils\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getJoynClients\"\n return=\"java.util.List&lt;android.content.pm.ResolveInfo&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isJoynClientActivated\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n<parameter name=\"receiverResult\" type=\"android.content.BroadcastReceiver\">\n</parameter>\n</method>\n<method name=\"loadJoynClientSettings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"Capabilities\"\n type=\"com.gsma.services.rcs.capability.Capabilities\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"imageSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"videoSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"imSession\" type=\"boolean\">\n</parameter>\n<parameter name=\"fileTransfer\" type=\"boolean\">\n</parameter>\n<parameter name=\"geolocPush\" type=\"boolean\">\n</parameter>\n<parameter name=\"ipVoiceCall\" type=\"boolean\">\n</parameter>\n<parameter name=\"ipVideoCall\" type=\"boolean\">\n</parameter>\n<parameter name=\"extensions\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</constructor>\n<constructor name=\"Capabilities\"\n type=\"com.gsma.services.rcs.capability.Capabilities\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGeolocPushSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isIPVideoCallSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isIPVoiceCallSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"com.gsma.services.rcs.capability.ICapabilitiesListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesLog\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_geoloc_push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IP_VIDEO_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_ip_video_call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IP_VOICE_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_ip_voice_call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<field name=\"EXTENSION_BASE_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;+g.3gpp.iari-ref&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTENSION_PREFIX_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;urn%3Aurn-7%3A3gpp-application.ims.iari.rcse&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendGeoloc\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatIntent\"\n type=\"com.gsma.services.rcs.chat.ChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;message&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatListener\"\n extends=\"com.gsma.services.rcs.chat.IChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatListener\"\n type=\"com.gsma.services.rcs.chat.ChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog\"\n type=\"com.gsma.services.rcs.chat.ChatLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.GroupChat\"\n type=\"com.gsma.services.rcs.chat.ChatLog.GroupChat\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BODY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;body&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sender&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_CHAT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Direction\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"IRRELEVANT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.Message.Status.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.Content\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.Content\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BLOCKED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TO_SEND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD_REPORT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status.System\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.System\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.System\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACCEPTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BUSY\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISCONNECTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GONE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"JOINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Type\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Type\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Type\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE_TRANSFER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GEOLOC\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SYSTEM\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"ChatMessage\"\n type=\"com.gsma.services.rcs.chat.ChatMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"messageId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remote\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"receiptAt\" type=\"java.util.Date\">\n</parameter>\n<parameter name=\"displayedReportRequested\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"ChatMessage\"\n type=\"com.gsma.services.rcs.chat.ChatMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getReceiptDate\"\n return=\"java.util.Date\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedReportRequested\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatFor\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.Chat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChatFor\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.GroupChat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"openSingleChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejoinGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"restartGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatServiceConfiguration\"\n type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSF\" type=\"boolean\">\n</parameter>\n<parameter name=\"chatTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"isComposingTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"maxGroupChatParticipants\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthSingleChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthGroupChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxGroupChat\" type=\"int\">\n</parameter>\n<parameter name=\"smsFallback\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptSingleChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptGroupChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"displayedDeliveryReport\" type=\"boolean\">\n</parameter>\n<parameter name=\"maxGeolocLabelLength\" type=\"int\">\n</parameter>\n<parameter name=\"geolocExpireTime\" type=\"int\">\n</parameter>\n</constructor>\n<constructor name=\"ChatServiceConfiguration\"\n type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocExpirationTime\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocLabelMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMaxParticipantsNumber\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxGroupChats\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSingleChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isChatWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedDeliveryReport\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGroupChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"state\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Geoloc\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.chat.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.chat.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.chat.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAccuracy\"\n return=\"float\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAltitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLabel\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLatitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLongitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setAcuracy\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</method>\n<method name=\"setAltitude\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"setExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n</method>\n<method name=\"setLabel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"setLatitude\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"setLongitude\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocMessage\"\n extends=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"GeolocMessage\"\n type=\"com.gsma.services.rcs.chat.GeolocMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"messageId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remote\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<parameter name=\"receiptAt\" type=\"java.util.Date\">\n</parameter>\n<parameter name=\"imdnDisplayedRequested\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"GeolocMessage\"\n type=\"com.gsma.services.rcs.chat.GeolocMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"geolocToString\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.chat.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stringToGeoloc\"\n return=\"com.gsma.services.rcs.chat.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"str\" type=\"java.lang.String\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"quitConversation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"fileicon\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendGeoloc\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChat.Direction\"\n type=\"com.gsma.services.rcs.chat.GroupChat.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CHAT_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_NOT_FOUND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CLOSED_BY_USER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatIntent\"\n type=\"com.gsma.services.rcs.chat.GroupChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"com.gsma.services.rcs.chat.IGroupChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onParticipantDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantJoined\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contactDisplayname\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantLeft\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSessionAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSessionError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSessionStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewChatListener\"\n extends=\"com.gsma.services.rcs.chat.INewChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewChatListener\"\n type=\"com.gsma.services.rcs.chat.NewChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewGroupChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onNewSingleChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contacts\"\n>\n<class name=\"ContactsProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsProvider\"\n type=\"com.gsma.services.rcs.contacts.ContactsProvider\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IP_VIDEO_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.ip-video-call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IP_VOICE_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.ip-voice-call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactsService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsService\"\n type=\"com.gsma.services.rcs.contacts.ContactsService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getJoynContact\"\n return=\"com.gsma.services.rcs.contacts.JoynContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVCard\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"JoynContact\"\n type=\"com.gsma.services.rcs.contacts.JoynContact\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"registered\" type=\"boolean\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</constructor>\n<constructor name=\"JoynContact\"\n type=\"com.gsma.services.rcs.contacts.JoynContact\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ft\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransfer\"\n type=\"com.gsma.services.rcs.ft.FileTransfer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferIntf\" type=\"com.gsma.services.rcs.ft.IFileTransfer\">\n</parameter>\n</constructor>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileIconName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransfer.Direction\"\n type=\"com.gsma.services.rcs.ft.FileTransfer.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFER_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferIntent\"\n type=\"com.gsma.services.rcs.ft.FileTransferIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ft.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.IFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferListener\"\n type=\"com.gsma.services.rcs.ft.FileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onFileTransferred\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onTransferAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onTransferError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onTransferProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onTransferStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferLog\"\n type=\"com.gsma.services.rcs.ft.FileTransferLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.ft.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransferFor\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfers\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ft.FileTransfer&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"fileicon\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"FileTransferServiceConfiguration\"\n type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n<parameter name=\"autoAcceptMode\" type=\"boolean\">\n</parameter>\n<parameter name=\"fileIcon\" type=\"boolean\">\n</parameter>\n<parameter name=\"maxFileIconSize\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"FileTransferServiceConfiguration\"\n type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxFileIconSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isFileIconSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewFileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.INewFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewFileTransferListener\"\n type=\"com.gsma.services.rcs.ft.NewFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewFileTransfer\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.gsh\"\n>\n<class name=\"GeolocSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.chat.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharing.Direction\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingIntent\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ish.action.NEW_GEOLOC_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingListener\"\n extends=\"com.gsma.services.rcs.gsh.IGeolocSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingListener\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onGeolocShared\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingService\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewGeolocSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocSharing\"\n return=\"com.gsma.services.rcs.gsh.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeolocSharingFor\"\n return=\"com.gsma.services.rcs.gsh.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeolocSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.gsh.GeolocSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewGeolocSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\"\n return=\"com.gsma.services.rcs.gsh.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"NewGeolocSharingListener\"\n extends=\"com.gsma.services.rcs.gsh.INewGeolocSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewGeolocSharingListener\"\n type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewGeolocSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.intent\"\n>\n<class name=\"ChatIntents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ClientIntents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_CLIENT_GET_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;.client.action.GET_STATUS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_SETTINGS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_SETTINGS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CLIENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;client&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferIntents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallIntents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_IPCALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_IPCALL&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_IPCALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_IPCALL&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ipcall\"\n>\n<class name=\"AudioCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"AudioCodec\"\n type=\"com.gsma.services.rcs.ipcall.AudioCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"sampleRate\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"AudioCodec\"\n type=\"com.gsma.services.rcs.ipcall.AudioCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"compare\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n</method>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSampleRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCall\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortCall\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addVideo\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"continueCall\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getCallId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"holdCall\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isOnHold\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeVideo\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"IPCall.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCall.Direction\"\n type=\"com.gsma.services.rcs.ipcall.IPCall.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCall.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CALL_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCall.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HOLD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"8\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallIntent\"\n type=\"com.gsma.services.rcs.ipcall.IPCallIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ipcall.action.NEW_CALL&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_AUDIO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;audioEncoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CALL_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;callId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_VIDEO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;videoEncoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_VIDEO_FORMAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;videoFormat&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallListener\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallListener\"\n type=\"com.gsma.services.rcs.ipcall.IPCallListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCallAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallContinue\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onCallHeld\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallLog\"\n type=\"com.gsma.services.rcs.ipcall.IPCallLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CALL_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;call_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallPlayer\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallPlayer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallPlayer\"\n type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAudioCodec\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IIPCallPlayerListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalAudioRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalVideoRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedAudioCodecs\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedVideoCodecs\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoCodec\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"audiocodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n<parameter name=\"videocodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remoteAudioPort\" type=\"int\">\n</parameter>\n<parameter name=\"remoteVideoPort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallPlayer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallPlayerListener\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallPlayerListener\"\n type=\"com.gsma.services.rcs.ipcall.IPCallPlayerListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPlayerClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallRenderer\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallRenderer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallRenderer\"\n type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAudioCodec\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IIPCallRendererListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalVideoRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedAudioCodecs\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedVideoCodecs\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoCodec\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"audiocodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n<parameter name=\"videocodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remoteAudioPort\" type=\"int\">\n</parameter>\n<parameter name=\"remoteVideoPort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallRenderer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallRendererListener\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallRendererListener\"\n type=\"com.gsma.services.rcs.ipcall.IPCallRendererListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onRendererClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallService\"\n type=\"com.gsma.services.rcs.ipcall.IPCallService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewIPCallListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCall\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"callId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCallFor\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCalls\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IPCall&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateCall\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewIPCallListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"IPCallServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"IPCallServiceConfiguration\"\n type=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"voiceBreakout\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"IPCallServiceConfiguration\"\n type=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVoiceCallBreakout\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewIPCallListener\"\n extends=\"com.gsma.services.rcs.ipcall.INewIPCallListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewIPCallListener\"\n type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewCall\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"callId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.ipcall.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"clockRate\" type=\"int\">\n</parameter>\n<parameter name=\"frameRate\" type=\"int\">\n</parameter>\n<parameter name=\"bitRate\" type=\"int\">\n</parameter>\n<parameter name=\"width\" type=\"int\">\n</parameter>\n<parameter name=\"height\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.ipcall.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"compare\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n</method>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ish\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharing.Direction\"\n type=\"com.gsma.services.rcs.ish.ImageSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingIntent\"\n type=\"com.gsma.services.rcs.ish.ImageSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ish.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.IImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onImageShared\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingLog\"\n type=\"com.gsma.services.rcs.ish.ImageSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.ish.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharingFor\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ish.ImageSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"ImageSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.INewImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.NewImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewImageSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.vsh\"\n>\n<class name=\"NewVideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.INewVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewVideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewVideoSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.vsh.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"clockRate\" type=\"int\">\n</parameter>\n<parameter name=\"frameRate\" type=\"int\">\n</parameter>\n<parameter name=\"bitRate\" type=\"int\">\n</parameter>\n<parameter name=\"width\" type=\"int\">\n</parameter>\n<parameter name=\"height\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.vsh.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"compare\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n</method>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoPlayerListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayerListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayerListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayerListener\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayerListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPlayerClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRenderer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRenderer\"\n type=\"com.gsma.services.rcs.vsh.VideoRenderer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoRendererListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoRendererListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRendererListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRendererListener\"\n type=\"com.gsma.services.rcs.vsh.VideoRendererListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onRendererClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.vsh.VideoRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoFormat\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharing.Direction\"\n type=\"com.gsma.services.rcs.vsh.VideoSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingIntent\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.vsh.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FORMAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;format&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingLog\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharingFor\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.VideoSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.vsh.VideoPlayer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"maxTime\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"VideoSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n</api>\n"
  },
  {
    "path": "SDK/releases/current.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"Intents\"\n type=\"com.gsma.services.rcs.Intents\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Client\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_CLIENT_GET_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;.client.action.GET_STATUS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_SETTINGS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_SETTINGS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CLIENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;client&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.IPCall\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_IPCALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_IPCALL&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_IPCALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_IPCALL&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynContactFormatException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynContactFormatException\"\n type=\"com.gsma.services.rcs.JoynContactFormatException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService\"\n type=\"com.gsma.services.rcs.JoynService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getServiceVersion\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"JoynService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.VERSION_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.VERSION_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CRANE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CONNECTION_LOST\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SERVICE_DISABLED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceConfiguration\"\n type=\"com.gsma.services.rcs.JoynServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getUserDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isServiceActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n</class>\n<class name=\"JoynServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceException\"\n type=\"com.gsma.services.rcs.JoynServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<interface name=\"JoynServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n</interface>\n<class name=\"JoynServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.JoynServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.JoynServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceRegistrationListener\"\n extends=\"com.gsma.services.rcs.IJoynServiceRegistrationListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynUtils\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynUtils\"\n type=\"com.gsma.services.rcs.JoynUtils\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getJoynClients\"\n return=\"java.util.List&lt;android.content.pm.ResolveInfo&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isJoynClientActivated\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n<parameter name=\"receiverResult\" type=\"android.content.BroadcastReceiver\">\n</parameter>\n</method>\n<method name=\"loadJoynClientSettings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutomata\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGeolocPushSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isIPVideoCallSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isIPVoiceCallSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"com.gsma.services.rcs.capability.ICapabilitiesListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesLog\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_geoloc_push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IP_VIDEO_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_ip_video_call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IP_VOICE_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_ip_voice_call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<field name=\"EXTENSION_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendGeoloc\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatIntent\"\n type=\"com.gsma.services.rcs.chat.ChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;message&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatListener\"\n extends=\"com.gsma.services.rcs.chat.IChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatListener\"\n type=\"com.gsma.services.rcs.chat.ChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewGeoloc\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.GeolocMessage\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog\"\n type=\"com.gsma.services.rcs.chat.ChatLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.GroupChat\"\n type=\"com.gsma.services.rcs.chat.ChatLog.GroupChat\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BODY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;body&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sender&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_CHAT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Direction\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"IRRELEVANT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.Message.Status.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.Content\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.Content\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BLOCKED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TO_SEND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD_REPORT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status.System\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.System\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.System\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACCEPTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BUSY\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISCONNECTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GONE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"JOINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Type\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Type\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Type\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE_TRANSFER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GEOLOC\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SYSTEM\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getReceiptDate\"\n return=\"java.util.Date\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedReportRequested\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatFor\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.Chat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChatFor\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.GroupChat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"openSingleChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejoinGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"restartGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocExpirationTime\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocLabelMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMaxParticipantsNumber\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxGroupChats\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSingleChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isChatWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedDeliveryReport\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGroupChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"state\" type=\"boolean\">\n</parameter>\n</method>\n</class>\n<class name=\"Geoloc\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getAccuracy\"\n return=\"float\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAltitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLabel\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLatitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLongitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setAcuracy\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</method>\n<method name=\"setAltitude\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"setExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n</method>\n<method name=\"setLabel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"setLatitude\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"setLongitude\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n</method>\n</class>\n<class name=\"GeolocMessage\"\n extends=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"geolocToString\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.chat.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stringToGeoloc\"\n return=\"com.gsma.services.rcs.chat.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"str\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"quitConversation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"fileicon\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendGeoloc\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChat.Direction\"\n type=\"com.gsma.services.rcs.chat.GroupChat.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CHAT_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_NOT_FOUND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CLOSED_BY_USER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatIntent\"\n type=\"com.gsma.services.rcs.chat.GroupChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"com.gsma.services.rcs.chat.IGroupChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewGeoloc\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.GeolocMessage\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onParticipantDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantJoined\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contactDisplayname\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantLeft\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSessionAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSessionError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSessionStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewChatListener\"\n extends=\"com.gsma.services.rcs.chat.INewChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewChatListener\"\n type=\"com.gsma.services.rcs.chat.NewChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewGroupChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onNewSingleChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contacts\"\n>\n<class name=\"ContactsProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsProvider\"\n type=\"com.gsma.services.rcs.contacts.ContactsProvider\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IP_VIDEO_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.ip-video-call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IP_VOICE_CALL\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.ip-voice-call&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactsService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsService\"\n type=\"com.gsma.services.rcs.contacts.ContactsService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getJoynContact\"\n return=\"com.gsma.services.rcs.contacts.JoynContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVCard\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"JoynContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ft\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileIconName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"pauseTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"resumeTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransfer.Direction\"\n type=\"com.gsma.services.rcs.ft.FileTransfer.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFER_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferIntent\"\n type=\"com.gsma.services.rcs.ft.FileTransferIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ft.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.IFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferListener\"\n type=\"com.gsma.services.rcs.ft.FileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onFileTransferred\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onTransferAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onTransferError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onTransferProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onTransferStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferLog\"\n type=\"com.gsma.services.rcs.ft.FileTransferLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.ft.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransferFor\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfers\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ft.FileTransfer&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"fileicon\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getMaxFileIconSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isFileIconSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewFileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.INewFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewFileTransferListener\"\n type=\"com.gsma.services.rcs.ft.NewFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewFileTransfer\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportFileDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportFileDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.gsh\"\n>\n<class name=\"GeolocSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.chat.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharing.Direction\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingIntent\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.gsh.action.NEW_GEOLOC_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingListener\"\n extends=\"com.gsma.services.rcs.gsh.IGeolocSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingListener\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onGeolocShared\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingService\"\n type=\"com.gsma.services.rcs.gsh.GeolocSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewGeolocSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocSharing\"\n return=\"com.gsma.services.rcs.gsh.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeolocSharingFor\"\n return=\"com.gsma.services.rcs.gsh.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeolocSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.gsh.GeolocSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewGeolocSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\"\n return=\"com.gsma.services.rcs.gsh.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"NewGeolocSharingListener\"\n extends=\"com.gsma.services.rcs.gsh.INewGeolocSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewGeolocSharingListener\"\n type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewGeolocSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ipcall\"\n>\n<class name=\"AudioCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"compare\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSampleRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCall\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortCall\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addVideo\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"continueCall\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getCallId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"holdCall\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isOnHold\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isVideo\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeVideo\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"IPCall.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCall.Direction\"\n type=\"com.gsma.services.rcs.ipcall.IPCall.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCall.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CALL_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCall.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HOLD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"8\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallIntent\"\n type=\"com.gsma.services.rcs.ipcall.IPCallIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ipcall.action.NEW_CALL&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_AUDIO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;audioEncoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CALL_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;callId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_VIDEO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;videoEncoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_VIDEO_FORMAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;videoFormat&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallListener\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallListener\"\n type=\"com.gsma.services.rcs.ipcall.IPCallListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCallAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallContinue\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onCallHeld\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallRinging\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onCallStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallLog\"\n type=\"com.gsma.services.rcs.ipcall.IPCallLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CALL_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;call_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallPlayer\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallPlayer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallPlayer\"\n type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAudioCodec\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IIPCallPlayerListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalAudioRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalVideoRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedAudioCodecs\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedVideoCodecs\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoCodec\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"audiocodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n<parameter name=\"videocodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remoteAudioPort\" type=\"int\">\n</parameter>\n<parameter name=\"remoteVideoPort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallPlayer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallPlayerListener\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallPlayerListener\"\n type=\"com.gsma.services.rcs.ipcall.IPCallPlayerListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPlayerClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallRenderer\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallRenderer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallRenderer\"\n type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getAudioCodec\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IIPCallRendererListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalVideoRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedAudioCodecs\"\n return=\"com.gsma.services.rcs.ipcall.AudioCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedVideoCodecs\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoCodec\"\n return=\"com.gsma.services.rcs.ipcall.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"audiocodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n<parameter name=\"videocodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remoteAudioPort\" type=\"int\">\n</parameter>\n<parameter name=\"remoteVideoPort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallRenderer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"IPCallRendererListener\"\n extends=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallRendererListener\"\n type=\"com.gsma.services.rcs.ipcall.IPCallRendererListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onRendererClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"IPCallService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"IPCallService\"\n type=\"com.gsma.services.rcs.ipcall.IPCallService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewIPCallListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCall\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"callId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCallFor\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCalls\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IPCall&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateCall\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateVisioCall\"\n return=\"com.gsma.services.rcs.ipcall.IPCall\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewIPCallListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"IPCallServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"isVoiceCallBreakout\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewIPCallListener\"\n extends=\"com.gsma.services.rcs.ipcall.INewIPCallListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewIPCallListener\"\n type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewCall\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"callId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"compare\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n</method>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ish\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharing.Direction\"\n type=\"com.gsma.services.rcs.ish.ImageSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingIntent\"\n type=\"com.gsma.services.rcs.ish.ImageSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ish.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.IImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onImageShared\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingLog\"\n type=\"com.gsma.services.rcs.ish.ImageSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.ish.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharingFor\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ish.ImageSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.INewImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.NewImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewImageSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.session\"\n>\n<class name=\"MultimediaMessageIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaMessageIntent\"\n type=\"com.gsma.services.rcs.session.MultimediaMessageIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.session.action.NEW_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTENT_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contentType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaSession\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sdp\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.session.MultimediaSessionListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getLocalSdp\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteSdp\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.session.MultimediaSessionListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSession.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSession.Direction\"\n type=\"com.gsma.services.rcs.session.MultimediaSession.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaSession.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SESSION_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaSession.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionIntent\"\n type=\"com.gsma.services.rcs.session.MultimediaSessionIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.session.action.NEW_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaSessionListener\"\n extends=\"com.gsma.services.rcs.session.IMultimediaSessionListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionListener\"\n type=\"com.gsma.services.rcs.session.MultimediaSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onSessionAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSessionError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSessionRinging\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSessionStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSessionService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionService\"\n type=\"com.gsma.services.rcs.session.MultimediaSessionService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSession\"\n return=\"com.gsma.services.rcs.session.MultimediaSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSessionFor\"\n return=\"com.gsma.services.rcs.session.MultimediaSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.session.MultimediaSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateSession\"\n return=\"com.gsma.services.rcs.session.MultimediaSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"sdp\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.session.MultimediaSessionListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.vsh\"\n>\n<class name=\"NewVideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.INewVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewVideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewVideoSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"compare\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n</method>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoPlayerListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayerListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayerListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayerListener\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayerListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPlayerClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRenderer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRenderer\"\n type=\"com.gsma.services.rcs.vsh.VideoRenderer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoRendererListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoRendererListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRendererListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRendererListener\"\n type=\"com.gsma.services.rcs.vsh.VideoRendererListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onRendererClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.vsh.VideoRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoCodec\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharing.Direction\"\n type=\"com.gsma.services.rcs.vsh.VideoSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.Encoding\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharing.Encoding\"\n type=\"com.gsma.services.rcs.vsh.VideoSharing.Encoding\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"H264\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingIntent\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.vsh.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_HEIGHT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;height&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_WIDTH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;width&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingLog\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharingFor\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.VideoSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.vsh.VideoPlayer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n</api>\n"
  },
  {
    "path": "SDK/releases/joyn-sdk.txt",
    "content": "README - joyn SDK\n\n\nNews v3.2.3:\n------------\n\n- Update extensions with new RCS 5.2 syntax.\n- Add new MM session API (internalization of the SDP negociation and media protocol).\n- Add new methods with an URI for FT and ISh to be compliant with Android KitKat and its new storage access framework.\n- Add parameter max image share warn threshold.\n- Issue RCSJTA #20: Displayed report not sent on first message.\n\n\nNews v3.2.2:\n------------\n\n- Add automata support.\n- Split the generic method onNewMessage into 2 methods: onNewMessage and onNewGeoloc.\n- Add TIMESTAMP_SEND, TIMESTAMP_DELIVERED & TIMESTAMP_DISPLAYED in FT database.\n- Internalize threading in the server part of the API.\n- Issue RCSJTA #19: It's not possible to send a geoloc message as a first message in a 1-1 chat conversation.\n- Add method GroupChat.sendDisplayedDeliveryReport.\n- Add status DELIVERED & DISPLAYED for file transfer.\n- Add CTS tests for API (signature tests, providers tests).\n- Add a type for spam messages in chat log.\n- The type of content message is identified by its MIME type.\n\n\nNews v3.2.1:\n------------\n\n- Simplify the service ID syntax used by Capability and MM session APIs.\n\n\nNews v3.2.0:\n------------\n\n- Rename all packages to \"com.gsma.services.rcs\".\n\n\nNews v3.1.0:\n------------\n\n- Blackbird release.\n\n\nNews v3.0.2:\n------------\n\n- Bug fix on single chat (joyn servcei + RI).\n\n\nNews v3.0.1:\n------------\n\n- See complete API javadoc:\n\thttps://rcsjta.googlecode.com/git/sdk-joyn/javadoc/packages.html.\n\n- See API samples:\n\thttps://rcsjta.googlecode.com/git/sdk-joyn/samples/index.html.\n\n- See API tutorials:\n\thttps://rcsjta.googlecode.com/git/sdk-joyn/samples/index.html.\n\n\n\nBugs fixed:\n-----------\n\nConcerning the open source stack and RI application, see details at http://code.google.com/p/android-rcs-ims-stack/issues/list.\n\n\n\nContact:\n--------\nOrange Labs\njeanmarc.auffret@orange.com\n"
  },
  {
    "path": "SDK/samples/connectService.jd",
    "content": "page.title=How to connect to a joyn service\ndoc.type=samples\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>How to connect to a joyn service</h1></p>\n\t\t\t<p><span>Learn how to instantiate a joyn service, connect to it and and listen to service events.</span></p>\n\t\t\t<p><span>Here we use the Capability service API as an example, the procedure will remain the same for any other service API.</span></p>\n\t\t</div>\n\t\t\n\t\t<div class=\"content-body center\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>Instantiate a service API</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>To instantiate an API, all you need to do is to pass an Android context and a service listener as parameter when calling the API constructor. The Android context is used by the Android API binding procedure. The listener is used to monitor the API connection events (JoynServiceListener).</p>\t\t\t\t\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<!--Generated HTML from java using Java2Html Converter -->\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Instanciate API<br />\n\t\t\t\t\t\t</span><span class=\"java10\">capabilityApi = </span><span class=\"java4\">new </span><span class=\"java10\">CapabilityService</span><span class=\"java8\">(</span><span class=\"java10\">getApplicationContext</span><span class=\"java8\">()</span><span class=\"java10\">, </span><span class=\"java4\">new </span><span class=\"java10\">MyEventListener </span><span class=\"java8\">())</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java4\">public class </span><span class=\"java10\">MyEventListener </span><span class=\"java4\">implements </span><span class=\"java10\">JoynServiceListener </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t}</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>Connect to the service API</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>After having instanciated the service Api, you should connect to it :</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\t\t\t\t\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Connect API<br />\n\t\t\t\t\t\t</span><span class=\"java10\">capabilityApi.connect</span><span class=\"java8\">()</span><span class=\"java10\">;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\t\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t\t<p>The API connection procedure is asynchronous and the connection result is given via callback events : The callback event onServiceConnected() means that the API binding was successful and methods may be called on the API.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\t\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>Disconnect from the service API</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>When you have no more need on the API don’t forget to disconnect from it :</p>\t\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\t\t\t\t\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Disconnect API<br />\n\t\t\t\t\t\t</span><span class=\"java10\">capabilityApi.disconnect</span><span class=\"java8\">()</span><span class=\"java10\">;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\t\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>Monitor API connection events</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/JoynServiceListener.html\">JoynServiceListener</a> contains 2 methods that allows you to monitor the API connection state :</p>\t\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\t\t\t\t\n\t\t\t\t\t<tt class=\"java\"><span class=\"java4\">public class </span><span class=\"java10\">MyEventListener </span><span class=\"java4\">implements </span><span class=\"java10\">JoynServiceListener </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java9\">void </span><span class=\"java10\">onServiceConnected</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java9\">void </span><span class=\"java10\">onServiceDisconnected</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t}</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t</br>\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/samples/detectServices.jd",
    "content": "page.title=Detect if joyn service is started\ndoc.type=samples\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>How to detect if the joyn service is started</h1></p>\n\t\t\t<p><span>Sometimes it’s useful to know if the joyn service is running or not in order to enable/disable views in the UI part of the application (e.g. a menu).</span></p>\t\t\t\n\t\t\t<p><span>The joyn API offers utility methods to get the current state of the joyn service from the class JoynServiceConfiguration:</span></p><p><span></span></p>\n\t\t\t<div class=\"code-block\">\n\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Get joyn service activation state<br />\n\t\t\t\t\t</span><span class=\"java9\">boolean </span><span class=\"java10\">activated = JoynServiceConfiguration.isServiceActivated</span><span class=\"java8\">(</span><span class=\"java10\">getApplicationContext</span><span class=\"java8\">())</span><span class=\"java10\">;</span>\n\t\t\t\t</tt>\n\t\t\t</div>\n\t\t\t<p><span></span></p>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/samples/index.jd",
    "content": "page.title=Samples\ndoc.type=samples\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Source code samples</h1></p>\n\t\t\t<p><span>Our different samples will show you how to perform specific tasks using joyn APIs.</span></p>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<ul class=\"list clickable\">\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span class=\"api-list-ver\">Albatros</span>\n\t\t\t\t\t\t<a href=\"{@docRoot}samples/connectService.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>How to connect to a joyn service</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>Lean how to instantiate a joyn service, connect to it and register listeners for receiving callback events.</p>\n\t\t\t\t\t</div>\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span class=\"api-list-ver\">Albatros</span>\n\t\t\t\t\t\t<a href=\"{@docRoot}samples/initChat.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>How to initialise a chat</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>Learn how to use the chat service.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span class=\"api-list-ver\">Albatros</span>\n\t\t\t\t\t\t<a href=\"{@docRoot}samples/listContacts.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>How to get online contacts</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>Shows you how to get contacts who are online and reachable via joyn services.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span class=\"api-list-ver\">Albatros</span>\n\t\t\t\t\t\t<a href=\"{@docRoot}samples/serviceSupported.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>How to get joyn contacts supporting a given service</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>Shows you how to get contacts who support a specific service.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<span class=\"api-list-ver\">Albatros</span>\n\t\t\t\t\t\t<a href=\"{@docRoot}samples/detectServices.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>How to detect if the joyn service is started</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>Shows you how to check if the joyn service is started or not on your device.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t\t\n\t</div>\n</div>"
  },
  {
    "path": "SDK/samples/initChat.jd",
    "content": "page.title=How to initialise a chat\ndoc.type=samples\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>How to initialise a chat</h1></p>\n\t\t\t<p><span>The <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/ChatService.html\" >Chat service API</a> offers all the features in order to manage single chat conversations and group chat conferences between joyn contacts.</span></p>\n\t\t\t<p><span>To initiate a chat conversation see the following steps :</span></p>\n\t\t\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>1. Connect to the chat service API</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>See <a href=\"{@docRoot}samples/connectService.html\">How to connect to a joyn service</a>.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>2. Check if the service is connected to the joyn platform</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Before initiating a chat you should check if the service platform is properly available : use the method <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/ChatService.html#isServiceRegistered()\">isServiceRegistered</a> from the service API in order to get the last registration state which indicates if the device is registered on the joyn platform.</p>\n\t\t\t\t<p>If the joyn platform is not available you can redirect the end user to classic services like SMS/MMS.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>3. Identify contacts supporting the chat service</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>All joyn contacts support the chat service because this is a mandatory service. So it’s not necessary to check the capabilities.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>4. Initiate a single chat conversation</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>To initiate a chat conversation you just need to use the method <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/ChatService.html#openSingleChat(java.lang.String, com.gsma.services.rcs.chat.ChatListener)\">openSingleChat</a> from the API, by passing the remote contact (ie. phone number) as parameter and also a listener on the chat events. The method will return a <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/Chat.html\">Chat</a> object of the corresponding conversation.. The chat session is really established after sending a first message.</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Open chat<br />\n\t\t\t\t\t\t</span><span class=\"java10\">Chat chat = chatApi.openSingleChat</span><span class=\"java8\">(</span><span class=\"java10\">contact, chatListener</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java10\">chat.sendMessage(\"Bla bla bla\");</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java14\">/**<br />\n\t\t\t\t\t\t * Chat event listener<br />\n\t\t\t\t\t\t */<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private class </span><span class=\"java10\">MyChatListener </span><span class=\"java4\">extends </span><span class=\"java10\">ChatListener </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java3\">// Callback called when a new message has been received<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onNewMessage</span><span class=\"java8\">(</span><span class=\"java4\">final </span><span class=\"java10\">ChatMessage message</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java3\">// Callback called when a new geoloc has been received<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onNewGeoloc</span><span class=\"java8\">(</span><span class=\"java4\">final </span><span class=\"java10\">GeolocMessage message</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java3\">// Callback called when a message has been delivered to the remote<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onReportMessageDelivered</span><span class=\"java8\">(</span><span class=\"java10\">String msgId</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java3\">// Callback called when a message has been displayed by the remote<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onReportMessageDisplayed</span><span class=\"java8\">(</span><span class=\"java10\">String msgId</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java3\">// Callback called when a message has failed to be delivered to the remote<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onReportMessageFailed</span><span class=\"java8\">(</span><span class=\"java10\">String msgId</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java3\">// Callback called when an Is-composing event has been received<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onComposingEvent</span><span class=\"java8\">(</span><span class=\"java4\">final </span><span class=\"java9\">boolean </span><span class=\"java10\">status</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; }<br />\n\t\t\t\t\t\t}<br />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>When leaving the chat conversation you should remove the listeners:</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Remove listener<br />\n\t\t\t\t\t\t</span><span class=\"java4\">if </span><span class=\"java8\">(</span><span class=\"java10\">chat != </span><span class=\"java4\">null</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java10\">chat.removeEventListener</span><span class=\"java8\">(</span><span class=\"java10\">chatListener</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>In the terminating side, a new chat conversation is received via an Intent :</p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;receiver android:name=</span><span class=\"java5\">&#34;.messaging.chat.SingleChatInvitationReceiver&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.chat.action.NEW_CHAT&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt;<br />\n\t\t\t\t\t\t&lt;/receiver&gt;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Then like on the originating side, you just have to use the method <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/ChatService.html#openSingleChat(java.lang.String, com.gsma.services.rcs.chat.ChatListener)\">openSingleChat</a> from the API to get a <a href=\"{@docRoot}javadoc/javadoc/com/gsma/services/rcs/chat/Chat.html\">Chat</a> object of the corresponding conversation.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/samples/listContacts.jd",
    "content": "page.title=Get online contacts\ndoc.type=samples\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>How to get online joyn contacts</h1></p>\n\t\t\t<p><span>Most of the time before using a service with a contact, we need to know if the contact is available in order to interact with him immediately. This is the main concept of joyn : <b>the possibility to know if a contact is online before initiating a rich communication</b>.</span></p>\n\t\t\t<p><span>The Contacts API offers a method to get the list of online contacts. Online contacts are contacts who are actually connected to the joyn platform. Then for each contact of the list we also have its supported capabilities :</span></p>\n\t\t\t<div class=\"code-block\">\n\t\t\t\t<tt class=\"java\"><span class=\"java10\">Set&lt;JoynContact&gt; onlineContacts = contactsApi.getJoynContactsOnline</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\tList&lt;JoynContact&gt; contacts = </span><span class=\"java4\">new </span><span class=\"java10\">ArrayList&lt;JoynContact&gt;</span><span class=\"java8\">(</span><span class=\"java10\">onlineContacts</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t</span><span class=\"java4\">if </span><span class=\"java8\">(</span><span class=\"java10\">contacts.size</span><span class=\"java8\">() </span><span class=\"java10\">&gt; </span><span class=\"java7\">0</span><span class=\"java8\">){<br />\n\t\t\t\t\t&#xA0; </span><span class=\"java4\">for </span><span class=\"java8\">(</span><span class=\"java9\">int </span><span class=\"java10\">i = </span><span class=\"java7\">0</span><span class=\"java10\">; i &lt; contacts.size</span><span class=\"java8\">()</span><span class=\"java10\">; i++</span><span class=\"java8\">) {<br />\n\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">JoynContact contact = contacts.get</span><span class=\"java8\">(</span><span class=\"java10\">i</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t&#xA0;&#xA0;&#xA0; Capabilities capabilities = contact.getCapabilities</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t&#xA0;&#xA0;&#xA0; ...<br />\n\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t}</span>\n\t\t\t\t</tt>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/samples/serviceSupported.jd",
    "content": "page.title=How to get joyn contacts supporting a given service\ndoc.type=samples\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>How to get joyn contacts supporting a given service</h1></p>\n\t\t\t<p><span>Most of the time before using a service with a contact, we need to know if the contact supports the requested service. This is a main concept of joyn : <b>the possibility to discover the services supported by a contact before using it</b>.</span></p>\n\t\t\t<p><span>The Contacts API offers a method to get the list of contacts supporting a given service or capability:</span></p>\n\t\t\t<div class=\"code-block\">\n\t\t\t\t<tt class=\"java\"><span class=\"java10\">String tag = </span><span class=\"java5\">&#34;&lt;your service ID here&gt;&#34; </span><span class=\"java10\">;<br />\n\t\t\t\t\tSet&lt;JoynContact&gt; supportedContacts = contactsApi.getJoynContactsSupporting</span><span class=\"java8\">(</span><span class=\"java10\">tag</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\tList&lt;JoynContact&gt; contacts = </span><span class=\"java4\">new </span><span class=\"java10\">ArrayList&lt;JoynContact&gt;</span><span class=\"java8\">(</span><span class=\"java10\">supportedContacts</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t</span><span class=\"java4\">if </span><span class=\"java8\">(</span><span class=\"java10\">contacts.size</span><span class=\"java8\">() </span><span class=\"java10\">&gt; </span><span class=\"java7\">0</span><span class=\"java8\">){<br />\n\t\t\t\t\t&#xA0; </span><span class=\"java4\">for </span><span class=\"java8\">(</span><span class=\"java9\">int </span><span class=\"java10\">i = </span><span class=\"java7\">0</span><span class=\"java10\">; i &lt; contacts.size</span><span class=\"java8\">()</span><span class=\"java10\">; i++</span><span class=\"java8\">) {<br />\n\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">JoynContact contact = contacts.get</span><span class=\"java8\">(</span><span class=\"java10\">i</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t&#xA0;&#xA0;&#xA0; ...<br />\n\t\t\t\t\t&#xA0;&#xA0;&#xA0; ...<br />\n\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t}</span>\n\t\t\t\t</tt>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/support.jd",
    "content": "page.title=Support\ndoc.type=faq\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Support</h1></p>\n\t\t\t<p><span><h2>Report a Bug</h2></span></p>\n\t\t\t<p><span>Use the <a target=\"_blank\" href=\"https://code.google.com/p/rcsjta/issues/list\">online tracker</a> to report a bug or to find a bug related to the joyn API.</span></p>\n\t\t\t<p><span><h2>Ask for Help</h2></span></p>\n\t\t\t<p><span>If the online tracker is not sufficient and if you have any questions related to the joyn API don't hesitate to <a href=\"mailto:jeanmarc.auffret@orange.com\">contact</a> us.</span></p>\n\t\t</div> \n\t</div> \n</div> "
  },
  {
    "path": "SDK/tools/getToKnow.jd",
    "content": "page.title=Get to know joyn services via the RI application\ndoc.type=tools\n@jd:body\n<div class=\"background-sdk\">\n<script type=\"text/javascript\">\n    $('.slideshow-container').dacSlideshow({\n        auto: true,\n        btnPrev: '.slideshow-prev',\n        btnNext: '.slideshow-next'\n    });\n    </script>\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Get to know joyn services via the RI application</h1></p>\n\t\t\t<p><span>The RI application will help you get a quick view of the different functionalities joyn APIs offer.</span></p>\n\t\t\t<p><span>The RI application uses the joyn APIs and offers a basic UI to test the joyn features.</span></p>\n\t\t\t<p><span>To install the RI, connect your device via USB. Make sure that USB debugging is active. Then use the following command:</span></p>\n\t\t\t<p><span><code style=\"background-color:#e1e1e1;\">adb install &lt;SDK&gt;\\tools\\joyn-RI.apk</code></span> </p>\n\t\t</div>\n\t\t\n\t\t<div class=\"content-body center\">\n\t\t\t<div id=\"mycarousel\" class=\"jcarousel-skin-tango\">\t\n\t\t\t\t<div class=\"jcarousel-control\" >\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn left\" id=\"1\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"2\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"3\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"4\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"5\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"6\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"7\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn\" id=\"8\"><div></div></a>\n\t\t\t\t\t<a href=\"#\" class=\"slide-btn right\" id=\"9\"><div></div></a>\n\t\t\t\t\t<ul >\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_home.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Home View</h1>\n\t\t\t\t\t\t\t\t<p>Choose among the different features to try out joyn services.</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_contacts.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Contacts</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/contacts/package-summary.html\">Contacts API</a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_capabilities.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Capabilities</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/capability/package-summary.html\">Capability API</a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_chat.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Chat</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/package-summary.html\">Chat API</a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_ft.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>File Transfer</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/ft/package-summary.html\">File transfer API</a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_ish.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Image Sharing</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/ish/package-summary.html\">Image sharing API </a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_vsh.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Video Sharing</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/vsh/package-summary.html\">Video sharing API</a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_multi.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Multimedia Session</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">MultiMedia session API </a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li >\n\t\t\t\t\t\t\t<div class=\"content-left\" >\n\t\t\t\t\t\t\t\t<img width=\"100%\" src=\"{@docRoot}assets-sdk/images/RI_intents.png\">\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"content-right\">\n\t\t\t\t\t\t\t\t<h1>Intents</h1>\n\t\t\t\t\t\t\t\t<p><a href=\"{@docRoot}javadoc/com/gsma/services/rcs/Intents.html\">Intents API</a></p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t</br>\n\t\t</div>\t\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tools/index.jd",
    "content": "page.title=Tools\ndoc.type=tools\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Tools</h1></p>\n\t\t\t<p><span>This section regroups a number of specific tools that can help you with your application development.</span></p>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<ul class=\"list clickable\">\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<a href=\"{@docRoot}tools/installJoynServices.html\"><span class=\"item-link\"></span><h2 >Standalone joyn service</h2></a>\n\t\t\t\t\t\t<p>If your device is not natively joyn compliant, you should deploy a standalone joyn service on your device before using the joyn APIs from applications.</p>\n\t\t\t\t\t\t<p>You will find a step by step explanation on how to accomplish this in our dedicated <a style=\"text-decoration:underline;z-index:2;position:relative;\" href=\"{@docRoot}tools/installJoynServices.html\">guide</a>.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<a href=\"{@docRoot}tools/getToKnow.html\"><span class=\"item-link\"></span><h2>Reference Implementation (RI)</h2></a>\n\t\t\t\t\t\t<p>The Reference Implementation is an application with a very basic UI which allows you to test the joyn features (chat, file transfer, sharing) step by step. See also the source code of the RI <a target=\"_blank\" style=\"text-decoration:underline;z-index:2;position:relative;\" href=\"https://code.google.com/p/rcsjta/source/browse/#git%2FRI\">here</a>.</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t\t\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tools/installJoynServices.jd",
    "content": "page.title=Install joyn standalone service\ndoc.type=tools\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Install and configure joyn standalone service</h1></p>\n\t\t\t<p><span>Some devices the are not yet joyn compliant, so it is necessary to instal a standalone joyn service on your device before using the joyn APIs on your application. The joyn SDK provides a joyn-service test application. Once these services are configured appropriately, your application will be able to communicate via joyn APIs and joyn network.</span></p>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t\t<p><h2>1. Install the standalone joyn service on your device</h2></p>\t\t\t\t\t\t\t\t\n\t\t\t\t\t<p>To install the application, connect your device via USB. Make sure that USB debugging is active.</p>\n\t\t\t\t\t<p>Then use the following command:</p>\n\t\t\t\t\t<p><code style=\"background-color:#e1e1e1;\">adb install &lt;SDK&gt;\\tools\\joyn-core.apk</code> </p>\n\t\t\t\t\t<p>Get more information on the adb tool <a href=\"http://developer.android.com/tools/help/adb.html\" target=\"_blank\">here</a></p>\n\t\t\t\t\t<p>Once joyn-core.apk installed, there will be two new applications present on your device:</p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p>The joyn service, an Android background service delivering the joyn service.</p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<p>The joyn provisioning tool which allows you to configure your joyn service and end user profile.</p>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<p><h2>2. Configure the joyn service</h2></p>\n\t\t\t\t<p>There are 2 ways of provisioning your joyn client: Automatic and Manual. By default the manual provisioning is activated.\n\t\t\t\t<p><h3>Automatic provisioning</h3></p>\n\t\t\t\t<div style=\"width:100%;display:inline-block;margin-bottom:15px\">\n\t\t\t\t\t<div style=\"width:60%;float:right;margin:75px 5% 0 0\">\n\t\t\t\t\t\t<p>First open the application named <b>Provisioning</b> and go to the second tab named <b>Stack</b>.</p>\n\t\t\t\t\t\t<p>Select <b>HTTPS</b> as <b>Auto config mode</b> option and press <b>Save</b>.</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"img-ssh\">\n\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_ss_prov.png\" width=\"100%\"  />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<p>Then restart the joyn service (see step 3).</p>\n\t\t\t\t</br>\n\t\t\t\t<p><h3>Manual provisioning</h3></b></p>\n\t\t\t\t<p>Return to <b>Provisioning</b> application and go to the second tab named <b>Stack</b>.</p>\n\t\t\t\t<p>Select <b>none</b> as <b>Auto config mode</b> option and press <b>Save</b>.</p>\n\t\t\t\t<div style=\"width:100%;display:inline-block;margin-bottom:15px\">\n\t\t\t\t\t<div style=\"width:60%;float:right;margin:75px 5% 0 0\">\n\t\t\t\t\t\t<p>Now go to the first tab named <b>Profile</b>.</p>\n\t\t\t\t\t\t<p>Press <b>Generate profile</b>.</p>\n\t\t\t\t\t\t<p>Fill-in the form as asked by entering your phone number, then by selecting the joyn platform you are <b>supposed</b> to connect to.</p>\n\t\t\t\t\t\t<p>Press <b>OK</b> and press <b>Save</b> to validate your config.</p>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"img-ssh\">\n\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_ss_prov2.png\" width=\"100%\"  />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<p>Then restart the joyn service (see step 3).</p>\t\t\t\t\n\t\t\t\t</br>\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<p><h2>3. Start the joyn service</h2></p>\n\t\t\t\t<div style=\"width:100%;display:inline-block;\">\n\t\t\t\t\t<div class=\"img-ssh\" style=\"float:right;\">\n\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_ss_settings.png\" width=\"100%\"  />\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"width:60%;float:left;margin:75px 5% 0 0\">\n\t\t\t\t\t\t<p>The joyn service is started automatically at device boot or via its settings Activity: see checkbox \"joyn Service\".</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t</br>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<p><h2>4. Debugging</h2></p>\n\t\t\t\t<div style=\"width:100%;display:inline-block;\">\n\t\t\t\t\t<p>The internal traces of the joyn service may be activated from the <b>Provisioning application</b> via the <b>Logger</b> tab:</p>\n\t\t\t\t\t<p></p>\n\t\t\t\t\t<div style=\"width:200px;margin:auto;\">\n\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_ss_logger.png\" width=\"100%\"  />\n\t\t\t\t\t</div>\n\t\t\t\t\t<p></p>\n\t\t\t\t\t<p>The option <b>Application traces</b> and <b>Trace level</b> allows one to generate logcat traces on the Device: joyn traces always starts with the following prefix “<b>[RCS]</b>”.</p>\n\t\t\t\t\t<p>You can also activate <b>SIP traces</b> which are sent to SDTOUT and also stored into a file on the SDCARD.</p>\n\t\t\t\t\t<p>You can also activate <b>Media traces</b> which are sent to SDTOUT. Media traces only concerns MSRP protocol.</p>\n\t\t\t\t\t<p>For SDTOUT traces, you can create a filter with DDMS tool: </p>\n\t\t\t\t\t<p></p>\n\t\t\t\t\t<div style=\"width:450px;margin:auto;\">\n\t\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tuto_ss_logfilter.png\" width=\"100%\"  />\n\t\t\t\t\t</div>\n\t\t\t\t\t<p></p>\n\t\t\t\t</div>\n\t\t\t\t</br>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t\t\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tutorials/index.jd",
    "content": "page.title=Tutorials\ndoc.type=tutorials\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Tutorials</h1></p>\n\t\t\t<p><span>Step-by-step explanations helping you master joyn APIs with complete and runnable applications.</span></p>\t\t\n\t\t\t<p><span>Before starting our tutorials, make sure you are familiar with joyn <a href=\"{@docRoot}concepts.html\">concepts</a> and don't be afraid to check out our <a href=\"{@docRoot}getStarted.html\">Get Started</a> page. See also the API <a href=\"{@docRoot}javadoc/index.html\">Javadoc</a>.</span></p>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<ul class=\"list clickable\">\n\t\t\t\t<li>\t\t\t\t\t\n\t\t\t\t\t<div class=\"ok\">\n\t\t\t\t\t\t<a href=\"{@docRoot}tutorials/ttsApp.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>Text to speech application</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>This tutorial demonstrates how to build a Text-To-Speech (TTS) application around the joyn chat service. This service permits to play a TTS synthesis on each received chat message.</p>\n\t\t\t\t\t</div>\t\t\t\t\t\t\n\t\t\t\t</li>\n\t\t\t\t<li>\t\t\t\t\t\n\t\t\t\t\t<div class=\"easy\">\n\t\t\t\t\t\t<a href=\"{@docRoot}tutorials/multiCapability.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>New multimedia capability</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>This tutorial shows you how to create a new capacity extension enabling you to declare a new supported service for your device.</p>\n\t\t\t\t\t</div>\t\t\t\t\t\t\n\t\t\t\t</li>\n\t\t\t\t<li>\t\t\t\t\t\n\t\t\t\t\t<div class=\"easy\">\n\t\t\t\t\t\t<a href=\"{@docRoot}tutorials/popUpApp.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>Popup application</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>This tutorial demonstrates how to build a new multimedia application based on the joyn technology.</p>\n\t\t\t\t\t\t<p>The idea of the Popup application is to offer a service which allows one to send animated popups to remote joyn contacts having the same application installed on their devices.</p>\n\t\t\t\t\t</div>\t\t\t\t\t\t\n\t\t\t\t</li>\n\t\t\t\t\n\t\t\t\t<li>\t\t\t\t\t\n\t\t\t\t\t<div class=\"hard\">\n\t\t\t\t\t\t<a href=\"{@docRoot}tutorials/multiApp.html\"><span class=\"item-link\"></span>\n\t\t\t\t\t\t\t<h2>New multimedia application</h2>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t\t<p>This tutorial demonstrates how to create a new multimedia service based on the joyn technology. Here the proposed application exchanges text in real-time via a mobile-to-mobile TCP connection.</p>\n\t\t\t\t\t</div>\t\t\t\t\t\t\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t\t\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tutorials/multiApp.jd",
    "content": "page.title=New multimedia application\ndoc.type=tutorials\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\">\n\t\t<div class=\"intro center\" >\n\t\t\t<p><h1>New multimedia application</h1></p>\n\t\t\t<p><span>This tutorial demonstrates how to build a new multimedia application based on the joyn technology.</span></p>\n\t\t\t<p><span>The multimedia application implements a conversational mobile-to-mobile service which permits to exchange data in real time. A multimedia session is established between the two endpoints by using the joyn platform, then the media is exchanged via the MSRP protocol (real time messaging protocol to exchange any media data). It’s up to the application to define the media content exchanged in real time via the MSRP protocol, the joyn API just hides the complexity of the multimedia session (ie. SIP, SDP and MSRP protocols).</span></p>\n\t\t\t<p><span>This tutorial shows how to exchange text in real time.</span></p>\n\t\t\t<p><span>This demonstrated application uses the <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session</a> API to initiate and to manage multimedia sessions (accept, reject, terminate). This API may also be combined with the Capability API to discover the new service accross contacts and to offer a complete end-to-end solution.</span></p>\n\t\t\t<p><span>The Multimedia Session API implements the following call flows:</span></p>\n\t\t\t<p><span><b>Originating side :</b></span></p>\n\t\t\t<p></p>\n\t\t\t<div style=\"width:700px;margin:auto;\">\n\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/multi_sample_1.png\" width=\"100%\"/>\n\t\t\t</div>\n\t\t\t<p></p>\n\t\t\t<p><span><b>Terminating side :</b></span></p>\n\t\t\t<p></p>\n\t\t\t<div style=\"width:700px;margin:auto;\">\n\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/multi_sample_2.png\" width=\"100%\"/>\n\t\t\t</div>\n\t\t\t<p></p>\n\t\t\t</br>\n\t\t\t<h1>How to implement a new multimedia service?</h1>\n\t\t</div>\n\t\t<div class=\"content-body center\" style=\"min-height:700px;\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>1. Define a service ID associated to your new application or service</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>A unique service ID should be associated to your application, this ID is used to route the incoming request internally in the API and may be used by the joyn platform for billing and routing.</p>\n\t\t\t\t<p>The service ID corresponds also to a capability (or extension) associated to your application (see <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/capability/package-summary.html\">Capability</a> API).</p>\t\t\t\t\t\t\n\t\t\t\t<p>Here the chosen service ID is \"ext.texto\".</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>2. Implement the sender side (see class InitiateMultimediaSession)</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>The session is initiated to a remote contact with the service ID.</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// MM session<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private </span><span class=\"java10\">MultimediaSession session = </span><span class=\"java4\">null</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// MM session listener<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private </span><span class=\"java10\">MySessionListener sessionListener = </span><span class=\"java4\">new </span><span class=\"java10\">MySessionListener</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\n\t\t\t\t\t\t</span><span class=\"java3\">// Initiate session<br />\n\t\t\t\t\t\t</span><span class=\"java10\">session = sessionApi.initiateSession</span><span class=\"java8\">(</span><span class=\"java10\">serviceId, contact, sessionListener</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t...<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Session event listener<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private class </span><span class=\"java10\">MySessionListener </span><span class=\"java4\">extends </span><span class=\"java10\">MultimediaSessionListener </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session ringing<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionRinging</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session started<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionStarted</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java5\">&lt; you can exchange data from now &gt;<br /><br>\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java3\">// Send data<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">byte[] data;<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">session.sendMessage</span><span class=\"java8\">(</span><span class=\"java10\">data</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\t\t\t\t\t\t\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session aborted<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionAborted</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session error<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionError</span><span class=\"java8\">(</span><span class=\"java4\">final </span><span class=\"java9\">int </span><span class=\"java10\">error</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Receive data<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onNewMessage</span><span class=\"java8\">(</span><span class=\"java9\">byte[] </span><span class=\"java10\">content</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java5\">&lt; you receive your data here &gt;<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t}</span><span class=\"java10\">;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>3. Implement the receiver side (see class MultimediaSessionInvitationReceiver)</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Defines an Intent receiver to catch the incoming multimedia session invitation. The Intent should have a MIME type having the following syntax: \"com.gsma.services.rcs&#47;ext.texto\",</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;receiver android:name=</span><span class=\"java5\">&#34;.session.MultimediaSessionInvitationReceiver&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.session.action.NEW_SESSION&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;data android:mimeType=</span><span class=\"java5\">&#34;com.gsma.services.rcs/ext.texto&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;category android:name=</span><span class=\"java5\">&#34;android.intent.category.LAUNCHER&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;category android:name=</span><span class=\"java5\">&#34;android.intent.category.DEFAULT&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt;<br />\n\t\t\t\t\t\t&lt;/receiver&gt;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Then the Intent receiver gets the session instance from its session ID found in the incoming Intent :</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// MM session<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private </span><span class=\"java10\">MultimediaSession session = </span><span class=\"java4\">null</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// MM session listener<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private </span><span class=\"java10\">MySessionListener sessionListener = </span><span class=\"java4\">new </span><span class=\"java10\">MySessionListener</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t...<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Get session ID<br />\n\t\t\t\t\t\t</span><span class=\"java10\">String sessionId = invitation.getStringExtra</span><span class=\"java8\">(</span><span class=\"java10\">MultimediaSessionIntent.EXTRA_SESSION_ID</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Get the session<br />\n\t\t\t\t\t\t</span><span class=\"java10\">session = sessionApi.getSession</span><span class=\"java8\">(</span><span class=\"java10\">sessionId</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Add session event listener<br />\n\t\t\t\t\t\t</span><span class=\"java10\">session.addEventListener</span><span class=\"java8\">(</span><span class=\"java10\">sessionListener</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Accept the invitation<br />\n\t\t\t\t\t\t</span><span class=\"java10\">session.acceptInvitation</span><span class=\"java8\">(</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t...<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Session event listener<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private class </span><span class=\"java10\">MySessionListener </span><span class=\"java4\">extends </span><span class=\"java10\">MultimediaSessionListener </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session ringing<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionRinging</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session started<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionStarted</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java5\">&lt; you can exchange data from now &gt;<br /><br>\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java3\">// Send data<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">byte[] data;<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">session.sendMessage</span><span class=\"java8\">(</span><span class=\"java10\">data</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\t\t\t\t\t\t\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session aborted<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionAborted</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Session error<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onSessionError</span><span class=\"java8\">(</span><span class=\"java4\">final </span><span class=\"java9\">int </span><span class=\"java10\">error</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Receive data<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onNewMessage</span><span class=\"java8\">(</span><span class=\"java9\">byte[] </span><span class=\"java10\">content</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; </span><span class=\"java5\">&lt; you receive your data here &gt;<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t}</span><span class=\"java10\">;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>See the complete source code of the application <a href=\"https://code.google.com/p/rcsjta/source/browse/#git%2Fsamples%2Fsession\" target=\"_blank\">here</a>.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tutorials/multiCapability.jd",
    "content": "page.title=New multimedia Capability\ndoc.type=tutorials\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\" style=\"min-height:700px;\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>New Multimedia capability or capacity extension</h1></p>\n\t\t\t<p><span>Capacity extensions enable you to declare new capabilities for your applications. This concept allows to extend dynamically the joyn services.</span></p>\t\t\t\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>1. Creating a new capability</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>A capacity extension is just an identifier helping similar applications recognise same capabilities and allowing them to communicate with each other.</p>\n\t\t\t\t<p>The new capability is just declared in the Manifest file of the application and that's it. Then when the application is installed on the device, the joyn service in background will detect it and will automatically share this new capability with joyn contacts of your Address Book.</p>\t\t\t\t\t\t\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;activity android:name=</span><span class=\"java5\">&#34;.MyApp&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.capability.EXTENSION&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;data android:mimeType=</span><span class=\"java5\">&#34;com.gsma.services.rcs/your_new_extension&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt; <br />\n\t\t\t\t\t\t&lt;/activity&gt;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>An extension may have two different syntaxes (case sensitive):</p>\n\t\t\t\t<ul>\n\t\t\t\t<p><li> For a third-party service, the extension should start with the prefix \"ext.\" followed by the unique service ID:</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;activity android:name=</span><span class=\"java5\">&#34;.MyApp&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.capability.EXTENSION&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;data android:mimeType=</span><span class=\"java5\">&#34;com.gsma.services.rcs/ext.your_service_id&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt; <br />\n\t\t\t\t\t\t&lt;/activity&gt;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t\t<p><li> For a service provider service, the extension should start with the prefix \"mnc&#60mnc&#62.mcc&#60mcc&#62.\" followed by the unique service ID, where &#60mnc&#62 is the Mobile Network Code and where &#60mcc&#62 is the Mobile Country Code:</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;activity android:name=</span><span class=\"java5\">&#34;.MyApp&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.capability.EXTENSION&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;data android:mimeType=</span><span class=\"java5\">&#34;com.gsma.services.rcs/mnc01.mcc208.your_service_id&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt; <br />\n\t\t\t\t\t\t&lt;/activity&gt;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>2. Using your new capability</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>To get an idea of what you can do with capacity extensions, have a look at the <a href=\"{@docRoot}tutorials/popUpApp.html\">Popup application tutorial</a>. This tutorial will take you through the process of creating an application with a new extension.</p>\t\t\t\t\t\t\n\t\t\t\t<p>The important thing to remember is that the extension is just an identifier. It identifies your application's capabilities, but also identifies incoming and outgoing SIP messages to be rooted internally in the device and also in the joyn network.</p>\n\t\t\t\t<p>Then it is up to you to choose a media protocol, format and contents used for your new service.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tutorials/popUpApp.jd",
    "content": "page.title=Popup application\ndoc.type=tutorials\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Popup application</h1></p>\n\t\t\t<p><span>This tutorial demonstrates how to build a new multimedia application based on the joyn technology.</span></p>\n\t\t\t<p><span>The idea of the Popup application is to offer a service which allows one to send animated popups to remote joyn contacts who also have the same application on their devices.</span></p>\n\t\t\t<p><span>A Popup is composed of a text message, an over-the-top picture and an animation used to display the picture in over-the-top.</span></p>\n\t\t\t<p><span>The application offers several harcoded Popups. A Text-To-Speech synthesis may also be requested on the remote device to play the text message.</span></p>\n\t\t\t<div style=\"width:440px;height:350px;margin:auto;\">\n\t\t\t\t<div style=\"height:350px;float:left\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/popup_sample_1.png\" height=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"height:350px;float:right\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/popup_sample_2.png\" height=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<p></p>\n\t\t\t<p><span>See the following video from the last Mobile World Congress (2012):</span></p>\n\t\t\t</br>\n\t\t\t<div style=\"margin-bottom: 3%;\">\n\t\t\t\t<iframe frameborder=\"0\" width=\"480\" height=\"270\" src=\"http://www.dailymotion.com/embed/video/k6zGwVvjQxn5Ek3Sp38\" class=\"video-frame\"></iframe>\n\t\t\t</div>\n\t\t\t\n\t\t\t<p><span>This application uses the following APIs :</span></p>\n\t\t\t<ul>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/capability/package-summary.html\">Capability</a> API to define a new capability (e.g. extension) corresponding to the Popup service.</span></p>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/contacts/package-summary.html\">Contact</a> API to extract contacts supporting the Popup service and to know which contact is online or not.</span></p>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/package-summary.html\">Multimedia Session y</a> API to send and receive Popups.</span></p>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The Android <a href=\"http://developer.android.com/reference/android/speech/tts/TextToSpeech.html\">TTS</a> API </span></p>\t\t\t\t\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<p></p>\n\t\t\t</br>\n\t\t\t<h1>How to implement the Popup application?</h1>\n\t\t</div>\n\t\t<div class=\"content-body center\" style=\"min-height:700px;\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>1. Define a new capability or extension</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>The new capability is just declared in the Manifest file of the application and that's it. Then when the application is installed on the device, the joyn service in background will detect it and will automatically share this new capability with joyn contacts of your Address Book.</p>\t\t\t\t\t\t\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;activity android:name=</span><span class=\"java5\">&#34;.SendPopup&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.capability.EXTENSION&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;data android:mimeType=</span><span class=\"java5\">&#34;com.gsma.services.rcs/mnc01.mcc208.popup&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt; <br />\n\t\t\t\t\t\t&lt;/activity&gt;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>2. Display contacts supporting the Popup service</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>We want to display contacts from the device Address Book supporting the Popup service and which are online in order to interract with them immediately. By using the Contact API, there are directly methods to find joyn contacts for a given capability :</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\">\n\t\t\t\t\t\t</span><span class=\"java3\">// Service ID for the service<br />\n\t\t\t\t\t\t</span><span class=\"java4\">public static final </span><span class=\"java10\">String SERVICE_ID = </span><span class=\"java5\">&#34;mnc01.mcc208.popup&#34;</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\tSet&lt;JoynContact&gt; supportedContacts = contactsApi.getJoynContactsSupporting</span><span class=\"java8\">(</span><span class=\"java10\">PopupManager.SERVICE_ID</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java4\">for </span><span class=\"java8\">(</span><span class=\"java10\">JoynContact contact : supportedContacts</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">if </span><span class=\"java8\">(</span><span class=\"java10\">contact.isRegistered</span><span class=\"java8\">()) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java10\">Log.d</span><span class=\"java8\">(</span><span class=\"java10\">TAG, </span><span class=\"java5\">&#34;Add online contact &#34; </span><span class=\"java10\">+ contact.getContactId</span><span class=\"java8\">())</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0;&#xA0; items.add</span><span class=\"java8\">(</span><span class=\"java4\">new </span><span class=\"java10\">ContactItem</span><span class=\"java8\">(</span><span class=\"java10\">contact.getContactId</span><span class=\"java8\">()))</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t}</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>In general a joyn application first displays the list of contacts from its local database and then executes a capability refresh in background in order to update capabilities and availability of contacts.</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Refresh capability task<br />\n\t\t\t\t\t\t</span><span class=\"java4\">private class </span><span class=\"java10\">RefreshCapabilitiesAsyncTask </span><span class=\"java4\">extends </span><span class=\"java10\">AsyncTask&lt;Void, Void, Void&gt; </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java16\">@Override<br />\n\t\t\t\t\t\t</span><span class=\"java4\">protected </span><span class=\"java9\">void </span><span class=\"java10\">onPreExecute</span><span class=\"java8\">() {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">super</span><span class=\"java10\">.onPreExecute</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java16\">@Override<br />\n\t\t\t\t\t\t</span><span class=\"java4\">protected </span><span class=\"java10\">Void doInBackground</span><span class=\"java8\">(</span><span class=\"java10\">Void... params</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">Set&lt;JoynContact&gt; rcsContacts = contactsApi.getJoynContacts</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">for </span><span class=\"java8\">(</span><span class=\"java10\">JoynContact contact : rcsContacts</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">capabilityApi.requestContactCapabilities</span><span class=\"java8\">(</span><span class=\"java10\">contact.getContactId</span><span class=\"java8\">())</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">return null</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java16\">@Override<br />\n\t\t\t\t\t\t</span><span class=\"java4\">protected </span><span class=\"java9\">void </span><span class=\"java10\">onPostExecute</span><span class=\"java8\">(</span><span class=\"java10\">Void result</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java4\">super</span><span class=\"java10\">.onPostExecute</span><span class=\"java8\">(</span><span class=\"java10\">result</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}<br />\n\t\t\t\t\t\t}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java10\">...<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Then use the CapabilitiesListener to receive the result and to update the list of contacts</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t</br>\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>3. Define a protocol to implement your new service</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Here we just want to send an instant message or a popup, so there is no session lasting over time. In this case the best practice is to use the method <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/session/MultimediaSessionService.html#sendMessage(java.lang.String, java.lang.String, java.lang.String, java.lang.String)\">MultimediaSessionService.sendMessage</a> which permits to send a SIP MESSAGE to the joyn network :</p>\t\t\t\t\t\t\n\t\t\t\t<p></p>\n\t\t\t\t<div style=\"width:600px;margin:auto\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/popup_sample_3.png\" width=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Then we should also define the format used to transfer the Popup information (text message, TTS option and animation). Here we have decided to use an XML format as the follows :</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java5\">&#34;&lt;?xml version=\\&#34;1.0\\&#34; encoding=\\&#34;UTF-8\\&#34;?&gt;&#34; </span><span class=\"java10\">+ CRLF +<br />\n\t\t\t\t\t\t</span><span class=\"java5\">&#34;&lt;popup&gt;&#34; </span><span class=\"java10\">+ CRLF +&#xA0;&#xA0;&#xA0; <br />\n\t\t\t\t\t\t</span><span class=\"java5\">&#34;&lt;message&gt;&#34; </span><span class=\"java10\">+ message + </span><span class=\"java5\">&#34;&lt;/message&gt;&#34; </span><span class=\"java10\">+ CRLF&#xA0; +<br />\n\t\t\t\t\t\t</span><span class=\"java5\">&#34;&lt;animation&gt;&#34; </span><span class=\"java10\">+ animation + </span><span class=\"java5\">&#34;&lt;/animation&gt;&#34; </span><span class=\"java10\">+ CRLF +<br />\n\t\t\t\t\t\t</span><span class=\"java5\">&#34;&lt;timeout&gt;&#34; </span><span class=\"java10\">+ DateUtils.encodeDate</span><span class=\"java8\">(</span><span class=\"java10\">System.currentTimeMillis</span><span class=\"java8\">()) </span><span class=\"java10\">+ </span><span class=\"java5\">&#34;&lt;/timeout&gt;&#34; </span><span class=\"java10\">+ CRLF +<br />\n\t\t\t\t\t\t</span><span class=\"java5\">&#34;&lt;tts&gt;&#34; </span><span class=\"java10\">+ Boolean.toString</span><span class=\"java8\">(</span><span class=\"java10\">tts</span><span class=\"java8\">) </span><span class=\"java10\">+ </span><span class=\"java5\">&#34;&lt;/tts&gt;&#34; </span><span class=\"java10\">+ CRLF +<br />\n\t\t\t\t\t\t</span><span class=\"java5\">&#34;&lt;/popup&gt;&#34;</span><span class=\"java10\">;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t</br>\n\t\t\t\t<p></p>\t\t\t\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>4. Implement the sender side (see class SendPopup)</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>The end user should select 1 or more contacts from the list of joyn contacts displayed in step 2. Then we use the Multimedia Session API to send the selected Popup to each contact sequentially.</p>\t\t\t\t\t\t\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java4\">for</span><span class=\"java8\">(</span><span class=\"java9\">int </span><span class=\"java10\">i=</span><span class=\"java7\">0</span><span class=\"java10\">; i &lt; selectedContacts.size</span><span class=\"java8\">()</span><span class=\"java10\">; i++</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; ContactItem contact = selectedContacts.get</span><span class=\"java8\">(</span><span class=\"java10\">i</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java9\">boolean </span><span class=\"java10\">result = sessionApi.sendMessage</span><span class=\"java8\">(<span class=\"java10\">PopupManager.SERVICE_ID,<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; contact.number,<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0; PopupManager.generatePopup</span><span class=\"java8\">(</span><span class=\"java10\">message, animation, tts</span><span class=\"java8\">)</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; ...<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>The static PopupManager.<span style=\"color:blue\">SERVICE_ID</span> contains the capability extension defined in step 1.</p>\t\t\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>5. Implement the receiver side (see class PopupReceiver)</h2>\n\t\t\t\t<p></p>\n\t\t\t\t<p>An incoming Popup is catched via the Intent MultimediaMessageIntent. See the following Intent receiver defined in the Manisfest file :</p>\t\t\t\t\t\t\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;receiver android:name=</span><span class=\"java5\">&#34;.PopupReceiver&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.session.action.NEW_MESSAGE&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;data android:mimeType=</span><span class=\"java5\">&#34;com.gsma.services.rcs/orange.popup&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;category android:name=</span><span class=\"java5\">&#34;android.intent.category.LAUNCHER&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; category android:name=</span><span class=\"java5\">&#34;android.intent.category.DEFAULT&#34; </span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt;<br />\n\t\t\t\t\t\t&lt;/receiver&gt;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>Then the XML content received in the incoming Intent is parsed and the Popup is displayed in over-the-top :</p>\n\t\t\t\t<p></p>\t\t\t\t\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Parse received popup<br />\n\t\t\t\t\t\t</span><span class=\"java10\">String content = getIntent</span><span class=\"java8\">()</span><span class=\"java10\">.getStringExtra</span><span class=\"java8\">(</span><span class=\"java5\">&#34;content&#34;</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tInputSource input = </span><span class=\"java4\">new </span><span class=\"java10\">InputSource</span><span class=\"java8\">(</span><span class=\"java4\">new </span><span class=\"java10\">ByteArrayInputStream</span><span class=\"java8\">(</span><span class=\"java10\">content.getBytes</span><span class=\"java8\">()))</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tPopupParser parser = </span><span class=\"java4\">new </span><span class=\"java10\">PopupParser</span><span class=\"java8\">(</span><span class=\"java10\">input</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Display message<br />\n\t\t\t\t\t\t</span><span class=\"java10\">String remote = getIntent</span><span class=\"java8\">()</span><span class=\"java10\">.getStringExtra</span><span class=\"java8\">(</span><span class=\"java5\">&#34;contact&#34;</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tString txt = parser.getMessage</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tString msg = getString</span><span class=\"java8\">(</span><span class=\"java10\">R.string.label_remote, remote</span><span class=\"java8\">) </span><span class=\"java10\">+ </span><span class=\"java5\">&#34;\\n&#34; </span><span class=\"java10\">+ txt;<br />\n\t\t\t\t\t\tTextView msgView = </span><span class=\"java8\">(</span><span class=\"java10\">TextView</span><span class=\"java8\">)</span><span class=\"java10\">findViewById</span><span class=\"java8\">(</span><span class=\"java10\">R.id.message</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tmsgView.setText</span><span class=\"java8\">(</span><span class=\"java10\">msg</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Play TTS<br />\n\t\t\t\t\t\t</span><span class=\"java4\">if </span><span class=\"java8\">(</span><span class=\"java10\">parser.isTTS</span><span class=\"java8\">() </span><span class=\"java10\">&amp;&amp; !TextUtils.isEmpty</span><span class=\"java8\">(</span><span class=\"java10\">txt</span><span class=\"java8\">)) {<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">Intent ttsIntent = </span><span class=\"java4\">new </span><span class=\"java10\">Intent</span><span class=\"java8\">(</span><span class=\"java10\">getApplicationContext</span><span class=\"java8\">()</span><span class=\"java10\">, PlayTTS.</span><span class=\"java4\">class</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; ttsIntent.putExtra</span><span class=\"java8\">(</span><span class=\"java5\">&#34;message&#34;</span><span class=\"java10\">, txt</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; startService</span><span class=\"java8\">(</span><span class=\"java10\">ttsIntent</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Make a vibration<br />\n\t\t\t\t\t\t</span><span class=\"java10\">Vibrator vibrator = </span><span class=\"java8\">(</span><span class=\"java10\">Vibrator</span><span class=\"java8\">)</span><span class=\"java10\">getSystemService</span><span class=\"java8\">(</span><span class=\"java10\">Context.VIBRATOR_SERVICE</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java9\">long</span><span class=\"java8\">[] </span><span class=\"java10\">pattern = </span><span class=\"java8\">{</span><span class=\"java7\">500L</span><span class=\"java10\">, </span><span class=\"java7\">200L</span><span class=\"java10\">, </span><span class=\"java7\">500L</span><span class=\"java8\">}</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tvibrator.vibrate</span><span class=\"java8\">(</span><span class=\"java10\">pattern, -</span><span class=\"java7\">1</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Display animation<br />\n\t\t\t\t\t\t</span><span class=\"java10\">ImageView imageView = </span><span class=\"java8\">(</span><span class=\"java10\">ImageView</span><span class=\"java8\">)</span><span class=\"java10\">findViewById</span><span class=\"java8\">(</span><span class=\"java10\">R.id.picture</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\timageView.setClickable</span><span class=\"java8\">(</span><span class=\"java4\">true</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\timageView.setFocusable</span><span class=\"java8\">(</span><span class=\"java4\">true</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\timageView.setOnClickListener</span><span class=\"java8\">(</span><span class=\"java4\">this</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tString animation = parser.getAnimation</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tInputStream stream = getResources</span><span class=\"java8\">()</span><span class=\"java10\">.getAssets</span><span class=\"java8\">()</span><span class=\"java10\">.open</span><span class=\"java8\">(</span><span class=\"java10\">animation.toLowerCase</span><span class=\"java8\">() </span><span class=\"java10\">+ </span><span class=\"java5\">&#34;.png&#34;</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\tDrawable d = Drawable.createFromStream</span><span class=\"java8\">(</span><span class=\"java10\">stream, </span><span class=\"java4\">null</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\timageView.setImageDrawable</span><span class=\"java8\">(</span><span class=\"java10\">d</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Play animation<br />\n\t\t\t\t\t\t</span><span class=\"java10\">Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation</span><span class=\"java8\">(</span><span class=\"java10\">this, R.anim.zoom</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\timageView.startAnimation</span><span class=\"java8\">(</span><span class=\"java10\">hyperspaceJumpAnimation</span><span class=\"java8\">)</span><span class=\"java10\">;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<div style=\"width:59px;height:63px;\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/popup_sample_4.png\" width=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>See the complete source code of the application <a target=\"_blank\" href=\"https://code.google.com/p/rcsjta/source/browse/#git%2Fsamples%2Fpopup\">here</a>.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "SDK/tutorials/ttsApp.jd",
    "content": "page.title=Text to speech application\ndoc.type=tutorials\n@jd:body\n<div class=\"background-sdk\">\n\t<div class=\"content-block\">\n\t\t<div class=\"intro center\">\n\t\t\t<p><h1>Text to speech application</h1></p>\n\t\t\t<p><span>This tutorial demonstrates how to build a Text-To-Speech (TTS) application around the joyn chat service. This service permits to play a TTS synthesis on each received chat message.</span></p>\n\t\t\t<p><span>The application offers a simple UI which permits to activate/deactivate the TTS synthesis:</span></p>\n\t\t\t<div style=\"width:280px;margin:auto;\">\n\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tts_sample_1.png\" width=\"100%\"/>\n\t\t\t</div>\n\t\t\t<p></p>\n\t\t\t<p><span>This application uses the following API :</span></p>\n\t\t\t<ul>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/package-summary.html\">Chat</a> API to receive incoming chat message.</span></p>\n\t\t\t\t</li>\n\t\t\t\t<li>\n\t\t\t\t\t<p><span>The Android <a href=\"http://developer.android.com/reference/android/speech/tts/TextToSpeech.html\">TTS</a> API </span></p>\t\t\t\t\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<p></p>\n\t\t\t</br>\n\t\t\t<h1>How to implement the Text-to-speech application?</h1>\n\t\t</div>\n\t\t<div class=\"content-body center\">\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>1. Activate the speech synthesis on your Android device</h2>\n\t\t\t\t<p></p>\t\t\t\n\t\t\t\n\t\t\t\t<ul>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>Load device parameters application.</p>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>Select the menu « Language and inputs ».</p>\t\t\t\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>Go to « Text-to-speech ouput ».</p>\t\t\t\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>Configure the TTS engine (speed, language, .etc).</p>\t\t\t\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t<div style=\"width:280px;margin:auto;\">\n\t\t\t\t\t<img src=\"{@docRoot}assets-sdk/images/tts_sample_2.png\" width=\"100%\"/>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>2. Catch a single chat message</h2>\n\t\t\t\t<p></p>\t\n\t\t\t\t<p>There are different ways to catch incoming chat messages:</p>\t\t\t\t\n\t\t\t\t\n\t\t\t\t<ul>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>From a chat listener interface <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/NewChatListener.html\">NewChatListener</a>.</p>\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>From the Intent <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/ChatIntent.html#ACTION_NEW_CHAT\">ChatIntent.ACTION_NEW_CHAT</a>.</p>\t\t\t\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>From a Chat object if a conversation is already opened.</p>\t\t\n\t\t\t\t\t</li>\n\t\t\t\t\t<li>\n\t\t\t\t\t\t<p>From the Content Provider <a href=\"{@docRoot}javadoc/com/gsma/services/rcs/chat/ChatLog.Message.html\">ChatLog.Message</a>.</p>\t\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t<p>Here, we have choosen to use the Intent to catch the incoming message:</p>\n\t\t\t\t<p>Using the Intent, we do not need to manage a joyn session. The Intent is broadcasted by the joyn service, we only need to receive it.</p>\n\t\t\t\t<p>An Intent receiver is declared in the Manisfest file with a filter on single chat message :</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java10\">&lt;receiver android:name=</span><span class=\"java5\">&#34;com.orangelabs.rcs.tts.ChatEvent&#34;</span><span class=\"java10\">&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;intent-filter&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;action android:name=</span><span class=\"java5\">&#34;com.gsma.services.rcs.chat.action.NEW_CHAT&#34;</span><span class=\"java10\">/&gt;<br />\n\t\t\t\t\t\t&#xA0; &lt;/intent-filter&gt;<br />\n\t\t\t\t\t\t&lt;/receiver&gt;</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>An Intent receiver is implemented to read the received chat message and to process a TTS in background:</p>\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java16\">@Override<br />\n\t\t\t\t\t\t</span><span class=\"java4\">public </span><span class=\"java9\">void </span><span class=\"java10\">onReceive</span><span class=\"java8\">(</span><span class=\"java10\">Context context, Intent intent</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// A new chat message is received<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; // Check activation state before to continue<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">...<br />\n\t\t\t\t\t\t&#xA0; ...<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Get the chat message from the Intent<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">ChatMessage message = intent.getParcelableExtra</span><span class=\"java8\">(</span><span class=\"java10\">ChatIntent.EXTRA_MESSAGE</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java3\">// Play TTS on the chat message<br />\n\t\t\t\t\t\t&#xA0; </span><span class=\"java10\">ArrayList&lt;String&gt; messages = </span><span class=\"java4\">new </span><span class=\"java10\">ArrayList&lt;String&gt;</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; messages.add</span><span class=\"java8\">(</span><span class=\"java10\">context.getString</span><span class=\"java8\">(</span><span class=\"java10\">R.string.label_new_msg</span><span class=\"java8\">))</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; messages.add</span><span class=\"java8\">(</span><span class=\"java10\">message.getMessage</span><span class=\"java8\">())</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; Intent serviceIntent = </span><span class=\"java4\">new </span><span class=\"java10\">Intent</span><span class=\"java8\">(</span><span class=\"java10\">context, PlayTextToSpeech.</span><span class=\"java4\">class</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; serviceIntent.putStringArrayListExtra</span><span class=\"java8\">(</span><span class=\"java5\">&#34;messages&#34;</span><span class=\"java10\">, messages</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; context.startService</span><span class=\"java8\">(</span><span class=\"java10\">serviceIntent</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0; ...<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t<div class=\"guide-block\">\n\t\t\t\t<h2>3. Play a TTS on the received text message</h2>\n\t\t\t\t<p></p>\t\n\t\t\t\t<p>See also an introduction to Text-to-Speech in Android at <a target=\"_blank\" href=\"http://android-developers.blogspot.fr/2009/09/introduction-to-text-to-speech-in.html\">http://android-developers.blogspot.fr/2009/09/introduction-to-text-to-speech-in.html</a>.</p>\t\t\t\t\n\t\t\t\t<p></p>\n\t\t\t\t<div class=\"code-block\">\n\t\t\t\t\t<tt class=\"java\"><span class=\"java3\">// Instanciate the TTS engine<br />\n\t\t\t\t\t\t</span><span class=\"java4\">try </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java10\">tts = </span><span class=\"java4\">new </span><span class=\"java10\">TextToSpeech</span><span class=\"java8\">(</span><span class=\"java10\">getApplicationContext</span><span class=\"java8\">()</span><span class=\"java10\">, </span><span class=\"java4\">this</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">} </span><span class=\"java4\">catch</span><span class=\"java8\">(</span><span class=\"java10\">Exception e</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java10\">Log.v</span><span class=\"java8\">(</span><span class=\"java10\">TAG, </span><span class=\"java5\">&#34;Can't instanciate TTS engine&#34;</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0;&#xA0; e.printStackTrace</span><span class=\"java8\">()</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java8\">}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Speak<br />\n\t\t\t\t\t\t</span><span class=\"java10\">Log.v</span><span class=\"java8\">(</span><span class=\"java10\">TAG, </span><span class=\"java5\">&#34;Start TTS session: play &#34; </span><span class=\"java10\">+ messages.size</span><span class=\"java8\">() </span><span class=\"java10\">+ </span><span class=\"java5\">&#34; messages&#34;</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\ttts.speak</span><span class=\"java8\">(</span><span class=\"java10\">messages.get</span><span class=\"java8\">(</span><span class=\"java7\">0</span><span class=\"java8\">)</span><span class=\"java10\">, TextToSpeech.QUEUE_FLUSH, </span><span class=\"java4\">null</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t</span><span class=\"java4\">if </span><span class=\"java8\">(</span><span class=\"java10\">messages.size</span><span class=\"java8\">() </span><span class=\"java10\">&gt; </span><span class=\"java7\">1</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">for</span><span class=\"java8\">(</span><span class=\"java9\">int </span><span class=\"java10\">i=</span><span class=\"java7\">1</span><span class=\"java10\">; i &lt; messages.size</span><span class=\"java8\">()</span><span class=\"java10\">; i++</span><span class=\"java8\">) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">tts.speak</span><span class=\"java8\">(</span><span class=\"java10\">messages.get</span><span class=\"java8\">(</span><span class=\"java10\">i</span><span class=\"java8\">)</span><span class=\"java10\">, TextToSpeech.QUEUE_ADD, </span><span class=\"java4\">null</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java8\">}<br />\n\t\t\t\t\t\t}<br />\n\t\t\t\t\t\t<br />\n\t\t\t\t\t\t</span><span class=\"java3\">// Wait end of speech<br />\n\t\t\t\t\t\t</span><span class=\"java4\">while</span><span class=\"java8\">(</span><span class=\"java10\">tts.isSpeaking</span><span class=\"java8\">()) {<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java4\">try </span><span class=\"java8\">{<br />\n\t\t\t\t\t\t&#xA0;&#xA0;&#xA0;&#xA0; </span><span class=\"java10\">Thread.sleep</span><span class=\"java8\">(</span><span class=\"java7\">500</span><span class=\"java8\">)</span><span class=\"java10\">;<br />\n\t\t\t\t\t\t&#xA0;&#xA0; </span><span class=\"java8\">} </span><span class=\"java4\">catch</span><span class=\"java8\">(</span><span class=\"java10\">Exception e</span><span class=\"java8\">) {}<br />\n\t\t\t\t\t\t}<br />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</tt>\n\t\t\t\t</div>\n\t\t\t\t<p></p>\n\t\t\t\t<p>See the complete source code of the application <a target=\"_blank\" href=\"https://code.google.com/p/rcsjta/source/browse/#git%2Fsamples%2Ftts\">here</a>.</p>\n\t\t\t\t<p></p>\n\t\t\t</div>\n\t\t\t</br>\n\t\t\t\n\t\t</div>\n\t</div>\n</div>"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.2.3'\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\nproject.ext.set(\"compileSdkVersion\", 23)\nproject.ext.set(\"minSdkVersion\", 12)\nproject.ext.set(\"targetSdkVersion\", 23)\nproject.ext.set(\"buildToolsVersion\", \"24.0.0\")\n"
  },
  {
    "path": "build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"GSMA Terminal API\" basedir=\".\" default=\"help\">\n\t<tstamp>\n\t\t<format property=\"TODAY_MY\" pattern=\"yyyyMMdd-HHmmss\" locale=\"en,UK\" />\n\t</tstamp>\n\n\t<property environment=\"env\" />\n\t<property name=\"terminal.root\" value=\".\" />\n\t<property name=\"ri.root\" value=\"${terminal.root}/RI\" />\n\t<property name=\"api.root\" value=\"${terminal.root}/libs/api\" />\n\t<property name=\"stack.root\" value=\"${terminal.root}/core\" />\n\t<property name=\"stack.bin\" value=\"${stack.root}/bin\" />\n\t<property name=\"tools\" value=\"${terminal.root}/tools\" />\n\t<property name=\"samples\" value=\"${terminal.root}/samples/api\" />\n\t<property name=\"template.root\" value=\"${tools}/provisioning\" />\n\t<property name=\"settings.root\" value=\"${tools}/settings\" />\n\t<property name=\"notification.root\" value=\"${tools}/notification\" />\n\t<property name=\"extension.root\" value=\"${samples}/extension\" />\n\t<property name=\"tts.root\" value=\"${samples}/tts\" />\n\t<property name=\"javadoc.root\" value=\"${api.root}/build/docs/javadoc\" />\n\t<property name=\"generate.root\" value=\"${terminal.root}/gen\" />\n\t<property name=\"sdk.zip\" value=\"${generate.root}/rcsjta_sdk_${TODAY_MY}.zip\" />\n\n\t<path id=\"j2se.lib\">\n\t\t<fileset dir=\"${env.JAVA_HOME}/lib/\">\n\t\t\t<include name=\"**/*.jar\" />\n\t\t</fileset>\n\t</path>\n\t<property name=\"j2se.classpath\" refid=\"j2se.lib\" />\n\n\t<!-- Generate RCS API SDK -->\n\t<!-- ********************* -->\n\t<target name=\"sdk\">\n\t\t<mkdir dir=\"${generate.root}\" />\n\t\t<delete>\n\t\t\t<fileset dir=\"${generate.root}\">\n\t\t\t\t<include name=\"*\" />\n\t\t\t</fileset>\n\t\t</delete>\n\t\t<zip destfile=\"${sdk.zip}\">\n\t\t\t<fileset dir=\"${stack.root}\" includes=\"LICENSE*.txt\" />\n\t\t\t<fileset dir=\"${stack.root}\" includes=\"NOTICE.txt\" />\n\t\t\t<zipfileset dir=\"${api.root}/build/outputs/aar\" includes=\"*debug.aar\"\n\t\t\t\tfullpath=\"api/rcs_api.aar\" />\n\t\t\t<zipfileset dir=\"${ri.root}/libs/armeabi\"\n\t\t\t\tincludes=\"lib*.so\" prefix=\"api/codecs\" />\n\t\t\t<zipfileset dir=\"${javadoc.root}\" prefix=\"api/javadoc\" />\n\t\t\t<zipfileset dir=\"${template.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"tools/RCS_template.apk\" />\n\t\t\t<zipfileset dir=\"${settings.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"tools/RCS_settings.apk\" />\n\t\t\t<zipfileset dir=\"${notification.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"tools/RCS_notification.apk\" />\n\t\t\t<zipfileset dir=\"${stack.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"stack/RCS_core.apk\" />\n\t\t\t<zipfileset dir=\"${ri.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"tools/RCS_RI.apk\" />\n\t\t\t<zipfileset dir=\"${extension.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"samples/RCS_extension.apk\" />\n\t\t\t<zipfileset dir=\"${tts.root}/build/outputs/apk\" includes=\"*debug.apk\"\n\t\t\t\tfullpath=\"samples/RCS_tts.apk\" />\n\t\t</zip>\n\t</target>\n\n\n\n\t<target name=\"help\">\n\t\t<echo>Available targets:</echo>\n\t\t<echo> help: Displays this help.</echo>\n\t\t<echo> sdk: Generates RCS SDK.</echo>\n\t</target>\n</project>\n\n"
  },
  {
    "path": "core/.gitignore",
    "content": "/libs\r\n/bin\r\n/gen\r\n\r\n.classpath\r\n.settings\r\nassets\r\nrcs_api.jar"
  },
  {
    "path": "core/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<manifest package=\"com.gsma.rcs\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\"/>\n    <uses-permission android:name=\"android.permission.READ_SMS\"/>\n    <uses-permission android:name=\"android.permission.WRITE_SMS\"/>\n    <uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>\n    <uses-permission android:name=\"android.permission.CAMERA\"/>\n    <uses-permission android:name=\"android.permission.VIBRATE\"/>\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n    <uses-permission android:name=\"android.permission.CALL_PHONE\"/>\n    <uses-permission android:name=\"android.permission.PROCESS_OUTGOING_CALLS\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>\n    <uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\"/>\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n    <uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>\n    <uses-permission android:name=\"android.permission.MANAGE_ACCOUNTS\"/>\n    <uses-permission android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\"/>\n    <uses-permission android:name=\"android.permission.WRITE_SYNC_SETTINGS\"/>\n    <uses-permission android:name=\"android.permission.RECEIVE_SMS\"/>\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\"/>\n\n    <permission\n        android:name=\"com.gsma.services.permission.RCS\"\n        android:description=\"@string/rcs_core_permission_desc\"\n        android:label=\"@string/rcs_core_permission\"\n        android:protectionLevel=\"normal\"/>\n    <permission\n        android:name=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"\n        android:protectionLevel=\"signature\"/>\n\n    <application\n        android:icon=\"@drawable/rcs_icon\"\n        android:label=\"@string/rcs_core_application_title\">\n\n        <!-- RCS service -->\n\n        <service\n            android:name=\"com.gsma.rcs.service.RcsCoreService\"\n            android:permission=\"com.gsma.services.permission.RCS\">\n            <intent-filter>\n                <action android:name=\"com.gsma.rcs.SERVICE\"/>\n                <action android:name=\"com.gsma.services.rcs.contact.IContactService\"/>\n                <action android:name=\"com.gsma.services.rcs.capability.ICapabilityService\"/>\n                <action android:name=\"com.gsma.services.rcs.chat.IChatService\"/>\n                <action android:name=\"com.gsma.services.rcs.filetransfer.IFileTransferService\"/>\n                <action android:name=\"com.gsma.services.rcs.sharing.video.IVideoSharingService\"/>\n                <action android:name=\"com.gsma.services.rcs.sharing.image.IImageSharingService\"/>\n                <action android:name=\"com.gsma.services.rcs.sharing.geoloc.IGeolocSharingService\"/>\n                <action android:name=\"com.gsma.services.rcs.history.IHistoryService\"/>\n                <action android:name=\"com.gsma.services.rcs.extension.IMultimediaSessionService\"/>\n                <action android:name=\"com.gsma.services.rcs.upload.IFileUploadService\"/>\n            </intent-filter>\n        </service>\n\n        <!-- RCS settings application -->\n\n        <activity\n            android:name=\"com.gsma.rcs.provisioning.https.HttpsProvisioningAlertDialog\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize\"\n            android:excludeFromRecents=\"true\"\n            android:theme=\"@style/Theme.UserDialog\"/>\n\n        <!-- RCS account: authenticator service for user's account information -->\n\n        <service\n            android:name=\"com.gsma.rcs.addressbook.AuthenticationService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.accounts.AccountAuthenticator\"/>\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.accounts.AccountAuthenticator\"\n                android:resource=\"@xml/rcs_core_authenticator\"/>\n        </service>\n\n        <!-- RCS account: sync adapter service -->\n\n        <service\n            android:name=\"com.gsma.rcs.addressbook.SyncAdapterService\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"android.content.SyncAdapter\"/>\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.content.SyncAdapter\"\n                android:resource=\"@xml/rcs_core_syncadapter\"/>\n            <meta-data\n                android:name=\"android.provider.CONTACTS_STRUCTURE\"\n                android:resource=\"@xml/rcs_core_contacts\"/>\n        </service>\n\n        <!-- RCS account: activity to create an account -->\n        <activity android:name=\"com.gsma.rcs.addressbook.SetupRcsAccount\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\"/>\n\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n            </intent-filter>\n        </activity>\n\n        <!-- RCS data providers -->\n\n        <provider\n            android:name=\"com.gsma.rcs.provider.messaging.ChatProvider\"\n            android:authorities=\"com.gsma.rcs.chat;com.gsma.services.rcs.provider.chat\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.messaging.GroupDeliveryInfoProvider\"\n            android:authorities=\"com.gsma.rcs.groupdeliveryinfo;com.gsma.services.rcs.provider.groupdeliveryinfo\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.messaging.FileTransferProvider\"\n            android:authorities=\"com.gsma.rcs.filetransfer;com.gsma.services.rcs.provider.filetransfer\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.sharing.ImageSharingProvider\"\n            android:authorities=\"com.gsma.rcs.imageshare;com.gsma.services.rcs.provider.imageshare\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.sharing.VideoSharingProvider\"\n            android:authorities=\"com.gsma.rcs.videoshare;com.gsma.services.rcs.provider.videoshare\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.contact.ContactProvider\"\n            android:authorities=\"com.gsma.rcs.capability;com.gsma.services.rcs.provider.capability\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.settings.RcsSettingsProvider\"\n            android:authorities=\"com.gsma.rcs.setting\"\n            android:exported=\"false\"\n            android:permission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.sharing.GeolocSharingProvider\"\n            android:authorities=\"com.gsma.rcs.geolocshare;com.gsma.services.rcs.provider.geolocshare\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n        <provider\n            android:name=\"com.gsma.rcs.provider.history.HistoryProvider\"\n            android:authorities=\"com.gsma.rcs.history;com.gsma.services.rcs.provider.history\"\n            android:exported=\"true\"\n            android:readPermission=\"com.gsma.services.permission.RCS\"\n            android:writePermission=\"com.gsma.services.permission.RCS_INTERNAL_ACCESS_ONLY\"/>\n\n        <!-- Device events receiver -->\n\n        <receiver android:name=\"com.gsma.rcs.service.DeviceBoot\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\"/>\n            </intent-filter>\n        </receiver>\n        <receiver android:name=\"com.gsma.rcs.service.DeviceShutdown\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.ACTION_SHUTDOWN\"/>\n            </intent-filter>\n        </receiver>\n\n        <!-- Provisioning Push SMS Receiver -->\n        <receiver android:name=\"com.gsma.rcs.provisioning.https.ProvisioningPushSMSReceiver\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.DATA_SMS_RECEIVED\"/>\n                <data\n                    android:host=\"localhost\"\n                    android:port=\"37273\"\n                    android:scheme=\"sms\"/>\n            </intent-filter>\n        </receiver>\n\n        <!-- HTTPS provisioning service -->\n        <service android:name=\"com.gsma.rcs.provisioning.https.HttpsProvisioningService\"/>\n\n        <!-- Startup service -->\n        <service android:name=\"com.gsma.rcs.service.StartService\"/>\n\n        <!-- Provisioning - Terms and conditions activity -->\n        <activity\n            android:name=\"com.gsma.rcs.provisioning.TermsAndConditionsRequest\"\n            android:theme=\"@style/Theme.UserDialog\"/>\n\n        <!-- RCS API -->\n\n        <receiver android:name=\"com.gsma.rcs.service.RcsServiceControlReceiver\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.action.GET_ACTIVATION_MODE_CHANGEABLE\"/>\n                <action android:name=\"com.gsma.services.rcs.action.GET_ACTIVATION_MODE\"/>\n                <action android:name=\"com.gsma.services.rcs.action.SET_ACTIVATION_MODE\"/>\n                <action android:name=\"com.gsma.services.rcs.action.GET_COMPATIBILITY\"/>\n                <action android:name=\"com.gsma.services.rcs.action.GET_SERVICE_STARTING_STATE\"/>\n            </intent-filter>\n        </receiver>\n\n        <!-- Local provisioning (only for debug) -->\n\n        <activity\n            android:name=\".provisioning.local.Provisioning\"\n            android:icon=\"@drawable/rcs_icon\"\n            android:label=\"@string/provisioning_app_name\"\n            android:theme=\"@style/Theme.AppCompat\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n\n        <service\n            android:name=\"com.gsma.rcs.service.api.OneToOneDeliveryExpirationService\"\n            android:exported=\"false\"/>\n\n        <activity\n            android:name=\".service.permissions.PermissionsAlertDialog\"\n            android:theme=\"@style/Theme.Transparent\"/>\n\n    </application>\n\n</manifest>"
  },
  {
    "path": "core/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "core/LICENSE-BOUNCYCASTLE.txt",
    "content": "Copyright (c) 2000-2012 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software \nand associated documentation files (the \"Software\"), to deal in the Software without restriction, \nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, \nand/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,\nINCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\nPURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE."
  },
  {
    "path": "core/LICENSE-DNS.txt",
    "content": "Copyright (c) 1998-2011, Brian Wellington.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n  * Redistributions of source code must retain the above copyright notice,\n    this list of conditions and the following disclaimer.\n\n  * Redistributions in binary form must reproduce the above copyright notice,\n    this list of conditions and the following disclaimer in the documentation\n    and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "core/LICENSE-NIST.txt",
    "content": "/*\n***********************************************************************\n* The following applies to the packages \"gov.nist\", \"test\" and \n* \"tools\" and all subpackages thereof\n***********************************************************************\n*\n* Conditions Of Use \n* \n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), and others. \n* This software has been contributed to the public domain. \n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain. \n* As a result, a formal license is not needed to use this software.\n* \n* This software is provided \"AS IS.\"  \n* NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* this software.\n* \n* \n*/\n"
  },
  {
    "path": "core/NOTICE.txt",
    "content": "NOTICE - RCS stack for Android with GSMA Terminal API \nRelease 1.6\n\nThe RCS stack is under Apache 2 license (see LICENSE-2.0.txt) and uses the following open source libraries:\n - NIST SIP: see LICENSE-NIST.txt.\n - DNS Java: see LICENSE-DNS.txt.\n - The Legion Of The Bouncy Castle: see LICENSE-BOUNCYCASTLE.txt.\n\nInstallation:\nThe RCS_core.apk must be first installed on the device. Client applications (like RCS_RI.apk, RCS_settings.apk, etc...) \nmust be installed after the core stack otherwise permission to bind to the core service is denied.\n\n   News:\n\n   Implementation of additional functions and changes required for Crane Priority Release profile.\n   - Capabilities service:\n   \t* Possibility to query for the support of a combination of capabilities.\n\t* Better backward compatibility if new capabilities are introduced.\n   - File transfer service:\n   \t* Support of audio messages.\n   - Multimedia service:\n   \t* Introduction of SIP instant messages (no session).\n\t* Possibility to flush pending messages for multimedia messaging sessions.\n\n   Bugs fixed:\n   -----------\n"
  },
  {
    "path": "core/README.md",
    "content": "#RCS core stack\nBuild instruction:\n\n<code>../gradlew :core:build</code>\n\nAdditional steps for Eclipse compatibility:\n\n<code>ant libs</code>\n\nThis will create the following jar files under the \"libs\" folder:\n- bouncycastle-xxx.jar\n- api.jar\n- nist_sip.jar\n\nDownload the [dnsjava-2.1.7.jar](http://mvnrepository.com/artifact/dnsjava/dnsjava/2.1.7) library and copy under the \"libs\" folder. \n"
  },
  {
    "path": "core/ant.properties",
    "content": "# This file is used to override default values used by the Ant build system.\n#\n# This file must be checked into Version Control Systems, as it is\n# integral to the build system of your project.\n\n# This file is only used by the Ant script.\n\n# You can use this to override default values such as\n#  'source.dir' for the location of your java source folder and\n#  'out.dir' for the location of your output folder.\n\n# You can also use it define how the release builds are signed by declaring\n# the following properties:\n#  'key.store' for the location of your keystore and\n#  'key.alias' for the name of the key to use.\n# The password will be asked during the build when you use the 'release' target.\n\nrenderscript.opt.level=O0\n\n"
  },
  {
    "path": "core/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n        }\n        androidTest.setRoot('tests')\n        androidTest {\n            //Defaults to core/tests/java\n            java.srcDirs = ['tests/src']\n        }\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.gsma.rcs\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 2\n        versionName \"2.0\"\n        archivesBaseName = \"RCS_Core\"\n    }\n\n}\n\ndependencies {\n    compile project(':bouncycastle')\n    compile project(':nist_sip')\n    compile project(':api')\n    compile 'dnsjava:dnsjava:2.1.7'\n    compile 'com.android.support:support-v4:25.0.1'\n    compile 'com.android.support:appcompat-v7:25.0.1'\n}\n"
  },
  {
    "path": "core/build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"core\" default=\"help\">\n\n\t<!-- This script to populate ./libs folder with generated jar files for building compatibility with Eclipse.\n\tThis script must be executed after dependent libraries have been generated by gradle.\n\tThis script must be removed after migration to Android Studio.\n\t-->\n\t<property name=\"terminal.root\" value=\".\" />\n\t<property name=\"terminal.lib_dst\" value=\"${terminal.root}/libs\" />\n\t<property name=\"terminal.lib_src2\" value=\"${terminal.root}/../libs/api/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.lib_src1\" value=\"${terminal.root}/../libs/nist_sip/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.lib_src3\" value=\"${terminal.root}/../libs/bouncycastle/build/libs/bouncycastle-0.1.0.jar\" />\n\t<property name=\"terminal.target2\" value=\"api.jar\" />\n\t<property name=\"terminal.target1\" value=\"nist_sip.jar\" />\n\t<property name=\"terminal.target3\" value=\"bouncycastle-0.1.0.jar\" />\n\n\t<target name=\"libs\">\n\t\t<echo>Copy ${terminal.target1} file</echo>\n\t\t<copy file=\"${terminal.lib_src1}\" tofile=\"${terminal.lib_dst}/${terminal.target1}\" />\n\t\t<echo>Copy ${terminal.target2} file</echo>\n\t\t<copy file=\"${terminal.lib_src2}\" tofile=\"${terminal.lib_dst}/${terminal.target2}\"/>\n\t\t<echo>Copy ${terminal.target3} file</echo>\n\t\t<copy file=\"${terminal.lib_src3}\" todir=\"${terminal.lib_dst}\" />\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<echo>Delete library files</echo>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target1}\"/>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target2}\"/>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target3}\"/>\n\t</target>\n\n\t<target name=\"all\" depends=\"clean,libs\" />\n\n\t<target name=\"help\">\n\t\t<echo>Library Ant Build. Available targets:</echo>\n\t\t<echo> help: Displays this help.</echo>\n\t\t<echo> clean: Removes output files created by other targets.</echo>\n\t\t<echo> libs: Generate input libraries.</echo>\n\t\t<echo> all: Deletes then copy input libraries.</echo>\n\t</target>\n\n</project>\n"
  },
  {
    "path": "core/default.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n# \n# This file must be checked in Version Control Systems.\n# \n# To customize properties used by the Ant build system use,\n# \"build.properties\", and override values to adapt the script to your\n# project structure.\n\n# Project target.\ntarget=android-7\nandroid.library=false\nproguard.config=proguard.cfg\n"
  },
  {
    "path": "core/findbugs-exclude.xml",
    "content": "<FindBugsFilter>\n    <!--\n        Suppress all warnings in the NIST stack,\n        switch has been checked and is intentional.\n    -->\n    <Match>\n        <Package name=\"~javax2\\..*\"/>\n    </Match>\n    <Match>\n        <Package name=\"~gov2\\..*\"/>\n    </Match>\n\n    <!--\n        Suppress all warnings in the DNSJava,\n        switch has been checked and is intentional.\n    -->\n    <Match>\n        <Package name=\"~org\\..*\"/>\n    </Match>\n\n    <!--\n        Suppress all warnings in Manifest and R,\n        switch has been checked and is intentional.\n    -->\n    <Match>\n        <Class name=\"~.*R\\$.*\"/>\n    </Match>\n    <Match>\n        <Class name=\"~.*Manifest\\$.*\"/>\n    </Match>\n\n    <!--\n        Suppress NM_METHOD_NAMING_CONVENTION warnings in encoder,\n        switch has been checked and is intentional.\n    -->\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.protocol.rtp.codec.video.h263.encoder.NativeH263Encoder\" />\n        <Or>\n            <Method name=\"InitEncoder\" />\n            <Method name=\"EncodeFrame\" />\n            <Method name=\"DeinitEncoder\" />\n        </Or>\n        <Bug pattern=\"NM_METHOD_NAMING_CONVENTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.encoder.NativeH264Encoder\" />\n        <Or>\n            <Method name=\"InitEncoder\" />\n            <Method name=\"EncodeFrame\" />\n            <Method name=\"DeinitEncoder\" />\n        </Or>\n        <Bug pattern=\"NM_METHOD_NAMING_CONVENTION\" />\n    </Match>\n\n    <!--\n        Suppress NN_NAKED_NOTIFY warning in FifoBuffer,\n        switch has been checked and is intentional.\n    -->\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.protocol.msrp.FifoBuffer\" />\n        <Method name=\"unblockRead\" />\n        <Bug pattern=\"NN_NAKED_NOTIFY\" />\n    </Match>\n\n    <!--\n        Suppress NN_NAKED_NOTIFY warning in FifoBuffer,\n        switch has been checked and is intentional.\n    -->\n    <Match>\n        <Class name=\"com.gsma.rcs.utils.FifoBuffer\" />\n        <Method name=\"close\" />\n        <Bug pattern=\"NN_NAKED_NOTIFY\" />\n    </Match>\n\n    <!--\n        Suppress REC_CATCH_EXCEPTION warning in top level\n        methods.\n    -->\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.ExtendOneOneChatSession\" />\n        <Method name=\"handle200OK\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.GroupChatSession\" />\n        <Method name=\"addParticipant\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.GroupChatSession\" />\n        <Method name=\"addParticipants\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.OriginatingOne2OneChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.OriginatingAdhocGroupChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.OriginatingAdhocGroupChatSession\" />\n        <Method name=\"handle200OK\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.TerminatingAdhocGroupChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.TerminatingOne2OneChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.standfw.TerminatingStoreAndForwardMsgSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.RestartGroupChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager\" />\n        <Method name=\"sendSipMessageDeliveryStatus\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.protocol.msrp.ChunkReceiver\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.filetransfer.OriginatingFileSharingSession\" />\n        <Method name=\"handle200OK\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.filetransfer.OriginatingFileSharingSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.filetransfer.TerminatingFileSharingSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.richcall.image.OriginatingImageTransferSession\" />\n        <Method name=\"handle200OK\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.richcall.image.TerminatingImageTransferSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.richcall.image.OriginatingImageTransferSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.protocol.sip.SipInterface\" />\n        <Method name=\"&lt;init&gt;\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.RejoinGroupChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.RejoinGroupChatSession\" />\n        <Method name=\"handle200OK\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.im.chat.ExtendOneOneChatSession\" />\n        <Method name=\"run\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n    <Match>\n        <Class name=\"com.gsma.rcs.core.ims.service.terms.TermsConditionsService\"/>\n        <Method name=\"sendSipMessage\" />\n        <Bug pattern=\"REC_CATCH_EXCEPTION\" />\n    </Match>\n\n</FindBugsFilter>"
  },
  {
    "path": "core/jarfiles.txt",
    "content": "com/gsma/services/rcs/"
  },
  {
    "path": "core/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\r\n# to define the proguard.config property as described in that file.\r\n#\r\n# Add project specific ProGuard rules here.\r\n# By default, the flags in this file are appended to flags specified\r\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\r\n# You can edit the include path and order by changing the ProGuard\r\n# include property in project.properties.\r\n#\r\n# For more details, see\r\n#   http://developer.android.com/guide/developing/tools/proguard.html\r\n\r\n# Add any project specific keep options here:\r\n\r\n# If your project uses WebView with JS, uncomment the following\r\n# and specify the fully qualified class name to the JavaScript interface\r\n# class:\r\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\r\n#   public *;\r\n#}\r\n#-optimizationpasses 5\r\n-dontusemixedcaseclassnames\r\n-dontskipnonpubliclibraryclasses\r\n-dontpreverify\r\n-verbose\r\n#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*\r\n-keepattributes *Annotation*\r\n-dontshrink\r\n-dontoptimize\r\n\r\n-keep public class * extends android.app.Activity\r\n-keep public class * extends android.app.Application\r\n-keep public class * extends android.app.Service\r\n-keep public class * extends android.content.BroadcastReceiver\r\n-keep public class * extends android.content.ContentProvider\r\n-keep public class com.android.vending.licensing.ILicensingService\r\n\r\n-keepclasseswithmembernames class * {\r\n    native <methods>;\r\n}\r\n\r\n-keepclasseswithmembers class * {\r\n    public <init>(android.content.Context, android.util.AttributeSet);\r\n}\r\n\r\n-keepclasseswithmembers class * {\r\n    public <init>(android.content.Context, android.util.AttributeSet, int);\r\n}\r\n\r\n-keepclassmembers enum * {\r\n    public static **[] values();\r\n    public static ** valueOf(java.lang.String);\r\n}\r\n\r\n-keep class * implements android.os.Parcelable {\r\n  public static final android.os.Parcelable$Creator *;\r\n}\r\n\r\n-keepclassmembers class **.R$* {\r\n    public static <fields>;\r\n}\r\n\r\n-keep class com.gsma.rcs.addressbook.**\r\n-keep class com.gsma.rcs.platform.**\r\n-keep class com.gsma.rcs.provider.**\r\n-keep class com.gsma.rcs.service.**\r\n-keep class com.gsma.rcs.utils.**\r\n-keep class gov2.**\r\n-keep class javax2.**\r\n\r\n\r\n"
  },
  {
    "path": "core/proguard.cfg",
    "content": "#-optimizationpasses 5\n-dontusemixedcaseclassnames\n-dontskipnonpubliclibraryclasses\n-dontpreverify\n-verbose\n#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*\n-keepattributes *Annotation*\n-dontshrink\n-dontoptimize\n\n-keep public class * extends android.app.Activity\n-keep public class * extends android.app.Application\n-keep public class * extends android.app.Service\n-keep public class * extends android.content.BroadcastReceiver\n-keep public class * extends android.content.ContentProvider\n-keep public class com.android.vending.licensing.ILicensingService\n\n-keepclasseswithmembernames class * {\n    native <methods>;\n}\n\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context, android.util.AttributeSet);\n}\n\n-keepclasseswithmembers class * {\n    public <init>(android.content.Context, android.util.AttributeSet, int);\n}\n\n-keepclassmembers enum * {\n    public static **[] values();\n    public static ** valueOf(java.lang.String);\n}\n\n-keep class * implements android.os.Parcelable {\n  public static final android.os.Parcelable$Creator *;\n}\n\n-keepclassmembers class **.R$* {\n    public static <fields>;\n}\n\n-keep class com.gsma.rcs.addressbook.**\n-keep class com.gsma.rcs.platform.**\n-keep class com.gsma.rcs.provider.**\n-keep class com.gsma.rcs.service.**\n-keep class com.gsma.rcs.utils.**\n-keep class gov2.**\n-keep class javax2.**\n\n"
  },
  {
    "path": "core/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system use,\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n\nandroid.library=false\nproguard.config=proguard.cfg\n# Project target.\ntarget=android-23\n"
  },
  {
    "path": "core/res/layout/activity_permissions_alert_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    tools:context=\".service.permissions.PermissionsAlertDialog\">\n\n</RelativeLayout>\n"
  },
  {
    "path": "core/res/layout/provisioning.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v4.widget.DrawerLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <com.gsma.rcs.provisioning.local.SlidingTabLayout\n            android:id=\"@+id/sliding_tabs\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?attr/colorPrimaryDark\"\n            android:paddingLeft=\"20dp\"\n            android:paddingRight=\"20dp\"/>\n\n        <android.support.v4.view.ViewPager\n            android:id=\"@+id/viewpager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0px\"\n            android:layout_weight=\"1\"\n            android:background=\"@android:color/white\"/>\n    </LinearLayout>\n\n    <ListView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:layout_marginTop=\"?attr/actionBarSize\"\n        android:background=\"?attr/colorPrimaryDark\"\n        android:choiceMode=\"singleChoice\"\n        android:divider=\"@android:color/white\"\n        android:dividerHeight=\"1dp\"\n        android:drawSelectorOnTop=\"false\"/>\n\n</android.support.v4.widget.DrawerLayout>"
  },
  {
    "path": "core/res/layout/provisioning_capabilities.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:background=\"@color/material_blue_grey_800\"\n            android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/image_sharing\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/Image_sharing\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/video_sharing\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/Video_sharing\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/file_transfer_msrp\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/File_transfer_MSRP\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/file_transfer_http\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/File_transfer_HTTP\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/im\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/IM_session\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/im_group\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/IM_Group_session\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/ipvoicecall\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/IP_Voice_call\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/ipvideocall\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/IP_Video_call\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/cs_video\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/CS_video\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/presence_discovery\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/Presence_discovery\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/social_presence\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/Social_presence\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/geolocation_push\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/Geolocation_push\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/file_transfer_thumbnail\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/File_transfer_thumbnail\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/file_transfer_sf\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/File_transfer_Store_Forward\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/group_chat_sf\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/Group_chat_Store_Forward\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/sip_automata\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/SIP_automata\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/call_composer\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/call_composer\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/shared_map\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/shared_map\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/shared_sketch\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/shared_sketch\"\n            android:textStyle=\"bold\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/post_call\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:enabled=\"true\"\n            android:text=\"@string/post_call\"\n            android:textStyle=\"bold\"/>\n\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "core/res/layout/provisioning_logger.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:background=\"@color/material_blue_grey_800\"\n            android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/TraceActivated\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Application_traces\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SipTraceActivated\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/SIP_traces\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/MediaTraceActivated\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Media_traces\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/SIP_traces_file\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipTraceFile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:lines=\"1\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Trace_level\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/TraceLevel\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n    </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "core/res/layout/provisioning_profile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:background=\"@color/material_blue_grey_800\"\n            android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/user_msg_title\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:id=\"@+id/user_msg_title\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:enabled=\"false\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/user_msg_content\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:id=\"@+id/user_msg_content\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:enabled=\"false\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/GSMA_release\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:id=\"@+id/release\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:enabled=\"false\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_authentication_procedure_for_Mobile_access\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/ImsAuthenticationProcedureForMobile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_username\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsUsername\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_display_name\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsDisplayName\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_home_domain\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsHomeDomain\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_private_URI_for_HTTP_Digest\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsPrivateId\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_password_for_HTTP_Digest\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsPassword\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_realm_for_HTTP_Digest\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsRealm\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/P_CSCF_address_for_Mobile_access\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsOutboundProxyAddrForMobile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/P_CSCF_port_for_Mobile_access\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsOutboundProxyPortForMobile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:maxLength=\"5\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/P_CSCF_address_for_Wi_Fi_access\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsOutboundProxyAddrForWifi\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/P_CSCF_port_for_Wi_Fi_access\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsOutboundProxyPortForWifi\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:maxLength=\"5\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/XDM_server_address\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/XdmServerAddr\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/XDM_server_login\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/XdmServerLogin\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/XDM_server_password\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/XdmServerPassword\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/FT_HTTP_server_address\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/FtHttpServerAddr\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/FT_HTTP_server_login\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/FtHttpServerLogin\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/FT_HTTP_server_password\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/FtHttpServerPassword\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IM_conference_URI\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImConferenceUri\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/End_user_confirmation_URI\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/EndUserConfReqUri\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:maxLength=\"100\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/APN\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/RcsApn\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"/>\n\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "core/res/layout/provisioning_service.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:background=\"@color/material_blue_grey_800\"\n            android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_photo_icon_size\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxPhotoIconSize\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_length_of_the_freetext\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxFreetextLength\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_number_of_participants_in_a_group_chat\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxChatParticipants\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"2\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_length_of_a_chat_message\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxChatMessageLength\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_length_of_a_group_chat_message\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxGroupChatMessageLength\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Idle_duration_of_a_chat_session_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ChatIdleDuration\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_size_of_a_file_transfer\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxFileTransferSize\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Threshold_warning_on_file_transfer_size\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/WarnFileTransferSize\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_size_of_an_image_share\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxImageShareSize\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_duration_of_a_video_share_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxVideoShareDuration\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_duration_of_audio_message_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxAudioMessageDuration\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n\n            android:text=\"@string/Max_number_of_simultaneous_chat_sessions\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxChatSessions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"2\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_number_of_simultaneous_file_transfer_sessions\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxFileTransferSessions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"2\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_number_of_concurrent_outgoing_file_transfer_sessions\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxConcurrentOutgoingFileTransferSessions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"2\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_number_of_simultaneous_IP_call_sessions\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxIpCallSessions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"2\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IM_session_start_mode\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/ImSessionStart\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_entries_per_contact_for_chat_history\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxChatLogEntries\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"4\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_entries_per_contact_for_richcall_history\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxRichcallLogEntries\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"4\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_entries_per_contact_for_IP_call_history\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxIpcallLogEntries\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"4\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_length_of_a_geolocation_label\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxGeolocLabelLength\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Expiration_time_of_a_geolocation_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/GeolocExpirationTime\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Idle_duration_of_a_callcomposer_session_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/CallComposerIdleDuration\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Directory_path_to_store_photos\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DirectoryPathPhotos\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"textUri\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Directory_path_to_store_videos\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DirectoryPathVideos\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"textUri\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Directory_path_to_store_audios\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DirectoryPathAudios\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"textUri\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Directory_path_to_store_files\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DirectoryPathFileIcons\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"textUri\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Directory_path_to_store_fileicons\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DirectoryPathFiles\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"textUri\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SmsFallbackService\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/SMS_fallback_service\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/StoreForwardServiceWarning\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Store_and_Forward_service_warning\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/AutoAcceptFileTransfer\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Auto_accept_file_transfer\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/AutoAcceptFileTransferInRoaming\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Auto_accept_file_transfer_in_roaming\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/AutoAcceptFileTransferChangeable\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Auto_accept_file_transfer_changeable\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/AutoAcceptChat\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Auto_accept_chat_invitation\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/AutoAcceptGroupChat\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Auto_accept_group_chat_invitation\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/EnrichCalling\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/EnrichCalling_support\"/>\n    </LinearLayout>\n</ScrollView>"
  },
  {
    "path": "core/res/layout/provisioning_stack.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:background=\"@color/material_blue_grey_800\"\n            android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/config_mode\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/Autoconfig\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Vendor\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:id=\"@+id/client_vendor\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:enabled=\"false\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/enable_rcs_switch\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/EnableRcsSwitch\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Secondary_provisioning_server\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SecondaryProvisioningAddress\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"text\"\n            android:lines=\"1\"\n            android:maxLength=\"100\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SecondaryProvisioningAddressOnly\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Use_only_the_secondary_provisioning_server\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Network_access\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/NetworkAccess\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/IMS_service_polling_period_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/ImsServicePollingPeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Default_protocol_for_file_transfer\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/FtProtocol\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Default_SIP_protocol_for_Mobile_access\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/SipDefaultProtocolForMobile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Default_SIP_protocol_for_Wi_Fi_access\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/SipDefaultProtocolForWifi\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/TLS_root_or_self_signed_certificate_from_sdcard\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/TlsCertificateRoot\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/TLS_intermediate_certificate_from_sdcard\"/>\n\n        <android.support.v7.widget.AppCompatSpinner\n            android:id=\"@+id/TlsCertificateIntermediate\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:drawSelectorOnTop=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Default_SIP_port\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipListeningPort\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/SIP_timer_base_T1_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipTimerT1\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/SIP_timer_T2_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipTimerT2\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/SIP_timer_T4_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipTimerT4\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/SIP_keep_alive_period_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipKeepAlivePeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"8\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/SIP_transaction_timeout\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SipTransactionTimeout\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"6\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Default_TCP_port_for_MSRP_session\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DefaultMsrpPort\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Default_UDP_port_for_RTP_session\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/DefaultRtpPort\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/MSRP_transaction_timeout_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MsrpTransactionTimeout\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"8\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Registration_expire_period_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/RegisterExpirePeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Registration_retry_base_time_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/RegisterRetryBaseTime\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Registration_retry_max_time_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/RegisterRetryMaxTime\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Publish_expire_period_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/PublishExpirePeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Revoke_timeout_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/RevokeTimeout\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Ringing_session_period\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/RingingPeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"10\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Subscribe_expiration_timeout_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SubscribeExpirePeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Is_composing_timeout_for_chat_ms\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/IsComposingTimeout\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"5\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Session_refresh_expire_period_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/SessionRefreshExpirePeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"number\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Capability_refresh_timeout_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/CapabilityRefreshTimeout\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Capability_expiry_timeout_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/CapabilityExpiryTimeout\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Capability_polling_period_milliseconds\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/CapabilityPollingPeriod\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"13\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Max_MSRP_length_for_extensions_bytes\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MaxMsrpLengthExtensions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"6\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatTextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Messaging_capabilities_validity\"/>\n\n        <android.support.v7.widget.AppCompatEditText\n            android:id=\"@+id/MessagingCapabilitiesValidity\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:inputType=\"numberSigned\"\n            android:lines=\"1\"\n            android:maxLength=\"6\"\n            android:singleLine=\"true\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/TcpFallback\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:paddingTop=\"5dip\"\n            android:text=\"@string/Enable_SIP_TCP_fallback\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SipKeepAlive\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Enable_SIP_keep_alive\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/TelUriFormat\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Tel_URI_format\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/ImAlwaysOn\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/IM_always_on\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/FtAlwaysOn\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/FT_always_on\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/FtHttpAlwaysOn\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/FT_HTTP_always_on\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/InviteOnlyGroupchatSF\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Invite_Only_Groupchat_SF\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/ImUseReports\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/IM_delivery_reports\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/PermanentState\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Permanent_state_mode\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/Gruu\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/GRUU\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/CpuAlwaysOn\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/CPU_Always_on\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SecureMsrpOverWifi\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Secure_MSRP_over_Wi_Fi_access\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SecureRtpOverWifi\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:enabled=\"false\"\n            android:text=\"@string/Secure_RTP_over_Wi_Fi_access\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SecureMsrpOverMobile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Secure_MSRP_over_Mobile_access\" />\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/SecureRtpOverMobile\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:enabled=\"false\"\n            android:text=\"@string/Secure_RTP_over_Mobile_access\" />\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/ImeiAsDeviceId\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/IMEI_as_device_ID\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/ControlExtensions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Control_extensions\"/>\n\n        <android.support.v7.widget.AppCompatCheckBox\n            android:id=\"@+id/AllowExtensions\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/Allow_extensions\"/>\n    </LinearLayout>\n</ScrollView>\n"
  },
  {
    "path": "core/res/layout/rcs_provisioning_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\" >\n\n    <ImageView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"10dp\"\n        android:layout_marginTop=\"10dp\"\n        android:src=\"@drawable/rcs_icon\" >\n    </ImageView>\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:text=\"@string/label_about_title\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\"\n        android:textStyle=\"bold\" />\n\n    <TextView\n        android:id=\"@+id/app_version\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <TextView\n        android:id=\"@+id/gsma_version\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n\n\n</LinearLayout>"
  },
  {
    "path": "core/res/layout/rcs_provisioning_generate_profile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\" >\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"5dip\"\n        android:text=\"@string/label_edit_msisdn\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n\n    <EditText\n        android:id=\"@+id/msisdn\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fadingEdge=\"vertical\"\n        android:gravity=\"top\"\n        android:lines=\"1\"\n        android:padding=\"5dip\"\n        android:inputType=\"phone\"\n        android:scrollbars=\"vertical\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"5dip\"\n        android:text=\"@string/label_select_provisioning_file\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n\n    <Spinner\n        android:id=\"@+id/XmlProvisioningFile\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\"\n        android:drawSelectorOnTop=\"true\" />\n\n</LinearLayout>"
  },
  {
    "path": "core/res/layout/rcs_terms_and_conditions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dip\"\n    android:orientation=\"vertical\" >\n\n    <TextView\n        android:id=\"@+id/title\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"5dip\"\n        android:padding=\"5dip\"\n        android:gravity=\"center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <ScrollView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"150dp\" >\n\n        <TextView\n            android:id=\"@+id/message\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dip\"\n            android:padding=\"5dip\"\n            android:autoLink=\"web\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\" />\n    </ScrollView>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"5dip\"\n        android:orientation=\"horizontal\" >\n\n        <Button\n            android:id=\"@+id/cancel_button\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/rcs_core_terms_decline\" />\n\n        <Button\n            android:id=\"@+id/ok_button\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/rcs_core_terms_accept\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "core/res/layout/rcs_wifi_provisioning.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dip\"\n    android:orientation=\"vertical\" >\n\n    <LinearLayout\n        android:id=\"@+id/normal_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" \n        android:orientation=\"vertical\">\n\n        <TextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dip\"\n            android:padding=\"5dip\"\n            android:text=\"@string/label_edit_msisdn\" />\n\n        <EditText\n            android:id=\"@+id/msisdn\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dip\"\n            android:inputType=\"phone\"\n            android:lines=\"1\"\n            android:padding=\"5dip\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dip\"\n            android:orientation=\"horizontal\" >\n\n            <Button\n                android:id=\"@+id/cancel_button\"\n                style=\"?android:attr/borderlessButtonStyle\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"@string/label_cancel\" />\n\n            <Button\n                android:id=\"@+id/ok_button\"\n                style=\"?android:attr/borderlessButtonStyle\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"@string/label_ok\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/error_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" \n        android:visibility=\"gone\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dip\"\n            android:padding=\"5dip\"\n            android:gravity=\"center_horizontal\"\n            android:text=\"@string/label_invalid_phone_number\" />\n\n        <Button\n            android:id=\"@+id/ok_error_button\"\n            style=\"?android:attr/borderlessButtonStyle\"\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/label_ok\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "core/res/menu/menu_provisioning.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/save\"\n        android:icon=\"@android:drawable/ic_menu_save\"\n        android:title=\"@string/save\"\n        app:showAsAction=\"ifRoom\">\n    </item>\n    <item\n        android:id=\"@+id/load\"\n        android:icon=\"@android:drawable/ic_menu_manage\"\n        android:title=\"@string/load\"\n        app:showAsAction=\"ifRoom|withText\">\n    </item>\n    <item\n        android:id=\"@+id/about\"\n        android:icon=\"@android:drawable/ic_menu_info_details\"\n        android:title=\"@string/info\"\n        app:showAsAction=\"ifRoom|withText\">\n    </item>\n</menu>"
  },
  {
    "path": "core/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "core/res/values/rcs_core_strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"rcs_core_application_title\">RCS services</string>\n    <string name=\"rcs_core_permission\">RCS</string>\n    <string name=\"rcs_core_permission_desc\">use RCS services</string>\n\n    <!-- Strings associated to ContactsContract menus -->\n    <string name=\"rcs_core_my_profile\">\\u0020My RCS profile</string>\n    \n    <string name=\"rcs_core_contact_file_transfer_summary\">Transfer a file via RCS</string>\n    <string name=\"rcs_core_contact_im_session_summary\">Initiate a chat via RCS </string>\n    <string name=\"rcs_core_contact_ip_voice_call_summary\">Start an IP voice call via RCS</string>\n    <string name=\"rcs_core_contact_ip_video_call_summary\">Start an IP video call via RCS</string>\n    <string name=\"rcs_core_contact_image_share_summary\">Share an image via RCS</string>\n    <string name=\"rcs_core_contact_video_share_summary\">Share a video via RCS</string>\n    \n    <string name=\"rcs_core_contact_file_transfer_details\">Transfer a file</string>\n    <string name=\"rcs_core_contact_im_session_details\">Initiate a chat</string>\n    <string name=\"rcs_core_contact_ip_voice_call_details\">Start an IP voice call</string>\n    <string name=\"rcs_core_contact_ip_video_call_details\">Start an IP video call</string>\n    <string name=\"rcs_core_contact_image_share_details\">Share an image</string>\n    <string name=\"rcs_core_contact_video_share_details\">Share a video</string>\n    <string name=\"rcs_core_contact_extensions_details\">Start a SIP session</string>\n\n    <!-- Strings linked to RCS account -->\n    <string name=\"rcs_core_account_id\">RCS</string>\n    <string name=\"rcs_core_account_username\">Rich Communication Suite</string>\n    <string name=\"rcs_core_account_main_title\">General settings</string>\n    <string name=\"rcs_core_account_menu_settings\">Settings</string>\n    <string name=\"rcs_core_account_configure\">Configure RCS service</string>\n    <string name=\"rcs_core_account_stopping_after_deletion\">The RCS service will be stopped as the RCS account was deleted</string>\n\n    <!-- Terms and Conditions -->\n    <string name=\"rcs_core_terms_title\">Terms and conditions</string>\n    <string name=\"rcs_core_terms_accept\">Accept</string>\n    <string name=\"rcs_core_terms_decline\">Decline</string>\n    <string name=\"rcs_core_terms_ok\">OK</string>\n\n    <!-- WIFI provisioning -->\n    <string name=\"label_ok\">OK</string>\n    <string name=\"label_cancel\">Cancel</string>\n    <string name=\"label_edit_msisdn\">Enter your phone number:</string>\n    <string name=\"label_invalid_phone_number\">This phone number is not valid</string>\n    \n</resources>"
  },
  {
    "path": "core/res/values/rcs_provisioning_strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\"\n\t\ttools:ignore=\"MissingTranslation\">\n\n    <string name=\"provisioning_app_name\">RCS Provisioning</string>\n    <string name=\"label_reboot_service\">The RCS service should be restarted before to take into account the modifications</string>\n    <string name=\"label_select_provisioning_file\">Select XML provisioning from /sdcard:</string>\n    <string name=\"label_generate_profile\">Load profile</string>\n    <string name=\"label_no_certificate\">No certificate</string>\n    <string name=\"label_parse_failed\">Cannot parse provisioning</string>\n    <string name=\"label_load_failed\">Cannot load provisioning</string>\n    <string name=\"label_sdcard_permission_not_granted\">SDCARD read permission not granted!</string>\n    <string name=\"label_no_xml_file\">No provisioning file</string>\n    <!-- rcs_provisioning_logger.xml -->\n    <string name=\"Application_traces\">Application traces</string>\n    <string name=\"SIP_traces\">SIP traces</string>\n    <string name=\"Media_traces\">Media traces</string>\n    <string name=\"SIP_traces_file\">SIP traces file:</string>\n    <string name=\"Trace_level\">Trace level:</string>\n    <!-- rcs_provisioning_profile.xml -->\n    <string name=\"user_msg_title\">User message title:</string>\n    <string name=\"user_msg_content\">User message content:</string>\n    <string name=\"GSMA_release\">GSMA release:</string>\n    <string name=\"IMS_authentication_procedure_for_Mobile_access\">IMS authentication procedure for Mobile access:</string>\n    <string name=\"IMS_username\">IMS username:</string>\n    <string name=\"IMS_display_name\">IMS display name:</string>\n    <string name=\"IMS_home_domain\">IMS home domain:</string>\n    <string name=\"IMS_private_URI_for_HTTP_Digest\">IMS private URI for HTTP Digest:</string>\n    <string name=\"IMS_password_for_HTTP_Digest\">IMS password for HTTP Digest:</string>\n    <string name=\"IMS_realm_for_HTTP_Digest\">IMS realm for HTTP Digest:</string>\n    <string name=\"P_CSCF_address_for_Mobile_access\">P-CSCF address for Mobile access:</string>\n    <string name=\"P_CSCF_port_for_Mobile_access\">P-CSCF port for Mobile access:</string>\n    <string name=\"P_CSCF_address_for_Wi_Fi_access\">P-CSCF address for Wi-Fi access:</string>\n    <string name=\"P_CSCF_port_for_Wi_Fi_access\">P-CSCF port for Wi-Fi access:</string>\n    <string name=\"XDM_server_address\">XDM server address:</string>\n    <string name=\"XDM_server_login\">XDM server login:</string>\n    <string name=\"XDM_server_password\">XDM server password:</string>\n    <string name=\"FT_HTTP_server_address\">FT HTTP server address:</string>\n    <string name=\"FT_HTTP_server_login\">FT HTTP server login:</string>\n    <string name=\"FT_HTTP_server_password\">FT HTTP server password:</string>\n    <string name=\"IM_conference_URI\">IM conference URI:</string>\n    <string name=\"End_user_confirmation_URI\">End user confirmation URI:</string>\n    <string name=\"APN\">APN:</string>\n    <string name=\"Image_sharing\">Image sharing</string>\n    <string name=\"Video_sharing\">Video sharing</string>\n    <string name=\"File_transfer_MSRP\">File transfer MSRP</string>\n    <string name=\"File_transfer_HTTP\">File transfer HTTP</string>\n    <string name=\"IM_session\">IM session</string>\n    <string name=\"IM_Group_session\">IM Group session</string>\n    <string name=\"IP_Voice_call\">IP Voice call</string>\n    <string name=\"IP_Video_call\">IP Video call</string>\n    <string name=\"CS_video\">CS video</string>\n    <string name=\"Presence_discovery\">Presence discovery</string>\n    <string name=\"Social_presence\">Social presence</string>\n    <string name=\"Geolocation_push\">Geolocation push</string>\n    <string name=\"File_transfer_thumbnail\">File transfer thumbnail</string>\n    <string name=\"File_transfer_Store_Forward\">File transfer Store &amp; Forward</string>\n    <string name=\"Group_chat_Store_Forward\">Group chat Store &amp; Forward</string>\n    <string name=\"SIP_automata\">SIP automata</string>\n    <string name=\"call_composer\">Call composer</string>\n    <string name=\"shared_map\">Shared map</string>\n    <string name=\"shared_sketch\">Shared sketch</string>\n    <string name=\"post_call\">Post call</string>\n    <!-- rcs_provisioning_service.xml -->\n    <string name=\"Max_photo_icon_size\">Max photo-icon size:</string>\n    <string name=\"Max_length_of_the_freetext\">Max length of the freetext:</string>\n    <string name=\"Max_number_of_participants_in_a_group_chat\">Max number of participants in a group chat:</string>\n    <string name=\"Max_length_of_a_chat_message\">Max length of a chat message:</string>\n    <string name=\"Max_length_of_a_group_chat_message\">Max length of a group chat message:</string>\n    <string name=\"Idle_duration_of_a_chat_session_milliseconds\">Idle duration of a chat session (milliseconds):</string>\n    <string name=\"Max_size_of_a_file_transfer\">Max size of a file transfer:</string>\n    <string name=\"Threshold_warning_on_file_transfer_size\">Threshold warning on file transfer size:</string>\n    <string name=\"Max_size_of_an_image_share\">Max size of an image share:</string>\n    <string name=\"Max_duration_of_a_video_share_milliseconds\">Max duration of a video share (milliseconds):</string>\n    <string name=\"Max_duration_of_audio_message_milliseconds\">Max duration of a audio message (milliseconds):</string>\n    <string name=\"Max_number_of_simultaneous_chat_sessions\">Max number of simultaneous chat sessions:</string>\n    <string name=\"Max_number_of_simultaneous_file_transfer_sessions\">Max number of simultaneous file transfer sessions:</string>\n    <string name=\"Max_number_of_concurrent_outgoing_file_transfer_sessions\">Max number of concurrent outgoing file transfer sessions:</string>\n    <string name=\"Max_number_of_simultaneous_IP_call_sessions\">Max number of simultaneous IP call sessions:</string>\n    <string name=\"IM_session_start_mode\">IM session start mode:</string>\n    <string name=\"Max_entries_per_contact_for_chat_history\">Max entries per contact for chat history:</string>\n    <string name=\"Max_entries_per_contact_for_richcall_history\">Max entries per contact for richcall history:</string>\n    <string name=\"Max_entries_per_contact_for_IP_call_history\">Max entries per contact for IP call history:</string>\n    <string name=\"Max_length_of_a_geolocation_label\">Max length of a geolocation label:</string>\n    <string name=\"Expiration_time_of_a_geolocation_milliseconds\">Expiration time of a geolocation (milliseconds):</string>\n    <string name=\"Directory_path_to_store_photos\">Directory path to store photos:</string>\n    <string name=\"Directory_path_to_store_videos\">Directory path to store videos:</string>\n    <string name=\"Directory_path_to_store_files\">Directory path to store files:</string>\n    <string name=\"Directory_path_to_store_fileicons\">Directory path to store file icons:</string>\n    <string name=\"SMS_fallback_service\">SMS fallback service</string>\n    <string name=\"Store_and_Forward_service_warning\">Store and Forward service warning</string>\n    <string name=\"Auto_accept_file_transfer\">Auto-accept file transfer</string>\n    <string name=\"Auto_accept_file_transfer_in_roaming\">Auto-accept file transfer in roaming</string>\n    <string name=\"Auto_accept_file_transfer_changeable\">Auto-accept file transfer changeable</string>\n    <string name=\"Auto_accept_chat_invitation\">Auto-accept chat invitation</string>\n    <string name=\"Auto_accept_group_chat_invitation\">Auto-accept group chat invitation</string>\n    <string name=\"EnrichCalling_support\">Enrich calling support</string>\n    <string name=\"Idle_duration_of_a_callcomposer_session_milliseconds\">Idle duration of a call composer session (milliseconds):</string>\n    <!-- rcs_provisioning_stack.xml -->\n    <string name=\"config_mode\">Configuration mode:</string>\n    <string name=\"Vendor\">Vendor:</string>\n    <string name=\"enable_rcs_switch\">Enable RCS switch:</string>\n    <string name=\"Secondary_provisioning_server\">Secondary provisioning server:</string>\n    <string name=\"Use_only_the_secondary_provisioning_server\">Use only the secondary provisioning server</string>\n    <string name=\"Network_access\">Network access:</string>\n    <string name=\"IMS_service_polling_period_milliseconds\">IMS service polling period (milliseconds):</string>\n    <string name=\"Default_protocol_for_file_transfer\">Default protocol for file transfer:</string>\n    <string name=\"Default_SIP_protocol_for_Mobile_access\">Default SIP protocol for Mobile access:</string>\n    <string name=\"Default_SIP_protocol_for_Wi_Fi_access\">Default SIP protocol for Wi-Fi access:</string>\n    <string name=\"TLS_root_or_self_signed_certificate_from_sdcard\">TLS root or self-signed certificate from /sdcard:</string>\n    <string name=\"TLS_intermediate_certificate_from_sdcard\">TLS intermediate certificate from /sdcard:</string>\n    <string name=\"Default_SIP_port\">Default SIP port:</string>\n    <string name=\"SIP_timer_base_T1_milliseconds\">SIP timer base T1 (milliseconds):</string>\n    <string name=\"SIP_timer_T2_milliseconds\">SIP timer T2 (milliseconds):</string>\n    <string name=\"SIP_timer_T4_milliseconds\">SIP timer T4 (milliseconds):</string>\n    <string name=\"SIP_keep_alive_period_milliseconds\">SIP keep-alive period (milliseconds):</string>\n    <string name=\"SIP_transaction_timeout\">SIP transaction timeout (ms):</string>\n    <string name=\"Default_TCP_port_for_MSRP_session\">Default TCP port for MSRP session:</string>\n    <string name=\"Default_UDP_port_for_RTP_session\">Default UDP port for RTP session:</string>\n    <string name=\"MSRP_transaction_timeout_milliseconds\">MSRP transaction timeout (milliseconds):</string>\n    <string name=\"Registration_expire_period_milliseconds\">Registration expire period (milliseconds):</string>\n    <string name=\"Registration_retry_base_time_milliseconds\">Registration retry base time (milliseconds):</string>\n    <string name=\"Registration_retry_max_time_milliseconds\">Registration retry max time (milliseconds):</string>\n    <string name=\"Publish_expire_period_milliseconds\">Publish expire period (milliseconds):</string>\n    <string name=\"Revoke_timeout_milliseconds\">Revoke timeout (milliseconds):</string>\n    <string name=\"Ringing_session_period\">Ringing session period (ms):</string>\n    <string name=\"Subscribe_expiration_timeout_milliseconds\">Subscribe expiration timeout (milliseconds):</string>\n    <string name=\"Is_composing_timeout_for_chat_ms\">Is-composing timeout for chat (milliseconds):</string>\n    <string name=\"Session_refresh_expire_period_milliseconds\">Session refresh expire period (milliseconds):</string>\n    <string name=\"Capability_refresh_timeout_milliseconds\">Capability refresh timeout (milliseconds):</string>\n    <string name=\"Capability_expiry_timeout_milliseconds\">Capability expiry timeout (milliseconds):</string>\n    <string name=\"Capability_polling_period_milliseconds\">Capability polling period (milliseconds):</string>\n    <string name=\"Max_MSRP_length_for_extensions_bytes\">Max MSRP length for extensions (bytes):</string>\n    <string name=\"Enable_SIP_TCP_fallback\">Enable SIP TCP fallback</string>\n    <string name=\"Enable_SIP_keep_alive\">Enable SIP keep-alive</string>\n    <string name=\"Tel_URI_format\">Tel-URI format</string>\n    <string name=\"IM_always_on\">IM always-on</string>\n    <string name=\"FT_always_on\">FT always-on</string>\n    <string name=\"FT_HTTP_always_on\">FT HTTP always-on</string>\n    <string name=\"Messaging_capabilities_validity\">Messaging capabilities validity (ms):</string>\n    <string name=\"Invite_Only_Groupchat_SF\">Groupchat Invite only if SF supported</string>\n    <string name=\"IM_delivery_reports\">IM delivery reports</string>\n    <string name=\"Permanent_state_mode\">Permanent state mode</string>\n    <string name=\"GRUU\">GRUU</string>\n    <string name=\"CPU_Always_on\">CPU Always on</string>\n    <string name=\"Secure_MSRP_over_Wi_Fi_access\">Secure MSRP over Wi-Fi access</string>\n    <string name=\"Secure_RTP_over_Wi_Fi_access\">Secure RTP over Wi-Fi access</string>\n    <string name=\"Secure_MSRP_over_Mobile_access\">Secure MSRP over mobile access</string>\n    <string name=\"Secure_RTP_over_Mobile_access\">Secure RTP over mobile access</string>\n    <string name=\"IMEI_as_device_ID\">IMEI as device ID</string>\n    <string name=\"Control_extensions\">Control extensions</string>\n    <string name=\"Allow_extensions\">Allow extensions</string>\n    <string name=\"load\">Load</string>\n    <string name=\"save\">Save</string>\n    <string name=\"info\">Info</string>\n    <string name=\"label_about_title\">RCS stack</string>\n    <string name=\"label_about\">About RCS service</string>\n    <string name=\"label_about_app_version\">App release %s</string>\n    <string name=\"Directory_path_to_store_audios\">Directory path to store audios</string>\n</resources>"
  },
  {
    "path": "core/res/values/rcs_settings_strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\"\n\t\ttools:ignore=\"MissingTranslation\">\n\n    <string-array name=\"provisioning_network_access\">\n        <item>All networks</item>\n        <item>Mobile only</item>\n        <item>Wi-Fi only</item>\n    </string-array>\n    <string-array name=\"provisioning_config_mode\">\n        <item>Manual</item>\n        <item>Automatic</item>\n    </string-array>\n    <string-array name=\"provisioning_enable_rcs_switch\">\n        <item>Only show in roaming</item>\n        <item>Always show</item>\n        <item>Never show</item>\n    </string-array>\n\n</resources>"
  },
  {
    "path": "core/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\"\n\t\ttools:ignore=\"MissingTranslation\">\n\n\t<style name=\"Theme.UserDialog\" parent=\"android:style/Theme.Dialog\">\n\t\t<item name=\"android:windowIsTranslucent\">false</item>\n\t\t<item name=\"android:windowNoTitle\">true</item>\n\t\t<item name=\"android:background\">@android:color/darker_gray</item>\n\t\t<item name=\"android:textColor\">@android:color/white</item>\n\t\t<item name=\"android:windowBackground\">@android:color/transparent</item>\n\t</style>\n\t<style name=\"Theme.Transparent\" parent=\"android:Theme\">\n\t\t<item name=\"android:windowIsTranslucent\">true</item>\n\t\t<item name=\"android:windowBackground\">@android:color/transparent</item>\n\t\t<item name=\"android:windowContentOverlay\">@null</item>\n\t\t<item name=\"android:windowNoTitle\">true</item>\n\t\t<item name=\"android:windowIsFloating\">true</item>\n\t\t<item name=\"android:backgroundDimEnabled\">false</item>\n\t</style>\n\n</resources>"
  },
  {
    "path": "core/res/values-de/rcs_core_strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"rcs_core_application_title\">RCS-Dienste</string>\n    <string name=\"rcs_core_permission\">RCS</string>\n    <string name=\"rcs_core_permission_desc\">RCS-Dienste nutzen</string>\n\n    <!-- Strings associated to ContactsContract menus -->\n    <string name=\"rcs_core_my_profile\">\\u0020Mein RCS-Profil</string>\n    \n    <string name=\"rcs_core_contact_file_transfer_summary\">Datei mittels RCS übertragen</string>\n    <string name=\"rcs_core_contact_im_session_summary\">Chat über RCS starten</string>\n    <string name=\"rcs_core_contact_ip_voice_call_summary\">IP-Telefonat über RCS starten</string>\n    <string name=\"rcs_core_contact_ip_video_call_summary\">IP-Video-Telefonat über RCS starten</string>\n    <string name=\"rcs_core_contact_image_share_summary\">Bild mittels RCS versenden</string>\n    <string name=\"rcs_core_contact_video_share_summary\">Video mittels RCS versenden</string>\n    \n    <string name=\"rcs_core_contact_file_transfer_details\">Datei übertragen</string>\n    <string name=\"rcs_core_contact_im_session_details\">Chat starten</string>\n    <string name=\"rcs_core_contact_ip_voice_call_details\">IP-Telefonat starten</string>\n    <string name=\"rcs_core_contact_ip_video_call_details\">IP-Video-Telefonat starten</string>\n    <string name=\"rcs_core_contact_image_share_details\">Bild versenden</string>\n    <string name=\"rcs_core_contact_video_share_details\">Video versenden</string>\n    <string name=\"rcs_core_contact_extensions_details\">SIP-Session starten</string>\n\n    <!-- Strings linked to RCS account -->\n    <string name=\"rcs_core_account_id\">RCS</string>\n    <string name=\"rcs_core_account_username\">Rich Communication Suite</string>\n    <string name=\"rcs_core_account_main_title\">Allgemeine Einstellungen</string>\n    <string name=\"rcs_core_account_menu_settings\">Einstellungen</string>\n    <string name=\"rcs_core_account_configure\">RCS-Dienst konfigurieren</string>\n    <string name=\"rcs_core_account_stopping_after_deletion\">Der RCS-Dienst wird beended, da das RCS-Nutzerkonto gelöscht wurde</string>\n\n    <!-- Terms and Conditions -->\n    <string name=\"rcs_core_terms_accept\">Akzeptieren</string>\n    <string name=\"rcs_core_terms_decline\">Ablehnen</string>\n    <string name=\"rcs_core_terms_ok\">Ok</string>\n\n    <!-- WIFI provisioning -->\n    <string name=\"rcs_core_terms_title\">RCS Nutzungsbedingungen</string>\n    <string name=\"label_ok\">OK</string>\n    <string name=\"label_cancel\">Abbrechen</string>\n    <string name=\"label_edit_msisdn\">Bitte Telefonnummer eingeben:</string>\n    <string name=\"label_invalid_phone_number\">Ungültige Telefonnummer</string>\n    \n</resources>"
  },
  {
    "path": "core/res/values-fr/rcs_core_strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"rcs_core_application_title\">RCS services</string>\n    <string name=\"rcs_core_permission\">RCS</string>\n    <string name=\"rcs_core_permission_desc\">utiliser les RCS services</string>\n\n    <!-- Strings associated to ContactsContract menus -->\n    <string name=\"rcs_core_my_profile\">\\u0020Mon profil RCS</string>\n    \n    <string name=\"rcs_core_contact_file_transfer_summary\">Transférer un fichier via RCS</string>\n    <string name=\"rcs_core_contact_im_session_summary\">Démarrer un chat via RCS</string>\n    <string name=\"rcs_core_contact_ip_voice_call_summary\">Démarrer un appel IP voix via RCS</string>\n    <string name=\"rcs_core_contact_ip_video_call_summary\">Démarrer un appel IP vidéo via RCS</string>\n    <string name=\"rcs_core_contact_image_share_summary\">Partager une image via RCS</string>\n    <string name=\"rcs_core_contact_video_share_summary\">Partager une vidéo via RCS</string>\n    \n    <string name=\"rcs_core_contact_file_transfer_details\">Transférer un fichier</string>\n    <string name=\"rcs_core_contact_im_session_details\">Démarrer une conversation</string>\n    <string name=\"rcs_core_contact_ip_voice_call_details\">Démarrer un appel IP voix</string>\n    <string name=\"rcs_core_contact_ip_video_call_details\">Démarrer un appel IP vidéo</string>\n    <string name=\"rcs_core_contact_image_share_details\">Partager une image</string>\n    <string name=\"rcs_core_contact_video_share_details\">Partager une vidéo</string>\n    <string name=\"rcs_core_contact_extensions_details\">Démarrer une session SIP</string>\n\n    <!-- Strings linked to RCS account -->\n    <string name=\"rcs_core_account_id\">RCS</string>\n    <string name=\"rcs_core_account_username\">Rich Communication Suite</string>\n    <string name=\"rcs_core_account_main_title\">Paramètres généraux</string>\n    <string name=\"rcs_core_account_menu_settings\">Paramètres</string>\n    <string name=\"rcs_core_account_configure\">Configurer le service RCS</string>\n    <string name=\"rcs_core_account_stopping_after_deletion\">Le service RCS sera arrêté lorsque le compte sera supprimé</string>\n\n    <!-- Terms and Conditions -->\n    <string name=\"rcs_core_terms_accept\">Accepter</string>\n    <string name=\"rcs_core_terms_decline\">Décliner</string>\n    <string name=\"rcs_core_terms_ok\">Ok</string>\n\n    <!-- WIFI provisioning -->\n    <string name=\"rcs_core_terms_title\">Conditions générales d\\'utilisation de RCS</string>\n    <string name=\"label_ok\">OK</string>\n    <string name=\"label_cancel\">Annuler</string>\n    <string name=\"label_edit_msisdn\">Veuillez renseigner votre numéro de téléphone:</string>\n    <string name=\"label_invalid_phone_number\">Ce numéro est incorrect</string>\n</resources>"
  },
  {
    "path": "core/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "core/res/xml/rcs_core_account_preferences.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <PreferenceCategory android:title=\"@string/rcs_core_account_main_title\" />\n\n    <PreferenceScreen\n        android:key=\"account_settings\"\n        android:summary=\"@string/rcs_core_account_configure\"\n        android:title=\"@string/rcs_core_account_menu_settings\" >\n        <intent android:action=\"com.gsma.services.rcs.action.VIEW_SETTINGS\" />\n    </PreferenceScreen>\n\n</PreferenceScreen>"
  },
  {
    "path": "core/res/xml/rcs_core_authenticator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- The attributes in this XML file provide configuration information -->\n<!-- for the Account Manager. -->\n\n<account-authenticator xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountPreferences=\"@xml/rcs_core_account_preferences\"\n    android:accountType=\"com.gsma.rcs\"\n    android:icon=\"@drawable/rcs_icon\"\n    android:label=\"@string/rcs_core_account_id\"\n    android:smallIcon=\"@drawable/rcs_icon\" />\n"
  },
  {
    "path": "core/res/xml/rcs_core_contacts.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ContactsSource xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <!-- This definition is important for the contact detail plugin -->\n    <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.image-share\"\n        android:summaryColumn=\"data2\" />\n    <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.video-share\"\n        android:summaryColumn=\"data2\" />\n    <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_core_chat_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.im-session\"\n        android:summaryColumn=\"data2\" />\n    <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_core_ft_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.file-transfer\"\n        android:summaryColumn=\"data2\" />\n    <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_core_ipcall_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.ip-voice-call\"\n        android:summaryColumn=\"data2\" />\n   <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_core_ipcall_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.ip-video-call\"\n        android:summaryColumn=\"data2\" />\n    <ContactsDataKind\n        android:detailColumn=\"data3\"\n        android:detailSocialSummary=\"false\"\n        android:icon=\"@drawable/rcs_core_extension_icon\"\n        android:mimeType=\"vnd.android.cursor.item/com.gsma.services.rcs.extensions\"\n        android:summaryColumn=\"data2\" />\n\n</ContactsSource>"
  },
  {
    "path": "core/res/xml/rcs_core_syncadapter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- The attributes in this XML file provide configuration information -->\n<!-- for the SyncAdapter. -->\n\n<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:accountType=\"com.gsma.rcs\"\n    android:contentAuthority=\"com.android.contacts\"\n    android:supportsUploading=\"false\" />\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/AccountChangedReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.platform.registry.RegistryFactory;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.accounts.Account;\nimport android.content.BroadcastReceiver;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.widget.Toast;\n\n/**\n * The user changed an account (modify, delete or add) <br>\n * We cannot prevent the user deleting the account but we can detect the deletion\n */\npublic class AccountChangedReceiver extends BroadcastReceiver {\n    /**\n     * Account has been manually deleted\n     */\n    private static final String REGISTRY_RCS_ACCOUNT_MANUALY_DELETED = \"RcsAccountManualyDeleted\";\n\n    private static final Logger sLogger = Logger.getLogger(AccountChangedReceiver.class.getName());\n\n    @Override\n    public void onReceive(final Context context, final Intent intent) {\n        Core.getInstance().scheduleCoreOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    ContentResolver contentResolver = context.getContentResolver();\n                    LocalContentResolver localContentResolver = new LocalContentResolver(\n                            contentResolver);\n                    RcsSettings rcsSettings = RcsSettings.getInstance(localContentResolver);\n                    AndroidFactory.setApplicationContext(context, rcsSettings);\n                    ContactManager contactManager = ContactManager.getInstance(context,\n                            contentResolver, localContentResolver, rcsSettings);\n                    RcsAccountManager accountUtility = RcsAccountManager.getInstance(context,\n                            contactManager);\n\n                    /* Verify that the RCS account is still here */\n                    Account mAccount = accountUtility.getAccount(context\n                            .getString(R.string.rcs_core_account_username));\n                    if (mAccount == null) {\n                        boolean logActivated = sLogger.isActivated();\n                        if (logActivated) {\n                            sLogger.debug(\"RCS account has been deleted: stop services\");\n                        }\n                        /* Set the user account manually deleted flag */\n                        if (rcsSettings.isUserProfileConfigured()) {\n                            setAccountResetByEndUser(true);\n                        }\n                        /*\n                         * RCS account was deleted. Warn the user we stop the service. The account\n                         * will be recreated when the service will be restarted.\n                         */\n                        Toast.makeText(\n                                context,\n                                context.getString(R.string.rcs_core_account_stopping_after_deletion),\n                                Toast.LENGTH_LONG).show();\n\n                        /* Stop the service */\n                        LauncherUtils.stopRcsService(context);\n                    } else {\n                        /* Set the user account manually deleted flag */\n                        setAccountResetByEndUser(false);\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\n                                    \"Unable to handle connection event for intent action : \")\n                                    .append(intent.getAction()).toString(), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Is user account reset by end user\n     * \n     * @return Boolean\n     */\n    public static boolean isAccountResetByEndUser() {\n        return RegistryFactory.getFactory()\n                .readBoolean(REGISTRY_RCS_ACCOUNT_MANUALY_DELETED, false);\n    }\n\n    /**\n     * Set user account reset by end user\n     * \n     * @param value True if RCS account is reseted by end user\n     */\n    public static void setAccountResetByEndUser(boolean value) {\n        RegistryFactory.getFactory().writeBoolean(REGISTRY_RCS_ACCOUNT_MANUALY_DELETED, value);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/AddressBookEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\n\n/**\n * Address book event listener\n */\npublic interface AddressBookEventListener {\n    /**\n     * Address book content has changed\n     * \n     * @throws ContactManagerException\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void handleAddressBookHasChanged() throws ContactManagerException, PayloadException,\n            NetworkException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/AddressBookManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.ContentResolver;\nimport android.database.ContentObserver;\nimport android.database.Cursor;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.provider.ContactsContract.CommonDataKinds.Phone;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * Address book manager:<br>\n * <br>\n * This manager is responsible of the synchronization between the native address book and the RCS\n * contacts. <br>\n * It observes the modifications done to the ContactsContract provider and revokes the missing\n * contacts. <br>\n * It also is responsible for creating the contacts if missing at first launch of the service. <br>\n * For more information, see the corresponding chapter in specifications.\n */\npublic class AddressBookManager {\n    /**\n     * Address book changed event listeners\n     */\n    private List<AddressBookEventListener> listeners = new ArrayList<AddressBookEventListener>();\n\n    private ContentResolver mContentResolver;\n\n    /**\n     * Cursor used to observe ContactsContract\n     */\n    private Cursor mContactsContractCursor;\n\n    private ContactsContractObserver mContactsContractObserver;\n\n    private CheckHandler mCheckHandler = new CheckHandler();\n\n    /**\n     * Check message ID\n     */\n    private final static int CHECK_MESSAGE = 5765;\n\n    /**\n     * Minimum period awaited before we do the checking in milliseconds\n     */\n    private final static long MINIMUM_CHECK_PERIOD = 1 * 1000;\n\n    /**\n     * Content observer registered flag\n     */\n    private boolean mObserverIsRegistered = false;\n\n    /**\n     * Background service executor\n     */\n    private ExecutorService mCleanupExecutor;\n\n    private static final Logger sLogger = Logger.getLogger(AddressBookManager.class.getName());\n\n    private ContactManager mContactManager;\n\n    /**\n     * Constructor\n     * \n     * @param contentResolver The content resolver\n     * @param contactManager Contact manager accessor\n     */\n    public AddressBookManager(ContentResolver contentResolver, ContactManager contactManager) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Address book manager is created\");\n        }\n        mContentResolver = contentResolver;\n        mContactManager = contactManager;\n    }\n\n    /**\n     * Start address book monitoring\n     */\n    public void start() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start address book monitoring\");\n        }\n        /* Instantiate background executor */\n        mCleanupExecutor = Executors.newSingleThreadExecutor();\n\n        if (!mObserverIsRegistered) {\n            /* Instantiate content observer */\n            mContactsContractObserver = new ContactsContractObserver(new Handler());\n\n            mContactsContractCursor = mContentResolver.query(Phone.CONTENT_URI, null, null, null,\n                    null);\n            CursorUtil.assertCursorIsNotNull(mContactsContractCursor, Phone.CONTENT_URI);\n\n            mContactsContractCursor.registerContentObserver(mContactsContractObserver);\n            mObserverIsRegistered = true;\n        }\n    }\n\n    /**\n     * Stop address book monitoring\n     */\n    public void stop() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Stop address book monitoring\");\n        }\n        /* Remove the messages that may still be scheduled */\n        mCheckHandler.removeMessages(CHECK_MESSAGE);\n\n        /* Unregister content observer */\n        if (mObserverIsRegistered) {\n            mContactsContractCursor.unregisterContentObserver(mContactsContractObserver);\n            mObserverIsRegistered = false;\n            mContactsContractCursor.close();\n        }\n\n        mCleanupExecutor.shutdownNow();\n    }\n\n    /**\n     * Add a listener\n     * \n     * @param listener Listener\n     */\n    public void addAddressBookListener(AddressBookEventListener listener) {\n        listeners.add(listener);\n    }\n\n    /**\n     * Remove a listener\n     * \n     * @param listener Listener\n     */\n    public void removeAddressBookListener(AddressBookEventListener listener) {\n        listeners.remove(listener);\n    }\n\n    /**\n     * Remove all listeners\n     */\n    public void removeAllAddressBookListeners() {\n        listeners.clear();\n    }\n\n    /**\n     * ContactsContract observer\n     */\n    private class ContactsContractObserver extends ContentObserver {\n\n        public ContactsContractObserver(Handler handler) {\n            super(handler);\n        }\n\n        @Override\n        public void onChange(boolean selfChange) {\n            super.onChange(selfChange);\n\n            // Something changed in the address book\n            if (!mCheckHandler.hasMessages(CHECK_MESSAGE)) {\n                // If we do not have a check already scheduled, schedule a new one\n                mCheckHandler.sendEmptyMessageDelayed(CHECK_MESSAGE, MINIMUM_CHECK_PERIOD);\n                if (sLogger.isActivated()) {\n                    sLogger.debug(new StringBuilder(\"New address book checking scheduled in \")\n                            .append(MINIMUM_CHECK_PERIOD).append(\" ms\").toString());\n                }\n            }\n        }\n    }\n\n    /**\n     * Handler used to avoid too many checks\n     */\n    private class CheckHandler extends Handler {\n        private boolean mCleanupNeeded;\n        private boolean mCleanupRunning;\n        private final Object mCheck = new Object();\n\n        @Override\n        public void handleMessage(Message msg) {\n            super.handleMessage(msg);\n\n            if (msg.what == CHECK_MESSAGE) {\n                /* Clean RCS entries associated to numbers that have been removed or modified */\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Minimum check period elapsed, notify listeners that a change occurred in the address book\");\n                }\n\n                /*\n                 * We may receive multiple CHECK_MESSAGE messages while already processing one. We\n                 * cannot stay in the handler for too long because the application will be killed as\n                 * ANR. Thus, we will schedule the processing if is is not running or tell the\n                 * running task that it will have to do it again once it is done.\n                 */\n                boolean scheduleCleanup = false;\n                synchronized (mCheck) {\n                    if (mCleanupRunning) {\n                        /* We need to re-do it again */\n                        mCleanupNeeded = true;\n                    } else {\n                        scheduleCleanup = true;\n                    }\n                }\n\n                if (scheduleCleanup) {\n                    mCleanupExecutor.execute(new Runnable() {\n                        public void run() {\n                            try {\n                                mCleanupRunning = true;\n\n                                while (true) {\n                                    mCleanupNeeded = false;\n\n                                    /*\n                                     * Clean RCS entries associated to numbers that have been\n                                     * removed or modified\n                                     */\n                                    mContactManager.cleanRCSEntries();\n\n                                    for (AddressBookEventListener listener : listeners) {\n                                        listener.handleAddressBookHasChanged();\n                                    }\n                                    synchronized (mCheck) {\n                                        if (!mCleanupNeeded) {\n                                            mCleanupRunning = false;\n                                            break;\n                                        }\n                                    }\n                                }\n                            } catch (ContactManagerException e) {\n                                sLogger.error(\"Failed to check address book!\", e);\n                            } catch (PayloadException e) {\n                                sLogger.error(\"Failed to check address book!\", e);\n                            } catch (NetworkException e) {\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(e.getMessage());\n                                }\n                            } catch (RuntimeException e) {\n                                /*\n                                 * Intentionally catch runtime exceptions as else it will abruptly\n                                 * end the thread and eventually bring the whole system down, which\n                                 * is not intended.\n                                 */\n                                sLogger.error(\"Failed to check address book!\", e);\n                            }\n                        }\n                    });\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/AuthenticationService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.accounts.AbstractAccountAuthenticator;\nimport android.accounts.Account;\nimport android.accounts.AccountAuthenticatorResponse;\nimport android.accounts.AccountManager;\nimport android.accounts.NetworkErrorException;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.IBinder;\n\n/**\n * This class is a Service to authenticate the user's account information.\n */\npublic class AuthenticationService extends Service {\n\n    private RcsContactsAccountAuthenticator mAuthenticator;\n\n    private static final Logger sLogger = Logger.getLogger(AuthenticationService.class.getName());\n\n    /**\n     * Called by the system when the service is first created.\n     */\n    @Override\n    public void onCreate() {\n        mAuthenticator = new RcsContactsAccountAuthenticator(this);\n    }\n\n    /**\n     * When binding to the service, return an interface to Authenticator Service.\n     */\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (AccountManager.ACTION_AUTHENTICATOR_INTENT.equals(intent.getAction())) {\n            return mAuthenticator.getIBinder();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Bound with unknown intent: \".concat(intent.toString()));\n        }\n        return null;\n    }\n\n    /**\n     * This class is used for creating AccountAuthenticators.\n     */\n    final static class RcsContactsAccountAuthenticator extends AbstractAccountAuthenticator {\n        private final Context mContext;\n\n        public RcsContactsAccountAuthenticator(Context context) {\n            super(context);\n            mContext = context;\n        }\n\n        /**\n         * Adds an account of the specified accountType.\n         */\n        @Override\n        public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,\n                String authTokenType, String[] requiredFeatures, Bundle options)\n                throws NetworkErrorException {\n            /*\n             * Launch the login activity to add the account, letting it know that we got there by\n             * trying to add an account so it can check for an existing account.\n             */\n            Bundle bundle = new Bundle();\n            Intent intent = new Intent(mContext, SetupRcsAccount.class);\n            intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);\n            bundle.putParcelable(AccountManager.KEY_INTENT, intent);\n            return bundle;\n        }\n\n        /**\n         * Returns a Bundle that contains the Intent of the activity that can be used to edit the\n         * properties.\n         */\n        @Override\n        public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {\n            throw new UnsupportedOperationException();\n        }\n\n        /**\n         * Checks that the user knows the credentials of an account.\n         */\n        @Override\n        public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,\n                Bundle options) {\n            return null;\n        }\n\n        /**\n         * Gets the authtoken for an account.\n         */\n        @Override\n        public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,\n                String authTokenType, Bundle loginOptions) throws NetworkErrorException {\n            return null;\n        }\n\n        /**\n         * Ask the authenticator for a localized label for the given authTokenType.\n         */\n        @Override\n        public String getAuthTokenLabel(String authTokenType) {\n            return null;\n        }\n\n        /**\n         * Update the locally stored credentials for an account.\n         */\n        @Override\n        public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,\n                String authTokenType, Bundle loginOptions) {\n            return null;\n        }\n\n        /**\n         * Checks if the account supports all the specified authenticator specific features.\n         */\n        @Override\n        public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,\n                String[] features) throws NetworkErrorException {\n            Bundle result = new Bundle();\n            result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);\n            return result;\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/LocaleManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\n\nimport java.util.Locale;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * A class to update the displayed strings of the RCS contact address book when the Locale changes\n * \n * @author yplo6403\n */\npublic class LocaleManager {\n\n    private final static Logger sLogger = Logger.getLogger(LocaleManager.class.getSimpleName());\n\n    private ExecutorService mUpdateExecutor;\n    private final Context mCtx;\n    private final RcsSettings mRcsSettings;\n    private final ContactManager mContactManager;\n    private final LocaleUpdater mLocaleUpdater;\n    private LocaleChangedReceiver mLocaleChangedReceiver;\n    private final Core mCore;\n\n    /**\n     * Constructor\n     * \n     * @param ctx The app context\n     * @param core The Core instance\n     * @param rcsSettings The RCS settings accessor\n     * @param contactManager The contact manager\n     */\n    public LocaleManager(Context ctx, Core core, RcsSettings rcsSettings,\n            ContactManager contactManager) {\n        mCtx = ctx;\n        mCore = core;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n        mLocaleUpdater = new LocaleUpdater();\n    }\n\n    /**\n     * Starts Locale manager\n     */\n    public void start() {\n        mUpdateExecutor = Executors.newSingleThreadExecutor();\n        IntentFilter filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);\n        mLocaleChangedReceiver = new LocaleChangedReceiver();\n        mCtx.registerReceiver(mLocaleChangedReceiver, filter);\n        String displayLanguage = mRcsSettings.getDisplayLanguage();\n        if (displayLanguage == null\n                || !displayLanguage.equals(Locale.getDefault().getDisplayLanguage())) {\n            mUpdateExecutor.execute(mLocaleUpdater);\n        }\n    }\n\n    /**\n     * Stops Locale manager\n     */\n    public void stop() {\n        if (mLocaleChangedReceiver != null) {\n            mCtx.unregisterReceiver(mLocaleChangedReceiver);\n            mLocaleChangedReceiver = null;\n        }\n        mUpdateExecutor.shutdownNow();\n    }\n\n    private class LocaleUpdater implements Runnable {\n\n        @Override\n        public void run() {\n            try {\n                mContactManager.updateStrings();\n                mRcsSettings.setDisplayLanguage(Locale.getDefault().getDisplayLanguage());\n            } catch (ContactManagerException e) {\n                sLogger.error(\"Failed to update contact strings!\", e);\n            } catch (RuntimeException e) {\n                /*\n                 * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n                 * which should be handled/fixed within the code. However the cases when we are\n                 * executing operations on a thread unhandling such exceptions will eventually lead\n                 * to exit the system and thus can bring the whole system down, which is not\n                 * intended.\n                 */\n                sLogger.error(\"Failed to update contact strings!\", e);\n            }\n        }\n\n    }\n\n    private class LocaleChangedReceiver extends BroadcastReceiver {\n\n        @Override\n        public void onReceive(final Context ctx, final Intent intent) {\n            mCore.scheduleCoreOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"The Locale has changed, we update the RCS strings in Contacts\");\n                        }\n                        mUpdateExecutor.execute(mLocaleUpdater);\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\n                                new StringBuilder(\"Failed to update rcs locale for action : \")\n                                        .append(intent.getAction()).toString(), e);\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/RcsAccountException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\n/**\n * RCS account exception\n */\npublic class RcsAccountException extends Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsAccountException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsAccountException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/RcsAccountManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\n\nimport android.accounts.Account;\nimport android.accounts.AccountManager;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.os.Build;\nimport android.provider.ContactsContract;\nimport android.provider.ContactsContract.Groups;\n\n/**\n * RCS account manager\n */\npublic class RcsAccountManager {\n\n    private static volatile RcsAccountManager sInstance;\n\n    private final Context mContext;\n\n    private final AccountManager mAccountManager;\n\n    private final ContentResolver mContentResolver;\n\n    private final ContactManager mContactManager;\n\n    /**\n     * Account manager type\n     */\n    public static final String ACCOUNT_MANAGER_TYPE = \"com.gsma.rcs\";\n\n    private static final String CONTACTSCONTRACT_GROUPS_COLUMN_TITLE_RES = \"title_res\";\n    private static final String CONTACTSCONTRACT_GROUPS_COLUMN_RES_PACKAGE = \"res_package\";\n\n    /**\n     * Constructor\n     * \n     * @param context Application context\n     * @param contactManager accessor for contact provider\n     */\n    public RcsAccountManager(Context context, ContactManager contactManager) {\n        mContext = context;\n        mAccountManager = AccountManager.get(context);\n        mContentResolver = mContext.getContentResolver();\n        mContactManager = contactManager;\n    }\n\n    /**\n     * Get or create singleton instance of RcsAccountManager\n     * \n     * @param context Application context\n     * @param contactManager accessor for contact provider\n     * @return singleton instance of RcsAccountManager\n     */\n    public static RcsAccountManager getInstance(Context context, ContactManager contactManager) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (RcsAccountManager.class) {\n            if (sInstance == null) {\n                sInstance = new RcsAccountManager(context, contactManager);\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Gets the account for the specified name\n     * \n     * @param username The username\n     * @return The account or null if it does not exist\n     */\n    public Account getAccount(String username) {\n        for (Account account : mAccountManager.getAccountsByType(ACCOUNT_MANAGER_TYPE)) {\n            if (username.equals(account.name)) {\n                return account;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Creates the RCS account if it does not already exist\n     * \n     * @param username The user name\n     * @param enableSync true to enable synchronization\n     * @throws RcsAccountException thrown if RCS account failed to be created\n     */\n    public void createRcsAccount(String username, boolean enableSync) throws RcsAccountException {\n        try {\n            /* Save the account info into the AccountManager if needed */\n            Account account = getAccount(username);\n            if (account == null) {\n                account = new Account(username, ACCOUNT_MANAGER_TYPE);\n                AccountManager accountManager = AccountManager.get(mContext);\n                boolean resource = accountManager.addAccountExplicitly(account, null, null);\n                if (!resource) {\n                    throw new RcsAccountException(\"Failed to create RCS account for username '\"\n                            + username + \"'!\");\n                }\n            }\n            /* Set contacts sync for this account. */\n            if (enableSync) {\n                ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1);\n            }\n            ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, enableSync);\n            /* Insert RCS group if it does not exist */\n            if (ContactManager.INVALID_ID == mContactManager\n                    .getRcsGroupIdFromContactsContractGroups()) {\n                ContentValues contentValues = new ContentValues();\n                contentValues.put(Groups.ACCOUNT_NAME, username);\n                contentValues.put(Groups.ACCOUNT_TYPE, ACCOUNT_MANAGER_TYPE);\n                contentValues.put(Groups.GROUP_VISIBLE, false);\n                contentValues.put(Groups.TITLE, mContext.getString(R.string.rcs_core_account_id));\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                    contentValues.put(CONTACTSCONTRACT_GROUPS_COLUMN_TITLE_RES,\n                            R.string.rcs_core_account_id);\n                    contentValues.put(CONTACTSCONTRACT_GROUPS_COLUMN_RES_PACKAGE,\n                            mContext.getPackageName());\n                }\n                contentValues.put(Groups.GROUP_IS_READ_ONLY, 1);\n                mContentResolver.insert(Groups.CONTENT_URI, contentValues);\n            }\n            /* Create the \"Me\" item */\n            mContactManager.createMyContact();\n        } catch (ContactManagerException e) {\n            throw new RcsAccountException(new StringBuilder(\n                    \"Failed to create RCS account for username '\").append(username).append(\"'!\")\n                    .toString(), e);\n        }\n    }\n\n    /**\n     * Checks if sync is enabled.\n     * \n     * @param username The username\n     * @return True if sync is enabled\n     */\n    public boolean isSyncEnabled(String username) {\n        Account account = getAccount(username);\n        if (account == null) {\n            return false;\n        }\n        return ContentResolver.getSyncAutomatically(account, ContactsContract.AUTHORITY);\n    }\n\n    /**\n     * Removes all RCS accounts with the exception of the excludeUsername account\n     * \n     * @param excludeUsername The username for which the account should not be removed (can be null)\n     */\n    public void removeRcsAccount(String excludeUsername) {\n        for (Account account : mAccountManager.getAccountsByType(ACCOUNT_MANAGER_TYPE)) {\n            if (!account.name.equals(excludeUsername)) {\n                mAccountManager.removeAccount(account, null, null);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/SetupRcsAccount.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.accounts.AccountAuthenticatorResponse;\nimport android.accounts.AccountManager;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.os.Bundle;\n\n/**\n * Setup RCS account activity\n */\npublic class SetupRcsAccount extends android.accounts.AccountAuthenticatorActivity {\n\n    private static final Logger sLogger = Logger.getLogger(SetupRcsAccount.class.getSimpleName());\n\n    public void onCreate(Bundle icicle) {\n        super.onCreate(icicle);\n        try {\n            Context ctx = getApplicationContext();\n            ContentResolver contentResolver = ctx.getContentResolver();\n            LocalContentResolver localContentResolver = new LocalContentResolver(contentResolver);\n            RcsSettings rcsSettings = RcsSettings.getInstance(localContentResolver);\n            ContactManager contactManager = ContactManager.getInstance(ctx, contentResolver,\n                    localContentResolver, rcsSettings);\n            RcsAccountManager rcsAccountMngr = RcsAccountManager.getInstance(ctx, contactManager);\n\n            String rcsAccountUsername = getString(R.string.rcs_core_account_username);\n\n            rcsAccountMngr.createRcsAccount(rcsAccountUsername, true);\n\n            Bundle extras = getIntent().getExtras();\n            if (extras != null) {\n                AccountAuthenticatorResponse response = extras\n                        .getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);\n                Bundle result = new Bundle();\n                result.putString(AccountManager.KEY_ACCOUNT_NAME, rcsAccountUsername);\n                result.putString(AccountManager.KEY_ACCOUNT_TYPE,\n                        RcsAccountManager.ACCOUNT_MANAGER_TYPE);\n                response.onResult(result);\n\n                // Start the service\n                LauncherUtils.launchRcsService(ctx, false, false, rcsSettings);\n            }\n        } catch (RcsAccountException e) {\n            sLogger.error(\"Failed to set up RCS account!\", e);\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to set up RCS account!\", e);\n        }\n        finish();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/addressbook/SyncAdapterService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.addressbook;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.accounts.Account;\nimport android.app.Service;\nimport android.content.AbstractThreadedSyncAdapter;\nimport android.content.ContentProviderClient;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SyncResult;\nimport android.os.Bundle;\nimport android.os.IBinder;\n\n/**\n * Service to handle account sync. This is invoked with an intent with action\n * ACTION_AUTHENTICATOR_INTENT. It instantiates the sync adapter and returns its IBinder.\n */\npublic class SyncAdapterService extends Service {\n\n    private RcsContactsSyncAdapter mSyncAdapter;\n\n    /**\n     * Android content sync adapter\n     */\n    public static final String ANDROID_CONTENT_SYNCADPTER = \"android.content.SyncAdapter\";\n\n    private static final Logger logger = Logger.getLogger(SyncAdapterService.class.getSimpleName());\n\n    /**\n     * Called when the activity is first created.\n     */\n    @Override\n    public void onCreate() {\n        mSyncAdapter = new RcsContactsSyncAdapter(this);\n    }\n\n    /**\n     * When binding to the service, return an interface to our sync adpater.\n     */\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (ANDROID_CONTENT_SYNCADPTER.equals(intent.getAction())) {\n            return mSyncAdapter.getSyncAdapterBinder();\n        }\n        if (logger.isActivated()) {\n            logger.error(\"Bound with unknown intent: \".concat(intent.toString()));\n        }\n        return null;\n    }\n\n    /**\n     * Sync adapter that spawns a thread to invoke a sync operation.\n     */\n    private class RcsContactsSyncAdapter extends AbstractThreadedSyncAdapter {\n\n        public RcsContactsSyncAdapter(Context context) {\n            super(context, true /* autoInitialize */);\n        }\n\n        /**\n         * Perform a sync for this account.\n         */\n        @Override\n        public void onPerformSync(Account account, Bundle extras, String authority,\n                ContentProviderClient provider, SyncResult syncResult) {\n            if (logger.isActivated()) {\n                logger.debug(\"On performing sync has been called, but nothing to be done\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/Core.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core;\n\nimport com.gsma.rcs.addressbook.AddressBookManager;\nimport com.gsma.rcs.addressbook.LocaleManager;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.security.cert.KeyStoreManager;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.history.HistoryLog;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.utils.DeviceUtils;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\n\nimport java.io.IOException;\nimport java.security.KeyStoreException;\n\n/**\n * Core (singleton pattern)\n * \n * @author JM. Auffret\n */\npublic class Core {\n\n    private static final String BACKGROUND_THREAD_NAME = Core.class.getSimpleName();\n\n    private static volatile Core sInstance;\n\n    private CoreListener mListener;\n\n    private boolean mStarted = false;\n\n    private ImsModule mImsModule;\n\n    private AddressBookManager mAddressBookManager;\n\n    private static final Logger sLogger = Logger.getLogger(BACKGROUND_THREAD_NAME);\n\n    /**\n     * Handler to process messages & runnable associated with background thread.\n     */\n    private Handler mBackgroundHandler;\n\n    /**\n     * Boolean to check is the Core is stopping\n     */\n    private boolean mStopping = false;\n\n    private final LocaleManager mLocaleManager;\n\n    /**\n     * Returns the singleton instance\n     * \n     * @return Core instance\n     */\n    public static Core getInstance() {\n        return sInstance;\n    }\n\n    /**\n     * Instantiate the core\n     * \n     * @param ctx The application context\n     * @param listener Listener\n     * @param rcsSettings RcsSettings instance\n     * @param contentResolver The content resolver\n     * @param localContentResolver The local content resolver\n     * @param contactManager The contact manager\n     * @param messagingLog The messaging log accessor\n     * @param historyLog The history log accessor\n     * @param richCallHistory The richcall log accessor\n     * @return Core instance\n     * @throws IOException\n     * @throws KeyStoreException\n     */\n    public static Core createCore(Context ctx, CoreListener listener, RcsSettings rcsSettings,\n            ContentResolver contentResolver, LocalContentResolver localContentResolver,\n            ContactManager contactManager, MessagingLog messagingLog, HistoryLog historyLog,\n            RichCallHistory richCallHistory) throws IOException, KeyStoreException {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (Core.class) {\n            if (sInstance == null) {\n                KeyStoreManager.loadKeyStore(rcsSettings);\n                sInstance = new Core(ctx, listener, contentResolver, localContentResolver,\n                        rcsSettings, contactManager, messagingLog, historyLog, richCallHistory);\n            }\n        }\n        return sInstance;\n    }\n\n    /**\n     * Terminate the core\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    public synchronized static void terminateCore() throws PayloadException, NetworkException,\n            ContactManagerException {\n        if (sInstance == null) {\n            return;\n        }\n        sInstance.stopCore();\n        sInstance = null;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param ctx The application context\n     * @param listener Listener\n     * @param contentResolver The content resolver\n     * @param localContentResolver The local content resolver\n     * @param rcsSettings The RCS settings accessor\n     * @param contactManager The contact manager\n     * @param messagingLog The messaging log accessor\n     * @param historyLog The history log accessor\n     * @param richCallHistory The richcall log accessor\n     */\n    private Core(Context ctx, CoreListener listener, ContentResolver contentResolver,\n            LocalContentResolver localContentResolver, RcsSettings rcsSettings,\n            ContactManager contactManager, MessagingLog messagingLog, HistoryLog historyLog,\n            RichCallHistory richCallHistory) {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Terminal core initialization\");\n        }\n        mListener = listener;\n        if (logActivated) {\n            sLogger.info(\"My device UUID is \".concat(String.valueOf(DeviceUtils.getDeviceUUID(ctx))));\n        }\n        PhoneUtils.initialize(rcsSettings);\n        mAddressBookManager = new AddressBookManager(contentResolver, contactManager);\n        mLocaleManager = new LocaleManager(ctx, this, rcsSettings, contactManager);\n\n        mImsModule = new ImsModule(this, ctx, localContentResolver, rcsSettings, contactManager,\n                messagingLog, historyLog, richCallHistory, mAddressBookManager);\n        if (logActivated) {\n            sLogger.info(\"Terminal core is created with success\");\n        }\n    }\n\n    /**\n     * Initializes Core\n     */\n    public void initialize() {\n        final HandlerThread backgroundThread = new HandlerThread(BACKGROUND_THREAD_NAME);\n        backgroundThread.start();\n        mBackgroundHandler = new Handler(backgroundThread.getLooper());\n        mImsModule.initialize();\n    }\n\n    /**\n     * Returns the event listener\n     * \n     * @return Listener\n     */\n    public CoreListener getListener() {\n        return mListener;\n    }\n\n    /**\n     * Returns the IMS module\n     * \n     * @return IMS module\n     */\n    public ImsModule getImsModule() {\n        return mImsModule;\n    }\n\n    /**\n     * Schedule a background task on Handler for execution\n     */\n    public void scheduleCoreOperation(Runnable task) {\n        mBackgroundHandler.post(task);\n    }\n\n    /**\n     * Is core started\n     * \n     * @return Boolean\n     */\n    public boolean isStarted() {\n        return mStarted;\n    }\n\n    /**\n     * Start the terminal core\n     */\n    public synchronized void startCore() {\n        if (mStarted) {\n            return;\n        }\n        mImsModule.start();\n        mAddressBookManager.start();\n        mLocaleManager.start();\n        mListener.onCoreLayerStarted();\n\n        mStarted = true;\n        if (sLogger.isActivated()) {\n            sLogger.info(\"RCS core service has been started with success\");\n        }\n    }\n\n    /**\n     * Stop the terminal core\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void stopCore() throws PayloadException, NetworkException, ContactManagerException {\n        if (!mStarted) {\n            return;\n        }\n        mStopping = true;\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Stop the RCS core service\");\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n            mBackgroundHandler.getLooper().quitSafely();\n        } else {\n            mBackgroundHandler.getLooper().quit();\n        }\n        mLocaleManager.stop();\n        mAddressBookManager.stop();\n        mImsModule.stop();\n\n        mStopping = false;\n        mStarted = false;\n        if (logActivated) {\n            sLogger.info(\"RCS core service has been stopped with success\");\n        }\n        sInstance = null;\n        mListener.onCoreLayerStopped();\n    }\n\n    /**\n     * Returns the capability service\n     * \n     * @return Capability service\n     */\n    public CapabilityService getCapabilityService() {\n        return getImsModule().getCapabilityService();\n    }\n\n    /**\n     * Returns the richcall service\n     * \n     * @return Rich call service\n     */\n    public RichcallService getRichcallService() {\n        return getImsModule().getRichcallService();\n    }\n\n    /**\n     * Returns the IM service\n     * \n     * @return IM service\n     */\n    public InstantMessagingService getImService() {\n        return getImsModule().getInstantMessagingService();\n    }\n\n    /**\n     * Returns the SIP service\n     * \n     * @return SIP service\n     */\n    public SipService getSipService() {\n        return getImsModule().getSipService();\n    }\n\n    /**\n     * Returns True if Core is stopping\n     * \n     * @return True if Core is stopping\n     */\n    public boolean isStopping() {\n        return mStopping;\n    }\n\n    /**\n     * Sets the listener\n     * \n     * @param listener The Core listener\n     */\n    public void setListener(CoreListener listener) {\n        mListener = listener;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/CoreException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core;\n\n/**\n * Core module exception\n * \n * @author JM. Auffret\n */\npublic class CoreException extends java.lang.Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     *\n     * @param error Error message\n     */\n    public CoreException(String error) {\n        super(error);\n    }\n\n    /**\n     * Constructor\n     *\n     * @param error Error message\n     * @param exception the cause of this exception\n     */\n    public CoreException(String error, Exception exception) {\n        super(error, exception);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/CoreListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core;\n\nimport com.gsma.rcs.core.ims.ImsError;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Observer of core events\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface CoreListener {\n    /**\n     * Core layer has been started\n     */\n    public void onCoreLayerStarted();\n\n    /**\n     * Core layer has been stopped\n     */\n    public void onCoreLayerStopped();\n\n    /**\n     * Registered to IMS\n     */\n    public void onRegistrationSuccessful();\n\n    /**\n     * IMS registration has failed\n     * \n     * @param error Error\n     */\n    public void onRegistrationFailed(ImsError error);\n\n    /**\n     * Unregistered from IMS\n     * \n     * @param reason reason code for registration termmination\n     */\n    public void onRegistrationTerminated(RcsServiceRegistration.ReasonCode reason);\n\n    /**\n     * User terms confirmation request\n     * \n     * @param contact Remote server\n     * @param id Request ID\n     * @param type Type of request\n     * @param pin PIN number requested\n     * @param subject Subject\n     * @param text Text\n     * @param btnLabelAccept Label of Accept button\n     * @param btnLabelReject Label of Reject button\n     * @param timeout Timeout request in milliseconds\n     */\n    public void onUserConfirmationRequest(ContactId contact, String id, String type, boolean pin,\n            String subject, String text, String btnLabelAccept, String btnLabelReject, long timeout);\n\n    /**\n     * User terms confirmation acknowledge\n     * \n     * @param contact Remote server\n     * @param id Request ID\n     * @param status Status\n     * @param subject Subject\n     * @param text Text\n     */\n    public void onUserConfirmationAck(ContactId contact, String id, String status, String subject,\n            String text);\n\n    /**\n     * User terms notification\n     * \n     * @param contact Remote server\n     * @param id Request ID\n     * @param subject Subject\n     * @param text Text\n     * @param btnLabel Label of OK button\n     */\n    public void onUserNotification(ContactId contact, String id, String subject, String text,\n            String btnLabel);\n\n    /**\n     * SIM has changed\n     */\n    public void onSimChangeDetected();\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/FileAccessException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core;\n\n/**\n * To be thrown when access to file read / write operation fails. As IOException is too generic\n * exception this exception class is used as base exception for all I/O errors which are nto related\n * to network. So during implementation the moment we get a IOException from native api's that are\n * not network related, we should cast those to this exception.\n * <p>\n * These exceptions should be logged and need to be communicated properly to upper service layers.\n * </p>\n */\npublic class FileAccessException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public FileAccessException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public FileAccessException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ParseFailureException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core;\n\n/**\n * To be thrown when there is a failure in parsing documents or input source from network.\n * <p>\n * These exceptions should be logged and need to be communicated properly to upper service layers.\n * </p>\n */\npublic class ParseFailureException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ParseFailureException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ParseFailureException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/TerminalInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsServiceControl;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager.NameNotFoundException;\nimport android.os.Build;\n\n/**\n * Terminal information\n * \n * @author JM. Auffret\n * @author Deutsche Telekom AG\n */\npublic class TerminalInfo {\n\n    private static final Logger sLogger = Logger.getLogger(TerminalInfo.class.getName());\n\n    /**\n     * Product name\n     */\n    private static final String productName = \"RCS-client\";\n\n    /**\n     * Product version\n     */\n    private static String sProductVersion;\n\n    /**\n     * RCS client version. Client Version Value = Platform \"-\" VersionMajor \".\" VersionMinor\n     * Platform = Alphanumeric (max 9) VersionMajor = Number (2 char max) VersionMinor = Number (2\n     * char max)\n     */\n    private static final String CLIENT_VERSION_PREFIX = \"RCSAndr-\";\n\n    private static final String UNKNOWN = \"unknown\";\n\n    private static final char FORWARD_SLASH = '/';\n\n    private static final char HYPHEN = '-';\n\n    private static String sClientVersion;\n\n    private static String sBuildInfo;\n\n    private static String sClientInfo;\n\n    /**\n     * Returns the product name\n     * \n     * @return Name\n     */\n    public static String getProductName() {\n        return productName;\n    }\n\n    /**\n     * Returns the product version\n     * \n     * @return Version\n     */\n    public static String getProductVersion(Context ctx) {\n        if (sProductVersion == null) {\n            try {\n                sProductVersion = ctx.getPackageManager().getPackageInfo(\n                        RcsServiceControl.RCS_STACK_PACKAGENAME, 0).versionName;\n\n            } catch (NameNotFoundException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.error(\"Version Name not defined in Manifest\", e);\n                }\n                sProductVersion = UNKNOWN;\n            }\n        }\n        return sProductVersion;\n    }\n\n    /**\n     * Returns the product name + version\n     * \n     * @return product information\n     */\n    public static String getProductInfo() {\n        return productName + FORWARD_SLASH + sProductVersion;\n    }\n\n    /**\n     * Returns the client version as mentioned under versionName in AndroidManifest, prefixed with\n     * CLIENT_VERSION_PREFIX.\n     * <p>\n     * In case versionName is not found under AndroidManifest it will default to UNKNOWN.\n     * </p>\n     * \n     * @param ctx the context\n     * @return Client version\n     */\n    public static String getClientVersion(Context ctx) {\n        if (sClientVersion == null) {\n            sClientVersion = CLIENT_VERSION_PREFIX + getProductVersion(ctx);\n        }\n        return sClientVersion;\n    }\n\n    /**\n     * Returns the client vendor\n     * \n     * @return Build.MANUFACTURER\n     */\n    public static String getClientVendor() {\n        return (Build.MANUFACTURER != null) ? Build.MANUFACTURER : UNKNOWN;\n    }\n\n    /**\n     * Returns the terminal vendor\n     * \n     * @return Build.MANUFACTURER\n     */\n    public static String getTerminalVendor() {\n        return (Build.MANUFACTURER != null) ? Build.MANUFACTURER : UNKNOWN;\n    }\n\n    /**\n     * Returns the terminal model\n     * \n     * @return Build.DEVICE\n     */\n    public static String getTerminalModel() {\n        return (Build.DEVICE != null) ? Build.DEVICE : UNKNOWN;\n    }\n\n    /**\n     * Returns the terminal software version\n     * \n     * @return Build.DISPLAY\n     */\n    public static String getTerminalSoftwareVersion() {\n        return (Build.DISPLAY != null) ? Build.DISPLAY : UNKNOWN;\n    }\n\n    /**\n     * Get the build info\n     * \n     * @return build info\n     */\n    public static String getBuildInfo() {\n        if (sBuildInfo == null) {\n            final String buildVersion = getTerminalModel() + HYPHEN + getTerminalSoftwareVersion();\n            sBuildInfo = getTerminalVendor() + FORWARD_SLASH + buildVersion;\n        }\n        return sBuildInfo;\n    }\n\n    /**\n     * Returns the client_vendor '/' client_version\n     * \n     * @return client information\n     */\n    public static String getClientInfo() {\n        if (sClientInfo == null) {\n            sClientInfo = getClientVendor() + FORWARD_SLASH\n                    + getClientVersion(AndroidFactory.getApplicationContext());\n        }\n        return sClientInfo;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/access/MobileNetworkAccess.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.access;\n\nimport com.gsma.rcs.core.ims.security.cert.KeyStoreManager;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.telephony.TelephonyManager;\n\nimport java.io.IOException;\nimport java.security.cert.CertificateException;\n\n/**\n * Mobile access network\n * \n * @author jexa7410\n */\npublic class MobileNetworkAccess extends NetworkAccess {\n\n    private TelephonyManager mTelephonyManager;\n\n    private static final Logger sLogger = Logger.getLogger(MobileNetworkAccess.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     */\n    public MobileNetworkAccess(RcsSettings rcsSettings) {\n        super(rcsSettings);\n        mTelephonyManager = (TelephonyManager) AndroidFactory.getApplicationContext()\n                .getSystemService(Context.TELEPHONY_SERVICE);\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Mobile access has been created (interface \" + getNetworkName() + \")\");\n        }\n    }\n\n    /**\n     * Connect to the network access\n     * \n     * @param ipAddress Local IP address\n     */\n    public void connect(String ipAddress) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Network access connected (\" + ipAddress + \")\");\n        }\n        mIpAddress = ipAddress;\n        if (mRcsSettings.isSecureMsrpOverMobile()) {\n            try {\n                KeyStoreManager.updateClientCertificate(ipAddress);\n\n            } catch (CertificateException | IOException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.error(e.getMessage());\n                }\n            }\n        }\n    }\n\n    /**\n     * Disconnect from the network access\n     */\n    public void disconnect() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Network access disconnected\");\n        }\n        mIpAddress = null;\n    }\n\n    /**\n     * Return the type of access\n     * \n     * @return Type\n     */\n    public String getType() {\n        int type = mTelephonyManager.getNetworkType();\n        switch (type) {\n            case TelephonyManager.NETWORK_TYPE_GPRS:\n            case TelephonyManager.NETWORK_TYPE_EDGE:\n                return \"3GPP-GERAN\";\n            case TelephonyManager.NETWORK_TYPE_UMTS:\n            case TelephonyManager.NETWORK_TYPE_HSDPA:\n            case TelephonyManager.NETWORK_TYPE_HSUPA:\n            case TelephonyManager.NETWORK_TYPE_HSPA:\n                return \"3GPP-UTRAN-FDD\";\n            default:\n                return null;\n        }\n    }\n\n    /**\n     * Return the network name\n     * \n     * @return Name\n     */\n    public String getNetworkName() {\n        int type = mTelephonyManager.getNetworkType();\n        switch (type) {\n            case TelephonyManager.NETWORK_TYPE_GPRS:\n                return \"GPRS\";\n            case TelephonyManager.NETWORK_TYPE_EDGE:\n                return \"EDGE\";\n            case TelephonyManager.NETWORK_TYPE_UMTS:\n                return \"UMTS\";\n            case TelephonyManager.NETWORK_TYPE_HSDPA:\n                return \"HSDPA\";\n            case TelephonyManager.NETWORK_TYPE_HSUPA:\n                return \"HSUPA\";\n            case TelephonyManager.NETWORK_TYPE_HSPA:\n                return \"HSPA\";\n            default:\n                return \"unknown\";\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/access/NetworkAccess.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.access;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport java.io.IOException;\nimport java.security.cert.CertificateException;\n\n/**\n * Abstract network access\n * \n * @author jexa7410\n */\npublic abstract class NetworkAccess {\n\n    /**\n     * Local IP address given to the network access\n     */\n    protected String mIpAddress;\n\n    /**\n     * Type of access\n     */\n    protected String mType;\n\n    /**\n     * rcs settings\n     */\n    protected final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     */\n    public NetworkAccess(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Return the local IP address\n     * \n     * @return IP address\n     */\n    public String getIpAddress() {\n        return mIpAddress;\n    }\n\n    /**\n     * Return the type of access\n     * \n     * @return Type\n     */\n    public abstract String getType();\n\n    /**\n     * Return the network name\n     * \n     * @return Name\n     */\n    public abstract String getNetworkName();\n\n    /**\n     * Connect to the network access\n     * \n     * @param ipAddress Local IP address\n     * @throws CertificateException\n     * @throws IOException\n     */\n    public abstract void connect(String ipAddress) throws CertificateException, IOException;\n\n    /**\n     * Disconnect from the network access\n     */\n    public abstract void disconnect();\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/access/WifiNetworkAccess.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.access;\n\nimport com.gsma.rcs.core.ims.security.cert.KeyStoreManager;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.net.wifi.WifiInfo;\nimport android.net.wifi.WifiManager;\n\nimport java.io.IOException;\nimport java.security.cert.CertificateException;\n\n/**\n * Wifi access network\n * \n * @author jexa7410\n */\npublic class WifiNetworkAccess extends NetworkAccess {\n\n    private WifiManager mWifiManager;\n\n    private static final Logger sLogger = Logger.getLogger(WifiNetworkAccess.class.getSimpleName());\n\n    /**\n     * Constructor\n     */\n    public WifiNetworkAccess(RcsSettings rcsSettings) {\n        super(rcsSettings);\n        mWifiManager = (WifiManager) AndroidFactory.getApplicationContext().getSystemService(\n                Context.WIFI_SERVICE);\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Wi-Fi access has been created (interface \" + getType() + \")\");\n        }\n    }\n\n    /**\n     * Connect to the network access\n     * \n     * @param ipAddress Local IP address\n     * @throws CertificateException\n     * @throws IOException\n     */\n    public void connect(String ipAddress) throws CertificateException, IOException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Network access connected (\" + ipAddress + \")\");\n        }\n        mIpAddress = ipAddress;\n        if (mRcsSettings.isSecureMsrpOverWifi()) {\n            try {\n                KeyStoreManager.updateClientCertificate(ipAddress);\n\n            } catch (CertificateException | IOException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.error(e.getMessage());\n                }\n            }\n        }\n    }\n\n    /**\n     * Disconnect from the network access\n     */\n    public void disconnect() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Network access disconnected\");\n        }\n        mIpAddress = null;\n    }\n\n    /**\n     * Return the type of access\n     * \n     * @return Type\n     */\n    public String getType() {\n        WifiInfo info = mWifiManager.getConnectionInfo();\n        if (info.getLinkSpeed() <= 11) {\n            return \"IEEE-802.11b\";\n        }\n        return \"IEEE-802.11a\";\n    }\n\n    /**\n     * Return the network name\n     * \n     * @return Name\n     */\n    public String getNetworkName() {\n        String name = \"Wi-Fi \";\n        WifiInfo info = mWifiManager.getConnectionInfo();\n        if (info.getLinkSpeed() <= 11) {\n            name += \"802.11b\";\n        } else {\n            name += \"802.11a\";\n        }\n        name += \", SSID=\" + mWifiManager.getConnectionInfo().getSSID();\n        return name;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/AudioContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport android.net.Uri;\n\n/**\n * Audio content\n * \n * @author opob7414\n */\npublic class AudioContent extends MmContent {\n\n    /**\n     * Constructor\n     * \n     * @aparam encoding Encoding\n     */\n    public AudioContent(String encoding) {\n        super(encoding);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param audioFile URI\n     * @param encoding Encoding\n     * @param size Size\n     * @param fileName Filename\n     */\n    public AudioContent(Uri audioFile, String encoding, long size, String fileName) {\n        super(audioFile, encoding, size, fileName);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/ContentManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.MimeManager;\n\nimport android.net.Uri;\n\nimport java.io.File;\nimport java.util.Vector;\n\n/**\n * Multimedia content manager\n *\n * @author jexa7410\n */\npublic class ContentManager {\n    /**\n     * Generate an Uri for the received content\n     *\n     * @param fileName the file name\n     * @param mime the MIME type\n     * @param rcsSettings the RCS settings accessor\n     * @return Uri\n     */\n    public static Uri generateUriForReceivedContent(String fileName, String mime,\n            RcsSettings rcsSettings) {\n        /* Generate a file path */\n        String path;\n        if (MimeManager.isImageType(mime)) {\n            path = rcsSettings.getPhotoRootDirectory();\n\n        } else if (MimeManager.isVideoType(mime)) {\n            path = rcsSettings.getVideoRootDirectory();\n\n        } else if (MimeManager.isAudioType(mime)) {\n            path = rcsSettings.getAudioRootDirectory();\n\n        } else {\n            path = rcsSettings.getFileRootDirectory();\n        }\n        /*\n         * Check that the fileName will not overwrite existing file We modify it if a file of the\n         * same name exists, by appending _1 before the extension For example if image.jpeg exists,\n         * next file will be image_1.jpeg, then image_2.jpeg etc.\n         */\n        StringBuilder extension = new StringBuilder(\"\");\n        if ((fileName != null) && (fileName.indexOf('.') != -1)) {\n            // if extension is present, split it\n            extension = new StringBuilder(\".\")\n                    .append(fileName.substring(fileName.lastIndexOf('.') + 1));\n            fileName = fileName.substring(0, fileName.lastIndexOf('.'));\n        }\n        String destination = fileName;\n        int i = 1;\n        while (new File(path + destination + extension).exists()) {\n            destination = fileName + '_' + i;\n            i++;\n        }\n        /* Return free destination URI */\n        return Uri.fromFile(new File(path + destination + extension));\n    }\n\n    /**\n     * Create a content object\n     *\n     * @param uri Content URI\n     * @param mime MIME type\n     * @param size Content size\n     * @param fileName The file name\n     * @return Content instance\n     */\n    public static MmContent createMmContent(Uri uri, String mime, long size, String fileName) {\n        if (mime != null) {\n            if (MimeManager.isImageType(mime)) {\n                return new PhotoContent(uri, mime, size, fileName);\n            }\n            if (MimeManager.isVideoType(mime)) {\n                return new VideoContent(uri, mime, size, fileName);\n            }\n            if (MimeManager.isAudioType(mime)) {\n                return new AudioContent(uri, mime, size, fileName);\n            }\n            if (MimeManager.isVCardType(mime)) {\n                return new VisitCardContent(uri, mime, size, fileName);\n            }\n            if (MimeManager.isGeolocType(mime)) {\n                return new GeolocContent(uri, size, fileName);\n            }\n        }\n        return new FileContent(uri, size, fileName);\n    }\n\n    /**\n     * Create a live video content object\n     *\n     * @param codec Codec\n     * @param width Width\n     * @param height Height\n     * @return Content instance\n     */\n    public static LiveVideoContent createLiveVideoContent(String codec, int width, int height) {\n        LiveVideoContent videoContent = new LiveVideoContent(\"video/\" + codec);\n        videoContent.setWidth(width);\n        videoContent.setHeight(height);\n        return videoContent;\n    }\n\n    /**\n     * Create a generic live video content object\n     *\n     * @return Content instance\n     */\n    public static LiveVideoContent createGenericLiveVideoContent() {\n        return new LiveVideoContent(\"video/*\");\n    }\n\n    /**\n     * Create a live video content object\n     *\n     * @param sdp SDP part\n     * @return Content instance\n     */\n    public static LiveVideoContent createLiveVideoContentFromSdp(byte[] sdp) {\n        /* Parse the remote SDP part */\n        SdpParser parser = new SdpParser(sdp);\n        Vector<MediaDescription> media = parser.getMediaDescriptions();\n        if (media.size() == 0) { /* there is no media in SDP */\n            return null;\n        }\n        MediaDescription desc = media.elementAt(0);\n        if (media.size() == 1) {\n            /*\n             * if only one media in SDP, test if 'video', if not then return null.\n             */\n            if (!desc.mName.equals(\"video\")) {\n                return null;\n            }\n        }\n        if (media.size() == 2) {\n            /*\n             * if two media in SDP, test if first 'video', if not then choose second and test if\n             * video, if not return null.\n             */\n            if (!desc.mName.equals(\"video\")) {\n                desc = media.elementAt(1);\n                if (!desc.mName.equals(\"video\")) {\n                    return null;\n                }\n            }\n        }\n\n        String rtpmap = desc.getMediaAttribute(\"rtpmap\").getValue();\n        /* Extract the video encoding */\n        String encoding = rtpmap.substring(rtpmap.indexOf(desc.mPayload) + desc.mPayload.length()\n                + 1);\n        String codec = encoding.toLowerCase().trim();\n        int index = encoding.indexOf(\"/\");\n        if (index != -1) {\n            codec = encoding.substring(0, index);\n        }\n\n        /* Extract video size */\n        MediaAttribute frameSize = desc.getMediaAttribute(\"framesize\");\n        int width = 0;\n        int height = 0;\n        if (frameSize != null) {\n            try {\n                String value = frameSize.getValue();\n                index = value.indexOf(desc.mPayload);\n                int separator = value.indexOf('-');\n                if (index != -1 && separator != -1) {\n                    width = Integer.parseInt(value.substring(index + desc.mPayload.length() + 1,\n                            separator));\n                    height = Integer.parseInt(value.substring(separator + 1));\n                }\n            } catch (NumberFormatException e) {\n                /* Use default value */\n                width = H264Config.QCIF_WIDTH;\n                height = H264Config.QCIF_HEIGHT;\n            }\n        }\n\n        return createLiveVideoContent(codec, width, height);\n    }\n\n    /**\n     * Create a content object from SDP description of a SIP invite request\n     *\n     * @param invite SIP invite request\n     * @param rcsSettings the RCS settings accessor\n     * @return Content instance\n     * @throws PayloadException\n     */\n    public static MmContent createMmContentFromSdp(SipRequest invite, RcsSettings rcsSettings)\n            throws PayloadException {\n        String remoteSdp = invite.getSdpContent();\n        SipUtils.assertContentIsNotNull(remoteSdp, invite);\n        SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n        Vector<MediaDescription> media = parser.getMediaDescriptions();\n        MediaDescription desc = media.elementAt(0);\n        MediaAttribute attr1 = desc.getMediaAttribute(\"file-selector\");\n        String fileSelectorValue = attr1.getValue();\n        String mime = SipUtils.extractParameter(fileSelectorValue, \"type:\",\n                \"application/octet-stream\");\n        long size = Long.parseLong(SipUtils.extractParameter(fileSelectorValue, \"size:\", \"-1\"));\n        String filename = SipUtils.extractParameter(fileSelectorValue, \"name:\", \"\");\n        Uri file = ContentManager.generateUriForReceivedContent(filename, mime, rcsSettings);\n        MediaAttribute attr2 = desc.getMediaAttribute(\"file-disposition\");\n        String fileDispoValue = attr2.getValue();\n        MmContent content = ContentManager.createMmContent(file, mime, size, filename);\n        if (FileSharingSession.FILE_DISPOSITION_RENDER.equals(fileDispoValue)) {\n            content.setPlayable(true);\n        }\n        return content;\n    }\n\n    /**\n     * Get sent photo root directory\n     *\n     * @param rcsSettings the RCS settings accessor\n     * @return Path of sent photo root directory\n     */\n    public static String getSentPhotoRootDirectory(RcsSettings rcsSettings) {\n        return rcsSettings.getPhotoRootDirectory().concat(FileFactory.SENT_DIRECTORY);\n    }\n\n    /**\n     * Get sent video root directory\n     *\n     * @param rcsSettings the RCS settings accessor\n     * @return Path of sent video root directory\n     */\n    public static String getSentVideoRootDirectory(RcsSettings rcsSettings) {\n        return rcsSettings.getVideoRootDirectory().concat(FileFactory.SENT_DIRECTORY);\n    }\n\n    /**\n     * Get sent audio root directory\n     *\n     * @param rcsSettings the RCS settings accessor\n     * @return Path of sent audio root directory\n     */\n    public static String getSentAudioRootDirectory(RcsSettings rcsSettings) {\n        return rcsSettings.getAudioRootDirectory().concat(FileFactory.SENT_DIRECTORY);\n    }\n\n    /**\n     * Get sent file root directory\n     *\n     * @param rcsSettings the RCS settings accessor\n     * @return Path of sent file root directory\n     */\n    public static String getSentFileRootDirectory(RcsSettings rcsSettings) {\n        return rcsSettings.getFileRootDirectory().concat(FileFactory.SENT_DIRECTORY);\n    }\n\n    /**\n     * Generate Uri for saving the content that has to be transferred\n     *\n     * @param fileName the file name\n     * @param mime the MIME type\n     * @param rcsSettings the RCS settings accessor\n     * @return Uri\n     */\n    public static Uri generateUriForSentContent(String fileName, String mime,\n            RcsSettings rcsSettings) {\n        String path;\n        if (MimeManager.isImageType(mime)) {\n            path = getSentPhotoRootDirectory(rcsSettings);\n\n        } else if (MimeManager.isVideoType(mime)) {\n            path = getSentVideoRootDirectory(rcsSettings);\n\n        } else if (MimeManager.isAudioType(mime)) {\n            path = getSentAudioRootDirectory(rcsSettings);\n\n        } else {\n            path = getSentFileRootDirectory(rcsSettings);\n        }\n        /*\n         * Check that the fileName will not overwrite existing file We modify it if a file of the\n         * same name exists, by appending _1 before the extension For example if image.jpeg exists,\n         * next file will be image_1.jpeg, then image_2.jpeg etc.\n         */\n\n        if (fileName.indexOf('.') == -1) {\n            throw new RuntimeException(\"Filename without extension: fileName='\" + fileName + \"'!\");\n        }\n        /* if extension is present, split it */\n        int extPosition = fileName.lastIndexOf('.');\n        String extension = \".\" + fileName.substring(extPosition + 1);\n        fileName = fileName.substring(0, extPosition);\n        String destination = fileName;\n        int incrementIndex = 1;\n        File generatedFile = new File(path + destination + extension);\n        while (generatedFile.exists()) {\n            destination = fileName + '_' + incrementIndex;\n            generatedFile = new File(path + destination + extension);\n            incrementIndex++;\n        }\n        return Uri.fromFile(generatedFile);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/FileContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport android.net.Uri;\n\n/**\n * File content\n * \n * @author jexa7410\n */\npublic class FileContent extends MmContent {\n    /**\n     * Encoding type\n     */\n    public static final String ENCODING = \"application/octet-stream\";\n\n    /**\n     * Constructor\n     * \n     * @param file URI\n     * @param size Content size\n     * @param fileName Filename\n     */\n    public FileContent(Uri file, long size, String fileName) {\n        super(file, ENCODING, size, fileName);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/GeolocContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoDocument;\n\nimport android.net.Uri;\n\n/**\n * Geoloc content\n * \n * @author vfml3370\n */\npublic class GeolocContent extends MmContent {\n\n    private byte[] mData;\n\n    /**\n     * Encoding type\n     */\n    public static final String ENCODING = GeolocInfoDocument.MIME_TYPE;\n\n    /**\n     * Constructor\n     * \n     * @param fileName File name\n     * @param size Content size\n     * @param data Geoloc\n     */\n    public GeolocContent(String fileName, long size, byte[] data) {\n        super(fileName, size, ENCODING);\n        mData = data;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param geolocFile URI\n     * @param size Content size\n     * @param fileName Filename\n     */\n    public GeolocContent(Uri geolocFile, long size, String fileName) {\n        super(geolocFile, ENCODING, size, fileName);\n    }\n\n    public byte[] getData() {\n        return mData;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/LiveAudioContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\n/**\n * Live audio content\n * \n * @author opob7414\n */\npublic class LiveAudioContent extends AudioContent {\n    /**\n     * Liveaudio URL constant\n     */\n    public static final String URL = \"capture://audio\";\n\n    /**\n     * Constructor\n     * \n     * @param encoding Encoding\n     */\n    public LiveAudioContent(String encoding) {\n        super(encoding);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/LiveVideoContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\n/**\n * Live video content\n * \n * @author jexa7410\n */\npublic class LiveVideoContent extends VideoContent {\n    /**\n     * Livevideo URL constant\n     */\n    public static final String URL = \"capture://video\";\n\n    /**\n     * Constructor\n     * \n     * @param encoding Encoding\n     */\n    public LiveVideoContent(String encoding) {\n        super(encoding);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/MmContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.utils.CloseableUtils;\n\nimport android.content.ContentResolver;\nimport android.net.Uri;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\n/**\n * Multimedia content\n * \n * @author jexa7410\n */\npublic abstract class MmContent {\n\n    private Uri mUri;\n\n    private String mFileName;\n\n    private long mSize;\n\n    private String mEncoding;\n\n    private boolean mPlayable = false;\n\n    /**\n     * Stream to write received data directly to file.\n     */\n    private BufferedOutputStream mOut;\n\n    /**\n     * Constructor\n     * \n     * @param encoding Encoding\n     */\n    public MmContent(String encoding) {\n        mEncoding = encoding;\n        mSize = -1;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param fileName File name\n     * @param size Content size\n     * @param encoding Encoding\n     */\n    public MmContent(String fileName, long size, String encoding) {\n        mFileName = fileName;\n        mSize = size;\n        mEncoding = encoding;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param file Uri\n     * @param encoding Encoding\n     * @param size Content size\n     * @param fileName File name\n     */\n    public MmContent(Uri file, String encoding, long size, String fileName) {\n        mUri = file;\n        mEncoding = encoding;\n        mSize = size;\n        mFileName = fileName;\n    }\n\n    /**\n     * Returns the uri\n     * \n     * @return uri\n     */\n    public Uri getUri() {\n        return mUri;\n    }\n\n    /**\n     * Sets the uri\n     * \n     * @param uri Uri\n     */\n    public void setUri(Uri uri) {\n        mUri = uri;\n    }\n\n    /**\n     * Returns the content size in bytes\n     * \n     * @return Size in bytes\n     */\n    public long getSize() {\n        return mSize;\n    }\n\n    /**\n     * Returns the encoding type\n     * \n     * @return Encoding type\n     */\n    public String getEncoding() {\n        return mEncoding;\n    }\n\n    /**\n     * Set the encoding type\n     * \n     * @param encoding Encoding type\n     */\n    public void setEncoding(String encoding) {\n        mEncoding = encoding;\n    }\n\n    /**\n     * Returns the codec from the encoding type\n     * \n     * @return Codec name\n     */\n    public String getCodec() {\n        int index = mEncoding.indexOf(\"/\");\n        if (index != -1) {\n            return mEncoding.substring(index + 1);\n        }\n        return mEncoding;\n    }\n\n    /**\n     * Get the name\n     * \n     * @return Name\n     */\n    public String getName() {\n        return mFileName;\n    }\n\n    /**\n     * Set the name\n     * \n     * @param fileName the file name\n     */\n    public void setName(String fileName) {\n        mFileName = fileName;\n    }\n\n    /**\n     * Set content playable\n     *\n     * @param flag Playable flag\n     */\n    public void setPlayable(boolean flag) {\n        mPlayable = flag;\n    }\n\n    /**\n     * Is a playable content\n     *\n     * @return Boolean\n     */\n    public boolean isPlayable() {\n        return mPlayable;\n    }\n\n    /**\n     * Returns the string representation of a content\n     * \n     * @return String\n     */\n    public String toString() {\n        return mUri + \" (\" + mSize + \" bytes)\";\n    }\n\n    /**\n     * Write data chunk to file\n     * \n     * @param data Data to append to file\n     * @throws FileAccessException\n     */\n    public void writeData2File(byte[] data) throws FileAccessException {\n        try {\n            if (mOut == null) {\n                File destination = new File(mUri.getPath());\n                FileOutputStream fos = new FileOutputStream(destination);\n                /* To optimize I/O set buffer size to 8 kBytes */\n                mOut = new BufferedOutputStream(fos, 8 * 1024);\n            }\n            mOut.write(data);\n        } catch (IOException e) {\n            throw new FileAccessException(\"Failed to write data chunk to file!\", e);\n        }\n    }\n\n    /**\n     * Close written file and update media storage.\n     */\n    public void closeFile() {\n        try {\n            FileFactory.getFactory().updateMediaStorage(getUri().getEncodedPath());\n        } finally {\n            CloseableUtils.tryToClose(mOut);\n        }\n    }\n\n    /**\n     * Delete File.\n     * \n     * @throws IOException\n     */\n    public void deleteFile() throws IOException {\n        CloseableUtils.tryToClose(mOut);\n        Uri fileToDelete = getUri();\n        if (ContentResolver.SCHEME_FILE.equals(fileToDelete.getScheme())) {\n            File file = new File(fileToDelete.getPath());\n            if (!file.delete()) {\n                throw new IOException(\"Unable to delete file: \" + file.getAbsolutePath());\n            }\n        } else {\n            throw new IOException(\"Not possible to delete file: \" + fileToDelete);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/PhotoContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport android.net.Uri;\n\n/**\n * Photo content\n * \n * @author jexa7410\n */\npublic class PhotoContent extends MmContent {\n\n    /**\n     * Constructor\n     * \n     * @param photoFile URI\n     * @param encoding Encoding\n     * @param size Size\n     * @param fileName Filename\n     */\n    public PhotoContent(Uri photoFile, String encoding, long size, String fileName) {\n        super(photoFile, encoding, size, fileName);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/VideoContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport android.net.Uri;\n\n/**\n * Video content\n * \n * @author jexa7410\n */\npublic class VideoContent extends MmContent {\n\n    /**\n     * Height\n     */\n    private int height = 0;\n\n    /**\n     * Width\n     */\n    private int width = 0;\n\n    /**\n     * Constructor\n     * \n     * @aparam encoding Encoding\n     */\n    public VideoContent(String encoding) {\n        super(encoding);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param videoFile URI\n     * @param encoding Encoding\n     * @param size Content size\n     * @param fileName Filename\n     */\n    public VideoContent(Uri videoFile, String encoding, long size, String fileName) {\n        super(videoFile, encoding, size, fileName);\n    }\n\n    /**\n     * Set the width\n     * \n     * @param width width\n     */\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    /**\n     * Get the width\n     * \n     * @return width\n     */\n    public int getWidth() {\n        return width;\n    }\n\n    /**\n     * Set the height\n     * \n     * @param height height\n     */\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    /**\n     * Get the height\n     * \n     * @return height\n     */\n    public int getHeight() {\n        return height;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/content/VisitCardContent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.content;\n\nimport android.net.Uri;\n\n/**\n * Visit Card content\n * \n * @author vfml3370\n */\npublic class VisitCardContent extends MmContent {\n\n    /**\n     * Constructor\n     * \n     * @param visitCardFile URI\n     * @param encoding the mime-type encoding\n     * @param size Content size\n     * @param fileName The filename\n     */\n    public VisitCardContent(Uri visitCardFile, String encoding, long size, String fileName) {\n        super(visitCardFile, encoding, size, fileName);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/ImsError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims;\n\n/**\n * IMS error\n * \n * @author jexa7410\n */\npublic class ImsError extends Error {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Unexpected exception occurs in the module (e.g. internal exception)\n     */\n    public final static int UNEXPECTED_EXCEPTION = 0x01;\n\n    /**\n     * Registration has failed\n     */\n    public final static int REGISTRATION_FAILED = 0x02;\n\n    /**\n     * Error code\n     */\n    private int mErrorCode;\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public ImsError(int code) {\n        super();\n        mErrorCode = code;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public ImsError(int code, String msg) {\n        super(msg);\n        mErrorCode = code;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ImsError(int code, Throwable cause) {\n        super(cause);\n        mErrorCode = code;\n    }\n\n    /**\n     * Returns the error code\n     * \n     * @return Error code\n     */\n    public int getErrorCode() {\n        return mErrorCode;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/ImsModule.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims;\n\nimport com.gsma.rcs.addressbook.AddressBookManager;\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.CoreListener;\nimport com.gsma.rcs.core.ims.network.ImsConnectionManager;\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.gsm.CallManager;\nimport com.gsma.rcs.core.ims.network.sip.SipManager;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpConnection;\nimport com.gsma.rcs.core.ims.protocol.sip.SipEventListener;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsService.ImsServiceType;\nimport com.gsma.rcs.core.ims.service.ImsServiceDispatcher;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.extension.ServiceExtensionManager;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.HttpTransferManager;\nimport com.gsma.rcs.core.ims.service.presence.PresenceService;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.terms.TermsConditionsService;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.history.HistoryLog;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * IMS module\n * \n * @author JM. Auffret\n */\npublic class ImsModule implements SipEventListener {\n\n    private Core mCore;\n\n    private static UserProfile sImsUserProfile;\n\n    private ImsConnectionManager mCnxManager;\n\n    private Map<ImsServiceType, ImsService> mServices;\n\n    private ImsServiceDispatcher mServiceDispatcher;\n\n    private final CallManager mCallManager;\n\n    private final ServiceExtensionManager mExtensionManager;\n\n    /**\n     * flag to indicate whether instantiation is finished\n     */\n    private boolean mInitializationFinished = false;\n\n    private final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(ImsModule.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param core Core\n     * @param ctx The context this module is part of\n     * @param localContentResolver The local content resolver\n     * @param rcsSettings RCSsettings instance\n     * @param contactManager Contact manager accessor\n     * @param messagingLog Messaging log accessor\n     * @param historyLog The history log accessor\n     * @param richCallHistory The rich call accessor\n     * @param addressBookManager The address book manager instance\n     */\n    public ImsModule(Core core, Context ctx, LocalContentResolver localContentResolver,\n            RcsSettings rcsSettings, ContactManager contactManager, MessagingLog messagingLog,\n            HistoryLog historyLog, RichCallHistory richCallHistory,\n            AddressBookManager addressBookManager) {\n        mCore = core;\n        mRcsSettings = rcsSettings;\n\n        mExtensionManager = new ServiceExtensionManager(this, ctx, mCore, rcsSettings);\n        mCnxManager = new ImsConnectionManager(this, ctx, mCore, rcsSettings);\n        mCallManager = new CallManager(this, ctx);\n\n        mServices = new HashMap<>();\n        mServices.put(ImsServiceType.TERMS_CONDITIONS,\n                new TermsConditionsService(this, rcsSettings));\n        CapabilityService capabilityService = new CapabilityService(this, rcsSettings,\n                contactManager, addressBookManager);\n        mServices.put(ImsServiceType.CAPABILITY, capabilityService);\n        mServices.put(ImsServiceType.INSTANT_MESSAGING, new InstantMessagingService(this,\n                rcsSettings, contactManager, messagingLog, historyLog, localContentResolver, ctx,\n                core));\n        mServices\n                .put(ImsServiceType.RICHCALL, new RichcallService(this, richCallHistory,\n                        contactManager, rcsSettings, mCallManager, localContentResolver,\n                        capabilityService));\n        mServices.put(ImsServiceType.PRESENCE, new PresenceService(this, ctx, rcsSettings,\n                contactManager, addressBookManager));\n        mServices.put(ImsServiceType.SIP, new SipService(this, contactManager, rcsSettings));\n\n        mServiceDispatcher = new ImsServiceDispatcher(this, rcsSettings);\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"IMS module creation\");\n        }\n    }\n\n    /**\n     * Initializes IMS module\n     */\n    public void initialize() {\n        SipManager.setTimeout(mRcsSettings.getSipTransactionTimeout());\n        MsrpConnection.setMsrpTraceEnabled(mRcsSettings.isMediaTraceActivated());\n        HttpTransferManager.setHttpTraceEnabled(mRcsSettings.isMediaTraceActivated());\n\n        mCnxManager.initialize();\n        getInstantMessagingService().initialize();\n        getRichcallService().initialize();\n        getPresenceService().initialize();\n\n        mInitializationFinished = true;\n        if (sLogger.isActivated()) {\n            sLogger.info(\"IMS module initialization\");\n        }\n    }\n\n    /**\n     * Returns the SIP manager\n     * \n     * @return SIP manager\n     */\n    public SipManager getSipManager() {\n        return getCurrentNetworkInterface().getSipManager();\n    }\n\n    /**\n     * Returns the current network interface\n     * \n     * @return Network interface\n     */\n    public ImsNetworkInterface getCurrentNetworkInterface() {\n        return mCnxManager.getCurrentNetworkInterface();\n    }\n\n    /**\n     * Is connected to a Wi-Fi access\n     * \n     * @return Boolean\n     */\n    public boolean isConnectedToWifiAccess() {\n        return mCnxManager.isConnectedToWifi();\n    }\n\n    /**\n     * Is connected to a mobile access\n     * \n     * @return Boolean\n     */\n    public boolean isConnectedToMobileAccess() {\n        return mCnxManager.isConnectedToMobile();\n    }\n\n    /**\n     * Returns the ImsConnectionManager\n     * \n     * @return ImsConnectionManager\n     */\n    public ImsConnectionManager getImsConnectionManager() {\n        return mCnxManager;\n    }\n\n    /**\n     * Start the IMS module\n     */\n    public void start() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start the IMS module\");\n        }\n        mCnxManager.start();\n        mExtensionManager.start();\n        mServiceDispatcher.start();\n        mCallManager.start();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"IMS module is started\");\n        }\n    }\n\n    /**\n     * Stop the IMS module\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void stop() throws PayloadException, NetworkException, ContactManagerException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Stop the IMS module\");\n        }\n        mCallManager.stop();\n        mCnxManager.terminate();\n        mServiceDispatcher.terminate();\n        mExtensionManager.stop();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"IMS module has been stopped\");\n        }\n    }\n\n    /**\n     * Start IMS services\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void startImsServices() throws PayloadException, NetworkException,\n            ContactManagerException {\n        for (ImsService imsService : mServices.values()) {\n            if (imsService.isActivated()) {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Start IMS service: \".concat(imsService.getClass().getName()));\n                }\n                imsService.start();\n            }\n        }\n        getCallManager().connectionEvent(true);\n    }\n\n    /**\n     * Stop IMS services\n     * \n     * @param reasonCode The reason code\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    public void stopImsServices(TerminationReason reasonCode) throws PayloadException,\n            NetworkException, ContactManagerException {\n        // Terminate all pending sessions\n        terminateAllSessions(reasonCode);\n\n        // Stop each services\n        for (ImsService imsService : mServices.values()) {\n            try {\n                if (imsService.isActivated()) {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Stop IMS service: \".concat(imsService.getClass().getName()));\n                    }\n                    imsService.stop(reasonCode);\n                }\n            } catch (PayloadException e) {\n                sLogger.error(\n                        \"Unable to stop IMS service: \".concat(imsService.getClass().getName()), e);\n            } catch (NetworkException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            }\n        }\n        // Send call manager event\n        getCallManager().connectionEvent(false);\n    }\n\n    /**\n     * Check IMS services\n     */\n    public void checkImsServices() {\n        for (ImsService imsService : mServices.values()) {\n            if (imsService.isActivated()) {\n                imsService.check();\n            }\n        }\n    }\n\n    /**\n     * Returns the call manager\n     * \n     * @return Call manager\n     */\n    public CallManager getCallManager() {\n        return mCallManager;\n    }\n\n    /**\n     * Returns the IMS services\n     * \n     * @return Collection of IMS service\n     */\n    public Collection<ImsService> getImsServices() {\n        return mServices.values();\n    }\n\n    /**\n     * Returns the terms & conditions service\n     * \n     * @return Terms & conditions service\n     */\n    public TermsConditionsService getTermsConditionsService() {\n        return (TermsConditionsService) mServices.get(ImsServiceType.TERMS_CONDITIONS);\n    }\n\n    /**\n     * Returns the capability service\n     * \n     * @return Capability service\n     */\n    public CapabilityService getCapabilityService() {\n        return (CapabilityService) mServices.get(ImsServiceType.CAPABILITY);\n    }\n\n    /**\n     * Returns the rich call service\n     * \n     * @return Richcall service\n     */\n    public RichcallService getRichcallService() {\n        return (RichcallService) mServices.get(ImsServiceType.RICHCALL);\n    }\n\n    /**\n     * Returns the presence service\n     * \n     * @return Presence service\n     */\n    public PresenceService getPresenceService() {\n        return (PresenceService) mServices.get(ImsServiceType.PRESENCE);\n    }\n\n    /**\n     * Returns the Instant Messaging service\n     * \n     * @return Instant Messaging service\n     */\n    public InstantMessagingService getInstantMessagingService() {\n        return (InstantMessagingService) mServices.get(ImsServiceType.INSTANT_MESSAGING);\n    }\n\n    /**\n     * Returns the SIP service\n     * \n     * @return SIP service\n     */\n    public SipService getSipService() {\n        return (SipService) mServices.get(ImsServiceType.SIP);\n    }\n\n    /**\n     * Return the core instance\n     * \n     * @return Core instance\n     */\n    public Core getCore() {\n        return mCore;\n    }\n\n    /**\n     * Return the core listener\n     * \n     * @return Core listener\n     */\n    public CoreListener getCoreListener() {\n        return mCore.getListener();\n    }\n\n    /**\n     * Receive SIP request\n     * \n     * @param request SIP request\n     */\n    public void receiveSipRequest(SipRequest request) {\n        // Post the incoming request to the service dispatcher\n        mServiceDispatcher.postSipRequest(request);\n    }\n\n    /**\n     * This function is used when all session needs to terminated in both invitation pending and\n     * started state.\n     * \n     * @param reasonCode The reason code\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void terminateAllSessions(TerminationReason reasonCode) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Terminate all sessions\");\n        }\n        for (ImsService service : getImsServices()) {\n            service.terminateAllSessions(reasonCode);\n        }\n    }\n\n    /**\n     * Check whether ImsModule instantiation has finished\n     * \n     * @return true if ImsModule is completely initialized\n     */\n    public boolean isInitializationFinished() {\n        return mInitializationFinished;\n    }\n\n    /**\n     * @return true is device is in roaming\n     */\n    public boolean isInRoaming() {\n        return mCnxManager.isInRoaming();\n    }\n\n    /**\n     * Gets IMS user profile\n     * \n     * @return IMS user profile\n     */\n    public static UserProfile getImsUserProfile() {\n        return sImsUserProfile;\n    }\n\n    /**\n     * Sets IMS user profile\n     * \n     * @param profile The user profile\n     */\n    public static void setImsUserProfile(UserProfile profile) {\n        sImsUserProfile = profile;\n    }\n\n    /**\n     * Return the extension manager\n     *\n     * @return Extension manager\n     */\n    public ServiceExtensionManager getExtensionManager() {\n        return mExtensionManager;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/ImsConnectionManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface.DnsResolvedFields;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtpSource;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.NetworkAccessType;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.os.BatteryManager;\nimport android.telephony.TelephonyManager;\n\nimport java.io.IOException;\nimport java.net.UnknownHostException;\nimport java.security.cert.CertificateException;\nimport java.util.Random;\n\n/**\n * IMS connection manager\n * \n * @author JM. Auffret\n * @author Deutsche Telekom\n */\npublic class ImsConnectionManager implements Runnable {\n\n    private static final long DEFAULT_RETRY_PERIOD = 5000;\n\n    private final Core mCore;\n\n    private final ImsModule mImsModule;\n\n    private ImsNetworkInterface[] mNetworkInterfaces = new ImsNetworkInterface[2];\n\n    private ImsNetworkInterface mCurrentNetworkInterface;\n\n    private Thread mImsPollingThread;\n\n    private long mImsPollingThreadId = -1;\n\n    private ConnectivityManager mCnxManager;\n\n    private NetworkAccessType mNetwork;\n\n    private String mOperator;\n\n    private DnsResolvedFields mDnsResolvedFields;\n\n    /**\n     * Battery level state\n     */\n    private boolean mDisconnectedByBattery = false;\n\n    private boolean mImsServicesStarted = false;\n\n    private static final Logger sLogger = Logger.getLogger(ImsConnectionManager.class.getName());\n\n    private final RcsSettings mRcsSettings;\n\n    private final Context mCtx;\n\n    private NetworkStateListener mNetworkStateListener;\n\n    private BatteryLevelListener mBatteryLevelListener;\n\n    /**\n     * Constructor\n     * \n     * @param imsModule The IMS module instance\n     * @param ctx The application context\n     * @param core The Core instance\n     * @param rcsSettings RcsSettings instance\n     */\n    public ImsConnectionManager(ImsModule imsModule, Context ctx, Core core, RcsSettings rcsSettings) {\n        mImsModule = imsModule;\n        mCore = core;\n        mRcsSettings = rcsSettings;\n        mCtx = ctx;\n    }\n\n    /**\n     * Initializes IMS connection manager\n     */\n    public void initialize() {\n        mCnxManager = (ConnectivityManager) mCtx.getSystemService(Context.CONNECTIVITY_SERVICE);\n        mNetwork = mRcsSettings.getNetworkAccess();\n        mOperator = mRcsSettings.getNetworkOperator();\n        /* Instantiates the IMS network interfaces */\n        mNetworkInterfaces[0] = new MobileNetworkInterface(mImsModule, mRcsSettings);\n        mNetworkInterfaces[1] = new WifiNetworkInterface(mImsModule, mRcsSettings);\n        /* Set the mobile network interface by default */\n        mCurrentNetworkInterface = getMobileNetworkInterface();\n        loadUserProfile();\n    }\n\n    /**\n     * Starts IMS connection manager\n     */\n    public void start() {\n        if (mNetworkStateListener == null) {\n            /* Register network state listener */\n            mNetworkStateListener = new NetworkStateListener();\n            mCtx.registerReceiver(mNetworkStateListener, new IntentFilter(\n                    ConnectivityManager.CONNECTIVITY_ACTION));\n        }\n        if (mBatteryLevelListener == null) {\n            /* Register changes about battery: charging state, level, etc... */\n            mBatteryLevelListener = new BatteryLevelListener();\n            mCtx.registerReceiver(mBatteryLevelListener, new IntentFilter(\n                    Intent.ACTION_BATTERY_CHANGED));\n        }\n    }\n\n    /**\n     * Returns the current network interface\n     * \n     * @return Current network interface\n     */\n    public ImsNetworkInterface getCurrentNetworkInterface() {\n        return mCurrentNetworkInterface;\n    }\n\n    /**\n     * Returns the mobile network interface\n     * \n     * @return Mobile network interface\n     */\n    public ImsNetworkInterface getMobileNetworkInterface() {\n        return mNetworkInterfaces[0];\n    }\n\n    /**\n     * Returns the Wi-Fi network interface\n     * \n     * @return Wi-Fi network interface\n     */\n    public ImsNetworkInterface getWifiNetworkInterface() {\n        return mNetworkInterfaces[1];\n    }\n\n    /**\n     * Is connected to Wi-Fi\n     * \n     * @return Boolean\n     */\n    public boolean isConnectedToWifi() {\n        return mCurrentNetworkInterface == getWifiNetworkInterface();\n    }\n\n    /**\n     * Is connected to mobile\n     * \n     * @return Boolean\n     */\n    public boolean isConnectedToMobile() {\n        return mCurrentNetworkInterface == getMobileNetworkInterface();\n    }\n\n    /**\n     * Is disconnected by battery\n     * \n     * @return Returns true if disconnected by battery, else returns false\n     */\n    public boolean isDisconnectedByBattery() {\n        return mDisconnectedByBattery;\n    }\n\n    /**\n     * Load the user profile associated to the network interface\n     */\n    private void loadUserProfile() {\n        ImsModule.setImsUserProfile(mCurrentNetworkInterface.getUserProfile());\n        RtpSource.setCname(ImsModule.getImsUserProfile().getPublicUri());\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"User profile has been reloaded\");\n        }\n    }\n\n    /**\n     * Terminate the connection manager\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    public void terminate() throws PayloadException, NetworkException, ContactManagerException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the IMS connection manager\");\n        }\n        if (mBatteryLevelListener != null) {\n            mCtx.unregisterReceiver(mBatteryLevelListener);\n            mBatteryLevelListener = null;\n        }\n        if (mNetworkStateListener != null) {\n            mCtx.unregisterReceiver(mNetworkStateListener);\n            mNetworkStateListener = null;\n        }\n        stopImsConnection(TerminationReason.TERMINATION_BY_SYSTEM);\n        mCurrentNetworkInterface.unregister();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"IMS connection manager has been terminated\");\n        }\n    }\n\n    /**\n     * Network state listener\n     */\n    private class NetworkStateListener extends BroadcastReceiver {\n        @Override\n        public void onReceive(Context context, final Intent intent) {\n            mCore.scheduleCoreOperation(new Runnable() {\n                @Override\n                public void run() {\n\n                    try {\n                        connectionEvent(intent);\n\n                    } catch (NetworkException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(e.getMessage());\n                        }\n                    } catch (ContactManagerException | RuntimeException | CertificateException\n                            | PayloadException e) {\n                        sLogger.error(\"Unable to handle connection event for intent action : \"\n                                + intent.getAction(), e);\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * Connection event\n     * \n     * @param intent Intent\n     * @throws PayloadException\n     * @throws CertificateException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    // @FIXME: This method is doing so many things at this moment and has become too complex thus\n    // needs a complete refactor, However at this moment due to other prior tasks the refactoring\n    // task has been kept in backlog.\n    private void connectionEvent(Intent intent) throws PayloadException, CertificateException,\n            NetworkException, ContactManagerException {\n        try {\n            if (mDisconnectedByBattery) {\n                return;\n            }\n            if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {\n                return;\n            }\n            boolean connectivity = intent.getBooleanExtra(\n                    ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);\n            String reason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);\n            boolean failover = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Connectivity event change: failover=\" + failover + \", connectivity=\"\n                        + !connectivity + \", reason=\" + reason);\n            }\n            NetworkInfo networkInfo = mCnxManager.getActiveNetworkInfo();\n            if (networkInfo == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Disconnect from IMS: no network (e.g. air plane mode)\");\n                }\n                disconnectFromIms();\n                return;\n            }\n            if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {\n                String lastUserAccount = LauncherUtils.getLastUserAccount(mCtx);\n                String currentUserAccount = LauncherUtils.getCurrentUserAccount(mCtx);\n                if (lastUserAccount != null) {\n                    if ((currentUserAccount == null)\n                            || !currentUserAccount.equalsIgnoreCase(lastUserAccount)) {\n                        mImsModule.getCoreListener().onSimChangeDetected();\n                        return;\n                    }\n                }\n            }\n            String localIpAddr;\n            if (networkInfo.getType() != mCurrentNetworkInterface.getType()) {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Data connection state: NETWORK ACCESS CHANGED\");\n                }\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Disconnect from IMS: network access has changed\");\n                }\n                disconnectFromIms();\n\n                if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Change the network interface to mobile\");\n                    }\n                    mCurrentNetworkInterface = getMobileNetworkInterface();\n                } else if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Change the network interface to Wi-Fi\");\n                    }\n                    mCurrentNetworkInterface = getWifiNetworkInterface();\n                }\n                loadUserProfile();\n                try {\n                    mDnsResolvedFields = mCurrentNetworkInterface.getDnsResolvedFields();\n                } catch (UnknownHostException e) {\n                    /*\n                     * Even if we are not able to resolve host name , we should still continue to\n                     * get local IP as this is a very obvious case, Specially for networks\n                     * supporting IPV4 protocol.\n                     */\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n                localIpAddr = NetworkFactory.getFactory().getLocalIpAddress(mDnsResolvedFields,\n                        networkInfo.getType());\n\n            } else {\n                /* Check if the IP address has changed */\n                try {\n                    if (mDnsResolvedFields == null) {\n                        mDnsResolvedFields = mCurrentNetworkInterface.getDnsResolvedFields();\n                    }\n                } catch (UnknownHostException e) {\n                    /*\n                     * Even if we are not able to resolve host name , we should still continue to\n                     * get local IP as this is a very obvious case, Specially for networks\n                     * supporting IPV4 protocol.\n                     */\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n                localIpAddr = NetworkFactory.getFactory().getLocalIpAddress(mDnsResolvedFields,\n                        networkInfo.getType());\n                String lastIpAddr = mCurrentNetworkInterface.getNetworkAccess().getIpAddress();\n                if (!localIpAddr.equals(lastIpAddr)) {\n                    if (lastIpAddr != null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Disconnect from IMS: IP address has changed\");\n                        }\n                        disconnectFromIms();\n                    } else {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"IP address available (again)\");\n                        }\n                    }\n                } else {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Neither interface nor IP address has changed; nothing to do.\");\n                    }\n                    return;\n                }\n            }\n            if (networkInfo.isConnected()) {\n                String remoteAddress;\n                if (mDnsResolvedFields != null) {\n                    remoteAddress = mDnsResolvedFields.mIpAddress;\n                } else {\n                    remoteAddress = \"unresolved\";\n                }\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Data connection state: CONNECTED to \" + networkInfo.getTypeName()\n                            + \" with local IP \" + localIpAddr + \" valid for \" + remoteAddress);\n                }\n                if (!NetworkAccessType.ANY.equals(mNetwork)\n                        && (mNetwork.toInt() != networkInfo.getType())) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Network access \" + networkInfo.getTypeName()\n                                + \" is not authorized\");\n                    }\n                    return;\n                }\n                TelephonyManager tm = (TelephonyManager) mCtx\n                        .getSystemService(Context.TELEPHONY_SERVICE);\n                String currentOpe = tm.getSimOperatorName();\n                if (mOperator != null && !currentOpe.equalsIgnoreCase(mOperator)) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Operator not authorized current=\" + currentOpe\n                                + \" authorized=\" + mOperator);\n                    }\n                    return;\n                }\n                if (!mCurrentNetworkInterface.isInterfaceConfigured()) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"IMS network interface not well configured\");\n                    }\n                    return;\n                }\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Connect to IMS\");\n                }\n                connectToIms(localIpAddr);\n            }\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            disconnectFromIms();\n        }\n    }\n\n    /**\n     * Connect to IMS network interface\n     * \n     * @param ipAddr IP address\n     * @throws CertificateException\n     * @throws IOException\n     */\n    private void connectToIms(String ipAddr) throws CertificateException, IOException {\n        // Connected to the network access\n        mCurrentNetworkInterface.getNetworkAccess().connect(ipAddr);\n        startImsConnection();\n    }\n\n    /**\n     * Disconnect from IMS network interface\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void disconnectFromIms() throws PayloadException, NetworkException,\n            ContactManagerException {\n        stopImsConnection(TerminationReason.TERMINATION_BY_CONNECTION_LOST);\n        mCurrentNetworkInterface.registrationTerminated();\n        mCurrentNetworkInterface.getNetworkAccess().disconnect();\n    }\n\n    /**\n     * Disconnect from IMS network interface and de-register due to battery low\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void disconnectFromImsByBatteryLow() throws PayloadException, NetworkException,\n            ContactManagerException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Disconnect from IMS network interface and de-register due to battery low\");\n        }\n        stopImsConnection(TerminationReason.TERMINATION_BY_LOW_BATTERY);\n        mCurrentNetworkInterface.unregister();\n        mCurrentNetworkInterface.getNetworkAccess().disconnect();\n    }\n\n    /**\n     * Start the IMS connection\n     */\n    private synchronized void startImsConnection() {\n        if (mImsPollingThreadId >= 0) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start the IMS connection manager\");\n        }\n        mImsPollingThread = new Thread(this);\n        mImsPollingThreadId = mImsPollingThread.getId();\n        mImsPollingThread.start();\n    }\n\n    /**\n     * Stop the IMS connection\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private synchronized void stopImsConnection(TerminationReason reasonCode)\n            throws PayloadException, NetworkException, ContactManagerException {\n        if (mImsPollingThreadId == -1) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Stop the IMS connection manager\");\n        }\n        mImsPollingThreadId = -1;\n        mImsPollingThread.interrupt();\n        mImsPollingThread = null;\n        if (mImsServicesStarted) {\n            mImsModule.stopImsServices(reasonCode);\n            mImsServicesStarted = false;\n        }\n    }\n\n    @Override\n    // @FIXME: This run method needs to be refactored as the current logic of polling is bit too\n    // complex and can be made much more simpler.\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Start polling of the IMS connection\");\n            }\n            long servicePollingPeriod = mRcsSettings.getImsServicePollingPeriod();\n            long regBaseTime = mRcsSettings.getRegisterRetryBaseTime();\n            long regMaxTime = mRcsSettings.getRegisterRetryMaxTime();\n            Random random = new Random();\n            int nbFailures = 0;\n            while (mImsPollingThreadId == Thread.currentThread().getId()) {\n                // Connection management\n                try {\n                    // Test IMS registration\n                    if (!mCurrentNetworkInterface.isRegistered()) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Not yet registered to IMS: try registration\");\n                        }\n                        // Try to register to IMS\n                        mCurrentNetworkInterface.register(mDnsResolvedFields);\n                        // InterruptedException thrown by stopImsConnection() may be caught by one\n                        // of the methods used in currentNetworkInterface.register() above\n                        if (mImsPollingThreadId != Thread.currentThread().getId()) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"IMS connection polling thread race condition\");\n                            }\n                            break;\n                        }\n                        if (mCurrentNetworkInterface.isRegistered()) {\n                            if (mImsModule.isInitializationFinished() && !mImsServicesStarted) {\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"Registered to the IMS with success: \"\n                                            + \"start IMS services\");\n                                }\n                                mImsModule.startImsServices();\n                                mImsServicesStarted = true;\n                            }\n\n                            // Reset number of failures\n                            nbFailures = 0;\n                        } else {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Registration failed: IMS service is not started\");\n                            }\n                            /* Increment number of failures */\n                            nbFailures++;\n                            /* Force to perform a new DNS lookup */\n                            mDnsResolvedFields = null;\n                        }\n                    } else {\n                        if (mImsModule.isInitializationFinished()) {\n                            if (!mImsServicesStarted) {\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"Already registered to IMS: start IMS services\");\n                                }\n                                mImsModule.startImsServices();\n                                mImsServicesStarted = true;\n                            } else {\n                                mImsModule.checkImsServices();\n                            }\n                        } else {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Already registered to IMS: IMS services not yet started\");\n                            }\n                        }\n                    }\n                } catch (ContactManagerException | PayloadException e) {\n                    sLogger.error(\"Can't register to the IMS!\", e);\n                    mCurrentNetworkInterface.getSipManager().closeStack();\n                    /* Increment number of failures */\n                    nbFailures++;\n                    /* Force to perform a new DNS lookup */\n                    mDnsResolvedFields = null;\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                    mCurrentNetworkInterface.getSipManager().closeStack();\n                    /* Increment number of failures */\n                    nbFailures++;\n                    /* Force to perform a new DNS lookup */\n                    mDnsResolvedFields = null;\n                }\n                // InterruptedException thrown by stopImsConnection() may be caught by one\n                // of the methods used in currentNetworkInterface.register() above\n                if (mImsPollingThreadId != Thread.currentThread().getId()) {\n                    sLogger.debug(\"IMS connection polling thread race condition\");\n                    break;\n                }\n                // Make a pause before the next polling\n                try {\n                    if (!mCurrentNetworkInterface.isRegistered()) {\n                        final long retryAfterHeaderDuration = mCurrentNetworkInterface\n                                .getRetryAfterHeaderDuration();\n                        if (retryAfterHeaderDuration > 0) {\n                            Thread.sleep(retryAfterHeaderDuration);\n                        } else {\n                            // Pause before the next register attempt\n                            double w = Math\n                                    .min(regMaxTime, (regBaseTime * Math.pow(2, nbFailures)));\n                            double coeff = (random.nextInt(51) + 50) / 100.0; // Coeff between 50%\n                                                                              // and\n                                                                              // 100%\n                            long retryPeriod = (long) (coeff * w);\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Wait \" + retryPeriod\n                                        + \"ms before retry registration (failures=\" + nbFailures\n                                        + \", coeff=\" + coeff + ')');\n                            }\n                            Thread.sleep(retryPeriod);\n                        }\n                    } else if (!mImsServicesStarted) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Wait \" + DEFAULT_RETRY_PERIOD\n                                    + \"ms before retry to start services\");\n                        }\n                        Thread.sleep(DEFAULT_RETRY_PERIOD);\n                    } else {\n                        // Pause before the next service check\n                        Thread.sleep(servicePollingPeriod);\n                    }\n                } catch (InterruptedException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"IMS connection polling is interrupted\", e);\n                    }\n                    break;\n                }\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"IMS connection polling is terminated\");\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to poll for ims connection!\", e);\n        }\n    }\n\n    /**\n     * Battery level listener class\n     */\n    private class BatteryLevelListener extends BroadcastReceiver {\n        @Override\n        public void onReceive(Context context, final Intent intent) {\n            mCore.scheduleCoreOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        MinimumBatteryLevel batteryLimit = mRcsSettings.getMinBatteryLevel();\n                        if (MinimumBatteryLevel.NEVER_STOP == batteryLimit) {\n                            mDisconnectedByBattery = false;\n                            return;\n                        }\n                        int batteryLevel = intent.getIntExtra(\"level\", 0);\n                        int batteryPlugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);\n                        if (sLogger.isActivated()) {\n                            sLogger.info(\"Battery level: \" + batteryLevel + \"% plugged: \"\n                                    + batteryPlugged);\n                        }\n                        if (batteryLevel <= batteryLimit.toInt() && batteryPlugged == 0) {\n                            if (!mDisconnectedByBattery) {\n                                mDisconnectedByBattery = true;\n                                disconnectFromImsByBatteryLow();\n                            }\n                        } else {\n                            if (mDisconnectedByBattery) {\n                                mDisconnectedByBattery = false;\n                                // Reconnect with a connection event\n                                connectionEvent(new Intent(ConnectivityManager.CONNECTIVITY_ACTION));\n                            }\n                        }\n                    } catch (ContactManagerException | RuntimeException | CertificateException\n                            | PayloadException e) {\n                        sLogger.error(\"Unable to handle connection event for intent action : \"\n                                + intent.getAction(), e);\n                    } catch (NetworkException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(e.getMessage());\n                        }\n                    }\n                }\n            });\n        }\n    }\n\n    /**\n     * @return true is device is in roaming\n     */\n    public boolean isInRoaming() {\n        NetworkInfo networkInfo = mCnxManager.getActiveNetworkInfo();\n        return networkInfo != null && networkInfo.isRoaming();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/ImsNetworkInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network;\n\nimport com.gsma.rcs.core.access.NetworkAccess;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.registration.GibaRegistrationProcedure;\nimport com.gsma.rcs.core.ims.network.registration.HttpDigestRegistrationProcedure;\nimport com.gsma.rcs.core.ims.network.registration.RegistrationManager;\nimport com.gsma.rcs.core.ims.network.registration.RegistrationProcedure;\nimport com.gsma.rcs.core.ims.network.sip.SipManager;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.userprofile.GibaUserProfileInterface;\nimport com.gsma.rcs.core.ims.userprofile.SettingsUserProfileInterface;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\nimport com.gsma.rcs.core.ims.userprofile.UserProfileInterface;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.AuthenticationProcedure;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\nimport org.xbill.DNS.Cache;\nimport org.xbill.DNS.ExtendedResolver;\nimport org.xbill.DNS.Lookup;\nimport org.xbill.DNS.NAPTRRecord;\nimport org.xbill.DNS.Record;\nimport org.xbill.DNS.ResolverConfig;\nimport org.xbill.DNS.SRVRecord;\nimport org.xbill.DNS.TextParseException;\nimport org.xbill.DNS.Type;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport javax2.sip.ListeningPoint;\n\n/**\n * Abstract IMS network interface\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class ImsNetworkInterface {\n\n    /**\n     * The maximum time in seconds that a negative response will be stored in this DNS Cache.\n     */\n    private static final int DNS_NEGATIVE_CACHING_TIME = 5;\n\n    /**\n     * IPv4 address format\n     */\n    private static final String REGEX_IPV4 = \"\\\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\\\.|$)){4}\\\\b\";\n\n    /**\n     * Dot constant\n     */\n    private static final char DOT = '.';\n\n    /**\n     * DNS SIP TLS service\n     */\n    private static final String DNS_SIP_TLS_SERVICE = \"SIPS+D2T\";\n\n    /**\n     * DNS SIP TCP service\n     */\n    private static final String DNS_SIP_TCP_SERVICE = \"SIP+D2T\";\n\n    /**\n     * DNS SIP UDP service\n     */\n    private static final String DNS_SIP_UDP_SERVICE = \"SIP+D2U\";\n\n    /**\n     * DNS SIP prefix service\n     */\n    private static final String DNS_SIP_PREFIX = \"_sip._\";\n\n    /**\n     * DNS SIPS prefix service\n     */\n    private static final String DNS_SIPS_PREFIX = \"_sips._\";\n\n    /**\n     * TCP protocol\n     */\n    private static final String TCP_PROTOCOL = \"tcp\";\n\n    /**\n     * Class containing the resolved fields\n     */\n    public class DnsResolvedFields {\n        /**\n         * DNS resoled IP address\n         */\n        public String mIpAddress;\n        /**\n         * DNS resolved port\n         */\n        public int mPort = -1;\n\n        /**\n         * Constructor\n         * \n         * @param ipAddress the IP address\n         * @param port the IP port\n         */\n        public DnsResolvedFields(String ipAddress, int port) {\n            mIpAddress = ipAddress;\n            mPort = port;\n        }\n    }\n\n    private ImsModule mImsModule;\n\n    /**\n     * Network interface type\n     */\n    private int mType;\n\n    private NetworkAccess mAccess;\n\n    private final SipManager mSip;\n\n    /**\n     * IMS authentication mode associated to the network interface\n     */\n    protected AuthenticationProcedure mImsAuthentMode;\n\n    protected String mImsProxyProtocol;\n\n    private String mImsProxyAddr;\n\n    private int mImsProxyPort;\n\n    /**\n     * Registration procedure associated to the network interface\n     */\n    protected RegistrationProcedure mRegistrationProcedure;\n\n    private RegistrationManager mRegistration;\n\n    private boolean mNatTraversal = false;\n\n    /**\n     * NAT public IP address for last registration\n     */\n    private String mNatPublicAddress;\n\n    /**\n     * NAT public UDP port\n     */\n    private int mNatPublicPort = -1;\n\n    /**\n     * TCP fallback according to RFC3261 chapter 18.1.1\n     */\n    private boolean mTcpFallback = false;\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Holds retry duration value obtained from Retry-After header\n     * <p>\n     * Default value = 0L\n     * </p>\n     */\n    private long mRetryDuration = 0;\n\n    private static Logger sLogger = Logger.getLogger(ImsNetworkInterface.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imsModule IMS module\n     * @param type Network interface type\n     * @param access Network access\n     * @param proxyAddr IMS proxy address\n     * @param proxyPort IMS proxy port\n     * @param proxyProtocol IMS proxy protocol\n     * @param authentMode IMS authentication mode\n     * @param rcsSettings the RCS settings accessor\n     */\n    public ImsNetworkInterface(ImsModule imsModule, int type, NetworkAccess access,\n            String proxyAddr, int proxyPort, String proxyProtocol,\n            AuthenticationProcedure authentMode, RcsSettings rcsSettings) {\n        mImsModule = imsModule;\n        mType = type;\n        mAccess = access;\n        mImsProxyAddr = proxyAddr;\n        mImsProxyPort = proxyPort;\n        mImsProxyProtocol = proxyProtocol;\n        mImsAuthentMode = authentMode;\n        mRcsSettings = rcsSettings;\n        if (ListeningPoint.UDP.equals(mImsProxyProtocol)) {\n            mTcpFallback = mRcsSettings.isTcpFallback();\n        }\n\n        mSip = new SipManager(this, mRcsSettings);\n\n        loadRegistrationProcedure();\n\n        mRegistration = new RegistrationManager(this, mRegistrationProcedure, mRcsSettings);\n    }\n\n    /**\n     * Is behind a NAT\n     * \n     * @return Boolean\n     */\n    public boolean isBehindNat() {\n        return mNatTraversal;\n    }\n\n    /**\n     * Set NAT traversal flag\n     * \n     * @param flag the flag\n     */\n    public void setNatTraversal(boolean flag) {\n        mNatTraversal = flag;\n    }\n\n    /**\n     * Returns last known NAT public address as discovered by UAC. Returns null if unknown, UAC is\n     * not registered or no NAT traversal is detected.\n     * \n     * @return Last known NAT public address discovered by UAC or null if UAC is not registered\n     */\n    public String getNatPublicAddress() {\n        return mNatPublicAddress;\n    }\n\n    /**\n     * Sets the last known NAT public address as discovered by UAC. Set to null on unregistering or\n     * if no NAT traversal is detected.\n     * \n     * @param publicAddress Public address\n     */\n    public void setNatPublicAddress(String publicAddress) {\n        mNatPublicAddress = publicAddress;\n    }\n\n    /**\n     * Returns last known NAT public UDP port as discovered by UAC. Returns -1 if unknown, UAC is\n     * not registered or no NAT traversal is detected.\n     * \n     * @return Last known NAT public UDP port discovered by UAC or -1 if UAC is not registered\n     */\n    public int getNatPublicPort() {\n        return mNatPublicPort;\n    }\n\n    /**\n     * Sets the last known NAT public address as discovered by UAC. Set to -1 on unregistering or if\n     * no NAT traversal is detected.\n     * \n     * @param publicPort Public port\n     */\n    public void setNatPublicPort(int publicPort) {\n        mNatPublicPort = publicPort;\n    }\n\n    /**\n     * Is network interface configured\n     * \n     * @return Boolean\n     */\n    public boolean isInterfaceConfigured() {\n        return mImsProxyAddr != null;\n    }\n\n    /**\n     * Returns the registration manager\n     * \n     * @return Registration manager\n     */\n    public RegistrationManager getRegistrationManager() {\n        return mRegistration;\n    }\n\n    /**\n     * Get the Retry header time\n     * \n     * @return retryHeader Retry-After duration value\n     */\n    public long getRetryAfterHeaderDuration() {\n        return mRetryDuration;\n    }\n\n    /**\n     * Sets the Retry header time\n     * \n     * @param retryValue Retry-After duration value\n     */\n    public void setRetryAfterHeaderDuration(long retryValue) {\n        mRetryDuration = retryValue;\n    }\n\n    /**\n     * Load the registration procedure associated to the network access\n     */\n    public void loadRegistrationProcedure() {\n        switch (mImsAuthentMode) {\n            case GIBA:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Load GIBA authentication procedure\");\n                }\n                mRegistrationProcedure = new GibaRegistrationProcedure();\n                break;\n            case DIGEST:\n            default:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Load HTTP Digest authentication procedure\");\n                }\n                mRegistrationProcedure = new HttpDigestRegistrationProcedure();\n                break;\n        }\n    }\n\n    /**\n     * Returns the user profile associated to the network access\n     * \n     * @return User profile\n     */\n    public UserProfile getUserProfile() {\n        UserProfileInterface intf;\n        switch (mImsAuthentMode) {\n            case GIBA:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Load user profile derived from IMSI (GIBA)\");\n                }\n                intf = new GibaUserProfileInterface(mRcsSettings);\n                break;\n            case DIGEST:\n            default:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Load user profile from RCS settings database\");\n                }\n                intf = new SettingsUserProfileInterface(mRcsSettings);\n                break;\n        }\n        return intf.read();\n    }\n\n    /**\n     * Returns the IMS module\n     * \n     * @return IMS module\n     */\n    public ImsModule getImsModule() {\n        return mImsModule;\n    }\n\n    /**\n     * Returns the network interface type\n     * \n     * @return Type (see ConnectivityManager class)\n     */\n    public int getType() {\n        return mType;\n    }\n\n    /**\n     * Returns the network access\n     * \n     * @return Network access\n     */\n    public NetworkAccess getNetworkAccess() {\n        return mAccess;\n    }\n\n    /**\n     * Returns the SIP manager\n     * \n     * @return SIP manager\n     */\n    public SipManager getSipManager() {\n        return mSip;\n    }\n\n    /**\n     * Is registered\n     * \n     * @return Return True if the terminal is registered, else return False\n     */\n    public boolean isRegistered() {\n        return mRegistration.isRegistered();\n    }\n\n    /**\n     * Gets reason code for RCS registration\n     * \n     * @return reason code\n     */\n    public RcsServiceRegistration.ReasonCode getRegistrationReasonCode() {\n        return mRegistration.getReasonCode();\n    }\n\n    /**\n     * Get DNS records\n     * \n     * @param domain Domain\n     * @param resolver Resolver\n     * @param type (Type.SRV or Type.NAPTR)\n     * @return SRV records or null if no record\n     * @throws TextParseException\n     */\n    private Record[] getDnsRequest(String domain, ExtendedResolver resolver, int type)\n            throws TextParseException {\n        if (sLogger.isActivated()) {\n            if (type == Type.SRV) {\n                sLogger.debug(\"DNS SRV lookup for \" + domain);\n            } else if (type == Type.NAPTR) {\n                sLogger.debug(\"DNS NAPTR lookup for \" + domain);\n            }\n        }\n        Lookup lookup = new Lookup(domain, type);\n        lookup.setResolver(resolver);\n        // Default negative cache TTL value is \"cache forever\". We do not want that.\n        Cache cache = Lookup.getDefaultCache(type);\n        cache.setMaxNCache(DNS_NEGATIVE_CACHING_TIME);\n        lookup.setCache(cache);\n        Record[] result = lookup.run();\n        int code = lookup.getResult();\n        if (code != Lookup.SUCCESSFUL) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Lookup error: \" + code + \"/\" + lookup.getErrorString());\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Get DNS A record\n     * \n     * @param domain Domain\n     * @return IP address or null if no record\n     * @throws UnknownHostException\n     */\n    private String getDnsA(String domain) throws UnknownHostException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"DNS A lookup for \" + domain);\n        }\n        return InetAddress.getByName(domain).getHostAddress();\n    }\n\n    /**\n     * Get best DNS SRV record\n     * \n     * @param records SRV records\n     * @return IP address\n     */\n    private SRVRecord getBestDnsSRV(Record[] records) {\n        SRVRecord result = null;\n        for (Record record : records) {\n            SRVRecord srv = (SRVRecord) record;\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"SRV record: \" + srv.toString());\n            }\n            if (result == null) {\n                // First record\n                result = srv;\n            } else {\n                // Next record\n                if (srv.getPriority() < result.getPriority()) {\n                    // Lowest priority\n                    result = srv;\n                } else if (srv.getPriority() == result.getPriority()) {\n                    // Highest weight\n                    if (srv.getWeight() > result.getWeight()) {\n                        result = srv;\n                    }\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Get the SRV Query\n     * \n     * @return constructed srv query\n     */\n    private String getSrvQuery(String sipService) {\n        StringBuilder query = new StringBuilder();\n        if (DNS_SIP_TLS_SERVICE.equalsIgnoreCase(sipService)) {\n            query.append(DNS_SIPS_PREFIX).append(TCP_PROTOCOL);\n        } else {\n            query.append(DNS_SIP_PREFIX).append(mImsProxyProtocol.toLowerCase());\n        }\n        query.append(DOT).append(mImsProxyAddr);\n        return query.toString();\n    }\n\n    /**\n     * Get the DNS resolved fields.\n     * \n     * @return The {@link DnsResolvedFields} object containing the DNS resolved fields.\n     * @throws PayloadException\n     * @throws UnknownHostException\n     */\n    protected DnsResolvedFields getDnsResolvedFields() throws PayloadException,\n            UnknownHostException {\n        try {\n            DnsResolvedFields dnsResolvedFields;\n            boolean useDns = true;\n            if (mImsProxyAddr.matches(REGEX_IPV4)) {\n                useDns = false;\n                dnsResolvedFields = new DnsResolvedFields(mImsProxyAddr, mImsProxyPort);\n\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"IP address found instead of FQDN!\");\n                }\n            } else {\n                dnsResolvedFields = new DnsResolvedFields(null, mImsProxyPort);\n            }\n            if (useDns) {\n                ResolverConfig.refresh();\n                ExtendedResolver resolver = new ExtendedResolver();\n                /*\n                 * Resolve the IMS proxy configuration: first try to resolve via a NAPTR query, then\n                 * a SRV query and finally via A query\n                 */\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Resolve IMS proxy address \".concat(mImsProxyAddr));\n                }\n                /* DNS NAPTR lookup */\n                String service;\n                if (ListeningPoint.UDP.equals(mImsProxyProtocol)) {\n                    service = DNS_SIP_UDP_SERVICE;\n\n                } else if (ListeningPoint.TCP.equals(mImsProxyProtocol)) {\n                    service = DNS_SIP_TCP_SERVICE;\n\n                } else if (ListeningPoint.TLS.equals(mImsProxyProtocol)) {\n                    service = DNS_SIP_TLS_SERVICE;\n\n                } else {\n                    throw new PayloadException(\"Unkown SIP protocol : \" + mImsProxyProtocol);\n                }\n                boolean resolved = false;\n                Record[] naptrRecords = getDnsRequest(mImsProxyAddr, resolver, Type.NAPTR);\n                if ((naptrRecords != null) && (naptrRecords.length > 0)) {\n                    /* First try with NAPTR */\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"NAPTR records found: \" + naptrRecords.length);\n                    }\n                    for (Record naptrRecord : naptrRecords) {\n                        NAPTRRecord naptr = (NAPTRRecord) naptrRecord;\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"NAPTR record: \".concat(naptr.toString()));\n                        }\n                        if ((naptr != null) && naptr.getService().equalsIgnoreCase(service)) {\n                            /* DNS SRV lookup */\n                            Record[] srvRecords = getDnsRequest(naptr.getReplacement().toString(),\n                                    resolver, Type.SRV);\n                            if ((srvRecords != null) && (srvRecords.length > 0)) {\n                                SRVRecord srvRecord = getBestDnsSRV(srvRecords);\n                                dnsResolvedFields.mIpAddress = getDnsA(srvRecord.getTarget()\n                                        .toString());\n                                dnsResolvedFields.mPort = srvRecord.getPort();\n                            } else {\n                                /* Direct DNS A lookup */\n                                dnsResolvedFields.mIpAddress = getDnsA(mImsProxyAddr);\n                            }\n                            resolved = true;\n                        }\n                    }\n                }\n                if (!resolved) {\n                    /* If no NAPTR: direct DNS SRV lookup */\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"No NAPTR record found: use DNS SRV instead\");\n                    }\n                    String srvQuery;\n                    if (mImsProxyAddr.startsWith(DNS_SIP_PREFIX)\n                            || mImsProxyAddr.startsWith(DNS_SIPS_PREFIX)) {\n                        srvQuery = mImsProxyAddr;\n                    } else {\n                        srvQuery = getSrvQuery(service);\n                    }\n                    Record[] srvRecords = getDnsRequest(srvQuery, resolver, Type.SRV);\n                    if ((srvRecords != null) && (srvRecords.length > 0)) {\n                        SRVRecord srvRecord = getBestDnsSRV(srvRecords);\n                        dnsResolvedFields.mIpAddress = getDnsA(srvRecord.getTarget().toString());\n                        dnsResolvedFields.mPort = srvRecord.getPort();\n                        resolved = true;\n                    }\n                    if (!resolved) {\n                        /* If not resolved: direct DNS A lookup */\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"No SRV record found: use DNS A instead\");\n                        }\n                        dnsResolvedFields.mIpAddress = getDnsA(mImsProxyAddr);\n                    }\n                }\n            }\n            if (dnsResolvedFields.mIpAddress == null) {\n                /* Try to use IMS proxy address as a fallback */\n                String imsProxyAddrResolved = getDnsA(mImsProxyAddr);\n                if (imsProxyAddrResolved == null) {\n                    throw new PayloadException(\"Proxy IP address : \" + mImsProxyAddr\n                            + \" not found!\");\n                }\n                dnsResolvedFields = new DnsResolvedFields(imsProxyAddrResolved, mImsProxyPort);\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"SIP outbound proxy configuration: \" + dnsResolvedFields.mIpAddress\n                        + \":\" + dnsResolvedFields.mPort + \";\" + mImsProxyProtocol);\n            }\n            return dnsResolvedFields;\n\n        } catch (TextParseException e) {\n            throw new PayloadException(\"Failed to resolve dns for proxy configuration: \"\n                    + mImsProxyAddr + \" with protocol: \" + mImsProxyProtocol + \"!\", e);\n        }\n    }\n\n    /**\n     * Register to the IMS\n     * \n     * @param dnsResolvedFields The {@link DnsResolvedFields} object containing the DNS resolved\n     *            fields.\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void register(DnsResolvedFields dnsResolvedFields) throws PayloadException,\n            NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Register to IMS\");\n            }\n            if (dnsResolvedFields == null) {\n                dnsResolvedFields = getDnsResolvedFields();\n            }\n            mSip.initStack(mAccess.getIpAddress(), dnsResolvedFields.mIpAddress,\n                    dnsResolvedFields.mPort, mImsProxyProtocol, mTcpFallback);\n            mSip.getSipStack().addSipEventListener(mImsModule);\n\n            mRegistration.register();\n\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"IMS registered: \".concat(Boolean.toString(mRegistration\n                        .isRegistered())));\n            }\n            // If registration is not successful skip starting keepalive\n            if (!mRegistration.isRegistered()) {\n                return;\n            }\n            /**\n             * Even if DUT is not behind NAT (Network Address Translation) and PROTOCOL !=\n             * ListeningPoint.UDP, it should still send the keep-Alive (double CRLF).\n             */\n            if (mRcsSettings.isSipKeepAliveEnabled()\n                    && !ListeningPoint.UDP.equals(mImsProxyProtocol)) {\n                mSip.getSipStack().getKeepAliveManager().start();\n            }\n        } catch (UnknownHostException e) {\n            throw new PayloadException(\n                    \"Unable to register due to stack initialization failure for address : \"\n                            + mImsProxyAddr, e);\n        }\n    }\n\n    /**\n     * Unregister from the IMS\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void unregister() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Unregister from IMS\");\n        }\n\n        mRegistration.deRegister();\n\n        mSip.closeStack();\n    }\n\n    /**\n     * Registration terminated\n     */\n    public void registrationTerminated() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Registration has been terminated\");\n        }\n\n        // Stop registration\n        mRegistration.stopRegistration();\n\n        // Close the SIP stack\n        mSip.closeStack();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/MobileNetworkInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network;\n\nimport com.gsma.rcs.core.access.MobileNetworkAccess;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.net.ConnectivityManager;\n\n/**\n * Mobile network interface\n * \n * @author JM. Auffret\n */\npublic class MobileNetworkInterface extends ImsNetworkInterface {\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param imsModule IMS module\n     * @param rcsSettings the RCS settings accessor\n     */\n    public MobileNetworkInterface(ImsModule imsModule, RcsSettings rcsSettings) {\n        super(imsModule, ConnectivityManager.TYPE_MOBILE, new MobileNetworkAccess(rcsSettings),\n                rcsSettings.getImsProxyAddrForMobile(), rcsSettings.getImsProxyPortForMobile(),\n                rcsSettings.getSipDefaultProtocolForMobile(), rcsSettings\n                        .getImsAuthenticationProcedureForMobile(), rcsSettings);\n\n        if (logger.isActivated()) {\n            logger.info(\"Mobile network interface has been loaded\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/NetworkException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.network;\n\n/**\n * To be thrown when a transaction gets interrupted due to network error, For ex : Loss of\n * connectivity or Airplane mode e.t.c\n * <p>\n * These exceptions should not be logged as there is not much to do for handling such type of\n * exceptions other then re-trying the transactions once network is restored.\n * </p>\n */\npublic class NetworkException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public NetworkException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public NetworkException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/WifiNetworkInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network;\n\nimport com.gsma.rcs.core.access.WifiNetworkAccess;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.net.ConnectivityManager;\n\n/**\n * Wi-Fi network interface\n * \n * @author JM. Auffret\n */\npublic class WifiNetworkInterface extends ImsNetworkInterface {\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param imsModule IMS module\n     * @param rcsSettings the RCS settings accessor\n     */\n    public WifiNetworkInterface(ImsModule imsModule, RcsSettings rcsSettings) {\n        super(imsModule, ConnectivityManager.TYPE_WIFI, new WifiNetworkAccess(rcsSettings),\n                rcsSettings.getImsProxyAddrForWifi(), rcsSettings.getImsProxyPortForWifi(),\n                rcsSettings.getSipDefaultProtocolForWifi(), rcsSettings\n                        .getImsAuthenticationProcedureForWifi(), rcsSettings);\n\n        if (logger.isActivated()) {\n            logger.info(\"Wi-Fi network interface has been loaded\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/gsm/CallManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.gsm;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.telephony.PhoneStateListener;\nimport android.telephony.TelephonyManager;\n\nimport java.util.Timer;\nimport java.util.TimerTask;\n\n/**\n * Call manager. Note: for outgoing call the capability request is initiated only when we receive\n * the OPTIONS from the remote because the call state goes directly to CONNETED even if the remote\n * has not ringing. For the incoming call, the capability are requested when phone is ringing.\n * \n * @author jexa7410\n */\npublic class CallManager {\n\n    private enum State {\n        /**\n         * Call state unknown\n         */\n        UNKNOWN,\n        /**\n         * Call state ringing\n         */\n        RINGING,\n        /**\n         * Call state connected\n         */\n        CONNECTED,\n        /**\n         * Call state disconnected\n         */\n        DISCONNECTED;\n    }\n\n    private final ImsModule mImsModule;\n\n    private State callState = State.UNKNOWN;\n\n    /**\n     * Remote contact\n     */\n    private static ContactId sContact;\n\n    private boolean mMultipartyCall = false;\n\n    private boolean mCallHold = false;\n\n    private final TelephonyManager mPhonyManager;\n\n    private BroadcastReceiver mOutgoingCallReceiver;\n\n    private final Context mCtx;\n\n    private static final Logger sLogger = Logger.getLogger(CallManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent The ImsModule this manager is part of\n     * @param ctx The Context this manager is part of\n     */\n    public CallManager(ImsModule parent, Context ctx) {\n        mImsModule = parent;\n        mCtx = ctx;\n        mPhonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);\n    }\n\n    /**\n     * Start call monitoring\n     */\n    public void start() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start call monitoring\");\n        }\n        mOutgoingCallReceiver = new BroadcastReceiver() {\n            @Override\n            public void onReceive(Context context, Intent intent) {\n                PhoneNumber number = ContactUtil.getValidPhoneNumberFromAndroid(intent\n                        .getStringExtra(Intent.EXTRA_PHONE_NUMBER));\n                if (number != null) {\n                    setRemoteParty(ContactUtil.createContactIdFromValidatedData(number));\n                }\n            }\n        };\n        /* Monitor phone state */\n        mPhonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);\n\n        mCtx.registerReceiver(mOutgoingCallReceiver, new IntentFilter(\n                Intent.ACTION_NEW_OUTGOING_CALL));\n    }\n\n    /**\n     * Stop call monitoring\n     */\n    public void stop() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Stop call monitoring\");\n        }\n        if (mOutgoingCallReceiver != null) {\n            mCtx.unregisterReceiver(mOutgoingCallReceiver);\n            mOutgoingCallReceiver = null;\n        }\n        /* Stop monitoring phone state */\n        mPhonyManager.listen(listener, PhoneStateListener.LISTEN_NONE);\n    }\n\n    /**\n     * Phone state listener\n     */\n    private PhoneStateListener listener = new PhoneStateListener() {\n        public void onCallStateChanged(final int state, final String incomingNumber) {\n            mImsModule.getCore().scheduleCoreOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        boolean logActivated = sLogger.isActivated();\n                        switch (state) {\n                            case TelephonyManager.CALL_STATE_RINGING:\n                                if (State.CONNECTED == callState) {\n                                    // Tentative of multiparty call\n                                    return;\n                                }\n                                PhoneNumber number = ContactUtil\n                                        .getValidPhoneNumberFromAndroid(incomingNumber);\n                                if (number == null) {\n                                    if (logActivated) {\n                                        sLogger.info(new StringBuilder(\"Invalid phone number '\")\n                                                .append(incomingNumber).append(\"' is RINGING\")\n                                                .toString());\n                                    }\n                                    return;\n                                }\n                                // Set remote party\n                                if (logActivated) {\n                                    sLogger.debug(\"Call is RINGING: incoming number=\"\n                                            .concat(incomingNumber));\n                                }\n                                sContact = ContactUtil.createContactIdFromValidatedData(number);\n                                // Phone is ringing: this state is only used for incoming call\n                                callState = State.RINGING;\n                                break;\n\n                            case TelephonyManager.CALL_STATE_IDLE:\n                                if (logActivated) {\n                                    sLogger.debug(\"Call is IDLE: last number=\" + sContact);\n                                }\n\n                                // No more call in progress\n                                callState = State.DISCONNECTED;\n                                mMultipartyCall = false;\n                                mCallHold = false;\n\n                                /* Terminate richcall sessions */\n                                mImsModule.getRichcallService().terminateAllSessions();\n\n                                if (sContact == null) {\n                                    return;\n                                }\n                                // Disable content sharing capabilities\n                                mImsModule.getCapabilityService()\n                                        .resetContactCapabilitiesForContentSharing(sContact);\n\n                                // Request capabilities to the remote\n                                mImsModule.getCapabilityService().requestContactCapabilities(\n                                        sContact);\n\n                                // Reset remote party\n                                sContact = null;\n                                break;\n\n                            case TelephonyManager.CALL_STATE_OFFHOOK:\n                                if (State.CONNECTED == callState) {\n                                    /*\n                                     * Request capabilities only if not a multiparty call or call\n                                     * hold.\n                                     */\n                                    if (logActivated) {\n                                        sLogger.debug(\"Multiparty call established\");\n                                    }\n                                    return;\n                                }\n\n                                if (logActivated) {\n                                    sLogger.debug(\"Call is CONNECTED: connected number=\" + sContact);\n                                }\n\n                                /* Both parties are connected. */\n                                callState = State.CONNECTED;\n\n                                /*\n                                 * Delay option request 2 seconds according to implementation\n                                 * guideline ID_4_20.\n                                 */\n                                Timer timer = new Timer();\n                                timer.schedule(new TimerTask() {\n                                    @Override\n                                    public void run() {\n                                        if (sContact != null) {\n                                            requestCapabilities(sContact);\n                                        }\n                                    }\n                                }, 2000);\n                                break;\n\n                            default:\n                                if (logActivated) {\n                                    sLogger.debug(\"Unknown call state \".concat(Integer\n                                            .toString(state)));\n                                }\n                                break;\n                        }\n\n                    } catch (ContactManagerException e) {\n                        sLogger.error(\n                                new StringBuilder(\"Unable to handle call state : \").append(state)\n                                        .append(\" for incoming number : \").append(incomingNumber)\n                                        .toString(), e);\n                    } catch (PayloadException e) {\n                        sLogger.error(\n                                new StringBuilder(\"Unable to handle call state : \").append(state)\n                                        .append(\" for incoming number : \").append(incomingNumber)\n                                        .toString(), e);\n                    } catch (NetworkException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(e.getMessage());\n                        }\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\n                                new StringBuilder(\"Unable to handle call state : \").append(state)\n                                        .append(\" for incoming number : \").append(incomingNumber)\n                                        .toString(), e);\n                    }\n                }\n            });\n        }\n    };\n\n    /**\n     * Set the remote contact\n     * \n     * @param contact\n     */\n    public static void setRemoteParty(ContactId contact) {\n        sContact = contact;\n    }\n\n    /**\n     * Get the remote connected phone number\n     * \n     * @return Phone number or null is disconnected\n     */\n    private ContactId getPhoneNumberOfConntectedRemote() {\n        if (State.DISCONNECTED == callState) {\n            return null;\n        }\n        return sContact;\n    }\n\n    /**\n     * Returns the calling remote contact identifier\n     * \n     * @return MSISDN\n     */\n    public ContactId getContact() {\n        return sContact;\n    }\n\n    /**\n     * Is call connected\n     * \n     * @return Boolean\n     */\n    public boolean isCallConnected() {\n        return (State.CONNECTED == callState);\n    }\n\n    /**\n     * Is call connected with a given contact\n     * \n     * @param contact Contact identifier\n     * @return Boolean\n     */\n\n    public boolean isCallConnectedWith(ContactId contact) {\n        if (mMultipartyCall || mCallHold) {\n            return false;\n        }\n\n        return (isCallConnected() && contact != null && contact\n                .equals(getPhoneNumberOfConntectedRemote()));\n    }\n\n    /**\n     * Is a multiparty call\n     * \n     * @return Boolean\n     */\n    public boolean isMultipartyCall() {\n        return mMultipartyCall;\n    }\n\n    /**\n     * Is call hold\n     * \n     * @return Boolean\n     */\n    public boolean isCallHold() {\n        return mCallHold;\n    }\n\n    /**\n     * Request capabilities to a given contact\n     * \n     * @param contact Contact identifier\n     */\n    private void requestCapabilities(ContactId contact) {\n        CapabilityService capabilityService = mImsModule.getCapabilityService();\n        if (capabilityService.isServiceStarted()) {\n            capabilityService.requestContactCapabilities(contact);\n        }\n    }\n\n    /**\n     * Call leg has changed\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    private void callLegHasChanged() throws PayloadException, NetworkException {\n        if (mMultipartyCall | mCallHold) {\n            /* Terminate richcall sessions if call hold or multiparty call */\n            mImsModule.getRichcallService().terminateAllSessions();\n        }\n        if (sContact != null) {\n            requestCapabilities(sContact);\n        }\n    }\n\n    /**\n     * Set multiparty call\n     * \n     * @param state State\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void setMultiPartyCall(boolean state) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Set multiparty call to \" + state);\n        }\n        mMultipartyCall = state;\n\n        callLegHasChanged();\n    }\n\n    /**\n     * Set call hold\n     * \n     * @param state State\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void setCallHold(boolean state) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Set call hold to \" + state);\n        }\n        mCallHold = state;\n\n        callLegHasChanged();\n    }\n\n    /**\n     * Connection event\n     * \n     * @param connected Connection state\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    public void connectionEvent(boolean connected) throws PayloadException, NetworkException,\n            ContactManagerException {\n        if (sContact == null) {\n            return;\n        }\n\n        if (connected) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Connectivity changed: update content sharing capabilities\");\n            }\n\n            // Update content sharing capabilities\n            requestCapabilities(sContact);\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Connectivity changed: disable content sharing capabilities\");\n            }\n\n            // Disable content sharing capabilities\n            mImsModule.getCapabilityService().resetContactCapabilitiesForContentSharing(sContact);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/registration/GibaRegistrationProcedure.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.registration;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.telephony.TelephonyManager;\n\nimport java.text.ParseException;\nimport java.util.ListIterator;\n\nimport javax2.sip.address.Address;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.address.URI;\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Header;\n\n/**\n * GIBA or early-IMS registration procedure\n * \n * @author jexa7410\n */\npublic class GibaRegistrationProcedure extends RegistrationProcedure {\n    /**\n     * IMSI\n     */\n    private String mImsi;\n\n    /**\n     * MNC\n     */\n    private String mMnc;\n\n    /**\n     * MCC\n     */\n    private String mMcc;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(GibaRegistrationProcedure.class\n            .getName());\n\n    /**\n     * Constructor\n     */\n    public GibaRegistrationProcedure() {\n    }\n\n    /**\n     * Initialize procedure\n     */\n    public void init() {\n        TelephonyManager mgr = (TelephonyManager) AndroidFactory.getApplicationContext()\n                .getSystemService(Context.TELEPHONY_SERVICE);\n        mImsi = mgr.getSubscriberId();\n        String mcc_mnc = mgr.getSimOperator();\n        mMcc = mcc_mnc.substring(0, 3);\n        mMnc = mcc_mnc.substring(3);\n        if (mcc_mnc.length() == 5) {\n            mMnc = \"0\" + mMnc;\n        }\n    }\n\n    /**\n     * Returns the home domain name\n     * \n     * @return Domain name\n     */\n    public String getHomeDomain() {\n        return \"ims.mnc\" + mMnc + \".mcc\" + mMcc + \".3gppnetwork.org\";\n    }\n\n    /**\n     * Returns the public URI or IMPU for registration\n     * \n     * @return Public URI\n     */\n    public String getPublicUri() {\n        // Derived IMPU from IMSI: <IMSI>@mnc<MNC>.mcc<MCC>.3gppnetwork.org\n        return PhoneUtils.SIP_URI_HEADER + mImsi + \"@\" + getHomeDomain();\n    }\n\n    /**\n     * Write the security header to REGISTER request\n     * \n     * @param request Request\n     */\n    public void writeSecurityHeader(SipRequest request) {\n        // Nothing to do here\n    }\n\n    /**\n     * Read the security header from REGISTER response\n     * \n     * @param response Response\n     * @throws PayloadException\n     */\n    public void readSecurityHeader(SipResponse response) throws PayloadException {\n        SipURI sipUri = getSipUri(response.getHeaders(SipUtils.HEADER_P_ASSOCIATED_URI));\n\n        String user = sipUri.getUser();\n        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(user);\n        if (number == null) {\n            throw new PayloadException(new StringBuilder(\n                    \"Can't read a SIP-URI from the P-Associated-URI header: invalid user '\")\n                    .append(user).append(\"'\").toString());\n        }\n        UserProfile profile = ImsModule.getImsUserProfile();\n        profile.setUsername(ContactUtil.createContactIdFromValidatedData(number));\n        profile.setHomeDomain(sipUri.getHost());\n        profile.setXdmServerLogin(PhoneUtils.SIP_URI_HEADER + sipUri.getUser() + \"@\"\n                + sipUri.getHost());\n    }\n\n    /**\n     * Return the associated SIP URI fetched from the 200 OK response\n     * \n     * @param list\n     * @return\n     * @throws PayloadException\n     */\n    private SipURI getSipUri(ListIterator<Header> list) throws PayloadException {\n        SipURI sipUri = null;\n        while (list.hasNext()) {\n            ExtensionHeader associatedHeader = (ExtensionHeader) list.next();\n            String unparsedAddress = associatedHeader.getValue();\n            try {\n                Address sipAddr = SipUtils.ADDR_FACTORY.createAddress(unparsedAddress);\n                URI uri = sipAddr.getURI();\n                if (uri instanceof SipURI) {\n                    sipUri = (SipURI) sipAddr.getURI();\n                    break;\n                }\n            } catch (ParseException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(new StringBuilder(\"Failed to parse extension header '\")\n                            .append(unparsedAddress).append(\"'\").toString());\n                }\n            }\n        }\n        if (sipUri == null) {\n            throw new PayloadException(\"No SIP-URI found in the P-Associated-URI header!\");\n        }\n        return sipUri;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/registration/HttpDigestRegistrationProcedure.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.registration;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.security.HttpDigestMd5Authentication;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\nimport com.gsma.rcs.utils.PhoneUtils;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.AuthenticationInfoHeader;\nimport javax2.sip.header.AuthorizationHeader;\nimport javax2.sip.header.WWWAuthenticateHeader;\n\n/**\n * HTTP Digest MD5 registration procedure\n * \n * @author jexa7410\n * @author Deutsche Telekom AG\n */\npublic class HttpDigestRegistrationProcedure extends RegistrationProcedure {\n    /**\n     * HTTP Digest MD5 agent\n     */\n    private HttpDigestMd5Authentication mDigest;\n\n    /**\n     * Constructor\n     */\n    public HttpDigestRegistrationProcedure() {\n    }\n\n    /**\n     * Initialize procedure\n     */\n    public void init() {\n        mDigest = new HttpDigestMd5Authentication();\n    }\n\n    /**\n     * Returns the home domain name\n     * \n     * @return Domain name\n     */\n    public String getHomeDomain() {\n        return ImsModule.getImsUserProfile().getHomeDomain();\n    }\n\n    /**\n     * Returns the public URI or IMPU for registration\n     * \n     * @return Public URI\n     */\n    public String getPublicUri() {\n        UserProfile profile = ImsModule.getImsUserProfile();\n        return new StringBuilder(PhoneUtils.SIP_URI_HEADER).append(profile.getUsername())\n                .append(\"@\").append(profile.getHomeDomain()).toString();\n    }\n\n    /**\n     * Write security header to REGISTER request\n     * \n     * @param request Request\n     * @throws PayloadException\n     */\n    public void writeSecurityHeader(SipRequest request) throws PayloadException {\n        try {\n            String realm = mDigest.getRealm();\n            UserProfile profile = ImsModule.getImsUserProfile();\n            if (realm == null) {\n                realm = profile.getRealm();\n            }\n\n            String nonce = \"\";\n            if (mDigest.getNextnonce() != null) {\n                mDigest.updateNonceParameters();\n                nonce = mDigest.getNonce();\n            }\n            String requestUri = request.getRequestURI();\n            String user = profile.getPrivateID();\n            String response = \"\";\n            if (nonce.length() > 0) {\n                String password = profile.getPassword();\n                response = mDigest.calculateResponse(user, password, request.getMethod(),\n                        requestUri, mDigest.buildNonceCounter(), request.getContent());\n            }\n\n            /* Build the Authorization header */\n            StringBuilder auth = new StringBuilder(\"Digest username=\\\"\").append(user)\n                    .append(\"\\\",uri=\\\"\").append(requestUri).append(\"\\\",algorithm=MD5,realm=\\\"\")\n                    .append(realm).append(\"\\\",nonce=\\\"\").append(nonce).append(\"\\\",response=\\\"\")\n                    .append(response).append(\"\\\"\");\n            String opaque = mDigest.getOpaque();\n            if (opaque != null) {\n                auth.append(\",opaque=\\\"\").append(opaque).append(\"\\\"\");\n            }\n            String qop = mDigest.getQop();\n            if (qop != null && qop.startsWith(\"auth\")) {\n                auth.append(\",nc=\").append(mDigest.buildNonceCounter()).append(\",qop=\").append(qop)\n                        .append(\",cnonce=\\\"\").append(mDigest.getCnonce()).append(\"\\\"\");\n            }\n            request.addHeader(AuthorizationHeader.NAME, auth.toString());\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to write security header!\", e);\n        }\n    }\n\n    /**\n     * Read security header from REGISTER response\n     * \n     * @param response SIP response\n     * @throws PayloadException\n     */\n    public void readSecurityHeader(SipResponse response) throws PayloadException {\n\n        WWWAuthenticateHeader wwwHeader = (WWWAuthenticateHeader) response\n                .getHeader(WWWAuthenticateHeader.NAME);\n        AuthenticationInfoHeader infoHeader = (AuthenticationInfoHeader) response\n                .getHeader(AuthenticationInfoHeader.NAME);\n\n        if (wwwHeader != null) {\n            /* Retrieve data from the header WWW-Authenticate (401 response) */\n            mDigest.setRealm(wwwHeader.getRealm());\n            mDigest.setOpaque(wwwHeader.getOpaque());\n            mDigest.setQop(wwwHeader.getQop());\n            mDigest.setNextnonce(wwwHeader.getNonce());\n\n        } else if (infoHeader != null) {\n            // Retrieve data from the header Authentication-Info (200 OK response)\n\n            // Check if 200 OK really included Authentication-Info: nextnonce=\"\"\n            if (infoHeader.getNextNonce() != null) {\n                // Get nextnonce to be used\n                mDigest.setNextnonce(infoHeader.getNextNonce());\n            }\n        }\n    }\n\n    /**\n     * Returns HTTP digest\n     * \n     * @return HTTP digest\n     */\n    public HttpDigestMd5Authentication getHttpDigest() {\n        return mDigest;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/registration/RegistrationManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.registration;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.ImsError;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipInterface;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provisioning.https.HttpsProvisioningService;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.DeviceUtils;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.RcsServiceRegistration.ReasonCode;\n\nimport android.content.Context;\n\nimport java.util.ListIterator;\n\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.RetryAfterHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.message.Response;\n\n/**\n * Registration manager (register, re-register, un-register)\n * \n * @author JM. Auffret\n */\npublic class RegistrationManager extends PeriodicRefresher {\n\n    private static final int MAX_REGISTRATION_FAILURES = 3;\n\n    /**\n     * maximum number of 403 failure attempts to register after provisioning success\n     */\n    private static final int MAX_403_REGISTRATION_FAILURES = 5;\n\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    private static final long DEFAULT_EXPIRE_PERIOD = 1200 * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n\n    private static final long SUBSTRACT_EXPIRE_PERIOD = DEFAULT_EXPIRE_PERIOD / 2;\n\n    /**\n     * First C Sequence\n     */\n    private static final int CSEQ_ONE = 1;\n\n    private long mExpirePeriod;\n\n    private SipDialogPath mDialogPath;\n\n    /**\n     * Supported feature tags\n     */\n    private String[] mFeatureTags;\n\n    private final ImsNetworkInterface mNetworkInterface;\n\n    private RegistrationProcedure mRegistrationProcedure;\n\n    private String mInstanceId;\n\n    private boolean mRegistered = false;\n\n    /**\n     * Reason code for un-registration\n     */\n    private RcsServiceRegistration.ReasonCode mReasonCode = RcsServiceRegistration.ReasonCode.UNSPECIFIED;\n\n    private boolean mPendingUnRegister = false;\n\n    private int mNb401Failures = 0;\n\n    /**\n     * Number of 4xx5xx6xx failures\n     */\n    private int mNb4xx5xx6xxFailures;\n\n    private final RcsSettings mRcsSettings;\n\n    private final Core mCore;\n\n    private static final Logger sLogger = Logger.getLogger(RegistrationManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param networkInterface IMS network interface\n     * @param registrationProcedure Registration procedure\n     * @param rcsSettings The RCS settings accessor\n     */\n    public RegistrationManager(ImsNetworkInterface networkInterface,\n            RegistrationProcedure registrationProcedure, RcsSettings rcsSettings) {\n        mCore = networkInterface.getImsModule().getCore();\n        mNetworkInterface = networkInterface;\n        mRegistrationProcedure = registrationProcedure;\n        mFeatureTags = RegistrationUtils.getSupportedFeatureTags(rcsSettings);\n        mRcsSettings = rcsSettings;\n        mExpirePeriod = mRcsSettings.getRegisterExpirePeriod();\n        if (mRcsSettings.isGruuSupported()) {\n            mInstanceId = DeviceUtils.getInstanceId(AndroidFactory.getApplicationContext(),\n                    rcsSettings);\n        }\n    }\n\n    /**\n     * Get the expiry value duration for the next SIP register\n     * \n     * @return value of the expiry period in milliseconds\n     */\n    private long getExpiryValue() {\n        if (CSEQ_ONE == mDialogPath.getCseq()) {\n            return mRcsSettings.getRegisterExpirePeriod();\n        }\n        return mExpirePeriod;\n    }\n\n    /**\n     * Init the registration procedure\n     */\n    public void init() {\n    }\n\n    /**\n     * Returns registration procedure\n     * \n     * @return Registration procedure\n     */\n    public RegistrationProcedure getRegistrationProcedure() {\n        return mRegistrationProcedure;\n    }\n\n    /**\n     * Is registered\n     * \n     * @return Return True if the terminal is registered, else return False\n     */\n    public boolean isRegistered() {\n        return mRegistered;\n    }\n\n    /**\n     * Gets reason code for RCS registration\n     * \n     * @return reason code\n     */\n    public RcsServiceRegistration.ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n\n    /**\n     * Restart registration procedure\n     */\n    public void restart() {\n        mCore.scheduleCoreOperation(new Runnable() {\n\n            @Override\n            public void run() {\n                // Stop the current registration\n                stopRegistration();\n                mFeatureTags = RegistrationUtils.getSupportedFeatureTags(mRcsSettings);\n                try {\n                    register();\n\n                } catch (PayloadException e) {\n                    sLogger.error(\"Registration has failed!\", e);\n                } catch (NetworkException e) {\n                    /* Nothing to be handled here */\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Registration has failed!\", e);\n                    handleError(new ImsError(ImsError.REGISTRATION_FAILED, e));\n                }\n\n            }\n        });\n    }\n\n    /**\n     * Attempts to perform a registration to IMS\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public synchronized void register() throws PayloadException, NetworkException {\n        try {\n            if (mDialogPath == null) {\n                /* Reset the registration authentication procedure */\n                mRegistrationProcedure.init();\n\n                SipInterface sipInterface = mNetworkInterface.getSipManager().getSipStack();\n                String callId = sipInterface.generateCallId();\n\n                String target = PhoneUtils.SIP_URI_HEADER.concat(mRegistrationProcedure\n                        .getHomeDomain());\n\n                String uri = mRegistrationProcedure.getPublicUri();\n                mDialogPath = new SipDialogPath(sipInterface, callId, 1, target, uri, uri,\n                        sipInterface.getDefaultRoutePath(), mRcsSettings);\n            } else {\n                mDialogPath.incrementCseq();\n            }\n\n            mNb401Failures = 0;\n\n            mNb4xx5xx6xxFailures = 0;\n\n            mNetworkInterface.setRetryAfterHeaderDuration(0);\n\n            SipRequest register = SipMessageFactory.createRegister(mDialogPath, mFeatureTags,\n                    getExpiryValue(), mInstanceId, mRcsSettings.isSipKeepAliveEnabled());\n\n            sendRegister(register);\n\n        } catch (PayloadException | NetworkException e) {\n            handleError(new ImsError(ImsError.REGISTRATION_FAILED, e));\n            throw e;\n        }\n\n    }\n\n    private boolean isBatteryLow() {\n        return mNetworkInterface.getImsModule().getImsConnectionManager().isDisconnectedByBattery();\n    }\n\n    /**\n     * Stop the registration manager without unregistering from IMS\n     */\n    public synchronized void stopRegistration() {\n        if (!mRegistered) {\n            // Already unregistered\n            return;\n        }\n\n        // Stop periodic registration\n        stopTimer();\n\n        // Force registration flag to false\n        mRegistered = false;\n\n        // Reset dialog path attributes\n        resetDialogPath();\n\n        mReasonCode = isBatteryLow() ? RcsServiceRegistration.ReasonCode.BATTERY_LOW\n                : RcsServiceRegistration.ReasonCode.CONNECTION_LOST;\n\n        // Notify event listener\n        mCore.getListener().onRegistrationTerminated(mReasonCode);\n    }\n\n    /**\n     * Performs a de-registration to IMS\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public synchronized void deRegister() throws PayloadException, NetworkException {\n        if (mRegistered) {\n            mPendingUnRegister = false;\n\n            stopTimer();\n\n            mDialogPath.incrementCseq();\n\n            mNb4xx5xx6xxFailures = 0;\n\n            /* Create REGISTER request with expire 0 */\n            SipRequest register = SipMessageFactory.createRegister(mDialogPath, mFeatureTags, 0,\n                    mInstanceId, mRcsSettings.isSipKeepAliveEnabled());\n            sendRegister(register);\n\n            mRegistered = false;\n\n            resetDialogPath();\n\n            mReasonCode = isBatteryLow() ? RcsServiceRegistration.ReasonCode.BATTERY_LOW\n                    : RcsServiceRegistration.ReasonCode.CONNECTION_LOST;\n\n            mCore.getListener().onRegistrationTerminated(mReasonCode);\n        } else {\n            mPendingUnRegister = true;\n        }\n    }\n\n    /**\n     * Send REGISTER message\n     * \n     * @param register SIP REGISTER\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendRegister(SipRequest register) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send REGISTER, expire=\" + register.getExpires() + \"ms\");\n        }\n        // Set the security header\n        mRegistrationProcedure.writeSecurityHeader(register);\n        // Send REGISTER request\n        SipTransactionContext ctx = mNetworkInterface.getSipManager().sendSipMessageAndWait(\n                register);\n        // Analyze the received response\n        if (ctx.isSipResponse()) {\n            // A response has been received\n            switch (ctx.getStatusCode()) {\n                case Response.OK:\n                    /**\n                     * 200 OK\n                     */\n                    if (register.getExpires() != 0) {\n                        handle200OK(ctx);\n                        Context appContext = AndroidFactory.getApplicationContext();\n                        /* Reset registration forbidden failure count to default value */\n                        LauncherUtils.setRegForbiddenCount(appContext, 0);\n\n                    } else {\n                        handle200OkUnregister();\n                    }\n                    break;\n\n                case Response.MOVED_TEMPORARILY:\n                    /**\n                     * 302 Moved Temporarily\n                     */\n                    handle302MovedTemporarily(ctx);\n                    break;\n\n                case Response.UNAUTHORIZED:\n                    /**\n                     * 401 Unauthorized\n                     */\n                    handle401Unauthorized(ctx);\n                    break;\n\n                case Response.FORBIDDEN:\n                    /**\n                     * 403 Forbidden\n                     */\n                    handle403Forbidden();\n                    break;\n\n                case Response.INTERVAL_TOO_BRIEF:\n                    /**\n                     * 423 Interval Too Brief\n                     */\n                    handle423IntervalTooBrief(ctx);\n                    break;\n\n                case Response.NOT_FOUND:\n                case Response.REQUEST_TIMEOUT:\n                case Response.TEMPORARILY_UNAVAILABLE:\n                case Response.SERVER_INTERNAL_ERROR:\n                case Response.SERVICE_UNAVAILABLE:\n                case Response.SERVER_TIMEOUT:\n                case Response.BUSY_EVERYWHERE:\n                    /**\n                     * Intentional fall-through for 4xx, 5xx & 6xx SIP error responses.\n                     */\n                    handle4xx5xx6xxNoRetryAfterHeader(ctx);\n                    break;\n\n                default:\n                    /**\n                     * Other error response\n                     */\n                    handleError(new ImsError(ImsError.REGISTRATION_FAILED, ctx.getStatusCode()\n                            + \" \" + ctx.getReasonPhrase()));\n                    break;\n            }\n        } else {\n            // No response received: timeout\n            handleError(new ImsError(ImsError.REGISTRATION_FAILED, \"timeout\"));\n        }\n    }\n\n    /**\n     * Handle 403 forbidden response\n     */\n    private void handle403Forbidden() {\n        Context appContext = AndroidFactory.getApplicationContext();\n        int regForbiddenCount = LauncherUtils.getRegForbiddenCount(appContext);\n        if (regForbiddenCount < MAX_403_REGISTRATION_FAILURES) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Received 403 Forbidden : Retry count \" + regForbiddenCount);\n            }\n            regForbiddenCount++;\n            LauncherUtils.setRegForbiddenCount(appContext, regForbiddenCount);\n            LauncherUtils.stopRcsCoreService(appContext);\n            HttpsProvisioningService.startHttpsProvisioningService(appContext, true, false);\n\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Received 403 Forbidden & Reached max retry count\");\n            }\n            LauncherUtils.stopRcsService(appContext);\n            /* As registration is not successful with current configuration, reset to default */\n            mRcsSettings.resetConfigParameters();\n            /* Set the configuration validity flag to false */\n            mRcsSettings.setConfigurationValid(false);\n            /* Reset to default value */\n            LauncherUtils.setRegForbiddenCount(appContext, 0);\n        }\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle200OK(SipTransactionContext ctx) throws PayloadException, NetworkException {\n        // 200 OK response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n        SipResponse resp = ctx.getSipResponse();\n        // Set the associated URIs\n        ListIterator<Header> associatedHeader = resp.getHeaders(SipUtils.HEADER_P_ASSOCIATED_URI);\n        ImsModule.getImsUserProfile().setAssociatedUri(associatedHeader);\n        // Set the GRUU\n        SipInterface sipInterface = mNetworkInterface.getSipManager().getSipStack();\n        sipInterface.setInstanceId(mInstanceId);\n        ListIterator<Header> contacts = resp.getHeaders(ContactHeader.NAME);\n        while (contacts.hasNext()) {\n            ContactHeader contact = (ContactHeader) contacts.next();\n            String contactInstanceId = contact.getParameter(SipUtils.SIP_INSTANCE_PARAM);\n            if ((contactInstanceId != null) && (mInstanceId != null)\n                    && (mInstanceId.contains(contactInstanceId))) {\n                String pubGruu = contact.getParameter(SipUtils.PUBLIC_GRUU_PARAM);\n                sipInterface.setPublicGruu(pubGruu);\n                String tempGruu = contact.getParameter(SipUtils.TEMP_GRUU_PARAM);\n                sipInterface.setTemporaryGruu(tempGruu);\n            }\n        }\n        // Set the service route path\n        ListIterator<Header> routes = resp.getHeaders(SipUtils.HEADER_SERVICE_ROUTE);\n        sipInterface.setServiceRoutePath(routes);\n        // If the IP address of the Via header in the 200 OK response to the initial\n        // SIP REGISTER request is different than the local IP address then there is a NAT\n        String localIpAddr = mNetworkInterface.getNetworkAccess().getIpAddress();\n        ViaHeader respViaHeader = ctx.getSipResponse().getViaHeaders().next();\n        String received = respViaHeader.getParameter(\"received\");\n        if (!respViaHeader.getHost().equals(localIpAddr)\n                || ((received != null) && !received.equals(localIpAddr))) {\n            mNetworkInterface.setNatTraversal(true);\n            mNetworkInterface.setNatPublicAddress(received);\n            String viaRportStr = respViaHeader.getParameter(\"rport\");\n            int viaRport = -1;\n            if (viaRportStr != null) {\n                try {\n                    viaRport = Integer.parseInt(viaRportStr);\n                } catch (NumberFormatException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Non-numeric rport value \\\"\" + viaRportStr + \"\\\"\");\n                    }\n                }\n            }\n            mNetworkInterface.setNatPublicPort(viaRport);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"NAT public interface detected: \" + received + \":\" + viaRport);\n            }\n        } else {\n            mNetworkInterface.setNatTraversal(false);\n            mNetworkInterface.setNatPublicAddress(null);\n            mNetworkInterface.setNatPublicPort(-1);\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"NAT traversal detection: \" + mNetworkInterface.isBehindNat());\n        }\n        // Read the security header\n        mRegistrationProcedure.readSecurityHeader(resp);\n        // Retrieve the expire value in the response\n        retrieveExpirePeriod(resp);\n        mRegistered = true;\n        mReasonCode = ReasonCode.UNSPECIFIED;\n        // Start the periodic registration\n        long currentTime = System.currentTimeMillis();\n        if (mExpirePeriod <= DEFAULT_EXPIRE_PERIOD) {\n            startTimer(currentTime, mExpirePeriod, 0.5);\n        } else {\n            startTimer(currentTime, mExpirePeriod - SUBSTRACT_EXPIRE_PERIOD);\n        }\n        // Notify event listener\n        mCore.getListener().onRegistrationSuccessful();\n        /* Start deregister procedure if necessary */\n        if (mPendingUnRegister) {\n            deRegister();\n        }\n    }\n\n    private void handle200OkUnregister() {\n        // 200 OK response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n        // Reset the NAT parameters as we are not expecting any more messages\n        // for this registration\n        mNetworkInterface.setNatPublicAddress(null);\n        mNetworkInterface.setNatPublicPort(-1);\n    }\n\n    /**\n     * Handle 302 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle302MovedTemporarily(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        // 302 Moved Temporarily response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"302 Moved Temporarily response received\");\n        }\n        // Extract new target URI from Contact header of the received response\n        SipResponse resp = ctx.getSipResponse();\n        ContactHeader contactHeader = (ContactHeader) resp.getStackMessage().getHeader(\n                ContactHeader.NAME);\n        String newUri = contactHeader.getAddress().getURI().toString();\n        mDialogPath.setTarget(newUri);\n        // Increment the Cseq number of the dialog path\n        mDialogPath.incrementCseq();\n        // Create REGISTER request with security token\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send REGISTER to new address\");\n        }\n        SipRequest register = SipMessageFactory.createRegister(mDialogPath, mFeatureTags, ctx\n                .getTransaction().getRequest().getExpires().getExpires()\n                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE, mInstanceId,\n                mRcsSettings.isSipKeepAliveEnabled());\n        // Send REGISTER request\n        sendRegister(register);\n    }\n\n    /**\n     * Handle 401 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle401Unauthorized(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        /**\n         * Increment the number of 401 failures\n         */\n        mNb401Failures++;\n        // 401 response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"401 response received, nbFailures=\" + mNb401Failures);\n        }\n        if (mNb401Failures >= MAX_REGISTRATION_FAILURES) {\n            /**\n             * We reached MAX_REGISTRATION_FAILURES, stop registration retries\n             */\n            handleError(new ImsError(ImsError.REGISTRATION_FAILED, \"too many 401\"));\n            return;\n        }\n        SipResponse resp = ctx.getSipResponse();\n        // Read the security header\n        mRegistrationProcedure.readSecurityHeader(resp);\n        // Increment the Cseq number of the dialog path\n        mDialogPath.incrementCseq();\n        // Create REGISTER request with security token\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send REGISTER with security token\");\n        }\n        SipRequest register = SipMessageFactory.createRegister(mDialogPath, mFeatureTags, ctx\n                .getTransaction().getRequest().getExpires().getExpires()\n                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE, mInstanceId,\n                mRcsSettings.isSipKeepAliveEnabled());\n\n        // Send REGISTER request\n        sendRegister(register);\n    }\n\n    /**\n     * Handle 423 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle423IntervalTooBrief(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        // 423 response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"423 response received\");\n        }\n        SipResponse resp = ctx.getSipResponse();\n        // Increment the Cseq number of the dialog path\n        mDialogPath.incrementCseq();\n        mExpirePeriod = SipUtils.getMinExpiresPeriod(resp);\n        // Create a new REGISTER with the right expire period\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send new REGISTER\");\n        }\n        SipRequest register = SipMessageFactory.createRegister(mDialogPath, mFeatureTags,\n                mExpirePeriod, mInstanceId, mRcsSettings.isSipKeepAliveEnabled());\n        sendRegister(register);\n    }\n\n    /**\n     * Handle error response\n     * \n     * @param error Error\n     */\n    private void handleError(ImsError error) {\n        // Error\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Registration has failed: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        mRegistered = false;\n        mReasonCode = ReasonCode.CONNECTION_LOST;\n        // Registration has failed, stop the periodic registration\n        stopTimer();\n        // Reset dialog path attributes\n        resetDialogPath();\n        // Notify event listener\n        mCore.getListener().onRegistrationFailed(error);\n    }\n\n    /**\n     * Reset the dialog path\n     */\n    private void resetDialogPath() {\n        mDialogPath = null;\n    }\n\n    /**\n     * Retrieve the expire period\n     * \n     * @param response SIP response\n     */\n    private void retrieveExpirePeriod(SipResponse response) {\n        // Extract expire value from Contact header\n        ListIterator<Header> contacts = response.getHeaders(ContactHeader.NAME);\n        if (contacts != null) {\n            while (contacts.hasNext()) {\n                ContactHeader contact = (ContactHeader) contacts.next();\n                if (contact.getAddress().getHost()\n                        .equals(mNetworkInterface.getNetworkAccess().getIpAddress())) {\n                    int expires = contact.getExpires();\n                    if (expires != -1) {\n                        mExpirePeriod = expires * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n                    }\n                    return;\n                }\n            }\n        }\n        // Extract expire value from Expires header\n        ExpiresHeader expiresHeader = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME);\n        if (expiresHeader != null) {\n            int expires = expiresHeader.getExpires();\n            if (expires != -1) {\n                mExpirePeriod = expires * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            }\n        }\n    }\n\n    /**\n     * Registration processing\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void periodicProcessing() throws PayloadException, NetworkException {\n        // Make a registration\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Execute re-registration\");\n        }\n        register();\n    }\n\n    /**\n     * Handle 4xx5xx6xx response without retry header\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle4xx5xx6xxNoRetryAfterHeader(SipTransactionContext ctx)\n            throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"4xx5xx6xx response without retry after header received\");\n        }\n        final SipResponse response = ctx.getSipResponse();\n        final RetryAfterHeader retryHeader = (RetryAfterHeader) response.getStackMessage()\n                .getHeader(RetryAfterHeader.NAME);\n        if (retryHeader != null) {\n            final long durationInMillis = retryHeader.getDuration()\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            if (durationInMillis > 0) {\n                mNetworkInterface.setRetryAfterHeaderDuration(durationInMillis);\n                handleError(new ImsError(ImsError.REGISTRATION_FAILED, \"retry after\"\n                        + durationInMillis + \" for 4xx/5xx/6xx\"));\n\n            } else {\n                mNb4xx5xx6xxFailures++;\n                if (mNb4xx5xx6xxFailures >= MAX_REGISTRATION_FAILURES) {\n                    /**\n                     * We reached MAX_REGISTRATION_FAILURES, stop registration retries\n                     */\n                    handleError(new ImsError(ImsError.REGISTRATION_FAILED, \"too many 4xx/5xx/6xx\"));\n                }\n            }\n            return;\n        }\n        mNb4xx5xx6xxFailures++;\n        if (mNb4xx5xx6xxFailures >= MAX_REGISTRATION_FAILURES) {\n            /**\n             * We reached MAX_REGISTRATION_FAILURES, stop registration retries\n             */\n            handleError(new ImsError(ImsError.REGISTRATION_FAILED, \"too many 4xx/5xx/6xx\"));\n            return;\n        }\n        SipRequest register = SipMessageFactory.createRegister(mDialogPath, mFeatureTags, ctx\n                .getTransaction().getRequest().getExpires().getExpires()\n                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE, mInstanceId,\n                mRcsSettings.isSipKeepAliveEnabled());\n        sendRegister(register);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/registration/RegistrationProcedure.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.registration;\n\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\n\n/**\n * Abstract registration procedure\n * \n * @author jexa7410\n */\npublic abstract class RegistrationProcedure {\n    /**\n     * Initialize procedure\n     */\n    public abstract void init();\n\n    /**\n     * Returns the home domain name\n     * \n     * @return Domain name\n     */\n    public abstract String getHomeDomain();\n\n    /**\n     * Returns the public URI or IMPU for registration\n     * \n     * @return Public URI\n     */\n    public abstract String getPublicUri();\n\n    /**\n     * Write the security header to REGISTER request\n     * \n     * @param request Request\n     * @throws PayloadException\n     */\n    public abstract void writeSecurityHeader(SipRequest request) throws PayloadException;\n\n    /**\n     * Read the security header from REGISTER response\n     * \n     * @param response Response\n     * @throws PayloadException\n     */\n    public abstract void readSecurityHeader(SipResponse response) throws PayloadException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/registration/RegistrationUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.registration;\n\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Registration utility functions\n * \n * @author jexa7410\n */\npublic class RegistrationUtils {\n    /**\n     * Get supported feature tags for registration\n     * \n     * @param rcsSettings RCS settings accessor\n     * @return List of tags\n     */\n    public static String[] getSupportedFeatureTags(RcsSettings rcsSettings) {\n        List<String> tags = new ArrayList<>();\n        List<String> icsiTags = new ArrayList<>();\n        List<String> iariTags = new ArrayList<>();\n\n        // IM support\n        if (rcsSettings.isImSessionSupported()) {\n            tags.add(FeatureTags.FEATURE_OMA_IM);\n        }\n\n        // Video share support\n        if (rcsSettings.isVideoSharingSupported()) {\n            tags.add(FeatureTags.FEATURE_3GPP_VIDEO_SHARE);\n        }\n\n        // IP call support\n        if (rcsSettings.isIPVoiceCallSupported()) {\n            tags.add(FeatureTags.FEATURE_RCSE_IP_VOICE_CALL);\n        }\n        if (rcsSettings.isIPVideoCallSupported()) {\n            tags.add(FeatureTags.FEATURE_RCSE_IP_VIDEO_CALL);\n        }\n        if (rcsSettings.isIPVoiceCallSupported() || rcsSettings.isIPVideoCallSupported()) {\n            icsiTags.add(FeatureTags.FEATURE_3GPP_IP_VOICE_CALL);\n        }\n\n        // Automata support\n        if (rcsSettings.isSipAutomata()) {\n            tags.add(FeatureTags.FEATURE_SIP_AUTOMATA);\n        }\n\n        // Image share support\n        if (rcsSettings.isImageSharingSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_IMAGE_SHARE);\n        }\n\n        // Geoloc push support\n        if (rcsSettings.isGeoLocationPushSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_GEOLOCATION_PUSH);\n        }\n\n        // File transfer HTTP support\n        if (rcsSettings.isFileTransferHttpSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_FT_HTTP);\n        }\n\n        // Extensions\n        if (rcsSettings.isExtensionsAllowed()) {\n            for (String extension : rcsSettings.getSupportedRcsExtensions()) {\n                if (rcsSettings.isExtensionAuthorized(extension)) {\n                    if (extension.startsWith(\"gsma.\")) {\n                        icsiTags.add(FeatureTags.FEATURE_RCSE_ICSI_EXTENSION + \".\" + extension);\n                    } else {\n                        iariTags.add(FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".\" + extension);\n                    }\n                }\n            }\n            icsiTags.add(FeatureTags.FEATURE_3GPP_EXTENSION);\n        }\n\n        // Add IARI prefix\n        if (!iariTags.isEmpty()) {\n            tags.add(FeatureTags.FEATURE_RCSE + \"=\\\"\" + TextUtils.join(\",\", iariTags) + \"\\\"\");\n        }\n\n        // Add ICSI prefix\n        if (!icsiTags.isEmpty()) {\n            tags.add(FeatureTags.FEATURE_3GPP + \"=\\\"\" + TextUtils.join(\",\", icsiTags) + \"\\\"\");\n        }\n\n        return tags.toArray(new String[tags.size()]);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/sip/FeatureTags.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.sip;\n\n/**\n * Feature tags\n * \n * @author jexa7410\n * @author yplo6403\n */\npublic class FeatureTags {\n    /**\n     * OMA IM feature tag\n     */\n    public final static String FEATURE_OMA_IM = \"+g.oma.sip-im\";\n\n    /**\n     * 3GPP video share feature tag\n     */\n    public final static String FEATURE_3GPP_VIDEO_SHARE = \"+g.3gpp.cs-voice\";\n\n    /**\n     * 3GPP image share feature tag\n     */\n    public final static String FEATURE_3GPP_IMAGE_SHARE = \"+g.3gpp.iari-ref=\\\"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-is\\\"\";\n\n    /**\n     * 3GPP image share feature tag for RCS 2.0\n     */\n    public final static String FEATURE_3GPP_IMAGE_SHARE_RCS2 = \"+g.3gpp.app_ref=\\\"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-is\\\"\";\n\n    /**\n     * 3GPP location share feature tag\n     */\n    public final static String FEATURE_3GPP_LOCATION_SHARE = \"+g.3gpp.iari-ref=\\\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\\\"\";\n\n    /**\n     * RCS-e feature tag prefix\n     */\n    public final static String FEATURE_RCSE = \"+g.3gpp.iari-ref\";\n\n    /**\n     * 3GPP feature tag prefix\n     */\n    public final static String FEATURE_3GPP = \"+g.3gpp.icsi-ref\";\n\n    /**\n     * RCS-e image share feature tag\n     */\n    public final static String FEATURE_RCSE_IMAGE_SHARE = \"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-is\";\n\n    /**\n     * RCS-e chat feature tag\n     */\n    public final static String FEATURE_RCSE_CHAT = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\";\n\n    /**\n     * RCS-e file transfer feature tag\n     */\n    public final static String FEATURE_RCSE_FT = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.ft\";\n\n    /**\n     * RCS-e file transfer over HTTP feature tag\n     */\n    public final static String FEATURE_RCSE_FT_HTTP = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\";\n\n    /**\n     * RCS-e presence discovery feature tag\n     */\n    public final static String FEATURE_RCSE_PRESENCE_DISCOVERY = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.dp\";\n\n    /**\n     * RCS-e social presence feature tag\n     */\n    public final static String FEATURE_RCSE_SOCIAL_PRESENCE = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.sp\";\n\n    /**\n     * RCS-e geolocation push feature tag\n     */\n    public final static String FEATURE_RCSE_GEOLOCATION_PUSH = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\";\n\n    /**\n     * RCS-e file transfer thumbnail feature tag\n     */\n    public final static String FEATURE_RCSE_FT_THUMBNAIL = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftthumb\";\n\n    /**\n     * RCS-e file transfer S&F feature tag\n     */\n    public final static String FEATURE_RCSE_FT_SF = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftstandfw\";\n\n    /**\n     * RCS-e group chat S&F feature tag\n     */\n    public final static String FEATURE_RCSE_GC_SF = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fullsfgroupchat\";\n\n    /**\n     * 3GPP IP call feature tag\n     */\n    public final static String FEATURE_3GPP_IP_VOICE_CALL = \"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\";\n\n    /**\n     * RCS-e IP call feature tag\n     */\n    public final static String FEATURE_RCSE_IP_VOICE_CALL = \"+g.gsma.rcs.ipcall\";\n\n    /**\n     * RCS IP video call feature tag\n     */\n    public final static String FEATURE_RCSE_IP_VIDEO_CALL = \"video\";\n\n    /**\n     * RCS-e IARI extension feature tag prefix\n     */\n    public final static String FEATURE_RCSE_IARI_EXTENSION = \"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs\";\n\n    /**\n     * RCS-e ICSI extension feature tag prefix\n     */\n    public final static String FEATURE_RCSE_ICSI_EXTENSION = \"urn%3Aurn-7%3A3gpp-service.ims.icsi\";\n\n    /**\n     * 3GPP RCS extension feature tag\n     */\n    public final static String FEATURE_3GPP_EXTENSION = \"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.rcs.extension\";\n\n    /**\n     * 3GPP RCS service extension\n     */\n    public final static String FEATURE_3GPP_SERVICE_EXTENSION = \"urn:urn-7:3gpp-service.ims.icsi.gsma.rcs.extension\";\n\n    /**\n     * SIP Automata feature tag\n     * \n     * <pre>\n     * @see RFC 3840 \"Indicating User Agent Capabilities in the Session Initiation Protocol (SIP)\"\n     * \n     * The automata tag indicates whether the UA represents an automata (such as a voicemail server, \n     * conference server, IVR, or recording device) or a human.\n     * </pre>\n     */\n    public final static String FEATURE_SIP_AUTOMATA = \"automata\";\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/sip/Multipart.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.sip;\n\nimport java.util.Hashtable;\n\nimport javax2.sip.header.ContentTypeHeader;\n\n/**\n * Multipart content for SIP message\n * \n * @author jexa7410\n */\npublic class Multipart {\n    /**\n     * Boundary delimiter\n     */\n    public final static String BOUNDARY_DELIMITER = \"--\";\n\n    private static final String DOUBLE_CRLF = \"\\r\\n\\r\\n\";\n\n    /**\n     * Parts\n     */\n    private Hashtable<String, String> parts = new Hashtable<>();\n\n    /**\n     * Constructor\n     * \n     * @param content Content parts\n     * @param boundary Boundary delimiter\n     */\n    public Multipart(String content, String boundary) {\n        String[] fragments = content.split(BOUNDARY_DELIMITER + boundary);\n        for (String fragment : fragments) {\n            if (fragment.length() > 0 && !BOUNDARY_DELIMITER.equals(fragment)) {\n                int begin = fragment.indexOf(DOUBLE_CRLF);\n                if (begin != -1) {\n                    begin += DOUBLE_CRLF.length();\n                    /* Extract content type */\n                    String type = fragment.substring(0, begin);\n                    /* Extract MIME type from content type */\n                    int beginType = type.indexOf(ContentTypeHeader.NAME);\n                    int endType = type.indexOf(SipUtils.CRLF, beginType);\n                    String mime;\n                    if (endType == -1) {\n                        mime = type.substring(beginType + ContentTypeHeader.NAME.length() + 1)\n                                .trim();\n                    } else {\n                        mime = type.substring(beginType + ContentTypeHeader.NAME.length() + 1,\n                                endType).trim();\n                    }\n                    /* Extract content part */\n                    String part = fragment.substring(begin);\n                    int endPart = part.lastIndexOf(SipUtils.CRLF);\n                    if (endPart != -1) {\n                        part = part.substring(0, endPart);\n                    }\n                    parts.put(mime.toLowerCase(), part);\n                }\n            }\n        }\n    }\n\n    /**\n     * Is a multipart\n     * \n     * @return Boolean\n     */\n    public boolean isMultipart() {\n        return (parts.size() > 0);\n    }\n\n    /**\n     * Get part from its MIME-type\n     * \n     * @param type MIME-type\n     * @return Part as string\n     */\n    public String getPart(String type) {\n        return parts.get(type.toLowerCase());\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/sip/SipManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.sip;\n\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.KeepAliveManager;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipInterface;\nimport com.gsma.rcs.core.ims.protocol.sip.SipMessage;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.util.ListIterator;\n\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.header.WarningHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/**\n * SIP manager\n * \n * @author JM. Auffret\n */\npublic class SipManager {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * SIP timeout for SIP transaction (in milliseconds)\n     */\n    private static long sTimeout = 30000;\n\n    private final ImsNetworkInterface mNetworkInterface;\n\n    private SipInterface mSipInterface;\n\n    private final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(SipManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS network interface\n     * @param rcsSettings the RCS settings accessor\n     */\n    public SipManager(ImsNetworkInterface parent, RcsSettings rcsSettings) {\n        mNetworkInterface = parent;\n        mRcsSettings = rcsSettings;\n        if (sLogger.isActivated()) {\n            sLogger.info(\"SIP manager started\");\n        }\n    }\n\n    /**\n     * Returns the network interface\n     * \n     * @return Network interface\n     */\n    public ImsNetworkInterface getNetworkInterface() {\n        return mNetworkInterface;\n    }\n\n    /**\n     * Returns the SIP stack\n     * \n     * @return SIP stack\n     */\n    public SipInterface getSipStack() {\n        return mSipInterface;\n    }\n\n    /**\n     * Terminate the manager\n     */\n    public void terminate() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the SIP manager\");\n        }\n        // Close the SIP stack\n        if (mSipInterface != null) {\n            closeStack();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"SIP manager has been terminated\");\n        }\n    }\n\n    /**\n     * Initialize the SIP stack\n     * \n     * @param localAddr Local IP address\n     * @param proxyAddr Outbound proxy address\n     * @param proxyPort Outbound proxy port\n     * @param protocol the protocol\n     * @param tcpFallback TCP fallback according to RFC3261 chapter 18.1.1\n     * @throws PayloadException\n     */\n    public synchronized void initStack(String localAddr, String proxyAddr, int proxyPort,\n            String protocol, boolean tcpFallback) throws PayloadException {\n        closeStack();\n        mSipInterface = new SipInterface(localAddr, proxyAddr, proxyPort, protocol, tcpFallback,\n                mRcsSettings);\n        mSipInterface.initialize();\n    }\n\n    /**\n     * Close the SIP stack\n     */\n    public synchronized void closeStack() {\n        if (mSipInterface == null) {\n            // Already closed\n            return;\n        }\n        // Close the SIP stack\n        mSipInterface.close();\n        mSipInterface = null;\n    }\n\n    /**\n     * Send a SIP message and wait a response\n     * \n     * @param message SIP message\n     * @return Transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessageAndWait(SipMessage message) throws PayloadException,\n            NetworkException {\n        return sendSipMessageAndWait(message, SipManager.sTimeout);\n    }\n\n    /**\n     * Send a SIP message and wait a response\n     * \n     * @param message SIP message\n     * @param timeout SIP timeout in milliseconds\n     * @return Transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessageAndWait(SipMessage message, long timeout)\n            throws PayloadException, NetworkException {\n        return sendSipMessageAndWait(message, timeout, null);\n    }\n\n    /**\n     * Send a SIP message and create a context to wait a response\n     * \n     * @param message SIP message\n     * @return Transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessage(SipMessage message) throws PayloadException,\n            NetworkException {\n        return sendSipMessage(message, null);\n    }\n\n    /**\n     * Send a SIP message and wait a response\n     * \n     * @param message the SIP message\n     * @param timeout in milliseconds\n     * @param callback callback to handle provisional response\n     * @return SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessageAndWait(SipMessage message, long timeout,\n            SipTransactionContext.INotifySipProvisionalResponse callback) throws NetworkException,\n            PayloadException {\n        SipTransactionContext ctx = mSipInterface.sendSipMessageAndWait(message, callback);\n        ctx.waitResponse(timeout);\n\n        if (!(message instanceof SipRequest) || !ctx.isSipResponse()) {\n            return ctx;\n        }\n        String method = ((SipRequest) message).getMethod();\n        SipResponse response = ctx.getSipResponse();\n        if (response == null) {\n            return ctx;\n        }\n        /* Analyze the received response */\n        if (!Request.REGISTER.equals(method)) {\n            /* Check if not registered and warning header */\n            WarningHeader warn = (WarningHeader) response.getHeader(WarningHeader.NAME);\n            if (Response.FORBIDDEN == ctx.getStatusCode() && warn == null) {\n                /* Launch new registration */\n                mNetworkInterface.getRegistrationManager().restart();\n            }\n        }\n        if (!Request.INVITE.equals(method) && !Request.REGISTER.equals(method)) {\n            return ctx;\n        }\n        KeepAliveManager keepAliveManager = mNetworkInterface.getSipManager().getSipStack()\n                .getKeepAliveManager();\n        if (keepAliveManager == null) {\n            return ctx;\n        }\n        /* Message is a response to INVITE or REGISTER: analyze \"keep\" flag of \"Via\" header */\n        ListIterator<ViaHeader> iterator = response.getViaHeaders();\n        if (!iterator.hasNext()) {\n            keepAliveManager.setPeriod(mRcsSettings.getSipKeepAlivePeriod());\n            return ctx;\n        }\n        ViaHeader respViaHeader = iterator.next();\n        String keepStr = respViaHeader.getParameter(\"keep\");\n        if (keepStr == null) {\n            keepAliveManager.setPeriod(mRcsSettings.getSipKeepAlivePeriod());\n            return ctx;\n        }\n        try {\n            long viaKeep = Integer.parseInt(keepStr) * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            if (viaKeep > 0) {\n                keepAliveManager.setPeriod(viaKeep);\n            } else {\n                /* Set Default Value fetched from provisioning settings */\n                keepAliveManager.setPeriod(mRcsSettings.getSipKeepAlivePeriod());\n            }\n        } catch (NumberFormatException e) {\n            /*\n             * If \"keep\" value is invalid or not present, Set Default Value fetched from\n             * provisioning settings\n             */\n            keepAliveManager.setPeriod(mRcsSettings.getSipKeepAlivePeriod());\n        }\n        return ctx;\n    }\n\n    /**\n     * Send a SIP message and create a context to wait a response\n     * \n     * @param message the SIP message\n     * @param callback callback to handle provisional response\n     * @return SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessage(SipMessage message,\n            SipTransactionContext.INotifySipProvisionalResponse callback) throws NetworkException,\n            PayloadException {\n        return mSipInterface.sendSipMessageAndWait(message, callback);\n    }\n\n    /**\n     * Wait a response\n     * \n     * @param ctx SIP transaction context\n     */\n    public void waitResponse(SipTransactionContext ctx) {\n        ctx.waitResponse(SipManager.sTimeout);\n    }\n\n    /**\n     * Wait a response\n     * \n     * @param ctx SIP transaction context\n     * @param timeout in milliseconds\n     */\n    public void waitResponse(SipTransactionContext ctx, long timeout) {\n        ctx.waitResponse(timeout);\n\n        SipMessage message = ctx.getMessageReceived();\n        if (!(message instanceof SipRequest) || !ctx.isSipResponse()) {\n            return;\n        }\n        String method = ((SipRequest) message).getMethod();\n        SipResponse response = ctx.getSipResponse();\n        if (response == null) {\n            return;\n        }\n        /* Analyze the received response */\n        if (!Request.REGISTER.equals(method)) {\n            /* Check if not registered and warning header */\n            WarningHeader warn = (WarningHeader) response.getHeader(WarningHeader.NAME);\n            if (Response.FORBIDDEN == ctx.getStatusCode() && warn == null) {\n                /* Launch new registration */\n                mNetworkInterface.getRegistrationManager().restart();\n            }\n        }\n        if (!Request.REGISTER.equals(method)) {\n            return;\n        }\n        KeepAliveManager keepAliveManager = mSipInterface.getKeepAliveManager();\n        if (keepAliveManager == null) {\n            return;\n        }\n        /* Message is a response to REGISTER: analyze \"keep\" flag of \"Via\" header */\n        ListIterator<ViaHeader> iterator = response.getViaHeaders();\n        if (!iterator.hasNext()) {\n            return;\n        }\n        ViaHeader respViaHeader = iterator.next();\n        String keepStr = respViaHeader.getParameter(\"keep\");\n        if (keepStr == null) {\n            return;\n        }\n        try {\n            long viaKeep = Integer.parseInt(keepStr) * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            if (viaKeep > 0) {\n                keepAliveManager.setPeriod(viaKeep);\n\n            } else if (viaKeep == 0) {\n                /*\n                 * If \"keep\" value is zero, set keep alive period to own discretion (i.e. default\n                 * value from provisioning)\n                 */\n                keepAliveManager.setPeriod(mRcsSettings.getSipKeepAlivePeriod());\n            }\n        } catch (NumberFormatException e) {\n            /*\n             * If \"keep\" value is invalid , set Default Value fetched from provisioning settings\n             */\n            keepAliveManager.setPeriod(mRcsSettings.getSipKeepAlivePeriod());\n        }\n    }\n\n    /**\n     * Send a SIP response\n     * \n     * @param response SIP response\n     * @throws NetworkException\n     */\n    public void sendSipResponse(SipResponse response) throws NetworkException {\n        mSipInterface.sendSipResponse(response);\n    }\n\n    /**\n     * Send a SIP ACK\n     * \n     * @param dialog Dialog path\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendSipAck(SipDialogPath dialog) throws PayloadException, NetworkException {\n        mSipInterface.sendSipAck(dialog);\n    }\n\n    /**\n     * Send a SIP BYE\n     * \n     * @param dialog Dialog path\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendSipBye(SipDialogPath dialog) throws PayloadException, NetworkException {\n        mSipInterface.sendSipBye(dialog);\n    }\n\n    /**\n     * Send a SIP CANCEL\n     * \n     * @param dialog Dialog path\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendSipCancel(SipDialogPath dialog) throws PayloadException, NetworkException {\n        mSipInterface.sendSipCancel(dialog);\n    }\n\n    /**\n     * Send a subsequent SIP request\n     * \n     * @param dialog Dialog path\n     * @param request Request\n     * @return SipTransactionContext\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public SipTransactionContext sendSubsequentRequest(SipDialogPath dialog, SipRequest request)\n            throws NetworkException, PayloadException {\n        return sendSubsequentRequest(dialog, request, SipManager.sTimeout);\n    }\n\n    /**\n     * Send a subsequent SIP request\n     * \n     * @param dialog Dialog path\n     * @param request Request\n     * @param timeout SIP timeout in milliseconds\n     * @return SipTransactionContext\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private SipTransactionContext sendSubsequentRequest(SipDialogPath dialog, SipRequest request,\n            long timeout) throws NetworkException, PayloadException {\n        SipTransactionContext ctx = mSipInterface.sendSubsequentRequest(dialog, request);\n        ctx.waitResponse(timeout);\n        if (ctx.isSipResponse()) {\n            int code = ctx.getStatusCode();\n            /* Check if not registered and warning header */\n            WarningHeader warn = (WarningHeader) ctx.getSipResponse().getHeader(WarningHeader.NAME);\n            if (Response.FORBIDDEN == code && warn == null) {\n                mNetworkInterface.getRegistrationManager().restart();\n                throw new PayloadException(\"Stack not properly registered with status code : \"\n                        + code);\n            }\n        }\n        return ctx;\n    }\n\n    /**\n     * Gets the timeout for SIP transaction (in milliseconds)\n     * \n     * @return timeout for SIP transaction (in milliseconds)\n     */\n    public static long getTimeout() {\n        return sTimeout;\n    }\n\n    /**\n     * Sets the timeout for SIP transaction (in milliseconds)\n     * \n     * @param timeout the timeout\n     */\n    public static void setTimeout(long timeout) {\n        sTimeout = timeout;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/sip/SipMessageFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.sip;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.javax2.sip.Utils;\nimport gov2.nist.javax2.sip.header.Subject;\n\nimport java.text.ParseException;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.Vector;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.SipException;\nimport javax2.sip.address.Address;\nimport javax2.sip.address.URI;\nimport javax2.sip.header.AcceptHeader;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.ReasonHeader;\nimport javax2.sip.header.ReferToHeader;\nimport javax2.sip.header.RequireHeader;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.SIPIfMatchHeader;\nimport javax2.sip.header.SupportedHeader;\nimport javax2.sip.header.ToHeader;\nimport javax2.sip.header.UserAgentHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.header.WarningHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/**\n * SIP message factory\n * \n * @author Jean-Marc AUFFRET\n */\npublic class SipMessageFactory {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Create a SIP REGISTER request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param expirePeriod Expiration period in milliseconds\n     * @param instanceId UA SIP instance ID\n     * @param announceKeepAlive propagate support of keep alive\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createRegister(SipDialogPath dialog, String[] featureTags,\n            long expirePeriod, String instanceId, boolean announceKeepAlive)\n            throws PayloadException {\n        try {\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.REGISTER);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    IdGenerator.getIdentifier());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress, null);\n\n            // Insert \"keep\" flag to Via header (RFC6223 \"Indication of Support for Keep-Alive\")\n            List<ViaHeader> viaHeaders = dialog.getSipStack().getViaHeaders();\n            if (viaHeaders != null && !viaHeaders.isEmpty() && announceKeepAlive) {\n                ViaHeader viaHeader = viaHeaders.get(0);\n                viaHeader.setParameter(new NameValue(\"keep\", null, true));\n            }\n\n            // Create the request\n            Request register = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.REGISTER,\n                    callIdHeader, cseqHeader, fromHeader, toHeader, viaHeaders,\n                    SipUtils.buildMaxForwardsHeader());\n\n            // Set Contact header\n            ContactHeader contact = dialog.getSipStack().getLocalContact();\n            if (instanceId != null) {\n                contact.setParameter(SipUtils.SIP_INSTANCE_PARAM, instanceId);\n            }\n            register.addHeader(contact);\n\n            // Set Supported header\n            String supported;\n            if (instanceId != null) {\n                supported = \"path, gruu\";\n            } else {\n                supported = \"path\";\n            }\n            SupportedHeader supportedHeader = SipUtils.HEADER_FACTORY\n                    .createSupportedHeader(supported);\n            register.addHeader(supportedHeader);\n\n            if (featureTags.length != 0) {\n                // Set feature tags\n                SipUtils.setContactFeatureTags(register, featureTags);\n            }\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(register);\n\n            // Set the Expires header\n            ExpiresHeader expHeader = SipUtils.HEADER_FACTORY\n                    .createExpiresHeader((int) (expirePeriod / SECONDS_TO_MILLISECONDS_CONVERSION_RATE));\n            register.addHeader(expHeader);\n\n            // Set User-Agent header\n            register.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) register.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(register);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message for instanceId : \" + instanceId, e);\n        }\n    }\n\n    /**\n     * Create a SIP SUBSCRIBE request\n     * \n     * @param dialog SIP dialog path\n     * @param expirePeriod Expiration period in milliseconds\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createSubscribe(SipDialogPath dialog, long expirePeriod)\n            throws PayloadException {\n        try {\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.SUBSCRIBE);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    dialog.getLocalTag());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress,\n                    dialog.getRemoteTag());\n\n            // Create the request\n            Request subscribe = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.SUBSCRIBE,\n                    callIdHeader, cseqHeader, fromHeader, toHeader, dialog.getSipStack()\n                            .getViaHeaders(), SipUtils.buildMaxForwardsHeader());\n\n            // Set the Route header\n            Vector<String> route = dialog.getRoute();\n            for (int i = 0; i < route.size(); i++) {\n                Header routeHeader = SipUtils.HEADER_FACTORY.createHeader(RouteHeader.NAME,\n                        route.elementAt(i));\n                subscribe.addHeader(routeHeader);\n            }\n\n            // Set the Expires header\n            ExpiresHeader expHeader = SipUtils.HEADER_FACTORY\n                    .createExpiresHeader((int) (expirePeriod / SECONDS_TO_MILLISECONDS_CONVERSION_RATE));\n            subscribe.addHeader(expHeader);\n\n            // Set User-Agent header\n            subscribe.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set Contact header\n            subscribe.addHeader(dialog.getSipStack().getContact());\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(subscribe);\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) subscribe.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(subscribe);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP MESSAGE request with a feature tag\n     * \n     * @param dialog SIP dialog path\n     * @param contentType Content type\n     * @param content Content\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createMessage(SipDialogPath dialog, String contentType, String content)\n            throws PayloadException {\n        return createMessage(dialog, null, contentType, content.getBytes(UTF8));\n    }\n\n    /**\n     * Create a SIP MESSAGE request with a feature tag\n     * \n     * @param dialog SIP dialog path\n     * @param featureTag Feature tag\n     * @param contentType Content type\n     * @param content Content\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createMessage(SipDialogPath dialog, String featureTag,\n            String contentType, byte[] content) throws PayloadException {\n        try {\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.MESSAGE);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    dialog.getLocalTag());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress,\n                    dialog.getRemoteTag());\n\n            // Create the request\n            Request message = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.MESSAGE,\n                    callIdHeader, cseqHeader, fromHeader, toHeader, dialog.getSipStack()\n                            .getViaHeaders(), SipUtils.buildMaxForwardsHeader());\n\n            // Set the Route header\n            Vector<String> route = dialog.getRoute();\n            for (int i = 0; i < route.size(); i++) {\n                Header routeHeader = SipUtils.HEADER_FACTORY.createHeader(RouteHeader.NAME,\n                        route.elementAt(i));\n                message.addHeader(routeHeader);\n            }\n\n            setPPreferedIdentityHeader(message);\n\n            // Set Contact header\n            message.addHeader(dialog.getSipStack().getContact());\n\n            // Set User-Agent header\n            message.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set feature tags\n            if (featureTag != null) {\n                SipUtils.setFeatureTags(message, new String[] {\n                    featureTag\n                });\n            }\n\n            // Set the message content\n            String[] type = contentType.split(\"/\");\n            message.setContent(content,\n                    SipUtils.HEADER_FACTORY.createContentTypeHeader(type[0], type[1]));\n\n            // Set the message content length\n            message.setContentLength(SipUtils.HEADER_FACTORY\n                    .createContentLengthHeader(content.length));\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) message.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            String remoteInstanceId = dialog.getRemoteSipInstance();\n            if (remoteInstanceId != null) {\n                // Add remote SIP instance ID\n                SipUtils.setRemoteInstanceID(message, remoteInstanceId);\n            }\n\n            return new SipRequest(message);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message for featureTag : \" + featureTag\n                    + \" with contentType : \" + contentType, e);\n        }\n    }\n\n    /**\n     * Create a SIP PUBLISH request\n     * \n     * @param dialog SIP dialog path\n     * @param expirePeriod Expiration period in milliseconds\n     * @param entityTag Entity tag\n     * @param sdp SDP part\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createPublish(SipDialogPath dialog, long expirePeriod,\n            String entityTag, String sdp) throws PayloadException {\n        try {\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.PUBLISH);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    dialog.getLocalTag());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress,\n                    dialog.getRemoteTag());\n\n            // Create the request\n            Request publish = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.PUBLISH,\n                    callIdHeader, cseqHeader, fromHeader, toHeader, dialog.getSipStack()\n                            .getViaHeaders(), SipUtils.buildMaxForwardsHeader());\n\n            // Set the Route header\n            Vector<String> route = dialog.getRoute();\n            for (int i = 0; i < route.size(); i++) {\n                Header routeHeader = SipUtils.HEADER_FACTORY.createHeader(RouteHeader.NAME,\n                        route.elementAt(i));\n                publish.addHeader(routeHeader);\n            }\n\n            // Set the Expires header\n            ExpiresHeader expHeader = SipUtils.HEADER_FACTORY\n                    .createExpiresHeader((int) (expirePeriod / SECONDS_TO_MILLISECONDS_CONVERSION_RATE));\n            publish.addHeader(expHeader);\n\n            // Set the SIP-If-Match header\n            if (entityTag != null) {\n                Header sipIfMatchHeader = SipUtils.HEADER_FACTORY.createHeader(\n                        SIPIfMatchHeader.NAME, entityTag);\n                publish.addHeader(sipIfMatchHeader);\n            }\n\n            // Set User-Agent header\n            publish.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set the Event header\n            publish.addHeader(SipUtils.HEADER_FACTORY.createHeader(EventHeader.NAME, \"presence\"));\n\n            // Set the message content\n            if (sdp != null) {\n                publish.setContent(sdp,\n                        SipUtils.HEADER_FACTORY.createContentTypeHeader(\"application\", \"pidf+xml\"));\n            }\n\n            // Set the message content length\n            int length = sdp == null ? 0 : sdp.getBytes(UTF8).length;\n            publish.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(length));\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) publish.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(publish);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message\", e);\n        }\n    }\n\n    /**\n     * Create a SIP INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param sdp SDP part\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createInvite(SipDialogPath dialog, String[] featureTags, String sdp)\n            throws PayloadException {\n        return createInvite(dialog, featureTags, featureTags, sdp);\n    }\n\n    /**\n     * Create a SIP INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param acceptTags Feature tags\n     * @param sdp SDP part\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createInvite(SipDialogPath dialog, String[] featureTags,\n            String[] acceptTags, String sdp) throws PayloadException {\n        try {\n            // Create the content type\n            ContentTypeHeader contentType = SipUtils.HEADER_FACTORY.createContentTypeHeader(\n                    \"application\", \"sdp\");\n\n            // Create the request\n            return createInvite(dialog, featureTags, acceptTags, sdp, contentType);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Can't create SIP message with SDP : \" + sdp, e);\n        }\n    }\n\n    /**\n     * Create a SIP INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param multipart Multipart\n     * @param boundary Boundary tag\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createMultipartInvite(SipDialogPath dialog, String[] featureTags,\n            String multipart, String boundary) throws PayloadException {\n        return createMultipartInvite(dialog, featureTags, featureTags, multipart, boundary);\n    }\n\n    /**\n     * Create a SIP INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param acceptTags Feature tags\n     * @param multipart Multipart\n     * @param boundary Boundary tag\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createMultipartInvite(SipDialogPath dialog, String[] featureTags,\n            String[] acceptTags, String multipart, String boundary) throws PayloadException {\n        try {\n            // Create the content type\n            ContentTypeHeader contentType = SipUtils.HEADER_FACTORY.createContentTypeHeader(\n                    \"multipart\", \"mixed\");\n            contentType.setParameter(\"boundary\", boundary);\n\n            // Create the request\n            return createInvite(dialog, featureTags, acceptTags, multipart, contentType);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Can't create SIP message with multipart : \" + multipart, e);\n        }\n    }\n\n    /**\n     * Create a SIP INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param acceptTags Feature tags\n     * @param content Content\n     * @param contentType Content type\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createInvite(SipDialogPath dialog, String[] featureTags,\n            String[] acceptTags, String content, ContentTypeHeader contentType)\n            throws PayloadException {\n        try {\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.INVITE);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    dialog.getLocalTag());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress, null);\n\n            // Insert \"keep\" flag to Via header (RFC6223 \"Indication of Support for Keep-Alive\")\n            List<ViaHeader> viaHeaders = dialog.getSipStack().getViaHeaders();\n            if (viaHeaders != null && !viaHeaders.isEmpty()) {\n                ViaHeader viaHeader = viaHeaders.get(0);\n                viaHeader.setParameter(new NameValue(\"keep\", null, true));\n            }\n\n            // Create the request\n            Request invite = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.INVITE,\n                    callIdHeader, cseqHeader, fromHeader, toHeader, viaHeaders,\n                    SipUtils.buildMaxForwardsHeader());\n\n            // Set Contact header\n            invite.addHeader(dialog.getSipStack().getContact());\n\n            // Set feature tags\n            SipUtils.setFeatureTags(invite, featureTags, acceptTags);\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(invite);\n\n            // Set the Route header\n            Vector<String> route = dialog.getRoute();\n            for (int i = 0; i < route.size(); i++) {\n                Header routeHeader = SipUtils.HEADER_FACTORY.createHeader(RouteHeader.NAME,\n                        route.elementAt(i));\n                invite.addHeader(routeHeader);\n            }\n\n            setPPreferedIdentityHeader(invite);\n\n            // Set User-Agent header\n            invite.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Add session timer management\n            if (dialog.getSessionExpireTime() >= SessionTimerManager.MIN_EXPIRE_PERIOD) {\n                // Set the Supported header\n                Header supportedHeader = SipUtils.HEADER_FACTORY.createHeader(SupportedHeader.NAME,\n                        \"timer\");\n                invite.addHeader(supportedHeader);\n\n                // Set Session-Timer headers\n                Header sessionExpiresHeader = SipUtils.HEADER_FACTORY.createHeader(\n                        SipUtils.HEADER_SESSION_EXPIRES, \"\" + dialog.getSessionExpireTime());\n                invite.addHeader(sessionExpiresHeader);\n            }\n\n            // Set the message content\n            invite.setContent(content, contentType);\n\n            // Set the content length\n            invite.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(content\n                    .getBytes(UTF8).length));\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) invite.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(invite);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message with content : \" + content, e);\n        }\n    }\n\n    /**\n     * Create a 200 OK response for INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param sdp SDP part\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse create200OkInviteResponse(SipDialogPath dialog, String[] featureTags,\n            String sdp) throws PayloadException {\n        return create200OkInviteResponse(dialog, featureTags, featureTags, sdp);\n    }\n\n    /**\n     * Create a 200 OK response for INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @param acceptContactTags Feature tags\n     * @param sdp SDP part\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse create200OkInviteResponse(SipDialogPath dialog, String[] featureTags,\n            String[] acceptContactTags, String sdp) throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY.createResponse(200, dialog.getInvite()\n                    .getStackMessage());\n\n            // Set the local tag\n            ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);\n            to.setTag(dialog.getLocalTag());\n\n            // Set Contact header\n            response.addHeader(dialog.getSipStack().getContact());\n\n            // Set feature tags\n            SipUtils.setFeatureTags(response, featureTags, acceptContactTags);\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(response);\n\n            // Set the Server header\n            response.addHeader(SipUtils.buildServerHeader());\n\n            // Add session timer management\n            if (dialog.getSessionExpireTime() >= SessionTimerManager.MIN_EXPIRE_PERIOD) {\n                // Set the Require header\n                Header requireHeader = SipUtils.HEADER_FACTORY.createHeader(RequireHeader.NAME,\n                        \"timer\");\n                response.addHeader(requireHeader);\n\n                // Set Session-Timer header\n                Header sessionExpiresHeader = SipUtils.HEADER_FACTORY.createHeader(\n                        SipUtils.HEADER_SESSION_EXPIRES,\n                        String.valueOf(dialog.getSessionExpireTime()\n                                / SECONDS_TO_MILLISECONDS_CONVERSION_RATE)\n                                + \";refresher=\" + dialog.getInvite().getSessionTimerRefresher());\n                response.addHeader(sessionExpiresHeader);\n            }\n\n            // Set the message content\n            response.setContent(sdp,\n                    SipUtils.HEADER_FACTORY.createContentTypeHeader(\"application\", \"sdp\"));\n\n            // Set the message content length\n            response.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(sdp\n                    .getBytes(UTF8).length));\n\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(dialog.getInvite().getStackTransaction());\n            return resp;\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP response with SDP : \" + sdp, e);\n        }\n    }\n\n    /**\n     * Create a SIP ACK request\n     * \n     * @param dialog SIP dialog path\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createAck(SipDialogPath dialog) throws PayloadException {\n        try {\n            Request ack;\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.ACK);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    dialog.getLocalTag());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress,\n                    dialog.getRemoteTag());\n\n            // Set the Via branch\n            List<ViaHeader> vias = dialog.getSipStack().getViaHeaders();\n            vias.get(0).setBranch(Utils.getInstance().generateBranchId());\n\n            // Create the ACK request\n            ack = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.ACK, callIdHeader,\n                    cseqHeader, fromHeader, toHeader, vias, SipUtils.buildMaxForwardsHeader());\n\n            // Set the Route header\n            Vector<String> route = dialog.getRoute();\n            for (int i = 0; i < route.size(); i++) {\n                Header routeHeader = SipUtils.HEADER_FACTORY.createHeader(RouteHeader.NAME,\n                        route.elementAt(i));\n                ack.addHeader(routeHeader);\n            }\n\n            // Set Contact header\n            ack.addHeader(dialog.getSipStack().getContact());\n\n            // Set User-Agent header\n            ack.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(ack);\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) ack.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(ack);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP response\n     * \n     * @param request SIP request\n     * @param code Response code\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse createResponse(SipRequest request, int code) throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY\n                    .createResponse(code, request.getStackMessage());\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(request.getStackTransaction());\n            return resp;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Can't create SIP response\", e);\n        }\n    }\n\n    /**\n     * Works just like SipResponse createResponse(SipRequest request, String localTag, int code,\n     * String warning) except the warning is always null\n     * \n     * @see #createResponse(SipRequest, String, int)\n     */\n    public static SipResponse createResponse(SipRequest request, String localTag, int code)\n            throws PayloadException {\n        return createResponse(request, localTag, code, null);\n    }\n\n    /**\n     * Create a SIP response with a specific local tag and warning\n     * \n     * @param request the SIP request\n     * @param localTag the Local tag\n     * @param warning the warning message\n     * @return the SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse createResponse(SipRequest request, String localTag, int code,\n            String warning) throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY\n                    .createResponse(code, request.getStackMessage());\n\n            // Set the local tag\n            if (localTag != null) {\n                ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);\n                to.setTag(localTag);\n            }\n            if (warning != null) {\n                WarningHeader warningHeader = SipUtils.HEADER_FACTORY.createWarningHeader(\"SIP\",\n                        403, warning);\n                response.addHeader(warningHeader);\n            }\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(request.getStackTransaction());\n            return resp;\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message for localTag : \" + localTag, e);\n        }\n    }\n\n    /**\n     * Create a SIP BYE request\n     * \n     * @param dialog SIP dialog path\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createBye(SipDialogPath dialog) throws PayloadException {\n        try {\n            // Create the request\n            Request bye = dialog.getStackDialog().createRequest(Request.BYE);\n\n            // Set termination reason\n            int reasonCode = dialog.getSessionTerminationReasonCode();\n            if (reasonCode != -1) {\n                ReasonHeader reasonHeader = SipUtils.HEADER_FACTORY.createReasonHeader(\"SIP\",\n                        reasonCode, dialog.getSessionTerminationReasonPhrase());\n                bye.addHeader(reasonHeader);\n            }\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) bye.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(bye);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP CANCEL request\n     * \n     * @param dialog SIP dialog path\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createCancel(SipDialogPath dialog) throws PayloadException {\n        try {\n            // Create the request\n            ClientTransaction transaction = (ClientTransaction) dialog.getInvite()\n                    .getStackTransaction();\n            Request cancel = transaction.createCancel();\n\n            // Set termination reason\n            int reasonCode = dialog.getSessionTerminationReasonCode();\n            if (reasonCode != -1) {\n                ReasonHeader reasonHeader = SipUtils.HEADER_FACTORY.createReasonHeader(\"SIP\",\n                        reasonCode, dialog.getSessionTerminationReasonPhrase());\n                cancel.addHeader(reasonHeader);\n            }\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) cancel.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n            return new SipRequest(cancel);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP OPTIONS request\n     * \n     * @param dialog SIP dialog path\n     * @param featureTags Feature tags\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createOptions(SipDialogPath dialog, String[] featureTags)\n            throws PayloadException {\n        try {\n            // Set request line header\n            URI requestURI = SipUtils.ADDR_FACTORY.createURI(dialog.getTarget());\n\n            // Set Call-Id header\n            CallIdHeader callIdHeader = SipUtils.HEADER_FACTORY.createCallIdHeader(dialog\n                    .getCallId());\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.OPTIONS);\n\n            // Set the From header\n            Address fromAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getLocalParty());\n            FromHeader fromHeader = SipUtils.HEADER_FACTORY.createFromHeader(fromAddress,\n                    dialog.getLocalTag());\n\n            // Set the To header\n            Address toAddress = SipUtils.ADDR_FACTORY.createAddress(dialog.getRemoteParty());\n            ToHeader toHeader = SipUtils.HEADER_FACTORY.createToHeader(toAddress, null);\n\n            // Create the request\n            Request options = SipUtils.MSG_FACTORY.createRequest(requestURI, Request.OPTIONS,\n                    callIdHeader, cseqHeader, fromHeader, toHeader, dialog.getSipStack()\n                            .getViaHeaders(), SipUtils.buildMaxForwardsHeader());\n\n            // Set Contact header\n            options.addHeader(dialog.getSipStack().getContact());\n\n            // Set Accept header\n            Header acceptHeader = SipUtils.HEADER_FACTORY.createHeader(AcceptHeader.NAME,\n                    \"application/sdp\");\n            options.addHeader(acceptHeader);\n\n            // Set feature tags\n            SipUtils.setFeatureTags(options, featureTags);\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(options);\n\n            // Set the Route header\n            Vector<String> route = dialog.getRoute();\n            for (int i = 0; i < route.size(); i++) {\n                Header routeHeader = SipUtils.HEADER_FACTORY.createHeader(RouteHeader.NAME,\n                        route.elementAt(i));\n                options.addHeader(routeHeader);\n            }\n\n            setPPreferedIdentityHeader(options);\n\n            // Set User-Agent header\n            options.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) options.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n            return new SipRequest(options);\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a 200 OK response for OPTIONS request\n     * \n     * @param options SIP options\n     * @param contact Contact header\n     * @param featureTags Feature tags\n     * @param sdp SDP part\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse create200OkOptionsResponse(SipRequest options, ContactHeader contact,\n            String[] featureTags, String sdp) throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY.createResponse(200, options.getStackMessage());\n\n            // Set the local tag\n            ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);\n            to.setTag(IdGenerator.getIdentifier());\n\n            // Set Contact header\n            response.addHeader(contact);\n\n            // Set feature tags\n            SipUtils.setFeatureTags(response, featureTags);\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(response);\n\n            // Set the Server header\n            response.addHeader(SipUtils.buildServerHeader());\n\n            // Set the content part if available\n            if (sdp != null) {\n                // Set the content type header\n                response.setContent(sdp,\n                        SipUtils.HEADER_FACTORY.createContentTypeHeader(\"application\", \"sdp\"));\n\n                // Set the content length header\n                response.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(sdp\n                        .getBytes(UTF8).length));\n            }\n\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(options.getStackTransaction());\n            return resp;\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create SIP response for SDP : \" + sdp, e);\n        }\n    }\n\n    /**\n     * Create a SIP REFER request\n     * \n     * @param dialog SIP dialog path\n     * @param toContact Refer to contact\n     * @param subject Subject\n     * @param contributionId Contribution ID\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createRefer(SipDialogPath dialog, Uri toContact, String subject,\n            String contributionId) throws PayloadException {\n        try {\n            // Create the request\n            Request refer = dialog.getStackDialog().createRequest(Request.REFER);\n\n            // Set feature tags\n            String[] tags = {\n                FeatureTags.FEATURE_OMA_IM\n            };\n            SipUtils.setFeatureTags(refer, tags);\n\n            // Set Refer-To header\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(ReferToHeader.NAME,\n                    toContact.toString()));\n\n            // Set Refer-Sub header\n            refer.addHeader(SipUtils.HEADER_FACTORY\n                    .createHeader(SipUtils.HEADER_REFER_SUB, \"false\"));\n\n            setPPreferedIdentityHeader(refer);\n\n            // Set Subject header\n            if (subject != null) {\n                Header sub = SipUtils.HEADER_FACTORY.createHeader(Subject.NAME, subject);\n                refer.addHeader(sub);\n            }\n\n            // Set Contribution-ID header\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(ChatUtils.HEADER_CONTRIBUTION_ID,\n                    contributionId));\n\n            // Set User-Agent header\n            refer.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) refer.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            String remoteInstanceId = dialog.getRemoteSipInstance();\n            if (remoteInstanceId != null) {\n                // Add remote SIP instance ID\n                SipUtils.setRemoteInstanceID(refer, remoteInstanceId);\n            }\n\n            return new SipRequest(refer);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP REFER for contact '\" + toContact\n                    + \"' with contributionId : \" + contributionId, e);\n        }\n    }\n\n    /**\n     * Create a SIP REFER request\n     * \n     * @param dialog SIP dialog path\n     * @param participants Set of participants\n     * @param subject Subject\n     * @param contributionId Contribution ID\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createRefer(SipDialogPath dialog, Set<ContactId> participants,\n            String subject, String contributionId) throws PayloadException {\n        try {\n            // Create the request\n            Request refer = dialog.getStackDialog().createRequest(Request.REFER);\n\n            // Generate a list URI\n            String listID = \"Id_\" + System.currentTimeMillis();\n\n            // Set feature tags\n            String[] tags = {\n                FeatureTags.FEATURE_OMA_IM\n            };\n            SipUtils.setFeatureTags(refer, tags);\n\n            // Set Require header\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(RequireHeader.NAME,\n                    \"multiple-refer\"));\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(RequireHeader.NAME, \"norefersub\"));\n\n            // Set Refer-To header\n            String homeDomain = ImsModule.getImsUserProfile().getHomeDomain();\n            String referToValue = \"<cid:\" + listID + \"@\" + homeDomain + \">\";\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(ReferToHeader.NAME, referToValue));\n\n            // Set Refer-Sub header\n            refer.addHeader(SipUtils.HEADER_FACTORY\n                    .createHeader(SipUtils.HEADER_REFER_SUB, \"false\"));\n\n            setPPreferedIdentityHeader(refer);\n\n            // Set Subject header\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(Subject.NAME, subject));\n\n            // Set Contribution-ID header\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(ChatUtils.HEADER_CONTRIBUTION_ID,\n                    contributionId));\n\n            // Set User-Agent header\n            refer.addHeader(SipUtils.buildUserAgentHeader());\n\n            // Set the Content-ID header\n            String contentIdHeadervalue = \"<\" + listID + \"@\" + homeDomain + \">\";\n            refer.addHeader(SipUtils.HEADER_FACTORY.createHeader(SipUtils.HEADER_CONTENT_ID,\n                    contentIdHeadervalue));\n\n            // Generate the resource list for given participants\n            String resourceList = ChatUtils.generateChatResourceList(participants);\n\n            // Set the message content\n            refer.setContent(resourceList, SipUtils.HEADER_FACTORY.createContentTypeHeader(\n                    \"application\", \"resource-lists+xml\"));\n\n            // Set the message content length\n            refer.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(resourceList\n                    .getBytes(UTF8).length));\n\n            // Set the Content-Disposition header\n            Header contentDispoHeader = SipUtils.HEADER_FACTORY.createHeader(\n                    ContentDispositionHeader.NAME, \"recipient-list\");\n            refer.addHeader(contentDispoHeader);\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) refer.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            String remoteInstanceId = dialog.getRemoteSipInstance();\n            if (remoteInstanceId != null) {\n                // Add remote SIP instance ID\n                SipUtils.setRemoteInstanceID(refer, remoteInstanceId);\n            }\n\n            return new SipRequest(refer);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP REFER for contributionId : \"\n                    + contributionId, e);\n        }\n    }\n\n    /**\n     * Create a SIP RE-INVITE request\n     * \n     * @param dialog SIP dialog path\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createReInvite(SipDialogPath dialog) throws PayloadException {\n        try {\n            // Build the request\n            Request reInvite = dialog.getStackDialog().createRequest(Request.INVITE);\n            SipRequest firstInvite = dialog.getInvite();\n\n            // Set feature tags\n            reInvite.removeHeader(ContactHeader.NAME);\n            reInvite.addHeader(firstInvite.getHeader(ContactHeader.NAME));\n            reInvite.removeHeader(SipUtils.HEADER_ACCEPT_CONTACT);\n            reInvite.addHeader(firstInvite.getHeader(SipUtils.HEADER_ACCEPT_CONTACT));\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(reInvite);\n\n            // Set the Route header\n            reInvite.addHeader(firstInvite.getHeader(RouteHeader.NAME));\n\n            // Set the P-Preferred-Identity header\n            reInvite.addHeader(firstInvite.getHeader(SipUtils.HEADER_P_PREFERRED_IDENTITY));\n\n            // Set User-Agent header\n            reInvite.addHeader(firstInvite.getHeader(UserAgentHeader.NAME));\n\n            // Add session timer management\n            if (dialog.getSessionExpireTime() >= SessionTimerManager.MIN_EXPIRE_PERIOD) {\n                // Set the Supported header\n                Header supportedHeader = SipUtils.HEADER_FACTORY.createHeader(SupportedHeader.NAME,\n                        \"timer\");\n                reInvite.addHeader(supportedHeader);\n\n                // Set Session-Timer headers\n                Header sessionExpiresHeader = SipUtils.HEADER_FACTORY.createHeader(\n                        SipUtils.HEADER_SESSION_EXPIRES, \"\" + dialog.getSessionExpireTime());\n                reInvite.addHeader(sessionExpiresHeader);\n            }\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) reInvite.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            String remoteInstanceId = dialog.getRemoteSipInstance();\n            if (remoteInstanceId != null) {\n                // Add remote SIP instance ID\n                SipUtils.setRemoteInstanceID(firstInvite.getStackMessage(), remoteInstanceId);\n            }\n            return new SipRequest(reInvite);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP RE-INVITE request with content using initial Invite request\n     * \n     * @param dialog Dialog path SIP request\n     * @param featureTags featureTags to set in request\n     * @param content sdp content\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createReInvite(SipDialogPath dialog, String[] featureTags,\n            String content) throws PayloadException {\n        try {\n            // Build the request\n            Request reInvite = dialog.getStackDialog().createRequest(Request.INVITE);\n            SipRequest firstInvite = dialog.getInvite();\n\n            // Set the CSeq header\n            CSeqHeader cseqHeader = SipUtils.HEADER_FACTORY.createCSeqHeader(dialog.getCseq(),\n                    Request.INVITE);\n            reInvite.removeHeader(CSeqHeader.NAME);\n            reInvite.addHeader(cseqHeader);\n\n            // Set Contact header\n            reInvite.removeHeader(ContactHeader.NAME);\n            reInvite.removeHeader(SipUtils.HEADER_ACCEPT_CONTACT);\n            reInvite.addHeader(dialog.getSipStack().getContact());\n\n            // Set feature tags\n            SipUtils.setFeatureTags(reInvite, featureTags);\n\n            String remoteInstanceId = dialog.getRemoteSipInstance();\n            if (remoteInstanceId != null) {\n                // Add remote SIP instance ID\n                SipUtils.setRemoteInstanceID(firstInvite.getStackMessage(), remoteInstanceId);\n            }\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(reInvite);\n\n            // Set the Route header\n            if (reInvite.getHeader(RouteHeader.NAME) == null\n                    && firstInvite.getHeader(RouteHeader.NAME) != null) {\n                reInvite.addHeader(firstInvite.getHeader(RouteHeader.NAME));\n            }\n\n            // Set the P-Preferred-Identity header\n            if (firstInvite.getHeader(SipUtils.HEADER_P_PREFERRED_IDENTITY) != null) {\n                reInvite.addHeader(firstInvite.getHeader(SipUtils.HEADER_P_PREFERRED_IDENTITY));\n            } else {\n                setPPreferedIdentityHeader(reInvite);\n            }\n\n            // Set User-Agent header\n            reInvite.addHeader(firstInvite.getHeader(UserAgentHeader.NAME));\n\n            // Add session timer management\n            if (dialog.getSessionExpireTime() >= SessionTimerManager.MIN_EXPIRE_PERIOD) {\n                // Set the Supported header\n                Header supportedHeader = SipUtils.HEADER_FACTORY.createHeader(SupportedHeader.NAME,\n                        \"timer\");\n                reInvite.addHeader(supportedHeader);\n\n                // Set Session-Timer headers\n                Header sessionExpiresHeader = SipUtils.HEADER_FACTORY.createHeader(\n                        SipUtils.HEADER_SESSION_EXPIRES, \"\" + dialog.getSessionExpireTime());\n                reInvite.addHeader(sessionExpiresHeader);\n            }\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) reInvite.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            // Create the content type and set content\n            ContentTypeHeader contentType = SipUtils.HEADER_FACTORY.createContentTypeHeader(\n                    \"application\", \"sdp\");\n            reInvite.setContent(content, contentType);\n\n            // Set the content length\n            reInvite.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(content\n                    .getBytes(UTF8).length));\n            return new SipRequest(reInvite);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP message with content : \" + content, e);\n        }\n\n    }\n\n    /**\n     * Create a SIP response for RE-INVITE request\n     * \n     * @param dialog Dialog path SIP request\n     * @param request SIP request\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse create200OkReInviteResponse(SipDialogPath dialog, SipRequest request)\n            throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY.createResponse(200, request.getStackMessage());\n\n            // Set Contact header\n            response.addHeader(dialog.getSipStack().getContact());\n\n            // Set the Server header\n            response.addHeader(SipUtils.buildServerHeader());\n\n            // Set the Require header\n            Header requireHeader = SipUtils.HEADER_FACTORY\n                    .createHeader(RequireHeader.NAME, \"timer\");\n            response.addHeader(requireHeader);\n\n            // Add Session-Timer header\n            Header sessionExpiresHeader = request.getHeader(SipUtils.HEADER_SESSION_EXPIRES);\n            if (sessionExpiresHeader != null) {\n                response.addHeader(sessionExpiresHeader);\n            }\n\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(request.getStackTransaction());\n            return resp;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Can't create response for re-invite!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP response for RE-INVITE request\n     * \n     * @param dialog Dialog path SIP request\n     * @param request SIP request\n     * @param featureTags featureTags to set in request\n     * @param content SDP content\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse create200OkReInviteResponse(SipDialogPath dialog, SipRequest request,\n            String[] featureTags, String content) throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY.createResponse(200, request.getStackMessage());\n\n            // Set the local tag\n            ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);\n            to.setTag(dialog.getLocalTag());\n\n            // Set Contact header\n            response.addHeader(dialog.getSipStack().getContact());\n\n            // Set feature tags\n            SipUtils.setFeatureTags(response, featureTags);\n\n            // Set Allow header\n            SipUtils.buildAllowHeader(response);\n\n            // Set the Server header\n            response.addHeader(SipUtils.buildServerHeader());\n\n            // Add session timer management\n            if (dialog.getSessionExpireTime() >= SessionTimerManager.MIN_EXPIRE_PERIOD) {\n                // Set the Require header\n                Header requireHeader = SipUtils.HEADER_FACTORY.createHeader(RequireHeader.NAME,\n                        \"timer\");\n                response.addHeader(requireHeader);\n\n                // Set Session-Timer header\n                Header sessionExpiresHeader = SipUtils.HEADER_FACTORY.createHeader(\n                        SipUtils.HEADER_SESSION_EXPIRES, dialog.getSessionExpireTime()\n                                + \";refresher=\" + dialog.getInvite().getSessionTimerRefresher());\n                response.addHeader(sessionExpiresHeader);\n            }\n\n            // Set the message content\n            response.setContent(content,\n                    SipUtils.HEADER_FACTORY.createContentTypeHeader(\"application\", \"sdp\"));\n\n            // Set the message content length\n            response.setContentLength(SipUtils.HEADER_FACTORY.createContentLengthHeader(content\n                    .getBytes(UTF8).length));\n\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(request.getStackTransaction());\n            return resp;\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create response for re-invite with content : \"\n                    + content, e);\n        }\n    }\n\n    /**\n     * Create a SIP UPDATE request\n     * \n     * @param dialog SIP dialog path\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public static SipRequest createUpdate(SipDialogPath dialog) throws PayloadException {\n        try {\n            // Create the request\n            Request update = dialog.getStackDialog().createRequest(Request.UPDATE);\n\n            // Set the Supported header\n            Header supportedHeader = SipUtils.HEADER_FACTORY.createHeader(SupportedHeader.NAME,\n                    \"timer\");\n            update.addHeader(supportedHeader);\n\n            // Add Session-Timer header\n            Header sessionExpiresHeader = SipUtils.HEADER_FACTORY.createHeader(\n                    SipUtils.HEADER_SESSION_EXPIRES, \"\" + dialog.getSessionExpireTime());\n            update.addHeader(sessionExpiresHeader);\n\n            // Set \"rport\" (RFC3581)\n            ViaHeader viaHeader = (ViaHeader) update.getHeader(ViaHeader.NAME);\n            viaHeader.setRPort();\n\n            return new SipRequest(update);\n\n        } catch (ParseException | SipException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    /**\n     * Create a SIP response for UPDATE request\n     * \n     * @param dialog Dialog path SIP request\n     * @param request SIP request\n     * @return SIP response\n     * @throws PayloadException\n     */\n    public static SipResponse create200OkUpdateResponse(SipDialogPath dialog, SipRequest request)\n            throws PayloadException {\n        try {\n            // Create the response\n            Response response = SipUtils.MSG_FACTORY.createResponse(200, request.getStackMessage());\n\n            // Set Contact header\n            response.addHeader(dialog.getSipStack().getContact());\n\n            // Set the Server header\n            response.addHeader(SipUtils.buildServerHeader());\n\n            // Set the Require header\n            Header requireHeader = SipUtils.HEADER_FACTORY\n                    .createHeader(RequireHeader.NAME, \"timer\");\n            response.addHeader(requireHeader);\n\n            // Add Session-Timer header\n            Header sessionExpiresHeader = request.getHeader(SipUtils.HEADER_SESSION_EXPIRES);\n            if (sessionExpiresHeader != null) {\n                response.addHeader(sessionExpiresHeader);\n            }\n\n            SipResponse resp = new SipResponse(response);\n            resp.setStackTransaction(request.getStackTransaction());\n            return resp;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Can't create SIP message!\", e);\n        }\n    }\n\n    private static void setPPreferedIdentityHeader(Request request) throws ParseException {\n        Uri preferedUri = ImsModule.getImsUserProfile().getPreferredUri();\n        if (preferedUri != null) {\n            Header prefHeader = SipUtils.HEADER_FACTORY.createHeader(\n                    SipUtils.HEADER_P_PREFERRED_IDENTITY, preferedUri.toString());\n            request.addHeader(prefHeader);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/network/sip/SipUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.network.sip;\n\nimport com.gsma.rcs.core.TerminalInfo;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipMessage;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.utils.PhoneUtils;\n\nimport java.text.ParseException;\nimport java.util.ListIterator;\nimport java.util.Vector;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.address.AddressFactory;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderFactory;\nimport javax2.sip.header.MaxForwardsHeader;\nimport javax2.sip.header.MinExpiresHeader;\nimport javax2.sip.header.RecordRouteHeader;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.ServerHeader;\nimport javax2.sip.header.UserAgentHeader;\nimport javax2.sip.message.Message;\nimport javax2.sip.message.MessageFactory;\nimport javax2.sip.message.Request;\n\n/**\n * SIP utility functions\n *\n * @author JM. Auffret\n */\npublic class SipUtils {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    private final static String UA_HEADER_OMA_SIMPLE_IM = \"IM-client/OMA1.0 \";\n\n    private final static String UA_HEADER_EXT_TO_EXT_CLIENT = \"ExttoExt-client/Ext1.0 \";\n\n    private final static String HEADER_EXT_TO_EXT_SERVER = \"ExttoExt-serv/Ext1.0 \";\n    /**\n     * CRLF constant\n     */\n    public final static String CRLF = \"\\r\\n\";\n\n    public final static char WHITESPACE = ' ';\n\n    /**\n     * Header factory\n     */\n    public static HeaderFactory HEADER_FACTORY;\n\n    /**\n     * Address factory\n     */\n\n    public static AddressFactory ADDR_FACTORY;\n\n    /**\n     * Message factory\n     */\n    public static MessageFactory MSG_FACTORY;\n\n    /**\n     * Content-Transfer-Encoding header\n     */\n    public static final String HEADER_CONTENT_TRANSFER_ENCODING = \"Content-Transfer-Encoding\";\n\n    /**\n     * Accept-Contact header\n     */\n    public static final String HEADER_ACCEPT_CONTACT = \"Accept-Contact\";\n    public static final String HEADER_ACCEPT_CONTACT_C = \"a\";\n\n    /**\n     * P-Access-Network-Info header\n     */\n    public static final String HEADER_P_ACCESS_NETWORK_INFO = \"P-Access-Network-Info\";\n\n    /**\n     * P-Asserted-Identity header\n     */\n    public static final String HEADER_P_ASSERTED_IDENTITY = \"P-Asserted-Identity\";\n\n    /**\n     * P-Preferred-Identity header\n     */\n    public static final String HEADER_P_PREFERRED_IDENTITY = \"P-Preferred-Identity\";\n\n    /**\n     * P-Associated-URI header\n     */\n    public static final String HEADER_P_ASSOCIATED_URI = \"P-Associated-URI\";\n\n    /**\n     * Service-Route header\n     */\n    public static final String HEADER_SERVICE_ROUTE = \"Service-Route\";\n\n    /**\n     * Privacy header\n     */\n    public static final String HEADER_PRIVACY = \"Privacy\";\n\n    /**\n     * Refer-Sub header\n     */\n    public static final String HEADER_REFER_SUB = \"Refer-Sub\";\n\n    /**\n     * Referred-By header\n     */\n    public static final String HEADER_REFERRED_BY = \"Referred-By\";\n    public static final String HEADER_REFERRED_BY_C = \"b\";\n\n    /**\n     * Content-ID header\n     */\n    public static final String HEADER_CONTENT_ID = \"Content-ID\";\n\n    /**\n     * Session-Expires header\n     */\n    public static final String HEADER_SESSION_EXPIRES = \"Session-Expires\";\n\n    /**\n     * Min-SE header\n     */\n    public static final String HEADER_MIN_SE = \"Min-SE\";\n\n    /**\n     * SIP instance parameter\n     */\n    public static final String SIP_INSTANCE_PARAM = \"+sip.instance\";\n\n    /**\n     * Public GRUU parameter\n     */\n    public static final String PUBLIC_GRUU_PARAM = \"pub-gruu\";\n\n    /**\n     * Temp GRUU parameter\n     */\n    public static final String TEMP_GRUU_PARAM = \"temp-gruu\";\n\n    /**\n     * Explicit require tag\n     */\n    public static final String EXPLICIT_REQUIRE = \"explicit;require\";\n\n    private static String sUserAgentString;\n\n    private static String sServerHeaderValue;\n\n    /**\n     * Extract the URI part of a SIP address\n     * \n     * @param addr SIP address\n     * @return URI\n     */\n    public static String extractUriFromAddress(String addr) {\n        String uri = addr;\n        int index = addr.indexOf(\"<\");\n        if (index != -1) {\n            uri = addr.substring(index + 1, addr.indexOf(\">\", index));\n        }\n        return uri;\n    }\n\n    /**\n     * Construct an NTP time from a date in milliseconds\n     * \n     * @param date Date in milliseconds\n     * @return NTP time in string format\n     */\n    public static String constructNTPtime(long date) {\n        long ntpTime = 2208988800L;\n        long startTime = (date / SECONDS_TO_MILLISECONDS_CONVERSION_RATE) + ntpTime;\n        return String.valueOf(startTime);\n    }\n\n    /**\n     * Build User Agent value for UAC\n     * <p>\n     * UA Format : IM-client/OMA1.0 [terminal_vendor/terminal_model-terminal_SW_version]\n     * [client_vendor/client_version]\n     * </p>\n     * \n     * @return UA value\n     */\n    public static String userAgentString() {\n        if (sUserAgentString == null) {\n            sUserAgentString = UA_HEADER_EXT_TO_EXT_CLIENT + UA_HEADER_OMA_SIMPLE_IM\n                    + TerminalInfo.getBuildInfo() + WHITESPACE + TerminalInfo.getClientInfo();\n        }\n        return sUserAgentString;\n    }\n\n    /**\n     * Build User-Agent header\n     * \n     * @return header\n     * @throws ParseException\n     */\n    public static Header buildUserAgentHeader() throws ParseException {\n        return HEADER_FACTORY.createHeader(UserAgentHeader.NAME, userAgentString());\n    }\n\n    /**\n     * Build Server header\n     * \n     * @return header\n     * @throws ParseException\n     */\n    public static Header buildServerHeader() throws ParseException {\n        if (sServerHeaderValue == null) {\n            sServerHeaderValue = HEADER_EXT_TO_EXT_SERVER + UA_HEADER_OMA_SIMPLE_IM\n                    + TerminalInfo.getClientInfo();\n        }\n        return HEADER_FACTORY.createHeader(ServerHeader.NAME, sServerHeaderValue);\n    }\n\n    /**\n     * Build Allow header\n     * \n     * @param msg SIP message\n     * @throws ParseException\n     */\n    public static void buildAllowHeader(Message msg) throws ParseException {\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.INVITE));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.UPDATE));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.ACK));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.CANCEL));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.BYE));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.NOTIFY));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.OPTIONS));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.MESSAGE));\n        msg.addHeader(HEADER_FACTORY.createAllowHeader(Request.REFER));\n    }\n\n    /**\n     * Build Max-Forwards header\n     * \n     * @return Header\n     * @throws InvalidArgumentException\n     */\n    public static MaxForwardsHeader buildMaxForwardsHeader() throws InvalidArgumentException {\n        return HEADER_FACTORY.createMaxForwardsHeader(70);\n    }\n\n    /**\n     * Build P-Access-Network-info\n     * \n     * @param info Access info\n     * @return Header\n     * @throws ParseException\n     */\n    public static Header buildAccessNetworkInfo(String info) throws ParseException {\n        return HEADER_FACTORY.createHeader(SipUtils.HEADER_P_ACCESS_NETWORK_INFO, info);\n    }\n\n    /**\n     * Extract a parameter from an input text\n     * \n     * @param input Input text\n     * @param param Parameter name\n     * @param defaultValue Default value\n     * @return Returns the parameter value or a default value in case of error\n     */\n    public static String extractParameter(String input, String param, String defaultValue) {\n        int begin = input.indexOf(param) + param.length();\n        if (begin != -1) {\n            int end = input.indexOf(\" \", begin); // The end is by default the next space\n                                                 // encountered\n            if (input.charAt(begin) == '\\\"') {\n                // The exception is when the first character of the param is a \"\n                // In this case, the end is the next \" character, not the blank one\n                begin++; // we remove also the first quote\n                end = input.indexOf(\"\\\"\", begin); // do not take last doubleQuote\n            }\n            if (end == -1) {\n                return input.substring(begin);\n            }\n            return input.substring(begin, end);\n        }\n        return defaultValue;\n    }\n\n    /**\n     * Get Min-Expires period from message\n     * \n     * @param message SIP message\n     * @return Expire period in milliseconds or -1 in case of error\n     * @throws PayloadException\n     */\n    public static long getMinExpiresPeriod(SipMessage message) throws PayloadException {\n        MinExpiresHeader minHeader = (MinExpiresHeader) message.getHeader(MinExpiresHeader.NAME);\n        if (minHeader == null) {\n            throw new PayloadException(\n                    \"Unable to read value for header :\".concat(MinExpiresHeader.NAME));\n        }\n        return minHeader.getExpires() * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n    }\n\n    /**\n     * Get Min-SE period from message\n     * \n     * @param message SIP message\n     * @return Expire period in milliseconds or -1 in case of error\n     */\n    public static long getMinSessionExpirePeriod(SipMessage message) {\n        ExtensionHeader minSeHeader = (ExtensionHeader) message.getHeader(SipUtils.HEADER_MIN_SE);\n        if (minSeHeader != null) {\n            String value = minSeHeader.getValue();\n            return Long.parseLong(value) * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n        }\n        return -1;\n    }\n\n    /**\n     * Get asserted identity header\n     * \n     * @param request SIP request\n     * @return Asserted Identity Header\n     */\n    public static String getAssertedIdentityHeader(SipRequest request) {\n        ListIterator<Header> list = request.getHeaders(SipUtils.HEADER_P_ASSERTED_IDENTITY);\n        if (list != null) {\n            // There is at most 2 P-Asserted-Identity headers, one with tel uri and one with sip uri\n            // We give preference to the tel uri if both are present, if not we return the first one\n            String assertedHeader1;\n            if (list.hasNext()) {\n                // Get value of the first header\n                assertedHeader1 = ((ExtensionHeader) list.next()).getValue();\n                if (assertedHeader1.contains(PhoneUtils.TEL_URI_HEADER)) {\n                    return assertedHeader1;\n                }\n\n                if (list.hasNext()) {\n                    // Get value of the second header (it may not be present)\n                    String assertedHeader2 = ((ExtensionHeader) list.next()).getValue();\n                    if (assertedHeader2.contains(PhoneUtils.TEL_URI_HEADER)) {\n                        return assertedHeader2;\n                    }\n                }\n                // In case there is no tel uri, return the value of the first header\n                return assertedHeader1;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Get asserted identity\n     * \n     * @param request SIP request\n     * @return SIP URI\n     */\n    public static String getAssertedIdentity(SipRequest request) {\n        String assertedIdentityHeader = getAssertedIdentityHeader(request);\n        if (assertedIdentityHeader != null) {\n            return PhoneUtils.extractUriFromSipHeader(assertedIdentityHeader);\n        }\n        // No P-AssertedIdentity header, we take the value in the FROM uri\n        return PhoneUtils.extractUriFromSipHeader(request.getFromUri());\n    }\n\n    /**\n     * Generate a list of route headers. The record route of the incoming message is used to\n     * generate the corresponding route header.\n     * \n     * @param msg SIP message\n     * @param invert Invert or not the route list\n     * @return List of route headers as string\n     */\n    public static Vector<String> routeProcessing(SipMessage msg, boolean invert) {\n        Vector<String> result = new Vector<>();\n        ListIterator<Header> list = msg.getHeaders(RecordRouteHeader.NAME);\n        if (list == null) {\n            // No route available\n            return null;\n        }\n        while (list.hasNext()) {\n            RecordRouteHeader record = (RecordRouteHeader) list.next();\n            RouteHeader route = SipUtils.HEADER_FACTORY.createRouteHeader(record.getAddress());\n            if (invert) {\n                result.insertElementAt(route.getAddress().toString(), 0);\n            } else {\n                result.addElement(route.getAddress().toString());\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Is a feature tag present or not in SIP message\n     * \n     * @param msg SIP message\n     * @param featureTag Feature tag to be checked\n     * @return Boolean\n     */\n    public static boolean isFeatureTagPresent(SipMessage msg, String featureTag) {\n        for (String tag : msg.getFeatureTags()) {\n            // TODO comparison should be done on the whole feature tag\n            if (tag.contains(featureTag)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Set feature tags to a message\n     * \n     * @param message SIP stack message\n     * @param tags Table of tags\n     * @throws ParseException\n     */\n    public static void setFeatureTags(Message message, String[] tags) throws ParseException {\n        setFeatureTags(message, tags, tags);\n    }\n\n    /**\n     * Set feature tags to a message\n     * \n     * @param message SIP stack message\n     * @param contactTags List of tags for Contact header\n     * @param acceptContactTags List of tags for Accept-Contact header\n     * @throws ParseException\n     */\n    public static void setFeatureTags(Message message, String[] contactTags,\n            String[] acceptContactTags) throws ParseException {\n        if (contactTags.length != 0) {\n            setContactFeatureTags(message, contactTags);\n        }\n        if (acceptContactTags.length != 0) {\n            setAcceptContactFeatureTags(message, acceptContactTags);\n        }\n    }\n\n    /**\n     * Set feature tags to Accept-Contact header\n     * \n     * @param message SIP stack message\n     * @param tags List of tags\n     * @throws ParseException\n     */\n    private static void setAcceptContactFeatureTags(Message message, String[] tags)\n            throws ParseException {\n        if (tags.length > 1 && SipUtils.EXPLICIT_REQUIRE.equals(tags[tags.length - 1])) {\n            /*\n             * According to RFC 3841, there MUST NOT be more than one req-param or explicit-param in\n             * an ac-params. Furthermore, there can only be one instance of any feature tag in\n             * feature-param.\n             */\n            for (int i = 0; i < tags.length - 1; i++) {\n                Header header = SipUtils.HEADER_FACTORY.createHeader(\n                        SipUtils.HEADER_ACCEPT_CONTACT, \"*;\" + tags[i] + ';'\n                                + SipUtils.EXPLICIT_REQUIRE);\n                message.addHeader(header);\n            }\n        } else {\n            StringBuilder acceptTags = new StringBuilder(\"*\");\n            for (String tag : tags) {\n                acceptTags.append(';');\n                acceptTags.append(tag);\n            }\n            Header header = SipUtils.HEADER_FACTORY.createHeader(SipUtils.HEADER_ACCEPT_CONTACT,\n                    acceptTags.toString());\n            message.addHeader(header);\n        }\n    }\n\n    /**\n     * Set feature tags to Contact header\n     * \n     * @param message SIP stack message\n     * @param tags List of tags\n     * @throws ParseException\n     */\n    public static void setContactFeatureTags(Message message, String[] tags) throws ParseException {\n        ContactHeader contact = (ContactHeader) message.getHeader(ContactHeader.NAME);\n        if (contact == null) {\n            return;\n        }\n        for (String tag : tags) {\n            contact.setParameter(tag, null);\n        }\n    }\n\n    /**\n     * Get the Referred-By header\n     * \n     * @param message SIP message\n     * @return String value or null if not exist\n     */\n    public static String getReferredByHeader(SipMessage message) {\n        // Read Referred-By header\n        ExtensionHeader referredByHeader = (ExtensionHeader) message\n                .getHeader(SipUtils.HEADER_REFERRED_BY);\n        if (referredByHeader != null) {\n            return referredByHeader.getValue();\n        }\n        // Check contracted form\n        referredByHeader = (ExtensionHeader) message.getHeader(SipUtils.HEADER_REFERRED_BY_C);\n        if (referredByHeader != null) {\n            return referredByHeader.getValue();\n        }\n        // Try to extract manually the header in the message\n        // TODO: to be removed when bug fix corrected in native NIST stack\n        String msg = message.getStackMessage().toString();\n        int index = msg.indexOf(SipUtils.CRLF + \"b:\");\n        if (index == -1) {\n            return null;\n        }\n        int begin = index + 4;\n        int end = msg.indexOf(SipUtils.CRLF, index + 2);\n        return msg.substring(begin, end).trim();\n    }\n\n    /**\n     * Get remote SIP instance ID\n     * \n     * @param message SIP message\n     * @return ID or null\n     */\n    public static String getRemoteInstanceId(SipMessage message) {\n        ContactHeader contactHeader = (ContactHeader) message.getHeader(ContactHeader.NAME);\n        if (contactHeader != null) {\n            return contactHeader.getParameter(SIP_INSTANCE_PARAM);\n        }\n        return null;\n    }\n\n    private static String getAcceptContactTagValue(SipMessage message, String tagName) {\n        ListIterator<Header> acceptHeaders = message.getHeaders(SipUtils.HEADER_ACCEPT_CONTACT);\n        if (acceptHeaders == null || !acceptHeaders.hasNext()) {\n            /* Check contracted form */\n            acceptHeaders = message.getHeaders(SipUtils.HEADER_ACCEPT_CONTACT_C);\n        }\n        if (acceptHeaders == null) {\n            return null;\n        }\n        while (acceptHeaders.hasNext()) {\n            ExtensionHeader acceptHeader = (ExtensionHeader) acceptHeaders.next();\n            String[] pnames = acceptHeader.getValue().split(\";\");\n            if (pnames.length <= 1) {\n                continue;\n            }\n            /* Start at index 1 to bypass the address */\n            for (int i = 1; i < pnames.length; i++) {\n                String pname = pnames[i];\n                if (pname.startsWith(tagName)) {\n                    return pname.substring(tagName.length() + 1, pname.length());\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Get SIP instance ID of an incoming message\n     * \n     * @param message SIP message\n     * @return ID or null\n     */\n    public static String getInstanceID(SipMessage message) {\n        return getAcceptContactTagValue(message, SipUtils.SIP_INSTANCE_PARAM);\n    }\n\n    /**\n     * Get public GRUU\n     * \n     * @param message SIP message\n     * @return GRUU or null\n     */\n    public static String getPublicGruu(SipMessage message) {\n        return getAcceptContactTagValue(message, SipUtils.PUBLIC_GRUU_PARAM);\n    }\n\n    /**\n     * Set remote SIP instance ID of a message\n     * \n     * @param message SIP message\n     * @param instanceId SIP instance ID\n     * @throws ParseException\n     */\n    public static void setRemoteInstanceID(Message message, String instanceId)\n            throws ParseException {\n        ExtensionHeader acceptHeader = (ExtensionHeader) message\n                .getHeader(SipUtils.HEADER_ACCEPT_CONTACT);\n        StringBuilder featureTag = new StringBuilder(\";\");\n        featureTag.append(SipUtils.SIP_INSTANCE_PARAM).append(\"=\\\"\").append(instanceId)\n                .append(\"\\\"\");\n\n        if (acceptHeader != null) {\n            // Update existing header with SIP instance\n            acceptHeader.setValue(acceptHeader.getValue() + featureTag.toString());\n        } else {\n            // Add header with SIP instance\n            Header header = SipUtils.HEADER_FACTORY.createHeader(SipUtils.HEADER_ACCEPT_CONTACT,\n                    \"*\" + featureTag.toString());\n            message.addHeader(header);\n        }\n    }\n\n    /**\n     * Get display name from URI\n     * \n     * @param uri URI\n     * @return Display name or null\n     */\n    private static String getDisplayNameFromUri(String uri) {\n        int index0 = uri.indexOf(\"\\\"\");\n        if (index0 != -1) {\n            int index1 = uri.indexOf(\"\\\"\", index0 + 1);\n            if (index1 > 0) {\n                return uri.substring(index0 + 1, index1);\n            }\n        }\n        return null;\n    }\n\n    public static void assertContentIsNotNull(String content, SipRequest invite)\n            throws PayloadException {\n        if (content == null) {\n            throw new PayloadException(\"Unable to extract content from invite: \" + invite);\n        }\n    }\n\n    /**\n     * Get display name from Invite\n     *\n     * @param invite the SIP invite\n     * @return Display name\n     */\n    public static String getDisplayNameFromInvite(SipRequest invite) {\n        String displayName;\n        String assertedHeader = getAssertedIdentityHeader(invite);\n        if (assertedHeader != null) {\n            // To get Display name from P-Asserted-Identity header as per spec section 2.5.2.1\n            displayName = getDisplayNameFromUri(assertedHeader);\n        } else {\n            // To get Display name from FROM header as per spec section 2.5.3.3\n            displayName = getDisplayNameFromUri(invite.getFrom());\n        }\n        if (displayName != null) {\n            return displayName;\n        }\n        // To get Display name from Contact header as per RFC3261\n        String contactHeader = invite.getContactAddress();\n        if (contactHeader != null) {\n            displayName = getDisplayNameFromUri(contactHeader);\n        }\n        return displayName;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/PayloadException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.protocol;\n\n/**\n * To be thrown when a transaction fails due to corrupted/invalid entries in payload. For ex : Error\n * while parsing SDP e.t.c.\n * <p>\n * These exceptions should be logged and need to be communicated properly to upper service layers.\n * </p>\n */\npublic class PayloadException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public PayloadException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public PayloadException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpAuthenticationAgent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.security.HttpDigestMd5Authentication;\nimport com.gsma.rcs.utils.Base64;\n\n/**\n * HTTP Digest MD5 authentication agent\n * \n * @author JM. Auffret\n * @author Deutsche Telekom\n */\npublic class HttpAuthenticationAgent {\n\n    private final String mServerLogin;\n\n    private final String mServerPwd;\n\n    /**\n     * HTTP Digest MD5 agent\n     */\n    private HttpDigestMd5Authentication mDigest = new HttpDigestMd5Authentication();\n\n    /**\n     * Controls if its a HTTP Digest authentication or Basic\n     */\n    private boolean mIsDigestAuthentication;\n\n    /**\n     * Constructor\n     * \n     * @param login Server login\n     * @param pwd Server pwd\n     */\n    public HttpAuthenticationAgent(String login, String pwd) {\n        mServerLogin = login;\n        mServerPwd = pwd;\n    }\n\n    /**\n     * Generate the authorization header\n     * \n     * @param method Method used\n     * @param requestUri Request Uri\n     * @param body Entity body\n     * @return authorizationHeader Authorization header\n     */\n    public String generateAuthorizationHeader(String method, String requestUri, String body) {\n        return \"Authorization: \".concat(generateAuthorizationHeaderValue(method, requestUri, body));\n    }\n\n    /**\n     * Generate the authorization header value\n     * \n     * @param method Method used\n     * @param requestUri Request Uri\n     * @param body Entity body\n     * @return authorizationHeader Authorization header value\n     */\n    public String generateAuthorizationHeaderValue(String method, String requestUri, String body) {\n        /*\n         * According to\n         * \"Rich Communication Suite 5.1 Advanced Communications - Services and Client Specification - Version 2.0 - 03 May 2013\"\n         * , the authentication should be performed using basic authentication or HTTP digest as\n         * per[RFC2617]\n         */\n        if (!mIsDigestAuthentication) {\n            /* Build the Basic Authorization header */\n            return \"Basic \".concat(Base64.encodeBase64ToString((new StringBuilder(mServerLogin)\n                    .append(':').append(mServerPwd).toString()).getBytes(UTF8)));\n        }\n\n        mDigest.updateNonceParameters();\n\n        /* Build the Authorization header */\n        StringBuilder authValue = new StringBuilder(\"Digest username=\\\"\").append(mServerLogin)\n                .append(\"\\\"\").append(\",realm=\\\"\").append(mDigest.getRealm()).append(\"\\\"\")\n                .append(\",nonce=\\\"\").append(mDigest.getNonce()).append(\"\\\"\").append(\",uri=\\\"\")\n                .append(requestUri).append(\"\\\"\").append(\",nc=\").append(mDigest.buildNonceCounter())\n                .append(\",cnonce=\\\"\").append(mDigest.getCnonce()).append(\"\\\"\");\n\n        String opaque = mDigest.getOpaque();\n        if (opaque != null) {\n            authValue.append(\",opaque=\\\"\").append(opaque).append(\"\\\"\");\n        }\n\n        String qop = mDigest.getQop();\n        if (qop != null && qop.startsWith(\"auth\")) {\n            authValue\n                    .append(\",qop=\\\"\")\n                    .append(qop)\n                    .append(\"\\\"\")\n                    .append(\",response=\\\"\")\n                    .append(mDigest.calculateResponse(mServerLogin, mServerPwd, method, requestUri,\n                            mDigest.buildNonceCounter(), body)).append(\"\\\"\");\n\n        } else {\n            authValue\n                    .append(\",response=\\\"\")\n                    .append(mDigest.calculateResponse(mServerLogin, mServerPwd, method, requestUri,\n                            mDigest.buildNonceCounter(), \"\")).append(\"\\\"\");\n        }\n\n        return authValue.toString();\n\n    }\n\n    /**\n     * Read the WWW-Authenticate header\n     * \n     * @param header WWW-Authenticate header\n     */\n    public void readWwwAuthenticateHeader(String header) {\n        if (header != null) {\n            // According to\n            // \"Rich Communication Suite 5.1 Advanced Communications - Services and Client Specification - Version 2.0 - 03 May 2013\",\n            // the authentication should be performed using basic authentication or HTTP digest as\n            // per [RFC2617]\n            mIsDigestAuthentication = header\n                    .startsWith(HttpDigestMd5Authentication.HTTP_DIGEST_SCHEMA);\n            if (!mIsDigestAuthentication) {\n                return;\n            }\n\n            // Get domain name\n            String value = getValue(header, \"realm\");\n            mDigest.setRealm(value);\n\n            // Get opaque parameter\n            value = getValue(header, \"opaque\");\n            mDigest.setOpaque(value);\n\n            // Get qop\n            value = getValue(header, \"qop\");\n            mDigest.setQop(value);\n\n            // Get nonce to be used\n            value = getValue(header, \"nonce\");\n            mDigest.setNextnonce(value);\n        }\n    }\n\n    /**\n     * Get the value of key in header\n     * \n     * @param header\n     * @param key\n     * @return value\n     */\n    private String getValue(String header, String key) {\n        String value = null;\n        int end = -1;\n        int begin = header.toLowerCase().indexOf(key + \"=\\\"\");\n        if (begin != -1) {\n            begin += key.length() + 2;\n            end = header.indexOf(\"\\\"\", begin);\n            if (end == -1)\n                end = header.length();\n            value = header.substring(begin, end);\n        } else {\n            begin = header.toLowerCase().indexOf(key + \"=\");\n            if (begin != -1) {\n                begin += key.length() + 1;\n                end = header.indexOf(\",\", begin);\n                if (end == -1)\n                    end = header.length();\n                value = header.substring(begin, end);\n            }\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpDeleteRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\n/**\n * HTTP DELETE request\n * \n * @author jexa7410\n */\npublic class HttpDeleteRequest extends HttpRequest {\n    /**\n     * Constructor\n     * \n     * @param url URL\n     */\n    public HttpDeleteRequest(String url) {\n        super(url, null, null);\n    }\n\n    /**\n     * Returns the HTTP method\n     * \n     * @return Method\n     */\n    public String getMethod() {\n        return \"DELETE\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpGetRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\n/**\n * HTTP GET request\n * \n * @author jexa7410\n */\npublic class HttpGetRequest extends HttpRequest {\n    /**\n     * Constructor\n     * \n     * @param url URL\n     */\n    public HttpGetRequest(String url) {\n        super(url, null, null);\n    }\n\n    /**\n     * Returns the HTTP method\n     * \n     * @return Method\n     */\n    public String getMethod() {\n        return \"GET\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpPostRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\n/**\n * HTTP POST request\n * \n * @author vfml3370\n */\npublic class HttpPostRequest extends HttpRequest {\n    /**\n     * Constructor\n     * \n     * @param url URL\n     * @param content Content\n     * @param contentType Content type\n     */\n    public HttpPostRequest(String url, String content, String contentType) {\n        super(url, content, contentType);\n    }\n\n    /**\n     * Returns the HTTP method\n     * \n     * @return Method\n     */\n    public String getMethod() {\n        return \"POST\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpPutRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\n/**\n * HTTP PUT request\n * \n * @author jexa7410\n */\npublic class HttpPutRequest extends HttpRequest {\n    /**\n     * Constructor\n     * \n     * @param url URL\n     * @param content Content\n     * @param contentType Content type\n     */\n    public HttpPutRequest(String url, String content, String contentType) {\n        super(url, content, contentType);\n    }\n\n    /**\n     * Returns the HTTP method\n     * \n     * @return Method\n     */\n    public String getMethod() {\n        return \"PUT\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\n/**\n * HTTP request\n * \n * @author jexa7410\n */\npublic abstract class HttpRequest {\n    /**\n     * URL\n     */\n    private String mUrl;\n\n    /**\n     * Content\n     */\n    private String mContent;\n\n    /**\n     * Content type\n     */\n    private String mContentType;\n\n    /**\n     * Cookie\n     */\n    private String mCookie;\n\n    /**\n     * HTTP authentication agent\n     */\n    private HttpAuthenticationAgent mAuthenticationAgent;\n\n    /**\n     * Constructor\n     * \n     * @param url URL\n     * @param content Content\n     * @param contentType Content type\n     */\n    public HttpRequest(String url, String content, String contentType) {\n        mUrl = url;\n        mContent = content;\n        mContentType = contentType;\n    }\n\n    /**\n     * Returns the authentication agent\n     * \n     * @return Authentication agent\n     */\n    public HttpAuthenticationAgent getAuthenticationAgent() {\n        return mAuthenticationAgent;\n    }\n\n    /**\n     * Set the authentication agent\n     * \n     * @param agent Authentication agent\n     */\n    public void setAuthenticationAgent(HttpAuthenticationAgent agent) {\n        mAuthenticationAgent = agent;\n    }\n\n    /**\n     * Returns the HTTP method\n     * \n     * @return Method\n     */\n    public abstract String getMethod();\n\n    /**\n     * Returns the HTTP URL\n     * \n     * @return URL\n     */\n    public String getUrl() {\n        return mUrl;\n    }\n\n    /**\n     * Returns the HTTP content\n     * \n     * @return Conetnt\n     */\n    public String getContent() {\n        return mContent;\n    }\n\n    /**\n     * Returns the HTTP content\n     * \n     * @return Conetnt\n     */\n    public int getContentLength() {\n        int length = 0;\n        if (mContent != null) {\n            length = mContent.length();\n        }\n        return length;\n    }\n\n    /**\n     * Returns the content type\n     * \n     * @return Mime content type\n     */\n    public String getContentType() {\n        return mContentType;\n    }\n\n    /**\n     * Returns the cookie\n     * \n     * @return Cookie\n     */\n    public String getCookie() {\n        return mCookie;\n    }\n\n    /**\n     * Set the cookie\n     * \n     * @param cookie Cookie\n     */\n    public void setCookie(String cookie) {\n        mCookie = cookie;\n    }\n\n    /**\n     * Returns the AUID of the request\n     * \n     * @return AUID\n     */\n    public String getAUID() {\n        return mUrl.split(\"/\")[1];\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/http/HttpResponse.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.http;\n\nimport android.text.TextUtils;\n\nimport java.util.Hashtable;\n\n/**\n * HTTP response\n * \n * @author jexa7410\n */\npublic class HttpResponse {\n\n    private static final int INVALID_RESPONSE = -1;\n\n    /**\n     * Status line\n     */\n    private String mStatus;\n\n    /**\n     * Headers\n     */\n    private Hashtable<String, String> headers = new Hashtable<String, String>();\n\n    /**\n     * Content\n     */\n    private byte[] content = null;\n\n    /**\n     * Constructor\n     */\n    public HttpResponse() {\n    }\n\n    /**\n     * Set the status line\n     * \n     * @param status Status line\n     */\n    public void setStatusLine(String status) {\n        mStatus = status;\n    }\n\n    /**\n     * Get the status line\n     * \n     * @return Status line\n     */\n    public String getStatusLine() {\n        return mStatus;\n    }\n\n    /**\n     * Add header\n     * \n     * @param name Header name\n     * @param value Header value\n     */\n    public void addHeader(String name, String value) {\n        headers.put(name, value);\n    }\n\n    /**\n     * Get header\n     * \n     * @param name Header name\n     * @return Header value\n     */\n    public String getHeader(String name) {\n        return headers.get(name.toLowerCase());\n    }\n\n    /**\n     * Returns the response code\n     * \n     * @return Response code or -1 in case of error\n     */\n    public int getResponseCode() {\n        try {\n            if (TextUtils.isEmpty(mStatus)) {\n                return INVALID_RESPONSE;\n            }\n            int index1 = mStatus.indexOf(\" \") + 1;\n            int index2 = mStatus.indexOf(\" \", index1);\n            return Integer.parseInt(mStatus.substring(index1, index2));\n\n        } catch (NumberFormatException e) {\n            return INVALID_RESPONSE;\n        }\n    }\n\n    /**\n     * Is a successful response\n     * \n     * @return Boolean\n     */\n    public boolean isSuccessfullResponse() {\n        int code = getResponseCode();\n        if ((code >= 200) && (code < 300)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Is not found response\n     * \n     * @return Boolean\n     */\n    public boolean isNotFoundResponse() {\n        int code = getResponseCode();\n        if (code == 404) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Returns the response content\n     * \n     * @return Content as byte array\n     */\n    public byte[] getContent() {\n        return content;\n    }\n\n    /**\n     * Set the response content\n     * \n     * @param content Content\n     */\n    public void setContent(byte[] content) {\n        this.content = content;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/ChunkReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Hashtable;\n\n/**\n * Chunks receiver\n * \n * @author jexa7410\n */\npublic class ChunkReceiver extends Thread {\n    /**\n     * MSRP connection\n     */\n    private MsrpConnection mConnection;\n\n    /**\n     * MSRP input stream\n     */\n    private InputStream mStream;\n\n    /**\n     * Termination flag\n     */\n    private boolean mTerminated;\n\n    /**\n     * Maximum length of MSRP chunk buffer\n     */\n    private int mBufferLength = MsrpConstants.CHUNK_MAX_SIZE;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(ChunkReceiver.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param connection MSRP connection\n     * @param stream TCP input stream\n     */\n    public ChunkReceiver(MsrpConnection connection, InputStream stream) {\n        mConnection = connection;\n        mStream = stream;\n    }\n\n    /**\n     * Returns the MSRP connection\n     * \n     * @return MSRP connection\n     */\n    public MsrpConnection getConnection() {\n        return mConnection;\n    }\n\n    /**\n     * Terminate the receiver\n     */\n    public void terminate() {\n        mTerminated = true;\n        interrupt();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            boolean msrpTraceEnabled = MsrpConnection.isMsrpTraceEnabled();\n            // Background processing\n            while (!mTerminated) {\n                StringBuilder trace = new StringBuilder();\n\n                // Read first line of a new data chunk\n                StringBuilder line = readLine();\n\n                if (line.length() == 0) {\n                    if (msrpTraceEnabled) {\n                        System.out.println(\"<<< End of stream\");\n                    }\n                    return;\n                }\n\n                if (msrpTraceEnabled) {\n                    trace.append(line);\n                    trace.append(MsrpConstants.NEW_LINE);\n                }\n                // Check the MSRP tag\n                String[] firstLineTags = line.toString().split(\" \");\n                if ((firstLineTags.length < 3)\n                        || !firstLineTags[0].equals(MsrpConstants.MSRP_HEADER)) {\n                    if (msrpTraceEnabled) {\n                        System.out.println(\"<<< Not a MSRP message\");\n                    }\n                    return;\n                }\n\n                // Get the transaction ID from the first line\n                String txId = firstLineTags[1];\n                String end = MsrpConstants.END_MSRP_MSG + txId;\n\n                // Get response code or method name from the first line\n                int responseCode = -1;\n                String method = null;\n                try {\n                    responseCode = Integer.parseInt(firstLineTags[2]);\n                } catch (NumberFormatException e) {\n                    method = firstLineTags[2];\n                }\n\n                // Data chunk\n                byte[] data = null;\n\n                // Read next lines\n                Hashtable<String, String> headers = new Hashtable<String, String>();\n                char continuationFlag = '\\0';\n                int totalSize = 0;\n                while (continuationFlag == '\\0' && !mTerminated) {\n                    line = readLine();\n                    if (msrpTraceEnabled) {\n                        trace.append(line);\n                        trace.append(MsrpConstants.NEW_LINE);\n                    }\n\n                    // Test if there is a new line separating headers from the data\n                    if (line.length() == 0) {\n                        // Read data\n                        String byteRange = headers.get(MsrpConstants.HEADER_BYTE_RANGE);\n                        int chunkSize = -1;\n                        if (byteRange != null) {\n                            chunkSize = MsrpUtils.getChunkSize(byteRange);\n                            totalSize = MsrpUtils.getTotalSize(byteRange);\n\n                            // Changed by Deutsche Telekom\n                            if (chunkSize == 0) {\n                                mBufferLength = totalSize;\n                            }\n                        }\n\n                        if (chunkSize >= 0) {\n                            // Use Byte-Range value to read directly the block of data\n                            byte[] buffer = readChunkedData(chunkSize, end);\n\n                            if (chunkSize > 0) {\n                                data = buffer;\n                                // TODO: we could harden the code by checking whether the chunk was\n                                // shorter than expected\n                            } else {\n                                // Cut off continuation flag\n                                data = new byte[buffer.length - 1];\n                                System.arraycopy(buffer, 0, data, 0, buffer.length - 1);\n                                continuationFlag = (char) buffer[buffer.length - 1];\n                            }\n\n                            if (msrpTraceEnabled) {\n                                trace.append(new String(data, UTF8));\n                                trace.append(MsrpConstants.NEW_LINE);\n                            }\n                        } else {\n                            // Read until terminating header is found\n                            StringBuilder buffer = new StringBuilder();\n                            StringBuilder dataline;\n                            boolean endchunk = false;\n                            while ((!endchunk) && (buffer.length() < MsrpConstants.CHUNK_MAX_SIZE)) {\n                                dataline = readLine();\n                                if ((dataline.length() - 1 == end.length())\n                                        && (dataline.toString().startsWith(end))) {\n                                    continuationFlag = dataline.charAt(dataline.length() - 1);\n                                    endchunk = true;\n                                } else {\n                                    if (buffer.length() > 0) {\n                                        buffer.append(MsrpConstants.NEW_LINE);\n                                    }\n                                    buffer.append(dataline);\n                                }\n                            }\n                            data = buffer.toString().getBytes(UTF8);\n                            totalSize = data.length;\n\n                            if (msrpTraceEnabled) {\n                                trace.append(new String(data, UTF8));\n                                trace.append(MsrpConstants.NEW_LINE);\n                                trace.append(end);\n                                trace.append(continuationFlag);\n                            }\n                        }\n                    } else if (line.toString().startsWith(end)) {\n                        continuationFlag = line.charAt(line.length() - 1);\n                    } else {\n                        // It's an header\n                        int index = line.indexOf(\":\");\n                        String headerName = line.substring(0, index).trim();\n                        String headerValue = line.substring(index + 1).trim();\n\n                        // Add the header in the list\n                        headers.put(headerName, headerValue);\n                    }\n                }\n\n                final MsrpSession session = mConnection.getSession();\n                // Process the received MSRP message\n                if (responseCode != -1) {\n                    // Process MSRP response\n                    if (msrpTraceEnabled) {\n                        System.out.println(\"<<< Receive MSRP response:\\n\" + trace);\n                    }\n                    session.receiveMsrpResponse(responseCode, txId, headers);\n                } else {\n                    // Process MSRP request\n                    if (MsrpConstants.METHOD_SEND.equals(method)) {\n                        // Process a SEND request\n                        if (msrpTraceEnabled) {\n                            System.out.println(\"<<< Receive MSRP SEND request:\\n\" + trace);\n                        }\n                        session.receiveMsrpSend(txId, headers, continuationFlag, data, totalSize);\n                    } else if (MsrpConstants.METHOD_REPORT.equals(method)) {\n                        // Process a REPORT request\n                        if (msrpTraceEnabled) {\n                            System.out.println(\"<<< Receive MSRP REPORT request:\\n\" + trace);\n                        }\n                        session.receiveMsrpReport(txId, headers);\n                    } else {\n                        // Unknown request\n                        if (msrpTraceEnabled) {\n                            System.out.println(\"<<< Unknown request received:\\n\" + trace);\n                        }\n                        // Remove transaction info from list\n                        // Changed by Deutsche Telekom\n                        session.removeMsrpTransactionInfo(txId);\n                    }\n                }\n\n                // Check transaction info data\n                // Changed by Deutsche Telekom\n                session.checkMsrpTransactionInfo();\n            }\n        } catch (FileAccessException e) {\n            sLogger.error(\"Unable to receive chunks!\", e);\n            if (!mTerminated) {\n                /* Notify the session listener that an error has occured */\n                final MsrpSession session = mConnection.getSession();\n                session.getMsrpEventListener().msrpTransferError(null, e.getMessage(),\n                        TypeMsrpChunk.Unknown);\n\n                /* Check transaction info data */\n                session.checkMsrpTransactionInfo();\n                mTerminated = true;\n            }\n        } catch (ContactManagerException e) {\n            sLogger.error(\"Unable to receive chunks!\", e);\n            if (!mTerminated) {\n                /* Notify the session listener that an error has occured */\n                final MsrpSession session = mConnection.getSession();\n                session.getMsrpEventListener().msrpTransferError(null, e.getMessage(),\n                        TypeMsrpChunk.Unknown);\n\n                /* Check transaction info data */\n                session.checkMsrpTransactionInfo();\n                mTerminated = true;\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Unable to receive chunks!\", e);\n            if (!mTerminated) {\n                /* Notify the session listener that an error has occured */\n                final MsrpSession session = mConnection.getSession();\n                session.getMsrpEventListener().msrpTransferError(null, e.getMessage(),\n                        TypeMsrpChunk.Unknown);\n\n                /* Check transaction info data */\n                session.checkMsrpTransactionInfo();\n                mTerminated = true;\n            }\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            if (!mTerminated) {\n                /* Notify the session listener that an error has occured */\n                /* Changed by Deutsche Telekom */\n                final MsrpSession session = mConnection.getSession();\n                session.getMsrpEventListener().msrpTransferError(null, e.getMessage(),\n                        TypeMsrpChunk.Unknown);\n\n                /* Check transaction info data */\n                /* Changed by Deutsche Telekom */\n                session.checkMsrpTransactionInfo();\n                mTerminated = true;\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Unable to receive chunks!\", e);\n            if (!mTerminated) {\n                /* Notify the session listener that an error has occured */\n                final MsrpSession session = mConnection.getSession();\n                session.getMsrpEventListener().msrpTransferError(null, e.getMessage(),\n                        TypeMsrpChunk.Unknown);\n\n                /* Check transaction info data */\n                session.checkMsrpTransactionInfo();\n                mTerminated = true;\n            }\n        }\n    }\n\n    /**\n     * Read line\n     * \n     * @return String\n     * @throws NetworkException\n     */\n    private StringBuilder readLine() throws NetworkException {\n        try {\n            StringBuilder line = new StringBuilder();\n            int previous = -1;\n            int current = -1;\n            while ((current = mStream.read()) != -1) {\n                line.append((char) current);\n                if ((previous == MsrpConstants.CHAR_LF) && (current == MsrpConstants.CHAR_CR)) {\n                    return line.delete(line.length() - 2, line.length());\n                }\n                previous = current;\n            }\n            return line;\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to read line!\", e);\n        }\n    }\n\n    /**\n     * Read chunked data\n     * \n     * @param chunkSize Chunk size\n     * @return Data\n     * @throws NetworkException\n     */\n    private byte[] readChunkedData(int chunkSize, String endTag) throws NetworkException {\n        try {\n            // Read data until chunk size is reached\n            byte[] result = null;\n            if (chunkSize != 0) {\n                result = new byte[chunkSize];\n                int nbRead = 0;\n                int nbData = -1;\n                while ((nbRead < chunkSize)\n                        && ((nbData = mStream.read(result, nbRead, chunkSize - nbRead)) != -1)) {\n                    nbRead += nbData;\n                }\n            } else {\n                int b;\n                int tagLength = endTag.length();\n                int[] tail = new int[tagLength];\n                byte[] buffer = new byte[mBufferLength + tagLength + 2];\n\n                // MSRP end tag in reverse order\n                int[] match = new int[tagLength];\n                for (int i = 0; i < tagLength; i++) {\n                    match[i] = endTag.charAt(tagLength - i - 1);\n                }\n\n                // Read stream byte by byte\n                for (int j = 0; (b = mStream.read()) != -1; j++) {\n                    // Sliding window over last received bytes\n                    System.arraycopy(tail, 0, tail, 1, tagLength - 1);\n                    tail[0] = b;\n\n                    if (b != match[0]) {\n                        buffer[j] = (byte) b;\n                    } else {\n                        // First char matches; let's check for the others\n                        boolean tagFound = true;\n                        for (int k = 1; k < tagLength - 1; k++) {\n                            if (tail[k] != match[k]) {\n                                buffer[j] = (byte) b;\n                                tagFound = false;\n                                break;\n                            }\n                        }\n                        if (tagFound) {\n                            // Strip off MSRP end tag\n                            // j+1 characters read; remove tagLength characters and CR/LF plus one\n                            // extra\n                            // character for continuation flag\n                            result = new byte[j - tagLength];\n                            System.arraycopy(buffer, 0, result, 0, j - tagLength - 1); // remove tag\n                                                                                       // and\n                                                                                       // CR/LF\n\n                            // read continuation flag\n                            result[j - tagLength - 1] = (byte) mStream.read();\n                            break;\n                        }\n                    }\n                }\n            }\n            mStream.read(); // Read LF\n            mStream.read(); // Read CR\n            return result;\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to read chunk data!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/ChunkSender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Chunks sender\n * \n * @author jexa7410\n */\npublic class ChunkSender extends Thread {\n    /**\n     * MSRP connection\n     */\n    private MsrpConnection mConnection;\n\n    /**\n     * MSRP output stream\n     */\n    private OutputStream mStream;\n\n    /**\n     * Buffer of chunks\n     */\n    private FifoBuffer mBuffer = new FifoBuffer();\n\n    /**\n     * Termination flag\n     */\n    private boolean mTerminated;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(ChunkSender.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param connection MSRP connection\n     * @param stream TCP output stream\n     */\n    public ChunkSender(MsrpConnection connection, OutputStream stream) {\n        mConnection = connection;\n        mStream = stream;\n    }\n\n    /**\n     * Returns the MSRP connection\n     * \n     * @return MSRP connection\n     */\n    public MsrpConnection getConnection() {\n        return mConnection;\n    }\n\n    /**\n     * Terminate the sender\n     */\n    public void terminate() {\n        mTerminated = true;\n        mBuffer.unblockRead();\n        interrupt();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            // Read chunk to be sent\n            byte chunk[] = null;\n            while ((chunk = (byte[]) mBuffer.getMessage()) != null) {\n                // Write chunk to the output stream\n                if (MsrpConnection.isMsrpTraceEnabled()) {\n                    System.out.println(\">>> Send MSRP message:\\n\" + new String(chunk, UTF8));\n                }\n                writeData(chunk);\n            }\n        } catch (NetworkException e) {\n            if (!mTerminated) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n                /* Notify the msrp session listener that an error has occured */\n                /* Changed by Deutsche Telekom */\n                mConnection.getSession().getMsrpEventListener()\n                        .msrpTransferError(null, e.getMessage(), TypeMsrpChunk.Unknown);\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Unable to send chunks!\", e);\n            if (!mTerminated) {\n                /* Notify the msrp session listener that an error has occured */\n                /* Changed by Deutsche Telekom */\n                mConnection.getSession().getMsrpEventListener()\n                        .msrpTransferError(null, e.getMessage(), TypeMsrpChunk.Unknown);\n            }\n        }\n    }\n\n    /**\n     * Send a chunk\n     * \n     * @param chunk New chunk\n     * @throws NetworkException\n     */\n    public void sendChunk(byte chunk[]) throws NetworkException {\n        if (mConnection.getSession().isFailureReportRequested()) {\n            mBuffer.putMessage(chunk);\n        } else {\n            sendChunkImmediately(chunk);\n        }\n    }\n\n    /**\n     * Send a chunk immediately\n     * \n     * @param chunk New chunk\n     * @throws NetworkException\n     */\n    public void sendChunkImmediately(byte chunk[]) throws NetworkException {\n        if (MsrpConnection.isMsrpTraceEnabled()) {\n            System.out.println(\">>> Send MSRP message:\\n\" + new String(chunk, UTF8));\n        }\n        writeData(chunk);\n    }\n\n    /**\n     * Write data to the stream\n     * \n     * @param chunk Data chunk\n     * @throws NetworkException\n     */\n    private synchronized void writeData(byte chunk[]) throws NetworkException {\n        try {\n            mStream.write(chunk);\n            mStream.flush();\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to write data!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/DataChunks.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport java.io.ByteArrayOutputStream;\n\n/**\n * Data chunks\n * \n * @author jexa7410\n */\npublic class DataChunks {\n    /**\n     * Current transfered size in bytes\n     */\n    private int currentSize = 0;\n\n    /**\n     * Cache used to save data chunks\n     */\n    private ByteArrayOutputStream cache = new ByteArrayOutputStream();\n\n    /**\n     * Constructor\n     */\n    public DataChunks() {\n    }\n\n    /**\n     * Add a new chunk\n     * \n     * @param data Data chunk\n     */\n    public void addChunk(byte[] data) {\n        cache.write(data, 0, data.length);\n        currentSize += data.length;\n    }\n\n    /**\n     * Get received data\n     * \n     * @return Byte array\n     */\n    public byte[] getReceivedData() {\n        return cache.toByteArray();\n    }\n\n    /**\n     * Reset the cache\n     */\n    public void resetCache() {\n        cache.reset();\n    }\n\n    /**\n     * Returns the current size of the received chunks\n     * \n     * @return Size in bytes\n     */\n    public int getCurrentSize() {\n        return currentSize;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/FifoBuffer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport java.util.Vector;\n\n/**\n * Fifo buffer\n * \n * @author JM. Auffret\n */\npublic class FifoBuffer {\n    /**\n     * Number of messages in the buffer\n     */\n    private int numMessage = 0;\n\n    /**\n     * Buffer of messages\n     */\n    private Vector<Object> fifo = new Vector<Object>();\n\n    /**\n     * Add a message in the buffer\n     * \n     * @param obj Message\n     */\n    public synchronized void putMessage(Object obj) {\n        fifo.addElement(obj);\n        numMessage++;\n        notifyAll();\n    }\n\n    /**\n     * Read a message in the buffer. This is a blocking method until a message is received in the\n     * buffer.\n     * \n     * @return Message\n     */\n    public synchronized Object getMessage() {\n        Object message = null;\n        if (numMessage == 0) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n                /* Nothing to be done here */\n            }\n        }\n        if (numMessage != 0) {\n            message = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            numMessage--;\n            notifyAll();\n        }\n        return message;\n    }\n\n    /**\n     * Read a message in the buffer. This is a blocking method until a timeout occurs or a message\n     * is received in the buffer.\n     * \n     * @param timeout Timeout\n     * @return Message\n     */\n    public synchronized Object getMessage(int timeout) {\n        Object message = null;\n        if (numMessage == 0) {\n            try {\n                wait(timeout);\n            } catch (InterruptedException e) {\n                /* Nothing to be done here */\n            }\n        }\n        if (numMessage != 0) {\n            message = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            numMessage--;\n            notifyAll();\n        }\n        return message;\n    }\n\n    /**\n     * Unblock the reading\n     */\n    public void unblockRead() {\n        synchronized (this) {\n            this.notifyAll();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpClientConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.platform.network.SocketConnection;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * MSRP client connection\n * \n * @author jexa7410\n */\npublic class MsrpClientConnection extends MsrpConnection {\n    /**\n     * Remote IP address\n     */\n    private String remoteAddress;\n\n    /**\n     * Remote TCP port number\n     */\n    private int remotePort;\n\n    /**\n     * Secured connection\n     */\n    private boolean secured = false;\n\n    // Changed by Deutsche Telekom\n    /**\n     * Secured connection\n     */\n    private String announcedFingerprint = null;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param session MSRP session\n     * @param remoteAddress Remote IP address\n     * @param remotePort Remote port number\n     */\n    public MsrpClientConnection(MsrpSession session, String remoteAddress, int remotePort) {\n        super(session);\n\n        this.remoteAddress = remoteAddress;\n        this.remotePort = remotePort;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param session MSRP session\n     * @param remoteAddress Remote IP address\n     * @param remotePort Remote port number\n     * @param secured Secured media flag\n     */\n    public MsrpClientConnection(MsrpSession session, String remoteAddress, int remotePort,\n            boolean secured) {\n        this(session, remoteAddress, remotePort);\n\n        this.secured = secured;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Constructor\n     * \n     * @param session MSRP session\n     * @param remoteAddress Remote IP address\n     * @param remotePort Remote port number\n     * @param secured Secured media flag\n     * @param fingerprint fingerprint announced in SDP\n     */\n    public MsrpClientConnection(MsrpSession session, String remoteAddress, int remotePort,\n            boolean secured, String fingerprint) {\n        this(session, remoteAddress, remotePort);\n\n        this.secured = secured;\n        this.announcedFingerprint = fingerprint;\n    }\n\n    /**\n     * Is secured connection\n     * \n     * @return Boolean\n     */\n    public boolean isSecured() {\n        return secured;\n    }\n\n    /**\n     * Returns the socket connection\n     * \n     * @return Socket\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public SocketConnection getSocketConnection() throws NetworkException, PayloadException {\n        if (logger.isActivated()) {\n            logger.debug(\"Open client socket to \" + remoteAddress + \":\" + remotePort);\n        }\n        SocketConnection socket;\n        if (secured) {\n            // Changed by Deutsche Telekom\n            if (this.announcedFingerprint != null) {\n                // follow RFC 4572\n                // use self-signed certificates\n                socket = NetworkFactory.getFactory().createSimpleSecureSocketClientConnection(\n                        this.announcedFingerprint);\n            } else {\n                socket = NetworkFactory.getFactory().createSecureSocketClientConnection();\n            }\n        } else {\n            socket = NetworkFactory.getFactory().createSocketClientConnection();\n        }\n        socket.open(remoteAddress, remotePort);\n        if (logger.isActivated()) {\n            logger.debug(\"Socket connected to \" + remoteAddress + \":\" + remotePort);\n        }\n        return socket;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.platform.network.SocketConnection;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Abstract MSRP connection between two end points\n * \n * @author jexa7410\n */\npublic abstract class MsrpConnection {\n\n    private static boolean sMsrpTraceEnabled = false;\n\n    private MsrpSession mSession;\n\n    private SocketConnection mSocket;\n\n    private OutputStream mOutputStream;\n\n    private InputStream mInputStream;\n\n    /**\n     * Chunk receiver\n     */\n    private ChunkReceiver mReceiver;\n\n    /**\n     * Chunk sender\n     */\n    private ChunkSender mSender;\n\n    private static final Logger sLogger = Logger.getLogger(MsrpConnection.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param session MSRP session\n     */\n    public MsrpConnection(MsrpSession session) {\n        mSession = session;\n    }\n\n    /**\n     * Returns the MSRP session associated to the MSRP connection\n     * \n     * @return MSRP session\n     */\n    public MsrpSession getSession() {\n        return mSession;\n    }\n\n    /**\n     * Open the connection\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void open() throws NetworkException, PayloadException {\n        // Open socket connection\n        mSocket = getSocketConnection();\n        // Open I/O stream\n        mInputStream = mSocket.getInputStream();\n        mOutputStream = mSocket.getOutputStream();\n        // Create the chunk receiver\n        mReceiver = new ChunkReceiver(this, mInputStream);\n        mReceiver.start();\n        // Create the chunk sender\n        mSender = new ChunkSender(this, mOutputStream);\n        mSender.start();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Connection has been opened\");\n        }\n    }\n\n    /**\n     * Open the connection with SO_TIMEOUT on the socket\n     * \n     * @param timeout Timeout value (in milliseconds)\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void open(long timeout) throws NetworkException, PayloadException {\n        // Open socket connection\n        mSocket = getSocketConnection();\n        // Set SoTimeout\n        mSocket.setSoTimeout(timeout);\n        // Open I/O stream\n        mInputStream = mSocket.getInputStream();\n        mOutputStream = mSocket.getOutputStream();\n        // Create the chunk receiver\n        mReceiver = new ChunkReceiver(this, mInputStream);\n        mReceiver.start();\n        // Create the chunk sender\n        mSender = new ChunkSender(this, mOutputStream);\n        mSender.start();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Connection has been opened\");\n        }\n    }\n\n    /**\n     * Close the connection\n     */\n    public void close() {\n        if (mSender != null) {\n            mSender.terminate();\n        }\n        if (mReceiver != null) {\n            mReceiver.terminate();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Close the socket connection\");\n        }\n        CloseableUtils.tryToClose(mInputStream);\n        CloseableUtils.tryToClose(mOutputStream);\n        CloseableUtils.tryToClose(mSocket);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Connection has been closed\");\n        }\n    }\n\n    /**\n     * Send a new data chunk\n     * \n     * @param chunk Data chunk\n     * @throws NetworkException\n     */\n    public void sendChunk(byte chunk[]) throws NetworkException {\n        if (mSender == null) {\n            throw new NetworkException(\"ChunkSender is already closed!\");\n        }\n        mSender.sendChunk(chunk);\n    }\n\n    /**\n     * Send a new data chunk immediately\n     * \n     * @param chunk Data chunk\n     * @throws NetworkException\n     */\n    public void sendChunkImmediately(byte chunk[]) throws NetworkException {\n        mSender.sendChunkImmediately(chunk);\n    }\n\n    /**\n     * Returns the socket connection\n     * \n     * @return Socket\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public abstract SocketConnection getSocketConnection() throws PayloadException,\n            NetworkException;\n\n    /**\n     * Checks if MSRP trace is enabled\n     * \n     * @return True if MSRP trace is enabled\n     */\n    public static boolean isMsrpTraceEnabled() {\n        return sMsrpTraceEnabled;\n    }\n\n    /**\n     * Sets MSRP trace enabled\n     * \n     * @param enable True if MSRP trace is enabled\n     */\n    public static void setMsrpTraceEnabled(boolean enable) {\n        sMsrpTraceEnabled = enable;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpConstants.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\n/**\n * MSRP contants\n * \n * @author jexa7410\n */\npublic interface MsrpConstants {\n    public static final String MSRP_PROTOCOL = \"msrp\";\n    public static final String MSRP_SECURED_PROTOCOL = \"msrps\";\n    public static final String SOCKET_MSRP_PROTOCOL = \"TCP/MSRP\";\n    public static final String SOCKET_MSRP_SECURED_PROTOCOL = \"TCP/TLS/MSRP\";\n\n    public static final String MSRP_HEADER = \"MSRP\";\n    public static final String NEW_LINE = \"\\r\\n\";\n    public static final String END_MSRP_MSG = \"-------\";\n\n    public static final int FLAG_LAST_CHUNK = '$';\n    public static final int FLAG_MORE_CHUNK = '+';\n    public static final int FLAG_ABORT_CHUNK = '#';\n\n    public static final byte CHAR_SP = ' ';\n    public static final byte CHAR_LF = '\\r';\n    public static final byte CHAR_CR = '\\n';\n    public static final byte CHAR_MIN = '-';\n    public static final byte CHAR_DOUBLE_POINT = ':';\n\n    public static final String HEADER_BYTE_RANGE = \"Byte-Range\";\n    public static final String HEADER_STATUS = \"Status\";\n    public static final String HEADER_CONTENT_TYPE = \"Content-Type\";\n    public static final String HEADER_MESSAGE_ID = \"Message-ID\";\n    public static final String HEADER_TO_PATH = \"To-Path\";\n    public static final String HEADER_FROM_PATH = \"From-Path\";\n    public static final String HEADER_FAILURE_REPORT = \"Failure-Report\";\n    public static final String HEADER_SUCCESS_REPORT = \"Success-Report\";\n\n    public static final String METHOD_SEND = \"SEND\";\n    public static final String METHOD_REPORT = \"REPORT\";\n    public static final String STATUS_200_OK = \"200 OK\";\n\n    public static final int CHUNK_MAX_SIZE = 10 * 1024;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\n\n/**\n * MSRP event listener\n * \n * @author jexa7410\n * @author Deutsche Telekom AG\n */\npublic interface MsrpEventListener {\n    /**\n     * Data has been transferred\n     * \n     * @param msgId Message ID\n     */\n    void msrpDataTransferred(String msgId);\n\n    /**\n     * Data has been received\n     * \n     * @param msgId Message ID\n     * @param data Received data\n     * @param mimeType Data mime-type\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    void receiveMsrpData(String msgId, byte[] data, String mimeType) throws PayloadException,\n            NetworkException, ContactManagerException;\n\n    /**\n     * Data transfer in progress\n     * \n     * @param currentSize Current transfered size in bytes\n     * @param totalSize Total size in bytes\n     */\n    void msrpTransferProgress(long currentSize, long totalSize);\n\n    /**\n     * Data transfer in progress\n     * \n     * @param currentSize Current transfered size in bytes\n     * @param totalSize Total size in bytes\n     * @param data received data chunk\n     * @return true if data are processed and can be delete in cache. If false, so data were stored\n     *         in MsrpSession cache until msrpDataReceived is called.\n     */\n    boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data);\n\n    /**\n     * Data transfer has been aborted\n     */\n    void msrpTransferAborted();\n\n    /**\n     * Data transfer error\n     * \n     * @param msgId Message ID\n     * @param error Error code\n     * @param typeMsrpChunk Type of MSRP chunk\n     */\n    void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.InetAddressUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.InputStream;\nimport java.util.Vector;\n\n/**\n * MSRP manager\n * \n * @author jexa7410\n */\npublic class MsrpManager {\n\n    private String mLocalMsrpAddress;\n\n    private int mLocalMsrpPort;\n\n    private MsrpSession mMsrpSession;\n\n    private long mSessionId;\n\n    private boolean mSecured = false;\n\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param localMsrpAddress Local MSRP address\n     * @param localMsrpPort Local MSRP port\n     * @param rcsSettings the RCS settings accessor\n     */\n    public MsrpManager(String localMsrpAddress, int localMsrpPort, RcsSettings rcsSettings) {\n        mLocalMsrpAddress = localMsrpAddress;\n        mLocalMsrpPort = localMsrpPort;\n        mSessionId = System.currentTimeMillis();\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param localMsrpAddress Local MSRP address\n     * @param localMsrpPort Local MSRP port\n     * @param service ImsService\n     * @param rcsSettings the RCS settings accessor\n     */\n    public MsrpManager(String localMsrpAddress, int localMsrpPort, ImsService service,\n            RcsSettings rcsSettings) {\n        this(localMsrpAddress, localMsrpPort, rcsSettings);\n        ImsModule imsModule = service.getImsModule();\n        if (imsModule.isConnectedToWifiAccess()) {\n            mSecured = rcsSettings.isSecureMsrpOverWifi();\n\n        } else if (imsModule.isConnectedToMobileAccess()) {\n            mSecured = rcsSettings.isSecureMsrpOverMobile();\n        }\n    }\n\n    /**\n     * Returns the local MSRP port\n     * \n     * @return Port number\n     */\n    public int getLocalMsrpPort() {\n        return mLocalMsrpPort;\n    }\n\n    /**\n     * Get the local socket protocol path\n     * \n     * @return Protocol\n     */\n    public String getLocalSocketProtocol() {\n        if (mSecured) {\n            return MsrpConstants.SOCKET_MSRP_SECURED_PROTOCOL;\n        }\n        return MsrpConstants.SOCKET_MSRP_PROTOCOL;\n    }\n\n    /**\n     * Get the local MSRP path\n     * \n     * @return MSRP path\n     */\n    public String getLocalMsrpPath() {\n        if (InetAddressUtils.isIPv6Address(mLocalMsrpAddress)) {\n            return getMsrpProtocol() + \"://[\" + mLocalMsrpAddress + \"]:\" + mLocalMsrpPort + \"/\"\n                    + mSessionId + \";tcp\";\n        }\n        return getMsrpProtocol() + \"://\" + mLocalMsrpAddress + \":\" + mLocalMsrpPort + \"/\"\n                + mSessionId + \";tcp\";\n    }\n\n    /**\n     * Get the MSRP protocol\n     * \n     * @return MSRP protocol\n     */\n    public String getMsrpProtocol() {\n        if (mSecured) {\n            return MsrpConstants.MSRP_SECURED_PROTOCOL;\n        }\n        return MsrpConstants.MSRP_PROTOCOL;\n    }\n\n    /**\n     * Return the MSRP session\n     * \n     * @return MSRP session\n     */\n    public MsrpSession getMsrpSession() {\n        return mMsrpSession;\n    }\n\n    /**\n     * Is secured\n     * \n     * @return Boolean\n     */\n    public boolean isSecured() {\n        return mSecured;\n    }\n\n    /**\n     * Set secured\n     * \n     * @param flag Boolean flag\n     */\n    public void setSecured(boolean flag) {\n        mSecured = flag;\n    }\n\n    /**\n     * Open the MSRP session\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void openMsrpSession() throws NetworkException, PayloadException {\n        mMsrpSession.getConnection().open();\n    }\n\n    /**\n     * Open the connection with SO_TIMEOUT on the socket\n     * \n     * @param timeout Timeout value (in milliseconds)\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void openMsrpSession(long timeout) throws NetworkException, PayloadException {\n        mMsrpSession.getConnection().open(timeout);\n    }\n\n    /**\n     * Create either an MSRP client or server connection depending on media attribute \"setup\" in the\n     * remote SDP answer.\n     * \n     * @param sdp remote SDP answer\n     * @param listener MsrpEventListener\n     * @return MsrpSession\n     */\n    public MsrpSession createMsrpSession(byte[] sdp, MsrpEventListener listener) {\n        SdpParser parser = new SdpParser(sdp);\n\n        Vector<MediaDescription> media = parser.getMediaDescriptions();\n        MediaDescription mediaDesc = media.elementAt(0);\n        MediaAttribute pathAttribute = mediaDesc.getMediaAttribute(\"path\");\n        String remoteMsrpPath = pathAttribute.getValue();\n\n        // Create the MSRP session\n        MsrpSession session;\n        MediaAttribute setupAttribute = mediaDesc.getMediaAttribute(\"setup\");\n        String setup = null;\n        if (setupAttribute != null) {\n            setup = setupAttribute.getValue();\n        } else {\n            logger.error(\"Media attribute \\\"setup\\\" is missing!\");\n            logger.warn(\"media=\" + mediaDesc.toString());\n            if (mediaDesc.mMediaAttributes != null)\n                for (MediaAttribute attribute : mediaDesc.mMediaAttributes) {\n                    logger.warn(\"attribute key=\" + attribute.getName() + \" value=\"\n                            + attribute.getValue());\n                }\n\n        }\n        // if remote peer is active this client needs to be passive (i.e. act as server)\n        if (\"active\".equalsIgnoreCase(setup)) {\n            session = createMsrpServerSession(remoteMsrpPath, listener);\n        } else {\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n            session = createMsrpClientSession(remoteHost, remotePort, remoteMsrpPath, listener,\n                    fingerprint);\n        }\n\n        return session;\n    }\n\n    /**\n     * Create a MSRP client session\n     * \n     * @param remoteHost Remote host\n     * @param remotePort Remote port\n     * @param remoteMsrpPath Remote MSRP path\n     * @param listener Event listener\n     * @param fingerprint the finger print\n     * @return Created session\n     */\n    public MsrpSession createMsrpClientSession(String remoteHost, int remotePort,\n            String remoteMsrpPath, MsrpEventListener listener, String fingerprint) {\n        if (logger.isActivated()) {\n            logger.info(\"Create MSRP client end point at \" + remoteHost + \":\" + remotePort);\n        }\n\n        /* Create a new MSRP session */\n        mMsrpSession = new MsrpSession(mRcsSettings);\n        mMsrpSession.setFrom(getLocalMsrpPath());\n        mMsrpSession.setTo(remoteMsrpPath);\n\n        /* Create a MSRP client connection */\n        MsrpConnection connection = new MsrpClientConnection(mMsrpSession, remoteHost, remotePort,\n                mSecured, fingerprint);\n        mMsrpSession.setConnection(connection);\n        mMsrpSession.addMsrpEventListener(listener);\n\n        return mMsrpSession;\n    }\n\n    /**\n     * Create a MSRP server session\n     * \n     * @param remoteMsrpPath Remote MSRP path\n     * @param listener Event listener\n     * @return Created session\n     */\n    public MsrpSession createMsrpServerSession(String remoteMsrpPath, MsrpEventListener listener) {\n        if (logger.isActivated()) {\n            logger.info(\"Create MSRP server end point at \" + mLocalMsrpPort);\n        }\n\n        // Create a MSRP session\n        mMsrpSession = new MsrpSession(mRcsSettings);\n        mMsrpSession.setFrom(getLocalMsrpPath());\n        mMsrpSession.setTo(remoteMsrpPath);\n\n        // Create a MSRP server connection\n        MsrpConnection connection = new MsrpServerConnection(mMsrpSession, mLocalMsrpPort);\n\n        // Associate the connection to the session\n        mMsrpSession.setConnection(connection);\n\n        // Add event listener\n        mMsrpSession.addMsrpEventListener(listener);\n\n        // Return the created session\n        return mMsrpSession;\n    }\n\n    /**\n     * Send data chunks\n     * \n     * @param inputStream Input stream\n     * @param msgId Message ID\n     * @param contentType Content type\n     * @param contentSize Content size\n     * @param typeMsrpChunk Type of MSRP chunk\n     * @throws NetworkException\n     */\n    public void sendChunks(InputStream inputStream, String msgId, String contentType,\n            long contentSize, TypeMsrpChunk typeMsrpChunk) throws NetworkException {\n        mMsrpSession.sendChunks(inputStream, msgId, contentType, contentSize, typeMsrpChunk);\n    }\n\n    /**\n     * Send an empty chunk\n     * \n     * @throws NetworkException\n     */\n    public void sendEmptyChunk() throws NetworkException {\n        mMsrpSession.sendEmptyChunk();\n    }\n\n    /**\n     * Close the MSRP session\n     */\n    public synchronized void closeSession() {\n        if (mMsrpSession != null) {\n            if (logger.isActivated()) {\n                logger.info(\"Close the MSRP session\");\n            }\n            mMsrpSession.close();\n            mMsrpSession = null;\n        }\n    }\n\n    /**\n     * Is established\n     * \n     * @return true If the empty packet was sent successfully\n     */\n    public boolean isEstablished() {\n        return mMsrpSession != null && mMsrpSession.isEstablished();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpServerConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport java.io.IOException;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.platform.network.SocketConnection;\nimport com.gsma.rcs.platform.network.SocketServerConnection;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * MSRP server connection\n * \n * @author jexa7410\n */\npublic class MsrpServerConnection extends MsrpConnection {\n    /**\n     * Local TCP port number\n     */\n    private int mLocalPort;\n\n    /**\n     * Socket server connection\n     */\n    private SocketServerConnection mSocketServer;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(MsrpServerConnection.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param session MSRP session\n     * @param localPort Local port number\n     */\n    public MsrpServerConnection(MsrpSession session, int localPort) {\n        super(session);\n        mLocalPort = localPort;\n    }\n\n    /**\n     * Returns the socket connection\n     * \n     * @return Socket\n     * @throws NetworkException\n     */\n    public SocketConnection getSocketConnection() throws NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Open server socket at \" + mLocalPort);\n            }\n            mSocketServer = NetworkFactory.getFactory().createSocketServerConnection();\n            mSocketServer.open(mLocalPort);\n\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Wait client connection\");\n            }\n\n            SocketConnection socket = mSocketServer.acceptConnection();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Socket connected to \" + socket.getRemoteAddress() + \":\"\n                        + socket.getRemotePort());\n            }\n            return socket;\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to get socket connection!\", e);\n        }\n    }\n\n    /**\n     * Close the connection\n     */\n    public void close() {\n        super.close();\n        CloseableUtils.tryToClose(mSocketServer);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Random;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * MSRP session\n * \n * @author jexa7410\n */\npublic class MsrpSession {\n\n    /**\n     * Transaction info expiry timeout in milliseconds\n     */\n    private static final long TRANSACTION_INFO_EXPIRY_PERIOD = 30000;\n\n    private static final byte[] NEW_LINE = MsrpConstants.NEW_LINE.getBytes(UTF8);\n\n    /**\n     * MSRP Chunk type\n     */\n    public enum TypeMsrpChunk {\n        TextMessage, IsComposing, MessageDisplayedReport, MessageDeliveredReport, OtherMessageDeliveredReportStatus, FileSharing, HttpFileSharing, ImageTransfer, EmptyChunk, GeoLocation, StatusReport, Unknown\n    }\n\n    /**\n     * MSRP transaction object that encapsulates the and map the msgId and if the origin was from\n     * displayed status message\n     */\n    private class MsrpTransactionInfo {\n        public String mTransactionId;\n        public String mMsrpMsgId;\n        public String mCpimMsgId;\n        public TypeMsrpChunk mTypeMsrpChunk = TypeMsrpChunk.Unknown;\n        private long mTimestamp = System.currentTimeMillis();\n\n        /**\n         * MSRP transaction info constructor\n         * \n         * @param transactionId MSRP transaction\n         * @param msrpMsgId MSRP message ID\n         * @param cpimMsgId CPIM message ID\n         * @param typeMsrpChunk MSRP chunk type (see {@link TypeMsrpChunk})\n         */\n        public MsrpTransactionInfo(String transactionId, String msrpMsgId, String cpimMsgId,\n                TypeMsrpChunk typeMsrpChunk) {\n            mTransactionId = transactionId;\n            mMsrpMsgId = msrpMsgId;\n            mCpimMsgId = cpimMsgId;\n            mTypeMsrpChunk = typeMsrpChunk;\n            mTimestamp = System.currentTimeMillis();\n        }\n\n        @Override\n        public String toString() {\n            return \"[MsrpTransactionInfo - \" + \"transactionId = \" + mTransactionId + \", \"\n                    + \"msrpMsgId = \" + mMsrpMsgId + \", \" + \"cpimMsgId = \" + mCpimMsgId + \", \"\n                    + \"typeMsrpChunk = \" + mTypeMsrpChunk + \", \" + \"timestamp = \" + mTimestamp\n                    + \"]\";\n        }\n    }\n\n    private boolean mFailureReportOption = false;\n\n    private boolean mSuccessReportOption = false;\n\n    private MsrpConnection mConnection;\n\n    /**\n     * From path\n     */\n    private String mFrom;\n\n    /**\n     * To path\n     */\n    private String mTo;\n\n    private boolean mCancelTransfer = false;\n\n    private RequestTransaction mRequestTransaction;\n\n    private DataChunks mReceivedChunks = new DataChunks();\n\n    private MsrpEventListener mMsrpEventListener;\n\n    /**\n     * Random generator\n     */\n    private static Random mRandom = new Random(System.currentTimeMillis());\n\n    private ReportTransaction mReportTransaction;\n\n    private MsrpTransaction mMsrpTransaction;\n\n    /**\n     * File transfer progress\n     */\n    private List<Long> mProgress = new ArrayList<>();\n\n    private long mTotalSize;\n\n    private static final Logger sLogger = Logger.getLogger(MsrpSession.class.getSimpleName());\n\n    /**\n     * Transaction info table\n     */\n    private ConcurrentHashMap<String, MsrpTransactionInfo> mTransactionInfoMap;\n\n    /**\n     * Mapping of messages to transactions\n     */\n    private ConcurrentHashMap<String, String> mMessageTransactionMap;\n\n    /**\n     * Transaction info table locking object\n     */\n    private final Object mTransactionMsgIdMapLock;\n\n    /**\n     * Controls if is to map the msgId from transactionId if not present on received MSRP messages\n     */\n    private boolean mMapMsgIdFromTransationId = false;\n\n    /**\n     * IsEstablished : set after media is successfully received\n     */\n    private boolean mIsEstablished = false;\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings The RCS settings accessor\n     */\n    public MsrpSession(RcsSettings rcsSettings) {\n        mTransactionMsgIdMapLock = new Object();\n        setMapMsgIdFromTransationId(true);\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * On destroy this instance\n     */\n    @Override\n    protected void finalize() throws Throwable {\n        setMapMsgIdFromTransationId(false);\n        super.finalize();\n    }\n\n    /**\n     * Generate a unique ID for transaction\n     * \n     * @return ID\n     */\n    private static synchronized String generateTransactionId() {\n        return Long.toHexString(mRandom.nextLong());\n    }\n\n    /**\n     * Is failure report requested\n     * \n     * @return Boolean\n     */\n    public boolean isFailureReportRequested() {\n        return mFailureReportOption;\n    }\n\n    /**\n     * Set the failure report option\n     * \n     * @param failureReportOption Boolean flag\n     */\n    public void setFailureReportOption(boolean failureReportOption) {\n        mFailureReportOption = failureReportOption;\n    }\n\n    /**\n     * Is success report requested\n     * \n     * @return Boolean\n     */\n    public boolean isSuccessReportRequested() {\n        return mSuccessReportOption;\n    }\n\n    /**\n     * Set the success report option\n     * \n     * @param successReportOption Boolean flag\n     */\n    public void setSuccessReportOption(boolean successReportOption) {\n        mSuccessReportOption = successReportOption;\n    }\n\n    /**\n     * Set the MSRP connection\n     * \n     * @param connection MSRP connection\n     */\n    public void setConnection(MsrpConnection connection) {\n        mConnection = connection;\n    }\n\n    /**\n     * Returns the MSRP connection\n     * \n     * @return MSRP connection\n     */\n    public MsrpConnection getConnection() {\n        return mConnection;\n    }\n\n    /**\n     * Get the MSRP event listener\n     * \n     * @return Listener\n     */\n    public MsrpEventListener getMsrpEventListener() {\n        return mMsrpEventListener;\n    }\n\n    /**\n     * Add a MSRP event listener\n     * \n     * @param listener Listener\n     */\n    public void addMsrpEventListener(MsrpEventListener listener) {\n        mMsrpEventListener = listener;\n    }\n\n    /**\n     * Returns the From path\n     * \n     * @return From path\n     */\n    public String getFrom() {\n        return mFrom;\n    }\n\n    /**\n     * Set the From path\n     * \n     * @param from From path\n     */\n    public void setFrom(String from) {\n        mFrom = from;\n    }\n\n    /**\n     * Returns the To path\n     * \n     * @return To path\n     */\n    public String getTo() {\n        return mTo;\n    }\n\n    /**\n     * Set the To path\n     * \n     * @param to To path\n     */\n    public void setTo(String to) {\n        mTo = to;\n    }\n\n    /**\n     * Close the session\n     */\n    public void close() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Close session\");\n        }\n\n        // Cancel transfer\n        mCancelTransfer = true;\n\n        // Close the connection\n        if (mConnection != null) {\n            mConnection.close();\n        }\n\n        // Unblock request transaction\n        if (mRequestTransaction != null) {\n            mRequestTransaction.terminate();\n        }\n\n        // Unblock report transaction\n        if (mReportTransaction != null) {\n            mReportTransaction.terminate();\n        }\n\n        // Unblock MSRP transaction\n        if (mMsrpTransaction != null) {\n            mMsrpTransaction.terminate();\n        }\n    }\n\n    /**\n     * Send chunks\n     * \n     * @param inputStream Input stream\n     * @param msgId Message ID\n     * @param contentType Content type to be sent\n     * @param totalSize Total size of content\n     * @param typeMsrpChunk Type of MSRP chunk\n     * @throws NetworkException\n     */\n    public void sendChunks(InputStream inputStream, String msgId, String contentType,\n            final long totalSize, TypeMsrpChunk typeMsrpChunk) throws NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send content (\" + contentType + \" - MSRP chunk type: \" + typeMsrpChunk\n                    + \")\");\n        }\n        mTotalSize = totalSize;\n        try {\n            byte data[] = new byte[MsrpConstants.CHUNK_MAX_SIZE];\n            long firstByte = 1;\n            long lastByte = 0;\n            mCancelTransfer = false;\n            if (mSuccessReportOption) {\n                mReportTransaction = new ReportTransaction();\n            } else {\n                mReportTransaction = null;\n            }\n            if (mFailureReportOption) {\n                mMsrpTransaction = new MsrpTransaction();\n            } else {\n                mMsrpTransaction = null;\n            }\n\n            // Calculate number of needed chunks\n            final int totalChunks = (int) Math.ceil(totalSize\n                    / (double) MsrpConstants.CHUNK_MAX_SIZE);\n\n            new Thread(new Runnable() {\n\n                @Override\n                public void run() {\n                    if (mMsrpTransaction != null) {\n                        while ((totalChunks - mMsrpTransaction.getNumberReceivedOk()) > 0\n                                && !mCancelTransfer) {\n                            mMsrpEventListener.msrpTransferProgress(\n                                    mMsrpTransaction.getNumberReceivedOk()\n                                            * MsrpConstants.CHUNK_MAX_SIZE, totalSize);\n                            try {\n                                Thread.sleep(500);\n                            } catch (InterruptedException e) {\n                                /* Nothing to be done here */\n                            }\n                        }\n                    }\n\n                }\n\n            }).start();\n\n            String newTransactionId;\n\n            // RFC4975, section 7.1.1. Sending SEND Requests\n            // When an endpoint has a message to deliver, it first generates a new\n            // Message-ID. The value MUST be highly unlikely to be repeated by\n            // another endpoint instance, or by the same instance in the future.\n            // Message-ID value follows the definition in RFC4975, section 9\n            String msrpMsgId = IdGenerator.generateMessageID();\n\n            // Send data chunk by chunk\n            for (int i = inputStream.read(data); (!mCancelTransfer) & (i > -1); i = inputStream\n                    .read(data)) {\n                // Update upper byte range\n                lastByte += i;\n\n                newTransactionId = generateTransactionId();\n                addMsrpTransactionInfo(newTransactionId, msrpMsgId, msgId, typeMsrpChunk);\n\n                // Send a chunk\n                sendMsrpSendRequest(newTransactionId, mTo, mFrom, msrpMsgId, contentType, i, data,\n                        firstByte, lastByte, totalSize);\n\n                // Update lower byte range\n                firstByte += i;\n\n                // Progress management\n                if (mFailureReportOption) {\n                    // Add value in progress vector\n                    mProgress.add(lastByte);\n                } else {\n                    // Direct notification\n                    if (!mCancelTransfer) {\n                        mMsrpEventListener.msrpTransferProgress(lastByte, totalSize);\n                    }\n                }\n            }\n\n            if (mCancelTransfer) {\n                // Transfer has been aborted\n                return;\n            }\n\n            // Waiting msrpTransaction\n            if (mMsrpTransaction != null) {\n                // Wait until all data have been reported\n                mMsrpTransaction.waitAllResponses();\n\n                // Notify event listener\n                if (mMsrpTransaction.isAllResponsesReceived()) {\n                    mMsrpEventListener.msrpDataTransferred(msgId);\n                } else {\n                    if (!mMsrpTransaction.isTerminated()) {\n                        mMsrpEventListener.msrpTransferError(msgId, \"response timeout 408\",\n                                typeMsrpChunk);\n                    }\n                }\n            }\n\n            // Waiting reportTransaction\n            if (mReportTransaction != null) {\n                // Wait until all data have been reported\n                while (!mReportTransaction.isTransactionFinished(totalSize)) {\n                    mReportTransaction.waitReport();\n                    if (mReportTransaction.getStatusCode() != 200) {\n                        // Error\n                        break;\n                    }\n                }\n\n                // Notify event listener\n                if (mReportTransaction.getStatusCode() == 200) {\n                    mMsrpEventListener.msrpDataTransferred(msgId);\n                } else {\n                    mMsrpEventListener.msrpTransferError(msgId, \"error report \"\n                            + mReportTransaction.getStatusCode(), typeMsrpChunk);\n                }\n            }\n\n            // No transaction\n            if (mMsrpTransaction == null && mReportTransaction == null) {\n                // Notify event listener\n                mMsrpEventListener.msrpDataTransferred(msgId);\n            }\n        } catch (IOException e) {\n            throw new NetworkException(\"Send chunk failed for msgId : \" + msgId, e);\n\n        } finally {\n            CloseableUtils.tryToClose(inputStream);\n        }\n    }\n\n    /**\n     * Send empty chunk\n     * \n     * @throws NetworkException\n     */\n    public void sendEmptyChunk() throws NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send an empty chunk\");\n        }\n        String newTransactionId = generateTransactionId();\n        String newMsgId = generateTransactionId();\n        addMsrpTransactionInfo(newTransactionId, newMsgId, null, TypeMsrpChunk.EmptyChunk);\n        sendEmptyMsrpSendRequest(newTransactionId, mTo, mFrom, newMsgId);\n    }\n\n    /**\n     * Send MSRP SEND request\n     * \n     * @param txId Transaction ID\n     * @param to To header\n     * @param from From header\n     * @param msrpMsgId MSRP message ID\n     * @param contentType Content type\n     * @param dataSize Data chunk size\n     * @param data Data chunk\n     * @param firstByte First byte range\n     * @param lastByte Last byte range\n     * @param totalSize Total size\n     * @throws NetworkException\n     */\n    private void sendMsrpSendRequest(String txId, String to, String from, String msrpMsgId,\n            String contentType, int dataSize, byte data[], long firstByte, long lastByte,\n            long totalSize) throws NetworkException {\n        ByteArrayOutputStream buffer = null;\n        try {\n            boolean isLastChunk = (lastByte == totalSize);\n            // Create request\n            buffer = new ByteArrayOutputStream(4000);\n            buffer.reset();\n            buffer.write(MsrpConstants.MSRP_HEADER.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write(txId.getBytes(UTF8));\n            buffer.write((\" \" + MsrpConstants.METHOD_SEND).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            String toHeader = MsrpConstants.HEADER_TO_PATH + \": \" + to + MsrpConstants.NEW_LINE;\n            buffer.write(toHeader.getBytes(UTF8));\n            String fromHeader = MsrpConstants.HEADER_FROM_PATH + \": \" + from\n                    + MsrpConstants.NEW_LINE;\n            buffer.write(fromHeader.getBytes(UTF8));\n            String msgIdHeader = MsrpConstants.HEADER_MESSAGE_ID + \": \" + msrpMsgId\n                    + MsrpConstants.NEW_LINE;\n            buffer.write(msgIdHeader.getBytes(UTF8));\n\n            // Write byte range\n            String byteRange = MsrpConstants.HEADER_BYTE_RANGE + \": \" + firstByte + \"-\" + lastByte\n                    + \"/\" + totalSize + MsrpConstants.NEW_LINE;\n            buffer.write(byteRange.getBytes(UTF8));\n\n            // Write optional headers\n            // According with GSMA guidelines\n            if (mFailureReportOption) {\n                String header = MsrpConstants.HEADER_FAILURE_REPORT + \": yes\"\n                        + MsrpConstants.NEW_LINE;\n                buffer.write(header.getBytes(UTF8));\n            }\n            if (mSuccessReportOption) {\n                String header = MsrpConstants.HEADER_SUCCESS_REPORT + \": yes\"\n                        + MsrpConstants.NEW_LINE;\n                buffer.write(header.getBytes(UTF8));\n            }\n\n            // Write content type\n            if (contentType != null) {\n                String content = MsrpConstants.HEADER_CONTENT_TYPE + \": \" + contentType\n                        + MsrpConstants.NEW_LINE;\n                buffer.write(content.getBytes(UTF8));\n            }\n\n            // Write data\n            if (data != null) {\n                buffer.write(NEW_LINE);\n                buffer.write(data, 0, dataSize);\n                buffer.write(NEW_LINE);\n            }\n\n            // Write end of request\n            buffer.write(MsrpConstants.END_MSRP_MSG.getBytes(UTF8));\n            buffer.write(txId.getBytes(UTF8));\n            if (isLastChunk) {\n                // '$' -> last chunk\n                buffer.write(MsrpConstants.FLAG_LAST_CHUNK);\n            } else {\n                // '+' -> more chunk\n                buffer.write(MsrpConstants.FLAG_MORE_CHUNK);\n            }\n            buffer.write(NEW_LINE);\n\n            // Send chunk\n            if (mFailureReportOption) {\n                if (mMsrpTransaction != null) {\n                    mMsrpTransaction.handleRequest();\n                    mRequestTransaction = null;\n                } else {\n                    mRequestTransaction = new RequestTransaction(mRcsSettings);\n                }\n                mConnection.sendChunk(buffer.toByteArray());\n                buffer.close();\n                if (mRequestTransaction != null) {\n                    mRequestTransaction.waitResponse();\n                    if (!mRequestTransaction.isResponseReceived()) {\n                        throw new NetworkException(\"Failed to receive transaction response!\");\n                    }\n                }\n            } else {\n                mConnection.sendChunk(buffer.toByteArray());\n                buffer.close();\n                if (mMsrpTransaction != null) {\n                    mMsrpTransaction.handleRequest();\n                }\n            }\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to read chunk data!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(buffer);\n        }\n    }\n\n    /**\n     * Send an empty MSRP SEND request\n     * \n     * @param txId Transaction ID\n     * @param to To header\n     * @param from From header\n     * @param msrpMsgId Message ID header\n     * @throws NetworkException\n     */\n    private void sendEmptyMsrpSendRequest(String txId, String to, String from, String msrpMsgId)\n            throws NetworkException {\n        ByteArrayOutputStream buffer = null;\n        try {\n            buffer = new ByteArrayOutputStream(4000);\n            buffer.reset();\n            buffer.write(MsrpConstants.MSRP_HEADER.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write(txId.getBytes(UTF8));\n            buffer.write((\" \" + MsrpConstants.METHOD_SEND).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            String toHeader = MsrpConstants.HEADER_TO_PATH + \": \" + to + MsrpConstants.NEW_LINE;\n            buffer.write(toHeader.getBytes(UTF8));\n            String fromHeader = MsrpConstants.HEADER_FROM_PATH + \": \" + from\n                    + MsrpConstants.NEW_LINE;\n            buffer.write(fromHeader.getBytes(UTF8));\n            String msgIdHeader = MsrpConstants.HEADER_MESSAGE_ID + \": \" + msrpMsgId\n                    + MsrpConstants.NEW_LINE;\n            buffer.write(msgIdHeader.getBytes(UTF8));\n\n            /* Write end of request */\n            buffer.write(MsrpConstants.END_MSRP_MSG.getBytes(UTF8));\n            buffer.write(txId.getBytes(UTF8));\n            /* '$' -> last chunk */\n            buffer.write(MsrpConstants.FLAG_LAST_CHUNK);\n            buffer.write(NEW_LINE);\n\n            mRequestTransaction = new RequestTransaction(mRcsSettings);\n            mConnection.sendChunkImmediately(buffer.toByteArray());\n\n            mRequestTransaction.waitResponse();\n            if (!mRequestTransaction.isResponseReceived()) {\n                throw new NetworkException(\"Failed to receive transaction response!\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to send empty Msrp send request!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(buffer);\n        }\n    }\n\n    /**\n     * Send MSRP response\n     * \n     * @param code Response code\n     * @param txId Transaction ID\n     * @param headers MSRP headers\n     * @throws NetworkException\n     */\n    private void sendMsrpResponse(String code, String txId, Hashtable<String, String> headers)\n            throws NetworkException {\n        ByteArrayOutputStream buffer = null;\n        try {\n            buffer = new ByteArrayOutputStream(4000);\n            buffer.write(MsrpConstants.MSRP_HEADER.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write(txId.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write(code.getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_TO_PATH.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write((headers.get(MsrpConstants.HEADER_FROM_PATH)).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_FROM_PATH.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write((headers.get(MsrpConstants.HEADER_TO_PATH)).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.END_MSRP_MSG.getBytes(UTF8));\n            buffer.write(txId.getBytes(UTF8));\n            buffer.write(MsrpConstants.FLAG_LAST_CHUNK);\n            buffer.write(NEW_LINE);\n\n            mConnection.sendChunk(buffer.toByteArray());\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to send Msrp response!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(buffer);\n        }\n    }\n\n    /**\n     * Send MSRP REPORT request\n     * \n     * @param txId Transaction ID\n     * @param headers MSRP headers\n     * @throws NetworkException\n     */\n    private void sendMsrpReportRequest(String txId, Hashtable<String, String> headers,\n            long lastByte, long totalSize) throws NetworkException {\n        ByteArrayOutputStream buffer = null;\n        try {\n            // Create request\n            buffer = new ByteArrayOutputStream(4000);\n            buffer.reset();\n            buffer.write(MsrpConstants.MSRP_HEADER.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write(txId.getBytes(UTF8));\n            buffer.write((\" \" + MsrpConstants.METHOD_REPORT).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_TO_PATH.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write(headers.get(MsrpConstants.HEADER_FROM_PATH).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_FROM_PATH.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write((headers.get(MsrpConstants.HEADER_TO_PATH)).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_MESSAGE_ID.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            buffer.write((headers.get(MsrpConstants.HEADER_MESSAGE_ID)).getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_BYTE_RANGE.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            String byteRange = \"1-\" + lastByte + \"/\" + totalSize;\n            buffer.write(byteRange.getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.HEADER_STATUS.getBytes(UTF8));\n            buffer.write(MsrpConstants.CHAR_DOUBLE_POINT);\n            buffer.write(MsrpConstants.CHAR_SP);\n            String status = \"000 200 OK\";\n            buffer.write(status.getBytes(UTF8));\n            buffer.write(NEW_LINE);\n\n            buffer.write(MsrpConstants.END_MSRP_MSG.getBytes(UTF8));\n            buffer.write(txId.getBytes(UTF8));\n            buffer.write(MsrpConstants.FLAG_LAST_CHUNK);\n            buffer.write(NEW_LINE);\n\n            // Send request\n            mRequestTransaction = new RequestTransaction(mRcsSettings);\n            mConnection.sendChunk(buffer.toByteArray());\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to send Msrp report request!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(buffer);\n        }\n    }\n\n    /**\n     * Receive MSRP SEND request\n     * \n     * @param txId Transaction ID\n     * @param headers Request headers\n     * @param flag Continuation flag\n     * @param data Received data\n     * @param totalSize Total size of the content\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void receiveMsrpSend(String txId, Hashtable<String, String> headers, int flag,\n            byte[] data, long totalSize) throws PayloadException, NetworkException,\n            ContactManagerException {\n        mIsEstablished = true;\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"SEND request received (flag=\" + flag + \", transaction=\" + txId\n                    + \", totalSize=\" + totalSize + \")\");\n        }\n\n        String msgId = headers.get(MsrpConstants.HEADER_MESSAGE_ID);\n        boolean failureReportNeeded = true;\n        String failureHeader = headers.get(MsrpConstants.HEADER_FAILURE_REPORT);\n        if ((failureHeader != null) && failureHeader.equalsIgnoreCase(\"no\")) {\n            failureReportNeeded = false;\n        }\n        if (failureReportNeeded) {\n            sendMsrpResponse(MsrpConstants.STATUS_200_OK, txId, headers);\n        }\n        if (data == null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Empty chunk\");\n            }\n            return;\n        }\n        mReceivedChunks.addChunk(data);\n\n        if (flag == MsrpConstants.FLAG_LAST_CHUNK) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Transfer terminated\");\n            }\n            byte[] dataContent = mReceivedChunks.getReceivedData();\n            mReceivedChunks.resetCache();\n\n            String contentTypeHeader = headers.get(MsrpConstants.HEADER_CONTENT_TYPE);\n            mMsrpEventListener.receiveMsrpData(msgId, dataContent, contentTypeHeader);\n\n            boolean successReportNeeded = false;\n            String reportHeader = headers.get(MsrpConstants.HEADER_SUCCESS_REPORT);\n            if ((reportHeader != null) && reportHeader.equalsIgnoreCase(\"yes\")) {\n                successReportNeeded = true;\n            }\n            if (successReportNeeded) {\n                sendMsrpReportRequest(txId, headers, dataContent.length, totalSize);\n            }\n        } else if (flag == MsrpConstants.FLAG_ABORT_CHUNK) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Transfer aborted\");\n            }\n            mMsrpEventListener.msrpTransferAborted();\n        } else if (flag == MsrpConstants.FLAG_MORE_CHUNK) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Transfer in progress...\");\n            }\n            byte[] dataContent = mReceivedChunks.getReceivedData();\n            boolean resetCache = mMsrpEventListener.msrpTransferProgress(\n                    mReceivedChunks.getCurrentSize(), totalSize, dataContent);\n\n            /*\n             * Data are only consumed chunk by chunk in file transfer & image share. In a chat\n             * session only the whole message is consumed after receiving the last chunk.\n             */\n            if (resetCache) {\n                mReceivedChunks.resetCache();\n            }\n        }\n    }\n\n    /**\n     * Receive MSRP response\n     * \n     * @param code Response code\n     * @param txId Transaction ID\n     * @param headers MSRP headers\n     */\n    public void receiveMsrpResponse(int code, String txId, Hashtable<String, String> headers) {\n        // Consider media is established when we received something\n        mIsEstablished = true;\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Response received (code=\" + code + \", transaction=\" + txId + \")\");\n        }\n\n        if (mFailureReportOption) {\n            // Notify progress\n            if (!mCancelTransfer && mProgress.size() > 0) {\n                mMsrpEventListener.msrpTransferProgress(mProgress.get(0), mTotalSize);\n                mProgress.remove(0);\n            }\n        }\n\n        // Notify request transaction\n        if (mRequestTransaction != null) {\n            mRequestTransaction.notifyResponse(code, headers);\n        }\n\n        // Notify MSRP transaction\n        if (mMsrpTransaction != null) {\n            mMsrpTransaction.handleResponse();\n        }\n\n        // Notify event listener\n        if (code != 200) {\n            String cpimMsgId = null;\n            TypeMsrpChunk typeMsrpChunk = TypeMsrpChunk.Unknown;\n            MsrpTransactionInfo msrpTransactionInfo = getMsrpTransactionInfo(txId);\n            if (msrpTransactionInfo != null) {\n                cpimMsgId = msrpTransactionInfo.mCpimMsgId;\n                typeMsrpChunk = msrpTransactionInfo.mTypeMsrpChunk;\n            }\n            mMsrpEventListener\n                    .msrpTransferError(cpimMsgId, \"error response \" + code, typeMsrpChunk);\n\n            // If an error is received it couldn't get any better nor worse; transaction has reached\n            // final state\n            removeMsrpTransactionInfo(txId);\n        }\n\n        // Don't remove transaction info in general from list as this could be a preliminary answer\n    }\n\n    /**\n     * Receive MSRP REPORT request\n     * \n     * @param txId Transaction ID\n     * @param headers MSRP headers\n     * @throws NetworkException\n     * @throws FileAccessException\n     */\n    public void receiveMsrpReport(String txId, Hashtable<String, String> headers)\n            throws FileAccessException, NetworkException {\n        // Example of an MSRP REPORT request:\n        // MSRP b276bb5b0adb22f6 SEND\n        // To-Path: msrp://10.108.25.89:19494/n02s00i2t0+519;tcp\n        // From-Path: msrp://10.102.192.68:20000/1375944013409;tcp\n        // Message-ID: MID-3BCqcBUXKA\n        // Byte-Range: 1-305/305\n        // Content-Type: message/cpim\n        //\n        // From: <sip:anonymous@anonymous.invalid>\n        // To: <sip:anonymous@anonymous.invalid>\n        // NS: imdn <urn:ietf:params:imdn>\n        // imdn.Message-ID: Msg2BCqcBUWKA\n        // DateTime: 2013-08-08T06:40:56.000Z\n        // imdn.Disposition-Notification: positive-delivery, display\n        //\n        // Content-type: text/plain; charset=utf-8\n        // Content-length: 1\n        //\n        // F\n        // -------b276bb5b0adb22f6$\n        //\n        // MSRP b276bb5b0adb22f6 200 OK\n        // To-Path: msrp://10.102.192.68:20000/1375944013409;tcp\n        // From-Path: msrp://10.108.25.89:19494/n02s00i2t0+519;tcp\n        // -------b276bb5b0adb22f6$\n        //\n        // MSRP n02s00i2t0+1937 REPORT\n        // To-Path: msrp://10.102.192.68:20000/1375944013409;tcp\n        // From-Path: msrp://10.108.25.89:19494/n02s00i2t0+519;tcp\n        // Status: 000 413 413\n        // Message-ID: MID-3BCqcBUXKA\n        // Byte-Range: 1-305/305\n        // -------n02s00i2t0+1937$\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"REPORT request received (transaction=\" + txId + \")\");\n        }\n\n        String msrpMsgId = headers.get(MsrpConstants.HEADER_MESSAGE_ID);\n        String cpimMsgId = null;\n\n        String originalTransactionId = null;\n        TypeMsrpChunk typeMsrpChunk = TypeMsrpChunk.Unknown;\n        MsrpTransactionInfo msrpTransactionInfo = getMsrpTransactionInfoByMessageId(msrpMsgId);\n        if (msrpTransactionInfo != null) {\n            typeMsrpChunk = msrpTransactionInfo.mTypeMsrpChunk;\n            originalTransactionId = msrpTransactionInfo.mTransactionId;\n            cpimMsgId = msrpTransactionInfo.mCpimMsgId;\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"REPORT request details; originalTransactionId=\"\n                        + originalTransactionId + \"; cpimMsgId=\" + cpimMsgId + \"; typeMsrpChunk=\"\n                        + typeMsrpChunk);\n            }\n        }\n\n        // Test if a failure report is needed\n        boolean failureReportNeeded = true;\n        String failureHeader = headers.get(MsrpConstants.HEADER_FAILURE_REPORT);\n        if ((failureHeader != null) && failureHeader.equalsIgnoreCase(\"no\")) {\n            failureReportNeeded = false;\n        }\n\n        // Send MSRP response if requested\n        if (failureReportNeeded) {\n            sendMsrpResponse(MsrpConstants.STATUS_200_OK, txId, headers);\n        }\n\n        // Check status code\n        int statusCode = ReportTransaction.parseStatusCode(headers);\n        if (statusCode != 200) {\n            mMsrpEventListener.msrpTransferError(cpimMsgId, \"error report \" + statusCode,\n                    typeMsrpChunk);\n        }\n\n        // Notify report transaction\n        if (mReportTransaction != null) {\n            mReportTransaction.notifyReport(statusCode, headers);\n        }\n\n        // Remove transaction info from list as transaction has reached a final state\n        removeMsrpTransactionInfo(originalTransactionId);\n    }\n\n    /**\n     * Set the control if is to map the msgId from transactionId if not present on received MSRP\n     * messages\n     * \n     * @param mapMsgIdFromTransationId boolean\n     */\n    public void setMapMsgIdFromTransationId(boolean mapMsgIdFromTransationId) {\n        if (mMapMsgIdFromTransationId != mapMsgIdFromTransationId) {\n            synchronized (mTransactionMsgIdMapLock) {\n                if (mapMsgIdFromTransationId) {\n                    mTransactionInfoMap = new ConcurrentHashMap<>();\n                    mMessageTransactionMap = new ConcurrentHashMap<>();\n                } else {\n                    if (mTransactionInfoMap != null) {\n                        mTransactionInfoMap.clear();\n                        mTransactionInfoMap = null;\n                    }\n                    if (mMessageTransactionMap != null) {\n                        mMessageTransactionMap.clear();\n                        mMessageTransactionMap = null;\n                    }\n                }\n            }\n            mMapMsgIdFromTransationId = mapMsgIdFromTransationId;\n        }\n    }\n\n    /**\n     * Add transaction info item to list\n     * \n     * @param transactionId MSRP transaction\n     * @param msrpMsgId MSRP message ID\n     * @param cpimMsgId CPIM message ID\n     * @param typeMsrpChunk MSRP chunk type (see {@link TypeMsrpChunk})\n     */\n    private void addMsrpTransactionInfo(String transactionId, String msrpMsgId, String cpimMsgId,\n            TypeMsrpChunk typeMsrpChunk) {\n        if (mTransactionInfoMap != null && transactionId != null) {\n            synchronized (mTransactionMsgIdMapLock) {\n                mTransactionInfoMap.put(transactionId, new MsrpTransactionInfo(transactionId,\n                        msrpMsgId, cpimMsgId, typeMsrpChunk));\n                if (mMessageTransactionMap != null && msrpMsgId != null) {\n                    mMessageTransactionMap.put(msrpMsgId, transactionId);\n                }\n            }\n        }\n    }\n\n    /**\n     * Remove transaction info item from list\n     * \n     * @param transactionId The transaction ID\n     */\n    public void removeMsrpTransactionInfo(String transactionId) {\n        if (mTransactionInfoMap != null && transactionId != null) {\n            synchronized (mTransactionMsgIdMapLock) {\n                if (mMessageTransactionMap != null) {\n                    MsrpTransactionInfo transactionInfo = getMsrpTransactionInfo(transactionId);\n                    if (transactionInfo != null && transactionInfo.mMsrpMsgId != null) {\n                        mMessageTransactionMap.remove(transactionInfo.mMsrpMsgId);\n                    }\n                }\n                mTransactionInfoMap.remove(transactionId);\n            }\n        }\n    }\n\n    /**\n     * Get the transactions info\n     */\n    private MsrpTransactionInfo getMsrpTransactionInfo(String transactionId) {\n        if (mTransactionInfoMap != null && transactionId != null) {\n            synchronized (mTransactionMsgIdMapLock) {\n                return mTransactionInfoMap.get(transactionId);\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Get the transactions info for a specific MSRP message ID\n     * \n     * @param msrpMsgId MSRP message ID\n     */\n    private MsrpTransactionInfo getMsrpTransactionInfoByMessageId(String msrpMsgId) {\n        if (mMessageTransactionMap != null && mTransactionInfoMap != null && msrpMsgId != null) {\n            synchronized (mTransactionMsgIdMapLock) {\n                String transactionId = mMessageTransactionMap.get(msrpMsgId);\n                if (transactionId != null) {\n                    return mTransactionInfoMap.get(transactionId);\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Check the transactions info that have expired\n     */\n    public void checkMsrpTransactionInfo() {\n        if (mTransactionInfoMap != null) {\n            List<MsrpTransactionInfo> msrpTransactionInfos;\n            synchronized (mTransactionMsgIdMapLock) {\n                // Copy the transaction info items to accelerate the locking while doing\n                // expiring process\n                msrpTransactionInfos = new ArrayList<>(mTransactionInfoMap.values());\n            }\n            for (MsrpTransactionInfo msrpTransactionInfo : msrpTransactionInfos) {\n                long delta = System.currentTimeMillis() - msrpTransactionInfo.mTimestamp;\n                if ((delta >= TRANSACTION_INFO_EXPIRY_PERIOD) || (delta < 0)) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Transaction info have expired (transactionId: \"\n                                + msrpTransactionInfo.mTransactionId + \", msgId: \"\n                                + msrpTransactionInfo.mMsrpMsgId + \")\");\n                    }\n                    mTransactionInfoMap.remove(msrpTransactionInfo.mTransactionId);\n                    if (mMessageTransactionMap != null) {\n                        mMessageTransactionMap.remove(msrpTransactionInfo.mMsrpMsgId);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Is established\n     * \n     * @return true If the empty packet was sent successfully\n     */\n    public boolean isEstablished() {\n        return mIsEstablished && !mCancelTransfer;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpTransaction.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport java.util.Timer;\nimport java.util.TimerTask;\n\n/**\n * MSRP transaction\n * \n * @author B. JOGUET\n */\npublic class MsrpTransaction extends Object {\n    /**\n     * MRSP report transaction timeout (in milliseconds)\n     */\n    private final static long TIMEOUT = 30000;\n\n    /**\n     * Count number of sent requests without response\n     */\n    private int waitingCount = 0;\n\n    /**\n     * Count the total number of received 200OK\n     */\n    private int totalReceivedResponses = 0;\n\n    /**\n     * Count number of sent requests without response\n     */\n    private boolean isWaiting = false;\n\n    /**\n     * Is MSRP session terminated\n     */\n    private boolean isTerminated = false;\n\n    /**\n     * Timer\n     */\n    private Timer timer = new Timer();\n\n    /**\n     * Constructor\n     */\n    public MsrpTransaction() {\n    }\n\n    /**\n     * Wait all MSRP responses\n     */\n    public synchronized void waitAllResponses() {\n        if (waitingCount > 0) {\n            isWaiting = true;\n            try {\n                // Start timeout\n                startTimer();\n\n                // Wait semaphore\n                super.wait();\n            } catch (InterruptedException e) {\n                /* Nothing to do */\n            }\n        }\n    }\n\n    /**\n     * Handle new request\n     */\n    public void handleRequest() {\n        // Changed by Deutsche Telekom\n        // requests and responses are handled in different threads which need to be synchronized\n        synchronized (this) {\n            waitingCount++;\n        }\n    }\n\n    /**\n     * Handle new response\n     */\n    public synchronized void handleResponse() {\n        // Changed by Deutsche Telekom\n        // requests and responses are handled in different threads which need to be synchronized\n        synchronized (this) {\n            waitingCount--;\n        }\n        // Changed by Deutsche Telekom\n        totalReceivedResponses++;\n        if (isWaiting) {\n            if (waitingCount == 0) {\n                // Unblock semaphore\n                super.notify();\n            } else {\n                // ReInit timeout\n                stopTimer();\n                startTimer();\n            }\n        }\n    }\n\n    /**\n     * Is all responses received\n     * \n     * @return Boolean\n     */\n    public boolean isAllResponsesReceived() {\n        return (waitingCount == 0);\n    }\n\n    /**\n     * Terminate transaction\n     */\n    public synchronized void terminate() {\n        isTerminated = true;\n        // Unblock semaphore\n        super.notify();\n        // Stop timer\n        stopTimer();\n    }\n\n    /**\n     * Return isTerminated status.\n     * \n     * @return true if terminated\n     */\n    public boolean isTerminated() {\n        return isTerminated;\n    }\n\n    /**\n     * Start the timer\n     */\n    private void startTimer() {\n        timer = new Timer();\n        TimerTask timertask = new TimerTask() {\n            @Override\n            public void run() {\n                timerExpire();\n            }\n        };\n        timer.schedule(timertask, TIMEOUT);\n    }\n\n    /**\n     * Stop the timer\n     */\n    private void stopTimer() {\n        timer.cancel();\n    }\n\n    /**\n     * Timer execution\n     */\n    private synchronized void timerExpire() {\n        // Unblock semaphore\n        super.notify();\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * @return totalReceivedResponses - number of received reports\n     */\n    public int getNumberReceivedOk() {\n        return totalReceivedResponses;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/MsrpUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\n/**\n * MSRP utility functions\n * \n * @author jexa7410\n */\npublic class MsrpUtils {\n    /**\n     * Get the chunk size\n     * \n     * @param header MSRP header\n     * @return Size in bytes or 0 for \"*\" range\n     */\n    public static int getChunkSize(String header) {\n        if (header == null) {\n            return -1;\n        }\n        int index1 = header.indexOf(\"-\");\n        int index2 = header.indexOf(\"/\");\n        if ((index1 != -1) && (index2 != -1)) {\n            try {\n                int lowByte = Integer.parseInt(header.substring(0, index1));\n                String highByteString = header.substring(index1 + 1, index2);\n                if (highByteString.equals(\"*\")) {\n                    return 0;\n                }\n                int highByte = Integer.parseInt(highByteString);\n                return (highByte - lowByte) + 1;\n            } catch (NumberFormatException e) {\n                return -1;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * Get the total size\n     * \n     * @param header MSRP header\n     * @return Size in bytes\n     */\n    public static int getTotalSize(String header) {\n        if (header == null) {\n            return -1;\n        }\n        int index = header.indexOf(\"/\");\n        if (index != -1) {\n            try {\n                return Integer.parseInt(header.substring(index + 1));\n            } catch (NumberFormatException e) {\n                return -1;\n            }\n        }\n        return -1;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/ReportTransaction.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport java.util.Hashtable;\n\n/**\n * Report transaction\n * \n * @author jexa7410\n */\npublic class ReportTransaction extends Object {\n    /**\n     * MRSP report transaction timeout (in milliseconds)\n     */\n    private final static long TIMEOUT = 3600000; // TODO: which value ?\n\n    private static final int INVALID_STATUS_RESPONSE = -1;\n\n    /**\n     * Reported size\n     */\n    private long reportedSize = 0L;\n\n    /**\n     * Status code\n     */\n    private int statusCode = -1;\n\n    /**\n     * Indicate if received the Byte-Range header\n     */\n    private boolean receivedByteRangeHeader;\n\n    /**\n     * Indicate if the report was notified\n     */\n    private boolean isNotified = false;\n\n    /**\n     * Constructor\n     */\n    public ReportTransaction() {\n    }\n\n    /**\n     * Notify report\n     * \n     * @param status Status code\n     * @param headers MSRP headers\n     */\n    public void notifyReport(int status, Hashtable<String, String> headers) {\n        synchronized (this) {\n            receivedByteRangeHeader = false;\n            isNotified = true;\n            statusCode = status;\n\n            // Get reported size\n            String byteRange = headers.get(MsrpConstants.HEADER_BYTE_RANGE);\n            if (byteRange != null) {\n                reportedSize = MsrpUtils.getChunkSize(byteRange);\n                receivedByteRangeHeader = true;\n            }\n\n            // Unblock semaphore\n            super.notify();\n        }\n    }\n\n    /**\n     * Wait report\n     */\n    public void waitReport() {\n        synchronized (this) {\n            try {\n                // Wait semaphore\n                super.wait(TIMEOUT);\n            } catch (InterruptedException e) {\n                /* Nothing to do */\n            }\n        }\n    }\n\n    /**\n     * Terminate transaction\n     */\n    public void terminate() {\n        synchronized (this) {\n            // Unblock semaphore\n            super.notify();\n        }\n    }\n\n    /**\n     * Returns the reported data size\n     * \n     * @return Size in bytes\n     */\n    public long getReportedSize() {\n        return reportedSize;\n    }\n\n    /**\n     * Returns the status\n     * \n     * @return Status or -1 in case of error\n     */\n    public int getStatusCode() {\n        return statusCode;\n    }\n\n    /**\n     * Verifies if the transaction is finished.\n     * \n     * @param totalSize Transaction total size.\n     * @return <code>True</code> if transaction is finished, <code>false</code> otherwise.\n     */\n    public boolean isTransactionFinished(long totalSize) {\n        if (isNotified) {\n            if (!receivedByteRangeHeader) {\n                return true;\n            }\n            if (reportedSize == totalSize) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Get the status code\n     * \n     * @param headers\n     * @return\n     */\n    public static int parseStatusCode(Hashtable<String, String> headers) {\n        final String status = headers.get(MsrpConstants.HEADER_STATUS);\n        if (status == null || status.startsWith(\"000 \")) {\n            return INVALID_STATUS_RESPONSE;\n        }\n        String[] parts = status.split(\" \");\n        if (parts.length < 2) {\n            return INVALID_STATUS_RESPONSE;\n        }\n        try {\n            return Integer.parseInt(parts[1]);\n\n        } catch (NumberFormatException e) {\n            return INVALID_STATUS_RESPONSE;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/msrp/RequestTransaction.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.msrp;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport java.util.Hashtable;\n\n/**\n * Request transaction\n * \n * @author jexa7410\n */\npublic class RequestTransaction extends Object {\n    /**\n     * RcsSettings\n     */\n    private RcsSettings mRcsSettings;\n\n    /**\n     * Received response\n     */\n    private int receivedResponse = -1;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings\n     */\n    public RequestTransaction(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Notify response\n     * \n     * @param code Response code\n     * @param headers MSRP headers\n     */\n    public void notifyResponse(int code, Hashtable<String, String> headers) {\n        synchronized (this) {\n            // Set response code\n            this.receivedResponse = code;\n\n            // Unblock semaphore\n            super.notify();\n        }\n    }\n\n    /**\n     * Wait response\n     */\n    public void waitResponse() {\n        synchronized (this) {\n            try {\n                super.wait(mRcsSettings.getMsrpTransactionTimeout());\n            } catch (InterruptedException e) {\n                /* Nothing to do */\n            }\n        }\n    }\n\n    /**\n     * Terminate transaction\n     */\n    public void terminate() {\n        synchronized (this) {\n            // Unblock semaphore\n            super.notify();\n        }\n    }\n\n    /**\n     * Is response received\n     * \n     * @return Boolean\n     */\n    public boolean isResponseReceived() {\n        return (receivedResponse != -1);\n    }\n\n    /**\n     * Returns received response\n     * \n     * @return Code\n     */\n    public int getResponse() {\n        return receivedResponse;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/CodecChain.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.ProcessorOutputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Codec chain\n * \n * @author jexa7410\n */\npublic class CodecChain {\n    /**\n     * List of codecs\n     */\n    private Codec[] codecs = null;\n\n    /**\n     * List of buffers\n     */\n    private Buffer[] buffers = null;\n\n    /**\n     * Renderer\n     */\n    private ProcessorOutputStream renderer;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param codecs Codecs list\n     */\n    public CodecChain(Codec[] codecs, ProcessorOutputStream renderer) {\n        this.codecs = codecs;\n        this.renderer = renderer;\n\n        // Create the buffer chain\n        buffers = new Buffer[codecs.length + 1];\n        for (int i = 0; i < codecs.length; i++) {\n            buffers[i] = new Buffer();\n        }\n\n        // Prepare codecs\n        for (int i = 0; i < codecs.length; i++) {\n            if (logger.isActivated()) {\n                logger.debug(\"Open codec \" + codecs[i].getClass().getName());\n            }\n            codecs[i].open();\n        }\n    }\n\n    /**\n     * Codec chain processing\n     * \n     * @param input Input buffer\n     * @return Result\n     */\n    public int process(Buffer input) {\n        int codecNo = 0;\n        return doProcess(codecNo, input);\n    }\n\n    /**\n     * Recursive codec processing\n     * \n     * @param codecNo Codec index\n     * @param input Input buffer\n     * @return Result\n     */\n    private int doProcess(int codecNo, Buffer input) {\n        if (codecNo == codecs.length) {\n            /* End of chain */\n            try {\n                /* Write data to the output stream */\n                if (input.isFragmented()) {\n                    /* Write data from sub-buffers to the output stream */\n                    final Buffer[] fragments = input.getFragments();\n                    for (int i = 0; i < input.getFragmentsSize(); i++) {\n                        Buffer fragment = fragments[i];\n                        renderer.write(fragment);\n                        fragment.setData(null);\n                    }\n                    input.setFragments(null);\n                } else {\n                    renderer.write(input);\n                }\n                return Codec.BUFFER_PROCESSED_OK;\n\n            } catch (NetworkException e) {\n                if (logger.isActivated()) {\n                    logger.debug(e.getMessage());\n                }\n                return Codec.BUFFER_PROCESSED_FAILED;\n            }\n        }\n        Codec codec = codecs[codecNo];\n        int returnVal;\n        do {\n            returnVal = codec.process(input, buffers[codecNo]);\n\n            if (Codec.BUFFER_PROCESSED_FAILED == returnVal) {\n                if (logger.isActivated()) {\n                    logger.error(\"Codec processing error \" + returnVal);\n                }\n                return Codec.BUFFER_PROCESSED_FAILED;\n            }\n\n            if ((returnVal & Codec.OUTPUT_BUFFER_NOT_FILLED) == 0) {\n                if (!(buffers[codecNo].isDiscard() || buffers[codecNo].isEOM())) {\n                    doProcess(codecNo + 1, buffers[codecNo]);\n                }\n                buffers[codecNo].setOffset(0);\n                buffers[codecNo].setLength(0);\n                buffers[codecNo].setFlags(0);\n                buffers[codecNo].setFragments(null);\n            }\n        } while ((returnVal & Codec.INPUT_BUFFER_NOT_CONSUMED) != 0);\n\n        return returnVal;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/DummyPacketGenerator.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.DummyPacketSourceStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpOutputStream;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Dummy packet generator for maintaining alive the network address in NAT\n * \n * @author jexa7410\n */\npublic class DummyPacketGenerator {\n    /**\n     * Media processor\n     */\n    private Processor processor = null;\n\n    /**\n     * RTP output stream\n     */\n    private RtpOutputStream outputStream = null;\n\n    /**\n     * DummyPacketSourceStream\n     */\n    private DummyPacketSourceStream inputStream = null;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     */\n    public DummyPacketGenerator() {\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtpStream already existing RTP input stream\n     * @throws NetworkException\n     */\n    public void prepareSession(String remoteAddress, int remotePort, RtpInputStream rtpStream)\n            throws NetworkException {\n        try {\n            // Create the input stream\n            inputStream = new DummyPacketSourceStream();\n            inputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Input stream: \" + inputStream.getClass().getName());\n            }\n\n            // Create the output stream\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, rtpStream);\n            outputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Output stream: \" + outputStream.getClass().getName());\n            }\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, new Codec[0]);\n\n            if (logger.isActivated()) {\n                logger.debug(\"Session has been prepared with success\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Can't prepare resources correctly for remoteAddress : \").append(remoteAddress)\n                    .append(\" with remotePort : \").append(remotePort).append(\"!\").toString(), e);\n        }\n    }\n\n    /**\n     * Start the RTP session\n     */\n    public void startSession() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start the session\");\n        }\n\n        // Start the media processor\n        if (processor != null) {\n            processor.startProcessing();\n        }\n    }\n\n    /**\n     * Stop the RTP session\n     */\n    public void stopSession() {\n        if (logger.isActivated()) {\n            logger.debug(\"Stop the session\");\n        }\n\n        // Stop the media processor\n        if (processor != null) {\n            processor.stopProcessing();\n        }\n\n        if (outputStream != null)\n            outputStream.close();\n    }\n\n    /**\n     * Set incomingStarted.\n     */\n    public void incomingStarted() {\n        inputStream.incomingStarted();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/MediaRegistry.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.audio.AmrWbAudioFormat;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.audio.AudioFormat;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.H264VideoFormat;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoFormat;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\n/**\n * Media registry that handles the supported codecs\n * \n * @author jexa7410\n */\npublic class MediaRegistry {\n\n    /**\n     * Supported codecs\n     */\n    private static Hashtable<String, Format> sSupportedCodexs = new Hashtable<String, Format>();\n    static {\n        sSupportedCodexs.put(H264VideoFormat.ENCODING.toLowerCase(), new H264VideoFormat());\n        sSupportedCodexs.put(AmrWbAudioFormat.ENCODING.toLowerCase(), new AmrWbAudioFormat());\n    }\n\n    /**\n     * Returns the list of the supported video format\n     * \n     * @return List of video formats\n     */\n    public static Vector<VideoFormat> getSupportedVideoFormats() {\n        Vector<VideoFormat> list = new Vector<VideoFormat>();\n        for (Enumeration<Format> e = sSupportedCodexs.elements(); e.hasMoreElements();) {\n            Format fmt = e.nextElement();\n            if (fmt instanceof VideoFormat) {\n                list.addElement((VideoFormat) fmt);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * Returns the list of the supported audio format\n     * \n     * @return List of audio formats\n     */\n    public static Vector<AudioFormat> getSupportedAudioFormats() {\n        Vector<AudioFormat> list = new Vector<AudioFormat>();\n        for (Enumeration<Format> e = sSupportedCodexs.elements(); e.hasMoreElements();) {\n            Format fmt = e.nextElement();\n            if (fmt instanceof AudioFormat) {\n                list.addElement((AudioFormat) fmt);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * Generate the format associated to the codec name\n     * \n     * @param codec Codec name\n     * @return Format\n     */\n    public static Format generateFormat(String codec) {\n        return sSupportedCodexs.get(codec.toLowerCase());\n    }\n\n    /**\n     * Is codec supported\n     * \n     * @param codec Codec name\n     * @return Boolean\n     */\n    public static boolean isCodecSupported(String codec) {\n        Format format = sSupportedCodexs.get(codec.toLowerCase());\n        return (format != null);\n    }\n\n    /**\n     * Generate the codec encoding chain\n     * \n     * @param encoding Encoding name\n     * @return Codec chain\n     */\n    public static Codec[] generateEncodingCodecChain(String encoding) {\n        if (encoding.equalsIgnoreCase(H264VideoFormat.ENCODING)) {\n            // Java H264 packetizer\n            Codec[] chain = {\n                new com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer()\n            };\n            return chain;\n        }\n        // Codec implemented in the native part\n        return new Codec[0];\n    }\n\n    /**\n     * Generate the decoding codec chain\n     * \n     * @param encoding Encoding name\n     * @return Codec chain\n     */\n    public static Codec[] generateDecodingCodecChain(String encoding) {\n        if (encoding.equalsIgnoreCase(H264VideoFormat.ENCODING)) {\n            // Java H264 depacketizer\n            Codec[] chain = {\n                new com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaDepacketizer()\n            };\n            return chain;\n        }\n        // Codec implemented in the native part\n        return new Codec[0];\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/MediaRtpReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.MediaRendererStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Media RTP receiver\n */\npublic class MediaRtpReceiver {\n    /**\n     * Media processor\n     */\n    protected Processor mProcessor;\n\n    /**\n     * Local port number (RTP listening port)\n     */\n    protected int mLocalPort;\n\n    /**\n     * RTP Input Stream\n     */\n    protected RtpInputStream mInputStream;\n\n    /**\n     * The logger\n     */\n    protected static final Logger sLogger = Logger.getLogger(MediaRtpReceiver.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param localPort Local port number\n     */\n    public MediaRtpReceiver(int localPort) {\n        this.mLocalPort = localPort;\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param renderer Renderer\n     * @param format format\n     * @param rtpStreamListener RTP Stream listener\n     * @throws NetworkException\n     */\n    public void prepareSession(String remoteAddress, int remotePort, MediaOutput renderer,\n            Format format, RtpStreamListener rtpStreamListener) throws NetworkException {\n        try {\n            // Create the input stream\n            mInputStream = new RtpInputStream(remoteAddress, remotePort, mLocalPort, format);\n            mInputStream.addRtpStreamListener(rtpStreamListener);\n            mInputStream.open();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Input stream: \" + mInputStream.getClass().getName());\n            }\n\n            // Create the output stream\n            MediaRendererStream outputStream = new MediaRendererStream(renderer);\n            outputStream.open();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Output stream: \" + outputStream.getClass().getName());\n            }\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateDecodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            mProcessor = new Processor(mInputStream, outputStream, codecChain);\n\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Session has been prepared with success\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Can't prepare resources correctly for remoteAddress : \").append(remoteAddress)\n                    .append(\" with remotePort : \").append(remotePort).append(\"!\").toString(), e);\n        }\n    }\n\n    /**\n     * Start the RTP session\n     */\n    public void startSession() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start the session\");\n        }\n\n        // Start the media processor\n        if (mProcessor != null) {\n            mProcessor.startProcessing();\n        }\n    }\n\n    /**\n     * Stop the RTP session\n     */\n    public void stopSession() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Stop the session\");\n        }\n\n        // Stop the media processor\n        if (mProcessor != null) {\n            mProcessor.stopProcessing();\n        }\n    }\n\n    /**\n     * Returns the RTP input stream\n     * \n     * @return RTP input stream\n     */\n    public RtpInputStream getInputStream() {\n        return mInputStream;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/MediaRtpSender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.MediaCaptureStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpOutputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Media RTP sender\n */\npublic class MediaRtpSender {\n    /**\n     * Format\n     */\n    protected Format format;\n\n    /**\n     * Media processor\n     */\n    protected Processor processor = null;\n\n    /**\n     * MediaCaptureStream\n     */\n    protected MediaCaptureStream inputStream = null;\n\n    /**\n     * RTP output stream\n     */\n    protected RtpOutputStream outputStream = null;\n\n    /**\n     * Local RTP port\n     */\n    protected int localPort;\n\n    /**\n     * The logger\n     */\n    protected Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param format Media format\n     */\n    public MediaRtpSender(Format format, int localRtpPort) {\n        this.format = format;\n        this.localPort = localRtpPort;\n    }\n\n    /**\n     * Prepare the RTP session for a sender associated to a receiver\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @throws NetworkException\n     */\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpInputStream rtpStream, RtpStreamListener rtpStreamListener)\n            throws NetworkException {\n        try {\n            if (logger.isActivated()) {\n                logger.debug(\"Prepare session\");\n            }\n\n            // Create the input stream\n            inputStream = new MediaCaptureStream(format, player);\n            inputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Input stream: \" + inputStream.getClass().getName());\n            }\n\n            // Create the output stream\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, rtpStream);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Output stream: \" + outputStream.getClass().getName());\n            }\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            if (logger.isActivated()) {\n                logger.debug(\"New processor\");\n            }\n            processor = new Processor(inputStream, outputStream, codecChain);\n\n            if (logger.isActivated()) {\n                logger.debug(\"Session has been prepared with success\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Can't prepare resources correctly for remoteAddress : \").append(remoteAddress)\n                    .append(\" with remotePort : \").append(remotePort).append(\"!\").toString(), e);\n        }\n    }\n\n    /**\n     * Start the RTP session\n     */\n    public void startSession() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start the session\");\n        }\n\n        // Start the media processor\n        if (processor != null) {\n            processor.startProcessing();\n        }\n    }\n\n    /**\n     * Stop the RTP session\n     */\n    public void stopSession() {\n        if (logger.isActivated()) {\n            logger.debug(\"Stop the session\");\n        }\n\n        // Stop the media processor\n        if (processor != null) {\n            processor.stopProcessing();\n        }\n\n        if (outputStream != null) {\n            outputStream.close();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/Processor.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.ProcessorInputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.ProcessorOutputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Media processor. A processor receives an input stream, use a codec chain to filter the data\n * before to send it to the output stream.\n * \n * @author jexa7410\n */\npublic class Processor extends Thread {\n    /**\n     * Processor input stream\n     */\n    private ProcessorInputStream inputStream;\n\n    /**\n     * Processor output stream\n     */\n    private ProcessorOutputStream outputStream;\n\n    /**\n     * Codec chain\n     */\n    private CodecChain codecChain;\n\n    /**\n     * Processor status flag\n     */\n    private boolean interrupted = false;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(Processor.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputStream Input stream\n     * @param outputStream Output stream\n     * @param codecs List of codecs\n     */\n    public Processor(ProcessorInputStream inputStream, ProcessorOutputStream outputStream,\n            Codec[] codecs) {\n        super();\n\n        this.inputStream = inputStream;\n        this.outputStream = outputStream;\n\n        // Create the codec chain\n        codecChain = new CodecChain(codecs, outputStream);\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Media processor created\");\n        }\n    }\n\n    /**\n     * Start processing\n     */\n    public void startProcessing() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start media processor\");\n        }\n        interrupted = false;\n        start();\n    }\n\n    /**\n     * Stop processing\n     */\n    public void stopProcessing() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop media processor\");\n        }\n        interrupted = true;\n\n        // Close streams\n        outputStream.close();\n        inputStream.close();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Processor processing is started\");\n            }\n\n            // Start processing\n            while (!interrupted) {\n                // Read data from the input stream\n                Buffer inBuffer = inputStream.read();\n                if (inBuffer == null) {\n                    interrupted = true;\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Processing terminated: null data received\");\n                    }\n                    break;\n                }\n\n                // Codec chain processing\n                int result = codecChain.process(inBuffer);\n                if ((result != Codec.BUFFER_PROCESSED_OK)\n                        && (result != Codec.OUTPUT_BUFFER_NOT_FILLED)) {\n                    interrupted = true;\n                    if (sLogger.isActivated()) {\n                        sLogger.error(\"Codec chain processing error: \" + result);\n                    }\n                    break;\n                }\n            }\n        } catch (NetworkException e) {\n            interrupted = true;\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            interrupted = true;\n            sLogger.error(\"Unable to process codec chain!\", e);\n        }\n    }\n\n    /**\n     * Returns the input stream\n     * \n     * @return Stream\n     */\n    public ProcessorInputStream getInputStream() {\n        return inputStream;\n    }\n\n    /**\n     * Returns the output stream\n     * \n     * @return Stream\n     */\n    public ProcessorOutputStream getOutputStream() {\n        return outputStream;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/RtpUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\n/**\n * RTP utils\n * \n * @author hlxn7157\n */\npublic class RtpUtils {\n\n    /**\n     * RTP Extension ID used by the client. The extension ID is a value between 1 and 15 arbitrarily\n     * chosen by the sender, as defined in RFC5285\n     */\n    public static final int RTP_DEFAULT_EXTENSION_ID = 9;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/VideoRtpReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.VideoRendererStream;\n\nimport java.io.IOException;\n\n/**\n * Video RTP receiver\n * \n * @author hlxn7157\n */\npublic class VideoRtpReceiver extends MediaRtpReceiver {\n    /**\n     * Constructor\n     * \n     * @param localPort Local port number\n     */\n    public VideoRtpReceiver(int localPort) {\n        super(localPort);\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param orientationHeaderId RTP orientation extension header id\n     * @param renderer Renderer\n     * @param format Video format\n     * @param rtpStreamListener RTP Stream listener\n     * @throws NetworkException\n     */\n    public void prepareSession(String remoteAddress, int remotePort, int orientationHeaderId,\n            MediaOutput renderer, Format format, RtpStreamListener rtpStreamListener)\n            throws NetworkException {\n        try {\n            // Create the input stream\n            mInputStream = new RtpInputStream(remoteAddress, remotePort, mLocalPort, format);\n            mInputStream.setExtensionHeaderId(orientationHeaderId);\n            mInputStream.addRtpStreamListener(rtpStreamListener);\n            mInputStream.open();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Input stream: \" + mInputStream.getClass().getName());\n            }\n\n            // Create the output stream\n            VideoRendererStream outputStream = new VideoRendererStream(renderer);\n            outputStream.open();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Output stream: \" + outputStream.getClass().getName());\n            }\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateDecodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            mProcessor = new Processor(mInputStream, outputStream, codecChain);\n\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Session has been prepared with success\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Can't prepare resources correctly for remoteAddress : \").append(remoteAddress)\n                    .append(\" with remotePort : \").append(remotePort)\n                    .append(\" orientationHeaderId : \").append(orientationHeaderId).append(\"!\")\n                    .toString(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/VideoRtpSender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpOutputStream;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.VideoCaptureStream;\n\nimport java.io.IOException;\n\n/**\n * Video RTP sender\n * \n * @author hlxn7157\n */\npublic class VideoRtpSender extends MediaRtpSender {\n    /**\n     * Constructor\n     * \n     * @param format Media format\n     */\n    public VideoRtpSender(Format format, int localRtpPort) {\n        super(format, localRtpPort);\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param RtpStreamListener rtp stream listener\n     * @throws NetworkException\n     */\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpStreamListener rtpStreamListener) throws NetworkException {\n        try {\n            // Create the input stream\n            inputStream = new VideoCaptureStream(format, player);\n            inputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Input stream: \" + inputStream.getClass().getName());\n            }\n\n            // Create the output stream\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, localPort,\n                    RtpOutputStream.RTCP_SOCKET_TIMEOUT);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Output stream: \" + outputStream.getClass().getName());\n            }\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n\n            if (logger.isActivated()) {\n                logger.debug(\"Session has been prepared with success\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Can't prepare resources correctly for remoteAddress : \").append(remoteAddress)\n                    .append(\" with remotePort : \").append(remotePort).append(\"!\").toString(), e);\n        }\n    }\n\n    /**\n     * Prepare the RTP session for a sender associated to a receiver\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtpStream rtp input stream\n     * @param RtpStreamListener rtp stream listener\n     * @throws NetworkException\n     */\n\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpInputStream rtpStream, RtpStreamListener rtpStreamListener)\n            throws NetworkException {\n        try {\n            // Create the input stream\n            inputStream = new VideoCaptureStream(format, player);\n            inputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Input stream: \" + inputStream.getClass().getName());\n            }\n\n            // Create the output stream\n            // outputStream = new RtpOutputStream(remoteAddress, remotePort, localRtpPort,\n            // RtpOutputStream.RTCP_SOCKET_TIMEOUT);\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, rtpStream);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n            if (logger.isActivated()) {\n                logger.debug(\"Output stream: \" + outputStream.getClass().getName());\n            }\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n\n            if (logger.isActivated()) {\n                logger.debug(\"Session has been prepared with success\");\n            }\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Can't prepare resources correctly for remoteAddress : \").append(remoteAddress)\n                    .append(\" with remotePort : \").append(remotePort).append(\"!\").toString(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/Codec.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Abstract codec\n * \n * @author jexa7410\n */\npublic abstract class Codec {\n\n    /**\n     * The input buffer was converted successfully to output\n     */\n    public static final int BUFFER_PROCESSED_OK = 0;\n\n    /**\n     * The input buffer could not be handled\n     */\n    public static final int BUFFER_PROCESSED_FAILED = 1 << 0;\n\n    /**\n     * The input buffer chunk was not fully consumed\n     */\n    public static final int INPUT_BUFFER_NOT_CONSUMED = 1 << 1;\n\n    /**\n     * The output buffer chunk was not filled\n     */\n    public static final int OUTPUT_BUFFER_NOT_FILLED = 1 << 2;\n\n    /**\n     * Input format\n     */\n    private Format inputFormat;\n\n    /**\n     * Ouput format\n     */\n    private Format outputFormat;\n\n    /**\n     * Set the input format\n     * \n     * @param input Input format\n     * @return New format\n     */\n    public Format setInputFormat(Format input) {\n        inputFormat = input;\n        return input;\n    }\n\n    /**\n     * Set the output format\n     * \n     * @param output Output format\n     * @return New format\n     */\n    public Format setOutputFormat(Format output) {\n        outputFormat = output;\n        return output;\n    }\n\n    /**\n     * Return the input format\n     * \n     * @return Format\n     */\n    public Format getInputFormat() {\n        return inputFormat;\n    }\n\n    /**\n     * Return the output format\n     * \n     * @return Format\n     */\n    public Format getOutputFormat() {\n        return outputFormat;\n    }\n\n    /**\n     * Reset the codec\n     */\n    public void reset() {\n    }\n\n    /**\n     * Open the codec\n     */\n    public void open() {\n    }\n\n    /**\n     * Close the codec\n     */\n    public void close() {\n    }\n\n    /**\n     * Test if it's the end of media\n     * \n     * @return Boolean\n     */\n    protected boolean isEOM(Buffer inputBuffer) {\n        return inputBuffer.isEOM();\n    }\n\n    /**\n     * Propagate EOM to the ouput buffer\n     * \n     * @param outputBuffer Ouput buffer\n     */\n    protected void propagateEOM(Buffer outputBuffer) {\n        updateOutput(outputBuffer, getOutputFormat(), 0, 0);\n        outputBuffer.setEOM(true);\n    }\n\n    /**\n     * Update the ouput buffer informations\n     * \n     * @param outputBuffer Ouput buffer\n     * @param format Ouput format\n     * @param length Ouput length\n     * @param offset Ouput offset\n     */\n    protected void updateOutput(Buffer outputBuffer, Format format, int length, int offset) {\n        outputBuffer.setFormat(format);\n        outputBuffer.setLength(length);\n        outputBuffer.setOffset(offset);\n    }\n\n    /**\n     * Validate that the Buffer's data size is at least newSize\n     * \n     * @return Array with sufficient capacity\n     */\n    protected byte[] validateByteArraySize(Buffer buffer, int newSize) {\n        byte[] typedArray = (byte[]) buffer.getData();\n        if (typedArray != null) {\n            if (typedArray.length >= newSize) {\n                return typedArray;\n            }\n\n            byte[] tempArray = new byte[newSize];\n            System.arraycopy(typedArray, 0, tempArray, 0, typedArray.length);\n            typedArray = tempArray;\n        } else {\n            typedArray = new byte[newSize];\n        }\n\n        buffer.setData(typedArray);\n        return typedArray;\n    }\n\n    /**\n     * Performs the media processing defined by this codec\n     * \n     * @param input The buffer that contains the media data to be processed\n     * @param output The buffer in which to store the processed media data\n     * @return Processing result\n     */\n    public abstract int process(Buffer input, Buffer output);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/audio/AudioCodec.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.audio;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\n\n/**\n * Audio codec abstract class\n * \n * @author jexa7410\n */\npublic abstract class AudioCodec extends Codec {\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/audio/amr/AMRWBConfig.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.audio.amr;\n\n/**\n * Default AMR WB settings\n * \n * @author opob7414\n */\npublic class AMRWBConfig {\n\n    /**\n     * Codec name\n     */\n    public final static String CODEC_NAME = \"AMR-WB\";\n\n    /**\n     * Default audio sample rate\n     */\n    public final static int SAMPLE_RATE = 16000;\n\n    /**\n     * Default payload number\n     */\n    public final static int PAYLOAD = 126;\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/VideoCodec.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.Codec;\n\n/**\n * Video codec abstract class\n * \n * @author jexa7410\n */\npublic abstract class VideoCodec extends Codec {\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/H264Config.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Default H264 Settings\n * \n * @author hlxn7157\n * @author Deutsche Telekom AG\n */\npublic class H264Config {\n\n    /** Constant values */\n    public static final int QCIF_WIDTH = 176;\n    public static final int QCIF_HEIGHT = 144;\n\n    public static final int CIF_WIDTH = 352;\n    public static final int CIF_HEIGHT = 288;\n\n    public static final int QVGA_WIDTH = 320;\n    public static final int QVGA_HEIGHT = 240;\n\n    public static final int VGA_WIDTH = 640;\n    public static final int VGA_HEIGHT = 480;\n\n    /**\n     * Codec name\n     */\n    public final static String CODEC_NAME = \"H264\";\n\n    /**\n     * Default clock rate\n     */\n    public final static int CLOCK_RATE = 90000;\n\n    /**\n     * H264 OPTIONAL payload format parameter \"profile-level-id\" - RFC 3984\n     */\n    public static final String CODEC_PARAM_PROFILEID = \"profile-level-id\";\n\n    /**\n     * H264 OPTIONAL payload format parameter \"packetization-mode\" - RFC 3984\n     */\n    public static final String CODEC_PARAM_PACKETIZATIONMODE = \"packetization-mode\";\n\n    /**\n     * H264 OPTIONAL payload format parameter \"sprop-parameter-sets\" - RFC 3984\n     */\n    public static final String CODEC_PARAM_SPROP_PARAMETER_SETS = \"sprop-parameter-sets\";\n\n    /**\n     * Default codec params\n     */\n    public final static String CODEC_PARAMS = \"profile-level-id=42900b;packetization-mode=1\";\n\n    /**\n     * Default video width\n     */\n    public final static int VIDEO_WIDTH = QCIF_WIDTH;\n\n    /**\n     * Default video height\n     */\n    public final static int VIDEO_HEIGHT = QCIF_HEIGHT;\n\n    /**\n     * Default video frame rate\n     */\n    public final static int FRAME_RATE = 15;\n\n    /**\n     * Default video bit rate\n     */\n    public final static int BIT_RATE = 64000;\n\n    /**\n     * Get value of profile level ID\n     * \n     * @param codecParams\n     * @return\n     */\n    public static String getCodecProfileLevelId(String codecParams) {\n        return getParameterValue(CODEC_PARAM_PROFILEID, codecParams);\n    }\n\n    /**\n     * Get parameter value from SDP parameters string with parameter-value format 'key1=value1; ...\n     * keyN=valueN'\n     * \n     * @param paramKey parameter name\n     * @param params parameters string\n     * @return if parameter exists return {@link String} with value, otherwise return\n     *         <code>null</code>\n     */\n    private static String getParameterValue(String paramKey, String params) {\n        Pattern p = Pattern.compile(\"(?<=\" + paramKey + \"=).*?(?=;|$)\");\n        Matcher m = p.matcher(params);\n        return m.find() ? m.group(0) : null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/H264RtpHeaders.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264;\n\n/**\n * H264RtpHeaders RFC 3984: Two special headers are added to each H264 packet that immediately\n * follows the RTP header: First Header - The FU indicator octet has the following format:\n * +---------------+ |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |F|NRI| Type | +---------------+ Second\n * Header - The FU header has the following format: +---------------+ |0|1|2|3|4|5|6|7|\n * +-+-+-+-+-+-+-+-+ |S|E|R| Type | +---------------+\n * \n * @author Deutsche Telekom AG\n */\npublic class H264RtpHeaders {\n\n    /**\n     * AVC NAL picture parameter\n     */\n    public static final int AVC_NALTYPE_FUA = 28;\n\n    private final static int FU_INDICATOR_SIZE = 1;\n    private final static int FU_HEADER_SIZE = 1;\n\n    /**\n     * First Header - The FU indicator octet\n     */\n    private boolean FUI_F;\n    private int FUI_NRI;\n    private byte FUI_TYPE;\n\n    /**\n     * Second Header - The FU header\n     */\n    private boolean FUH_S;\n    private boolean FUH_E;\n    private boolean FUH_R;\n    private byte FUH_TYPE;\n\n    private boolean hasFUHeader;\n\n    /**\n     * Constructor\n     * \n     * @param rtpPacketData\n     */\n    public H264RtpHeaders(byte[] rtpPacketData) {\n        // Get FU indicator\n        byte data_FUI = rtpPacketData[0];\n        this.FUI_F = ((data_FUI >> 7) & 0x01) != 0;\n        this.FUI_NRI = ((data_FUI >> 5) & 0x07);\n        this.FUI_TYPE = (byte) (data_FUI & 0x1f);\n        this.hasFUHeader = false;\n\n        if (FUI_TYPE == AVC_NALTYPE_FUA) {\n            // Get FU header\n            byte data_FUH = rtpPacketData[1];\n            this.FUH_S = (data_FUH & 0x80) != 0;\n            this.FUH_E = (data_FUH & 0x40) != 0;\n            this.FUH_R = (data_FUH & 0x20) != 0;\n            this.FUH_TYPE = (byte) (data_FUH & 0x1f);\n            this.hasFUHeader = true;\n        }\n    }\n\n    /**\n     * Is Frame Non Interleaved\n     * \n     * @return Is Frame Non Interleaved\n     */\n    public boolean isFrameNonInterleaved() { // not fragmented\n        return (FUI_TYPE == AVC_NALTYPE_FUA);\n    }\n\n    /**\n     * Header Size\n     * \n     * @return Header Size\n     */\n    public int getHeaderSize() {\n        int headerSize = FU_INDICATOR_SIZE;\n        if (hasFUHeader) {\n            headerSize += FU_HEADER_SIZE;\n        }\n        return headerSize;\n    }\n\n    /**\n     * Get NAL Header\n     * \n     * @return NAL Header\n     */\n    public byte getNALHeader() {\n        // Compose and copy NAL header\n        if (hasFUHeader) {\n            return (byte) (((getFUI_F() ? 1 : 0) << 7) | (FUI_NRI << 5) | (FUH_TYPE & 0x1F));\n        }\n        return (byte) (((getFUI_F() ? 1 : 0) << 7) | (FUI_NRI << 5) | (FUI_TYPE & 0x1F));\n    }\n\n    /**\n     * Verifies if packet is a code slice of a IDR picture\n     * \n     * @param packet packet to verify\n     * @return <code>True</code> if it is, <code>false</code> otherwise\n     */\n    public boolean isIDRSlice() {\n        if (FUI_TYPE == (byte) 0x05) {\n            return true;\n        }\n\n        if (isFrameNonInterleaved() && FUH_TYPE == (byte) 0x05) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Verifies if packet is a code slice of a NON IDR picture\n     * \n     * @param packet packet to verify\n     * @return <code>True</code> if it is, <code>false</code> otherwise\n     */\n    public boolean isNonIDRSlice() {\n        if (FUI_TYPE == (byte) 0x01) {\n            return true;\n        }\n\n        if (isFrameNonInterleaved() && FUH_TYPE == (byte) 0x01) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Get FUI_F\n     * \n     * @return FUI_F\n     */\n    public boolean getFUI_F() {\n        return FUI_F;\n    }\n\n    /**\n     * Get FUI_NRI\n     * \n     * @return FUI_NRI\n     */\n    public int getFUI_NRI() {\n        return FUI_NRI;\n    }\n\n    /**\n     * Get FUI_TYPE\n     * \n     * @return FUI_TYPE\n     */\n    public byte getFUI_TYPE() {\n        return FUI_TYPE;\n    }\n\n    /**\n     * Get FUH_S\n     * \n     * @return FUH_S\n     */\n    public boolean getFUH_S() {\n        return FUH_S;\n    }\n\n    /**\n     * Get FUH_E\n     * \n     * @return FUH_E\n     */\n    public boolean getFUH_E() {\n        return FUH_E;\n    }\n\n    /**\n     * Get FUH_R\n     * \n     * @return FUH_R\n     */\n    public boolean getFUH_R() {\n        return FUH_R;\n    }\n\n    /**\n     * Get FUH_TYPE\n     * \n     * @return FUH_TYPE\n     */\n    public byte getFUH_TYPE() {\n        return FUH_TYPE;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder result = new StringBuilder();\n\n        result.append(\"[FUI_F = \" + getFUI_F() + \" \");\n        result.append(\"FUI_NRI = \" + FUI_NRI + \" \");\n        result.append(\"FUI_TYPE = \" + FUI_TYPE + \" \");\n        result.append(\"hasFUHeader = \" + hasFUHeader + \" \");\n\n        if (hasFUHeader) {\n            result.append(\"[FUH_S = \" + FUH_S + \" \");\n            result.append(\"[FUH_E = \" + FUH_E + \" \");\n            result.append(\"[FUH_R = \" + FUH_R + \" \");\n            result.append(\"[FUH_TYPE = \" + FUH_TYPE + \" \");\n        }\n\n        result.append(\"HeaderSize = \" + getHeaderSize() + \"]\");\n\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/JavaDepacketizer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.VideoCodec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Reassembles H264 RTP packets into H264 frames, as per RFC 3984 Complete frames are sent to\n * decoder once reassembled\n * \n * @author Deutsche Telekom AG\n */\npublic class JavaDepacketizer extends VideoCodec {\n\n    /**\n     * Collection of frameAssemblers. Allows the construction of several frames if incoming packets\n     * are out of order\n     */\n    private FrameAssemblerCollection assemblersCollection = new FrameAssemblerCollection();\n\n    /**\n     * Max frame size to give for next module, as some decoder have frame size limits\n     */\n    private static final int MAX_H264_FRAME_SIZE = 8192;\n\n    /**\n     * Default frame packet size\n     */\n    public static int H264_FRAME_PACKET_SIZE = 1500;\n\n    /**\n     * Video decoder max payloads chunks mask\n     */\n    private static final byte VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK = 0x1F;\n\n    /**\n     * Packet NalUnitHeader\n     */\n    private NalUnitHeader mNalUnitHeader;\n\n    /**\n     * Reading position for aggregation packet\n     */\n    private int aggregationPositon = 1;\n\n    /**\n     * Constructor\n     */\n    public JavaDepacketizer() {\n    }\n\n    /**\n     * Performs the media processing defined by this codec\n     * \n     * @param input The buffer that contains the media data to be processed\n     * @param output The buffer in which to store the processed media data\n     * @return Processing result\n     */\n    public int process(Buffer input, Buffer output) {\n        if (input == null || output == null) {\n            return BUFFER_PROCESSED_FAILED;\n        }\n\n        // Extracts the NAL Unit Header from the Input Buffer\n        extractNalUnitHeader(input);\n\n        if (mNalUnitHeader.isFragmentationUnit()) {\n            return handleFragmentationUnitPacket(input, output);\n        } else if (mNalUnitHeader.isAggregationPacket()) {\n            return handleAggregationPacket(input, output);\n        } else {\n            return handleSingleNalUnitPacket(input, output);\n        }\n\n    }\n\n    /**\n     * Extract the NAL unit header\n     * \n     * @param input\n     */\n    private void extractNalUnitHeader(Buffer input) {\n        if (mNalUnitHeader == null) {\n            mNalUnitHeader = NalUnitHeader.extract((byte[]) input.getData());\n        } else {\n            NalUnitHeader.extract((byte[]) input.getData(), mNalUnitHeader);\n        }\n    }\n\n    /**\n     * Extract the NAL unit header at position\n     * \n     * @param input\n     * @param position\n     */\n    private void extractNalUnitHeader(int position, Buffer input) {\n        if (mNalUnitHeader == null) {\n            mNalUnitHeader = NalUnitHeader.extract(position, (byte[]) input.getData());\n        } else {\n            NalUnitHeader.extract(position, (byte[]) input.getData(), mNalUnitHeader);\n        }\n    }\n\n    /**\n     * Handle single NAL Unit packet\n     * \n     * @return Processing result\n     */\n    private int handleSingleNalUnitPacket(Buffer input, Buffer output) {\n        // Create output buffer\n        byte[] bufferData = (byte[]) input.getData();\n        int bufferDataLength = bufferData.length;\n        byte[] data = new byte[bufferDataLength];\n        System.arraycopy(bufferData, 0, data, 0, bufferDataLength);\n\n        // Set buffer\n        output.setData(data);\n        output.setLength(data.length);\n        output.setOffset(0);\n        output.setTimestamp(input.getTimestamp());\n        output.setSequenceNumber(input.getSequenceNumber());\n        output.setVideoOrientation(input.getVideoOrientation());\n        output.setFormat(input.getFormat());\n        output.setFlags(input.getFlags());\n\n        return BUFFER_PROCESSED_OK;\n    }\n\n    /**\n     * Handle Aggregation NAL Unit packet\n     * \n     * @return Processing result\n     */\n    private int handleAggregationPacket(Buffer input, Buffer output) {\n        // Get data\n        byte[] bufferData = (byte[]) input.getData();\n        if (aggregationPositon + 1 >= bufferData.length) {\n            // No more data in aggregation packet\n            aggregationPositon = 1;\n            output.setDiscard(true);\n            return BUFFER_PROCESSED_OK;\n        }\n\n        // Get NALU size\n        int nalu_size = (((bufferData[aggregationPositon] & 0xff) << 8) | (bufferData[aggregationPositon + 1] & 0xff));\n        aggregationPositon += 2;\n        if (aggregationPositon + nalu_size > bufferData.length) {\n            // Not a correct packet\n            aggregationPositon = 1;\n            return BUFFER_PROCESSED_FAILED;\n        }\n\n        // Get NALU HDR\n        extractNalUnitHeader(aggregationPositon, input);\n        if (mNalUnitHeader.isSingleNalUnitPacket()) {\n            // Create output buffer\n            byte[] data = new byte[nalu_size];\n            System.arraycopy(bufferData, aggregationPositon, data, 0, nalu_size);\n            aggregationPositon += nalu_size;\n\n            // Set buffer\n            output.setData(data);\n            output.setLength(data.length);\n            output.setOffset(0);\n            output.setTimestamp(input.getTimestamp());\n            output.setSequenceNumber(input.getSequenceNumber());\n            output.setVideoOrientation(input.getVideoOrientation());\n            output.setFormat(input.getFormat());\n            output.setFlags(input.getFlags());\n\n            return INPUT_BUFFER_NOT_CONSUMED;\n        }\n        // Not a correct packet\n        aggregationPositon = 1;\n        return BUFFER_PROCESSED_FAILED;\n    }\n\n    /**\n     * Handle Fragmentation NAL Unit packet\n     * \n     * @return Processing result\n     */\n    private int handleFragmentationUnitPacket(Buffer input, Buffer output) {\n        if (!input.isDiscard()) {\n            assemblersCollection.put(input);\n            if (assemblersCollection.getLastActiveAssembler().complete()) {\n                assemblersCollection.getLastActiveAssembler().copyToBuffer(output);\n                assemblersCollection.removeOldestThan(input.getTimestamp());\n                return BUFFER_PROCESSED_OK;\n            }\n            output.setDiscard(true);\n            return OUTPUT_BUFFER_NOT_FILLED;\n        }\n        output.setDiscard(true);\n        return OUTPUT_BUFFER_NOT_FILLED;\n    }\n\n    /**\n     * Used to assemble fragments with the same timestamp into a single frame.\n     */\n    public static class FrameAssembler {\n        private byte[][] reassembledData = null; // Frame sequence chunks\n        private int[] reassembledDataSize = null; // Sequence chunk size\n        private int reassembledDataFullSize = 0; // Frame sequence chunks full size\n        private boolean reassembledDataHasStart = false; // Has start chunk\n        private boolean reassembledDataHasEnd = false; // Has end chunk\n        private int reassembledDataPosSeqStart = Integer.MAX_VALUE; // Pos seq start\n        private int reassembledDataPosSeqEnd = Integer.MIN_VALUE; // Pos seq end\n        private byte reassembledDataNALHeader = 0; // Final frame NAL header\n        private long timestamp = -1;\n        private Format format = null;\n        private long seqNumber = -1;\n        private VideoOrientation videoOrientation;\n\n        /**\n         * Add the buffer (which contains a fragment) to the assembler.\n         * \n         * @param buffer\n         */\n        public void put(Buffer buffer) {\n\n            if (buffer.getLength() <= 2) {\n                // no actual data in buffer, no need to keep. Typically\n                // happens when RTP marker is set.\n                return;\n            }\n\n            byte[] currentRtpPacketData = ((byte[]) buffer.getData());\n            H264RtpHeaders h264RtpHeaders = new H264RtpHeaders(currentRtpPacketData);\n\n            // Forbidden zero bit, must be zero for a valid stream\n            if (h264RtpHeaders.getFUI_F()) {\n                return;\n            }\n\n            if (reassembledData == null) {\n                // First packet\n                timestamp = buffer.getTimestamp();\n                format = buffer.getFormat();\n                seqNumber = buffer.getSequenceNumber();\n\n                // Get NAL header\n                reassembledDataNALHeader = h264RtpHeaders.getNALHeader();\n\n                // Copy packet data to reassembledData\n                reassembledData = new byte[JavaPacketizer.H264_MAX_RTP_PKTS][H264_FRAME_PACKET_SIZE];\n                reassembledDataSize = new int[JavaPacketizer.H264_MAX_RTP_PKTS];\n                reassembledDataHasStart = false;\n                reassembledDataHasEnd = false;\n            }\n\n            // Sequence position on frame\n            int posSeq = (int) (buffer.getSequenceNumber() & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK);\n\n            // Exclude header size\n            int payloadStartPosition = h264RtpHeaders.getHeaderSize();\n            // Exclude header size\n            int payloadLength = buffer.getLength() - h264RtpHeaders.getHeaderSize();\n\n            // Fragmentation Units (FU-A) have NALs separated through several\n            // RTP packets\n            if (h264RtpHeaders.getFUI_TYPE() == H264RtpHeaders.AVC_NALTYPE_FUA) {\n\n                // Fill Has Start Chunk\n                reassembledDataHasStart |= (h264RtpHeaders.getFUH_S());\n                // Fill Has End Chunk\n                reassembledDataHasEnd |= (h264RtpHeaders.getFUH_E());\n\n                // Fill Pos Seq Start\n                reassembledDataPosSeqStart = ((h264RtpHeaders.getFUH_S()) ? posSeq\n                        : reassembledDataPosSeqStart);\n                // Fill Pos Seq End\n                reassembledDataPosSeqEnd = ((h264RtpHeaders.getFUH_E()) ? posSeq\n                        : reassembledDataPosSeqEnd);\n            }\n\n            // Sequence chuck size\n            reassembledDataSize[posSeq] = payloadLength;\n\n            // Sum chucks total sizes\n            reassembledDataFullSize += payloadLength;\n\n            // Copy data\n            System.arraycopy(currentRtpPacketData, payloadStartPosition, reassembledData[posSeq],\n                    0, payloadLength);\n            videoOrientation = buffer.getVideoOrientation();\n        }\n\n        /**\n         * Is the frame complete?\n         */\n        public boolean complete() {\n\n            if (!reassembledDataHasStart || !reassembledDataHasEnd) {\n                return false; // has start and end chunk\n            }\n\n            // Validate chunk sizes between start and end pos\n            int posCurrent = reassembledDataPosSeqStart;\n            while ((posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK) != reassembledDataPosSeqEnd) {\n                // need more data?\n                if (reassembledDataSize[posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK] <= 0) {\n                    return false;\n                }\n                posCurrent++;\n            }\n            // Validate last chunk\n            if (reassembledDataSize[reassembledDataPosSeqEnd] <= 0) {\n                return false;\n            }\n\n            // TODO: if some of the last ones come in after the marker, there\n            // will be blank squares in the lower right.\n            return true;\n        }\n\n        /**\n         * Assumes that complete() has been called and returns true.\n         */\n        private void copyToBuffer(Buffer bDest) {\n\n            if (reassembledDataFullSize <= MAX_H264_FRAME_SIZE) {\n                // + 1 because of the header size\n                byte[] finalData = new byte[reassembledDataFullSize + 1];\n                int finalDataPos = 0;\n\n                // Copy NAL header\n                finalData[finalDataPos] = reassembledDataNALHeader;\n                finalDataPos += 1;\n\n                // Copy chunk data between start and end pos\n                int posCurrent = reassembledDataPosSeqStart;\n                int posSeq = 0;\n                while ((posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK) != reassembledDataPosSeqEnd) {\n                    // need more data?\n                    posSeq = posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK;\n\n                    // Copy data\n                    System.arraycopy(reassembledData[posSeq], 0, finalData, finalDataPos,\n                            reassembledDataSize[posSeq]);\n                    finalDataPos += reassembledDataSize[posSeq];\n\n                    posCurrent++;\n                }\n\n                // Copy last chunk data\n                System.arraycopy(reassembledData[reassembledDataPosSeqEnd], 0, finalData,\n                        finalDataPos, reassembledDataSize[reassembledDataPosSeqEnd]);\n\n                // If the frame data can be processed by native module, ie\n                // reassembled frame size not too big\n                // Set buffer\n                bDest.setData(finalData);\n                bDest.setLength(reassembledDataSize[reassembledDataPosSeqEnd]);\n                bDest.setOffset(0);\n                bDest.setTimestamp(timestamp);\n                bDest.setFormat(format);\n                bDest.setFlags(Buffer.FLAG_RTP_MARKER | Buffer.FLAG_RTP_TIME);\n                bDest.setVideoOrientation(videoOrientation);\n                bDest.setSequenceNumber(seqNumber);\n            }\n\n            // Set reassembledData to null\n            reassembledData = null;\n        }\n\n        /**\n         * Reset the FrameAssembler It as package access instead of private for improved\n         * performance. See: http://developer.android.com/guide/practices/performance.html Consider\n         * Package Instead of Private Access with Private Inner Classes\n         */\n        private void reset() {\n            reassembledData = null;\n            reassembledDataSize = null;\n            reassembledDataFullSize = 0;\n            reassembledDataHasStart = false;\n            reassembledDataHasEnd = false;\n            reassembledDataPosSeqStart = Integer.MAX_VALUE;\n            reassembledDataPosSeqEnd = Integer.MIN_VALUE;\n            reassembledDataNALHeader = 0;\n            timestamp = -1;\n            format = null;\n        }\n\n        /**\n         * Get timestamp\n         * \n         * @return timestamp\n         */\n        public long getTimestamp() {\n            return timestamp;\n        }\n    }\n\n    /**\n     * Used to manage different timestamps, as packets could be coming not in order. Data is an\n     * array of FrameAssemblers, sorted by timestamps (oldest is first, newest is last)\n     */\n    public static class FrameAssemblerCollection {\n        private final static int NUMBER_OF_ASSEMBLERS = 5;\n        private FrameAssembler[] assemblers = new FrameAssembler[NUMBER_OF_ASSEMBLERS];\n        private int activeAssembler = 0;\n        private int numberOfAssemblers = 0;\n\n        /**\n         * Add the buffer (which contains a fragment) to the right assembler.\n         * \n         * @param buffer\n         */\n        public void put(Buffer buffer) {\n            activeAssembler = getAssembler(buffer.getTimestamp());\n            assemblers[activeAssembler].put(buffer);\n        }\n\n        /**\n         * Get the active frame assembler\n         * \n         * @return frameAssembler Last active assembler\n         */\n        public FrameAssembler getLastActiveAssembler() {\n            return assemblers[activeAssembler];\n        }\n\n        /**\n         * Create a new frame assembler for given timestamp\n         * \n         * @param timestamp\n         * @return assembler number Position of the assembler in the collection\n         */\n        public int createNewAssembler(long timestamp) {\n            int spot = -1;\n            if (numberOfAssemblers < NUMBER_OF_ASSEMBLERS) {\n                // If there's enough space left to create a new assembler\n                // We search its spot\n                for (int i = 0; i < numberOfAssemblers; i++) {\n                    if (timestamp < assemblers[i].getTimestamp()) {\n                        spot = i;\n                    }\n                }\n                if (spot == -1) {\n                    spot = numberOfAssemblers;\n                }\n                numberOfAssemblers++;\n\n                // Store the assembler that will be \"discarded\" and can be reused\n                FrameAssembler oldAssembler = assemblers[numberOfAssemblers - 1];\n\n                // Decale all assemblers with newest timestamp to the right\n                for (int i = numberOfAssemblers - 1; i > spot; i--) {\n                    assemblers[i] = assemblers[i - 1];\n                }\n                if (oldAssembler != null) {\n                    // Reuse and reset the discarded assembler\n                    assemblers[spot] = oldAssembler;\n                    assemblers[spot].reset();\n                } else {\n                    assemblers[spot] = new FrameAssembler();\n                }\n            } else {\n                // Store the assembler that will be \"discarded\" and can be reused\n                FrameAssembler oldAssembler = assemblers[0];\n\n                // Not enough space, we destroy the oldest assembler\n                for (int i = 1; i < NUMBER_OF_ASSEMBLERS; i++) {\n                    assemblers[i - 1] = assemblers[i];\n                }\n                // Last spot is for the new assembler\n                spot = NUMBER_OF_ASSEMBLERS - 1;\n                if (oldAssembler != null) {\n                    // Reuse and reset the discarded assembler\n                    assemblers[spot] = oldAssembler;\n                    assemblers[spot].reset();\n                } else {\n                    assemblers[spot] = new FrameAssembler();\n                }\n            }\n            return spot;\n        }\n\n        /**\n         * Get the assembler used for given timestamp\n         * \n         * @param timestamp\n         * @return FrameAssembler associated to timestamp\n         */\n        public int getAssembler(long timestamp) {\n            int assemblerNumber = -1;\n            for (int i = 0; i < numberOfAssemblers; i++) {\n                if (assemblers[i].getTimestamp() == timestamp) {\n                    assemblerNumber = i;\n                }\n            }\n            if (assemblerNumber == -1) {\n                // Given timestamp never used, we create a new assembler\n                assemblerNumber = createNewAssembler(timestamp);\n            }\n            return assemblerNumber;\n        }\n\n        /**\n         * Remove oldest FrameAssembler than given timestamp (if given timestamp has been rendered,\n         * then oldest ones are no more of no use) This also removes given timestamp\n         * \n         * @param timestamp\n         */\n        public void removeOldestThan(long timestamp) {\n            // Find spot from which to remove\n            int spot = numberOfAssemblers - 1;\n            for (int i = 0; i < numberOfAssemblers; i++) {\n                if (timestamp <= assemblers[i].getTimestamp()) {\n                    spot = i;\n                }\n            }\n            // remove all assemblers with oldest timestamp to the left\n            for (int i = numberOfAssemblers - 1; i > spot; i--) {\n                assemblers[i - 1] = assemblers[i];\n            }\n            numberOfAssemblers -= spot + 1;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/JavaPacketizer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.VideoCodec;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.CameraOptions;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.Orientation;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Reassembles H264 RTP packets into H264 frames, as per RFC 3984\n * \n * @author Deutsche Telekom AG\n */\npublic class JavaPacketizer extends VideoCodec {\n\n    /**\n     * Packetization mode 0 -> Only Single NAL 1 -> Use FU-A if necessary Warning:\n     * packetization-mode 1 normally requires the management of STAP-A. But, this is not yet\n     * implemented in the stack. Then, there can be some IOT issues if you use this mode.\n     */\n    public static final int H264_ENABLED_PACKETIZATION_MODE = 1;\n\n    /**\n     * Max frame size to H264\n     */\n    public static int H264_MAX_PACKET_FRAME_SIZE = 1300; // TODO remove the rtp size...\n\n    /**\n     * Max number of packets to H264\n     */\n    public static final int H264_MAX_RTP_PKTS = 32;\n\n    /**\n     * Buffer size for FU Indicator and Header\n     */\n    public static final int H264_FU_HEADER_SIZE = 2;\n\n    /**\n     * AVC NAL sequence parameter\n     */\n    public static final int AVC_NALTYPE_SPS = 7;\n\n    /**\n     * AVC NAL picture parameter\n     */\n    public static final int AVC_NALTYPE_PPS = 8;\n\n    /**\n     * Full frame auxiliary buffer (No Packetization)\n     */\n    private byte fullFrameData[] = new byte[H264_MAX_PACKET_FRAME_SIZE];\n\n    /**\n     * Full frame temporary packets buffer (With Packetization)\n     */\n    private byte packetsData[][] = new byte[H264_MAX_RTP_PKTS][H264_MAX_PACKET_FRAME_SIZE];\n\n    /**\n     * Full frame final chunks buffer (With Packetization)\n     */\n    private Buffer[] outputs = new Buffer[H264_MAX_RTP_PKTS];\n\n    /**\n     * Buffer for FU Indicator and Header\n     */\n    private byte[] h264FU = new byte[H264_FU_HEADER_SIZE];\n\n    /**\n     * Previous sent orientation\n     */\n    private VideoOrientation previousOrientation = new VideoOrientation(CameraOptions.BACK,\n            Orientation.NONE);\n\n    /**\n     * Because packets can come out of order, it is possible that some packets for a newer frame may\n     * arrive while an older frame is still incomplete. However, in the case where we get nothing\n     * but incomplete frames, we don't want to keep all of them around forever.\n     */\n    public JavaPacketizer() {\n    }\n\n    public int process(Buffer input, Buffer output) {\n\n        if (input == null || output == null) {\n            return BUFFER_PROCESSED_FAILED;\n        }\n\n        if (!input.isDiscard()) {\n            byte[] bufferData = (byte[]) input.getData();\n            int bufferDataLength = input.getLength();\n            if (input.getLength() < H264_MAX_PACKET_FRAME_SIZE\n                    || H264_ENABLED_PACKETIZATION_MODE == 0) {\n                if ((fullFrameData == null) || (fullFrameData.length < bufferDataLength)) {\n                    fullFrameData = new byte[bufferDataLength];\n                }\n                System.arraycopy(bufferData, 0, fullFrameData, 0, bufferDataLength);\n                if (fullFrameData.length > 0) {\n                    // Copy to buffer\n                    output.setFormat(input.getFormat());\n                    output.setData(fullFrameData);\n                    output.setLength(bufferDataLength);\n                    output.setOffset(0);\n                    output.setTimestamp(input.getTimestamp());\n                    output.setFlags(Buffer.FLAG_RTP_MARKER | Buffer.FLAG_RTP_TIME);\n                    output.setVideoOrientation(null);\n                    if (isToAddOrientationHeader(bufferData, input.getVideoOrientation())) {\n                        output.setVideoOrientation(input.getVideoOrientation());\n                        previousOrientation = input.getVideoOrientation();\n                    }\n\n                }\n                return BUFFER_PROCESSED_OK;\n            }\n\n            output.setFragments(outputs);\n            output.setFragmentsSize(0);\n\n            /*\n             * First Header - The FU indicator octet has the following format: +---------------+\n             * |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |F|NRI| Type | +---------------+\n             */\n\n            // FU Indicator pos = 0\n            h264FU[0] = 0;\n            h264FU[0] |= (bufferData[0] & 0xe0);// F | NRI\n            h264FU[0] |= H264RtpHeaders.AVC_NALTYPE_FUA;\n\n            /*\n             * Second Header - The FU header has the following format: +---------------+\n             * |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |S|E|R| Type | +---------------+\n             */\n\n            // FU Header pos = 1\n            h264FU[1] = 0;\n            h264FU[1] |= 0x80;// for the first pkt, the start bit is on\n            // copy the original nal type from the stream\n            h264FU[1] |= (bufferData[0] & 0x1f);\n\n            // Split frame into pkts\n            // for FU-A, we need to consume the first byte with the NAL header\n            int startPosBufferData = 1;\n            int available = bufferDataLength - 1;// see comment above\n            // define max size (not counting with the fuIndicator and fuHeader)\n            int maxSize = H264_MAX_PACKET_FRAME_SIZE - h264FU.length;\n            int numberOfRtpPkts = 0;\n            while (available > maxSize) {\n\n                // >>>>>>>>>>>> create packet >>>>>>>>>>>>\n                // Write h264 payload\n                System.arraycopy(h264FU, 0, packetsData[numberOfRtpPkts], 0, h264FU.length);\n\n                // Write frame data\n                System.arraycopy(bufferData, startPosBufferData, packetsData[numberOfRtpPkts],\n                        h264FU.length, maxSize);\n\n                // Copy to buffer\n                Buffer buffer = outputs[numberOfRtpPkts];\n                if (buffer == null) {\n                    buffer = new Buffer();\n                }\n                buffer.setFormat(input.getFormat());\n                buffer.setData(packetsData[numberOfRtpPkts]);\n                buffer.setLength(H264_MAX_PACKET_FRAME_SIZE); // Max packet frame size\n                buffer.setOffset(0);\n                buffer.setTimestamp(input.getTimestamp());\n                buffer.setFlags(Buffer.FLAG_RTP_TIME);\n                buffer.setVideoOrientation(null);\n\n                // Add data buffer to outputs\n                outputs[numberOfRtpPkts] = buffer;\n\n                // Increment number of rtp pkts\n                numberOfRtpPkts++;\n                // <<<<<<<<<<<< create packet <<<<<<<<<<<<\n\n                // -1 to leave room for the last pkt\n                if (numberOfRtpPkts >= H264_MAX_RTP_PKTS - 1) {\n                    output.setFragments(null);\n                    output.setFragmentsSize(0);\n                    output.setData(null);\n                    output.setDiscard(true);\n                    output.setVideoOrientation(null);\n                    return OUTPUT_BUFFER_NOT_FILLED;\n                    // this frame is too big and needs to be split into more\n                    // pkts than we can buffer\n                }\n\n                // reset the start bit\n                // FU Header pos = 1\n                // we need to switch the start bit off\n                h264FU[1] &= 0x3f; // 0x7f\n\n                // update variables\n                startPosBufferData += maxSize;\n                available -= maxSize;\n            }\n\n            // write the last chunk of the FU-A\n\n            // set the end bit\n            // FU Header pos = 1\n            h264FU[1] |= 0x40;// we need to switch the end bit on\n\n            // >>>>>>>>>>>> create packet >>>>>>>>>>>>\n            // write h264 payload\n            System.arraycopy(h264FU, 0, packetsData[numberOfRtpPkts], 0, h264FU.length);\n\n            // write frame data\n            System.arraycopy(bufferData, startPosBufferData, packetsData[numberOfRtpPkts],\n                    h264FU.length, available);\n\n            // copy to buffer\n            Buffer buffer = outputs[numberOfRtpPkts];\n            if (buffer == null) {\n                buffer = new Buffer();\n            }\n            buffer.setFormat(input.getFormat());\n            buffer.setData(packetsData[numberOfRtpPkts]);\n            buffer.setLength(h264FU.length + available); // H264FU header length + remaining frame\n                                                         // chunk size\n            buffer.setOffset(0);\n            buffer.setTimestamp(input.getTimestamp());\n            buffer.setFlags(Buffer.FLAG_RTP_MARKER | Buffer.FLAG_RTP_TIME);\n            buffer.setVideoOrientation(null);\n            if (isToAddOrientationHeader(packetsData[numberOfRtpPkts], input.getVideoOrientation())) {\n                buffer.setVideoOrientation(input.getVideoOrientation());\n                previousOrientation = input.getVideoOrientation();\n            }\n\n            // add data buffer to outputs\n            outputs[numberOfRtpPkts] = buffer;\n\n            // increment number of rtp pkts\n            numberOfRtpPkts++;\n\n            // Set outputs size\n            output.setFragmentsSize(numberOfRtpPkts);\n            // <<<<<<<<<<<< create packet <<<<<<<<<<<<\n\n            return BUFFER_PROCESSED_OK;\n        }\n        output.setDiscard(true);\n        return OUTPUT_BUFFER_NOT_FILLED;\n    }\n\n    /**\n     * Verifies if we need to send the orientation header. The orientation header should be sent if\n     * it's the end packet of an I-Frame or if its the end packet of B/P Frames and the orientation\n     * has changed.\n     * \n     * @param h264Frame H264 Frame\n     * @param frameOrientation Frame orientation\n     * @return <code>True</code> if it's to add, <code>false</code> otherwise.\n     */\n    private boolean isToAddOrientationHeader(byte[] h264Frame, VideoOrientation frameOrientation) {\n        H264RtpHeaders h264Header = new H264RtpHeaders(h264Frame);\n        if (h264Header.isIDRSlice()) {\n            return true;\n        }\n\n        if ((frameOrientation != null && previousOrientation != null && previousOrientation\n                .getOrientation() != frameOrientation.getOrientation())\n                && h264Header.isNonIDRSlice()) {\n            return true;\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/NalUnitHeader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264;\n\n/**\n * RFC 6184 RTP Payload Format for H.264 Video The first byte of the H264 payload represents the NAL\n * Unit which has the following format: +---------------+ |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+\n * |F|NRI| Type | +---------------+ F: 1 bit forbidden_zero_bit. The H.264 specification declares a\n * value of 1 as a syntax violation. NRI: 2 bits nal_ref_idc. A value of 00 indicates that the\n * content of the NAL unit is not used to reconstruct reference pictures for inter picture\n * prediction. Such NAL units can be discarded without risking the integrity of the reference\n * pictures. Values greater than 00 indicate that the decoding of the NAL unit is required to\n * maintain the integrity of the reference pictures. Type: 5 bits nal_unit_type. This component\n * specifies the NAL unit payload type\n * \n * @author Deutsche Telekom\n */\npublic class NalUnitHeader {\n\n    /**\n     * Forbidden zero bit\n     */\n    private boolean forbiddenZeroBit;\n\n    /**\n     * NAL Reference id\n     */\n    private int nalRefId;\n\n    /**\n     * NAL Unit Type\n     */\n    private NalUnitType decodeNalUnitType;\n\n    /**\n     * Class constructor\n     * \n     * @param forbiddenZeroBit Forbidden zero bit\n     * @param nalRefId NAL Reference id\n     * @param nalUnitType NAL Unit Type value\n     */\n    private NalUnitHeader(boolean forbiddenZeroBit, int nalRefId, int nalUnitType) {\n        this.forbiddenZeroBit = forbiddenZeroBit;\n        this.nalRefId = nalRefId;\n        this.decodeNalUnitType = NalUnitType.parse(nalUnitType);\n    }\n\n    /**\n     * Checks if the Forbidden Zero Bit is set.\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isForbiddenBitSet() {\n        return forbiddenZeroBit;\n    }\n\n    /**\n     * Gets the NAL Reference ID\n     * \n     * @return NAL Reference ID\n     */\n    public int getNalRefId() {\n        return nalRefId;\n    }\n\n    /**\n     * Gets the NAL Unit Type\n     * \n     * @return\n     */\n    public NalUnitType getNalUnitType() {\n        return decodeNalUnitType;\n    }\n\n    /**\n     * Verifies if the H264 packet is Single NAL Unit\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isSingleNalUnitPacket() {\n        return decodeNalUnitType == NalUnitType.CODE_SLICE_IDR_PICTURE\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_NON_IDR_PICTURE\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_DATA_PARTITION_A\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_DATA_PARTITION_B\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_DATA_PARTITION_C\n                || decodeNalUnitType == NalUnitType.SEQUENCE_PARAMETER_SET\n                || decodeNalUnitType == NalUnitType.PICTURE_PARAMETER_SET\n                || decodeNalUnitType == NalUnitType.OTHER_NAL_UNIT;\n    }\n\n    /**\n     * Verifies if the H264 packet is an Aggregation Packet\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isAggregationPacket() {\n        return decodeNalUnitType == NalUnitType.STAP_A || decodeNalUnitType == NalUnitType.STAP_B\n                || decodeNalUnitType == NalUnitType.MTAP16\n                || decodeNalUnitType == NalUnitType.MTAP24;\n    }\n\n    /**\n     * Verifies if the H264 packet is a Fragmentation Unit Packet\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isFragmentationUnit() {\n        return decodeNalUnitType == NalUnitType.FU_A || decodeNalUnitType == NalUnitType.FU_B;\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet\n     * \n     * @param h264Packet H264 Packet\n     * @return {@link NalUnitHeader} Extracted NAL Unit Header\n     * @throws {@link RuntimeException} If the H264 packet data is null\n     */\n    public static NalUnitHeader extract(byte[] h264Packet) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        NalUnitHeader header = new NalUnitHeader(false, 0, 0);\n        extract(h264Packet, header);\n\n        return header;\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet. Puts the extracted info in the given header\n     * object\n     * \n     * @param h264Packet H264 packet\n     * @param header Header object to fill with data\n     * @throws {@link RuntimeException} If the H264 packet data is null or the header is null;\n     */\n    public static void extract(byte[] h264Packet, NalUnitHeader header) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        if (header == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid header packet\");\n        }\n\n        byte headerByte = h264Packet[0];\n\n        header.forbiddenZeroBit = ((headerByte & 0x80) >> 7) != 0;\n        header.nalRefId = ((headerByte & 0x60) >> 5);\n        int nalUnitType = (headerByte & 0x1f);\n        header.decodeNalUnitType = NalUnitType.parse(nalUnitType);\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet\n     * \n     * @param h264Packet H264 Packet\n     * @return {@link NalUnitHeader} Extracted NAL Unit Header\n     * @throws {@link RuntimeException} If the H264 packet data is null\n     */\n    public static NalUnitHeader extract(int position, byte[] h264Packet) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        NalUnitHeader header = new NalUnitHeader(false, 0, 0);\n        extract(position, h264Packet, header);\n\n        return header;\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet. Puts the extracted info in the given header\n     * object\n     * \n     * @param h264Packet H264 packet\n     * @param header Header object to fill with data\n     * @throws {@link RuntimeException} If the H264 packet data is null or the header is null;\n     */\n    public static void extract(int position, byte[] h264Packet, NalUnitHeader header) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        if (header == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid header packet\");\n        }\n\n        byte headerByte = h264Packet[position];\n\n        header.forbiddenZeroBit = ((headerByte & 0x80) >> 7) != 0;\n        header.nalRefId = ((headerByte & 0x60) >> 5);\n        int nalUnitType = (headerByte & 0x1f);\n        header.decodeNalUnitType = NalUnitType.parse(nalUnitType);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/NalUnitType.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264;\n\n/**\n * H264 NAL Unit Types\n * \n * @author Deutsche Telekom\n */\npublic enum NalUnitType {\n\n    RESERVED, CODE_SLICE_NON_IDR_PICTURE, CODE_SLICE_DATA_PARTITION_A, CODE_SLICE_DATA_PARTITION_B, CODE_SLICE_DATA_PARTITION_C, CODE_SLICE_IDR_PICTURE, SEQUENCE_PARAMETER_SET, PICTURE_PARAMETER_SET, STAP_A, STAP_B, MTAP16, MTAP24, FU_A, FU_B, OTHER_NAL_UNIT;\n\n    /**\n     * Decodes the NAL Unit type\n     * \n     * @param value NAL value\n     * @return NAL Unit Type\n     */\n    public static NalUnitType parse(int value) {\n        switch (value) {\n            case 1:\n                return CODE_SLICE_NON_IDR_PICTURE;\n\n            case 2:\n                return CODE_SLICE_DATA_PARTITION_A;\n\n            case 3:\n                return CODE_SLICE_DATA_PARTITION_B;\n\n            case 4:\n                return CODE_SLICE_DATA_PARTITION_C;\n\n            case 5:\n                return CODE_SLICE_IDR_PICTURE;\n\n            case 7:\n                return SEQUENCE_PARAMETER_SET;\n\n            case 8:\n                return PICTURE_PARAMETER_SET;\n\n            case 24:\n                return STAP_A;\n\n            case 25:\n                return STAP_B;\n\n            case 26:\n                return MTAP16;\n\n            case 27:\n                return MTAP24;\n\n            case 28:\n                return FU_A;\n\n            case 29:\n                return FU_B;\n\n            case 0:\n            case 30:\n            case 31:\n                return RESERVED;\n\n            default:\n                return OTHER_NAL_UNIT;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/decoder/NativeH264Decoder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.decoder;\n\npublic class NativeH264Decoder {\n\n    public NativeH264Decoder() {\n    }\n\n    public static native int InitDecoder();\n\n    public static native int DeinitDecoder();\n\n    public static synchronized native int[] DecodeAndConvert(byte abyte0[], int rotateOrientation,\n            int[] dimensions);\n\n    public static synchronized native int getLastDecodeStatus();\n\n    static {\n        String libname = \"H264Decoder\";\n        System.loadLibrary(libname);\n    }\n}"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/encoder/NativeH264Encoder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.encoder;\n\n/**\n * Native H264 Encoder\n * \n * @author Orange\n */\npublic class NativeH264Encoder {\n\n    public static native int InitEncoder(NativeH264EncoderParams nativeH264EncoderParams);\n\n    // Resize the frame and Encode\n    public static native byte[] ResizeAndEncodeFrame(byte abyte0[], long l, boolean mirroring,\n            int srcWidth, int srcHeight);\n\n    // Scale the frame and Encode\n    public static native byte[] EncodeFrame(byte abyte0[], long l, boolean mirroring,\n            float scalingFactor);\n\n    public static native byte[] getNAL();\n\n    public static native int DeinitEncoder();\n\n    public static native int getLastEncodeStatus();\n\n    static {\n        String libname = \"H264Encoder\";\n        try {\n            System.loadLibrary(libname);\n        } catch (UnsatisfiedLinkError unsatisfiedlinkerror) {\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/encoder/NativeH264EncoderParams.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.encoder;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264Profile;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeLevel;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeProfile;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeLevel.H264ConstraintSetFlagType;\n\n/**\n * H264 Encoder settings\n * \n * @author Deutsche Telekom AG\n */\npublic class NativeH264EncoderParams {\n\n    // ----- Contants -----\n    // This constants values must be updated with those that were in the encoder\n    // codec\n\n    // - Targeted profile to encode -\n    public static final int PROFILE_DEFAULT = 0;\n    public static final int PROFILE_BASELINE = 1;\n    public static final int PROFILE_MAIN = 2;\n    public static final int PROFILE_EXTENDED = 3;\n    public static final int PROFILE_HIGH = 4;\n    public static final int PROFILE_HIGH10 = 5;\n    public static final int PROFILE_HIGH422 = 6;\n    public static final int PROFILE_HIGH444 = 7;\n\n    // - Targeted level to encode -\n    public static final int LEVEL_AUTODETECT = 0;\n    public static final int LEVEL_1 = 1;\n    public static final int LEVEL_1B = 2;\n    public static final int LEVEL_11 = 3;\n    public static final int LEVEL_12 = 4;\n    public static final int LEVEL_13 = 5;\n    public static final int LEVEL_2 = 6;\n    public static final int LEVEL_21 = 7;\n    public static final int LEVEL_22 = 8;\n    public static final int LEVEL_3 = 9;\n    public static final int LEVEL_31 = 10;\n    public static final int LEVEL_32 = 11;\n    public static final int LEVEL_4 = 12;\n    public static final int LEVEL_41 = 13;\n    public static final int LEVEL_42 = 14;\n    public static final int LEVEL_5 = 15;\n    public static final int LEVEL_51 = 16;\n\n    // - Contains supported video input format -\n    public static final int VIDEO_FORMAT_RGB24 = 0;\n    public static final int VIDEO_FORMAT_RGB12 = 1;\n    public static final int VIDEO_FORMAT_YUV420 = 2;\n    public static final int VIDEO_FORMAT_UYVY = 3;\n    public static final int VIDEO_FORMAT_YUV420SEMIPLANAR = 4;\n\n    // - Type of contents for optimal encoding mode -\n    public static final int ENCODING_MODE_TWOWAY = 0;\n    public static final int ENCODING_MODE_RECORDER = 1;\n    public static final int ENCODING_MODE_STREAMING = 2;\n    public static final int ENCODING_MODE_DOWNLOAD = 3;\n\n    // - Output format -\n    public static final int OUTPUT_FORMAT_ANNEXB = 0;\n    public static final int OUTPUT_FORMAT_MP4 = 1;\n    public static final int OUTPUT_FORMAT_RTP = 2;\n\n    // - Rate control type -\n    public static final int RATE_CONTROL_TYPE_CONSTANT_Q = 0;\n    public static final int RATE_CONTROL_TYPE_CBR_1 = 1;\n    public static final int RATE_CONTROL_TYPE_VBR_1 = 2;\n\n    // ----- Properties -----\n\n    /**\n     * Contains the width in pixels of the input frame.\n     */\n    private int frameWidth;\n\n    /**\n     * Contains the height in pixels of the input frame.\n     */\n    private int frameHeight;\n\n    /**\n     * Contains the input frame rate in the unit of frame per second.\n     */\n    private float frameRate;\n\n    /**\n     * Contains Frame Orientation. Used for RGB input. 1 means Bottom_UP RGB, 0 means Top_Down RGB,\n     * -1 for video formats other than RGB\n     */\n    private int frameOrientation; // TODO not implemented yet on the codec side\n\n    /**\n     * Contains the format of the input video, e.g., YUV 4:2:0, UYVY, RGB24, etc.\n     */\n    private int videoFormat;\n\n    /**\n     * Specifies an ID that will be used to specify this encoder while returning the bitstream in\n     * asynchronous mode.\n     */\n\n    private int encodeID;\n    /**\n     * Specifies the targeted profile, and will also specifies available tools for iEncMode. If\n     * default is used, encoder will choose its own preferred profile. If autodetect is used,\n     * encoder will check other settings and choose the right profile that doesn't have any\n     * conflicts.\n     */\n    private int profile;\n\n    /**\n     * Specifies the targeted profile IOP, composed of the values of constraint flags\n     */\n    private byte profileIOP;\n\n    /**\n     * Specifies the target level When present, other settings will be checked against the range\n     * allowable by this target level. Fail will returned upon Initialize call. If not known, users\n     * must set it to autodetect. Encoder will calculate the right level that doesn't conflict with\n     * other settings.\n     */\n    private int level;\n\n    /**\n     * Specifies whether base only (numLayer = 1) or base + enhancement layer (numLayer =2 ) is to\n     * be used.\n     */\n    private int numLayer;\n\n    /**\n     * Specifies the bit rate in bit per second.\n     */\n    private int bitRate;\n\n    /**\n     * Specifies the encoding mode. This translates to the complexity of encoding modes and error\n     * resilient tools.\n     */\n    private int encMode;\n\n    /**\n     * Specifies that SPS and PPS are retrieved first and sent out-of-band\n     */\n    private boolean outOfBandParamSet;\n\n    /**\n     * Specifies the desired output format.\n     */\n    private int outputFormat;\n\n    /**\n     * Specifies the packet size in bytes which represents the desired number of bytes per NAL. If\n     * this number is set to 0, the encoder will encode the entire slice group as one NAL.\n     */\n    private int packetSize;\n\n    /**\n     * Specifies the rate control algorithm among one of the following constant Q, CBR and VBR.\n     */\n    private int rateControlType;\n\n    /**\n     * Specifies the VBV buffer size which determines the end-to-end delay between the encoder and\n     * the decoder. The size is in unit of seconds. For download application, the buffer size can be\n     * larger than the streaming application. For 2-way application, this buffer shall be kept\n     * minimal. For a special case, in VBR mode, iBufferDelay will be set to -1 to allow buffer\n     * underflow.\n     */\n    private float bufferDelay;\n\n    /**\n     * Specifies the initial quantization parameter for the first I-frame. If constant Q rate\n     * control is used, this QP will be used for all the I-frames. This number must be set between 1\n     * and 31, otherwise, Initialize() will fail.\n     */\n    private int iquant;\n\n    /**\n     * Specifies the initial quantization parameter for the first P-frame. If constant Q rate\n     * control is used, this QP will be used for all the P-frames. This number must be set between 1\n     * and 31, otherwise, Initialize() will fail.\n     */\n    private int pquant;\n\n    /**\n     * Specifies the initial quantization parameter for the first B-frame. If constant Q rate\n     * control is used, this QP will be used for all the B-frames. This number must be set between 1\n     * and 31, otherwise, Initialize() will fail.\n     */\n    private int bquant;\n\n    /**\n     * Specifies automatic scene detection where I-frame will be used the the first frame in a new\n     * scene.\n     */\n    private boolean sceneDetection;\n\n    /**\n     * Specifies the maximum period in seconds between 2 INTRA frames. An INTRA mode is forced to a\n     * frame once this interval is reached. When there is only one I-frame is present at the\n     * beginning of the clip, iFrameInterval should be set to -1. For all I-frames coding this\n     * number should be set to 0.\n     */\n    private int iFrameInterval;\n\n    /**\n     * According to iIFrameInterval setting, the minimum number of intra MB per frame is optimally\n     * calculated for error resiliency. However, when iIFrameInterval is set to -1,\n     * numIntraMBRefresh must be specified to guarantee the minimum number of intra macroblocks per\n     * frame.\n     */\n    private int numIntraMBRefresh;\n\n    /**\n     * Specifies the duration of the clip in millisecond, needed for VBR encode. Set to 0 if\n     * unknown.\n     */\n    private int clipDuration;\n\n    /**\n     * Specify FSI Buffer input\n     */\n    private byte[] fSIBuff;\n\n    /**\n     * Specify FSI Buffer Length\n     */\n    private int fSIBuffLength;\n\n    // ----- Constructors -----\n\n    /**\n     * Constructor for native H264Encoder parameters\n     */\n    public NativeH264EncoderParams() {\n        // Default parameter that were being used in the codec, some of them\n        // hard coded\n        this.frameWidth = 176;\n        this.frameHeight = 144;\n        this.frameRate = 15;\n        this.frameOrientation = 0;\n        this.videoFormat = VIDEO_FORMAT_YUV420SEMIPLANAR;\n        this.encodeID = 0;\n        this.profile = PROFILE_BASELINE;\n        this.profileIOP = 0;\n        this.level = LEVEL_1B;\n        this.numLayer = 1;\n        this.bitRate = 64000;\n        this.encMode = ENCODING_MODE_TWOWAY;\n        this.outOfBandParamSet = true;\n        this.outputFormat = OUTPUT_FORMAT_RTP;\n        this.packetSize = 8192;\n        this.rateControlType = RATE_CONTROL_TYPE_CBR_1;\n        this.bufferDelay = 2;\n        this.iquant = 15;\n        this.pquant = 12;\n        this.bquant = 0;\n        this.sceneDetection = false;\n        this.iFrameInterval = 1;\n        this.numIntraMBRefresh = 50;\n        this.clipDuration = 0;\n        this.fSIBuff = null;\n        this.fSIBuffLength = 0;\n    }\n\n    /**\n     * Constructor for native H264Encoder parameters\n     * \n     * @param profileType Profile type\n     * @param profileIOP Profile IOP\n     * @param levelType Profile level type\n     * @param frameWidth Width in pixels of the input frame\n     * @param frameHeight Height in pixels of the input frame\n     * @param bitRate Bit rate in bit per second\n     * @param frameRate Frame rate in the unit of frame per second\n     * @param packetSize Packet size in bytes which represents the desired number of bytes per NAL\n     */\n    public NativeH264EncoderParams(H264TypeProfile profileType, byte profileIOP,\n            H264TypeLevel levelType, int frameWidth, int frameHeight, int bitRate, float frameRate,\n            int packetSize) {\n        this(); // to fill the default parameters\n\n        this.frameWidth = frameWidth;\n        this.frameHeight = frameHeight;\n        this.bitRate = bitRate;\n        this.frameRate = frameRate;\n        this.packetSize = packetSize;\n        setProfile(profileType);\n        setLevel(levelType);\n        this.profileIOP = profileIOP;\n    }\n\n    // ----- Getters and Setters -----\n\n    /**\n     * Method to set profiles and level from a given codec parameter string\n     * \n     * @param codecParams Codec parameters\n     */\n    public void setProfilesAndLevel(String codecParams) {\n        String profile_level_id = H264Config.getCodecProfileLevelId(codecParams);\n        Byte profile_idc = H264Profile.getProfileIDCFromLevelId(profile_level_id);\n        Byte profile_iop = H264Profile.getProfileIOPFromLevelId(profile_level_id);\n        Byte level_idc = H264Profile.getLevelIDCFromLevelId(profile_level_id);\n\n        if (profile_idc != null && profile_iop != null && level_idc != null) {\n            // constraintSet3Flag is the X bit on YYYX YYYY\n            int constraintSet3FlagValue = ((profile_iop >> 4) & 0x01);\n            H264ConstraintSetFlagType constraintSet3Flag = ((constraintSet3FlagValue == 1) ? H264ConstraintSetFlagType.TRUE\n                    : H264ConstraintSetFlagType.FALSE);\n\n            setProfileIOP(profile_iop);\n            setProfile(H264TypeProfile.getH264ProfileType(profile_idc));\n            setLevel(H264TypeLevel.getH264LevelType(level_idc, constraintSet3Flag));\n        }\n    }\n\n    public int getFrameWidth() {\n        return frameWidth;\n    }\n\n    public void setFrameWidth(int frameWidth) {\n        this.frameWidth = frameWidth;\n    }\n\n    public int getFrameHeight() {\n        return frameHeight;\n    }\n\n    public void setFrameHeight(int frameHeight) {\n        this.frameHeight = frameHeight;\n    }\n\n    public float getFrameRate() {\n        return frameRate;\n    }\n\n    public void setFrameRate(float frameRate) {\n        this.frameRate = frameRate;\n    }\n\n    public int getFrameOrientation() {\n        return frameOrientation;\n    }\n\n    public void setFrameOrientation(int frameOrientation) {\n        this.frameOrientation = frameOrientation;\n    }\n\n    public int getVideoFormat() {\n        return videoFormat;\n    }\n\n    public void setVideoFormat(int videoFormat) {\n        this.videoFormat = videoFormat;\n    }\n\n    public int getEncodeID() {\n        return encodeID;\n    }\n\n    public void setEncodeID(int encodeID) {\n        this.encodeID = encodeID;\n    }\n\n    public int getProfile() {\n        return profile;\n    }\n\n    public void setProfile(H264TypeProfile profile) {\n        this.profile = parseH264TypeProfile(profile);\n    }\n\n    public byte getProfileIOP() {\n        return profileIOP;\n    }\n\n    public void setProfileIOP(byte profileIOP) {\n        this.profileIOP = profileIOP;\n    }\n\n    public int getLevel() {\n        return level;\n    }\n\n    public void setLevel(H264TypeLevel level) {\n        this.level = parseH264TypeLevel(level);\n    }\n\n    public int getNumLayer() {\n        return numLayer;\n    }\n\n    public void setNumLayer(int numLayer) {\n        this.numLayer = numLayer;\n    }\n\n    public int getBitRate() {\n        return bitRate;\n    }\n\n    public void setBitRate(int bitRate) {\n        this.bitRate = bitRate;\n    }\n\n    public int getEncMode() {\n        return encMode;\n    }\n\n    public void setEncMode(int encMode) {\n        this.encMode = encMode;\n    }\n\n    public boolean isOutOfBandParamSet() {\n        return outOfBandParamSet;\n    }\n\n    public void setOutOfBandParamSet(boolean outOfBandParamSet) {\n        this.outOfBandParamSet = outOfBandParamSet;\n    }\n\n    public int getOutputFormat() {\n        return outputFormat;\n    }\n\n    public void setOutputFormat(int outputFormat) {\n        this.outputFormat = outputFormat;\n    }\n\n    public int getPacketSize() {\n        return packetSize;\n    }\n\n    public void setPacketSize(int packetSize) {\n        this.packetSize = packetSize;\n    }\n\n    public int getRateControlType() {\n        return rateControlType;\n    }\n\n    public void setRateControlType(int rateControlType) {\n        this.rateControlType = rateControlType;\n    }\n\n    public float getBufferDelay() {\n        return bufferDelay;\n    }\n\n    public void setBufferDelay(float bufferDelay) {\n        this.bufferDelay = bufferDelay;\n    }\n\n    public int getIquant() {\n        return iquant;\n    }\n\n    public void setIquant(int iquant) {\n        this.iquant = iquant;\n    }\n\n    public int getPquant() {\n        return pquant;\n    }\n\n    public void setiPquant(int pquant) {\n        this.pquant = pquant;\n    }\n\n    public int getBquant() {\n        return bquant;\n    }\n\n    public void setiBquant(int bquant) {\n        this.bquant = bquant;\n    }\n\n    public boolean isSceneDetection() {\n        return sceneDetection;\n    }\n\n    public void setSceneDetection(boolean sceneDetection) {\n        this.sceneDetection = sceneDetection;\n    }\n\n    public int getIFrameInterval() {\n        return iFrameInterval;\n    }\n\n    public void setIFrameInterval(int iFrameInterval) {\n        this.iFrameInterval = iFrameInterval;\n    }\n\n    public int getNumIntraMBRefresh() {\n        return numIntraMBRefresh;\n    }\n\n    public void setNumIntraMBRefresh(int numIntraMBRefresh) {\n        this.numIntraMBRefresh = numIntraMBRefresh;\n    }\n\n    public int getClipDuration() {\n        return clipDuration;\n    }\n\n    public void setClipDuration(int clipDuration) {\n        this.clipDuration = clipDuration;\n    }\n\n    public byte[] getFSIBuff() {\n        return fSIBuff;\n    }\n\n    public void setFSIBuff(byte[] fSIBuff) {\n        this.fSIBuff = fSIBuff;\n    }\n\n    public int getFSIBuffLength() {\n        return fSIBuffLength;\n    }\n\n    public void setFSIBuffLength(int fSIBuffLength) {\n        this.fSIBuffLength = fSIBuffLength;\n    }\n\n    /**\n     * Parse {@link H264TypeLevel} to map encode parameter 'Level'\n     * \n     * @param level\n     * @return map value if valid type, otherwise return <code>-1</code>\n     */\n    public static int parseH264TypeLevel(H264TypeLevel level) {\n        if (level == H264TypeLevel.LEVEL_1) {\n            return LEVEL_1;\n        } else if (level == H264TypeLevel.LEVEL_1B) {\n            return LEVEL_1B;\n        } else if (level == H264TypeLevel.LEVEL_1_1) {\n            return LEVEL_11;\n        } else if (level == H264TypeLevel.LEVEL_1_2) {\n            return LEVEL_12;\n        } else if (level == H264TypeLevel.LEVEL_1_3) {\n            return LEVEL_13;\n        } else if (level == H264TypeLevel.LEVEL_2) {\n            return LEVEL_2;\n        } else if (level == H264TypeLevel.LEVEL_2_1) {\n            return LEVEL_21;\n        } else if (level == H264TypeLevel.LEVEL_2_2) {\n            return LEVEL_22;\n        } else if (level == H264TypeLevel.LEVEL_3) {\n            return LEVEL_3;\n        } else if (level == H264TypeLevel.LEVEL_3_1) {\n            return LEVEL_31;\n        } else if (level == H264TypeLevel.LEVEL_3_2) {\n            return LEVEL_32;\n        } else if (level == H264TypeLevel.LEVEL_4) {\n            return LEVEL_4;\n        } else if (level == H264TypeLevel.LEVEL_4_1) {\n            return LEVEL_41;\n        } else if (level == H264TypeLevel.LEVEL_4_2) {\n            return LEVEL_42;\n        } else if (level == H264TypeLevel.LEVEL_5) {\n            return LEVEL_5;\n        } else if (level == H264TypeLevel.LEVEL_5_1) {\n            return LEVEL_51;\n        } else {\n            return -1;\n        }\n    }\n\n    /**\n     * Parse {@link H264TypeProfile} to map encode parameter 'Profile'\n     * \n     * @param profile\n     * @return map value if valid type, otherwise <code>PROFILE_DEFAULT<code>\n     */\n    public static int parseH264TypeProfile(H264TypeProfile profile) {\n        if (profile == H264TypeProfile.PROFILE_BASELINE) {\n            return PROFILE_BASELINE;\n        } else if (profile == H264TypeProfile.PROFILE_MAIN) {\n            return PROFILE_MAIN;\n        } else if (profile == H264TypeProfile.PROFILE_EXTENDED) {\n            return PROFILE_EXTENDED;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH) {\n            return PROFILE_HIGH;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH10) {\n            return PROFILE_HIGH10;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH422) {\n            return PROFILE_HIGH422;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH444) {\n            return PROFILE_HIGH444;\n        } else {\n            return PROFILE_DEFAULT;\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeLevel.H264ConstraintSetFlagType;\nimport com.gsma.rcs.utils.HexadecimalUtils;\n\n/**\n * Represent H264 base Profile\n * \n * @author Deutsche Telekom AG\n */\npublic abstract class H264Profile {\n\n    /**\n     * Video width\n     */\n    private int videoWidth;\n\n    /**\n     * Video height\n     */\n    private int videoHeight;\n\n    /**\n     * Video frame rate\n     */\n    private float frameRate;\n\n    /**\n     * Video bit rate\n     */\n    private int bitRate;\n\n    /**\n     * Packet size\n     */\n    private int packetSize;\n\n    /**\n     * Level type (1, 1b, 1.1...)\n     */\n    private H264TypeLevel level;\n\n    /**\n     * Profile type (BASELINE, MAIN...)\n     */\n    private H264TypeProfile type;\n\n    /**\n     * Codec parameters\n     */\n    private String codeParams;\n\n    /**\n     * Profile level id\n     */\n    private String levelId;\n\n    /**\n     * Profile name\n     */\n    private String profileName;\n\n    /**\n     * Profile IOP\n     */\n    private Byte profileIOP;\n\n    /**\n     * Base constructor for H264 Profiles\n     * \n     * @param profileName Profile name\n     * @param level Profile level\n     * @param type Profile type\n     * @param levelId Profile level id\n     * @param videoWidth Video with\n     * @param videoHeight Video height\n     * @param frameRate Frame rate\n     * @param bitRate Bit rate\n     * @param packetSize Packet size\n     * @param codeParams Codec parameters\n     */\n    public H264Profile(String profileName, H264TypeLevel level, H264TypeProfile type,\n            String levelId, int videoWidth, int videoHeight, float frameRate, int bitRate,\n            int packetSize, String codeParams) {\n\n        this.videoWidth = videoWidth;\n        this.videoHeight = videoHeight;\n        this.frameRate = frameRate;\n        this.bitRate = bitRate;\n        this.packetSize = packetSize;\n        this.level = level;\n        this.type = type;\n        this.codeParams = codeParams;\n        this.levelId = levelId;\n        this.profileIOP = getProfileIOPFromLevelId(levelId);\n    }\n\n    public String getCodeParams() {\n        return codeParams;\n    }\n\n    public int getVideoWidth() {\n        return videoWidth;\n    }\n\n    public int getVideoHeight() {\n        return videoHeight;\n    }\n\n    public float getFrameRate() {\n        return frameRate;\n    }\n\n    public int getBitRate() {\n        return bitRate;\n    }\n\n    public int getPacketSize() {\n        return packetSize;\n    }\n\n    public H264TypeLevel getLevel() {\n        return level;\n    }\n\n    public H264TypeProfile getType() {\n        return type;\n    }\n\n    public String getLevelId() {\n        return levelId;\n    }\n\n    public String getProfileName() {\n        return profileName;\n    }\n\n    public Byte getProfileIOP() {\n        return profileIOP;\n    }\n\n    /**\n     * Get the byte that represents the profile IDC\n     * \n     * @param profileId H264 profile-id\n     * @return profile IDC\n     */\n    public static Byte getProfileIDCFromLevelId(final String profileLevelId) {\n        return getProfileInformationFromLevelId(profileLevelId, 0);\n    }\n\n    /**\n     * Get the byte that represents the profile IOP\n     * \n     * @param profileId H264 profile-id\n     * @return profile IOP\n     */\n    public static Byte getProfileIOPFromLevelId(final String profileLevelId) {\n        return getProfileInformationFromLevelId(profileLevelId, 1);\n    }\n\n    /**\n     * Get the byte that represents the level IDC\n     * \n     * @param profileId H264 profile-id\n     * @return level IDC\n     */\n    public static Byte getLevelIDCFromLevelId(final String profileLevelId) {\n        return getProfileInformationFromLevelId(profileLevelId, 2);\n    }\n\n    /**\n     * Get informations after parse H264 profile-id\n     * \n     * @param profileId H264 profile-id\n     * @param what 0: Profile IDC, 1: Profile IOP, 2: Level IDC\n     * @return\n     */\n    private static Byte getProfileInformationFromLevelId(final String profileLevelId, int what) {\n        byte[] arrProfileId = HexadecimalUtils.hexStringToByteArray(profileLevelId);\n        if (arrProfileId == null || arrProfileId.length != 3 || what < 0 || what > 2) {\n            return null;\n        }\n        return arrProfileId[what];\n    }\n\n    /**\n     * Get instance of H264 profile, using profile-id\n     * \n     * @param profileId\n     * @return {@link H264Profile} if supported, otherwise <code>null</code>\n     */\n    public static H264Profile getProfile(String profileId) {\n        final Byte profileIDC = getProfileIDCFromLevelId(profileId);\n        final Byte profileIOP = getProfileIOPFromLevelId(profileId);\n        final Byte levelIDC = getLevelIDCFromLevelId(profileId);\n\n        if (profileIDC == null || profileIOP == null || levelIDC == null) {\n            return null;\n        }\n\n        /* constraintSet3Flag is the X bit on YYYX YYYY */\n        int constraintSet3FlagValue = ((profileIOP >> 4) & 0x01);\n        H264ConstraintSetFlagType constraintSet3Flag = ((constraintSet3FlagValue == 1) ? H264ConstraintSetFlagType.TRUE\n                : H264ConstraintSetFlagType.FALSE);\n\n        H264TypeLevel level = H264TypeLevel.getH264LevelType(levelIDC, constraintSet3Flag);\n        switch (level) {\n            case LEVEL_1:\n                return new H264Profile1();\n            case LEVEL_1B:\n                return new H264Profile1b();\n            case LEVEL_1_1:\n                return new H264Profile1_1();\n            case LEVEL_1_2:\n                return new H264Profile1_2();\n            case LEVEL_1_3:\n                return new H264Profile1_3();\n            default:\n                return null;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0a (level 1)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800a\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 64000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 80000;\n\n    private static final String base64CodeSPS = \"J0KACpY1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\"\n                + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\"\n                + H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" + base64CodeSPS + \",\"\n                + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1() {\n        super(PROFILE_NAME, H264TypeLevel.LEVEL_1, H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID, 176, 144, 15.0f, BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE, profileParams);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1_1.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1.1\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1_1 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1.1\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0b (level 1.1)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800b\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 192000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 240000;\n\n    private static final String base64CodeSPS = \"J0KAC5Y1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\"\n                + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\"\n                + H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" + base64CodeSPS + \",\"\n                + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1_1() {\n        super(PROFILE_NAME, H264TypeLevel.LEVEL_1_1, H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID, 176, 144, 15.0f, BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE, profileParams);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1_2.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1.2\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1_2 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1.2\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0c (level 1.2)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800c\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 384000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 480000;\n\n    private static final String base64CodeSPS = \"J0KADJY1BYnI\"; // QCIF\n    // static final String base64CodeSPS = \"J0KADJo1AoPy\"; // QVGA\n\n    private static final String base64CodePPS = \"KM4C/IA=\"; // QCIF\n    // static final String base64CodePPS = \"KM4C/IA=\"; // QVGA\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\"\n                + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\"\n                + H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" + base64CodeSPS + \",\"\n                + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1_2() {\n        super(PROFILE_NAME, H264TypeLevel.LEVEL_1_2, H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID, 176, 144, 15.0f, // QCIF\n                // 320, 240, 20.0f, // QVGA\n                BASELINE_PROFILE_BITRATE, JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE, profileParams);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1_3.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1.3\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1_3 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1.3\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0d (level 1.3)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800d\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 768000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 960000;\n\n    private static final String base64CodeSPS = \"J0KADZY1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\"\n                + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\"\n                + H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" + base64CodeSPS + \",\"\n                + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1_3() {\n        super(PROFILE_NAME, H264TypeLevel.LEVEL_1_3, H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID, 176, 144, 15.0f, BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE, profileParams);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1b.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1b\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1b extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1b\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 90 (Constrained baseline with level 1.b), 11 (level 1.b, because\n     * of the constraint_set3_flag)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42900b\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 128000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 160000;\n\n    private static final String base64CodeSPS = \"J0KQCZY1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\"\n                + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\"\n                + H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" + base64CodeSPS + \",\"\n                + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1b() {\n        super(PROFILE_NAME, H264TypeLevel.LEVEL_1B, H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID, 176, 144, 15.0f, BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE, profileParams);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264TypeLevel.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\n/**\n * Targeted level to encode\n * \n * @author Deutsche Telekom AG\n */\npublic enum H264TypeLevel {\n\n    LEVEL_AUTODETECT(0, H264ConstraintSetFlagType.ANY), LEVEL_1(10, H264ConstraintSetFlagType.ANY), LEVEL_1B(\n            11, H264ConstraintSetFlagType.TRUE), LEVEL_1_1(11, H264ConstraintSetFlagType.FALSE), LEVEL_1_2(\n            12, H264ConstraintSetFlagType.ANY), LEVEL_1_3(13, H264ConstraintSetFlagType.ANY), LEVEL_2(\n            20, H264ConstraintSetFlagType.ANY), LEVEL_2_1(21, H264ConstraintSetFlagType.ANY), LEVEL_2_2(\n            22, H264ConstraintSetFlagType.ANY), LEVEL_3(30, H264ConstraintSetFlagType.ANY), LEVEL_3_1(\n            31, H264ConstraintSetFlagType.ANY), LEVEL_3_2(32, H264ConstraintSetFlagType.ANY), LEVEL_4(\n            40, H264ConstraintSetFlagType.ANY), LEVEL_4_1(41, H264ConstraintSetFlagType.ANY), LEVEL_4_2(\n            42, H264ConstraintSetFlagType.ANY), LEVEL_5(50, H264ConstraintSetFlagType.ANY), LEVEL_5_1(\n            51, H264ConstraintSetFlagType.ANY);\n\n    /**\n     * Level value\n     */\n    private int decimalValue;\n\n    /**\n     * Constraint Flag\n     */\n    private H264ConstraintSetFlagType constraintSet3Flag;\n\n    /**\n     * Constructor\n     * \n     * @param decimalValue level\n     * @param constraintSet3Flag constraint Flag\n     */\n    private H264TypeLevel(int decimalValue, H264ConstraintSetFlagType constraintSet3Flag) {\n        this.decimalValue = decimalValue;\n        this.constraintSet3Flag = constraintSet3Flag;\n    }\n\n    /**\n     * Get Level value\n     * \n     * @return level\n     */\n    public int getDecimalValue() {\n        return decimalValue;\n    }\n\n    /**\n     * Get Constraint Flag\n     * \n     * @return Constraint Flag\n     */\n    public H264ConstraintSetFlagType getH264ConstraintSet3Flag() {\n        return constraintSet3Flag;\n    }\n\n    /**\n     * Get H264TypeLevel\n     * \n     * @param decimalValue level\n     * @param constraintSet3Flag constraint Flag\n     * @return H264TypeLevel\n     */\n    public static H264TypeLevel getH264LevelType(int decimalValue,\n            H264ConstraintSetFlagType constraintSet3Flag) {\n        for (H264TypeLevel h264LevelType : H264TypeLevel.values()) {\n            if ((h264LevelType.getDecimalValue() == decimalValue)\n                    && ((h264LevelType.getH264ConstraintSet3Flag() == H264ConstraintSetFlagType.ANY) || (h264LevelType\n                            .getH264ConstraintSet3Flag() == constraintSet3Flag))) {\n                return h264LevelType;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Targeted constrains set flags to encode.\n     */\n    public enum H264ConstraintSetFlagType {\n        ANY(0), FALSE(1), TRUE(2);\n\n        /**\n         * Constraint flag value\n         */\n        private int decimalValue;\n\n        /**\n         * Constructor\n         * \n         * @param decimalValue constraint flag value\n         */\n        private H264ConstraintSetFlagType(int decimalValue) {\n            this.decimalValue = decimalValue;\n        }\n\n        /**\n         * Get constraint flag value\n         * \n         * @return constraint flag\n         */\n        public int getDecimalValue() {\n            return decimalValue;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264TypeProfile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\n/**\n * Targeted profile to encode\n * \n * @author Deutsche Telekom AG\n */\npublic enum H264TypeProfile {\n\n    /* Non-scalable profile */\n    PROFILE_BASELINE(66), PROFILE_MAIN(77), PROFILE_EXTENDED(88), PROFILE_HIGH(100), PROFILE_HIGH10(\n            110), PROFILE_HIGH422(122), PROFILE_HIGH444(244), PROFILE_CAVLC444(44);\n\n    /**\n     * Type value\n     */\n    public int decimalValue;\n\n    /**\n     * Constructor\n     * \n     * @param decimalValue type\n     */\n    private H264TypeProfile(int decimalValue) {\n        this.decimalValue = decimalValue;\n    }\n\n    /**\n     * Get Type\n     * \n     * @return type value\n     */\n    public int getDecimalValue() {\n        return decimalValue;\n    }\n\n    /**\n     * Get instance of {@link H264TypeProfile}, using decimal value\n     * \n     * @param decimalValue\n     * @return {@link H264TypeProfile} if valid decimal, otherwise <code>null</code>\n     */\n    public static H264TypeProfile getH264ProfileType(int decimalValue) {\n        for (H264TypeProfile h264ProfileType : H264TypeProfile.values()) {\n            if (h264ProfileType.getDecimalValue() == decimalValue) {\n                return h264ProfileType;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/ReceptionReport.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * ReceptionReport based on RFC 3550 specification\n * \n * @author Deutsche Telekom\n */\npublic class ReceptionReport {\n\n    /**\n     * The SSRC identifier of the source to which the information in this reception report block\n     * pertains\n     */\n    private int ssrc;\n\n    /**\n     * The fraction of RTP data packets from source SSRC lost since the previous SR or RR packet was\n     * sent\n     */\n    private double fractionLost;\n\n    /**\n     * The total number of RTP data packets from source SSRC_n that have been lost since the\n     * beginning of reception\n     */\n    private int cumulativeNumberOfPacketsLost;\n\n    /**\n     * The low 16 bits contain the highest sequence number received in an RTP data packet from\n     * source SSRC, and the most significant 16 bits extend that sequence number with the\n     * corresponding count of sequence number cycles\n     */\n    private long extendedHighestSequenceNumberReceived;\n\n    /**\n     * An estimate of the statistical variance of the RTP data packet interarrival time, measured in\n     * timestamp units and expressed as anunsigned integer\n     */\n    private long interarrivalJitter;\n\n    /**\n     * The middle 32 bits out of 64 in the NTP timestamp received as part of the most recent RTCP\n     * sender report (SR) packet from source SSRC. If no SR has been received yet, the field is set\n     * to zero\n     */\n    private long lastSenderReport;\n\n    /**\n     * The delay, expressed in units of 1/65536 seconds, between receiving the last SR packet from\n     * source SSRC and sending this reception report block\n     */\n    private long delaySinceLastSenderReport;\n\n    /**\n     * Default constructor\n     * \n     * @param ssrc Source identifier\n     */\n    public ReceptionReport(int ssrc) {\n        this.ssrc = ssrc;\n    }\n\n    public long getSsrc() {\n        return ssrc;\n    }\n\n    public int setSsrc(int ssrc) {\n        return ssrc;\n    }\n\n    public double getFractionLost() {\n        return fractionLost;\n    }\n\n    public void setFractionLost(double fractionLost) {\n        this.fractionLost = fractionLost;\n    }\n\n    public int getCumulativeNumberOfPacketsLost() {\n        return cumulativeNumberOfPacketsLost;\n    }\n\n    public void setCumulativeNumberOfPacketsLost(int cumulativeNumberOfPacketsLost) {\n        this.cumulativeNumberOfPacketsLost = cumulativeNumberOfPacketsLost;\n    }\n\n    public long getExtendedHighestSequenceNumberReceived() {\n        return extendedHighestSequenceNumberReceived;\n    }\n\n    public void setExtendedHighestSequenceNumberReceived(long extendedHighestSequenceNumberReceived) {\n        this.extendedHighestSequenceNumberReceived = extendedHighestSequenceNumberReceived;\n    }\n\n    public long getInterarrivalJitter() {\n        return interarrivalJitter;\n    }\n\n    public void setInterarrivalJitter(long interarrivalJitter) {\n        this.interarrivalJitter = interarrivalJitter;\n    }\n\n    public long getLastSenderReport() {\n        return lastSenderReport;\n    }\n\n    public void setLastSenderReport(long lastSenderReport) {\n        this.lastSenderReport = lastSenderReport;\n    }\n\n    public long getDelaySinceLastSenderReport() {\n        return delaySinceLastSenderReport;\n    }\n\n    public void setDelaySinceLastSenderReport(long delaySinceLastSenderReport) {\n        this.delaySinceLastSenderReport = delaySinceLastSenderReport;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpAppPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RTCP APP packet\n * \n * @author jexa7410\n */\npublic class RtcpAppPacket extends RtcpPacket {\n    public int mSsrc;\n    public int mName;\n    public int mSubtype;\n\n    public RtcpAppPacket(RtcpPacket parent) {\n        super(parent);\n        mType = 204;\n    }\n\n    public RtcpAppPacket(int ssrc, int name, int subtype, byte data[]) {\n        mSsrc = ssrc;\n        mName = name;\n        mSubtype = subtype;\n        mData = data;\n        mType = 204;\n\n        if ((data.length & 3) != 0) {\n            throw new IllegalArgumentException(\"Bad data length\");\n        }\n        if (subtype < 0 || subtype > 31) {\n            throw new IllegalArgumentException(\"Bad subtype\");\n        }\n    }\n\n    public int calcLength() {\n        return 12 + mData.length;\n    }\n\n    public void assemble(DataOutputStream out) throws IOException {\n        out.writeByte(128 + mSubtype);\n        out.writeByte(204);\n        out.writeShort(2 + (mData.length >> 2));\n        out.writeInt(mSsrc);\n        out.writeInt(mName);\n        out.write(mData);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpByePacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RTCP BYE packet\n * \n * @author jexa7410\n */\npublic class RtcpByePacket extends RtcpPacket {\n\n    public int mSsrc[];\n    public byte mReason[];\n\n    public RtcpByePacket(RtcpPacket parent) {\n        super(parent);\n        mType = 203;\n    }\n\n    public RtcpByePacket(int ssrc[], byte reason[]) {\n        this.mSsrc = ssrc;\n        if (reason != null) {\n            this.mReason = reason;\n        } else {\n            this.mReason = new byte[0];\n        }\n        if (ssrc.length > 31) {\n            throw new IllegalArgumentException(\"Too many SSRCs\");\n        }\n    }\n\n    public int calcLength() {\n        return 4 + (mSsrc.length << 2) + (mReason.length <= 0 ? 0 : mReason.length + 4 & -4);\n    }\n\n    public void assemble(DataOutputStream out) throws IOException {\n        out.writeByte(128 + mSsrc.length);\n        out.writeByte(203);\n        out.writeShort(mSsrc.length + (mReason.length <= 0 ? 0 : mReason.length + 4 >> 2));\n        for (int i = 0; i < mSsrc.length; i++) {\n            out.writeInt(mSsrc[i]);\n        }\n\n        if (mReason.length > 0) {\n            out.writeByte(mReason.length);\n            out.write(mReason);\n            for (int i = (mReason.length + 4 & -4) - mReason.length - 1; i > 0; i--) {\n                out.writeByte(0);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpCompoundPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Packet;\n\n/**\n * RTCP compound packet\n * \n * @author jexa7410\n */\npublic class RtcpCompoundPacket extends RtcpPacket {\n    public RtcpPacket[] mPackets;\n\n    public RtcpCompoundPacket(Packet packet) {\n        super(packet);\n        mType = -1;\n    }\n\n    public RtcpCompoundPacket(RtcpPacket[] rtcppackets) {\n        mPackets = rtcppackets;\n        mType = -1;\n    }\n\n    public void assemble(int i, boolean bool) throws IOException {\n        mLength = i;\n        mOffset = 0;\n        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(i);\n        DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);\n        int i_0_;\n        if (bool) {\n            mOffset += 4;\n        }\n        i_0_ = mOffset;\n        for (int i_1_ = 0; i_1_ < mPackets.length; i_1_++) {\n            i_0_ = bytearrayoutputstream.size();\n            mPackets[i_1_].assemble(dataoutputstream);\n        }\n        int i_2_ = bytearrayoutputstream.size();\n        mData = bytearrayoutputstream.toByteArray();\n        if (i_2_ > i) {\n            throw new IOException(\"RTCP Packet overflow\");\n        }\n        if (i_2_ < i) {\n            if (mData.length < i)\n                System.arraycopy(mData, 0, mData = new byte[i], 0, i_2_);\n            mData[i_0_] |= 0x20;\n            mData[i - 1] = (byte) (i - i_2_);\n            int i_3_ = (mData[i_0_ + 3] & 0xff) + (i - i_2_ >> 2);\n            if (i_3_ >= 256)\n                mData[i_0_ + 2] += i - i_2_ >> 10;\n            mData[i_0_ + 3] = (byte) i_3_;\n        }\n    }\n\n    public void assemble(DataOutputStream dataoutputstream) throws IOException {\n        throw new IllegalArgumentException(\"Recursive Compound Packet\");\n    }\n\n    public int calcLength() {\n        int i = 0;\n        if (mPackets == null || mPackets.length < 1)\n            throw new IllegalArgumentException(\"Bad RTCP Compound Packet\");\n        for (int i_4_ = 0; i_4_ < mPackets.length; i_4_++)\n            i += mPackets[i_4_].calcLength();\n        return i;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Packet;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * Abstract RCTP packet\n * \n * @author jexa7410\n */\npublic abstract class RtcpPacket extends Packet {\n    /**\n     * Version =2\n     */\n    public static final byte VERSION = 2;\n\n    /**\n     * Padding =0\n     */\n    public static final byte PADDING = 0;\n\n    /**\n     * RTCP SR\n     */\n    public static final int RTCP_SR = 200;\n\n    /**\n     * RTCP RR\n     */\n    public static final int RTCP_RR = 201;\n\n    /**\n     * RTCP SDES\n     */\n    public static final int RTCP_SDES = 202;\n\n    /**\n     * RTCP BYE\n     */\n    public static final int RTCP_BYE = 203;\n\n    /**\n     * RTCP APP\n     */\n    public static final int RTCP_APP = 204;\n\n    /**\n     * RTCP APP\n     */\n    public static final int RTCP_COMPOUND = -1;\n\n    public Packet mBase;\n\n    public int mType;\n\n    public RtcpPacket() {\n    }\n\n    public RtcpPacket(RtcpPacket rtcppacket) {\n        super(rtcppacket);\n\n        mBase = rtcppacket.mBase;\n    }\n\n    public RtcpPacket(Packet packet) {\n        super(packet);\n\n        mBase = packet;\n    }\n\n    public abstract void assemble(DataOutputStream dataoutputstream) throws IOException;\n\n    public abstract int calcLength();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpPacketReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpApplicationEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpByeEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpEventListener;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpReceiverReportEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpSdesEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpSenderReportEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Packet;\nimport com.gsma.rcs.platform.network.DatagramConnection;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.Closeable;\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.net.SocketTimeoutException;\nimport java.util.Vector;\n\n/**\n * RTCP packet receiver\n * \n * @author jexa7410\n */\npublic class RtcpPacketReceiver extends Thread implements Closeable {\n\n    private DatagramConnection mDatagramConnection;\n\n    /**\n     * Statistics\n     */\n    private RtcpStatisticsReceiver mStats = new RtcpStatisticsReceiver();\n\n    /**\n     * RTCP event listeners\n     */\n    private Vector<RtcpEventListener> mListeners = new Vector<RtcpEventListener>();\n\n    private RtcpSession mRtcpSession;\n\n    /**\n     * Signals that thread is interrupted\n     */\n    private boolean mIsInterrupted = false;\n\n    private static final Logger sLogger = Logger.getLogger(RtcpPacketReceiver.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param port Listening port\n     * @param rtcpSession the RTCP session\n     * @param socketTimeout\n     * @throws IOException\n     */\n    public RtcpPacketReceiver(int port, RtcpSession rtcpSession, int socketTimeout)\n            throws IOException {\n        super();\n\n        mRtcpSession = rtcpSession;\n\n        // Create the UDP server\n        mDatagramConnection = NetworkFactory.getFactory().createDatagramConnection(socketTimeout);\n        mDatagramConnection.open(port);\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"RTCP receiver created at port \" + port);\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param port Listening port\n     * @param rtcpSession the RTCP session\n     * @throws IOException\n     */\n    public RtcpPacketReceiver(int port, RtcpSession rtcpSession) throws IOException {\n        this(port, rtcpSession, 0);\n    }\n\n    /**\n     * Close the receiver\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        mIsInterrupted = true;\n        interrupt();\n\n        if (mDatagramConnection != null) {\n            mDatagramConnection.close();\n            mDatagramConnection = null;\n        }\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            while (mDatagramConnection != null) {\n                // Wait a packet\n                byte[] data = mDatagramConnection.receive();\n\n                // Create a packet object\n                Packet packet = new Packet();\n                packet.mData = data;\n                packet.mLength = data.length;\n                packet.mOffset = 0;\n                packet.mReceivedAt = System.currentTimeMillis();\n\n                // Process the received packet\n                /* Update statistics */\n                mStats.numRtcpPkts++;\n                mStats.numRtcpBytes += packet.mLength;\n                parseRtcpPacket(packet);\n            }\n        } catch (SocketTimeoutException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            mStats.numBadRtcpPkts++;\n            notifyRtcpListenersOfTimeout();\n        } catch (IOException e) {\n            if (!mIsInterrupted) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            }\n            mStats.numBadRtcpPkts++;\n        } catch (NetworkException e) {\n            if (!mIsInterrupted) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            }\n            mStats.numBadRtcpPkts++;\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to establish datagramConnection!\", e);\n            mStats.numBadRtcpPkts++;\n        }\n    }\n\n    private RtcpReport getRtcpReport(DataInputStream in) throws IOException {\n        int ssrc = in.readInt();\n        long val = in.readInt();\n        val &= 0xffffffffL;\n        int fractionLost = (int) (val >> 24);\n        int packetsLost = (int) (val & 0xffffffL);\n        long lastSeq = in.readInt() & 0xffffffffL;\n        int jitter = in.readInt();\n        long lsr = in.readInt() & 0xffffffffL;\n        long dlsr = in.readInt() & 0xffffffffL;\n        return new RtcpReport(ssrc, fractionLost, packetsLost, lastSeq, jitter, lsr, dlsr);\n    }\n\n    /**\n     * Parse the RTCP packet\n     * \n     * @param packet RTCP packet not yet parsed\n     * @return RTCP packet\n     * @throws IOException\n     */\n    private RtcpPacket parseRtcpPacket(Packet packet) throws IOException {\n        RtcpCompoundPacket compoundPacket = new RtcpCompoundPacket(packet);\n        Vector<RtcpPacket> subpackets = new Vector<RtcpPacket>();\n        DataInputStream in = new DataInputStream(new ByteArrayInputStream(compoundPacket.mData,\n                compoundPacket.mOffset, compoundPacket.mLength));\n        mRtcpSession.updateavgrtcpsize(compoundPacket.mLength);\n        int length = 0;\n        for (int offset = 0; offset < compoundPacket.mLength; offset += length) {\n            int firstbyte = in.readUnsignedByte();\n            if ((firstbyte & 0xc0) != 128) {\n                throw new IOException(new StringBuilder(\"Bad RTCP packet version for firstbyte : \")\n                        .append(firstbyte).toString());\n            }\n\n            /* Read type of subpacket */\n            int type = in.readUnsignedByte();\n\n            /* Read length of subpacket */\n            length = in.readUnsignedShort();\n            length = length + 1 << 2;\n            int padlen = 0;\n            if (offset + length > compoundPacket.mLength) {\n                throw new IOException(new StringBuilder(\"Bad RTCP packet length : \").append(\n                        offset + length).toString());\n            }\n            if (offset + length == compoundPacket.mLength) {\n                if ((firstbyte & 0x20) != 0) {\n                    padlen = compoundPacket.mData[compoundPacket.mOffset + compoundPacket.mLength\n                            - 1] & 0xff;\n                    if (padlen == 0) {\n                        if (sLogger.isActivated()) {\n                            sLogger.error(\"Bad RTCP packet format\");\n                        }\n                        throw new IOException(new StringBuilder(\n                                \"Bad RTCP packet format with length : \").append(padlen).toString());\n                    }\n                }\n            } else if ((firstbyte & 0x20) != 0) {\n                throw new IOException(\"Bad RTCP packet format (P != 0)\");\n            }\n            int inlength = length - padlen;\n            firstbyte &= 0x1f;\n\n            RtcpPacket subpacket;\n            switch (type) {\n                case RtcpPacket.RTCP_SR:\n                    mStats.numSrPkts++;\n                    if (inlength != 28 + 24 * firstbyte) {\n                        mStats.numMalformedRtcpPkts++;\n                        throw new IOException(\"Bad RTCP SR packet format\");\n                    }\n                    RtcpSenderReportPacket srp = new RtcpSenderReportPacket(compoundPacket);\n                    subpacket = srp;\n                    srp.ssrc = in.readInt();\n                    srp.ntptimestampmsw = in.readInt() & 0xffffffffL;\n                    srp.ntptimestamplsw = in.readInt() & 0xffffffffL;\n                    srp.rtptimestamp = in.readInt() & 0xffffffffL;\n                    srp.packetcount = in.readInt() & 0xffffffffL;\n                    srp.octetcount = in.readInt() & 0xffffffffL;\n                    srp.reports = new RtcpReport[firstbyte];\n\n                    RtpSource sourceSR = mRtcpSession.getMySource();\n                    if (sourceSR != null) {\n                        sourceSR.receivedSenderReport(srp);\n                    }\n\n                    for (int i = 0; i < srp.reports.length; i++) {\n                        srp.reports[i] = getRtcpReport(in);\n                    }\n\n                    notifyRtcpListeners(new RtcpSenderReportEvent(srp));\n                    break;\n\n                case RtcpPacket.RTCP_RR:\n                    if (inlength != 8 + 24 * firstbyte) {\n                        mStats.numMalformedRtcpPkts++;\n                        throw new IOException(\"Bad RTCP RR packet format\");\n                    }\n                    RtcpReceiverReportPacket rrp = new RtcpReceiverReportPacket(compoundPacket);\n                    subpacket = rrp;\n                    rrp.ssrc = in.readInt();\n                    rrp.reports = new RtcpReport[firstbyte];\n\n                    for (int i = 0; i < rrp.reports.length; i++) {\n                        rrp.reports[i] = getRtcpReport(in);\n                    }\n\n                    notifyRtcpListeners(new RtcpReceiverReportEvent(rrp));\n                    break;\n\n                case RtcpPacket.RTCP_SDES:\n                    RtcpSdesPacket sdesp = new RtcpSdesPacket(compoundPacket);\n                    subpacket = sdesp;\n                    sdesp.sdes = new RtcpSdesBlock[firstbyte];\n                    int sdesoff = 4;\n                    for (int i = 0; i < sdesp.sdes.length; i++) {\n                        RtcpSdesBlock chunk = new RtcpSdesBlock();\n                        sdesp.sdes[i] = chunk;\n                        chunk.ssrc = in.readInt();\n                        sdesoff += 5;\n                        Vector<RtcpSdesItem> items = new Vector<RtcpSdesItem>();\n                        boolean gotcname = false;\n                        int j;\n                        while ((j = in.readUnsignedByte()) != 0) {\n                            if (j < 1 || j > 8) {\n                                mStats.numMalformedRtcpPkts++;\n                                throw new IOException(\"Bad RTCP SDES packet format\");\n                            }\n                            if (j == 1) {\n                                gotcname = true;\n                            }\n                            RtcpSdesItem item = new RtcpSdesItem();\n                            items.addElement(item);\n                            item.type = j;\n                            int sdeslen = in.readUnsignedByte();\n                            item.data = new byte[sdeslen];\n                            in.readFully(item.data);\n                            sdesoff += 2 + sdeslen;\n                        }\n                        if (!gotcname) {\n                            mStats.numMalformedRtcpPkts++;\n                            throw new IOException(\"Bad RTCP SDES packet format\");\n                        }\n                        chunk.items = new RtcpSdesItem[items.size()];\n                        items.copyInto(chunk.items);\n                        if ((sdesoff & 3) != 0) {\n                            if (in.skip(4 - (sdesoff & 3)) != 4 - (sdesoff & 3)) {\n                                throw new IOException(\"Bad RTCP SDES packet format\");\n                            }\n                            sdesoff = sdesoff + 3 & -4;\n                        }\n                    }\n\n                    if (inlength != sdesoff) {\n                        mStats.numMalformedRtcpPkts++;\n                        throw new IOException(\"Bad RTCP SDES packet format\");\n                    }\n\n                    notifyRtcpListeners(new RtcpSdesEvent(sdesp));\n                    break;\n\n                case RtcpPacket.RTCP_BYE:\n                    RtcpByePacket byep = new RtcpByePacket(compoundPacket);\n                    subpacket = byep;\n                    byep.mSsrc = new int[firstbyte];\n                    for (int i = 0; i < byep.mSsrc.length; i++) {\n                        byep.mSsrc[i] = in.readInt();\n                    }\n\n                    int reasonlen;\n                    if (inlength > 4 + 4 * firstbyte) {\n                        reasonlen = in.readUnsignedByte();\n                        byep.mReason = new byte[reasonlen];\n                        reasonlen++;\n                    } else {\n                        reasonlen = 0;\n                        byep.mReason = new byte[0];\n                    }\n                    reasonlen = reasonlen + 3 & -4;\n                    if (inlength != 4 + 4 * firstbyte + reasonlen) {\n                        mStats.numMalformedRtcpPkts++;\n                        throw new IOException(\"Bad RTCP BYE packet format\");\n                    }\n                    in.readFully(byep.mReason);\n                    int skipBye = reasonlen - byep.mReason.length;\n                    if (in.skip(skipBye) != skipBye) {\n                        throw new IOException(\"Bad RTCP BYE packet format\");\n                    }\n\n                    notifyRtcpListeners(new RtcpByeEvent(byep));\n                    break;\n\n                case RtcpPacket.RTCP_APP:\n                    if (inlength < 12) {\n                        throw new IOException(\"Bad RTCP APP packet format\");\n                    }\n                    RtcpAppPacket appp = new RtcpAppPacket(compoundPacket);\n                    subpacket = appp;\n                    appp.mSsrc = in.readInt();\n                    appp.mName = in.readInt();\n                    appp.mSubtype = firstbyte;\n                    appp.mData = new byte[inlength - 12];\n                    in.readFully(appp.mData);\n                    int skipApp = inlength - 12 - appp.mData.length;\n                    if (in.skip(skipApp) != skipApp) {\n                        throw new IOException(\"Bad RTCP APP packet format\");\n                    }\n\n                    notifyRtcpListeners(new RtcpApplicationEvent(appp));\n                    break;\n\n                default:\n                    mStats.numUnknownTypes++;\n                    throw new IOException(\"Bad RTCP packet format\");\n            }\n            subpacket.mOffset = offset;\n            subpacket.mLength = length;\n            subpackets.addElement(subpacket);\n            if (in.skipBytes(padlen) != padlen) {\n                throw new IOException(\"Bad RTCP packet format\");\n            }\n        }\n        compoundPacket.mPackets = new RtcpPacket[subpackets.size()];\n        subpackets.copyInto(compoundPacket.mPackets);\n        return compoundPacket;\n    }\n\n    /**\n     * Add a RTCP event listener\n     * \n     * @param listener Listener\n     */\n    public void addRtcpListener(RtcpEventListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add a RTCP event listener\");\n        }\n        mListeners.addElement(listener);\n    }\n\n    /**\n     * Remove a RTCP event listener\n     * \n     * @param listener Listener\n     */\n    public void removeRtcpListener(RtcpEventListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a RTCP event listener\");\n        }\n        mListeners.removeElement(listener);\n    }\n\n    /**\n     * Notify RTCP event listeners\n     * \n     * @param event RTCP event\n     */\n    public void notifyRtcpListeners(RtcpEvent event) {\n        for (int i = 0; i < mListeners.size(); i++) {\n            RtcpEventListener listener = mListeners.elementAt(i);\n            listener.receiveRtcpEvent(event);\n        }\n    }\n\n    /**\n     * Notify timeout on RTCP listener\n     */\n    private void notifyRtcpListenersOfTimeout() {\n        for (RtcpEventListener listener : mListeners) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"RTCP connection timeout\");\n            }\n            listener.connectionTimeout();\n        }\n    }\n\n    /**\n     * Returns the statistics of RTCP reception\n     * \n     * @return Statistics\n     */\n    public RtcpStatisticsReceiver getRtcpReceptionStats() {\n        return mStats;\n    }\n\n    /**\n     * Returns the DatagramConnection of RTCP\n     * \n     * @return DatagramConnection\n     */\n    public DatagramConnection getConnection() {\n        return mDatagramConnection;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpPacketTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.platform.network.DatagramConnection;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.util.Random;\nimport java.util.Vector;\n\n/**\n * RTCP packet transmitter\n * \n * @author jexa7410\n */\npublic class RtcpPacketTransmitter extends Thread implements Closeable {\n\n    private String mRemoteAddress;\n\n    private int mRemotePort;\n\n    /**\n     * Statistics\n     */\n    private RtcpStatisticsTransmitter mStats = new RtcpStatisticsTransmitter();\n\n    private DatagramConnection mDatagramConnection;\n\n    private RtcpSession mRtcpSession;\n\n    /**\n     * Flag used to determine when to terminate after sending a BYE\n     */\n    private boolean mWaitingForByeBackoff = false;\n\n    /**\n     * Flag used to properly close\n     */\n    private boolean mClosed = false;\n\n    /**\n     * Random value\n     */\n    private Random mRand = new Random();\n\n    private static final Logger sLogger = Logger.getLogger(RtcpPacketTransmitter.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession the RTCP session\n     * @throws IOException\n     */\n    public RtcpPacketTransmitter(String address, int port, RtcpSession rtcpSession)\n            throws IOException {\n        super();\n\n        mRemoteAddress = address;\n        mRemotePort = port;\n        mRtcpSession = rtcpSession;\n\n        // Open the connection\n        mDatagramConnection = NetworkFactory.getFactory().createDatagramConnection();\n        mDatagramConnection.open();\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"RTCP transmitter connected to \" + mRemoteAddress + \":\" + mRemotePort);\n        }\n    }\n\n    /**\n     * Constructor - used for SYMETRIC_RTP\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession the RTCP session\n     * @param DatagramConnection datagram connection of the RtpPacketReceiver\n     * @throws IOException\n     */\n    public RtcpPacketTransmitter(String address, int port, RtcpSession rtcpSession,\n            DatagramConnection connection) throws IOException {\n        super();\n\n        mRemoteAddress = address;\n        mRemotePort = port;\n        mRtcpSession = rtcpSession;\n\n        // Open the connection\n        if (connection != null) {\n            mDatagramConnection = connection;\n        } else {\n            mDatagramConnection = NetworkFactory.getFactory().createDatagramConnection();\n            mDatagramConnection.open();\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"RTCP transmitter connected to \" + mRemoteAddress + \":\" + mRemotePort);\n        }\n    }\n\n    /**\n     * Close the transmitter\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (mClosed) {\n            return;\n        }\n\n        mRtcpSession.isByeRequested = true;\n        mClosed = true;\n\n        // Close the datagram connection\n        if (mDatagramConnection != null) {\n            mDatagramConnection.close();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"RTCP transmitter closed\");\n        }\n        // If the method start() was never invoked this Thread will be on NEW\n        // state and the resources won't be freed. We need to force the start()\n        // to allow it to die gracefully\n        if (getState() == State.NEW) {\n            start();\n        }\n\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        if (mClosed) {\n            return;\n        }\n\n        try {\n            // Send a SDES packet\n            sendSdesPacket();\n\n            boolean terminate = false;\n            while (!terminate) {\n                try {\n                    // Wait the RTCP report interval.\n                    Thread.sleep((long) mRtcpSession.getReportInterval());\n\n                    // Right time to send a RTCP packet or reschedule ?\n                    if ((mRtcpSession.timeOfLastRTCPSent + mRtcpSession.T) <= mRtcpSession\n                            .currentTime()) {\n                        // We know that it is time to send a RTCP packet, is it\n                        // a BYE packet\n                        if ((mRtcpSession.isByeRequested && mWaitingForByeBackoff)) {\n                            // If it is bye then did we ever sent anything\n                            if (mRtcpSession.timeOfLastRTCPSent > 0\n                                    && mRtcpSession.timeOfLastRTPSent > 0) {\n                                mRtcpSession.getMySource().activeSender = false;\n                                mRtcpSession.timeOfLastRTCPSent = mRtcpSession.currentTime();\n                            } else {\n                                // We never sent anything and we have to quit :(\n                                // do not send BYE\n                                terminate = true;\n                            }\n                        } else {\n                            if (!mClosed) {\n                                byte[] data = assembleRtcpPacket();\n                                if (data != null) {\n                                    transmit(assembleRtcpPacket());\n                                }\n                                if (mRtcpSession.isByeRequested && !mWaitingForByeBackoff) {\n                                    // We have sent a BYE packet, so terminate\n                                    terminate = true;\n                                } else {\n                                    mRtcpSession.timeOfLastRTCPSent = mRtcpSession.currentTime();\n                                }\n                            } else {\n                                terminate = true;\n                            }\n\n                        }\n                    }\n                    mWaitingForByeBackoff = false;\n\n                } catch (InterruptedException e) {\n                    mWaitingForByeBackoff = true;\n                    mRtcpSession.isByeRequested = true;\n                }\n            }\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Can't send the RTCP packet\", e);\n        }\n    }\n\n    /**\n     * assemble RTCP packet\n     */\n    private byte[] assembleRtcpPacket() {\n        byte data[] = new byte[0];\n\n        // Sender or receiver packet\n        RtpSource s = mRtcpSession.getMySource();\n        if ((s.activeSender) && (mRtcpSession.timeOfLastRTCPSent < mRtcpSession.timeOfLastRTPSent)) {\n            data = RtcpPacketUtils.append(data, assembleSenderReportPacket());\n        } else {\n            data = RtcpPacketUtils.append(data, assembleReceiverReportPacket());\n        }\n\n        // SDES packets\n        Vector<RtcpSdesPacket> repvec = makereports();\n        for (int i = 0; i < repvec.size(); i++) {\n            if (repvec.elementAt(i).mData != null)\n                data = RtcpPacketUtils.append(data, repvec.elementAt(i).mData);\n        }\n\n        // BYE packet\n        RtcpByePacket byepacket = null;\n        if (mRtcpSession.isByeRequested) {\n            int ssrc[] = {\n                mRtcpSession.SSRC\n            };\n            byepacket = new RtcpByePacket(ssrc, null);\n            data = RtcpPacketUtils.append(data, byepacket.mData);\n        }\n\n        return data;\n    }\n\n    /**\n     * assemble RTCP SR packet\n     * \n     * @return packet data\n     */\n    private byte[] assembleSenderReportPacket() {\n        final int FIXED_HEADER_SIZE = 4;\n        byte V_P_RC = (byte) ((RtcpPacket.VERSION << 6) | (RtcpPacket.PADDING << 5) | (0x00));\n        byte ss[] = RtcpPacketUtils.longToBytes(mRtcpSession.SSRC, 4);\n        byte PT[] = RtcpPacketUtils.longToBytes(RtcpPacket.RTCP_SR, 1);\n        byte NTP_Timestamp[] = RtcpPacketUtils.longToBytes(mRtcpSession.currentTime(), 8);\n        short randomOffset = (short) Math.abs(mRand.nextInt() & 0x000000FF);\n        byte RTP_Timestamp[] = RtcpPacketUtils\n                .longToBytes((long) mRtcpSession.tc + randomOffset, 4);\n        byte SenderPacketCount[] = RtcpPacketUtils.longToBytes(mRtcpSession.packetCount, 4);\n        byte SenderOctetCount[] = RtcpPacketUtils.longToBytes(mRtcpSession.octetCount, 4);\n\n        // report block\n        byte receptionReportBlocks[] = new byte[0];\n        receptionReportBlocks = RtcpPacketUtils.append(receptionReportBlocks,\n                assembleRTCPReceptionReport());\n        byte receptionReports = (byte) (receptionReportBlocks.length / 24);\n        V_P_RC = (byte) (V_P_RC | (byte) (receptionReports & 0x1F));\n\n        // Length is 32 bit words contained in the packet -1\n        byte length[] = RtcpPacketUtils.longToBytes((FIXED_HEADER_SIZE + ss.length\n                + NTP_Timestamp.length + RTP_Timestamp.length + SenderPacketCount.length\n                + SenderOctetCount.length + receptionReportBlocks.length) / 4 - 1, 2);\n\n        // Build RTCP SR Packet\n        byte rtcpSRPacket[] = new byte[1];\n        rtcpSRPacket[0] = V_P_RC;\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, PT);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, length);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, ss);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, NTP_Timestamp);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, RTP_Timestamp);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, SenderPacketCount);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, SenderOctetCount);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, receptionReportBlocks);\n\n        return rtcpSRPacket;\n    }\n\n    /**\n     * assemble RTCP RR packet\n     * \n     * @return packet data\n     */\n    private byte[] assembleReceiverReportPacket() {\n        final int FIXED_HEADER_SIZE = 4;\n        byte V_P_RC = (byte) ((RtcpPacket.VERSION << 6) | (RtcpPacket.PADDING << 5) | (0x00));\n        byte ss[] = RtcpPacketUtils.longToBytes(mRtcpSession.SSRC, 4);\n        byte PT[] = RtcpPacketUtils.longToBytes(RtcpPacket.RTCP_RR, 1);\n\n        // report block\n        byte receptionReportBlocks[] = new byte[0];\n        receptionReportBlocks = RtcpPacketUtils.append(receptionReportBlocks,\n                assembleRTCPReceptionReport());\n        byte receptionReports = (byte) (receptionReportBlocks.length / 24);\n        V_P_RC = (byte) (V_P_RC | (byte) (receptionReports & 0x1F));\n\n        byte length[] = RtcpPacketUtils.longToBytes(\n                (FIXED_HEADER_SIZE + ss.length + receptionReportBlocks.length) / 4 - 1, 2);\n\n        // Build RTCP RR Packet\n        byte RRPacket[] = new byte[1];\n        RRPacket[0] = V_P_RC;\n        RRPacket = RtcpPacketUtils.append(RRPacket, PT);\n        RRPacket = RtcpPacketUtils.append(RRPacket, length);\n        RRPacket = RtcpPacketUtils.append(RRPacket, ss);\n        RRPacket = RtcpPacketUtils.append(RRPacket, receptionReportBlocks);\n        return RRPacket;\n    }\n\n    /**\n     * assemble RTCP Reception report block\n     * \n     * @return report data\n     */\n    private byte[] assembleRTCPReceptionReport() {\n        byte reportBlock[] = new byte[0];\n        RtpSource source = mRtcpSession.getMySource();\n\n        ReceptionReport rr = source.generateReceptionReport();\n        byte SSRC[] = RtcpPacketUtils.longToBytes(rr.getSsrc(), 4);\n        byte fraction_lost[] = RtcpPacketUtils.longToBytes((long) rr.getFractionLost(), 1);\n        byte pkts_lost[] = RtcpPacketUtils.longToBytes(rr.getCumulativeNumberOfPacketsLost(), 3);\n        byte last_seq[] = RtcpPacketUtils.longToBytes(\n                rr.getExtendedHighestSequenceNumberReceived(), 4);\n        byte jitter[] = RtcpPacketUtils.longToBytes(rr.getInterarrivalJitter(), 4);\n        byte lst[] = RtcpPacketUtils.longToBytes(rr.getLastSenderReport(), 4);\n        byte dlsr[] = RtcpPacketUtils.longToBytes(rr.getDelaySinceLastSenderReport(), 4);\n\n        reportBlock = RtcpPacketUtils.append(reportBlock, SSRC);\n        reportBlock = RtcpPacketUtils.append(reportBlock, fraction_lost);\n        reportBlock = RtcpPacketUtils.append(reportBlock, pkts_lost);\n        reportBlock = RtcpPacketUtils.append(reportBlock, last_seq);\n        reportBlock = RtcpPacketUtils.append(reportBlock, jitter);\n        reportBlock = RtcpPacketUtils.append(reportBlock, lst);\n        reportBlock = RtcpPacketUtils.append(reportBlock, dlsr);\n\n        return reportBlock;\n    }\n\n    /**\n     * Generate a RTCP report\n     * \n     * @return Vector\n     */\n    public Vector<RtcpSdesPacket> makereports() {\n        Vector<RtcpSdesPacket> packets = new Vector<RtcpSdesPacket>();\n\n        RtcpSdesPacket rtcpsdespacket = new RtcpSdesPacket(new RtcpSdesBlock[1]);\n        rtcpsdespacket.sdes[0] = new RtcpSdesBlock();\n        rtcpsdespacket.sdes[0].ssrc = mRtcpSession.SSRC;\n\n        Vector<RtcpSdesItem> vector = new Vector<RtcpSdesItem>();\n        vector.addElement(new RtcpSdesItem(1, RtpSource.getCname()));\n        rtcpsdespacket.sdes[0].items = new RtcpSdesItem[vector.size()];\n        vector.copyInto(rtcpsdespacket.sdes[0].items);\n\n        packets.addElement(rtcpsdespacket);\n        return packets;\n    }\n\n    /**\n     * Transmit a RTCP compound packet to the remote destination\n     * \n     * @param packet Compound packet to be sent\n     * @throws NetworkException\n     */\n    private void transmit(RtcpCompoundPacket packet) throws NetworkException {\n        // Prepare data to be sent\n        byte[] data = packet.mData;\n        if (packet.mOffset > 0) {\n            System.arraycopy(data, packet.mOffset, data = new byte[packet.mLength], 0,\n                    packet.mLength);\n        }\n\n        // Update statistics\n        mStats.numBytes += packet.mLength;\n        mStats.numPackets++;\n        mRtcpSession.updateavgrtcpsize(packet.mLength);\n        mRtcpSession.timeOfLastRTCPSent = mRtcpSession.currentTime();\n        // Send data over UDP\n        if (data == null) {\n            return;\n        }\n        mDatagramConnection.send(mRemoteAddress, mRemotePort, data);\n    }\n\n    /**\n     * Transmit a RTCP compound packet to the remote destination\n     * \n     * @param packet Compound packet to be sent\n     * @throws NetworkException\n     */\n    private void transmit(byte packet[]) throws NetworkException {\n        mStats.numBytes += packet.length;\n        mStats.numPackets++;\n        mRtcpSession.updateavgrtcpsize(packet.length);\n        mRtcpSession.timeOfLastRTCPSent = mRtcpSession.currentTime();\n        /* Send data over UDP */\n        mDatagramConnection.send(mRemoteAddress, mRemotePort, packet);\n    }\n\n    /**\n     * Returns the statistics of RTCP transmission\n     * \n     * @return Statistics\n     */\n    public RtcpStatisticsTransmitter getStatistics() {\n        return mStats;\n    }\n\n    /**\n     * Send a SDES packet\n     * \n     * @throws NetworkException\n     */\n    private void sendSdesPacket() throws NetworkException {\n        try {\n            // Create a report\n            Vector<RtcpSdesPacket> repvec = makereports();\n            RtcpPacket packets[] = new RtcpPacket[repvec.size()];\n            repvec.copyInto(packets);\n\n            // Create a RTCP compound packet\n            RtcpCompoundPacket cp = new RtcpCompoundPacket(packets);\n\n            // Assemble the RTCP packet\n            int i = cp.calcLength();\n            cp.assemble(i, false);\n\n            // Send the RTCP packet\n            transmit(cp);\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to send a SDES packet!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpPacketUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP utils.\n * \n * @author hlxn7157\n */\npublic class RtcpPacketUtils {\n\n    /**\n     * Convert 64 bit long to n bytes.\n     * \n     * @param data data\n     * @param n desired number of bytes to convert the long to.\n     * @return buffer\n     */\n    public static byte[] longToBytes(long data, int n) {\n        byte buf[] = new byte[n];\n        for (int i = n - 1; i >= 0; i--) {\n            buf[i] = (byte) data;\n            data = data >> 8;\n        }\n        return buf;\n    }\n\n    /**\n     * Append two byte arrays.\n     * \n     * @param pck1 first packet.\n     * @param pck2 second packet.\n     * @return concatenated packet.\n     */\n    public static byte[] append(byte[] pck1, byte[] pck2) {\n        byte packet[] = new byte[pck1.length + pck2.length];\n        for (int i = 0; i < pck1.length; i++)\n            packet[i] = pck1[i];\n        for (int i = 0; i < pck2.length; i++)\n            packet[i + pck1.length] = pck2[i];\n        return packet;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpReceiverReportPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RCTP RR packet\n * \n * @author jexa7410\n */\npublic class RtcpReceiverReportPacket extends RtcpPacket {\n    public int ssrc;\n    public RtcpReport[] reports;\n\n    public RtcpReceiverReportPacket(int i, RtcpReport[] rtcpreportblocks) {\n        ssrc = i;\n        reports = rtcpreportblocks;\n        if (rtcpreportblocks.length > 31)\n            throw new IllegalArgumentException(\"Too many reports\");\n    }\n\n    public RtcpReceiverReportPacket(RtcpPacket rtcppacket) {\n        super(rtcppacket);\n        mType = 201;\n    }\n\n    public void assemble(DataOutputStream dataoutputstream) throws IOException {\n        dataoutputstream.writeByte(128 + reports.length);\n        dataoutputstream.writeByte(201);\n        dataoutputstream.writeShort(1 + reports.length * 6);\n        dataoutputstream.writeInt(ssrc);\n        for (int i = 0; i < reports.length; i++) {\n            dataoutputstream.writeInt(reports[i].getSsrc());\n            dataoutputstream.writeInt((reports[i].getPacketsLost() & 0xffffff)\n                    + (reports[i].getFractionLost() << 24));\n            dataoutputstream.writeInt((int) reports[i].getLastSeq());\n            dataoutputstream.writeInt(reports[i].getJitter());\n            dataoutputstream.writeInt((int) reports[i].getLsr());\n            dataoutputstream.writeInt((int) reports[i].getDlsr());\n        }\n    }\n\n    public int calcLength() {\n        return 8 + reports.length * 24;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpReport.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP report\n * \n * @author jexa7410\n */\npublic class RtcpReport {\n    private final int mSsrc;\n    private final int mFractionLost;\n    private final int mPacketsLost;\n    private final long mLastSeq;\n    private final int mJitter;\n    private final long mLsr;\n    private final long mDlsr;\n\n    public RtcpReport(int ssrc, int fractionLost, int packetsLost, long lastSeq, int jitter,\n            long lsr, long dlsr) {\n        mSsrc = ssrc;\n        mFractionLost = fractionLost;\n        mPacketsLost = packetsLost;\n        mLastSeq = lastSeq;\n        mJitter = jitter;\n        mLsr = lsr;\n        mDlsr = dlsr;\n    }\n\n    public long getDlsr() {\n        return mDlsr;\n    }\n\n    public int getFractionLost() {\n        return mFractionLost;\n    }\n\n    public int getJitter() {\n        return mJitter;\n    }\n\n    public long getLsr() {\n        return mLsr;\n    }\n\n    public int getPacketsLost() {\n        return mPacketsLost;\n    }\n\n    public int getSsrc() {\n        return mSsrc;\n    }\n\n    public long getLastSeq() {\n        return mLastSeq;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpSdesBlock.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RCTP SDES block\n * \n * @author jexa7410\n */\npublic class RtcpSdesBlock {\n    public int ssrc;\n\n    public RtcpSdesItem[] items;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpSdesItem.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\n/**\n * RCTP SDES item\n * \n * @author jexa7410\n */\npublic class RtcpSdesItem {\n    public int type;\n    public byte[] data;\n\n    public RtcpSdesItem() {\n    }\n\n    public RtcpSdesItem(int i, String string) {\n        type = i;\n        data = string.getBytes(UTF8);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpSdesPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RCTP SDES packet\n * \n * @author jexa7410\n */\npublic class RtcpSdesPacket extends RtcpPacket {\n\n    public RtcpSdesBlock sdes[];\n\n    public RtcpSdesPacket(RtcpPacket parent) {\n        super(parent);\n        super.mType = 202;\n    }\n\n    public RtcpSdesPacket(RtcpSdesBlock sdes[]) {\n        this.sdes = sdes;\n        if (sdes.length > 31) {\n            throw new IllegalArgumentException(\"Too many SDESs\");\n        }\n    }\n\n    public int calcLength() {\n        int len = 4;\n        for (int i = 0; i < sdes.length; i++) {\n            int sublen = 5;\n            for (int j = 0; j < sdes[i].items.length; j++) {\n                sublen += 2 + sdes[i].items[j].data.length;\n            }\n\n            sublen = sublen + 3 & -4;\n            len += sublen;\n        }\n\n        return len;\n    }\n\n    public void assemble(DataOutputStream out) throws IOException {\n        out.writeByte(128 + sdes.length);\n        out.writeByte(202);\n        out.writeShort(calcLength() - 4 >> 2);\n        for (int i = 0; i < sdes.length; i++) {\n            out.writeInt(sdes[i].ssrc);\n            int sublen = 0;\n            for (int j = 0; j < sdes[i].items.length; j++) {\n                out.writeByte(sdes[i].items[j].type);\n                out.writeByte(sdes[i].items[j].data.length);\n                out.write(sdes[i].items[j].data);\n                sublen += 2 + sdes[i].items[j].data.length;\n            }\n\n            for (int j = (sublen + 4 & -4) - sublen; j > 0; j--) {\n                out.writeByte(0);\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpSenderReportPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RCTP SR packet\n * \n * @author jexa7410\n */\npublic class RtcpSenderReportPacket extends RtcpPacket {\n    public int ssrc;\n    public long ntptimestampmsw;\n    public long ntptimestamplsw;\n    public long rtptimestamp;\n    public long packetcount;\n    public long octetcount;\n    public RtcpReport[] reports;\n\n    public RtcpSenderReportPacket(int i, RtcpReport[] rtcpreportblocks) {\n        ssrc = i;\n        reports = rtcpreportblocks;\n        if (rtcpreportblocks.length > 31)\n            throw new IllegalArgumentException(\"Too many reports\");\n    }\n\n    public RtcpSenderReportPacket(RtcpPacket rtcppacket) {\n        super(rtcppacket);\n        mType = 200;\n    }\n\n    public void assemble(DataOutputStream dataoutputstream) throws IOException {\n        dataoutputstream.writeByte(128 + reports.length);\n        dataoutputstream.writeByte(200);\n        dataoutputstream.writeShort(6 + reports.length * 6);\n        dataoutputstream.writeInt(ssrc);\n        dataoutputstream.writeInt((int) ntptimestampmsw);\n        dataoutputstream.writeInt((int) ntptimestamplsw);\n        dataoutputstream.writeInt((int) rtptimestamp);\n        dataoutputstream.writeInt((int) packetcount);\n        dataoutputstream.writeInt((int) octetcount);\n        for (int i = 0; i < reports.length; i++) {\n            dataoutputstream.writeInt(reports[i].getSsrc());\n            dataoutputstream.writeInt((reports[i].getPacketsLost())\n                    + (reports[i].getFractionLost() << 24));\n            dataoutputstream.writeInt((int) reports[i].getLastSeq());\n            dataoutputstream.writeInt(reports[i].getJitter());\n            dataoutputstream.writeInt((int) reports[i].getLsr());\n            dataoutputstream.writeInt((int) reports[i].getDlsr());\n        }\n    }\n\n    public int calcLength() {\n        return 28 + reports.length * 24;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.util.Random;\n\n/**\n * RTCP Session Information\n * \n * @author hlxn7157\n */\npublic class RtcpSession {\n\n    /**\n     * Default minimum time between RTCP message (ms)\n     */\n    private static final int DEFAULT_RTCP_MIN_TIME = 5000;\n\n    /**\n     * Fraction of RTCP sender messages\n     */\n    private static final double RTCP_SENDER_BW_FRACTION = 0.25;\n\n    /**\n     * Fraction of RTCP receiver messages\n     */\n    private static final double RTCP_RCVR_BW_FRACTION = 0.75;\n\n    /**\n     * Bandwidth\n     */\n    private double bandwidth;\n\n    /**\n     * RTCP bandwidth\n     */\n    private double rtcpBandwidth;\n\n    /**\n     * Minimum time between RTCP message (ms)\n     */\n    private int rtcp_min_time = DEFAULT_RTCP_MIN_TIME;\n\n    /**\n     * RTCP average packet size\n     */\n    private int avgrtcpsize;\n\n    /**\n     * Number of members\n     */\n    private int members;\n\n    /**\n     * Number of senders\n     */\n    private int senders;\n\n    /**\n     * Initial state\n     */\n    private boolean initial;\n\n    /**\n     * Is a sender\n     */\n    private boolean isSender;\n\n    /**\n     * True if session instantiator requested a close.\n     */\n    public boolean isByeRequested = false;\n\n    /**\n     * Time this source last sent an RTP Packet\n     */\n    public double timeOfLastRTPSent = 0;\n\n    /**\n     * The last time an RTCP packet was transmitted.\n     */\n    public double timeOfLastRTCPSent = 0;\n\n    /**\n     * The startup time for the application.\n     */\n    public long appStartupTime;\n\n    /**\n     * Ramdomized time interval for next RTCP transmission.\n     */\n    public double T = 0;\n\n    /**\n     * Synchronization Source identifier for this source.\n     */\n    public int SSRC;\n\n    /**\n     * RTP Source\n     */\n    private RtpSource rtpSource;\n\n    /**\n     * The current time.\n     */\n    public double tc = 0;\n\n    /**\n     * Total Number of RTP data packets sent out by this source since starting transmission.\n     */\n    public long packetCount;\n\n    /**\n     * Total Number of payload octets (i.e not including header or padding) sent out by this source\n     * since starting transmission.\n     */\n    public long octetCount;\n\n    /**\n     * Initialize the Random Number Generator.\n     */\n    private Random rnd = new Random();\n\n    /**\n     * Constructor.\n     * \n     * @param isSender is sender\n     * @param bandwidth bandwidth (can set 16000 (16kops 128kbps))\n     */\n    public RtcpSession(boolean isSender, double bandwidth) {\n        this.isSender = isSender;\n        members = 2;\n        senders = 1;\n        this.bandwidth = bandwidth;\n        rtcpBandwidth = 0.05 * bandwidth;\n        avgrtcpsize = 128;\n        initial = true;\n\n        // Initialize the Session level variables\n        appStartupTime = currentTime();\n        timeOfLastRTCPSent = appStartupTime;\n        tc = appStartupTime;\n        SSRC = rnd.nextInt();\n        packetCount = 0;\n        octetCount = 0;\n\n        // Init RTP source\n        rtpSource = new RtpSource(SSRC);\n    }\n\n    /**\n     * Setter of members\n     * \n     * @param members no of members\n     */\n    public void setMembers(int members) {\n        this.members = members;\n    }\n\n    /**\n     * Setter of senders\n     * \n     * @param senders no of senders\n     */\n    public void setSenders(int senders) {\n        this.senders = senders;\n    }\n\n    /**\n     * Get the interval of RTCP message\n     * \n     * @return interval\n     */\n    public double getReportInterval() {\n        // Interval\n        double t;\n        // no. of members for computation\n        double n;\n\n        // initial half the min delay for quicker notification\n        if (initial) {\n            initial = false;\n            rtcp_min_time /= 2;\n        }\n\n        // If there were active senders, give them at least a minimum share of\n        // the RTCP bandwidth. Otherwise all participants share the RTCP\n        // bandwidth equally.\n        n = members;\n        if (senders > 0 && senders < members * RTCP_SENDER_BW_FRACTION) {\n            if (isSender) {\n                rtcpBandwidth *= RTCP_SENDER_BW_FRACTION;\n                n = senders;\n            } else {\n                rtcpBandwidth *= RTCP_RCVR_BW_FRACTION;\n                n -= senders;\n            }\n        }\n\n        // get interval\n        t = avgrtcpsize * n / bandwidth;\n        if (t < rtcp_min_time)\n            t = rtcp_min_time;\n\n        // add noise to avoid traffic bursts\n        t *= (Math.random() + 0.5);\n\n        T = t;\n        return t;\n    }\n\n    /**\n     * Update the average RTCP packet size\n     * \n     * @param size\n     */\n    public void updateavgrtcpsize(int size) {\n        avgrtcpsize = (int) (0.0625 * size + 0.9375 * avgrtcpsize);\n    }\n\n    /**\n     * Returns a self source object.\n     * \n     * @return My source object.\n     */\n    public RtpSource getMySource() {\n        return rtpSource;\n    }\n\n    /**\n     * Returns current time from the System.currentTimeMillis function.\n     * \n     * @return The current time.\n     */\n    public long currentTime() {\n        long timestamp = System.currentTimeMillis();\n        tc = timestamp;\n        return timestamp;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpStatisticsReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP packet statistics receiver\n * \n * @author jexa7410\n */\npublic class RtcpStatisticsReceiver {\n    /**\n     * Number of RTCP packets received\n     */\n    public int numRtcpPkts = 0;\n\n    /**\n     * Number of RTCP bytes received\n     */\n    public int numRtcpBytes = 0;\n\n    /**\n     * Number of RTCP SR packets received\n     */\n    public int numSrPkts = 0;\n\n    /**\n     * Number of bad RTCP packets received\n     */\n    public int numBadRtcpPkts = 0;\n\n    /**\n     * Number of unknown RTCP packets received\n     */\n    public int numUnknownTypes = 0;\n\n    /**\n     * Number of malformed RTCP packets received\n     */\n    public int numMalformedRtcpPkts = 0;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtcpStatisticsTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP packet statistics transmitter\n * \n * @author jexa7410\n */\npublic class RtcpStatisticsTransmitter {\n    /**\n     * Total number of packets sent\n     */\n    public int numPackets = 0;\n\n    /**\n     * Total number of bytes sent\n     */\n    public int numBytes = 0;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpExtensionHeader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * Represent a RTP extension header\n * \n * @author Deutsche Telekom\n */\npublic class RtpExtensionHeader implements Iterable<RtpExtensionHeader.ExtensionElement> {\n    /**\n     * Allowed extension header id for RCS video orientation\n     */\n    public static final int RTP_EXTENSION_HEADER_ID = ((0xbe << 8) | 0xde);\n\n    /**\n     * elements list\n     */\n    private List<RtpExtensionHeader.ExtensionElement> elements = new ArrayList<RtpExtensionHeader.ExtensionElement>(\n            0);\n\n    /**\n     * Default constructor\n     */\n    public RtpExtensionHeader() {\n    }\n\n    /**\n     * Add header element.\n     * \n     * @param id Element id\n     * @param data Element data\n     */\n    public void addElement(int id, byte[] data) {\n        elements.add(new ExtensionElement(id, data));\n    }\n\n    /**\n     * Get ExtensionHeader element by id.\n     * \n     * @param id ID to search for\n     * @return Element data\n     */\n    public ExtensionElement getElementById(int id) {\n        for (ExtensionElement element : elements) {\n            if (element.id == id) {\n                return element;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Counts the number of elements in the header\n     * \n     * @return Number of elements\n     */\n    public int elementsCount() {\n        return elements.size();\n    }\n\n    @Override\n    public Iterator<ExtensionElement> iterator() {\n        return this.elements.iterator();\n    }\n\n    /**\n     * Extension Header Element\n     */\n    public static class ExtensionElement {\n        public final int id;\n        public final byte[] data;\n\n        public ExtensionElement(int id, byte[] data) {\n            this.id = id;\n            this.data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Packet;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * Abstract RTP packet\n * \n * @author jexa7410\n * @author Deutsche Telekom\n */\npublic class RtpPacket extends Packet {\n    public Packet base;\n    public int marker;\n    public int payloadType;\n    public int seqnum;\n    public long timestamp;\n    public int ssrc;\n    public int payloadoffset;\n    public int payloadlength;\n    public boolean extension;\n    public RtpExtensionHeader extensionHeader;\n\n    public RtpPacket() {\n        super();\n    }\n\n    public RtpPacket(Packet packet) {\n        super(packet);\n\n        base = packet;\n    }\n\n    public void assemble(int length) throws NetworkException {\n        try {\n            this.mLength = length;\n            this.mOffset = 0;\n\n            ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(length);\n            DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);\n            if (extension) {\n                dataoutputstream.writeByte(144);\n            } else {\n                dataoutputstream.writeByte(128);\n            }\n\n            int i = payloadType;\n            if (marker == 1) {\n                i = payloadType | 0x80;\n            }\n            dataoutputstream.writeByte((byte) i);\n            dataoutputstream.writeShort(seqnum);\n            dataoutputstream.writeInt((int) timestamp);\n            dataoutputstream.writeInt(ssrc);\n\n            if (extension && extensionHeader != null) {\n                // Write extension header id\n                dataoutputstream.writeShort(RtpExtensionHeader.RTP_EXTENSION_HEADER_ID);\n                // Write extension header length\n                dataoutputstream.writeShort(extensionHeader.elementsCount());\n                // Write extension element. For now we will only support the orientation element\n                for (RtpExtensionHeader.ExtensionElement element : extensionHeader) {\n                    int orientationElement = (((((element.id & 0xff) << 4) | ((element.data.length - 1) & 0xff)) << 8) | (element.data[0] & 0xff)) << 16;\n                    dataoutputstream.writeInt(orientationElement);\n                }\n            }\n            dataoutputstream.write(base.mData, base.mOffset, base.mLength);\n            mData = bytearrayoutputstream.toByteArray();\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to write assemble data!\", e);\n        }\n    }\n\n    public int calcLength() {\n        return payloadlength + 12;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpPacketReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.platform.network.DatagramConnection;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.FifoBuffer;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.util.concurrent.TimeoutException;\n\n/**\n * RTP packet receiver\n * \n * @author jexa7410\n */\npublic class RtpPacketReceiver extends Thread implements Closeable {\n    /**\n     * Statistics\n     */\n    private RtpStatisticsReceiver mStats = new RtpStatisticsReceiver();\n\n    /**\n     * Datagram connection\n     */\n    public DatagramConnection mDatagramConnection;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession mRtcpSession;\n\n    /**\n     * Fifo buffer for received packet\n     */\n    private FifoBuffer mBuffer = new FifoBuffer();\n\n    /**\n     * Max size for the fifo\n     */\n    private static final int FIFO_MAX_NUMBER = 100;\n\n    /**\n     * Number of element to clean in the fifo\n     */\n    private static final int FIFO_CLEAN_NUMBER = 20;\n\n    /**\n     * Signals that thread is interrupted\n     */\n    private boolean mInterrupted;\n\n    /**\n     * Last sequence number\n     */\n    private int mLastSeqnum;\n\n    /**\n     * timeout\n     */\n    private int mTimeout;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(RtpPacketReceiver.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param port Listening port\n     * @param rtcpSession\n     * @param socketTimeout\n     * @throws IOException\n     */\n    public RtpPacketReceiver(int port, RtcpSession rtcpSession, int socketTimeout)\n            throws IOException {\n        super();\n\n        mRtcpSession = rtcpSession;\n        mTimeout = socketTimeout;\n        // Create the UDP server\n        mDatagramConnection = NetworkFactory.getFactory().createDatagramConnection(socketTimeout);\n        mDatagramConnection.open(port);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"RTP receiver created on port \" + port);\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param port Listenning port\n     * @param rtcpSession\n     * @throws IOException\n     */\n    public RtpPacketReceiver(int port, RtcpSession rtcpSession) throws IOException {\n        this(port, rtcpSession, 0);\n    }\n\n    /**\n     * Close the receiver\n     */\n    public void close() {\n        mInterrupted = true;\n        interrupt();\n        CloseableUtils.tryToClose(mDatagramConnection);\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"RTP Receiver processing is started\");\n        }\n        try {\n            while (mDatagramConnection != null) {\n                // Wait a new packet\n                byte[] data = mDatagramConnection.receive();\n\n                if (data.length >= 12) {\n                    // Drop empty packet (payload 20)\n                    int payloadType = (byte) ((data[1] & 0xff) & 0x7f);\n                    if (payloadType != 20) {\n                        // Drop too old packet\n                        int seqnum = (char) ((data[2] << 8) | (data[3] & 0xff));\n                        if (seqnum > mLastSeqnum - 10) {\n                            // Clean the FIFO if full\n                            if (mBuffer.size() >= FIFO_MAX_NUMBER) {\n                                mBuffer.clean(FIFO_CLEAN_NUMBER);\n                            }\n                            mBuffer.addObject(data);\n                            mLastSeqnum = seqnum;\n                        } else {\n                            mStats.numBadRtpPkts++;\n                        }\n                    }\n                }\n            }\n        } catch (NetworkException e) {\n            if (!mInterrupted) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Datagram socket server failed!\", e);\n        }\n    }\n\n    /**\n     * Read a RTP packet (blocking method)\n     * \n     * @return RTP packet\n     * @throws TimeoutException\n     */\n    public RtpPacket readRtpPacket() throws TimeoutException {\n        // Get a new packet in FIFO\n        byte[] data = (byte[]) mBuffer.getObject(mTimeout);\n        if (data == null) {\n            throw new TimeoutException(\"Unable to fetch packet from FIFO queue!\");\n        }\n\n        // Parse the RTP packet\n        RtpPacket pkt = parseRtpPacket(data);\n\n        if (pkt != null) {\n            // Update statistics\n            mStats.numPackets++;\n            mStats.numBytes += data.length;\n\n            RtpSource s = mRtcpSession.getMySource();\n            s.setSsrc(pkt.ssrc);\n            s.activeSender = true;\n            s.receiveRtpPacket(pkt);\n            pkt.seqnum = s.generateExtendedSequenceNumber(pkt.seqnum);\n\n            return pkt;\n        }\n        return readRtpPacket();\n    }\n\n    /**\n     * Parse the RTP packet\n     * \n     * @param data RTP packet not yet parsed\n     * @return RTP packet\n     */\n    private RtpPacket parseRtpPacket(byte[] data) {\n        RtpPacket packet = new RtpPacket();\n        // Read RTP packet length\n        packet.mLength = data.length;\n\n        // Set received timestamp\n        packet.mReceivedAt = System.currentTimeMillis();\n\n        // Read extension bit\n        packet.extension = (data[0] & 0x10) > 0;\n\n        // Read marker\n        if ((byte) ((data[1] & 0xff) & 0x80) == (byte) 0x80) {\n            packet.marker = 1;\n        } else {\n            packet.marker = 0;\n        }\n\n        // Read payload type\n        packet.payloadType = (byte) ((data[1] & 0xff) & 0x7f);\n\n        // Read sequence number (it's a unsigned 16 bit value. Because Java only supports\n        // signed values for int and short we use char to do the correct conversion.)\n        packet.seqnum = (char) ((data[2] << 8) | (data[3] & 0xff));\n\n        // Read timestamp\n        packet.timestamp = (((data[4] & 0xff) << 24) | ((data[5] & 0xff) << 16)\n                | ((data[6] & 0xff) << 8) | (data[7] & 0xff));\n\n        // Read SSRC\n        packet.ssrc = (((data[8] & 0xff) << 24) | ((data[9] & 0xff) << 16)\n                | ((data[10] & 0xff) << 8) | (data[11] & 0xff));\n\n        // Extract the extension header\n        if (packet.extension) {\n            int dataId = 11;\n            int extensionHeaderId = ((data[++dataId] & 0xff) << 8) | (data[++dataId] & 0xff);\n            int length = ((data[++dataId] & 0xff) << 8) | (data[++dataId] & 0xff);\n\n            if (extensionHeaderId == RtpExtensionHeader.RTP_EXTENSION_HEADER_ID) {\n                extractExtensionHeader(data, length, dataId, packet);\n            }\n\n            // increment payload offset = RtpHeader size (12) + Extension Header ID (2) + Header\n            // Length (2) +\n            // elements * 4 (32 bits each) + 1 (to set at correct index)\n            packet.payloadoffset = 16 + length * 4;\n        } else {\n            packet.payloadoffset = 12;\n        }\n        packet.payloadlength = packet.mLength - packet.payloadoffset;\n        packet.mData = new byte[packet.payloadlength];\n        System.arraycopy(data, packet.payloadoffset, packet.mData, 0, packet.payloadlength);\n\n        return packet;\n    }\n\n    /**\n     * Returns the statistics of RTP reception\n     * \n     * @return Statistics\n     */\n    public RtpStatisticsReceiver getRtpReceptionStats() {\n        return mStats;\n    }\n\n    /**\n     * Returns the DatagramConnection of RTP\n     * \n     * @return DatagramConnection\n     */\n    public DatagramConnection getConnection() {\n        return mDatagramConnection;\n    }\n\n    /**\n     * Extract Extension Header\n     * \n     * @param data\n     * @param length\n     * @param dataId\n     * @param packet\n     */\n    private void extractExtensionHeader(byte[] data, int length, int dataId, RtpPacket packet) {\n        byte[] extensionHeaderData = new byte[length * 4];\n        System.arraycopy(data, ++dataId, extensionHeaderData, 0, extensionHeaderData.length);\n        packet.extensionHeader = new RtpExtensionHeader();\n\n        int i = 0;\n        while (packet.extensionHeader.elementsCount() < length) {\n            byte idAndLength = extensionHeaderData[i];\n            if (idAndLength == 0x00) {\n                // its a padding byte, skip it\n                i = i + 1;\n                continue;\n            }\n\n            int elementId = (idAndLength & 0xf0) >>> 4;\n\n            // Each extension element id must have a value between 1 and 14 inclusive\n            if (elementId > 0 && elementId < 15) {\n                int elementLength = (idAndLength & 0x0f);\n                byte[] elementData = new byte[elementLength + 1];\n                System.arraycopy(extensionHeaderData, i + 1, elementData, 0, elementData.length);\n                packet.extensionHeader.addElement(elementId, elementData);\n                i = i + elementData.length + 1;\n            } else {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpPacketTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Packet;\nimport com.gsma.rcs.platform.network.DatagramConnection;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * RTP packet transmitter\n * \n * @author jexa7410\n */\npublic class RtpPacketTransmitter implements Closeable {\n\n    /**\n     * Sequence number\n     */\n    private int seqNumber = 0;\n\n    /**\n     * Remote address\n     */\n    private String remoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int remotePort;\n\n    /**\n     * Statistics\n     */\n    private RtpStatisticsTransmitter stats = new RtpStatisticsTransmitter();\n\n    /**\n     * Datagram connection\n     */\n    private DatagramConnection datagramConnection = null;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * The logger\n     */\n    private final Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession RTCP session\n     * @throws IOException\n     */\n    public RtpPacketTransmitter(String address, int port, RtcpSession rtcpSession)\n            throws IOException {\n        this.remoteAddress = address;\n        this.remotePort = port;\n        this.rtcpSession = rtcpSession;\n\n        datagramConnection = NetworkFactory.getFactory().createDatagramConnection();\n        datagramConnection.open();\n\n        if (logger.isActivated()) {\n            logger.debug(\"RTP transmitter connected to \" + remoteAddress + \":\" + remotePort);\n        }\n    }\n\n    /**\n     * Constructor used for symetric RTP\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession RTCP session\n     * @param connection Connection from RTP receiver\n     * @throws IOException\n     */\n    public RtpPacketTransmitter(String address, int port, RtcpSession rtcpSession,\n            DatagramConnection connection) throws IOException {\n        this.remoteAddress = address;\n        this.remotePort = port;\n        this.rtcpSession = rtcpSession;\n\n        if (connection != null) {\n            this.datagramConnection = connection;\n        } else {\n            this.datagramConnection = NetworkFactory.getFactory().createDatagramConnection();\n            this.datagramConnection.open();\n        }\n\n        if (logger.isActivated()) {\n            logger.debug(\"RTP transmitter connected to \" + remoteAddress + \":\" + remotePort);\n        }\n    }\n\n    /**\n     * Close the transmitter\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        // Close the datagram connection\n        if (datagramConnection != null) {\n            datagramConnection.close();\n        }\n        if (logger.isActivated()) {\n            logger.debug(\"RTP transmitter closed\");\n        }\n    }\n\n    /**\n     * Send a RTP packet\n     * \n     * @param buffer Input buffer\n     * @throws NetworkException\n     */\n    public void sendRtpPacket(Buffer buffer) throws NetworkException {\n        // Build a RTP packet\n        RtpPacket packet = buildRtpPacket(buffer);\n        if (packet == null) {\n            return;\n        }\n\n        // Assemble RTP packet\n        int size = packet.calcLength();\n        packet.assemble(size);\n\n        // Send the RTP packet to the remote destination\n        transmit(packet);\n    }\n\n    /**\n     * Build a RTP packet\n     * \n     * @param buffer Input buffer\n     * @return RTP packet\n     */\n    private RtpPacket buildRtpPacket(Buffer buffer) {\n        byte data[] = (byte[]) buffer.getData();\n        if (data == null) {\n            return null;\n        }\n        Packet packet = new Packet();\n        packet.mData = data;\n        packet.mOffset = 0;\n        packet.mLength = buffer.getLength();\n\n        RtpPacket rtppacket = new RtpPacket(packet);\n        if (buffer.isRTPMarkerSet()) {\n            rtppacket.marker = 1;\n        } else {\n            rtppacket.marker = 0;\n        }\n\n        rtppacket.payloadType = buffer.getFormat().getPayload();\n        rtppacket.seqnum = seqNumber++;\n        rtppacket.timestamp = buffer.getTimestamp();\n        rtppacket.ssrc = rtcpSession.SSRC;\n        rtppacket.payloadoffset = buffer.getOffset();\n        rtppacket.payloadlength = buffer.getLength();\n        if (buffer.getVideoOrientation() != null) {\n            rtppacket.extension = true;\n            rtppacket.extensionHeader = new RtpExtensionHeader();\n            rtppacket.extensionHeader.addElement(buffer.getVideoOrientation().getHeaderId(),\n                    new byte[] {\n                        buffer.getVideoOrientation().getVideoOrientation()\n                    });\n        }\n        return rtppacket;\n    }\n\n    /**\n     * Transmit a RTCP compound packet to the remote destination\n     * \n     * @param packet RTP packet\n     * @throws NetworkException\n     */\n    private void transmit(Packet packet) throws NetworkException {\n        byte[] data = packet.mData;\n        if (packet.mOffset > 0) {\n            System.arraycopy(data, packet.mOffset, data = new byte[packet.mLength], 0,\n                    packet.mLength);\n        }\n        stats.numBytes += packet.mLength;\n        stats.numPackets++;\n        if (data == null) {\n            return;\n        }\n        /* Send data over UDP */\n        datagramConnection.send(remoteAddress, remotePort, data);\n        RtpSource s = rtcpSession.getMySource();\n        s.activeSender = true;\n        rtcpSession.timeOfLastRTPSent = rtcpSession.currentTime();\n        rtcpSession.packetCount++;\n        rtcpSession.octetCount += data.length;\n    }\n\n    /**\n     * Returns the statistics of RTP transmission\n     * \n     * @return Statistics\n     */\n    public RtpStatisticsTransmitter getStatistics() {\n        return stats;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpSource.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTP source\n * \n * @author jexa7410\n * @author Deutsche Telekom\n */\npublic class RtpSource {\n    /**\n     * RFC 3550: The dropout parameter MAX_DROPOUT should be a small fraction of the 16-bit sequence\n     * number space to give a reasonable probability that new sequence numbers after a restart will\n     * not fall in the acceptable range for sequence numbers from before the restart.\n     */\n    private static final int MAX_DROPOUT = 3000;\n\n    /**\n     * RFC 3550: the sequence number is considered valid if it is no more than MAX_DROPOUT ahead of\n     * maxSeq nor more than MAX_MISORDER behind\n     */\n    private static final int MAX_MISORDER = 100;\n\n    /**\n     * RFC 3550: RTP sequence number module\n     */\n    private static final int RTP_SEQ_MOD = (1 << 16);\n\n    /**\n     * CNAME value\n     */\n    private static String sCname = \"anonymous@127.0.0.1\";\n\n    /**\n     * Source is not valid until MIN_SEQUENTIAL packets with sequential sequence numbers have been\n     * received.\n     */\n    private static int MIN_SEQUENCIAL = 0;\n\n    /**\n     * Is this source and ActiveSender.\n     */\n    public boolean activeSender;\n\n    /**\n     * Source description\n     */\n    public int ssrc;\n\n    /**\n     * Highest Sequence number received from this source\n     */\n    private int maxSeq;\n\n    /**\n     * Keep track of the wrapping around of RTP sequence numbers, since RTP Seq No. are only 16 bits\n     */\n    private int cycles;\n\n    /**\n     * Sequence Number of the first RTP packet received from this source\n     */\n    private int baseSeq;\n\n    /**\n     * Last 'bad' sequence number + 1\n     */\n    private int badSeq;\n\n    /**\n     * Sequence packets till source is valid\n     */\n    private int probation;\n\n    /**\n     * Packets received\n     */\n    private int received;\n\n    /**\n     * Packet expected at last interval\n     */\n    private int expectedPrior;\n\n    /**\n     * Packet received at last interval\n     */\n    private int receivedPrior;\n\n    /**\n     * Estimated jitter.\n     */\n    public long jitter;\n\n    /**\n     * Last SR Packet timestamp\n     */\n    private long lastSenderReport;\n\n    /**\n     * Constructor requires an SSRC for it to be a valid source. The constructor initializes all the\n     * source class members to a default value\n     * \n     * @param sourceSSRC SSRC of the new source\n     */\n    RtpSource(int sourceSSRC) {\n        ssrc = sourceSSRC;\n        lastSenderReport = 0;\n        probation = MIN_SEQUENCIAL;\n        jitter = 0;\n        initSeq(-1);\n    }\n\n    /**\n     * Generates the extended sequence number.\n     * \n     * @param seq Original sequence number\n     * @return Extended sequence number\n     */\n    public int generateExtendedSequenceNumber(int seq) {\n        return seq + (RTP_SEQ_MOD * cycles);\n    }\n\n    /**\n     * Updates the statistics related to Sender Reports. Should be invoked when a RTCP Sender Report\n     * is received.\n     * \n     * @param srp Sender Report\n     */\n    public void receivedSenderReport(RtcpSenderReportPacket srp) {\n        // RFC 3550: last SR timestamp (LSR): 32 bits - The middle 32 bits out\n        // of 64 in the NTP timestamp received as part of the most recent RTCP\n        // sender report\n        lastSenderReport = (((srp.ntptimestampmsw << 32) | srp.ntptimestamplsw) & 0x0000ffffffff0000L) >>> 16;\n    }\n\n    /**\n     * Updates the statistics related to RTP packets Should be invoked every time this source\n     * receive an RTP Packet .\n     * \n     * @param packet\n     */\n    public void receiveRtpPacket(RtpPacket packet) {\n        if (baseSeq == -1) {\n            // First packet received\n            initSeq(packet.seqnum);\n        }\n        updateSeq(packet.seqnum);\n    }\n\n    /**\n     * Generate the Reception Report\n     * \n     * @return ReceptionReport\n     */\n    public ReceptionReport generateReceptionReport() {\n        ReceptionReport report = new ReceptionReport(ssrc);\n        updateReceptionReport(report);\n        return report;\n    }\n\n    /**\n     * Updates the reception report with latest data. The statistics calculation is based on the\n     * algorithms present in RFC 3550\n     * \n     * @param report Reception report to update\n     */\n    public void updateReceptionReport(ReceptionReport report) {\n        // Calculate the number of packets lost\n        int extendedMax = getExtendedSequenceNumber();\n        int expected = extendedMax - baseSeq + 1;\n        report.setCumulativeNumberOfPacketsLost(expected - received);\n\n        // TODO : Calculate the delay after last sender report received\n        report.setDelaySinceLastSenderReport(0);\n        report.setExtendedHighestSequenceNumberReceived(getExtendedSequenceNumber());\n\n        // Calculate the fraction lost\n        long expectedInterval = expected - expectedPrior;\n        expectedPrior = expected;\n        int receivedInterval = received - receivedPrior;\n        receivedPrior = received;\n        long lostInterval = expectedInterval - receivedInterval;\n        if (expectedInterval == 0 || lostInterval <= 0) {\n            report.setFractionLost(0);\n        } else {\n            report.setFractionLost((lostInterval << 8) / (double) expectedInterval);\n        }\n\n        // TODO : Calculate jitter\n        report.setInterarrivalJitter(0);\n\n        report.setLastSenderReport(lastSenderReport);\n        report.setSsrc(ssrc);\n    }\n\n    /**\n     * Set the Source description\n     * \n     * @param ssrc\n     */\n    public void setSsrc(int ssrc) {\n        this.ssrc = ssrc;\n    }\n\n    /**\n     * Initiate sequence. RFC 3550\n     * \n     * @param sequenceNumber\n     */\n    private void initSeq(int sequenceNumber) {\n        baseSeq = sequenceNumber;\n        maxSeq = sequenceNumber;\n        badSeq = RTP_SEQ_MOD + 1; // so seq == bad_seq is false\n        cycles = 0;\n        received = 0;\n        receivedPrior = 0;\n        expectedPrior = 0;\n    }\n\n    /**\n     * Ensures that a source is declared valid only after MIN_SEQUENTIAL packets have been received\n     * in sequence.It also validates the sequence number seq of a newly received packet and updates\n     * the sequence state. Algorithm in the RFC 3550 (Appendix A.1)\n     * \n     * @param seq Sequence Number\n     */\n    private int updateSeq(int seq) {\n        long udelta = seq - maxSeq;\n\n        // Source is not valid until MIN_SEQUENTIAL packets with sequential\n        // sequence numbers have been received.\n        if (probation > 0) {\n            if (seq == maxSeq + 1) {\n                probation--;\n                maxSeq = seq;\n                if (probation == 0) {\n                    initSeq(seq);\n                    received++;\n                    return 1;\n                }\n            } else {\n                probation = MIN_SEQUENCIAL - 1;\n                maxSeq = seq;\n                return 1;\n            }\n            return 0;\n        } else if (udelta < MAX_DROPOUT) {\n            // in order, with permissible gap\n            if (seq < maxSeq && (udelta >= (MAX_MISORDER * -1))) {\n                // late packet within interval\n                received++;\n                return 1;\n            }\n\n            if (seq < maxSeq) {\n                // Sequence number wrapped - count another 64K cycle.\n                cycles++;\n            }\n            maxSeq = seq;\n        } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {\n            // the sequence number made a very large jump\n            if (seq == badSeq) {\n                // Two sequential packets -- assume that the other side\n                // restarted without telling us so just re-sync\n                // (i.e., pretend this was the first packet).\n                initSeq(seq);\n            } else {\n                badSeq = (seq + 1) & (RTP_SEQ_MOD - 1);\n                return 0;\n            }\n        } else {\n            // duplicate or reordered packet\n        }\n        received++;\n        return 1;\n    }\n\n    /**\n     * Return the extended sequence number for a source considering that sequences cycle.\n     * \n     * @return Extended sequence number\n     */\n    private int getExtendedSequenceNumber() {\n        return generateExtendedSequenceNumber(maxSeq);\n    }\n\n    /**\n     * Gets Cname\n     * \n     * @return Cname\n     */\n    public static String getCname() {\n        return sCname;\n    }\n\n    /**\n     * Sets Cname\n     * \n     * @param cname\n     */\n    public static void setCname(String cname) {\n        sCname = cname;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpStatisticsReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTP statistics receiver\n * \n * @author jexa7410\n */\npublic class RtpStatisticsReceiver {\n    /**\n     * Number of RTP packets received\n     */\n    public int numPackets = 0;\n\n    /**\n     * Number of RTP bytes received\n     */\n    public int numBytes = 0;\n\n    /**\n     * Number of bad RTP packet received\n     */\n    public int numBadRtpPkts = 0;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/core/RtpStatisticsTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTP statistics transmitter\n * \n * @author jexa7410\n */\npublic class RtpStatisticsTransmitter {\n    /**\n     * Total number of packets sent\n     */\n    public int numPackets = 0;\n\n    /**\n     * Total number of bytes sent\n     */\n    public int numBytes = 0;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpApplicationEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpAppPacket;\n\n/**\n * RTCP application event\n * \n * @author jexa7410\n */\npublic class RtcpApplicationEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP APP packet\n     */\n    public RtcpApplicationEvent(RtcpAppPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpByeEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpByePacket;\n\n/**\n * RTCP bye event\n * \n * @author jexa7410\n */\npublic class RtcpByeEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP BYE packet\n     */\n    public RtcpByeEvent(RtcpByePacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpPacket;\n\n/**\n * Abstract RTCP event\n * \n * @author jexa7410\n */\npublic abstract class RtcpEvent {\n    /**\n     * RTCP packet\n     */\n    private RtcpPacket packet;\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP packet\n     */\n    public RtcpEvent(RtcpPacket packet) {\n        this.packet = packet;\n    }\n\n    /**\n     * Returns the RTCP packet\n     * \n     * @return Packet\n     */\n    public RtcpPacket getPacket() {\n        return packet;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\n/**\n * RTCP events listener interface\n * \n * @author jexa7410\n */\npublic interface RtcpEventListener {\n    /**\n     * Receive RTCP event\n     * \n     * @param event RTCP event\n     */\n    void receiveRtcpEvent(RtcpEvent event);\n\n    /**\n     * Invoked when the RTCP connection times out\n     */\n    void connectionTimeout();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpReceiverReportEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpReceiverReportPacket;\n\n/**\n * RTCP receiver report event\n * \n * @author jexa7410\n */\npublic class RtcpReceiverReportEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP RR packet\n     */\n    public RtcpReceiverReportEvent(RtcpReceiverReportPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpSdesEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpSdesPacket;\n\n/**\n * RTCP session description event\n * \n * @author jexa7410\n */\npublic class RtcpSdesEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP SDES packet\n     */\n    public RtcpSdesEvent(RtcpSdesPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/event/RtcpSenderReportEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.event;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpSenderReportPacket;\n\n/**\n * RTCP sender report event\n * \n * @author jexa7410\n */\npublic class RtcpSenderReportEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP SR packet\n     */\n    public RtcpSenderReportEvent(RtcpSenderReportPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/DummyFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format;\n\n/**\n * Dummy format\n * \n * @author jexa7410\n */\npublic class DummyFormat extends Format {\n\n    /**\n     * Encoding name\n     */\n    public static final String ENCODING = \"dummy\";\n\n    /**\n     * Payload type\n     */\n    public static final int PAYLOAD = 20;\n\n    /**\n     * Constructor\n     */\n    public DummyFormat() {\n        super(ENCODING, PAYLOAD);\n    }\n\n    /**\n     * Get the size of a chunk of data from the source\n     * \n     * @return The minimum size of the buffer needed to read a chunk of data\n     */\n    public int getDataChunkSize() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/Format.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format;\n\n/**\n * Abstract format\n * \n * @author jexa7410\n */\npublic abstract class Format {\n    /**\n     * Unknown payload\n     */\n    public static final int UNKNOWN_PAYLOAD = -1;\n\n    /**\n     * Codec\n     */\n    private String codec;\n\n    /**\n     * Payload type\n     */\n    private int payload;\n\n    /**\n     * Constructor\n     * \n     * @param codec Codec\n     * @param payload Payload type\n     */\n    public Format(String codec, int payload) {\n        this.codec = codec;\n        this.payload = payload;\n    }\n\n    /**\n     * Get the codec name\n     * \n     * @return Name\n     */\n    public String getCodec() {\n        return codec;\n    }\n\n    /**\n     * Get the type of payload\n     * \n     * @return Payload type\n     */\n    public int getPayload() {\n        return payload;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/audio/AmrWbAudioFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.audio;\n\n/**\n * AMR WB audio format\n * \n * @author opob7414\n */\npublic class AmrWbAudioFormat extends AudioFormat {\n\n    /**\n     * Encoding name\n     */\n    public static final String ENCODING = \"AMR-WB\";\n\n    /**\n     * Payload type\n     */\n    public static final int PAYLOAD = 126;\n\n    /**\n     * Constructor\n     */\n    public AmrWbAudioFormat() {\n        super(ENCODING, PAYLOAD);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/audio/AudioFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.audio;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\n\n/**\n * Audio format\n */\npublic class AudioFormat extends Format {\n    /**\n     * Constructor\n     * \n     * @param codec Codec\n     * @param payload Payload type\n     */\n    public AudioFormat(String codec, int payload) {\n        super(codec, payload);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/data/DataFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.data;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\n\n/**\n * Data format for generic RCS streaming session\n */\npublic class DataFormat extends Format {\n\n    /**\n     * Encoding name\n     */\n    public static final String ENCODING = \"X-RCS/9000\";\n\n    /**\n     * Payload type\n     */\n    public static final int PAYLOAD = 97;\n\n    /**\n     * Constructor\n     */\n    public DataFormat() {\n        super(ENCODING, PAYLOAD);\n    }\n\n    /**\n     * Constructor\n     *\n     * @param encoding Encoding\n     */\n    public DataFormat(String encoding) {\n        super(encoding, PAYLOAD);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/video/CameraOptions.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.video;\n\n/**\n * Represents the available camera options\n * \n * @author Deutsche Telekom\n */\npublic enum CameraOptions {\n\n    /**\n     * Cameras value\n     */\n    FRONT(0), BACK(1);\n\n    /**\n     * Private value\n     */\n    private int value;\n\n    /**\n     * Default constructor\n     * \n     * @param value Camera ID\n     */\n    private CameraOptions(int value) {\n        this.value = value;\n    }\n\n    /**\n     * Gets the camera int value\n     * \n     * @return value\n     */\n    public int getValue() {\n        return this.value;\n    }\n\n    /**\n     * Converts the given value in to a Camera\n     * \n     * @param value value\n     * @return Camera\n     */\n    public static CameraOptions convert(int value) {\n        if (value == FRONT.value) {\n            return FRONT;\n        }\n        return BACK;\n    }\n\n    /**\n     * Verifies if it's a front camera\n     * \n     * @return <code>True</code> if it is, <code>false</code> otherwise.\n     */\n    public boolean isFrontCamera() {\n        return this.value == FRONT.value;\n    }\n\n    /**\n     * Verifies if it's a back camera\n     * \n     * @return <code>True</code> if it is, <code>false</code> otherwise.\n     */\n    public boolean isBackCamera() {\n        return this.value == BACK.value;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/video/H264VideoFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.video;\n\n/**\n * H264 video format\n * \n * @author jexa7410\n */\npublic class H264VideoFormat extends VideoFormat {\n\n    /**\n     * Encoding name\n     */\n    public static final String ENCODING = \"H264\";\n\n    /**\n     * Payload type\n     */\n    public static final int PAYLOAD = 96;\n\n    /**\n     * Constructor\n     */\n    public H264VideoFormat() {\n        super(ENCODING, PAYLOAD);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/video/Orientation.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.video;\n\n/**\n * Represents the Video frame orientation\n * \n * @author Deutsche Telekom\n */\npublic enum Orientation {\n    /**\n     * Orientation values\n     */\n    NONE(0), ROTATE_90_CW(1), ROTATE_180(2), ROTATE_90_CCW(3), FLIP_HORIZONTAL(4), ROTATE_90_CW_FLIP_HORIZONTAL(\n            5), ROTATE_180_FLIP_HORIZONTAL(6), ROTATE_90_CCW_FLIP_HORIZONTAL(7);\n\n    /**\n     * Private value\n     */\n    private int value;\n\n    /**\n     * Constructor\n     * \n     * @param value Enum value\n     */\n    private Orientation(int value) {\n        this.value = value;\n    }\n\n    /**\n     * Return the value of the Orientation\n     * \n     * @return Orientation value\n     */\n    public int getValue() {\n        return this.value;\n    }\n\n    /**\n     * Converts the Value into an Orientation\n     * \n     * @param value value to convert\n     * @return Orientation\n     */\n    public static Orientation convert(int value) {\n        if (NONE.value == value) {\n            return NONE;\n        } else if (ROTATE_90_CW.value == value) {\n            return ROTATE_90_CW;\n        } else if (ROTATE_180.value == value) {\n            return ROTATE_180;\n        } else if (ROTATE_90_CCW.value == value) {\n            return ROTATE_90_CCW;\n        } else if (FLIP_HORIZONTAL.value == value) {\n            return FLIP_HORIZONTAL;\n        } else if (ROTATE_90_CW_FLIP_HORIZONTAL.value == value) {\n            return ROTATE_90_CW_FLIP_HORIZONTAL;\n        } else if (ROTATE_180_FLIP_HORIZONTAL.value == value) {\n            return ROTATE_180_FLIP_HORIZONTAL;\n        } else if (ROTATE_90_CCW_FLIP_HORIZONTAL.value == value) {\n            return ROTATE_90_CCW_FLIP_HORIZONTAL;\n        }\n        return NONE;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/video/VideoFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.video;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\n\n/**\n * Video format\n */\npublic class VideoFormat extends Format {\n    /**\n     * Constructor\n     * \n     * @param codec Codec\n     * @param payload Payload type\n     */\n    public VideoFormat(String codec, int payload) {\n        super(codec, payload);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/format/video/VideoOrientation.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.format.video;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.RtpUtils;\n\n/**\n * RCS Video orientation\n * \n * @author Deutsche Telekom\n */\npublic class VideoOrientation {\n\n    /**\n     * Header Id\n     */\n    private int headerId = RtpUtils.RTP_DEFAULT_EXTENSION_ID;\n\n    /**\n     * Camera\n     */\n    private CameraOptions camera;\n\n    /**\n     * Camera orientation\n     */\n    private Orientation orientation;\n\n    /**\n     * Constructor\n     * \n     * @param headerId Orientation header id\n     * @param camera Camera\n     * @param orientation Orientation\n     */\n    public VideoOrientation(int headerId, CameraOptions camera, Orientation orientation) {\n        this.headerId = headerId;\n        this.camera = camera;\n        this.orientation = orientation;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param camera Camera\n     * @param orientation Orientation\n     */\n    public VideoOrientation(CameraOptions camera, Orientation orientation) {\n        this.camera = camera;\n        this.orientation = orientation;\n    }\n\n    /**\n     * Gets the VideoOrientation camera\n     * \n     * @return Camera\n     */\n    public CameraOptions getCamera() {\n        return this.camera;\n    }\n\n    /**\n     * Gets the VideoOrientation orientation\n     * \n     * @return Orientation\n     */\n    public Orientation getOrientation() {\n        return this.orientation;\n    }\n\n    /**\n     * Converts the video orientation into the byte used to transmit int RTP header\n     * \n     * @return Byte representing the video orientation\n     */\n    public byte getVideoOrientation() {\n        return (byte) ((camera.getValue() << 3) | orientation.getValue());\n    }\n\n    /**\n     * Gets the negotiated header ID.\n     * \n     * @return Header id\n     */\n    public int getHeaderId() {\n        return headerId;\n    }\n\n    /**\n     * Parses the byte into a VideoOrientation object\n     * \n     * @param videoOrientation Byte representing the video Orientation\n     * @return VideoOrientation object\n     */\n    public static VideoOrientation parse(byte videoOrientation) {\n        return new VideoOrientation(CameraOptions.convert((videoOrientation & 0x08) >>> 3),\n                Orientation.convert(videoOrientation & 0x07));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/media/MediaException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.media;\n\nimport java.io.IOException;\n\n/**\n * Media exception\n * \n * @author JM. Auffret\n */\npublic class MediaException extends IOException {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public MediaException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public MediaException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/media/MediaInput.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media input (e.g. camera, microphone)\n * \n * @author jexa7410\n */\npublic interface MediaInput {\n    /**\n     * Open the player\n     * \n     * @throws MediaException\n     */\n    public void open() throws MediaException;\n\n    /**\n     * Close the player\n     */\n    public void close();\n\n    /**\n     * Read a media sample (blocking method)\n     * \n     * @return Media sample\n     */\n    public MediaSample readSample();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/media/MediaListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media listener\n * \n * @author jexa7410\n */\npublic interface MediaListener {\n    /**\n     * Media is started\n     */\n    public void mediaStarted();\n\n    /**\n     * Media is stopped\n     */\n    public void mediaStopped();\n\n    /**\n     * Media has failed\n     * \n     * @param error Error code\n     */\n    public void mediaError(String error);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/media/MediaOutput.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media output (e.g. screen, headset)\n * \n * @author jexa7410\n */\npublic interface MediaOutput {\n    /**\n     * Open the renderer\n     * \n     * @throws MediaException\n     */\n    public void open() throws MediaException;\n\n    /**\n     * Close the renderer\n     */\n    public void close();\n\n    /**\n     * Write a media sample\n     * \n     * @param sample Media sample\n     */\n    public void writeSample(MediaSample sample);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/media/MediaSample.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media sample\n * \n * @author jexa7410\n */\npublic class MediaSample {\n\n    /**\n     * Data\n     */\n    private byte[] data;\n\n    /**\n     * Timestamp\n     */\n    private long mTimestamp;\n\n    /**\n     * RTP marker bit\n     */\n    private boolean marker = false;\n\n    /**\n     * Sequence number\n     */\n    private long sequenceNumber;\n\n    // TODO: remove after implement receiver buffer\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param timestamp Timestamp\n     * @Param sequenceNumber Packet sequence number\n     */\n    public MediaSample(byte[] data, long timestamp, long sequenceNumber) {\n        this.data = data;\n        this.mTimestamp = timestamp;\n        this.sequenceNumber = sequenceNumber;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param timestamp Timestamp\n     */\n    public MediaSample(byte[] data, long timestamp) {\n        this.data = data;\n        this.mTimestamp = timestamp;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param timestamp Timestamp\n     * @param marker Marker bit\n     */\n    public MediaSample(byte[] data, long timestamp, boolean marker) {\n        this.data = data;\n        this.mTimestamp = timestamp;\n        this.marker = marker;\n    }\n\n    /**\n     * Returns the data sample\n     * \n     * @return Byte array\n     */\n    public byte[] getData() {\n        return data;\n    }\n\n    /**\n     * Returns the length of the data sample\n     * \n     * @return Data sample length\n     */\n    public int getLength() {\n        if (data != null) {\n            return data.length;\n        }\n        return 0;\n    }\n\n    /**\n     * Returns the timestamp of the sample\n     * \n     * @return Timestamp in microseconds\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Is RTP marker bit\n     * \n     * @return Boolean\n     */\n    public boolean isMarker() {\n        return marker;\n    }\n\n    /**\n     * Get the sequence number\n     * \n     * @return sequence number\n     */\n    public long getSequenceNumber() {\n        return this.sequenceNumber;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/media/VideoSample.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.media;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\n\n/**\n * Video sample\n * \n * @author hlxn7157\n */\npublic class VideoSample extends MediaSample {\n\n    /**\n     * Video Orientation\n     */\n    private VideoOrientation videoOrientation;\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param timestamp Timestamp\n     * @param videoOrientation Video orientation\n     */\n    public VideoSample(byte[] data, long timestamp, VideoOrientation videoOrientation) {\n        super(data, timestamp);\n        this.videoOrientation = videoOrientation;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param timestamp Timestamp\n     * @Param sequenceNumber Packet sequence number\n     * @param videoOrientation Video orientation\n     */\n    public VideoSample(byte[] data, long timestamp, long sequenceNumber,\n            VideoOrientation videoOrientation) {\n        super(data, timestamp, sequenceNumber);\n        this.videoOrientation = videoOrientation;\n    }\n\n    /**\n     * Gets the video orientation\n     * \n     * @return VideoOrientation\n     */\n    public VideoOrientation getVideoOrientation() {\n        return videoOrientation;\n    }\n\n    /**\n     * Sets the video orientation\n     * \n     * @param videoOrientation VideoOrientation\n     */\n    public void setVideoOrientation(VideoOrientation orientation) {\n        this.videoOrientation = orientation;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/DummyPacketSourceStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.DummyFormat;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.SystemTimeBase;\nimport com.gsma.rcs.utils.FifoBuffer;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Dummy packet source stream (used to pass NAT)\n * \n * @author jexa7410\n */\npublic class DummyPacketSourceStream extends Thread implements ProcessorInputStream {\n\n    /**\n     * Source period for the opening phase (in milliseconds)\n     */\n    public final static int DUMMY_SOURCE_OPENING_PERIOD = 100;\n\n    /**\n     * Source period (in milliseconds)\n     */\n    public final static int DUMMY_SOURCE_PERIOD = 15000;\n\n    /**\n     * Input format\n     */\n    private DummyFormat mFormat = new DummyFormat();\n\n    /**\n     * Time base\n     */\n    private SystemTimeBase mSystemTimeBase = new SystemTimeBase();\n\n    /**\n     * Sequence number\n     */\n    private long mSeqNo;\n\n    /**\n     * Message buffer\n     */\n    private FifoBuffer mBuffer = new FifoBuffer();\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(DummyPacketSourceStream.class.getName());\n\n    /**\n     * Interruption flag\n     */\n    private boolean mInterrupted;\n\n    /**\n     * Incoming stream is started ?\n     */\n    private boolean mIncomingStarted;\n\n    /**\n     * Constructor\n     */\n    public DummyPacketSourceStream() {\n    }\n\n    /**\n     * Open the input stream\n     */\n    public void open() {\n        start();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Dummy source stream opened\");\n        }\n    }\n\n    /**\n     * Close the input stream\n     */\n    public void close() {\n        mInterrupted = true;\n        mBuffer.close();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Dummy source stream closed\");\n        }\n    }\n\n    /**\n     * Format of the data provided by the source stream\n     * \n     * @return Format\n     */\n    public Format getFormat() {\n        return mFormat;\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            while (!mInterrupted) {\n                try {\n                    // Build a new dummy packet\n                    Buffer packet = new Buffer();\n                    packet.setData(new byte[0]);\n                    packet.setLength(0);\n                    packet.setFormat(mFormat);\n                    packet.setSequenceNumber(mSeqNo++);\n                    packet.setTimestamp(mSystemTimeBase.getTimestamp());\n\n                    // Post the packet in the FIFO\n                    mBuffer.addObject(packet);\n\n                    // Make a pause\n                    if (!mIncomingStarted) {\n                        Thread.sleep(DUMMY_SOURCE_OPENING_PERIOD);\n                    } else {\n                        Thread.sleep(DUMMY_SOURCE_PERIOD);\n                    }\n                } catch (InterruptedException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Dummy packet source has failed!\", e);\n        }\n    }\n\n    /**\n     * Read from the stream\n     * \n     * @return Buffer\n     */\n    public Buffer read() {\n        // Read the FIFO the buffer\n        Buffer buffer = (Buffer) mBuffer.getObject();\n        return buffer;\n    }\n\n    /**\n     * Set incomingStarted.\n     */\n    public void incomingStarted() {\n        mIncomingStarted = true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/MediaCaptureStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaException;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaSample;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Media capture stream\n * \n * @author jexa7410\n */\npublic class MediaCaptureStream implements ProcessorInputStream {\n    /**\n     * Media player\n     */\n    private MediaInput player;\n\n    /**\n     * Media format\n     */\n    private Format format;\n\n    /**\n     * Sequence number\n     */\n    protected long seqNo = 0;\n\n    /**\n     * Input buffer\n     */\n    protected Buffer buffer = new Buffer();\n\n    /**\n     * The logger\n     */\n    private Logger mLogger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param format Input format\n     * @param player Media player\n     */\n    public MediaCaptureStream(Format format, MediaInput player) {\n        this.format = format;\n        this.player = player;\n    }\n\n    /**\n     * Open the input stream\n     * \n     * @throws MediaException\n     */\n    public void open() throws MediaException {\n        player.open();\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Media capture stream opened\");\n        }\n    }\n\n    /**\n     * Close the input stream\n     */\n    public void close() {\n        player.close();\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Media capture stream closed\");\n        }\n    }\n\n    /**\n     * Format of the data provided by the source stream\n     * \n     * @return Format\n     */\n    public Format getFormat() {\n        return format;\n    }\n\n    /**\n     * returns the MediaInput\n     * \n     * @return MediaInput\n     */\n    public MediaInput getPlayer() {\n        return player;\n    }\n\n    /**\n     * Read from the stream\n     * \n     * @return Buffer\n     * @throws NetworkException\n     */\n    public Buffer read() throws NetworkException {\n        // Read a new sample from the media player\n        MediaSample sample = player.readSample();\n        if (sample == null) {\n            return null;\n        }\n\n        // Create a buffer\n        buffer.setData(sample.getData());\n        buffer.setLength(sample.getLength());\n        buffer.setFormat(format);\n        buffer.setSequenceNumber(seqNo++);\n        if (sample.isMarker()) {\n            buffer.setFlags(Buffer.FLAG_RTP_MARKER);\n        }\n        buffer.setTimestamp(sample.getTimestamp());\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/MediaRendererStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaException;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaSample;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Media renderer stream\n * \n * @author jexa7410\n */\npublic class MediaRendererStream implements ProcessorOutputStream {\n    /**\n     * Media renderer\n     */\n    private MediaOutput renderer;\n\n    /**\n     * The logger\n     */\n    private final Logger mLogger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param renderer Media renderer\n     */\n    public MediaRendererStream(MediaOutput renderer) {\n        this.renderer = renderer;\n    }\n\n    /**\n     * Get Media renderer\n     * \n     * @return renderer Media renderer\n     */\n    public MediaOutput getRenderer() {\n        return renderer;\n    }\n\n    /**\n     * Open the output stream\n     * \n     * @throws MediaException\n     */\n    public void open() throws MediaException {\n        renderer.open();\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Media renderer stream opened\");\n        }\n\n    }\n\n    /**\n     * Close the output stream\n     */\n    public void close() {\n        renderer.close();\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Media renderer stream closed\");\n        }\n    }\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     */\n    public void write(Buffer buffer) {\n        MediaSample sample = new MediaSample((byte[]) buffer.getData(), buffer.getTimestamp(),\n                buffer.getSequenceNumber());\n        renderer.writeSample(sample);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/ProcessorInputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\nimport java.io.IOException;\n\n/**\n * Processor input stream\n */\npublic interface ProcessorInputStream {\n\n    /**\n     * Open the input stream\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException;\n\n    /**\n     * Close the input stream\n     */\n    public void close();\n\n    /**\n     * Read from the input stream without blocking\n     * \n     * @return Buffer\n     * @throws NetworkException\n     */\n    public Buffer read() throws NetworkException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/ProcessorOutputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\nimport java.io.IOException;\n\n/**\n * Processor output stream\n */\npublic interface ProcessorOutputStream {\n    /**\n     * Open the output stream\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException;\n\n    /**\n     * Close from the output stream\n     */\n    public void close();\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     * @throws NetworkException\n     */\n    public void write(Buffer buffer) throws NetworkException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/RtpInputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.RtpUtils;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpPacketReceiver;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpPacketTransmitter;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpSession;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtpExtensionHeader.ExtensionElement;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtpPacket;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtpPacketReceiver;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.utils.CloseableUtils;\n\nimport java.io.IOException;\nimport java.util.Comparator;\nimport java.util.PriorityQueue;\nimport java.util.concurrent.TimeoutException;\n\n/**\n * RTP input stream\n * \n * @author jexa7410\n */\npublic class RtpInputStream implements ProcessorInputStream {\n    /**\n     * RTP Socket Timeout Used a 20s timeout value because the RTP packets can have a delay\n     */\n    private static final int RTP_SOCKET_TIMEOUT = 20000;\n\n    private static final int MAX_RTP_PACKETS = 5;\n\n    /**\n     * Remote address\n     */\n    private String mRemoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int mRemotePort;\n\n    /**\n     * Local port\n     */\n    private int mLocalPort;\n\n    /**\n     * RTP receiver\n     */\n    private RtpPacketReceiver mRtpReceiver;\n\n    /**\n     * RTCP receiver\n     */\n    private RtcpPacketReceiver mRtcpReceiver;\n\n    /**\n     * RTCP transmitter\n     */\n    private RtcpPacketTransmitter mRtcpTransmitter;\n\n    /**\n     * Input buffer\n     */\n    private Buffer mBuffer = new Buffer();\n\n    /**\n     * Input format\n     */\n    private Format mInputFormat;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession mRtcpSession;\n\n    /**\n     * RTP stream listener\n     */\n    private RtpStreamListener mRtpStreamListener;\n\n    /**\n     * The negotiated orientation extension header id\n     */\n    private int mExtensionHeaderId = RtpUtils.RTP_DEFAULT_EXTENSION_ID;\n\n    /**\n     * Indicates if the stream was closed\n     */\n    private boolean mIsClosed;\n\n    /**\n     * Sequence RTP packets buffer\n     */\n    private PriorityQueue<RtpPacket> mRtpPacketsBuffer;\n\n    /**\n     * Constructor\n     * \n     * @param localPort Local port\n     * @param inputFormat Input format\n     */\n    public RtpInputStream(String remoteAddress, int remotePort, int localPort, Format inputFormat) {\n        mRemoteAddress = remoteAddress;\n        mRemotePort = remotePort;\n        mLocalPort = localPort;\n        mInputFormat = inputFormat;\n\n        mRtcpSession = new RtcpSession(false, 16000);\n\n        mRtpPacketsBuffer = new PriorityQueue<RtpPacket>(10, new Comparator<RtpPacket>() {\n            @Override\n            public int compare(RtpPacket object1, RtpPacket object2) {\n                if (object1.seqnum == object2.seqnum) {\n                    return 0;\n                } else if (object1.seqnum < object2.seqnum) {\n                    return -1;\n                }\n                return 1;\n            }\n        });\n\n    }\n\n    /**\n     * Open the input stream\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException {\n        mRtpReceiver = new RtpPacketReceiver(mLocalPort, mRtcpSession, RTP_SOCKET_TIMEOUT);\n        mRtpReceiver.start();\n\n        mRtcpReceiver = new RtcpPacketReceiver(mLocalPort + 1, mRtcpSession);\n        mRtcpReceiver.start();\n\n        mRtcpTransmitter = new RtcpPacketTransmitter(mRemoteAddress, mRemotePort + 1, mRtcpSession,\n                mRtcpReceiver.getConnection());\n        mRtcpTransmitter.start();\n\n        mIsClosed = false;\n    }\n\n    /**\n     * Close the input stream\n     */\n    public void close() {\n        mIsClosed = true;\n        CloseableUtils.tryToClose(mRtcpTransmitter);\n        CloseableUtils.tryToClose(mRtpReceiver);\n        CloseableUtils.tryToClose(mRtcpReceiver);\n        mRtpStreamListener = null;\n    }\n\n    /**\n     * Returns the RTP receiver\n     * \n     * @return RTP receiver\n     */\n    public RtpPacketReceiver getRtpReceiver() {\n        return mRtpReceiver;\n    }\n\n    /**\n     * Returns the RTCP receiver\n     * \n     * @return RTCP receiver\n     */\n    public RtcpPacketReceiver getRtcpReceiver() {\n        return mRtcpReceiver;\n    }\n\n    /**\n     * Read from the input stream without blocking\n     * \n     * @return Buffer\n     * @throws NetworkException\n     */\n    public Buffer read() throws NetworkException {\n        do {\n            try {\n                /* Wait and read a RTP packet */\n                RtpPacket rtpPacket = mRtpReceiver.readRtpPacket();\n                if (rtpPacket == null) {\n                    throw new NetworkException(\"Unable to read RTP packet!\");\n                }\n\n                mRtpPacketsBuffer.add(rtpPacket);\n            } catch (TimeoutException e) {\n                if (!mIsClosed) {\n                    if (mRtpStreamListener != null) {\n                        mRtpStreamListener.rtpStreamAborted();\n                    }\n                }\n                throw new NetworkException(\"RTP Packet reading timeout!\", e);\n            }\n        } while (mRtpPacketsBuffer.size() <= MAX_RTP_PACKETS);\n\n        RtpPacket packet = mRtpPacketsBuffer.poll();\n\n        mBuffer.setData(packet.mData);\n        mBuffer.setLength(packet.payloadlength);\n        mBuffer.setOffset(0);\n        mBuffer.setFormat(mInputFormat);\n        mBuffer.setSequenceNumber(packet.seqnum);\n        mBuffer.setRTPMarker(packet.marker != 0);\n        mBuffer.setTimestamp(packet.timestamp);\n\n        if (packet.extensionHeader != null) {\n            ExtensionElement element = packet.extensionHeader.getElementById(mExtensionHeaderId);\n            if (element != null) {\n                mBuffer.setVideoOrientation(VideoOrientation.parse(element.data[0]));\n            }\n        }\n\n        mInputFormat = null;\n        return mBuffer;\n    }\n\n    /**\n     * Adds the RTP stream listener\n     * \n     * @param rtpStreamListener\n     */\n    public void addRtpStreamListener(RtpStreamListener rtpStreamListener) {\n        mRtpStreamListener = rtpStreamListener;\n    }\n\n    /**\n     * Sets the negotiated orientation extension header id\n     * \n     * @param extensionHeaderId Header id\n     */\n    public void setExtensionHeaderId(int extensionHeaderId) {\n        mExtensionHeaderId = extensionHeaderId;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/RtpOutputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpPacketReceiver;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpPacketTransmitter;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtcpSession;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtpPacketReceiver;\nimport com.gsma.rcs.core.ims.protocol.rtp.core.RtpPacketTransmitter;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpEvent;\nimport com.gsma.rcs.core.ims.protocol.rtp.event.RtcpEventListener;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.gsma.rcs.utils.CloseableUtils;\n\nimport java.io.IOException;\n\n/**\n * RTP output stream\n * \n * @author jexa7410\n */\npublic class RtpOutputStream implements ProcessorOutputStream, RtcpEventListener {\n    /**\n     * RTCP Socket Timeout\n     */\n    public static final int RTCP_SOCKET_TIMEOUT = 20000;\n\n    /**\n     * Remote address\n     */\n    private String mRemoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int mRemotePort;\n\n    /**\n     * Local port\n     */\n    private int mLocalRtpPort = -1;\n\n    /**\n     * RTP receiver\n     */\n    private RtpPacketReceiver mRtpReceiver;\n\n    /**\n     * RTCP receiver\n     */\n    private RtcpPacketReceiver mRtcpReceiver;\n\n    /**\n     * RTP transmitter\n     */\n    private RtpPacketTransmitter mRtpTransmitter;\n\n    /**\n     * RTCP transmitter\n     */\n    private RtcpPacketTransmitter mRtcpTransmitter;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession mRtcpSession;\n\n    /**\n     * RTCP socket timeout\n     */\n    private int mRtcpSocketTimeout = 0;\n\n    /**\n     * RTP stream listener\n     */\n    private RtpStreamListener mRtpStreamListener;\n\n    /**\n     * RTP Input stream\n     */\n    private RtpInputStream mRtpInputStream;\n\n    /**\n     * Constructor\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     */\n    public RtpOutputStream(String remoteAddress, int remotePort) {\n        mRemoteAddress = remoteAddress;\n        mRemotePort = remotePort;\n        mRtcpSession = new RtcpSession(true, 16000);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtpInputStream RTP input stream\n     */\n    public RtpOutputStream(String remoteAddress, int remotePort, RtpInputStream rtpInputStream) {\n        mRemoteAddress = remoteAddress;\n        mRemotePort = remotePort;\n        mRtpInputStream = rtpInputStream;\n        mRtcpSession = new RtcpSession(true, 16000);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtcpTimeout RTCP timeout\n     */\n    public RtpOutputStream(String remoteAddress, int remotePort, int localRtpPort, int rtcpTimeout) {\n        mRemoteAddress = remoteAddress;\n        mRemotePort = remotePort;\n        mLocalRtpPort = localRtpPort;\n        mRtcpSocketTimeout = rtcpTimeout;\n        mRtcpSession = new RtcpSession(true, 16000);\n    }\n\n    /**\n     * Open the output stream\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException {\n        if (mLocalRtpPort != -1) {\n            mRtpReceiver = new RtpPacketReceiver(mLocalRtpPort, mRtcpSession);\n            mRtpReceiver.start();\n\n            mRtcpReceiver = new RtcpPacketReceiver(mLocalRtpPort + 1, mRtcpSession,\n                    mRtcpSocketTimeout);\n            mRtcpReceiver.addRtcpListener(this);\n            mRtcpReceiver.start();\n\n            mRtpTransmitter = new RtpPacketTransmitter(mRemoteAddress, mRemotePort, mRtcpSession,\n                    mRtpReceiver.getConnection());\n\n            mRtcpTransmitter = new RtcpPacketTransmitter(mRemoteAddress, mRemotePort + 1,\n                    mRtcpSession, mRtcpReceiver.getConnection());\n            mRtcpTransmitter.start();\n        } else if (mRtpInputStream != null) {\n            mRtpTransmitter = new RtpPacketTransmitter(mRemoteAddress, mRemotePort, mRtcpSession,\n                    mRtpInputStream.getRtpReceiver().getConnection());\n\n            mRtcpTransmitter = new RtcpPacketTransmitter(mRemoteAddress, mRemotePort + 1,\n                    mRtcpSession, mRtpInputStream.getRtcpReceiver().getConnection());\n        } else {\n            mRtpTransmitter = new RtpPacketTransmitter(mRemoteAddress, mRemotePort, mRtcpSession);\n\n            mRtcpTransmitter = new RtcpPacketTransmitter(mRemoteAddress, mRemotePort + 1,\n                    mRtcpSession);\n        }\n    }\n\n    /**\n     * Close the output stream\n     */\n    public void close() {\n        CloseableUtils.tryToClose(mRtpTransmitter);\n        CloseableUtils.tryToClose(mRtcpTransmitter);\n        CloseableUtils.tryToClose(mRtpReceiver);\n        CloseableUtils.tryToClose(mRtcpReceiver);\n        mRtpStreamListener = null;\n    }\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     * @throws NetworkException\n     */\n    public void write(Buffer buffer) throws NetworkException {\n        mRtpTransmitter.sendRtpPacket(buffer);\n    }\n\n    @Override\n    public void receiveRtcpEvent(RtcpEvent event) {\n        // Nothing to do\n    }\n\n    @Override\n    public void connectionTimeout() {\n        if (mRtpStreamListener != null) {\n            mRtpStreamListener.rtpStreamAborted();\n        }\n    }\n\n    /**\n     * Adds the RTP stream listener\n     * \n     * @param rtpStreamListener\n     */\n    public void addRtpStreamListener(RtpStreamListener rtpStreamListener) {\n        mRtpStreamListener = rtpStreamListener;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/RtpStreamListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\n/**\n * RTP Stream listener interface\n * \n * @author Deutsche Telekom\n */\npublic interface RtpStreamListener {\n    /**\n     * Invoked when the RTP stream was aborted.\n     */\n    void rtpStreamAborted();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/VideoCaptureStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.VideoSample;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Video capture stream\n * \n * @author hlxn7157\n */\npublic class VideoCaptureStream extends MediaCaptureStream {\n    /**\n     * Constructor\n     * \n     * @param format Input format\n     * @param player Media player\n     */\n    public VideoCaptureStream(Format format, MediaInput player) {\n        super(format, player);\n    }\n\n    /**\n     * Read from the stream\n     * \n     * @return Buffer\n     * @throws NetworkException\n     */\n    public Buffer read() throws NetworkException {\n        // Read a new sample from the media player\n        VideoSample sample = (VideoSample) getPlayer().readSample();\n        if (sample == null) {\n            throw new NetworkException(\"Failed to read video sample!\");\n        }\n\n        // Create a buffer\n        buffer.setData(sample.getData());\n        buffer.setLength(sample.getLength());\n        buffer.setFormat(getFormat());\n        buffer.setSequenceNumber(seqNo++);\n        if (sample.isMarker()) {\n            buffer.setFlags(Buffer.FLAG_RTP_MARKER);\n        }\n        buffer.setTimestamp(sample.getTimestamp());\n        buffer.setVideoOrientation(sample.getVideoOrientation());\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/stream/VideoRendererStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.stream;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.VideoSample;\nimport com.gsma.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Video renderer stream\n * \n * @author hlxn7157\n */\npublic class VideoRendererStream extends MediaRendererStream {\n    /**\n     * Constructor\n     * \n     * @param renderer Media renderer\n     */\n    public VideoRendererStream(MediaOutput renderer) {\n        super(renderer);\n    }\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     */\n    public void write(Buffer buffer) {\n        VideoSample sample = new VideoSample((byte[]) buffer.getData(), buffer.getTimestamp(),\n                buffer.getSequenceNumber(), buffer.getVideoOrientation());\n        getRenderer().writeSample(sample);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/util/Buffer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.util;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\n\n/**\n * Buffer\n * \n * @author jexa7410\n */\npublic class Buffer {\n    /**\n     * Indicates that this buffer marks the end of media for the data stream\n     */\n    public final static int FLAG_EOM = (1 << 0);\n\n    /**\n     * Indicates that the media data should be ignored\n     */\n    public final static int FLAG_DISCARD = (1 << 1);\n\n    /**\n     * This is a marker bit for RTP\n     */\n    public final static int FLAG_RTP_MARKER = (1 << 11);\n\n    /**\n     * Indicates that the buffer carries a timestamp that's in RTP (NTP) time units\n     */\n    public final static int FLAG_RTP_TIME = (1 << 12);\n\n    /**\n     * Default value if the timestamp of the media is not known\n     */\n    public final static long TIME_UNKNOWN = -1L;\n\n    /**\n     * Default value if the sequence number is not known\n     */\n    public final static long SEQUENCE_UNKNOWN = Long.MAX_VALUE - 1;\n\n    /**\n     * The timestamp of the data in nanoseconds\n     */\n    protected long mTimestamp = TIME_UNKNOWN;\n\n    /**\n     * The format of the data chunk\n     */\n    protected Format format = null;\n\n    /**\n     * States how many samples are valid in the array of data\n     */\n    protected int length = 0;\n\n    /**\n     * Starting point (offset) into the array where the valid data begins\n     */\n    protected int offset = 0;\n\n    /**\n     * A flag mask that describes the boolean attributes of the buffer\n     */\n    protected int flags = 0;\n\n    /**\n     * The duration of the data in the buffer in nanoseconds\n     */\n    protected long duration = TIME_UNKNOWN;\n\n    /**\n     * Media data chunk\n     */\n    protected Object data = null;\n\n    /**\n     * The sequence number\n     */\n    protected long sequenceNumber = SEQUENCE_UNKNOWN;\n\n    /**\n     * The array of buffer fragments\n     */\n    protected Buffer[] fragments = null;\n\n    /**\n     * The size of used items from array of buffer fragments\n     */\n    protected int fragmentsSize = 0;\n\n    /**\n     * Video orientation\n     */\n    private VideoOrientation videoOrientation;\n\n    /**\n     * Get the data format\n     * \n     * @return Format\n     */\n    public Format getFormat() {\n        return format;\n    }\n\n    /**\n     * Set the data format\n     * \n     * @param format New format\n     */\n    public void setFormat(Format format) {\n        this.format = format;\n    }\n\n    /**\n     * Get the flag mask\n     * \n     * @return Flag\n     */\n    public int getFlags() {\n        return flags;\n    }\n\n    /**\n     * Set the flag mask\n     * \n     * @param flags New flags\n     */\n    public void setFlags(int flags) {\n        this.flags = flags;\n    }\n\n    /**\n     * Check if it's the end of the media stream\n     * \n     * @return Boolean\n     */\n    public boolean isEOM() {\n        return (flags & FLAG_EOM) != 0;\n    }\n\n    /**\n     * Set the EOM flag\n     * \n     * @param eom EOM status flag\n     */\n    public void setEOM(boolean eom) {\n        if (eom)\n            flags |= FLAG_EOM;\n        else\n            flags &= ~FLAG_EOM;\n    }\n\n    /**\n     * Check if the RTP marker is set\n     * \n     * @return Boolean\n     */\n    public boolean isRTPMarkerSet() {\n        return (flags & FLAG_RTP_MARKER) != 0;\n    }\n\n    /**\n     * Set the RTP marker\n     * \n     * @param marker RTP marker flag\n     */\n    public void setRTPMarker(boolean marker) {\n        if (marker)\n            flags |= FLAG_RTP_MARKER;\n        else\n            flags &= ~FLAG_RTP_MARKER;\n    }\n\n    /**\n     * Check whether or not this buffer is to be discarded\n     * \n     * @return Boolean\n     */\n    public boolean isDiscard() {\n        return (flags & FLAG_DISCARD) != 0;\n    }\n\n    /**\n     * Set the discard flag\n     * \n     * @param discard Discard flag.\n     */\n    public void setDiscard(boolean discard) {\n        if (discard)\n            flags |= FLAG_DISCARD;\n        else\n            flags &= ~FLAG_DISCARD;\n    }\n\n    /**\n     * Get the internal data that holds the media chunk\n     * \n     * @return Data\n     */\n    public Object getData() {\n        return data;\n    }\n\n    /**\n     * Set the internal data that holds the media chunk\n     * \n     * @param data Data\n     */\n    public void setData(Object data) {\n        this.data = data;\n    }\n\n    /**\n     * Get the length of the valid data in the buffer\n     * \n     * @return The length of the valid data\n     */\n    public int getLength() {\n        return length;\n    }\n\n    /**\n     * Set the length of the valid data stored in the buffer\n     * \n     * @param length The length of the valid data\n     */\n    public void setLength(int length) {\n        this.length = length;\n    }\n\n    /**\n     * Get the offset into the data array where the valid data begins\n     * \n     * @return Offset\n     */\n    public int getOffset() {\n        return offset;\n    }\n\n    /**\n     * Set the offset\n     * \n     * @param offset The starting point for the valid data\n     */\n    public void setOffset(int offset) {\n        this.offset = offset;\n    }\n\n    /**\n     * Get the timestamp\n     * \n     * @return Timestamp in nanoseconds.\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Set the timestamp\n     * \n     * @param timestamp Timestamp in nanoseconds\n     */\n    public void setTimestamp(long timestamp) {\n        mTimestamp = timestamp;\n    }\n\n    /**\n     * Get the duration\n     * \n     * @return Duration in nanoseconds\n     */\n    public long getDuration() {\n        return duration;\n    }\n\n    /**\n     * Set the duration\n     * \n     * @param duration Duration\n     */\n    public void setDuration(long duration) {\n        this.duration = duration;\n    }\n\n    /**\n     * Set the sequence number\n     * \n     * @param number Sequence number\n     */\n    public void setSequenceNumber(long number) {\n        sequenceNumber = number;\n    }\n\n    /**\n     * Ges the sequence number\n     * \n     * @return Sequence number\n     */\n    public long getSequenceNumber() {\n        return sequenceNumber;\n    }\n\n    /**\n     * Get the buffer fragments\n     * \n     * @return the fragments\n     */\n    public Buffer[] getFragments() {\n        return fragments;\n    }\n\n    /**\n     * Set the buffer fragments\n     * \n     * @param fragments the fragments to set\n     */\n    public void setFragments(Buffer[] fragments) {\n        this.fragments = fragments;\n    }\n\n    /**\n     * Get the buffer fragments size\n     * \n     * @return the fragments size\n     */\n    public int getFragmentsSize() {\n        return fragmentsSize;\n    }\n\n    /**\n     * Set the buffer fragments size\n     * \n     * @param fragmentsSize the fragments size to set\n     */\n    public void setFragmentsSize(int fragmentsSize) {\n        this.fragmentsSize = fragmentsSize;\n    }\n\n    /**\n     * Get the sub buffers\n     * \n     * @return <code>true</code> in case of fragmented buffer, otherwise <code>false</code>\n     */\n    public boolean isFragmented() {\n        return (fragments != null && fragments.length > 0 && fragmentsSize > 0);\n    }\n\n    /**\n     * Gets the VideoOrientation\n     * \n     * @return Video orientation\n     */\n    public VideoOrientation getVideoOrientation() {\n        return videoOrientation;\n    }\n\n    /**\n     * Sets the video orientation\n     * \n     * @param videoOrientation VideoOrientation\n     */\n    public void setVideoOrientation(VideoOrientation videoOrientation) {\n        this.videoOrientation = videoOrientation;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/util/Packet.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.util;\n\n/**\n * Generic packet\n * \n * @author jexa7410\n */\npublic class Packet {\n    /**\n     * Data\n     */\n    public byte[] mData;\n\n    /**\n     * Packet length\n     */\n    public int mLength;\n\n    /**\n     * Offset\n     */\n    public int mOffset;\n\n    /**\n     * Received at\n     */\n    public long mReceivedAt;\n\n    /**\n     * Constructor\n     */\n    public Packet() {\n    }\n\n    /**\n     * Constructor\n     * \n     * @param packet Packet\n     */\n    public Packet(Packet packet) {\n        mData = packet.mData;\n        mLength = packet.mLength;\n        mOffset = packet.mOffset;\n        mReceivedAt = packet.mReceivedAt;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/util/RtpConstants.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.util;\n\n/**\n * RTP constants\n * \n * @author jexa7410\n */\npublic class RtpConstants {\n    public static final String RTP_PROTOCOL = \"rtp\";\n    public static final String RTP_SECURED_PROTOCOL = \"srtp\";\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/rtp/util/SystemTimeBase.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.rtp.util;\n\n/**\n * Time base\n */\npublic class SystemTimeBase {\n\n    /**\n     * Offset time (start-up time)\n     */\n    private static long offset = System.currentTimeMillis() * 1000000L;\n\n    /**\n     * Returns a timestamp base value in nanoseconds\n     * \n     * @return Timestamp\n     */\n    public long getTimestamp() {\n        return (System.currentTimeMillis() * 1000000L) - offset;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/MediaAttribute.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\n/**\n * Media attribute\n * \n * @author jexa7410\n */\npublic class MediaAttribute {\n    /**\n     * Attribute name\n     */\n    private String name;\n\n    /**\n     * Attribute value\n     */\n    private String value;\n\n    /**\n     * Constructor\n     * \n     * @param name Attribute name\n     * @param value Attribute value\n     */\n    public MediaAttribute(String name, String value) {\n        this.name = name;\n        this.value = value;\n    }\n\n    /**\n     * Returns the attribute name\n     * \n     * @return Name\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the attribute value\n     * \n     * @return Value\n     */\n    public String getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/MediaDescription.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\nimport java.util.Vector;\n\n/**\n * Media description\n * \n * @author jexa7410\n */\npublic class MediaDescription {\n\n    /**\n     * Media name\n     */\n    public String mName;\n\n    @Override\n    public String toString() {\n        return \"MediaDescription [name=\" + mName + \", port=\" + mPort + \", protocol=\" + mProtocol\n                + \", payload=\" + mPayload + \", mediaTitle=\" + mMediaTitle + \", connectionInfo=\"\n                + mConnectionInfo + \", bandwidthInfo=\" + mBandwidthInfo + \", senderBandwidthInfo=\"\n                + mSenderBandwidthInfo + \", receiverBandwidthInfo=\" + mReceiverBandwidthInfo\n                + \", encryptionKey=\" + mEncryptionKey + \", mediaAttributes=\" + mMediaAttributes\n                + \"]\";\n    }\n\n    /**\n     * Media port\n     */\n    public int mPort;\n\n    /**\n     * Media protocol\n     */\n    public String mProtocol;\n\n    /**\n     * Payload\n     */\n    public String mPayload;\n\n    /**\n     * Media title\n     */\n    public String mMediaTitle;\n\n    /**\n     * Connection info\n     */\n    public String mConnectionInfo;\n\n    /**\n     * Bandwidth info\n     */\n    public String mBandwidthInfo;\n\n    /**\n     * Sender bandwidth info (RFC 3556)\n     */\n    public String mSenderBandwidthInfo;\n\n    /**\n     * Receiver bandwidth info (RFC 3556)\n     */\n    public String mReceiverBandwidthInfo;\n\n    /**\n     * Encryption key\n     */\n    public String mEncryptionKey;\n\n    /**\n     * Media attributes\n     */\n    public Vector<MediaAttribute> mMediaAttributes = new Vector<>();\n\n    /**\n     * Constructor\n     * \n     * @param name Media name\n     * @param port Media port\n     * @param protocol Media protocol\n     * @param payload Media payload\n     */\n    public MediaDescription(String name, int port, String protocol, String payload) {\n        mName = name;\n        mPort = port;\n        mProtocol = protocol;\n        mPayload = payload;\n    }\n\n    public MediaAttribute getMediaAttribute(String name) {\n        MediaAttribute attribute = null;\n        if (mMediaAttributes != null) {\n            for (int i = 0; i < mMediaAttributes.size(); i++) {\n                MediaAttribute entry = mMediaAttributes.elementAt(i);\n                if (entry.getName().equals(name)) {\n                    attribute = entry;\n                    break;\n                }\n            }\n        }\n        return attribute;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/Parser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.util.Vector;\n\n/**\n * Generic parser\n * \n * @author jexa7410\n */\nclass Parser {\n    /**\n     * Buffer\n     */\n    private Vector<Integer> buffer = new Vector<Integer>();\n\n    /**\n     * Unget a token\n     * \n     * @param tk Token\n     */\n    public void ungetToken(String tk) {\n        byte token[] = tk.getBytes(UTF8);\n        for (int i = 0; i < token.length; i++) {\n            buffer.insertElementAt(Integer.valueOf(token[token.length - i - 1]), 0);\n        }\n    }\n\n    /**\n     * Get a token\n     * \n     * @param input Input stream\n     * @param tk Token\n     * @return Token value\n     */\n    public boolean getToken(ByteArrayInputStream input, String tk) {\n        boolean found = false;\n\n        ByteArrayOutputStream bout = new ByteArrayOutputStream();\n        skipWhitespace(input);\n\n        if (input.available() > 0) {\n            int ch = readChar(input);\n            while (ch != '=' && ch != '\\n' && ch != '\\r' && ch != -1) {\n                bout.write(ch);\n                ch = readChar(input);\n            }\n            bout.write(ch);\n        }\n\n        String token = new String(bout.toByteArray(), UTF8);\n        if (tk.equals(token)) {\n            found = true;\n        } else {\n            ungetToken(token);\n        }\n\n        return found;\n    }\n\n    /**\n     * Get a line\n     * \n     * @param input Input stream\n     * @return Line\n     */\n    public String getLine(ByteArrayInputStream input) {\n        ByteArrayOutputStream bout = new ByteArrayOutputStream();\n        if (input.available() > 0) {\n            int ch = readChar(input);\n            while (ch != '\\n' && ch != '\\r' && ch != -1) {\n                bout.write(ch);\n                ch = readChar(input);\n            }\n        }\n        return new String(bout.toByteArray(), UTF8);\n    }\n\n    /**\n     * Skip whitespace\n     * \n     * @param input Input stream\n     */\n    private void skipWhitespace(ByteArrayInputStream input) {\n        int ch = readChar(input);\n        while (ch == ' ' || ch == '\\n' || ch == '\\r') {\n            ch = readChar(input);\n        }\n        buffer.insertElementAt(Integer.valueOf(ch), 0);\n    }\n\n    /**\n     * Read char\n     * \n     * @param input Input stream\n     */\n    private int readChar(ByteArrayInputStream input) {\n        int ch;\n        if (buffer.size() > 0) {\n            ch = (buffer.elementAt(0)).intValue();\n            buffer.removeElementAt(0);\n        } else {\n            ch = input.read();\n        }\n        return ch;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/SdpParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.Vector;\n\n/**\n * SDP parser\n *\n * @author jexa7410\n */\npublic class SdpParser extends Parser {\n    /**\n     * Session description\n     */\n    public SessionDescription sessionDescription = new SessionDescription();\n\n    /**\n     * Media description\n     */\n    public Vector<MediaDescription> mediaDescriptions = new Vector<>();\n\n    /**\n     * Input stream\n     */\n    private ByteArrayInputStream bin = null;\n\n    /**\n     * Constructor\n     *\n     * @param data Data\n     */\n    public SdpParser(byte data[]) {\n        bin = new ByteArrayInputStream(data);\n        if (getToken(bin, \"v=\")) {\n            parseSessionDescription();\n            parseMediaDescriptions();\n        }\n    }\n\n    /**\n     * Parse session description\n     */\n    private void parseSessionDescription() {\n        // Protocol version\n        sessionDescription.version = getLine(bin);\n\n        // Origin\n        if (getToken(bin, \"o=\")) {\n            sessionDescription.origin = getLine(bin);\n        }\n\n        // Session name\n        if (getToken(bin, \"s=\")) {\n            sessionDescription.sessionName = getLine(bin);\n        }\n\n        // Session and media Information\n        if (getToken(bin, \"i=\")) {\n            sessionDescription.sessionInfo = getLine(bin);\n        }\n\n        // URI\n        if (getToken(bin, \"u=\")) {\n            sessionDescription.uri = getLine(bin);\n        }\n\n        // E-Mail\n        if (getToken(bin, \"e=\")) {\n            sessionDescription.email = getLine(bin);\n        }\n\n        // Phone number\n        if (getToken(bin, \"p=\")) {\n            sessionDescription.phone = getLine(bin);\n        }\n\n        // Connection information\n        if (getToken(bin, \"c=\")) {\n            sessionDescription.connectionInfo = getLine(bin);\n        }\n\n        // Bandwidth information\n        while (getToken(bin, \"b=\")) {\n            // session bandwidth information is not used right now; just consumed for parsing\n            sessionDescription.bandwidthInfo = getLine(bin);\n        }\n\n        // Time description\n        sessionDescription.timeDescriptions = new Vector<>();\n        while (getToken(bin, \"t=\")) {\n            TimeDescription timeDescription = parseTimeDescription();\n            this.sessionDescription.timeDescriptions.addElement(timeDescription);\n        }\n\n        // Time zone adjustments\n        if (getToken(bin, \"z=\")) {\n            sessionDescription.timezoneAdjustment = getLine(bin);\n        }\n\n        // Encryption key\n        if (getToken(bin, \"k=\")) {\n            sessionDescription.encryptionKey = getLine(bin);\n        }\n\n        // Session attributes\n        sessionDescription.sessionAttributes = new Vector<>();\n        while (getToken(bin, \"a=\")) {\n            String sessionAttribute = getLine(bin);\n            int index = sessionAttribute.indexOf(':');\n            if (index > 0) {\n                String name = sessionAttribute.substring(0, index);\n                String value = sessionAttribute.substring(index + 1);\n                MediaAttribute attribute = new MediaAttribute(name, value);\n                sessionDescription.sessionAttributes.addElement(attribute);\n            }\n        }\n    }\n\n    /**\n     * Parse time description\n     *\n     * @return Time description\n     */\n    private TimeDescription parseTimeDescription() {\n        TimeDescription td = new TimeDescription();\n\n        // Time the session is active\n        td.timeActive = getLine(bin);\n\n        // Repeat times\n        td.repeatTimes = new Vector<>();\n        while (getToken(bin, \"r=\")) {\n            String repeatTime = getLine(bin);\n            td.repeatTimes.addElement(repeatTime);\n        }\n\n        return td;\n    }\n\n    /**\n     * Parse media descriptions\n     */\n    private void parseMediaDescriptions() {\n        while (getToken(bin, \"m=\")) {\n            Vector<MediaDescription> descs = new Vector<>();\n\n            // Media name and transport address\n            String line = getLine(bin);\n            int end = line.indexOf(' ');\n            String name = line.substring(0, end);\n\n            int start = end + 1;\n            end = line.indexOf(' ', start);\n            int port = Integer.parseInt(line.substring(start, end));\n\n            start = end + 1;\n            end = line.indexOf(' ', start);\n            String protocol = line.substring(start, end);\n\n            String payload;\n            start = end + 1;\n            end = line.indexOf(' ', start);\n            while (end != -1) {\n                payload = line.substring(start, end);\n                descs.addElement(new MediaDescription(name, port, protocol, payload));\n                start = end + 1;\n                end = line.indexOf(' ', start);\n            }\n            payload = line.substring(start);\n            descs.addElement(new MediaDescription(name, port, protocol, payload));\n\n            // Session and media information\n            if (getToken(bin, \"i=\")) {\n                String mediaTitle = getLine(bin);\n                for (int i = 0; i < descs.size(); i++) {\n                    descs.elementAt(i).mMediaTitle = mediaTitle;\n                }\n            }\n\n            // Connection information\n            if (getToken(bin, \"c=\")) {\n                String connectionInfo = getLine(bin);\n                for (int i = 0; i < descs.size(); i++) {\n                    descs.elementAt(i).mConnectionInfo = connectionInfo;\n                }\n            }\n\n            // Bandwidth information\n            while (getToken(bin, \"b=\")) {\n                line = getLine(bin);\n                int index = line.indexOf(':');\n                if (index > 0) {\n                    String valueAttribute = line.substring(index + 1);\n                    if (line.contains(\"AS\")) {\n                        for (int i = 0; i < descs.size(); i++) {\n                            descs.elementAt(i).mBandwidthInfo = valueAttribute;\n                        }\n                    } else if (line.contains(\"RS\")) {\n                        for (int i = 0; i < descs.size(); i++) {\n                            descs.elementAt(i).mSenderBandwidthInfo = valueAttribute;\n                        }\n                    } else if (line.contains(\"RR\")) {\n                        for (int i = 0; i < descs.size(); i++) {\n                            descs.elementAt(i).mReceiverBandwidthInfo = valueAttribute;\n                        }\n                    }\n                }\n            }\n\n            // Encryption key\n            if (getToken(bin, \"k=\")) {\n                String encryptionKey = getLine(bin);\n                for (int i = 0; i < descs.size(); i++) {\n                    descs.elementAt(i).mEncryptionKey = encryptionKey;\n                }\n            }\n\n            // Media attributes\n            while (getToken(bin, \"a=\")) {\n                line = getLine(bin);\n                int index = line.indexOf(':');\n                if (index > 0) {\n                    String nameAttribute = line.substring(0, index);\n                    String valueAttribute = line.substring(index + 1);\n                    MediaAttribute attribute = new MediaAttribute(nameAttribute, valueAttribute);\n\n                    // Dispatch for specific payload\n                    if (valueAttribute.indexOf(' ') != -1) {\n                        // Add the attribute only for same payload\n                        boolean payloadFound = false;\n                        for (int i = 0; i < descs.size(); i++) {\n                            // Check if first element is a payload\n                            if (valueAttribute.startsWith(descs.elementAt(i).mPayload)) {\n                                descs.elementAt(i).mMediaAttributes.addElement(attribute);\n                                payloadFound = true;\n                            }\n                        }\n                        // Add for all if first element is not a payload\n                        if (!payloadFound) {\n                            for (int i = 0; i < descs.size(); i++) {\n                                descs.elementAt(i).mMediaAttributes.addElement(attribute);\n                            }\n                        }\n                    } else {\n                        // Add for all\n                        for (int i = 0; i < descs.size(); i++) {\n                            descs.elementAt(i).mMediaAttributes.addElement(attribute);\n                        }\n                    }\n                }\n            }\n\n            // Copy in media descriptions\n            for (int i = 0; i < descs.size(); i++) {\n                mediaDescriptions.addElement(descs.elementAt(i));\n            }\n        }\n    }\n\n    /**\n     * Returns session attribute\n     *\n     * @param name Attribute name\n     * @return Attribute\n     */\n    public MediaAttribute getSessionAttribute(String name) {\n        if (sessionDescription != null) {\n            return sessionDescription.getSessionAttribute(name);\n        }\n        return null;\n    }\n\n    /**\n     * Returns a media description\n     *\n     * @param name Media name\n     * @return Media\n     */\n    public MediaDescription getMediaDescription(String name) {\n        MediaDescription description = null;\n        if (mediaDescriptions != null) {\n            for (int i = 0; i < mediaDescriptions.size(); i++) {\n                MediaDescription entry = mediaDescriptions.elementAt(i);\n                if (entry.mName.equals(name)) {\n                    description = entry;\n                    break;\n                }\n            }\n        }\n        return description;\n    }\n\n    /**\n     * Returns media descriptions\n     *\n     * @param name Media name\n     * @return Medias\n     */\n    public Vector<MediaDescription> getMediaDescriptions(String name) {\n        Vector<MediaDescription> result = new Vector<>();\n        if (mediaDescriptions != null) {\n            for (int i = 0; i < mediaDescriptions.size(); i++) {\n                MediaDescription entry = mediaDescriptions.elementAt(i);\n                if (entry.mName.equals(name)) {\n                    result.add(entry);\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Returns all media descriptions\n     *\n     * @return Medias\n     */\n    public Vector<MediaDescription> getMediaDescriptions() {\n        return mediaDescriptions;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/SdpUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.security.cert.KeyStoreManager;\nimport com.gsma.rcs.utils.InetAddressUtils;\nimport com.gsma.rcs.utils.StringUtils;\n\n/**\n * SDP utility functions\n * \n * @author jexa7410\n */\npublic class SdpUtils {\n    // Changed by Deutsche Telekom\n    // name of SDP fingerprint attribute\n    final private static String FINGERPRINT = \"fingerprint\";\n\n    // Changed by Deutsche Telekom\n    // directions\n    final public static String DIRECTION_SENDONLY = \"sendonly\";\n    final public static String DIRECTION_RECVONLY = \"recvonly\";\n    final public static String DIRECTION_SENDRECV = \"sendrecv\";\n\n    // Changed by Deutsche Telekom\n    // protocols\n    final public static String MSRPS_PROTOCOL = \"TCP/TLS/MSRP\";\n    final public static String MSRP_PROTOCOL = \"TCP/MSRP\";\n\n    /**\n     * Extract the remote host address from the connection info\n     * \n     * @param connectionInfo Connection info\n     * @return Address\n     */\n    public static String extractRemoteHost(String connectionInfo) {\n        // c=IN IP4 172.20.138.145\n        String[] tokens = connectionInfo.split(\" \");\n        if (tokens.length > 2) {\n            return tokens[2];\n        }\n        return null;\n    }\n\n    /**\n     * Extract the remote host address from the connection info\n     * \n     * @param sessionDescription Session description part of SDP\n     * @param mediaDescription Media description part of SDP\n     * @return Remote host address or null if not found\n     */\n    public static String extractRemoteHost(SessionDescription sessionDescription,\n            MediaDescription mediaDescription) {\n        String remoteHost = null;\n\n        // First we need try to use the media description connection info\n        if ((mediaDescription != null) && (mediaDescription.mConnectionInfo != null)) {\n            remoteHost = extractRemoteHost(mediaDescription.mConnectionInfo);\n        }\n\n        // If media description has no connection info or remote host information, we need to try\n        // to use the session description connection info\n        if ((remoteHost == null) && (sessionDescription != null)\n                && (sessionDescription.connectionInfo != null)) {\n            remoteHost = extractRemoteHost(sessionDescription.connectionInfo);\n        }\n        return remoteHost;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Extract the fingerprint from certificate announced by remote\n     * \n     * @param parser SDP parser\n     * @param mediaDescription media description part of SDP\n     * @return fingerprint\n     */\n    public static String extractFingerprint(SdpParser parser, MediaDescription mediaDescription) {\n        String fingerprint = null;\n        if (parser != null && parser.getSessionAttribute(FINGERPRINT) != null) {\n            fingerprint = new String(parser.getSessionAttribute(FINGERPRINT).getValue());\n        }\n        if (mediaDescription != null && mediaDescription.getMediaAttribute(FINGERPRINT) != null) {\n            fingerprint = new String(mediaDescription.getMediaAttribute(FINGERPRINT).getValue());\n        }\n        return fingerprint;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Check if an SDP attribute from media description contains a specific value\n     * \n     * @param mediaDesc {@link MediaDescription}\n     * @param sdpAttribute SDP attribute string\n     * @param sdpAttributeValue SDP attribute value\n     * @param supportAllValuesCharacter {@link true} for assume that contains the value if attribute\n     *            contains '*' as value, {@link false} to force find the specific value\n     * @return {@link true} if contains the specific value, otherwise {@link false}\n     */\n    public static boolean attributeContains(MediaDescription mediaDesc, String sdpAttribute,\n            String sdpAttributeValue, boolean supportAllValuesCharacter) {\n\n        if (mediaDesc == null || StringUtils.isEmpty(sdpAttribute)\n                || StringUtils.isEmpty(sdpAttributeValue)) {\n            return false;\n        }\n\n        MediaAttribute mediaSdpAttrib = mediaDesc.getMediaAttribute(sdpAttribute);\n\n        if (mediaSdpAttrib != null && !StringUtils.isEmpty(mediaSdpAttrib.getValue())) {\n            if (supportAllValuesCharacter) {\n                if (\"*\".equals(mediaSdpAttrib.getValue().trim())) {\n                    return true;\n                }\n            }\n\n            String[] attribValues = mediaSdpAttrib.getValue().split(\"[\\\\s]+\");\n            for (int i = 0; i < attribValues.length; i++) {\n                if (sdpAttributeValue.equalsIgnoreCase(attribValues[i].trim())) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Format \"IN IP\" attribute (4 or 6)\n     * \n     * @param address IP address\n     * @return \"IN IP4 address\" or \"IN IP6 address\"\n     */\n    public static String formatAddressType(String address) {\n        if (InetAddressUtils.isIPv6Address(address)) {\n            return \"IN IP6 \".concat(address);\n        }\n        return \"IN IP4 \".concat(address);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Build an SDP block for an One-2-One chat sessions\n     * \n     * @param ipAddress local IP address used in o and c line\n     * @param localPort local port used in m line\n     * @param protocol protocol used in m line\n     * @param acceptTypes accepted MIME types\n     * @param wrapperTypes accepted wrapper types\n     * @param setup connection setup (active, passive, actpass)\n     * @param path\n     * @param direction message direction (sendrecv, recvonly)\n     * @return SDP\n     */\n    public static String buildChatSDP(String ipAddress, int localPort, String protocol,\n            String acceptTypes, String wrapperTypes, String setup, String path, String direction) {\n        return buildSDP(ipAddress, localPort, protocol, acceptTypes, wrapperTypes, null, null,\n                null, setup, path, direction, null, 0);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Build an SDP block for a group chat sessions\n     * \n     * @param ipAddress local IP address used in o and c line\n     * @param localPort local port used in m line\n     * @param protocol protocol used in m line\n     * @param acceptTypes accepted MIME types\n     * @param wrapperTypes accepted wrapper types\n     * @param setup connection setup (active, passive, actpass)\n     * @param path\n     * @param direction message direction (sendrecv, recvonly)\n     * @return SDP\n     */\n    public static String buildGroupChatSDP(String ipAddress, int localPort, String protocol,\n            String acceptTypes, String wrapperTypes, String setup, String path, String direction) {\n        return buildSDP(ipAddress, localPort, protocol, acceptTypes, wrapperTypes, null, null,\n                null, setup, path, direction, null, 0);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * @param ipAddress local IP address used in o and c line\n     * @param localPort local port used in m line\n     * @param protocol protocol used in m line\n     * @param acceptTypes accepted MIME types\n     * @param transferId file-transfer-id\n     * @param selector file-selector\n     * @param disposition file-disposition (used only when sendonly)\n     * @param setup connection setup (active, passive, actpass)\n     * @param path\n     * @param direction message direction (sendonly, recvonly)\n     * @param maxSize maximum file size\n     * @return SDP\n     */\n    public static String buildFileSDP(String ipAddress, int localPort, String protocol,\n            String acceptTypes, String transferId, String selector, String disposition,\n            String setup, String path, String direction, long maxSize) {\n        return buildSDP(ipAddress, localPort, protocol, acceptTypes, null, transferId, selector,\n                disposition, setup, path, direction, null, maxSize);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * @param ipAddress local IP address used in o and c line\n     * @param media media part\n     * @param direction message direction (sendonly, recvonly)\n     * @return SDP\n     */\n    public static String buildVideoSDP(String ipAddress, String media, String direction) {\n        return buildSDP(ipAddress, 0, null, null, null, null, null, null, null, null, direction,\n                media, 0);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * @param ipAddress local IP address used in o and c line\n     * @param protocol protocol used in m line\n     * @param acceptTypes accepted MIME types\n     * @param selector file-selector\n     * @param media media description (used for video share)\n     * @param maxSize maximum file size\n     * @return SDP\n     */\n    public static String buildCapabilitySDP(String ipAddress, String protocol, String acceptTypes,\n            String selector, String media, long maxSize) {\n        return buildSDP(ipAddress, 0, protocol, acceptTypes, null, null, selector, null, null,\n                null, null, media, maxSize);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * @param ipAddress local IP address used in o and c line\n     * @param localPort local port used in m line\n     * @param protocol protocol used in m line\n     * @param acceptTypes accepted MIME types\n     * @param wrapperTypes accepted wrapper types\n     * @param transferId file-transfer-id\n     * @param selector file-selector\n     * @param disposition file-disposition\n     * @param setup connection setup (active, passive, actpass)\n     * @param path\n     * @param direction message direction (sendrecv, recvonly, sendonly)\n     * @param media media description (used for video share)\n     * @param maxSize maximum file size\n     * @return SDP\n     */\n    private static String buildSDP(String ipAddress, int localPort, String protocol,\n            String acceptTypes, String wrapperTypes, String transferId, String selector,\n            String disposition, String setup, String path, String direction, String media,\n            long maxSize) {\n        String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis());\n\n        StringBuffer sdp = new StringBuffer(\"v=0\" + SipUtils.CRLF + \"o=- \" + ntpTime + \" \"\n                + ntpTime + \" \" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"s=-\"\n                + SipUtils.CRLF + \"c=\" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF\n                + \"t=0 0\" + SipUtils.CRLF);\n\n        if (media != null) {\n            sdp.append(media);\n        }\n\n        if (protocol != null) {\n            sdp.append(\"m=message \" + localPort + \" \" + protocol + \" *\" + SipUtils.CRLF);\n        }\n\n        appendIfNotNull(sdp, \"a=accept-types:\", acceptTypes);\n\n        appendIfNotNull(sdp, \"a=accept-wrapped-types:\", wrapperTypes);\n\n        appendIfNotNull(sdp, \"a=file-transfer-id:\", transferId);\n\n        appendIfNotNull(sdp, \"a=file-disposition:\", disposition);\n\n        if ((selector != null) && (selector.length() > 0)) {\n            // SDP used for file sharing services\n            appendIfNotNull(sdp, \"a=file-selector:\", selector);\n        } else {\n            // SDP that may be used for capability exchange\n            appendIfNotNull(sdp, \"a=file-selector\", selector);\n        }\n\n        appendIfNotNull(sdp, \"a=setup:\", setup);\n\n        appendIfNotNull(sdp, \"a=path:\", path);\n\n        if (MSRPS_PROTOCOL.equalsIgnoreCase(protocol)) {\n            appendIfNotNull(sdp, \"a=\" + FINGERPRINT + \":SHA-1 \",\n                    KeyStoreManager.getClientCertificateFingerprint());\n        }\n\n        appendIfNotNull(sdp, \"a=\", direction);\n\n        if (maxSize > 0) {\n            sdp.append(\"a=max-size:\" + maxSize + SipUtils.CRLF);\n        }\n\n        return new String(sdp);\n    }\n\n    // Changed by Deutsche Telekom\n    private static void appendIfNotNull(StringBuffer sdp, String tag, String value) {\n        if (value != null) {\n            sdp.append(tag + value + SipUtils.CRLF);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/SessionDescription.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\nimport java.util.Vector;\n\n/**\n * Session description\n * \n * @author jexa7410\n */\npublic class SessionDescription {\n    public Vector<TimeDescription> timeDescriptions;\n\n    public Vector<MediaAttribute> sessionAttributes;\n\n    public boolean connectionIncluded;\n\n    public String version;\n\n    public String origin;\n\n    public String sessionName;\n\n    public String sessionInfo;\n\n    public String uri;\n\n    public String email;\n\n    public String phone;\n\n    public String connectionInfo;\n\n    public String bandwidthInfo;\n\n    public String timezoneAdjustment;\n\n    public String encryptionKey;\n\n    public MediaAttribute getSessionAttribute(String name) {\n        MediaAttribute attribute = null;\n        if (sessionAttributes != null) {\n            for (int i = 0; i < sessionAttributes.size(); i++) {\n                MediaAttribute entry = sessionAttributes.elementAt(i);\n                if (entry.getName().equals(name)) {\n                    attribute = entry;\n                    break;\n                }\n            }\n        }\n        return attribute;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sdp/TimeDescription.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sdp;\n\nimport java.util.Vector;\n\n/**\n * Time description\n * \n * @author jexa7410\n */\npublic class TimeDescription {\n    public String timeActive;\n\n    public Vector<String> repeatTimes;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/KeepAliveManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Keep-alive manager (see RFC 5626)\n * \n * @author BJ\n */\npublic class KeepAliveManager extends PeriodicRefresher {\n    /**\n     * Keep-alive period (in milliseconds)\n     */\n    private long mPeriod;\n\n    /**\n     * SIP interface\n     */\n    private SipInterface mSip;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(KeepAliveManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param sip\n     * @param rcsSettings\n     */\n    public KeepAliveManager(SipInterface sip, RcsSettings rcsSettings) {\n        mSip = sip;\n        mPeriod = rcsSettings.getSipKeepAlivePeriod();\n    }\n\n    /**\n     * Start\n     */\n    public void start() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start keep-alive\");\n        }\n        startTimer(System.currentTimeMillis(), mPeriod);\n    }\n\n    /**\n     * Start\n     */\n    public void stop() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop keep-alive\");\n        }\n        stopTimer();\n    }\n\n    /**\n     * Keep-alive processing\n     * \n     * @throws NetworkException\n     */\n    public void periodicProcessing() throws NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Send keep-alive\");\n            }\n            /* Send a double-CRLF */\n            mSip.getDefaultSipProvider().getListeningPoints()[0].sendHeartbeat(\n                    mSip.getOutboundProxyAddr(), mSip.getOutboundProxyPort());\n            startTimer(System.currentTimeMillis(), mPeriod);\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to send keep-alive!\", e);\n        }\n    }\n\n    /**\n     * @param period the keep alive period in milliseconds\n     */\n    public void setPeriod(long period) {\n        mPeriod = period;\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Set keep-alive period \\\"\" + period + \"\\\"\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipDialogPath.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.platform.registry.RegistryFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.IdGenerator;\n\nimport java.util.Vector;\n\nimport javax2.sip.Dialog;\n\n/**\n * SIP dialog path. A dialog path corresponds to a SIP session, for example from the INVITE to the\n * BYE.\n * \n * @author JM. Auffret\n */\npublic class SipDialogPath {\n    /**\n     * Last min session expire period key\n     */\n    private static final String REGISTRY_MIN_SESSION_EXPIRE_PERIOD = \"MinSessionExpirePeriod\";\n\n    /**\n     * SIP stack interface\n     */\n    private SipInterface mStack;\n\n    /**\n     * Call-Id\n     */\n    private String mCallId;\n\n    /**\n     * CSeq number\n     */\n    private long mCseq = 1;\n\n    /**\n     * Local tag\n     */\n    private String mLocalTag = IdGenerator.getIdentifier();\n\n    /**\n     * Remote tag\n     */\n    private String mRemoteTag;\n\n    /**\n     * Target\n     */\n    private String mTarget;\n\n    /**\n     * Local party\n     */\n    private String mLocalParty;\n\n    /**\n     * Remote party\n     */\n    private String mRemoteParty;\n\n    /**\n     * Initial INVITE request\n     */\n    private SipRequest mInvite;\n\n    /**\n     * Local content\n     */\n    private String mLocalContent;\n\n    /**\n     * Remote content\n     */\n    private String mRemoteContent;\n\n    /**\n     * Remote sip instance\n     */\n    private String mRemoteSipInstance;\n\n    /**\n     * Route path\n     */\n    private Vector<String> mRoute;\n\n    /**\n     * Authentication agent\n     */\n    private SessionAuthenticationAgent mAuthenticationAgent;\n\n    /**\n     * Session expire time in milliseconds\n     */\n    private long mSessionExpireTime;\n\n    /**\n     * Flag that indicates if the signalisation is established or not\n     */\n    private boolean mSigEstablished = false;\n\n    /**\n     * Flag that indicates if the session (sig + media) is established or not\n     */\n    private boolean mSessionEstablished = false;\n\n    /**\n     * Flag that indicates if the session has been cancelled by the end-user\n     */\n    private boolean mSessionCancelled = false;\n\n    /**\n     * Flag that indicates if the session has been terminated by the server\n     */\n    private boolean mSessionTerminated = false;\n\n    /**\n     * Session termination reason code\n     */\n    private int mSessionTerminationReasonCode = -1;\n\n    /**\n     * Session termination reason phrase\n     */\n    private String mSessionTerminationReasonPhrase;\n\n    /**\n     * Constructor\n     * \n     * @param stack SIP stack interface\n     * @param callId Call-Id\n     * @param cseq CSeq\n     * @param target Target\n     * @param localParty Local party\n     * @param remoteParty Remote party\n     * @param route Route path\n     * @param rcsSettings the RCS settings accessor\n     */\n    public SipDialogPath(SipInterface stack, String callId, long cseq, String target,\n            String localParty, String remoteParty, Vector<String> route, RcsSettings rcsSettings) {\n        mStack = stack;\n        mCallId = callId;\n        mCseq = cseq;\n        mTarget = SipUtils.extractUriFromAddress(target);\n        mLocalParty = localParty;\n        mRemoteParty = remoteParty;\n        mRoute = route;\n\n        long defaultExpireTime = rcsSettings.getSessionRefreshExpirePeriod();\n        long minExpireValue = RegistryFactory.getFactory().readLong(\n                REGISTRY_MIN_SESSION_EXPIRE_PERIOD, -1);\n        if ((defaultExpireTime > SessionTimerManager.MIN_EXPIRE_PERIOD) && (minExpireValue != -1)\n                && (defaultExpireTime < minExpireValue)) {\n            mSessionExpireTime = minExpireValue;\n        } else {\n            mSessionExpireTime = defaultExpireTime;\n        }\n    }\n\n    /**\n     * Constructor<br>\n     * Perform a deep copy of the dialogPath\n     * \n     * @param dialogPath the dialog path\n     */\n    public SipDialogPath(SipDialogPath dialogPath) {\n        mStack = dialogPath.getSipStack();\n        mCallId = dialogPath.getCallId();\n        mCseq = dialogPath.getCseq();\n        mLocalTag = dialogPath.getLocalTag();\n        mRemoteTag = dialogPath.getRemoteTag();\n        mTarget = dialogPath.getTarget();\n        mLocalParty = dialogPath.getLocalParty();\n        mRemoteParty = dialogPath.getRemoteParty();\n        mInvite = dialogPath.getInvite();\n        mLocalContent = dialogPath.getLocalContent();\n        mRemoteContent = dialogPath.getRemoteContent();\n        mRemoteSipInstance = dialogPath.getRemoteSipInstance();\n        mRoute = dialogPath.getRoute();\n        mAuthenticationAgent = dialogPath.getAuthenticationAgent();\n        mSessionExpireTime = dialogPath.getSessionExpireTime();\n        mSigEstablished = dialogPath.isSigEstablished();\n        mSessionEstablished = dialogPath.isSessionEstablished();\n        mSessionCancelled = dialogPath.isSessionCancelled();\n        mSessionTerminated = dialogPath.isSessionTerminated();\n        mSessionTerminationReasonCode = dialogPath.getSessionTerminationReasonCode();\n        mSessionTerminationReasonPhrase = dialogPath.getSessionTerminationReasonPhrase();\n    }\n\n    /**\n     * Get the current SIP stack interface\n     * \n     * @return SIP stack interface\n     */\n    public SipInterface getSipStack() {\n        return mStack;\n    }\n\n    /**\n     * Get the target of the dialog path\n     * \n     * @return String\n     */\n    public String getTarget() {\n        return mTarget;\n    }\n\n    /**\n     * Set the target of the dialog path\n     * \n     * @param tg Target address\n     */\n    public void setTarget(String tg) {\n        mTarget = tg;\n    }\n\n    /**\n     * Get the local party of the dialog path\n     * \n     * @return String\n     */\n    public String getLocalParty() {\n        return mLocalParty;\n    }\n\n    /**\n     * Get the remote party of the dialog path\n     * \n     * @return String\n     */\n    public String getRemoteParty() {\n        return mRemoteParty;\n    }\n\n    /**\n     * Get the local tag of the dialog path\n     * \n     * @return String\n     */\n    public String getLocalTag() {\n        return mLocalTag;\n    }\n\n    /**\n     * Get the remote tag of the dialog path\n     * \n     * @return String\n     */\n    public String getRemoteTag() {\n        return mRemoteTag;\n    }\n\n    /**\n     * Set the remote tag of the dialog path\n     * \n     * @param tag Remote tag\n     */\n    public void setRemoteTag(String tag) {\n        mRemoteTag = tag;\n    }\n\n    /**\n     * Get the call-id of the dialog path\n     * \n     * @return String\n     */\n    public String getCallId() {\n        return mCallId;\n    }\n\n    /**\n     * Return the Cseq number of the dialog path\n     * \n     * @return Cseq number\n     */\n    public long getCseq() {\n        return mCseq;\n    }\n\n    /**\n     * Increment the Cseq number of the dialog path\n     */\n    public void incrementCseq() {\n        mCseq++;\n\n        // Increment internal stack CSeq if terminating side (NIST stack issue?)\n        Dialog dlg = getStackDialog();\n        if ((dlg != null) && dlg.isServer()) {\n            dlg.incrementLocalSequenceNumber();\n        }\n    }\n\n    /**\n     * Get the initial INVITE request of the dialog path\n     * \n     * @return String\n     */\n    public SipRequest getInvite() {\n        return mInvite;\n    }\n\n    /**\n     * Set the initial INVITE request of the dialog path\n     * \n     * @param invite INVITE request\n     */\n    public void setInvite(SipRequest invite) {\n        mInvite = invite;\n    }\n\n    /**\n     * Returns the local content\n     * \n     * @return String\n     */\n    public String getLocalContent() {\n        return mLocalContent;\n    }\n\n    /**\n     * Returns the remote content\n     * \n     * @return String\n     */\n    public String getRemoteContent() {\n        return mRemoteContent;\n    }\n\n    /**\n     * Sets the local content\n     * \n     * @param local Local content\n     */\n    public void setLocalContent(String local) {\n        mLocalContent = local;\n    }\n\n    /**\n     * Returns the remote SIP instance ID\n     * \n     * @return String\n     */\n    public String getRemoteSipInstance() {\n        return mRemoteSipInstance;\n    }\n\n    /**\n     * Sets the remote SIP instance ID\n     * \n     * @param instanceId SIP instance ID\n     */\n    public void setRemoteSipInstance(String instanceId) {\n        mRemoteSipInstance = instanceId;\n    }\n\n    /**\n     * Sets the remote content\n     * \n     * @param remote Remote content\n     */\n    public void setRemoteContent(String remote) {\n        mRemoteContent = remote;\n    }\n\n    /**\n     * Returns the route path\n     * \n     * @return Vector of string\n     */\n    public Vector<String> getRoute() {\n        return mRoute;\n    }\n\n    /**\n     * Set the route path\n     * \n     * @param route New route path\n     */\n    public void setRoute(Vector<String> route) {\n        mRoute = route;\n    }\n\n    /**\n     * Is session cancelled\n     * \n     * @return Boolean\n     */\n    public boolean isSessionCancelled() {\n        return mSessionCancelled;\n    }\n\n    /**\n     * The session has been cancelled\n     */\n    public synchronized void setSessionCancelled() {\n        mSessionCancelled = true;\n    }\n\n    /**\n     * Is session established\n     * \n     * @return Boolean\n     */\n    public boolean isSessionEstablished() {\n        return mSessionEstablished;\n    }\n\n    /**\n     * Session is established\n     */\n    public synchronized void setSessionEstablished() {\n        mSessionEstablished = true;\n    }\n\n    /**\n     * Is session terminated\n     * \n     * @return Boolean\n     */\n    public boolean isSessionTerminated() {\n        return mSessionTerminated;\n    }\n\n    /**\n     * Session is terminated\n     */\n    public synchronized void setSessionTerminated() {\n        mSessionTerminated = true;\n        mSessionTerminationReasonCode = -1;\n        mSessionTerminationReasonPhrase = null;\n    }\n\n    /**\n     * Session is terminated with a specific reason code\n     * \n     * @param code Reason code\n     * @param phrase Reason phrase\n     */\n    public synchronized void setSessionTerminated(int code, String phrase) {\n        mSessionTerminated = true;\n        mSessionTerminationReasonCode = code;\n        mSessionTerminationReasonPhrase = phrase;\n    }\n\n    /**\n     * Get session termination reason code\n     * \n     * @return Reason code\n     */\n    public int getSessionTerminationReasonCode() {\n        return mSessionTerminationReasonCode;\n    }\n\n    /**\n     * Get session termination reason phrase\n     * \n     * @return Reason phrase\n     */\n    public String getSessionTerminationReasonPhrase() {\n        return mSessionTerminationReasonPhrase;\n    }\n\n    /**\n     * Is signalisation established with success\n     * \n     * @return Boolean\n     */\n    public boolean isSigEstablished() {\n        return mSigEstablished;\n    }\n\n    /**\n     * Signalisation is established with success\n     */\n    public synchronized void setSigEstablished() {\n        mSigEstablished = true;\n    }\n\n    /**\n     * Set the session authentication agent\n     * \n     * @param agent Authentication agent\n     */\n    public void setAuthenticationAgent(SessionAuthenticationAgent agent) {\n        mAuthenticationAgent = agent;\n    }\n\n    /**\n     * Returns the session authentication agent\n     * \n     * @return Authentication agent\n     */\n    public SessionAuthenticationAgent getAuthenticationAgent() {\n        return mAuthenticationAgent;\n    }\n\n    /**\n     * Returns the session expire value\n     * \n     * @return Session expire time in milliseconds\n     */\n    public long getSessionExpireTime() {\n        return mSessionExpireTime;\n    }\n\n    /**\n     * Set the session expire value\n     * \n     * @param sessionExpireTime Session expire time in milliseconds\n     */\n    public void setSessionExpireTime(long sessionExpireTime) {\n        mSessionExpireTime = sessionExpireTime;\n    }\n\n    /**\n     * Set the min session expire value\n     * \n     * @param sessionExpireTime Session expire time in milliseconds\n     */\n    public void setMinSessionExpireTime(long sessionExpireTime) {\n        RegistryFactory.getFactory().writeLong(REGISTRY_MIN_SESSION_EXPIRE_PERIOD,\n                sessionExpireTime);\n    }\n\n    /**\n     * Get stack dialog\n     * \n     * @return Dialog or null\n     */\n    public Dialog getStackDialog() {\n        if (mInvite != null) {\n            return mInvite.getStackTransaction().getDialog();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\n/**\n * SIP event listener\n * \n * @author jexa7410\n */\npublic interface SipEventListener {\n    /**\n     * Receive SIP request\n     * \n     * @param request SIP request\n     */\n    void receiveSipRequest(SipRequest request);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext.INotifySipProvisionalResponse;\nimport com.gsma.rcs.core.ims.security.cert.KeyStoreManager;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.InetAddressUtils;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.message.SIPMessage;\n\nimport java.io.File;\nimport java.security.KeyStoreException;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Properties;\nimport java.util.TooManyListenersException;\nimport java.util.Vector;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.DialogTerminatedEvent;\nimport javax2.sip.IOExceptionEvent;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.ListeningPoint;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.RequestEvent;\nimport javax2.sip.ResponseEvent;\nimport javax2.sip.ServerTransaction;\nimport javax2.sip.SipException;\nimport javax2.sip.SipFactory;\nimport javax2.sip.SipListener;\nimport javax2.sip.SipProvider;\nimport javax2.sip.SipStack;\nimport javax2.sip.TimeoutEvent;\nimport javax2.sip.TransactionAlreadyExistsException;\nimport javax2.sip.TransactionTerminatedEvent;\nimport javax2.sip.TransactionUnavailableException;\nimport javax2.sip.address.Address;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.address.URI;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/**\n * SIP interface which manage the SIP stack. The NIST stack is used statefully (i.e. messages are\n * sent via a SIP transaction). NIST release is nist-sip-96f517a (2010-10-29)\n *\n * @author JM. Auffret\n */\npublic class SipInterface implements SipListener {\n\n    private final static String TRACE_SEPARATOR = \"-----------------------------------------------------------------------------\";\n\n    /**\n     * SIP traces activation\n     */\n    private boolean mSipTraceEnabled;\n\n    private final String mSipTraceFile;\n\n    private final String mLocalIpAddress;\n\n    private final String mOutboundProxyAddr;\n\n    private int mOutboundProxyPort;\n\n    private final Vector<String> mDefaultRoutePath;\n\n    private final Vector<String> mServiceRoutePath;\n\n    private final int mListeningPort;\n\n    private final String mDefaultProtocol;\n\n    /**\n     * TCP fallback according to RFC3261 chapter 18.1.1\n     */\n    private final boolean mTcpFallback;\n\n    /**\n     * List of current SIP transactions\n     */\n    private final SipTransactionList mTransactions;\n\n    private final List<SipEventListener> mListeners;\n\n    private SipStack mSipStack;\n\n    private SipProvider mDefaultSipProvider;\n\n    private final List<SipProvider> mSipProviders;\n\n    private final KeepAliveManager mKeepAliveManager;\n\n    private String mPublicGruu;\n\n    private String mTempGruu;\n\n    private String mInstanceId;\n\n    /**\n     * Base timer T1 (in ms)\n     */\n    private long mTimerT1 = 500;\n\n    /**\n     * Base timer T2 (in ms)\n     */\n    private long mTimerT2 = 4000;\n\n    /**\n     * Base timer T4 (in ms)\n     */\n    private long mTimerT4 = 5000;\n\n    private static final Logger sLogger = Logger.getLogger(SipInterface.class.getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     *\n     * @param localIpAddress Local IP address\n     * @param proxyAddr Outbound proxy address\n     * @param proxyPort Outbound proxy port\n     * @param defaultProtocol Default protocol\n     * @param tcpFallback TCP fallback according to RFC3261 chapter 18.1.1\n     * @param rcsSettings The RCS settings accessor\n     */\n    public SipInterface(String localIpAddress, String proxyAddr, int proxyPort,\n            String defaultProtocol, boolean tcpFallback, RcsSettings rcsSettings) {\n        mLocalIpAddress = localIpAddress;\n        mDefaultProtocol = defaultProtocol;\n        mTcpFallback = tcpFallback;\n        mListeningPort = NetworkRessourceManager.generateLocalSipPort(rcsSettings);\n        mOutboundProxyAddr = proxyAddr;\n        mOutboundProxyPort = proxyPort;\n        mKeepAliveManager = new KeepAliveManager(this, rcsSettings);\n        mSipTraceEnabled = rcsSettings.isSipTraceActivated();\n        mSipTraceFile = rcsSettings.getSipTraceFile();\n        /* Set timers value from provisioning */\n        mTimerT1 = rcsSettings.getSipTimerT1();\n        mTimerT2 = rcsSettings.getSipTimerT2();\n        mTimerT4 = rcsSettings.getSipTimerT4();\n        /* Set the default route path */\n        mDefaultRoutePath = new Vector<>();\n        mDefaultRoutePath.addElement(getDefaultRoute());\n        /* Set the default service route path */\n        mServiceRoutePath = new Vector<>();\n        mServiceRoutePath.addElement(getDefaultRoute());\n        mRcsSettings = rcsSettings;\n        mSipProviders = new ArrayList<>();\n        mListeners = new ArrayList<>();\n        mTransactions = new SipTransactionList();\n    }\n\n    /**\n     * Initialize sip stack\n     *\n     * @throws PayloadException\n     */\n    public void initialize() throws PayloadException {\n        try {\n            /* Init SIP factories */\n            SipFactory sipFactory = SipFactory.getInstance();\n            SipUtils.HEADER_FACTORY = sipFactory.createHeaderFactory();\n            SipUtils.ADDR_FACTORY = sipFactory.createAddressFactory();\n            SipUtils.MSG_FACTORY = sipFactory.createMessageFactory();\n            /* Set SIP stack properties */\n            Properties properties = new Properties();\n            properties.setProperty(\"javax2.sip.STACK_NAME\", mLocalIpAddress);\n            properties.setProperty(\"gov2.nist.javax2.sip.THREAD_POOL_SIZE\", \"1\");\n            properties.setProperty(\"javax2.sip.OUTBOUND_PROXY\", getOutboundProxy());\n            if (mSipTraceEnabled) {\n                /* Activate SIP stack traces */\n                boolean cleanLog = true;\n                /* Remove previous log file */\n                File fs = new File(mSipTraceFile);\n                if (fs.exists()) {\n                    cleanLog = fs.delete();\n                }\n                if (cleanLog) {\n                    properties.setProperty(\"gov2.nist.javax2.sip.TRACE_LEVEL\", \"DEBUG\");\n                    properties.setProperty(\"gov2.nist.javax2.sip.SERVER_LOG\", mSipTraceFile);\n                    properties.setProperty(\"gov2.nist.javax2.sip.LOG_MESSAGE_CONTENT\", \"true\");\n                    properties.setProperty(\"gov2.nist.javax2.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND\",\n                            \"true\");\n                }\n            }\n            if (mDefaultProtocol.equals(ListeningPoint.TLS)) {\n                /* Set SSL properties */\n                properties.setProperty(\"gov2.nist.javax2.sip.TLS_CLIENT_PROTOCOLS\", \"SSLv3, TLSv1\");\n                if (KeyStoreManager.isOwnCertificateUsed(mRcsSettings)) {\n                    properties.setProperty(\"javax2.net.ssl.keyStoreType\",\n                            KeyStoreManager.getKeystoreType());\n                    String keyStorePath = KeyStoreManager.getKeystore().getPath();\n                    properties.setProperty(\"javax2.net.ssl.keyStore\", keyStorePath);\n                    properties.setProperty(\"javax2.net.ssl.keyStorePassword\",\n                            KeyStoreManager.getKeystorePassword());\n                    properties.setProperty(\"javax2.net.ssl.trustStore\", keyStorePath);\n                } else {\n                    properties.setProperty(\"gov2.nist.javax2.sip.NETWORK_LAYER\",\n                            \"gov2.nist.core.net.SslNetworkLayer\");\n                }\n            }\n            mSipStack = sipFactory.createSipStack(properties);\n            ListeningPoint udp = mSipStack.createListeningPoint(mLocalIpAddress, mListeningPort,\n                    ListeningPoint.UDP);\n            SipProvider udpSipProvider = mSipStack.createSipProvider(udp);\n            udpSipProvider.addSipListener(this);\n            mSipProviders.add(udpSipProvider);\n            /* Set the default SIP provider */\n            switch (mDefaultProtocol) {\n                case ListeningPoint.TLS:\n                    ListeningPoint tls = mSipStack.createListeningPoint(mLocalIpAddress,\n                            mListeningPort, ListeningPoint.TLS);\n                    SipProvider tlsSipProvider = mSipStack.createSipProvider(tls);\n                    tlsSipProvider.addSipListener(this);\n                    mSipProviders.add(tlsSipProvider);\n                    mDefaultSipProvider = tlsSipProvider;\n                    break;\n\n                case ListeningPoint.TCP: {\n                    ListeningPoint tcp = mSipStack.createListeningPoint(mLocalIpAddress,\n                            mListeningPort, ListeningPoint.TCP);\n                    SipProvider tcpSipProvider = mSipStack.createSipProvider(tcp);\n                    tcpSipProvider.addSipListener(this);\n                    mSipProviders.add(tcpSipProvider);\n                    mDefaultSipProvider = tcpSipProvider;\n                    break;\n                }\n                default: {\n                    ListeningPoint tcp = mSipStack.createListeningPoint(mLocalIpAddress,\n                            mListeningPort, ListeningPoint.TCP);\n                    if (!mTcpFallback) {\n                        SipProvider tcpSipProvider = mSipStack.createSipProvider(tcp);\n                        tcpSipProvider.addSipListener(this);\n                        mSipProviders.add(tcpSipProvider);\n                    }\n                    mDefaultSipProvider = udpSipProvider;\n                    if (mTcpFallback) {\n                        /* prepare 2nd listening point for TCP fallback */\n                        mDefaultSipProvider.addListeningPoint(tcp);\n                    }\n                    break;\n                }\n            }\n            if (sLogger.isActivated()) {\n                if (mDefaultProtocol.equals(ListeningPoint.UDP))\n                    sLogger.debug(\"Default SIP provider is UDP (TCP fallback=\" + mTcpFallback + \")\");\n                else\n                    sLogger.debug(\"Default SIP provider is \".concat(mDefaultProtocol));\n            }\n            mSipStack.start();\n\n        } catch (TooManyListenersException | SipException | KeyStoreException e) {\n            throw new PayloadException(\"Unable to instantiate SIP stack for localIpAddress : \"\n                    + mLocalIpAddress + \" with defaultProtocol : \" + mDefaultProtocol, e);\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"SIP stack initialized at \" + mLocalIpAddress + \":\" + mListeningPort);\n        }\n    }\n\n    private String getOutboundProxy() {\n        if (InetAddressUtils.isIPv6Address(mOutboundProxyAddr)) {\n            return \"[\" + mOutboundProxyAddr + \"]\" + ':' + mOutboundProxyPort + '/'\n                    + mDefaultProtocol;\n        }\n        return mOutboundProxyAddr + ':' + mOutboundProxyPort + '/' + mDefaultProtocol;\n    }\n\n    /**\n     * Close the SIP stack\n     */\n    public void close() {\n        try {\n            mKeepAliveManager.stop();\n            mListeners.clear();\n            for (SipProvider sipProvider : mSipProviders) {\n                sipProvider.removeSipListener(this);\n                sipProvider.removeListeningPoints();\n                try {\n                    mSipStack.deleteSipProvider(sipProvider);\n\n                } catch (ObjectInUseException e) {\n                    /* Nothing to be done here */\n                    sLogger.error(\"SipProvider still has an associated SipListener!\", e);\n                }\n            }\n        } finally {\n            if (mSipStack != null) {\n                mSipStack.stop();\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"SIP stack is null\");\n                }\n            }\n            SipFactory.getInstance().resetFactory();\n        }\n    }\n\n    /**\n     * Return the default SIP provider\n     *\n     * @return SIP provider\n     */\n    public SipProvider getDefaultSipProvider() {\n        return mDefaultSipProvider;\n    }\n\n    /**\n     * Create a transaction; either default or fallback provider is used (depending on request size)\n     *\n     * @param request the SIP request\n     * @return ClientTransaction\n     * @throws ParseException\n     * @throws SipException\n     */\n    private ClientTransaction createNewTransaction(SipRequest request) throws ParseException,\n            SipException {\n        // fall back to TCP if channel is UDP and request size exceeds the limit\n        // according to RFC3261, chapter 18.1.1:\n        // If a request is within 200 bytes of the path MTU, or if it is larger\n        // than 1300 bytes and the path MTU is unknown, the request MUST be sent\n        // using an RFC 2914 [43] congestion controlled transport protocol, such\n        // as TCP. If this causes a change in the transport protocol from the\n        // one indicated in the top Via, the value in the top Via MUST be\n        // changed.\n        if (ListeningPoint.UDP.equals(mDefaultProtocol) && mTcpFallback\n                && (request.getStackMessage().toString().length() > (mSipStack.getMtuSize() - 200))) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Transaction falls back to TCP as request size is \"\n                        + request.getStackMessage().toString().length() + \" and MTU size is \"\n                        + mSipStack.getMtuSize());\n            }\n            // Change Via header\n            ViaHeader topViaHeader = ((SIPMessage) request.getStackMessage()).getTopmostViaHeader();\n            if (topViaHeader != null) {\n                topViaHeader.setTransport(\"TCP\");\n            } else {\n                topViaHeader = SipUtils.HEADER_FACTORY.createViaHeader(mLocalIpAddress,\n                        mListeningPort, \"TCP\", null);\n            }\n            request.getStackMessage().removeFirst(ViaHeader.NAME);\n            request.getStackMessage().addFirst(topViaHeader);\n            // Change Route header\n            RouteHeader topRouteHeader = (RouteHeader) request.getStackMessage().getHeader(\n                    RouteHeader.NAME);\n            if (topRouteHeader != null) {\n                URI uri = topRouteHeader.getAddress().getURI();\n                if (uri.isSipURI()) {\n                    SipURI sipUri = (SipURI) uri;\n                    sipUri.setTransportParam(\"tcp\");\n                    AddressImpl address = new AddressImpl();\n                    address.setURI(sipUri);\n                    topRouteHeader = SipUtils.HEADER_FACTORY.createRouteHeader(address);\n                } else {\n                    // TODO\n                    // check whether this could happen anyhow and if so whether this would be valid\n                    sLogger.error(\"Update of route header due to TCP fallback failed due to wrong address format!\");\n                }\n                request.getStackMessage().removeFirst(RouteHeader.NAME);\n                request.getStackMessage().addFirst(topRouteHeader);\n            }\n        }\n        ClientTransaction transaction = mDefaultSipProvider.getNewClientTransaction(request\n                .getStackMessage());\n        /* NOTE: External API limiting timers that should be in type 'long' to 'int'. */\n        transaction.setRetransmitTimers((int) mTimerT1, (int) mTimerT2, (int) mTimerT4);\n        return transaction;\n    }\n\n    /**\n     * Returns the local IP address\n     *\n     * @return IP address\n     */\n    public String getLocalIpAddress() {\n        return mLocalIpAddress;\n    }\n\n    /**\n     * Returns the outbound proxy address\n     *\n     * @return Outbound proxy address\n     */\n    public String getOutboundProxyAddr() {\n        return mOutboundProxyAddr;\n    }\n\n    /**\n     * Returns the outbound proxy port\n     *\n     * @return Outbound proxy port\n     */\n    public int getOutboundProxyPort() {\n        return mOutboundProxyPort;\n    }\n\n    /**\n     * Returns the proxy protocol\n     *\n     * @return Outbound proxy protocol\n     */\n    public String getProxyProtocol() {\n        return mDefaultProtocol;\n    }\n\n    /**\n     * Returns the keep-alive manager\n     *\n     * @return Keep-alive manager\n     */\n    public KeepAliveManager getKeepAliveManager() {\n        return mKeepAliveManager;\n    }\n\n    /**\n     * Get public GRUU\n     *\n     * @return GRUU\n     */\n    public String getPublicGruu() {\n        return mPublicGruu;\n    }\n\n    /**\n     * Set public GRUU\n     *\n     * @param gruu GRUU\n     */\n    public void setPublicGruu(String gruu) {\n        mPublicGruu = gruu;\n    }\n\n    /**\n     * Set temporary GRUU\n     *\n     * @param gruu GRUU\n     */\n    public void setTemporaryGruu(String gruu) {\n        mTempGruu = gruu;\n    }\n\n    /**\n     * Get instance ID\n     *\n     * @return ID\n     */\n    public String getInstanceId() {\n        return mInstanceId;\n    }\n\n    /**\n     * Set instance ID\n     *\n     * @param id Instance ID\n     */\n    public void setInstanceId(String id) {\n        mInstanceId = id;\n    }\n\n    /**\n     * Returns the local via path\n     *\n     * @return List of headers\n     * @throws PayloadException\n     */\n    public List<ViaHeader> getViaHeaders() throws PayloadException {\n        try {\n            List<ViaHeader> viaHeaders = new ArrayList<>();\n            ViaHeader via = SipUtils.HEADER_FACTORY.createViaHeader(mLocalIpAddress,\n                    mListeningPort, getProxyProtocol(), null);\n            viaHeaders.add(via);\n            return viaHeaders;\n\n        } catch (ParseException | InvalidArgumentException e) {\n            throw new PayloadException(\"Can't create Via headers!\", e);\n        }\n    }\n\n    /**\n     * Generate a unique call-ID\n     *\n     * @return Call-Id\n     */\n    public String generateCallId() {\n        // Call-ID value follows RFC 3261, section 25.1\n        return IdGenerator.getIdentifier() + \"@\" + mLocalIpAddress;\n    }\n\n    /**\n     * Get local contact\n     *\n     * @return Header\n     * @throws PayloadException\n     */\n    public ContactHeader getLocalContact() throws PayloadException {\n        try {\n            // Set the contact with the terminal IP address, port and transport\n            SipURI contactURI = SipUtils.ADDR_FACTORY.createSipURI(null, mLocalIpAddress);\n            contactURI.setPort(mListeningPort);\n            contactURI.setParameter(\"transport\", mDefaultProtocol);\n            // Create the Contact header\n            Address contactAddress = SipUtils.ADDR_FACTORY.createAddress(contactURI);\n            return SipUtils.HEADER_FACTORY.createContactHeader(contactAddress);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to create SIP URI : \" + mLocalIpAddress, e);\n\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Unable to set port : \" + mListeningPort\n                    + \" for contact with ip address : \" + mLocalIpAddress, e);\n        }\n    }\n\n    /**\n     * Get contact based on local contact info and multidevice infos (GRUU, sip.instance)\n     *\n     * @return Header\n     * @throws PayloadException\n     */\n    public ContactHeader getContact() throws PayloadException {\n        try {\n            ContactHeader contactHeader;\n            if (mPublicGruu != null) {\n                // Create a contact with GRUU\n                SipURI contactURI = SipUtils.ADDR_FACTORY.createSipURI(mPublicGruu);\n                contactURI.setTransportParam(mDefaultProtocol);\n                Address contactAddress = SipUtils.ADDR_FACTORY.createAddress(contactURI);\n                contactHeader = SipUtils.HEADER_FACTORY.createContactHeader(contactAddress);\n\n            } else if (mInstanceId != null) {\n                // Create a local contact with an instance ID\n                contactHeader = getLocalContact();\n                contactHeader.setParameter(SipUtils.SIP_INSTANCE_PARAM, mInstanceId);\n            } else {\n                // Create a local contact\n                contactHeader = getLocalContact();\n            }\n            return contactHeader;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to create SIP URI : \" + mPublicGruu, e);\n        }\n    }\n\n    /**\n     * Returns the default route\n     *\n     * @return Route\n     */\n    public String getDefaultRoute() {\n        String defaultRoute;\n        if (InetAddressUtils.isIPv6Address(mOutboundProxyAddr)) {\n            defaultRoute = String.format(\"<sip:[%s]:%s;transport=%s;lr>\", mOutboundProxyAddr,\n                    mOutboundProxyPort, getProxyProtocol());\n        } else {\n            defaultRoute = String.format(\"<sip:%s:%s;transport=%s;lr>\", mOutboundProxyAddr,\n                    mOutboundProxyPort, getProxyProtocol());\n        }\n        return defaultRoute.toLowerCase();\n    }\n\n    /**\n     * Returns the default route path\n     *\n     * @return Route path\n     */\n    public Vector<String> getDefaultRoutePath() {\n        return mDefaultRoutePath;\n    }\n\n    /**\n     * Returns the service route path\n     *\n     * @return Route path\n     */\n    public Vector<String> getServiceRoutePath() {\n        return mServiceRoutePath;\n    }\n\n    /**\n     * Set the service route path\n     *\n     * @param routes List of routes\n     */\n    public void setServiceRoutePath(ListIterator<Header> routes) {\n        mServiceRoutePath.clear();\n        // Always add the outbound proxy\n        mServiceRoutePath.addElement(getDefaultRoute());\n        if (routes != null) {\n            // Add the received service route path\n            while (routes.hasNext()) {\n                ExtensionHeader route = (ExtensionHeader) routes.next();\n                String rt = route.getValue().toLowerCase();\n                if (!mServiceRoutePath.contains(rt)) {\n                    mServiceRoutePath.addElement(rt);\n                }\n            }\n        }\n    }\n\n    /**\n     * Add a SIP event listener\n     *\n     * @param listener Listener\n     */\n    public void addSipEventListener(SipEventListener listener) {\n        mListeners.add(listener);\n    }\n\n    /**\n     * Remove a transaction context from its ID\n     *\n     * @param id Transaction ID\n     */\n    public synchronized void removeTransactionContext(String id) {\n        mTransactions.remove(id);\n    }\n\n    /**\n     * Notify the transaction context that a message has been received (response or ACK)\n     *\n     * @param transactionId Transaction ID\n     * @param msg SIP message\n     */\n    private void notifyTransactionContext(String transactionId, SipMessage msg) {\n        SipTransactionContext ctx = mTransactions.get(transactionId);\n        if (ctx != null) {\n            removeTransactionContext(transactionId);\n            ctx.responseReceived(msg);\n        }\n    }\n\n    /**\n     * Send a SIP message and create a context to wait a response\n     *\n     * @param message SIP message\n     * @param callbackSipProvisionalResponse a callback to handle SIP provisional response\n     * @return Transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessageAndWait(SipMessage message,\n            INotifySipProvisionalResponse callbackSipProvisionalResponse) throws PayloadException,\n            NetworkException {\n        try {\n            if (message instanceof SipRequest) {\n                SipRequest req = (SipRequest) message;\n                ClientTransaction transaction = (ClientTransaction) req.getStackTransaction();\n                if (transaction == null) {\n                    transaction = createNewTransaction(req);\n                    req.setStackTransaction(transaction);\n                }\n                SipTransactionContext ctx = new SipTransactionContext(transaction,\n                        callbackSipProvisionalResponse);\n                String id = SipTransactionContext.getTransactionContextId(req);\n                mTransactions.put(id, ctx);\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Create a transaction context \".concat(id));\n                }\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\">>> Send SIP \".concat(req.getMethod()));\n                }\n                if (mSipTraceEnabled) {\n                    System.out.println(\">>> \" + req.getStackMessage().toString());\n                    System.out.println(TRACE_SEPARATOR);\n                }\n                transaction.sendRequest();\n                return ctx;\n            }\n            SipResponse resp = (SipResponse) message;\n            ServerTransaction transaction = (ServerTransaction) resp.getStackTransaction();\n            if (transaction == null) {\n                throw new NetworkException(\"No transaction exist for \" + resp.getCallId()\n                        + \": the response can't be sent!\");\n            }\n            SipTransactionContext ctx = new SipTransactionContext(transaction);\n            String id = SipTransactionContext.getTransactionContextId(resp);\n            mTransactions.put(id, ctx);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Create a transaction context \".concat(id));\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\">>> Send SIP \" + resp.getStatusCode() + \" response\");\n            }\n            if (mSipTraceEnabled) {\n                System.out.println(\">>> \" + resp.getStackMessage().toString());\n                System.out.println(TRACE_SEPARATOR);\n            }\n            transaction.sendResponse(resp.getStackMessage());\n            return ctx;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to instantiate SIP transaction!\", e);\n\n        } catch (SipException e) {\n            throw new NetworkException(\"Can't send SIP message!\", e);\n        }\n    }\n\n    /**\n     * Send a SIP message and create a context to wait a response\n     *\n     * @param message SIP message\n     * @return Transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSipMessageAndWait(SipMessage message) throws PayloadException,\n            NetworkException {\n        return sendSipMessageAndWait(message, null);\n    }\n\n    /**\n     * Send a SIP response\n     *\n     * @param response SIP response\n     * @throws NetworkException\n     */\n    public void sendSipResponse(SipResponse response) throws NetworkException {\n        try {\n            ServerTransaction transaction = (ServerTransaction) response.getStackTransaction();\n            if (transaction == null) {\n                throw new NetworkException(\"No transaction available for sending response!\");\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\">>> Send SIP \" + response.getStatusCode() + \" response\");\n            }\n            if (mSipTraceEnabled) {\n                System.out.println(\">>> \" + response.getStackMessage().toString());\n                System.out.println(TRACE_SEPARATOR);\n            }\n            transaction.sendResponse(response.getStackMessage());\n\n        } catch (SipException e) {\n            throw new NetworkException(\"Can't send SIP message!\", e);\n        }\n    }\n\n    /**\n     * Send a SIP ACK\n     *\n     * @param dialog Dialog path\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendSipAck(SipDialogPath dialog) throws PayloadException, NetworkException {\n        try {\n            SipRequest ack = SipMessageFactory.createAck(dialog);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\">>> Send SIP ACK\");\n            }\n            if (mSipTraceEnabled) {\n                System.out.println(\">>> \" + ack.getStackMessage().toString());\n                System.out.println(TRACE_SEPARATOR);\n            }\n            /* Re-use INVITE transaction */\n            dialog.getStackDialog().sendAck(ack.getStackMessage());\n\n        } catch (SipException e) {\n            throw new NetworkException(\"Can't send SIP message!\", e);\n        }\n    }\n\n    /**\n     * Send a SIP CANCEL\n     *\n     * @param dialog Dialog path\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendSipCancel(SipDialogPath dialog) throws PayloadException, NetworkException {\n        try {\n            if (dialog.getInvite().getStackTransaction() instanceof ServerTransaction) {\n                /* Server transaction can't send a cancel */\n                return;\n            }\n            SipRequest cancel = SipMessageFactory.createCancel(dialog);\n            SessionAuthenticationAgent agent = dialog.getAuthenticationAgent();\n            if (agent != null) {\n                agent.setProxyAuthorizationHeader(cancel);\n            }\n            ClientTransaction transaction = createNewTransaction(cancel);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\">>> Send SIP CANCEL\");\n            }\n            if (mSipTraceEnabled) {\n                System.out.println(\">>> \" + cancel.getStackMessage().toString());\n                System.out.println(TRACE_SEPARATOR);\n            }\n            transaction.sendRequest();\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to instantiate SIP transaction!\", e);\n\n        } catch (SipException e) {\n            throw new NetworkException(\"Can't send SIP message!\", e);\n        }\n    }\n\n    /**\n     * Send a SIP BYE\n     *\n     * @param dialog Dialog path\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendSipBye(SipDialogPath dialog) throws PayloadException, NetworkException {\n        boolean loggerActivated = sLogger.isActivated();\n        try {\n            SipRequest bye = SipMessageFactory.createBye(dialog);\n            SessionAuthenticationAgent agent = dialog.getAuthenticationAgent();\n            if (agent != null) {\n                agent.setProxyAuthorizationHeader(bye);\n            }\n            ClientTransaction transaction = createNewTransaction(bye);\n            if (loggerActivated) {\n                sLogger.debug(\">>> Send SIP BYE\");\n            }\n            if (mSipTraceEnabled) {\n                System.out.println(\">>> \" + bye.getStackMessage().toString());\n                System.out.println(TRACE_SEPARATOR);\n            }\n            dialog.getStackDialog().sendRequest(transaction);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to instantiate SIP transaction!\", e);\n\n        } catch (SipException e) {\n            throw new NetworkException(\"Can't send SIP message!\", e);\n        }\n    }\n\n    /**\n     * Send a subsequent SIP request and create a context to wait a response\n     *\n     * @param dialog Dialog path\n     * @param request Request\n     * @return SipTransactionContext\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public SipTransactionContext sendSubsequentRequest(SipDialogPath dialog, SipRequest request)\n            throws PayloadException, NetworkException {\n        boolean loggerActivated = sLogger.isActivated();\n        try {\n            SessionAuthenticationAgent agent = dialog.getAuthenticationAgent();\n            if (agent != null) {\n                agent.setProxyAuthorizationHeader(request);\n            }\n            ClientTransaction transaction = createNewTransaction(request);\n            if (loggerActivated) {\n                sLogger.debug(\">>> Send SIP \".concat(request.getMethod().toUpperCase()));\n            }\n            if (mSipTraceEnabled) {\n                System.out.println(\">>> \" + request.getStackMessage().toString());\n                System.out.println(TRACE_SEPARATOR);\n            }\n            dialog.getStackDialog().sendRequest(transaction);\n            SipTransactionContext ctx = new SipTransactionContext(transaction);\n            String id = SipTransactionContext.getTransactionContextId(request);\n            mTransactions.put(id, ctx);\n            return ctx;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to instantiate SIP transaction!\", e);\n\n        } catch (SipException e) {\n            throw new NetworkException(\"Can't send SIP message!\", e);\n        }\n    }\n\n    /**\n     * Process an asynchronously reported DialogTerminatedEvent\n     *\n     * @param dialogTerminatedEvent Event\n     */\n    public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Dialog terminated\");\n        }\n    }\n\n    /**\n     * Process an asynchronously reported IO Exception\n     *\n     * @param exceptionEvent Event\n     */\n    public void processIOException(IOExceptionEvent exceptionEvent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"IO Exception on \" + exceptionEvent.getTransport() + \" transport\");\n        }\n    }\n\n    /**\n     * Processes a Request received on a SipProvider upon which this SipListener is registered.\n     *\n     * @param requestEvent Event\n     */\n    public void processRequest(RequestEvent requestEvent) {\n        Request request = requestEvent.getRequest();\n        boolean loggerActivated = sLogger.isActivated();\n        if (loggerActivated) {\n            sLogger.debug(\"<<< Receive SIP \" + request.getMethod());\n        }\n        if (mSipTraceEnabled) {\n            System.out.println(\"<<< \" + request.toString());\n            System.out.println(TRACE_SEPARATOR);\n        }\n        try {\n            // Get transaction\n            ServerTransaction transaction = requestEvent.getServerTransaction();\n            if (transaction == null) {\n                // Create a transaction for this new incoming request\n                SipProvider srcSipProvider = (SipProvider) requestEvent.getSource();\n                transaction = srcSipProvider.getNewServerTransaction(request);\n            }\n            // Create received request with its associated transaction\n            SipRequest req = new SipRequest(request);\n            req.setStackTransaction(transaction);\n            if (Request.ACK.equals(req.getMethod())) {\n                // Search the context associated to the received ACK and notify it\n                String transactionId = SipTransactionContext.getTransactionContextId(req);\n                notifyTransactionContext(transactionId, req);\n                return;\n            }\n            // Notify event listeners\n            for (SipEventListener listener : mListeners) {\n                listener.receiveSipRequest(req);\n            }\n        } catch (TransactionAlreadyExistsException | TransactionUnavailableException e) {\n            /**\n             * Intentionally consuming this exception as no need to create a new transaction in case\n             * it already exists.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n    }\n\n    /**\n     * Processes a Response received on a SipProvider upon which this SipListener is registered\n     *\n     * @param responseEvent Event\n     */\n    public void processResponse(ResponseEvent responseEvent) {\n        Response response = responseEvent.getResponse();\n        int responseStatusCode = response.getStatusCode();\n        boolean loggerActivated = sLogger.isActivated();\n        if (loggerActivated) {\n            sLogger.debug(\"<<< Receive SIP \" + responseStatusCode + \" response\");\n        }\n        if (mSipTraceEnabled) {\n            System.out.println(\"<<< \" + response.toString());\n            System.out.println(TRACE_SEPARATOR);\n        }\n        // Search transaction\n        ClientTransaction transaction = responseEvent.getClientTransaction();\n        if (transaction == null) {\n            if (loggerActivated) {\n                sLogger.debug(\"No transaction exist for this response: by-pass it\");\n            }\n            return;\n        }\n        // Create received response with its associated transaction\n        SipResponse resp = new SipResponse(response);\n        resp.setStackTransaction(transaction);\n        // Search the context associated to the received response and notify it\n        String transactionId = SipTransactionContext.getTransactionContextId(resp);\n        if (Response.OK <= responseStatusCode) {\n            notifyTransactionContext(transactionId, resp);\n        } else {\n            // Is the response provisional ?\n            if (Response.TRYING <= responseStatusCode) {\n                notifyProvisionalResponse(transactionId, resp);\n            }\n        }\n    }\n\n    /**\n     * Processes a retransmit or expiration Timeout of an underlying Transaction handled by this\n     * SipListener\n     *\n     * @param timeoutEvent Event\n     */\n    public void processTimeout(TimeoutEvent timeoutEvent) {\n        boolean loggerActivated = sLogger.isActivated();\n        if (loggerActivated) {\n            sLogger.debug(\"Transaction timeout \" + timeoutEvent.getTimeout().toString());\n        }\n        if (timeoutEvent.isServerTransaction()) {\n            if (loggerActivated) {\n                sLogger.warn(\"Unexpected timeout for a server transaction: should never arrives\");\n            }\n            return;\n        }\n        ClientTransaction transaction = timeoutEvent.getClientTransaction();\n        if (transaction == null) {\n            if (loggerActivated) {\n                sLogger.debug(\"No transaction exist for this transaction: by-pass it\");\n            }\n            return;\n        }\n        // Search the context associated to the received timeout and notify it\n        String transactionId = SipTransactionContext.getTransactionContextId(transaction\n                .getRequest());\n        notifyTransactionContext(transactionId, null);\n    }\n\n    /**\n     * Process an asynchronously reported TransactionTerminatedEvent\n     *\n     * @param transactionTerminatedEvent Event\n     */\n    public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {\n        // if (sLogger.isActivated()) {\n        // sLogger.debug(\"Transaction terminated\");\n        // }\n    }\n\n    /**\n     * Notify provisional SIP response\n     *\n     * @param transactionId Transaction ID\n     * @param response SIP response\n     */\n    private void notifyProvisionalResponse(String transactionId, SipResponse response) {\n        SipTransactionContext ctx = mTransactions.get(transactionId);\n        if (ctx == null) {\n            return;\n        }\n        boolean loggerActivated = sLogger.isActivated();\n        if (loggerActivated) {\n            sLogger.debug(\"Callback object found for transaction \" + transactionId);\n        }\n        INotifySipProvisionalResponse callback = ctx.getCallbackSipProvisionalResponse();\n        // Only consider ringing event\n        if (callback != null && Response.RINGING == response.getStatusCode()) {\n            callback.handle180Ringing(response);\n        } else {\n            if (loggerActivated) {\n                sLogger.debug(\"By pass provisional response\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipMessage.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.utils.StringUtils;\n\nimport android.text.TextUtils;\n\nimport gov2.nist.javax2.sip.header.extensions.SessionExpiresHeader;\n\nimport java.text.ParseException;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.ListIterator;\nimport java.util.Set;\n\nimport javax2.sip.Transaction;\nimport javax2.sip.header.AcceptHeader;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.SubjectHeader;\nimport javax2.sip.header.ToHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.message.Message;\n\n/**\n * SIP message\n * \n * @author jexa7410\n * @author Deutsche Telekom AG\n */\npublic abstract class SipMessage {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    protected static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n    private static final String HEADER_OF_NON_BASED_FTAG = \"+\";\n    private static final String FTAG_VALUE_LIST_EQUAL = \"=\";\n    private static final String FTAG_VALUE_LIST_QUOT = \"\\\"\";\n    private static final String FTAG_VALUE_LIST_COMA = \",\";\n    private static final String ACCEPT_CONTACT_PARAMS_SEMI = \";\";\n\n    /**\n     * SIP stack API object\n     */\n    protected Message mStackMessage;\n\n    private Transaction mStackTransaction;\n\n    /**\n     * Constructor\n     * \n     * @param message SIP stack message\n     */\n    public SipMessage(Message message) {\n        mStackMessage = message;\n    }\n\n    /**\n     * Return the SIP stack message\n     * \n     * @return SIP message\n     */\n    public abstract Message getStackMessage();\n\n    /**\n     * Return the SIP stack transaction\n     * \n     * @return SIP transaction\n     */\n    public Transaction getStackTransaction() {\n        return mStackTransaction;\n    }\n\n    /**\n     * Set the SIP stack transaction\n     * \n     * @param transaction SIP transaction\n     */\n    public void setStackTransaction(Transaction transaction) {\n        mStackTransaction = transaction;\n    }\n\n    /**\n     * Add a SIP header\n     * \n     * @param name Header name\n     * @param value Header value\n     * @throws ParseException\n     */\n    public void addHeader(String name, String value) throws ParseException {\n        Header header = SipUtils.HEADER_FACTORY.createHeader(name, value);\n        mStackMessage.setHeader(header);\n    }\n\n    /**\n     * Return a header value\n     * \n     * @param name Header name\n     * @return Header\n     */\n    public Header getHeader(String name) {\n        return mStackMessage.getHeader(name);\n    }\n\n    /**\n     * Return values of an header\n     * \n     * @param name Header name\n     * @return List of headers\n     */\n    public ListIterator<Header> getHeaders(String name) {\n        return mStackMessage.getHeaders(name);\n    }\n\n    /**\n     * Get Via headers list\n     * \n     * @return List of headers\n     */\n    public ListIterator<ViaHeader> getViaHeaders() {\n        return mStackMessage.getHeaders(ViaHeader.NAME);\n    }\n\n    /**\n     * Return the From\n     * \n     * @return String\n     */\n    public String getFrom() {\n        FromHeader header = (FromHeader) mStackMessage.getHeader(FromHeader.NAME);\n        return header.getAddress().toString();\n    }\n\n    /**\n     * Return the From tag\n     * \n     * @return String\n     */\n    public String getFromTag() {\n        FromHeader header = (FromHeader) mStackMessage.getHeader(FromHeader.NAME);\n        return header.getTag();\n    }\n\n    /**\n     * Return the From URI\n     * \n     * @return String\n     */\n    public String getFromUri() {\n        FromHeader header = (FromHeader) mStackMessage.getHeader(FromHeader.NAME);\n        return header.getAddress().getURI().toString();\n    }\n\n    /**\n     * Return the To\n     * \n     * @return String\n     */\n    public String getTo() {\n        ToHeader header = (ToHeader) mStackMessage.getHeader(ToHeader.NAME);\n        return header.getAddress().toString();\n    }\n\n    /**\n     * Return the To tag\n     * \n     * @return String\n     */\n    public String getToTag() {\n        ToHeader header = (ToHeader) mStackMessage.getHeader(ToHeader.NAME);\n        return header.getTag();\n    }\n\n    /**\n     * Return the To URI\n     * \n     * @return String\n     */\n    public String getToUri() {\n        ToHeader header = (ToHeader) mStackMessage.getHeader(ToHeader.NAME);\n        return header.getAddress().getURI().toString();\n    }\n\n    /**\n     * Return the CSeq value\n     * \n     * @return Number\n     */\n    public long getCSeq() {\n        CSeqHeader header = (CSeqHeader) mStackMessage.getHeader(CSeqHeader.NAME);\n        return header.getSeqNumber();\n    }\n\n    /**\n     * Return the ContactAddress\n     *\n     * @return String\n     */\n    public String getContactAddress() {\n        ContactHeader header = (ContactHeader) mStackMessage.getHeader(ContactHeader.NAME);\n        if (header != null) {\n            return header.getAddress().toString();\n        }\n        return null;\n    }\n\n    /**\n     * Return the contact URI\n     * \n     * @return String or null\n     */\n    public String getContactURI() {\n        ContactHeader header = (ContactHeader) mStackMessage.getHeader(ContactHeader.NAME);\n        if (header != null) {\n            return header.getAddress().getURI().toString();\n        }\n        return null;\n    }\n\n    /**\n     * Return the content part\n     * \n     * @return String or null\n     */\n    public String getContent() {\n        byte[] content = mStackMessage.getRawContent();\n        if (content != null) {\n            return new String(content, UTF8);\n        }\n        return null;\n    }\n\n    /**\n     * Return the raw content part\n     * \n     * @return Byte array or null\n     */\n    public byte[] getRawContent() {\n        return mStackMessage.getRawContent();\n    }\n\n    /**\n     * Return the SDP content part\n     * \n     * @return String or null\n     */\n    public String getSdpContent() {\n        String content = getContent();\n        if (content == null) {\n            return null;\n        }\n\n        String contentType = getContentType();\n        if (contentType == null) {\n            return null;\n        }\n\n        if (contentType.startsWith(\"multipart\")) {\n            String boundary = getBoundaryContentType();\n            Multipart multi = new Multipart(content, boundary);\n            return multi.getPart(\"application/sdp\");\n\n        } else if (contentType.equals(\"application/sdp\")) {\n            return content;\n        }\n        return null;\n    }\n\n    /**\n     * Return the content part as bytes\n     * \n     * @return String or null\n     */\n    public byte[] getContentBytes() {\n        return mStackMessage.getRawContent();\n    }\n\n    /**\n     * Return the content type\n     * \n     * @return String or null\n     */\n    public String getContentType() {\n        ContentTypeHeader header = (ContentTypeHeader) mStackMessage\n                .getHeader(ContentTypeHeader.NAME);\n        if (header != null) {\n            return header.getContentType() + \"/\" + header.getContentSubType();\n        }\n        return null;\n    }\n\n    /**\n     * Return the boudary parameter of the content type\n     * \n     * @return String or null\n     */\n    public String getBoundaryContentType() {\n        ContentTypeHeader header = (ContentTypeHeader) mStackMessage\n                .getHeader(ContentTypeHeader.NAME);\n        if (header != null) {\n            String value = header.getParameter(\"boundary\");\n            if (value != null) {\n                // Remove quotes\n                value = StringUtils.removeQuotes(value);\n            }\n            return value;\n        }\n        return null;\n    }\n\n    /**\n     * Returns the call-ID value\n     * \n     * @return String or null\n     */\n    public String getCallId() {\n        CallIdHeader header = (CallIdHeader) mStackMessage.getHeader(CallIdHeader.NAME);\n        if (header != null) {\n            return header.getCallId();\n        }\n        return null;\n    }\n\n    /**\n     * Returns the subject value\n     * \n     * @return String or empty\n     */\n    public String getSubject() {\n        SubjectHeader header = (SubjectHeader) getHeader(SubjectHeader.NAME);\n        if (header != null) {\n            return header.getSubject();\n        }\n        return \"\";\n    }\n\n    /**\n     * Return the accept type\n     * \n     * @return String or null\n     */\n    public String getAcceptType() {\n        AcceptHeader header = (AcceptHeader) getHeader(AcceptHeader.NAME);\n        if (header != null) {\n            return header.getContentType() + \"/\" + header.getContentSubType();\n        }\n        return null;\n    }\n\n    private StringBuilder formatFeatureTag(String name, String value) {\n        StringBuilder parameter = new StringBuilder(name);\n        parameter.append(FTAG_VALUE_LIST_EQUAL);\n        parameter.append(FTAG_VALUE_LIST_QUOT);\n        parameter.append(value);\n        parameter.append(FTAG_VALUE_LIST_QUOT);\n        return parameter;\n    }\n\n    private void addContactFeatureTags(Set<String> tags, ContactHeader contactHeader) {\n        for (Iterator<?> i = contactHeader.getParameterNames(); i.hasNext();) {\n            /* Extract parameter name & value */\n            String pname = (String) i.next();\n            if (!pname.startsWith(HEADER_OF_NON_BASED_FTAG)\n                    && !pname.equals(FeatureTags.FEATURE_RCSE_IP_VIDEO_CALL)\n                    && !pname.equals(FeatureTags.FEATURE_SIP_AUTOMATA)) {\n                /*\n                 * Only keep non based feature tags except AUTOMATA and VIDEO_CALL. Reject parameter\n                 * not starting with a + except FEATURE_SIP_AUTOMATA and FEATURE_RCSE_IP_VIDEO_CALL\n                 * which do not start with '+'\n                 */\n                continue;\n            }\n            String pvalue = contactHeader.getParameter(pname);\n            if (StringUtils.isEmpty(pvalue)) {\n                /* Add single parameter */\n                tags.add(pname);\n            } else {\n                /* Add pair parameters */\n                String[] values = pvalue.split(FTAG_VALUE_LIST_COMA);\n                for (String tag : values) {\n                    tags.add(formatFeatureTag(pname, tag.trim()).toString());\n                }\n            }\n        }\n    }\n\n    private void addAcceptContactFeatureTags(Set<String> tags, ListIterator<Header> acceptHeaders) {\n        /* Extract header parameters */\n        while (acceptHeaders.hasNext()) {\n            ExtensionHeader acceptHeader = (ExtensionHeader) acceptHeaders.next();\n            String acceptHeaderValue = acceptHeader.getValue();\n            String[] parameters = acceptHeaderValue.split(ACCEPT_CONTACT_PARAMS_SEMI);\n            for (String parameter : parameters) {\n                /* Extract parameter name & value */\n                String[] param = parameter.split(FTAG_VALUE_LIST_EQUAL);\n                String pname = param[0];\n                if (!pname.startsWith(HEADER_OF_NON_BASED_FTAG)) {\n                    /* only keep non based feature tags */\n                    continue;\n                }\n                String pvalue = null;\n                if (param.length == 2) {\n                    pvalue = param[1];\n                }\n                if (TextUtils.isEmpty(pvalue)) {\n                    /* Add single parameter */\n                    tags.add(pname);\n                } else {\n                    /* Add pair parameter */\n                    pvalue = pvalue.replace(FTAG_VALUE_LIST_QUOT, \"\");\n                    String[] values = pvalue.split(FTAG_VALUE_LIST_COMA);\n                    for (String tag : values) {\n                        tags.add(formatFeatureTag(pname, tag.trim()).toString());\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Get the features tags from Contact header and Accept-Contact header\n     * \n     * @return Set of feature tags\n     */\n    public Set<String> getFeatureTags() {\n        Set<String> tags = new HashSet<>();\n        /* Read Contact header */\n        ContactHeader contactHeader = (ContactHeader) mStackMessage.getHeader(ContactHeader.NAME);\n        if (contactHeader != null) {\n            addContactFeatureTags(tags, contactHeader);\n        }\n        /* Read Accept-Contact header */\n        ListIterator<Header> acceptHeaders = getHeaders(SipUtils.HEADER_ACCEPT_CONTACT);\n        if (acceptHeaders == null || !acceptHeaders.hasNext()) {\n            /* Check contracted form */\n            acceptHeaders = getHeaders(SipUtils.HEADER_ACCEPT_CONTACT_C);\n        }\n        if (acceptHeaders != null) {\n            addAcceptContactFeatureTags(tags, acceptHeaders);\n        }\n        Set<String> result = new HashSet<>();\n        /* Filter irrelevant feature tags */\n        for (String tag : tags) {\n            /* Reject sip.instance parameter */\n            if (tag.startsWith(SipUtils.SIP_INSTANCE_PARAM)) {\n                continue;\n            }\n            result.add(tag);\n        }\n        return result;\n    }\n\n    /**\n     * Get session timer expire\n     * \n     * @return Expire time in milliseconds or -1 if no session timer\n     */\n    public long getSessionTimerExpire() {\n        SessionExpiresHeader sessionExpiresHeader = (SessionExpiresHeader) getHeader(SessionExpiresHeader.NAME);\n        if (sessionExpiresHeader != null) {\n            return sessionExpiresHeader.getExpires() * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n        }\n        return -1;\n    }\n\n    /**\n     * Get session timer refresher role\n     * \n     * @return \"uac\" or \"uas\"\n     */\n    public String getSessionTimerRefresher() {\n        String role = null;\n        SessionExpiresHeader sessionExpiresHeader = (SessionExpiresHeader) getHeader(SessionExpiresHeader.NAME);\n        if (sessionExpiresHeader != null) {\n            role = sessionExpiresHeader.getRefresher();\n        }\n        if (role == null) {\n            return SessionTimerManager.UAC_ROLE;\n        }\n        return role;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport gov2.nist.javax2.sip.header.Reason;\n\nimport java.util.ListIterator;\n\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.ReasonHeader;\nimport javax2.sip.message.Request;\n\n/**\n * SIP request\n * \n * @author jexa7410\n */\npublic class SipRequest extends SipMessage {\n\n    /**\n     * Constructor\n     * \n     * @param request SIP stack request\n     */\n    public SipRequest(Request request) {\n        super(request);\n    }\n\n    /**\n     * Return the SIP stack message\n     * \n     * @return SIP request\n     */\n    public Request getStackMessage() {\n        return (Request) mStackMessage;\n    }\n\n    /**\n     * Returns the method value\n     * \n     * @return Method name or null is case of response\n     */\n    public String getMethod() {\n        return getStackMessage().getMethod();\n    }\n\n    /**\n     * Return the request URI\n     * \n     * @return String\n     */\n    public String getRequestURI() {\n        return getStackMessage().getRequestURI().toString();\n    }\n\n    /**\n     * Return the expires value\n     * \n     * @return Expire value in milliseconds\n     */\n    public long getExpires() {\n        ExpiresHeader expires = (ExpiresHeader) getStackMessage().getHeader(ExpiresHeader.NAME);\n        if (expires != null) {\n            return expires.getExpires() * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n        }\n        return -1;\n    }\n\n    /**\n     * Extract the reason from the SIP message header\n     * \n     * @return the reason or null if none\n     */\n    public Reason getReason() {\n        ListIterator<Header> headers = getHeaders(ReasonHeader.NAME);\n        if (headers == null) {\n            return null;\n        }\n        while (headers.hasNext()) {\n            Header header = headers.next();\n            if (header instanceof Reason) {\n                return (Reason) header;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipResponse.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport javax2.sip.message.Response;\n\n/**\n * SIP response\n * \n * @author jexa7410\n */\npublic class SipResponse extends SipMessage {\n\n    /**\n     * Constructor\n     * \n     * @param response SIP stack response\n     */\n    public SipResponse(Response response) {\n        super(response);\n    }\n\n    /**\n     * Return the SIP stack message\n     * \n     * @return SIP response\n     */\n    public Response getStackMessage() {\n        return (Response) mStackMessage;\n    }\n\n    /**\n     * Returns the status code value\n     * \n     * @return Status code or -1\n     */\n    public int getStatusCode() {\n        Response response = getStackMessage();\n        if (response != null) {\n            return response.getStatusCode();\n        }\n        return -1;\n    }\n\n    /**\n     * Returns the reason phrase of the response\n     * \n     * @return String or null\n     */\n    public String getReasonPhrase() {\n        Response response = getStackMessage();\n        if (response != null) {\n            return getStackMessage().getReasonPhrase();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipTransactionContext.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport javax2.sip.Transaction;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.message.Message;\nimport javax2.sip.message.Response;\n\n/**\n * SIP transaction context object composed of a request and of the corresponding response. The\n * Transaction context is used for waiting responses of requests and also for waiting an ACK message\n * (special case).\n * \n * @author JM. Auffret\n * @author yplo6403\n */\npublic class SipTransactionContext {\n\n    /**\n     * An interface to handle SIP provisional response\n     */\n    public interface INotifySipProvisionalResponse {\n        public void handle180Ringing(SipResponse response);\n    }\n\n    /**\n     * Transaction\n     */\n    private Transaction mTransaction;\n\n    /**\n     * Received message\n     */\n    private SipMessage recvMsg;\n\n    /**\n     * Callback to handle SIP provisional response\n     */\n    private INotifySipProvisionalResponse mCallbackSipProvisionalResponse;\n\n    /**\n     * Constructor\n     * \n     * @param transaction SIP transaction\n     */\n    public SipTransactionContext(Transaction transaction) {\n        this(transaction, null);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param transaction SIP transaction\n     * @param callback Callback to handle SIP provisional response\n     */\n    public SipTransactionContext(Transaction transaction, INotifySipProvisionalResponse callback) {\n        mTransaction = transaction;\n        mCallbackSipProvisionalResponse = callback;\n    }\n\n    /**\n     * Get the SIP transaction\n     * \n     * @return Transaction\n     */\n    public Transaction getTransaction() {\n        return mTransaction;\n    }\n\n    /**\n     * Get the SIP message that has been received\n     * \n     * @return SIP message\n     */\n    public SipMessage getMessageReceived() {\n        return recvMsg;\n    }\n\n    /**\n     * Determine if a timeout has occurred\n     * \n     * @return Returns True if there is a timeout else returns False\n     */\n    public boolean isTimeout() {\n        return (recvMsg == null);\n    }\n\n    /**\n     * Determine if the received message is a SIP response\n     * \n     * @return Returns True if it's a SIP response else returns False\n     */\n    public boolean isSipResponse() {\n        if (recvMsg != null) {\n            return (recvMsg instanceof SipResponse);\n        }\n        return false;\n    }\n\n    /**\n     * Determine if the received message is an intermediate response\n     * \n     * @return Returns True if it's an intermediate response else returns False\n     */\n    public boolean isSipIntermediateResponse() {\n        int code = getStatusCode();\n        return (code < 200);\n    }\n\n    /**\n     * Determine if the received message is a successful response\n     * \n     * @return Returns True if it's a successful response else returns False\n     */\n    public boolean isSipSuccessfullResponse() {\n        int code = getStatusCode();\n        return (Response.OK <= code && Response.MULTIPLE_CHOICES > code);\n    }\n\n    /**\n     * Determine if the received message is a SIP ACK\n     * \n     * @return Returns True if it's a SIP ACK else returns False\n     */\n    public boolean isSipAck() {\n        if (recvMsg != null) {\n            SipRequest req = (SipRequest) recvMsg;\n            if (req.getMethod().equals(\"ACK\")) {\n                return true;\n            }\n            return false;\n        }\n        return false;\n    }\n\n    /**\n     * Get the SIP response that has been received\n     * \n     * @return SIP response or null if it's not a response (e.g. ACK message)\n     */\n    public SipResponse getSipResponse() {\n        if (isSipResponse()) {\n            return (SipResponse) recvMsg;\n        }\n        return null;\n    }\n\n    /**\n     * Get the status code of the received SIP response\n     * \n     * @return Returns a status code or -1 if it's not a SIP response (e.g. ACK message)\n     */\n    public int getStatusCode() {\n        int ret = -1;\n        if (isSipResponse()) {\n            SipResponse resp = (SipResponse) recvMsg;\n            ret = resp.getStatusCode();\n        }\n        return ret;\n    }\n\n    /**\n     * Get the reason phrase of the received SIP response\n     * \n     * @return Returns a reason phrase or null if it's not a SIP response (e.g. ACK message)\n     */\n    public String getReasonPhrase() {\n        String ret = null;\n        SipResponse resp = getSipResponse();\n        if (resp != null) {\n            ret = resp.getReasonPhrase();\n        }\n        return ret;\n    }\n\n    /**\n     * Wait the response of a request until a timeout occurs\n     * \n     * @param timeout value in milliseconds\n     */\n    public void waitResponse(long timeout) {\n        try {\n            if (recvMsg != null) {\n                // Response already received, no need to wait\n                return;\n            }\n            synchronized (this) {\n                super.wait(timeout);\n            }\n        } catch (InterruptedException e) {\n            // Thread has been interrupted\n            recvMsg = null;\n        }\n    }\n\n    /**\n     * A response has been received (SIP response or ACK or any other SIP message)\n     * \n     * @param msg SIP message object\n     */\n    public void responseReceived(SipMessage msg) {\n        synchronized (this) {\n            recvMsg = msg;\n            super.notify();\n        }\n    }\n\n    /**\n     * Reset transaction context\n     */\n    public void resetContext() {\n        synchronized (this) {\n            recvMsg = null;\n            super.notify();\n        }\n    }\n\n    /**\n     * Get the transaction context ID associated a SIP message\n     * \n     * @param msg SIP message\n     * @return Transaction context ID\n     */\n    public static String getTransactionContextId(SipMessage msg) {\n        return getTransactionContextId(msg.getStackMessage());\n    }\n\n    /**\n     * Get the transaction context ID associated a SIP message\n     * \n     * @param msg SIP message\n     * @return Transaction context ID\n     */\n    public static String getTransactionContextId(Message msg) {\n        CallIdHeader header = (CallIdHeader) msg.getHeader(CallIdHeader.NAME);\n        return header.getCallId();\n    }\n\n    /**\n     * Get the callback to handle provisional SIP response\n     * \n     * @return the callback\n     */\n    public INotifySipProvisionalResponse getCallbackSipProvisionalResponse() {\n        return mCallbackSipProvisionalResponse;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/protocol/sip/SipTransactionList.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.protocol.sip;\n\nimport java.util.Hashtable;\n\n/**\n * List of SIP transactions\n * \n * @author JM. Auffret\n */\npublic class SipTransactionList extends Hashtable<String, SipTransactionContext> {\n    static final long serialVersionUID = 1L;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/Digest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security;\n\n/**\n * Interface that a message digest conforms to\n */\npublic interface Digest {\n    /**\n     * return the algorithm name\n     * \n     * @return the algorithm name\n     */\n    public String getAlgorithmName();\n\n    /**\n     * return the size, in bytes, of the digest produced by this message digest\n     * \n     * @return the size, in bytes, of the digest produced by this message digest\n     */\n    public int getDigestSize();\n\n    /**\n     * Update the message digest with a single byte.\n     * \n     * @param in Input byte to be entered.\n     */\n    public void update(byte in);\n\n    /**\n     * Update the message digest with a block of bytes.\n     * \n     * @param in Byte array containing the data\n     * @param inOff Offset into the byte array where the data starts\n     * @param len Length of the data\n     */\n    public void update(byte[] in, int inOff, int len);\n\n    /**\n     * Close the digest, producing the final digest value. The doFinal call leaves the digest reset.\n     * \n     * @param out Array the digest is to be copied into\n     * @param outOff Offset into the out array the digest is to start at\n     */\n    public int doFinal(byte[] out, int outOff);\n\n    /**\n     * reset the digest back to it's initial state.\n     */\n    public void reset();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/GeneralDigest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security;\n\n/**\n * base implementation of MD4 family style digest as outlined in \"Handbook of Applied Cryptography\",\n * pages 344 - 347.\n */\npublic abstract class GeneralDigest implements Digest {\n    private byte[] xBuf;\n    private int xBufOff;\n\n    private long byteCount;\n\n    /**\n     * Standard constructor\n     */\n    protected GeneralDigest() {\n        xBuf = new byte[4];\n        xBufOff = 0;\n    }\n\n    /**\n     * Copy constructor. We are using copy constructors in place of the Object.clone() interface as\n     * this interface is not supported by J2ME.\n     */\n    protected GeneralDigest(GeneralDigest t) {\n        xBuf = new byte[t.xBuf.length];\n        System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);\n\n        xBufOff = t.xBufOff;\n        byteCount = t.byteCount;\n    }\n\n    public void update(byte in) {\n        xBuf[xBufOff++] = in;\n\n        if (xBufOff == xBuf.length) {\n            processWord(xBuf, 0);\n            xBufOff = 0;\n        }\n\n        byteCount++;\n    }\n\n    public void update(byte[] in, int inOff, int len) {\n        //\n        // fill the current word\n        //\n        while ((xBufOff != 0) && (len > 0)) {\n            update(in[inOff]);\n\n            inOff++;\n            len--;\n        }\n\n        //\n        // process whole words.\n        //\n        while (len > xBuf.length) {\n            processWord(in, inOff);\n\n            inOff += xBuf.length;\n            len -= xBuf.length;\n            byteCount += xBuf.length;\n        }\n\n        //\n        // load in the remainder.\n        //\n        while (len > 0) {\n            update(in[inOff]);\n\n            inOff++;\n            len--;\n        }\n    }\n\n    public void finish() {\n        long bitLength = (byteCount << 3);\n\n        //\n        // add the pad bytes.\n        //\n        update((byte) 128);\n\n        while (xBufOff != 0) {\n            update((byte) 0);\n        }\n\n        processLength(bitLength);\n\n        processBlock();\n    }\n\n    public void reset() {\n        byteCount = 0;\n\n        xBufOff = 0;\n        for (int i = 0; i < xBuf.length; i++) {\n            xBuf[i] = 0;\n        }\n    }\n\n    protected abstract void processWord(byte[] in, int inOff);\n\n    protected abstract void processLength(long bitLength);\n\n    protected abstract void processBlock();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/HttpDigestMd5Authentication.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\n/**\n * HTTP Digest MD5 authentication (see RFC2617)\n * \n * @author jexa7410\n */\npublic class HttpDigestMd5Authentication {\n\n    private static final char COLON = ':';\n\n    /**\n     * Constant\n     */\n    public static final String NC_PARAM = \"nc\";\n\n    /**\n     * HTTP Digest scheme\n     */\n    public final static String HTTP_DIGEST_SCHEMA = \"Digest\";\n\n    /**\n     * HTTP Digest algorithm\n     */\n    public final static String HTTP_DIGEST_ALGO = \"MD5\";\n\n    /**\n     * Hex chars\n     */\n    private static final char[] HEX = {\n            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\n    };\n\n    /**\n     * Domain name\n     */\n    private String mRealm;\n\n    /**\n     * Opaque parameter\n     */\n    private String mOpaque;\n\n    /**\n     * Nonce\n     */\n    private String mNonce;\n\n    /**\n     * Next nonce\n     */\n    private String mNextNonce;\n\n    /**\n     * Qop\n     */\n    private String mQop;\n\n    /**\n     * Cnonce\n     */\n    private String mCnonce = Long.toString(System.currentTimeMillis());\n\n    /**\n     * Cnonce counter\n     */\n    private int mCnonceCounter = 0;\n\n    /**\n     * MD5 algorithm\n     */\n    private MD5Digest mMd5Digest = new MD5Digest();\n\n    /**\n     * Constructor\n     */\n    public HttpDigestMd5Authentication() {\n    }\n\n    /**\n     * Returns realm parameter\n     * \n     * @return Realm\n     */\n    public String getRealm() {\n        return mRealm;\n    }\n\n    /**\n     * Set the realm parameter\n     * \n     * @param realm Realm\n     */\n    public void setRealm(String realm) {\n        mRealm = realm;\n    }\n\n    /**\n     * Returns opaque parameter\n     * \n     * @return Opaque\n     */\n    public String getOpaque() {\n        return mOpaque;\n    }\n\n    /**\n     * Set the opaque parameter\n     * \n     * @param opaque Opaque\n     */\n    public void setOpaque(String opaque) {\n        mOpaque = opaque;\n    }\n\n    /**\n     * Get the client nonce parameter\n     * \n     * @return Client nonce\n     */\n    public String getCnonce() {\n        return mCnonce;\n    }\n\n    /**\n     * Get the nonce parameter\n     * \n     * @return Nonce\n     */\n    public String getNonce() {\n        return mNonce;\n    }\n\n    /**\n     * Set the nonce parameter\n     * \n     * @param nonce Nonce\n     */\n    public void setNonce(String nonce) {\n        mNonce = nonce;\n    }\n\n    /**\n     * Returns the next nonce parameter\n     * \n     * @return Next nonce\n     */\n    public String getNextnonce() {\n        return mNextNonce;\n    }\n\n    /**\n     * Set the next nonce parameter\n     * \n     * @param nextnonce Next nonce\n     */\n    public void setNextnonce(String nextnonce) {\n        mNextNonce = nextnonce;\n    }\n\n    /**\n     * Returns the Qop parameter\n     * \n     * @return Qop\n     */\n    public String getQop() {\n        return mQop;\n    }\n\n    /**\n     * Set the Qop parameter\n     * \n     * @param qop Qop parameter\n     */\n    public void setQop(String qop) {\n        if (qop != null) {\n            qop = qop.split(\",\")[0];\n        }\n        mQop = qop;\n    }\n\n    /**\n     * Update the nonce parameters\n     */\n    public void updateNonceParameters() {\n        // Update nonce and nc\n        if (mNextNonce.equals(mNonce)) {\n            // Next nonce == nonce\n            mCnonceCounter++;\n        } else {\n            // Next nonce != nonce\n            mCnonceCounter = 1;\n            mNonce = mNextNonce;\n        }\n    }\n\n    /**\n     * Build the cnonce counter\n     * \n     * @return String (ie. \"00000001\")\n     */\n    public String buildNonceCounter() {\n        String result = Integer.toHexString(mCnonceCounter);\n        while (result.length() != 8) {\n            result = \"0\" + result;\n        }\n        return result;\n    }\n\n    /**\n     * Convert to hexa string\n     * \n     * @param value Value to convert\n     * @return String\n     */\n    private String toHexString(byte[] value) {\n        int pos = 0;\n        char[] c = new char[value.length * 2];\n        for (int i = 0; i < value.length; i++) {\n            c[pos++] = HEX[value[i] >> 4 & 0xf];\n            c[pos++] = HEX[value[i] & 0xf];\n        }\n        return new String(c);\n    }\n\n    /**\n     * Calculate HTTP Digest nonce response\n     * \n     * @param user User\n     * @param password Password\n     * @param method Method\n     * @param uri Request URI\n     * @param nc Nonce counter\n     * @param body Entity body\n     * @return the HTTP Digest nonce response\n     */\n    public String calculateResponse(String user, String password, String method, String uri,\n            String nc, String body) {\n        String a1 = new StringBuilder(user).append(COLON).append(mRealm).append(COLON)\n                .append(password).toString();\n        StringBuilder a2 = new StringBuilder(method).append(COLON).append(uri);\n\n        if (mQop != null) {\n            if (!mQop.startsWith(\"auth\")) {\n                throw new IllegalArgumentException(\"Invalid qop: \".concat(mQop));\n            }\n\n            if (mQop.equals(\"auth-int\")) {\n                a2.append(COLON).append(H(body));\n            }\n\n            return H(new StringBuilder(H(a1)).append(COLON).append(mNonce).append(COLON).append(nc)\n                    .append(COLON).append(mCnonce).append(COLON).append(mQop).append(COLON)\n                    .append(H(a2.toString())).toString());\n        }\n        return H(new StringBuilder(H(a1)).append(COLON).append(mNonce).append(COLON)\n                .append(H(a2.toString())).toString());\n    }\n\n    /**\n     * HTTP Digest algo\n     * \n     * @param data Input data\n     * @return Hash key\n     */\n    private String H(String data) {\n        if (data == null) {\n            data = \"\";\n        }\n        byte[] bytes = data.getBytes(UTF8);\n        mMd5Digest.update(bytes, 0, bytes.length);\n        byte returnValue[] = new byte[mMd5Digest.getDigestSize()];\n        mMd5Digest.doFinal(returnValue, 0);\n        return toHexString(returnValue);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/MD5Digest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security;\n\n/**\n * implementation of MD5 as outlined in \"Handbook of Applied Cryptography\", pages 346 - 347.\n */\npublic class MD5Digest extends GeneralDigest {\n    private static final int DIGEST_LENGTH = 16;\n\n    private int H1, H2, H3, H4; // IV's\n\n    private int[] X = new int[16];\n    private int xOff;\n\n    /**\n     * Standard constructor\n     */\n    public MD5Digest() {\n        reset();\n    }\n\n    /**\n     * Copy constructor. This will copy the state of the provided message digest.\n     */\n    public MD5Digest(MD5Digest t) {\n        super(t);\n\n        H1 = t.H1;\n        H2 = t.H2;\n        H3 = t.H3;\n        H4 = t.H4;\n\n        System.arraycopy(t.X, 0, X, 0, t.X.length);\n        xOff = t.xOff;\n    }\n\n    public String getAlgorithmName() {\n        return \"MD5\";\n    }\n\n    public int getDigestSize() {\n        return DIGEST_LENGTH;\n    }\n\n    protected void processWord(byte[] in, int inOff) {\n        X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)\n                | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24);\n\n        if (xOff == 16) {\n            processBlock();\n        }\n    }\n\n    protected void processLength(long bitLength) {\n        if (xOff > 14) {\n            processBlock();\n        }\n\n        X[14] = (int) (bitLength & 0xffffffff);\n        X[15] = (int) (bitLength >>> 32);\n    }\n\n    private void unpackWord(int word, byte[] out, int outOff) {\n        out[outOff] = (byte) word;\n        out[outOff + 1] = (byte) (word >>> 8);\n        out[outOff + 2] = (byte) (word >>> 16);\n        out[outOff + 3] = (byte) (word >>> 24);\n    }\n\n    public int doFinal(byte[] out, int outOff) {\n        finish();\n\n        unpackWord(H1, out, outOff);\n        unpackWord(H2, out, outOff + 4);\n        unpackWord(H3, out, outOff + 8);\n        unpackWord(H4, out, outOff + 12);\n\n        reset();\n\n        return DIGEST_LENGTH;\n    }\n\n    /**\n     * reset the chaining variables to the IV values.\n     */\n    public void reset() {\n        super.reset();\n\n        H1 = 0x67452301;\n        H2 = 0xefcdab89;\n        H3 = 0x98badcfe;\n        H4 = 0x10325476;\n\n        xOff = 0;\n\n        for (int i = 0; i != X.length; i++) {\n            X[i] = 0;\n        }\n    }\n\n    //\n    // round 1 left rotates\n    //\n    private static final int S11 = 7;\n    private static final int S12 = 12;\n    private static final int S13 = 17;\n    private static final int S14 = 22;\n\n    //\n    // round 2 left rotates\n    //\n    private static final int S21 = 5;\n    private static final int S22 = 9;\n    private static final int S23 = 14;\n    private static final int S24 = 20;\n\n    //\n    // round 3 left rotates\n    //\n    private static final int S31 = 4;\n    private static final int S32 = 11;\n    private static final int S33 = 16;\n    private static final int S34 = 23;\n\n    //\n    // round 4 left rotates\n    //\n    private static final int S41 = 6;\n    private static final int S42 = 10;\n    private static final int S43 = 15;\n    private static final int S44 = 21;\n\n    /*\n     * rotate int x left n bits.\n     */\n    private int rotateLeft(int x, int n) {\n        return (x << n) | (x >>> (32 - n));\n    }\n\n    /*\n     * F, G, H and I are the basic MD5 functions.\n     */\n    private int F(int u, int v, int w) {\n        return (u & v) | (~u & w);\n    }\n\n    private int G(int u, int v, int w) {\n        return (u & w) | (v & ~w);\n    }\n\n    private int H(int u, int v, int w) {\n        return u ^ v ^ w;\n    }\n\n    private int K(int u, int v, int w) {\n        return v ^ (u | ~w);\n    }\n\n    protected void processBlock() {\n        int a = H1;\n        int b = H2;\n        int c = H3;\n        int d = H4;\n\n        //\n        // Round 1 - F cycle, 16 times.\n        //\n        a = rotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;\n        d = rotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;\n        c = rotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;\n        b = rotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;\n        a = rotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;\n        d = rotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;\n        c = rotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;\n        b = rotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;\n        a = rotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;\n        d = rotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;\n        c = rotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;\n        b = rotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;\n        a = rotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;\n        d = rotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;\n        c = rotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;\n        b = rotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;\n\n        //\n        // Round 2 - G cycle, 16 times.\n        //\n        a = rotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;\n        d = rotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;\n        c = rotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;\n        b = rotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;\n        a = rotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;\n        d = rotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;\n        c = rotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;\n        b = rotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;\n        a = rotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;\n        d = rotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;\n        c = rotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;\n        b = rotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;\n        a = rotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;\n        d = rotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;\n        c = rotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;\n        b = rotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;\n\n        //\n        // Round 3 - H cycle, 16 times.\n        //\n        a = rotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;\n        d = rotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;\n        c = rotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;\n        b = rotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;\n        a = rotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;\n        d = rotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;\n        c = rotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;\n        b = rotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;\n        a = rotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;\n        d = rotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;\n        c = rotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;\n        b = rotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;\n        a = rotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;\n        d = rotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;\n        c = rotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;\n        b = rotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;\n\n        //\n        // Round 4 - K cycle, 16 times.\n        //\n        a = rotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;\n        d = rotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;\n        c = rotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;\n        b = rotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;\n        a = rotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;\n        d = rotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;\n        c = rotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;\n        b = rotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;\n        a = rotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;\n        d = rotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;\n        c = rotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;\n        b = rotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;\n        a = rotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;\n        d = rotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;\n        c = rotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;\n        b = rotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;\n\n        H1 += a;\n        H2 += b;\n        H3 += c;\n        H4 += d;\n\n        //\n        // reset the offset and clean out the word buffer.\n        //\n        xOff = 0;\n        for (int i = 0; i != X.length; i++) {\n            X[i] = 0;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/cert/KeyStoreManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security.cert;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport com.telekom.bouncycastle.wrapper.SimpleContentSignerBuilder;\n\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.BasicConstraints;\nimport local.org.bouncycastle.asn1.x509.ExtendedKeyUsage;\nimport local.org.bouncycastle.asn1.x509.GeneralName;\nimport local.org.bouncycastle.asn1.x509.GeneralNames;\nimport local.org.bouncycastle.asn1.x509.KeyPurposeId;\nimport local.org.bouncycastle.asn1.x509.KeyUsage;\nimport local.org.bouncycastle.asn1.x509.X509Extension;\nimport local.org.bouncycastle.cert.CertIOException;\nimport local.org.bouncycastle.cert.X509v3CertificateBuilder;\nimport local.org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;\nimport local.org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;\nimport local.org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;\nimport local.org.bouncycastle.operator.ContentSigner;\nimport local.org.bouncycastle.operator.OperatorCreationException;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigInteger;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStoreException;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.Provider;\nimport java.security.PublicKey;\nimport java.security.SecureRandom;\nimport java.security.Security;\nimport java.security.UnrecoverableEntryException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.Date;\n\n/**\n * Keystore manager for certificates\n * \n * @author B. JOGUET\n * @author Deutsche Telekom AG\n */\npublic class KeyStoreManager {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Keystore name\n     */\n    private final static String KEYSTORE_NAME = \"rcs_keystore.jks\";\n\n    // Changed by Deutsche Telekom\n    /**\n     * alias of own, client certificate\n     */\n    protected final static String CLIENT_CERT_ALIAS = \"myJoynCertificate\";\n\n    // Changed by Deutsche Telekom\n    /**\n     * The logger\n     */\n    private static Logger sLogger = Logger.getLogger(KeyStoreManager.class.getName());\n\n    /**\n     * Keystore password\n     */\n    private final static String KEYSTORE_PASSWORD = \"01RCSrcs\";\n\n    // Changed by Deutsche Telekom\n    /**\n     * The logger\n     */\n    private static String sFingerprint;\n\n    // Changed by Deutsche Telekom\n    /**\n     * last used IP address\n     */\n    private static String sLastIpAddress;\n\n    private static KeyStore sKeyStore;\n\n    /**\n     * Load the keystore manager\n     * \n     * @param rcsSettings\n     * @throws IOException\n     * @throws KeyStoreException\n     */\n    // Changed by Deutsche Telekom\n    public static void loadKeyStore(RcsSettings rcsSettings) throws KeyStoreException, IOException {\n        // Changed by Deutsche Telekom\n        if (sLogger.isActivated()) {\n            Provider[] currentProviders = Security.getProviders();\n            if (currentProviders.length > 0) {\n                for (Provider provider : currentProviders) {\n                    sLogger.debug(\"Registered provider: \" + provider.getName() + \"; info: \"\n                            + provider.getInfo());\n                }\n            }\n        }\n\n        // Changed by Deutsche Telekom\n        if (!isKeystoreExists()) {\n            // Changed by Deutsche Telekom\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Create new keystore file \".concat(getKeystore().getPath()));\n            }\n            createKeyStore();\n        }\n\n        String certRoot = rcsSettings.getTlsCertificateRoot();\n        if (!TextUtils.isEmpty(certRoot)) {\n            Uri certFile = Uri.parse(certRoot);\n            if (!isCertificateEntry(buildCertificateAlias(certFile))) {\n                addCertificates(certFile);\n            }\n        }\n        String certIntermediate = rcsSettings.getTlsCertificateIntermediate();\n        if (!TextUtils.isEmpty(certIntermediate)) {\n            Uri certIntermediateFile = Uri.parse(certIntermediate);\n            if (!isCertificateEntry(buildCertificateAlias(certIntermediateFile))) {\n                addCertificates(certIntermediateFile);\n            }\n        }\n    }\n\n    /**\n     * Returns the keystore type\n     * \n     * @return Type\n     */\n    public static String getKeystoreType() {\n        return KeyStore.getDefaultType();\n    }\n\n    /**\n     * Returns the keystore password\n     * \n     * @return Password\n     */\n    public static String getKeystorePassword() {\n        return KEYSTORE_PASSWORD;\n    }\n\n    /**\n     * returns the keystore uri\n     */\n    public static Uri getKeystore() {\n        return Uri.fromFile(new File(AndroidFactory.getApplicationContext().getFilesDir()\n                .getAbsolutePath(), KEYSTORE_NAME));\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Returns the fingerprint of the client certificate\n     * \n     * @return fingerprint\n     */\n    public static String getClientCertificateFingerprint() {\n        return sFingerprint;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Sets the fingerprint of the client certificate\n     * \n     * @param cert certificate\n     * @throws NoSuchAlgorithmException\n     * @throws CertificateEncodingException\n     */\n    public static void setClientCertificateFingerprint(Certificate cert)\n            throws CertificateEncodingException, NoSuchAlgorithmException {\n        sFingerprint = getCertFingerprint(cert, \"SHA-1\");\n    }\n\n    /**\n     * Test if a keystore is created\n     * \n     * @return True if already created\n     */\n    private static boolean isKeystoreExists() {\n        File file = new File(getKeystore().getPath());\n        if (!file.exists()) {\n            return false;\n        }\n        return sKeyStore != null;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * update (or create) current client certificate to reflect latest IP address\n     * \n     * @param ipAddress IP address to be set in subjectAltName according to RFC 4572\n     * @throws CertificateException\n     * @throws IOException\n     */\n    public static void updateClientCertificate(String ipAddress) throws CertificateException,\n            IOException {\n        if (!isKeystoreExists()) {\n            throw new CertificateException(new StringBuilder(\n                    \"Client certificate not created as keystore file \").append(getKeystore())\n                    .append(\" is not available\").toString());\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Update client certificate\");\n        }\n        createClientCertificate(ipAddress);\n    }\n\n    // Changed by Deutsche Telekom\n    private static synchronized void createClientCertificate(String ipAddress)\n            throws CertificateException, IOException {\n        try {\n            if (ipAddress != null && ipAddress.equals(sLastIpAddress)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"IP address hasn't changed. No update needed.\");\n                }\n                return;\n            }\n            sLastIpAddress = ipAddress;\n\n            KeyStore ks = loadKeyStoreFromFile();\n            PrivateKey privKey = null;\n            PublicKey pubKey = null;\n            if (ks.isKeyEntry(CLIENT_CERT_ALIAS)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"old keypair is recycled\");\n                }\n\n                PrivateKeyEntry entry = (PrivateKeyEntry) ks.getEntry(CLIENT_CERT_ALIAS,\n                        new KeyStore.PasswordProtection(KEYSTORE_PASSWORD.toCharArray()));\n                privKey = entry.getPrivateKey();\n                pubKey = entry.getCertificate().getPublicKey();\n                ks.deleteEntry(CLIENT_CERT_ALIAS);\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"new keypair is generated\");\n                }\n\n                KeyPairGenerator keyGen = KeyPairGenerator.getInstance(\"RSA\");\n                SecureRandom secureRandom = new SecureRandom();\n                /*\n                 * Do *not* seed secureRandom! Automatically seeded from system entropy.\n                 */\n                keyGen.initialize(1024, secureRandom);\n                KeyPair keypair = keyGen.generateKeyPair();\n                privKey = keypair.getPrivate();\n                pubKey = keypair.getPublic();\n            }\n            X509Certificate[] certChain = new X509Certificate[1];\n            X500Name subjectName = new X500Name(\"CN=com.gsma.rcs.client\");\n            long timestamp = System.currentTimeMillis();\n            Date startDate = new Date(timestamp - 24 * 60 * 60\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n            Date endDate = new Date(timestamp + 365L * 26 * 60 * 60\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n            X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(subjectName,\n                    BigInteger.ONE, startDate, endDate, subjectName, pubKey);\n            JcaX509ExtensionUtils x509ExtUtils = new JcaX509ExtensionUtils();\n            certGen.addExtension(X509Extension.subjectKeyIdentifier, false,\n                    x509ExtUtils.createSubjectKeyIdentifier(pubKey));\n            certGen.addExtension(X509Extension.authorityKeyIdentifier, false,\n                    x509ExtUtils.createAuthorityKeyIdentifier(pubKey));\n            certGen.addExtension(X509Extension.keyUsage, false, new KeyUsage(\n                    KeyUsage.digitalSignature | KeyUsage.keyCertSign));\n            certGen.addExtension(X509Extension.extendedKeyUsage, false, new ExtendedKeyUsage(\n                    KeyPurposeId.id_kp_clientAuth));\n            certGen.addExtension(X509Extension.subjectAlternativeName, false, new GeneralNames(\n                    new GeneralName[] {\n                            new GeneralName(GeneralName.iPAddress, ipAddress),\n                            new GeneralName(GeneralName.uniformResourceIdentifier, ImsModule\n                                    .getImsUserProfile().getPublicUri())\n                    }));\n            certGen.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(true));\n\n            ContentSigner sigGen = new SimpleContentSignerBuilder().build(privKey);\n\n            JcaX509CertificateConverter certConv = new JcaX509CertificateConverter();\n            certChain[0] = certConv.getCertificate(certGen.build(sigGen));\n\n            setClientCertificateFingerprint(certChain[0]);\n\n            ks.setEntry(CLIENT_CERT_ALIAS, new KeyStore.PrivateKeyEntry(privKey, certChain),\n                    new KeyStore.PasswordProtection(KEYSTORE_PASSWORD.toCharArray()));\n\n            saveKeyStoreToFile(ks);\n\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Client certificate \" + CLIENT_CERT_ALIAS + \" for IP address \"\n                        + ipAddress + \" with fingerprint \" + getClientCertificateFingerprint()\n                        + \" added\");\n            }\n        } catch (KeyStoreException e) {\n            throw new CertificateException(new StringBuilder(\n                    \"Unable to create client certificate : \").append(CLIENT_CERT_ALIAS)\n                    .append(\" for IP address : \").append(ipAddress).toString(), e);\n\n        } catch (NoSuchAlgorithmException e) {\n            throw new CertificateException(new StringBuilder(\n                    \"Unable to create client certificate : \").append(CLIENT_CERT_ALIAS)\n                    .append(\" for IP address : \").append(ipAddress).toString(), e);\n\n        } catch (UnrecoverableEntryException e) {\n            throw new CertificateException(new StringBuilder(\n                    \"Unable to create client certificate : \").append(CLIENT_CERT_ALIAS)\n                    .append(\" for IP address : \").append(ipAddress).toString(), e);\n\n        } catch (CertIOException e) {\n            throw new CertificateException(new StringBuilder(\n                    \"Unable to create client certificate : \").append(CLIENT_CERT_ALIAS)\n                    .append(\" for IP address : \").append(ipAddress).toString(), e);\n\n        } catch (OperatorCreationException e) {\n            throw new CertificateException(new StringBuilder(\n                    \"Unable to create client certificate : \").append(CLIENT_CERT_ALIAS)\n                    .append(\" for IP address : \").append(ipAddress).toString(), e);\n        }\n    }\n\n    /**\n     * Create the RCS keystore\n     * \n     * @throws KeyStoreException\n     * @@throws IOException\n     */\n    private static void createKeyStore() throws KeyStoreException, IOException {\n        if (sKeyStore != null) {\n            return;\n        }\n        try {\n            sKeyStore = KeyStore.getInstance(getKeystoreType());\n            // Changed by Deutsche Telekom\n            synchronized (KeyStoreManager.class) {\n                sKeyStore.load(null, KEYSTORE_PASSWORD.toCharArray());\n            }\n            // Changed by Deutsche Telekom\n            saveKeyStoreToFile(sKeyStore);\n        } catch (NoSuchAlgorithmException e) {\n            throw new KeyStoreException(\"Unable to create key store!\", e);\n\n        } catch (CertificateException e) {\n            throw new KeyStoreException(\"Unable to create key store!\", e);\n\n        }\n    }\n\n    /**\n     * Check if a certificate is in the keystore\n     * \n     * @param alias certificate alias\n     * @return True if available\n     * @throws KeyStoreException\n     */\n    // Changed by Deutsche Telekom\n    private static boolean isCertificateEntry(String alias) throws KeyStoreException {\n        return sKeyStore.isCertificateEntry(alias);\n    }\n\n    /**\n     * Add a certificate or all certificates in folder in the keystore\n     * \n     * @param certificateFile Uri\n     * @throws KeyStoreException\n     * @throws IOException\n     */\n    // Changed by Deutsche Telekom\n    private static void addCertificates(Uri certificateFile) throws KeyStoreException, IOException {\n        InputStream inStream = null;\n        try {\n            // Changed by Deutsche Telekom\n            KeyStore ks = loadKeyStoreFromFile();\n            final String certPath = certificateFile.getPath();\n            File pathFile = new File(certPath);\n            if (pathFile.isDirectory()) {\n                File[] certificates = pathFile.listFiles(new FilenameFilter() {\n                    public boolean accept(File dir, String filename) {\n                        return filename.endsWith(RcsSettingsData.CERTIFICATE_FILE_TYPE);\n                    }\n                });\n\n                if (certificates != null) {\n                    for (File file : certificates) {\n                        CertificateFactory cf = CertificateFactory.getInstance(\"X.509\");\n                        inStream = new FileInputStream(file);\n                        X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);\n                        CloseableUtils.tryToClose(inStream);\n                        ks.setCertificateEntry(buildCertificateAlias(certificateFile), cert);\n                        // Changed by Deutsche Telekom\n                        saveKeyStoreToFile(ks);\n                    }\n                }\n            } else {\n                if (certPath.endsWith(RcsSettingsData.CERTIFICATE_FILE_TYPE)) {\n                    CertificateFactory cf = CertificateFactory.getInstance(\"X.509\");\n                    inStream = new FileInputStream(certPath);\n                    X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);\n                    ks.setCertificateEntry(buildCertificateAlias(certificateFile), cert);\n                    // Changed by Deutsche Telekom\n                    saveKeyStoreToFile(ks);\n                }\n            }\n        } catch (CertificateException e) {\n            throw new KeyStoreException(new StringBuilder(\"Adding certificate \")\n                    .append(certificateFile).append(\" failed!\").toString(), e);\n\n        } catch (FileNotFoundException e) {\n            throw new KeyStoreException(new StringBuilder(\"Adding certificate \")\n                    .append(certificateFile).append(\" failed!\").toString(), e);\n\n        } finally {\n            CloseableUtils.tryToClose(inStream);\n        }\n    }\n\n    /**\n     * Build alias from path\n     * \n     * @param path File path\n     * @return Alias\n     */\n    private static String buildCertificateAlias(Uri certFile) {\n        File file = new File(certFile.getPath());\n        String filename = file.getName();\n        long lastModified = file.lastModified();\n        int lastDotPosition = filename.lastIndexOf('.');\n        StringBuilder alias = new StringBuilder();\n        if (lastDotPosition > 0) {\n            alias.append(filename.substring(0, lastDotPosition));\n        } else {\n            alias.append(filename);\n        }\n        return alias.append(lastModified).toString();\n    }\n\n    /**\n     * Returns the fingerprint of a certificate\n     * \n     * @param cert Certificate\n     * @param algorithm hash algorithm to be used\n     * @return String as xx:yy:zz\n     * @throws NoSuchAlgorithmException\n     * @throws CertificateEncodingException\n     */\n    public static String getCertFingerprint(Certificate cert, String algorithm)\n            throws NoSuchAlgorithmException, CertificateEncodingException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Getting \" + algorithm + \" fingerprint for certificate: \"\n                    + cert.toString());\n        }\n        MessageDigest md = MessageDigest.getInstance(algorithm);\n        md.update(cert.getEncoded());\n        return hexify(md.digest());\n    }\n\n    /**\n     * Hexify a byte array\n     * \n     * @param bytes Byte array\n     * @return String\n     */\n    private static String hexify(byte bytes[]) {\n        char[] hexDigits = {\n                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'\n        };\n        StringBuffer buf = new StringBuffer(bytes.length * 2);\n        for (int i = 0; i < bytes.length; ++i) {\n            if (i != 0) {\n                buf.append(\":\");\n            }\n            buf.append(hexDigits[(bytes[i] & 0xf0) >> 4]);\n            buf.append(hexDigits[bytes[i] & 0x0f]);\n        }\n        return buf.toString();\n    }\n\n    /**\n     * Returns whether own certificates are used\n     * \n     * @param rcsSettings\n     * @return True if own certificates are used\n     * @throws KeyStoreException\n     */\n    public static boolean isOwnCertificateUsed(RcsSettings rcsSettings) throws KeyStoreException {\n        String certRoot = rcsSettings.getTlsCertificateRoot();\n        if (TextUtils.isEmpty(certRoot)) {\n            return false;\n        }\n        return isCertificateEntry(buildCertificateAlias(Uri.parse(certRoot)));\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Returns keystore from file\n     * \n     * @return KeyStore\n     * @throws KeyStoreException\n     * @throws IOException\n     */\n    private static KeyStore loadKeyStoreFromFile() throws KeyStoreException, IOException {\n        if (sKeyStore == null) {\n            FileInputStream fis = null;\n            try {\n                String keyStorePath = getKeystore().getPath();\n                File file = new File(keyStorePath);\n                if (!file.exists()) {\n                    throw new KeyStoreException(new StringBuilder(\n                            \"Loading of key store failed, Reason : \").append(keyStorePath)\n                            .append(\" does not exist!\").toString());\n                }\n                fis = new FileInputStream(keyStorePath);\n                sKeyStore = KeyStore.getInstance(getKeystoreType());\n                synchronized (KeyStoreManager.class) {\n                    sKeyStore.load(fis, KEYSTORE_PASSWORD.toCharArray());\n                }\n            } catch (NoSuchAlgorithmException e) {\n                throw new KeyStoreException(\"Loading of key store from file failed!\", e);\n\n            } catch (CertificateException e) {\n                throw new KeyStoreException(\"Loading of key store from file failed!\", e);\n\n            } finally {\n                CloseableUtils.tryToClose(fis);\n            }\n        }\n        return sKeyStore;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Saves keystore in file\n     * \n     * @throws IOException\n     * @throws\n     * @throws KeyStoreException\n     */\n    private static void saveKeyStoreToFile(KeyStore ks) throws KeyStoreException, IOException {\n        FileOutputStream fos = null;\n        try {\n            fos = new FileOutputStream(getKeystore().getPath());\n            synchronized (KeyStoreManager.class) {\n                ks.store(fos, KEYSTORE_PASSWORD.toCharArray());\n            }\n        } catch (FileNotFoundException e) {\n            throw new KeyStoreException(\"Saving of key store to file failed!\", e);\n\n        } catch (NoSuchAlgorithmException e) {\n            throw new KeyStoreException(\"Saving of key store to file failed!\", e);\n\n        } catch (CertificateException e) {\n            throw new KeyStoreException(\"Saving of key store to file failed!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(fos);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/cert/KeyStoreManagerException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security.cert;\n\n/**\n * Keystore manager exception\n * \n * @author B. Joguet\n */\npublic class KeyStoreManagerException extends java.lang.Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param error Error message\n     */\n    public KeyStoreManagerException(String error) {\n        super(error);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/security/cert/X509KeyManagerWrapper.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.security.cert;\n\nimport java.net.Socket;\nimport java.security.Principal;\nimport java.security.PrivateKey;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.X509KeyManager;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\n// Changed by Deutsche Telekom\n/**\n * This is a wrapper class to allow overwriting of requested DN in certificate request\n * \n * @author Deutsche Telekom AG\n */\npublic class X509KeyManagerWrapper implements X509KeyManager {\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private X509KeyManager defaultKeyManager;\n\n    public X509KeyManagerWrapper(KeyManager[] keyManagers) {\n        for (KeyManager keyManager : keyManagers) {\n            if (keyManager instanceof X509KeyManager) {\n                defaultKeyManager = (X509KeyManager) keyManager;\n                if (logger.isActivated()) {\n                    logger.debug(\"Choosen key manager: \" + defaultKeyManager.toString()\n                            + \" of class \" + defaultKeyManager.getClass().getName());\n                }\n            }\n        }\n\n    }\n\n    @Override\n    public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {\n        String alias = null;\n        if (logger.isActivated()) {\n            if ((keyType != null) && (keyType.length > 0)) {\n                for (String kt : keyType) {\n                    logger.debug(\"chooseClientAlias;  key: \" + kt);\n                }\n            }\n            if ((issuers != null) && (issuers.length > 0)) {\n                for (Principal issuer : issuers) {\n                    logger.debug(\"chooseClientAlias;  issuer: \" + issuer.getName());\n                }\n            }\n        }\n\n        alias = defaultKeyManager.chooseClientAlias(keyType, issuers, socket);\n        // patch to work around TLS handshake which request a client certificate\n        // from a specific issuer\n        if (alias == null) {\n            if (logger.isActivated()) {\n                logger.debug(\"No client certificate alias found! Fall back to default certificate.\");\n            }\n            alias = KeyStoreManager.CLIENT_CERT_ALIAS;\n        }\n        return alias;\n    }\n\n    @Override\n    public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {\n        return defaultKeyManager.chooseServerAlias(keyType, issuers, socket);\n    }\n\n    @Override\n    public X509Certificate[] getCertificateChain(String alias) {\n        return defaultKeyManager.getCertificateChain(alias);\n    }\n\n    @Override\n    public String[] getClientAliases(String keyType, Principal[] issuers) {\n        return defaultKeyManager.getClientAliases(keyType, issuers);\n    }\n\n    @Override\n    public PrivateKey getPrivateKey(String alias) {\n        return defaultKeyManager.getPrivateKey(alias);\n    }\n\n    @Override\n    public String[] getServerAliases(String keyType, Principal[] issuers) {\n        return defaultKeyManager.getServerAliases(keyType, issuers);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ContactInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.presence.PresenceInfo;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.SparseArray;\n\n/**\n * Contact info\n */\npublic class ContactInfo {\n\n    /**\n     * IMS registration state\n     */\n    public enum RegistrationState {\n        /**\n         * Unknown registration state\n         */\n        UNKNOWN(0),\n        /**\n         * Registered\n         */\n        ONLINE(1),\n        /**\n         * Not registered\n         */\n        OFFLINE(2);\n\n        private int mValue;\n\n        /**\n         * A data array to keep mapping between value and RegistrationState\n         */\n        private static SparseArray<RegistrationState> mValueToEnum = new SparseArray<RegistrationState>();\n        static {\n            for (RegistrationState entry : RegistrationState.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        private RegistrationState(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to RegistrationState instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a RegistrationState instance for the specified integer value.\n         * \n         * @param value to convert\n         * @return instance of RegistrationState\n         */\n        public static RegistrationState valueOf(int value) {\n            RegistrationState state = mValueToEnum.get(value);\n            if (state != null) {\n                return state;\n            }\n            return UNKNOWN;\n        }\n    }\n\n    /**\n     * User blocking state\n     */\n    public enum BlockingState {\n        /**\n         * User is not blocked\n         */\n        NOT_BLOCKED(0),\n        /**\n         * user is blocked\n         */\n        BLOCKED(1);\n\n        private int mValue;\n\n        /**\n         * A data array to keep mapping between value and BlockingState\n         */\n        private static SparseArray<BlockingState> mValueToEnum = new SparseArray<BlockingState>();\n        static {\n            for (BlockingState entry : BlockingState.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        private BlockingState(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to BlockingState instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a BlockingState instance for the specified integer value.\n         * \n         * @param value to convert\n         * @return instance of BlockingState\n         */\n        public static BlockingState valueOf(int value) {\n            BlockingState state = mValueToEnum.get(value);\n            if (state != null) {\n                return state;\n            }\n            return NOT_BLOCKED;\n        }\n    }\n\n    /**\n     * RCS status\n     */\n    public enum RcsStatus {\n        /**\n         * The contact is RCS capable but there is no special presence relationship with the user\n         */\n        RCS_CAPABLE(0),\n        /**\n         * The contact is not RCS\n         */\n        NOT_RCS(1),\n        /**\n         * Presence relationship: contact 'rcs granted' with the user\n         */\n        ACTIVE(2),\n        /**\n         * Presence relationship: the user has revoked the contact\n         */\n        REVOKED(3),\n        /**\n         * Presence relationship: the user has blocked the contact\n         */\n        BLOCKED(4),\n        /**\n         * Presence relationship: the user has sent an invitation to the contact without response\n         * for now\n         */\n        PENDING_OUT(5),\n        /**\n         * Presence relationship: the contact has sent an invitation to the user without response\n         * for now\n         */\n        PENDING(6),\n        /**\n         * Presence relationship: the contact has sent an invitation to the user and cancel it\n         */\n        CANCELLED(7),\n        /**\n         * We have never queried the contact capabilities for now\n         */\n        NO_INFO(8);\n\n        private int mValue;\n\n        /**\n         * A data array to keep mapping between value and PresenceSharingStatus\n         */\n        private static SparseArray<RcsStatus> mValueToEnum = new SparseArray<RcsStatus>();\n        static {\n            for (RcsStatus entry : RcsStatus.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        private RcsStatus(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to RcsStatus instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a RcsStatus instance for the specified integer value.\n         * \n         * @param value to convert\n         * @return instance of RcsStatus\n         */\n        public static RcsStatus valueOf(int value) {\n            RcsStatus status = mValueToEnum.get(value);\n            if (status != null) {\n                return status;\n            }\n            return NO_INFO;\n        }\n    }\n\n    /**\n     * Capabilities\n     */\n    private Capabilities mCapabilities;\n\n    /**\n     * Presence info, relevant only if social info is activated for this contact\n     */\n    private PresenceInfo mPresenceInfo;\n\n    /**\n     * Contact identifier\n     */\n    private ContactId mContact;\n\n    /**\n     * Display name of RCS contact\n     */\n    private String mDisplayName;\n\n    /**\n     * Registration state\n     */\n    private RegistrationState mRegistrationState = RegistrationState.UNKNOWN;\n\n    /**\n     * RCS status\n     */\n    private RcsStatus mRcsStatus = RcsStatus.NOT_RCS;\n\n    /**\n     * RCS status timestamp\n     */\n    private long mRcsStatusTimestamp = 0L;\n\n    /**\n     * Blocking state\n     */\n    private BlockingState mBlockingState = BlockingState.NOT_BLOCKED;\n\n    /**\n     * Blocking timestamp\n     */\n    private long mBlockingTs;\n\n    /**\n     * Constructor\n     */\n    public ContactInfo() {\n    }\n\n    /**\n     * Copy constructor\n     * \n     * @param info to copy\n     */\n    public ContactInfo(ContactInfo info) {\n        mContact = info.getContact();\n        mRegistrationState = info.getRegistrationState();\n        mRcsStatus = info.getRcsStatus();\n        mRcsStatusTimestamp = info.getRcsStatusTimestamp();\n        mCapabilities = new CapabilitiesBuilder(info.mCapabilities).build();\n        mPresenceInfo = info.getPresenceInfo();\n        mDisplayName = info.getDisplayName();\n        mBlockingState = info.getBlockingState();\n        mBlockingTs = info.getBlockingTimestamp();\n    }\n\n    /**\n     * Set the capabilities\n     * \n     * @param capabilities Capabilities\n     */\n    public void setCapabilities(Capabilities capabilities) {\n        mCapabilities = capabilities;\n    }\n\n    /**\n     * Returns the capabilities\n     * \n     * @return Capabilities\n     */\n    public Capabilities getCapabilities() {\n        return mCapabilities;\n    }\n\n    /**\n     * Set the presence info\n     * \n     * @param info Presence info\n     */\n    public void setPresenceInfo(PresenceInfo info) {\n        mPresenceInfo = info;\n    }\n\n    /**\n     * Returns the presence info\n     * \n     * @return PresenceInfo\n     */\n    public PresenceInfo getPresenceInfo() {\n        return mPresenceInfo;\n    }\n\n    /**\n     * Set the contact identifier\n     * \n     * @param contact Contact identifier\n     */\n    public void setContact(ContactId contact) {\n        mContact = contact;\n    }\n\n    /**\n     * Returns the contact identifier\n     * \n     * @return contactId\n     */\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    /**\n     * Set the RCS status\n     * \n     * @param rcsStatus RCS status\n     */\n    public void setRcsStatus(RcsStatus rcsStatus) {\n        mRcsStatus = rcsStatus;\n    }\n\n    /**\n     * Returns the RCS status\n     * \n     * @return rcsStatus\n     */\n    public RcsStatus getRcsStatus() {\n        return mRcsStatus;\n    }\n\n    /**\n     * Set the registration state\n     * \n     * @param state the registration state\n     */\n    public void setRegistrationState(RegistrationState state) {\n        mRegistrationState = state;\n    }\n\n    /**\n     * Returns the registration state\n     * \n     * @return registrationState\n     */\n    public RegistrationState getRegistrationState() {\n        return mRegistrationState;\n    }\n\n    /**\n     * Set the RCS status timestamp\n     * \n     * @param timestamp Last RCS status date of change\n     */\n    public void setRcsStatusTimestamp(long timestamp) {\n        mRcsStatusTimestamp = timestamp;\n    }\n\n    /**\n     * Returns the RCS status timestamp\n     * \n     * @return timestamp\n     */\n    public long getRcsStatusTimestamp() {\n        return mRcsStatusTimestamp;\n    }\n\n    /**\n     * Is a RCS contact\n     * \n     * @return true if the contact is RCS\n     */\n    public boolean isRcsContact() {\n        return (RcsStatus.NO_INFO != mRcsStatus && RcsStatus.NOT_RCS != mRcsStatus);\n    }\n\n    /**\n     * Returns the RCS display name\n     * \n     * @return the RCS display name\n     */\n    public String getDisplayName() {\n        return mDisplayName;\n    }\n\n    /**\n     * Sets the RCS display name\n     * \n     * @param displayName the RCS display name\n     */\n    public void setDisplayName(String displayName) {\n        mDisplayName = displayName;\n    }\n\n    /**\n     * Set the blocking state\n     * \n     * @param state State\n     */\n    public void setBlockingState(BlockingState state) {\n        mBlockingState = state;\n    }\n\n    /**\n     * Returns the blocking state\n     * \n     * @return State\n     */\n    public BlockingState getBlockingState() {\n        return mBlockingState;\n    }\n\n    /**\n     * Returns the blocking timestamp\n     * \n     * @return Timestamp\n     */\n    public long getBlockingTimestamp() {\n        return mBlockingTs;\n    }\n\n    /**\n     * Set the blocking timestamp\n     * \n     * @param ts Timestamp\n     */\n    public void setBlockingTimestamp(long ts) {\n        mBlockingTs = ts;\n    }\n\n    /**\n     * Returns a string representation of the object\n     * \n     * @return String\n     */\n    public String toString() {\n        String result = \"Contact=\" + mContact + \", Status=\" + mRcsStatus + \", State=\"\n                + mRegistrationState + \", Timestamp=\" + mRcsStatusTimestamp + \", Blocked=\"\n                + mBlockingState + \", Blocked at=\" + mBlockingTs;\n        if (mCapabilities != null) {\n            result += \", Capabilities=\" + mCapabilities.toString();\n        }\n        if (mPresenceInfo != null) {\n            result += \", Presence=\" + mPresenceInfo.toString();\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ImsService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\n\n/**\n * Abstract IMS service\n * \n * @author jexa7410\n */\npublic abstract class ImsService {\n    /**\n     * IMS service enumerated type\n     */\n    public enum ImsServiceType {\n        /**\n         * Terms & conditions service\n         */\n        TERMS_CONDITIONS,\n        /**\n         * Capability service\n         */\n        CAPABILITY,\n        /**\n         * Instant Messaging service\n         */\n        INSTANT_MESSAGING,\n        /**\n         * IP call service\n         */\n        IPCALL,\n        /**\n         * Richcall service\n         */\n        RICHCALL,\n        /**\n         * Presence service\n         */\n        PRESENCE,\n        /**\n         * SIP service\n         */\n        SIP\n    }\n\n    private boolean mActivated = true;\n\n    private boolean mStarted = false;\n\n    private ImsModule mImsModule;\n\n    /**\n     * ImsServiceSessionCache with session dialog path's CallId as key\n     */\n    private Map<String, ImsServiceSession> mImsServiceSessionCache = new HashMap<>();\n\n    /**\n     * ImsServiceSessionWithoutDialogPathCache with session Id as key\n     */\n    private Map<String, ImsServiceSession> mImsServiceSessionWithoutDialogPathCache = new HashMap<>();\n\n    private static final Logger sLogger = Logger.getLogger(ImsService.class.getSimpleName());\n\n    protected final static class SharingDirection {\n\n        public static final int UNIDIRECTIONAL = 1;\n\n        public static final int BIDIRECTIONAL = 2;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param activated Activation flag\n     */\n    public ImsService(ImsModule parent, boolean activated) {\n        mImsModule = parent;\n        mActivated = activated;\n    }\n\n    /**\n     * Is service activated\n     * \n     * @return Boolean\n     */\n    public boolean isActivated() {\n        return mActivated;\n    }\n\n    /**\n     * Change the activation flag of the service\n     * \n     * @param activated Activation flag\n     */\n    public void setActivated(boolean activated) {\n        mActivated = activated;\n    }\n\n    /**\n     * Returns the IMS module\n     * \n     * @return IMS module\n     */\n    public ImsModule getImsModule() {\n        return mImsModule;\n    }\n\n    /*\n     * This method is by choice not synchronized here since the class extending this base-class will\n     * need to handle the synchronization over a larger scope when calling this method anyway and we\n     * would like to avoid double locks.\n     */\n    protected void addImsServiceSession(ImsServiceSession session) {\n        mImsServiceSessionCache.put(session.getDialogPath().getCallId(), session);\n    }\n\n    /*\n     * This method is by choice not synchronized here since the class extending this base-class will\n     * need to handle the synchronization over a larger scope when calling this method anyway and we\n     * would like to avoid double locks.\n     */\n    protected void removeImsServiceSession(ImsServiceSession session) {\n        mImsServiceSessionCache.remove(session.getDialogPath().getCallId());\n    }\n\n    /**\n     * Gets IMS session from callId\n     * \n     * @param callId call ID\n     * @return ImsServiceSession\n     */\n    public ImsServiceSession getImsServiceSession(String callId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mImsServiceSessionCache.get(callId);\n        }\n    }\n\n    /*\n     * This method is by choice not synchronized here since the class extending this base-class will\n     * need to handle the synchronization over a larger scope when calling this method anyway and we\n     * would like to avoid double locks.\n     */\n    protected void addImsServiceSessionWithoutDialogPath(ImsServiceSession session) {\n        mImsServiceSessionWithoutDialogPathCache.put(session.getSessionID(), session);\n    }\n\n    /*\n     * This method is by choice not synchronized here since the class extending this base-class will\n     * need to handle the synchronization over a larger scope when calling this method anyway and we\n     * would like to avoid double locks.\n     */\n    protected void removeImsServiceSessionWithoutDialogPath(ImsServiceSession session) {\n        mImsServiceSessionWithoutDialogPathCache.remove(session.getSessionID());\n    }\n\n    protected Object getImsServiceSessionOperationLock() {\n        return mImsServiceSessionCache;\n    }\n\n    /**\n     * Is service started\n     * \n     * @return Boolean\n     */\n    public boolean isServiceStarted() {\n        return mStarted;\n    }\n\n    /**\n     * Set service state\n     * \n     * @param state State\n     */\n    public void setServiceStarted(boolean state) {\n        mStarted = state;\n    }\n\n    /**\n     * Start the IMS service\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public abstract void start() throws PayloadException, NetworkException;\n\n    /**\n     * Stop the IMS service\n     *\n     * @param reasonCode the reason to stop services\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public abstract void stop(TerminationReason reasonCode) throws PayloadException,\n            NetworkException;\n\n    /**\n     * Check the IMS service\n     */\n    public abstract void check();\n\n    /**\n     * This function is used when all session needs to terminated in both invitation pending and\n     * started state.\n     * \n     * @param reason termination reason\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void terminateAllSessions(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        synchronized (getImsServiceSessionOperationLock()) {\n            /*\n             * Iterate over a copy of the session set to allow removal in the cache map while\n             * iterating.\n             */\n            for (ImsServiceSession session : new HashSet<>(mImsServiceSessionCache.values())) {\n                session.terminateSession(reason);\n            }\n\n            /*\n             * Iterate over a copy of the session set to allow removal in the cache map while\n             * iterating.\n             */\n            for (ImsServiceSession session : new HashSet<>(\n                    mImsServiceSessionWithoutDialogPathCache.values())) {\n                session.terminateSession(reason);\n            }\n        }\n    }\n\n    /**\n     * Send an error response to a request\n     * \n     * @param request Request\n     * @param error Error code\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendErrorResponse(SipRequest request, int error) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send error \".concat(String.valueOf(error)));\n        }\n        SipResponse resp = SipMessageFactory.createResponse(request, IdGenerator.getIdentifier(),\n                error);\n        getImsModule().getSipManager().sendSipResponse(resp);\n    }\n\n    /**\n     * Try to send an error response to a request. If failing then just log the failure but throw\n     * now exception.\n     * \n     * @param request Request\n     * @param error Error code\n     */\n    public void tryToSendErrorResponse(SipRequest request, int error) {\n        try {\n            sendErrorResponse(request, error);\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unable to send error response! (\" + e.getMessage() + \")\");\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Unable to send error response!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ImsServiceDispatcher.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.standfw.StoreAndForwardManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.presence.PresenceService;\nimport com.gsma.rcs.core.ims.service.terms.TermsConditionsService;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.FifoBuffer;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Intent;\n\nimport java.text.ParseException;\n\nimport javax2.sip.address.SipURI;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.header.SubscriptionStateHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/**\n * IMS service dispatcher\n * \n * @author jexa7410\n */\npublic class ImsServiceDispatcher extends Thread {\n\n    private ImsModule mImsModule;\n\n    /**\n     * Buffer of messages\n     */\n    private FifoBuffer mBuffer = new FifoBuffer();\n\n    private SipIntentManager mIntentMgr = new SipIntentManager();\n\n    private static final Logger sLogger = Logger.getLogger(ImsServiceDispatcher.class.getName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param imsModule IMS module\n     * @param rcsSettings the RCS settings\n     */\n    public ImsServiceDispatcher(ImsModule imsModule, RcsSettings rcsSettings) {\n        super(\"SipDispatcher\");\n        mImsModule = imsModule;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Terminate the SIP dispatcher\n     */\n    public void terminate() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the multi-session manager\");\n        }\n        mBuffer.close();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Multi-session manager has been terminated\");\n        }\n    }\n\n    /**\n     * Post a SIP request in the buffer\n     * \n     * @param request SIP request\n     */\n    public void postSipRequest(SipRequest request) {\n        mBuffer.addObject(request);\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start background processing\");\n        }\n        SipRequest request;\n        while ((request = (SipRequest) mBuffer.getObject()) != null) {\n            try {\n                dispatch(request, System.currentTimeMillis());\n\n            } catch (PayloadException | RuntimeException e) {\n                sLogger.error(\n                        \"Failed to dispatch received SIP request! CallId=\" + request.getCallId(), e);\n                handleImsDispatchError(request);\n\n            } catch (NetworkException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n                handleImsDispatchError(request);\n            }\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"End of background processing\");\n        }\n    }\n\n    /**\n     * Dispatch the received SIP request\n     * \n     * @param request SIP request\n     * @param timestamp Local timestamp when got SipRequest\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void dispatch(SipRequest request, long timestamp) throws PayloadException,\n            NetworkException {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Receive \" + request.getMethod() + \" request\");\n        }\n        /* Check the IP address of the request-URI */\n        String localIpAddress = mImsModule.getCurrentNetworkInterface().getNetworkAccess()\n                .getIpAddress();\n        ImsNetworkInterface imsNetIntf = mImsModule.getCurrentNetworkInterface();\n        SipURI requestURI;\n        try {\n            requestURI = SipUtils.ADDR_FACTORY.createSipURI(request.getRequestURI());\n\n        } catch (ParseException e) {\n            if (logActivated) {\n                sLogger.error(\"Unable to parse request URI \" + request.getRequestURI(), e);\n            }\n            sendFinalResponse(request, Response.BAD_REQUEST);\n            return;\n        }\n        /* First check if the request URI matches with the local interface address */\n        boolean isMatchingRegistered = localIpAddress.equals(requestURI.getHost());\n        /* If no matching, perhaps we are behind a NAT */\n        if ((!isMatchingRegistered) && imsNetIntf.isBehindNat()) {\n            /*\n             * We are behind NAT: check if the request URI contains the previously discovered public\n             * IP address and port number\n             */\n            String natPublicIpAddress = imsNetIntf.getNatPublicAddress();\n            int natPublicUdpPort = imsNetIntf.getNatPublicPort();\n            isMatchingRegistered = (natPublicUdpPort != -1) && (natPublicIpAddress != null)\n                    && natPublicIpAddress.equals(requestURI.getHost())\n                    && (natPublicUdpPort == requestURI.getPort());\n            /* NAT traversal and unknown public address/port */\n        }\n        if (!isMatchingRegistered) {\n            if (logActivated) {\n                sLogger.debug(\"Request-URI address and port do not match with registered contact: reject the request\");\n            }\n            sendFinalResponse(request, Response.NOT_FOUND);\n            return;\n        }\n        /*\n         * Check SIP instance ID: RCS client supporting the multidevice procedure shall respond to\n         * the invite with a 486 BUSY HERE if the identifier value of the \"+sip.instance\" tag\n         * included in the Accept-Contact header of that incoming SIP request does not match theirs.\n         */\n        String instanceId = SipUtils.getInstanceID(request);\n        if ((instanceId != null)\n                && !instanceId.contains(mImsModule.getSipManager().getSipStack().getInstanceId())) {\n            if (logActivated) {\n                sLogger.debug(\"SIP instance ID doesn't match: reject the request\");\n            }\n            sendFinalResponse(request, Response.BUSY_HERE);\n            return;\n        }\n        /*\n         * Check public GRUU : RCS client supporting the multidevice procedure shall respond to the\n         * invite with a 486 BUSY HERE if the identifier value of the \"pub-gruu\" tag included in the\n         * Accept-Contact header of that incoming SIP request does not match theirs.\n         */\n        String publicGruu = SipUtils.getPublicGruu(request);\n        if ((publicGruu != null)\n                && !publicGruu.contains(mImsModule.getSipManager().getSipStack().getPublicGruu())) {\n            if (logActivated) {\n                sLogger.debug(\"SIP public-gruu doesn't match: reject the request\");\n            }\n            sendFinalResponse(request, Response.BUSY_HERE);\n            return;\n        }\n        /* Update remote SIP instance ID in the dialog path of the session */\n        ImsServiceSession session = getImsServiceSession(request.getCallId());\n        if (session != null) {\n            ContactHeader contactHeader = (ContactHeader) request.getHeader(ContactHeader.NAME);\n            if (contactHeader != null) {\n                String remoteInstanceId = contactHeader.getParameter(SipUtils.SIP_INSTANCE_PARAM);\n                session.getDialogPath().setRemoteSipInstance(remoteInstanceId);\n            }\n        }\n        if (request.getMethod().equals(Request.OPTIONS)) {\n            mImsModule.getCapabilityService().onCapabilityRequestReceived(request);\n\n        } else if (request.getMethod().equals(Request.INVITE)) {\n            if (session != null) {\n                /* Subsequent request received */\n                session.receiveReInvite(request);\n                return;\n            }\n            send100Trying(request);\n            String sdp = request.getSdpContent();\n            if (sdp == null) {\n                /* No SDP found: reject the invitation with a 606 Not Acceptable */\n                if (logActivated) {\n                    sLogger.debug(\"No SDP found: automatically reject\");\n                }\n                sendFinalResponse(request, Response.SESSION_NOT_ACCEPTABLE);\n                return;\n            }\n            sdp = sdp.toLowerCase();\n            /* New incoming session invitation */\n            if (isTagPresent(sdp, \"msrp\")\n                    && SipUtils.isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_VIDEO_SHARE)\n                    && (SipUtils.isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_IMAGE_SHARE) || SipUtils\n                            .isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_IMAGE_SHARE_RCS2))) {\n                if (mRcsSettings.isImageSharingSupported()) {\n                    if (logActivated) {\n                        sLogger.debug(\"Image content sharing transfer invitation\");\n                    }\n                    mImsModule.getRichcallService().onImageSharingInvitationReceived(request,\n                            timestamp);\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"Image share service not supported: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.DECLINE);\n                }\n            } else if (isTagPresent(sdp, \"msrp\")\n                    && SipUtils.isFeatureTagPresent(request, FeatureTags.FEATURE_OMA_IM)\n                    && isTagPresent(sdp, \"file-selector\")) {\n                if (mRcsSettings.isFileTransferSupported()) {\n                    if (logActivated) {\n                        sLogger.debug(\"File transfer invitation\");\n                    }\n                    mImsModule.getInstantMessagingService().onMsrpFileTransferInvitationReceived(\n                            request, timestamp);\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"File transfer service not supported: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.DECLINE);\n                }\n            } else if (isTagPresent(sdp, \"msrp\")\n                    && SipUtils.isFeatureTagPresent(request, FeatureTags.FEATURE_OMA_IM)) {\n                if (!mRcsSettings.isImSessionSupported()) {\n                    if (logActivated) {\n                        sLogger.debug(\"IM service not supported: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.DECLINE);\n                    return;\n                }\n                if (ChatUtils.isFileTransferOverHttp(request)) {\n                    FileTransferHttpInfoDocument ftHttpInfo = FileTransferUtils.getHttpFTInfo(\n                            request, mRcsSettings);\n                    if (ftHttpInfo != null) {\n                        if (SipUtils.getReferredByHeader(request) != null) {\n                            if (logActivated) {\n                                sLogger.debug(\"Single S&F file transfer over HTTP invitation\");\n                            }\n                            mImsModule.getInstantMessagingService()\n                                    .onStoreAndForwardOneToOneHttpFileTranferInvitationReceived(\n                                            request, ftHttpInfo, timestamp);\n                        } else {\n                            if (logActivated) {\n                                sLogger.debug(\"Single file transfer over HTTP invitation\");\n                            }\n                            mImsModule.getInstantMessagingService()\n                                    .onOneToOneHttpFileTranferInvitationReceived(request,\n                                            ftHttpInfo, timestamp);\n                        }\n                    } else {\n                        // TODO : else return error to Originating side\n                        // Malformed XML for FToHTTP: automatically reject with a 606 Not Acceptable\n                        if (logActivated) {\n                            sLogger.debug(\"Malformed xml for FToHTTP: automatically reject\");\n                        }\n                        sendFinalResponse(request, Response.SESSION_NOT_ACCEPTABLE);\n                    }\n                } else {\n                    String contentType = request.getContentType();\n                    SipUtils.assertContentIsNotNull(contentType, request);\n                    if (SipUtils.getAssertedIdentity(request).contains(\n                            StoreAndForwardManager.SERVICE_URI)\n                            && (!contentType.contains(\"multipart\"))) {\n                        if (logActivated) {\n                            sLogger.debug(\"Store & Forward push notifications\");\n                        }\n                        mImsModule.getInstantMessagingService()\n                                .onStoredAndForwardPushNotificationReceived(request, timestamp);\n\n                    } else if (ChatUtils.isGroupChatInvitation(request)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Ad-hoc group chat session invitation\");\n                        }\n                        mImsModule.getInstantMessagingService().onAdHocGroupChatSessionReceived(\n                                request, timestamp);\n\n                    } else if (SipUtils.getReferredByHeader(request) != null) {\n                        if (logActivated) {\n                            sLogger.debug(\"Store & Forward push messages session\");\n                        }\n                        mImsModule.getInstantMessagingService()\n                                .onStoreAndForwardPushMessagesReceived(request, timestamp);\n\n                    } else {\n                        if (logActivated) {\n                            sLogger.debug(\"1-1 chat session invitation\");\n                        }\n                        mImsModule.getInstantMessagingService().onOne2OneChatSessionReceived(\n                                request, timestamp);\n                    }\n                }\n            } else if (isTagPresent(sdp, \"rtp\")\n                    && SipUtils.isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_VIDEO_SHARE)) {\n                if (mRcsSettings.isVideoSharingSupported()) {\n                    if (logActivated) {\n                        sLogger.debug(\"Video content sharing streaming invitation\");\n                    }\n                    mImsModule.getRichcallService().onVideoSharingInvitationReceived(request,\n                            timestamp);\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"Video share service not supported: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.DECLINE);\n                }\n            } else if (isTagPresent(sdp, \"msrp\")\n                    && SipUtils.isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_VIDEO_SHARE)\n                    && SipUtils.isFeatureTagPresent(request,\n                            FeatureTags.FEATURE_RCSE_GEOLOCATION_PUSH)) {\n                if (mRcsSettings.isGeoLocationPushSupported()) {\n                    if (logActivated) {\n                        sLogger.debug(\"Geoloc content sharing transfer invitation\");\n                    }\n                    mImsModule.getRichcallService().onGeolocSharingInvitationReceived(request,\n                            timestamp);\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"Geoloc share service not supported: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.DECLINE);\n                }\n            } else if (SipUtils\n                    .isFeatureTagPresent(request, FeatureTags.FEATURE_RCSE_IP_VOICE_CALL)\n                    && SipUtils\n                            .isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_IP_VOICE_CALL)) {\n                // TODO: Add Ipcall support here in future releases\n                // Service not supported: reject the invitation with a 603 Decline\n                if (logActivated) {\n                    sLogger.debug(\"IP Voice call service not supported: automatically reject\");\n                }\n                sendFinalResponse(request, Response.DECLINE);\n\n            } else if (SipUtils\n                    .isFeatureTagPresent(request, FeatureTags.FEATURE_RCSE_IP_VOICE_CALL)\n                    && SipUtils\n                            .isFeatureTagPresent(request, FeatureTags.FEATURE_3GPP_IP_VOICE_CALL)\n                    && SipUtils\n                            .isFeatureTagPresent(request, FeatureTags.FEATURE_RCSE_IP_VIDEO_CALL)) {\n                // TODO: Add Ipcall support here in future releases\n                // Service not supported: reject the invitation with a 603 Decline\n                if (logActivated) {\n                    sLogger.debug(\"IP video call service not supported: automatically reject\");\n                }\n                sendFinalResponse(request, Response.DECLINE);\n\n            } else {\n                Intent intent = mIntentMgr.isSipRequestResolved(request);\n                if (intent != null) {\n                    if (isTagPresent(sdp, \"msrp\")) {\n                        if (logActivated) {\n                            sLogger.debug(\"Generic SIP session invitation with MSRP media\");\n                        }\n                        mImsModule.getSipService().onMsrpSessionInvitationReceived(intent, request,\n                                timestamp);\n                    } else if (isTagPresent(sdp, \"rtp\")) {\n                        if (logActivated) {\n                            sLogger.debug(\"Generic SIP session invitation with RTP media\");\n                        }\n                        mImsModule.getSipService().onRtpSessionInvitationReceived(intent, request,\n                                timestamp);\n                    } else {\n                        if (logActivated) {\n                            sLogger.debug(\"Media not supported for a generic SIP session\");\n                        }\n                        sendFinalResponse(request, Response.SESSION_NOT_ACCEPTABLE);\n                    }\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"Unknown IMS service: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.FORBIDDEN, \"Unsupported Extension\");\n                }\n            }\n        } else if (request.getMethod().equals(Request.MESSAGE)) {\n            if (ChatUtils.isImdnService(request)) {\n                mImsModule.getInstantMessagingService().onMessageDeliveryStatusReceived(request);\n            } else if (TermsConditionsService.isTermsRequest(request)) {\n                mImsModule.getTermsConditionsService().onMessageReceived(request);\n            } else {\n                Intent intent = mIntentMgr.isSipRequestResolved(request);\n                if (intent != null) {\n                    mImsModule.getSipService().onInstantMessageReceived(intent, request);\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"Unknown IMS service: automatically reject\");\n                    }\n                    sendFinalResponse(request, Response.FORBIDDEN);\n                }\n            }\n        } else if (request.getMethod().equals(Request.NOTIFY)) {\n            dispatchNotify(request, timestamp);\n\n        } else if (request.getMethod().equals(Request.BYE)) {\n            if (session != null) {\n                session.receiveBye(request);\n            }\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            mImsModule.getSipManager().sendSipResponse(\n                    SipMessageFactory.createResponse(request, Response.OK));\n\n        } else if (request.getMethod().equals(Request.CANCEL)) {\n            if (session != null) {\n                session.receiveCancel(request);\n            }\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            mImsModule.getSipManager().sendSipResponse(\n                    SipMessageFactory.createResponse(request, Response.OK));\n\n        } else if (request.getMethod().equals(Request.UPDATE)) {\n            if (session != null) {\n                session.receiveUpdate(request);\n            }\n        } else {\n            /* Unknown request: : reject the request with a 403 Forbidden */\n            if (logActivated) {\n                sLogger.debug(\"Unknown request \" + request.getMethod());\n            }\n            sendFinalResponse(request, Response.FORBIDDEN);\n        }\n    }\n\n    /**\n     * Dispatch the received SIP NOTIFY\n     * \n     * @param notify SIP request\n     * @param timestamp Local timestamp when got SipRequest\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void dispatchNotify(SipRequest notify, long timestamp) throws PayloadException,\n            NetworkException {\n        mImsModule.getSipManager().sendSipResponse(\n                SipMessageFactory.createResponse(notify, Response.OK));\n        EventHeader eventHeader = (EventHeader) notify.getHeader(EventHeader.NAME);\n        if (eventHeader == null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unknown notification event type\");\n            }\n            return;\n        }\n        /* Dispatch the notification to the corresponding service */\n        if (eventHeader.getEventType().equalsIgnoreCase(\"presence.winfo\")) {\n            if (mRcsSettings.isSocialPresenceSupported()\n                    && mImsModule.getPresenceService().isServiceStarted()) {\n                mImsModule.getPresenceService().getWatcherInfoSubscriber()\n                        .receiveNotification(notify);\n            }\n        } else if (eventHeader.getEventType().equalsIgnoreCase(\"presence\")) {\n            if (notify.getTo().contains(\"anonymous\")) {\n                mImsModule.getCapabilityService().onNotificationReceived(notify);\n            } else {\n                mImsModule.getPresenceService().getPresenceSubscriber().receiveNotification(notify);\n            }\n        } else if (eventHeader.getEventType().equalsIgnoreCase(\"conference\")) {\n            mImsModule.getInstantMessagingService().onConferenceNotificationReceived(notify,\n                    timestamp);\n\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not supported notification event type\");\n            }\n        }\n    }\n\n    /**\n     * Test a tag is present or not in SIP message\n     * \n     * @param message Message or message part\n     * @param tag Tag to be searched\n     * @return Boolean\n     */\n    private boolean isTagPresent(String message, String tag) {\n        return (message != null) && (tag != null) && (message.toLowerCase().contains(tag));\n    }\n\n    /**\n     * Search the IMS session that corresponds to a given call-ID\n     * \n     * @param callId Call-ID\n     * @return IMS session\n     */\n    private ImsServiceSession getImsServiceSession(String callId) {\n        for (ImsService service : mImsModule.getImsServices()) {\n            ImsServiceSession session = service.getImsServiceSession(callId);\n            if (session != null) {\n                return session;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Send a 100 Trying response to the remote party\n     * \n     * @param request SIP request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void send100Trying(SipRequest request) throws NetworkException, PayloadException {\n        mImsModule.getCurrentNetworkInterface().getSipManager()\n                .sendSipResponse(SipMessageFactory.createResponse(request, null, Response.TRYING));\n    }\n\n    /**\n     * Send a final response\n     * \n     * @param request SIP request\n     * @param code Response code\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendFinalResponse(SipRequest request, int code) throws NetworkException,\n            PayloadException {\n        mImsModule\n                .getCurrentNetworkInterface()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(request, IdGenerator.getIdentifier(), code));\n    }\n\n    /**\n     * Send a final response\n     * \n     * @param request SIP request\n     * @param code Response code\n     * @param warning Warning message\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendFinalResponse(SipRequest request, int code, String warning)\n            throws NetworkException, PayloadException {\n        mImsModule\n                .getCurrentNetworkInterface()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(request, IdGenerator.getIdentifier(),\n                                code, warning));\n    }\n\n    /**\n     * Handle ims dispatch error\n     * \n     * @param request the SIP request\n     */\n    private void handleImsDispatchError(SipRequest request) {\n        final PresenceService service = mImsModule.getPresenceService();\n        if (request.getMethod().equals(Request.NOTIFY) && mRcsSettings.isSocialPresenceSupported()\n                && service.isServiceStarted()) {\n            SubscriptionStateHeader stateHeader = (SubscriptionStateHeader) request\n                    .getHeader(SubscriptionStateHeader.NAME);\n            if ((stateHeader != null) && stateHeader.getState().equalsIgnoreCase(\"terminated\")) {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Presence subscription has been terminated by server\");\n                }\n                service.getPresenceSubscriber().terminatedByServer();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ImsServiceError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\n/**\n * IMS service error\n * \n * @author jexa7410\n */\npublic class ImsServiceError extends Error {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Error code base for IMS sessions\n     */\n    protected static final int SESSION_ERROR_CODES = 100;\n\n    /**\n     * Error code base for capabitity service\n     */\n    protected static final int CAPABILITY_ERROR_CODES = 200;\n\n    /**\n     * Error code base for presence service\n     */\n    protected static final int PRESENCE_ERROR_CODES = 300;\n\n    /**\n     * Unexpected exception occurs in the module (e.g. internal exception)\n     */\n    public final static int UNEXPECTED_EXCEPTION = 1;\n\n    /**\n     * Error code\n     */\n    private int mErrorCode;\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public ImsServiceError(int code) {\n        super();\n\n        mErrorCode = code;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public ImsServiceError(int code, String msg) {\n        super(msg);\n\n        mErrorCode = code;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ImsServiceError(int code, Throwable cause) {\n        super(cause);\n\n        mErrorCode = code;\n    }\n\n    /**\n     * Returns the error code\n     * \n     * @return Error code\n     */\n    public int getErrorCode() {\n        return mErrorCode;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ImsServiceSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipManager;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Vector;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.message.Response;\n\n/**\n * IMS service session\n * \n * @author jexa7410\n */\npublic abstract class ImsServiceSession extends Thread {\n    // @formatter:off\n    /**\n     * Session invitation status\n     */\n    public enum InvitationStatus {\n\n        INVITATION_NOT_ANSWERED, INVITATION_ACCEPTED, INVITATION_REJECTED, INVITATION_CANCELED, \n        INVITATION_TIMEOUT, INVITATION_REJECTED_BY_SYSTEM, INVITATION_DELETED, \n        INVITATION_REJECTED_DECLINE, INVITATION_REJECTED_BUSY_HERE, INVITATION_REJECTED_FORBIDDEN\n    }\n\n    /**\n     * Session termination reason\n     */\n    public enum TerminationReason {\n        TERMINATION_BY_SYSTEM, TERMINATION_BY_USER, TERMINATION_BY_TIMEOUT, TERMINATION_BY_INACTIVITY, \n        TERMINATION_BY_CONNECTION_LOST, TERMINATION_BY_LOW_BATTERY, TERMINATION_BY_REMOTE\n    }\n    // @formatter:on\n\n    private final static int SESSION_INTERVAL_TOO_SMALL = 422;\n\n    private final ImsService mImsService;\n\n    private String mSessionId = SessionIdGenerator.getNewId();\n\n    /**\n     * Remote contactId\n     */\n    private ContactId mContact;\n\n    /**\n     * Remote contactUri\n     */\n    private Uri mRemoteId;\n\n    private String mRemoteDisplayName;\n\n    private SipDialogPath mDialogPath;\n\n    /**\n     * Authentication agent\n     */\n    private SessionAuthenticationAgent mAuthenticationAgent;\n\n    /**\n     * Session invitation status\n     */\n    protected InvitationStatus mInvitationStatus = InvitationStatus.INVITATION_NOT_ANSWERED;\n\n    /**\n     * Wait user answer for session invitation\n     */\n    protected final Object mWaitUserAnswer = new Object();\n\n    private List<ImsSessionListener> mListeners = new ArrayList<>();\n\n    /**\n     * Session timer manager\n     */\n    private SessionTimerManager mSessionTimer = new SessionTimerManager(this);\n\n    /**\n     * Update session manager\n     */\n    protected UpdateSessionManager mUpdateMgr;\n\n    /**\n     * Ringing period (in milliseconds)\n     */\n    private final long mRingingPeriod;\n\n    /**\n     * Session interrupted flag\n     */\n    private boolean mSessionInterrupted = false;\n\n    /**\n     * Session terminated by remote flag\n     */\n    private boolean mSessionTerminatedByRemote = false;\n\n    /**\n     * Session accepting flag\n     */\n    private boolean mSessionAccepted = false;\n\n    protected final RcsSettings mRcsSettings;\n\n    protected final ContactManager mContactManager;\n\n    /**\n     * Session timestamp\n     */\n    private long mTimestamp;\n\n    private static final Logger sLogger = Logger.getLogger(ImsServiceSession.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param imsService IMS service\n     * @param contact Remote contact Identifier\n     * @param remoteId Remote contact URI\n     * @param rcsSettings RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager accessor\n     */\n    public ImsServiceSession(ImsService imsService, ContactId contact, Uri remoteId,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager) {\n        mImsService = imsService;\n        mContact = contact;\n        mRemoteId = remoteId;\n        mAuthenticationAgent = new SessionAuthenticationAgent(imsService.getImsModule());\n        mUpdateMgr = new UpdateSessionManager(this, rcsSettings);\n        mContactManager = contactManager;\n        mRcsSettings = rcsSettings;\n        mRingingPeriod = mRcsSettings.getRingingPeriod();\n        mTimestamp = timestamp;\n    }\n\n    /**\n     * Create originating dialog path\n     */\n    public void createOriginatingDialogPath() {\n        // Set Call-Id\n        String callId = getImsService().getImsModule().getSipManager().getSipStack()\n                .generateCallId();\n\n        // Set the route path\n        Vector<String> route = getImsService().getImsModule().getSipManager().getSipStack()\n                .getServiceRoutePath();\n\n        // @FIXME: This method should take mRemoteId param as an URI instead of String\n        // Create a dialog path\n        mDialogPath = new SipDialogPath(getImsService().getImsModule().getSipManager()\n                .getSipStack(), callId, 1, mRemoteId.toString(), ImsModule.getImsUserProfile()\n                .getPublicAddress(), mRemoteId.toString(), route, mRcsSettings);\n\n        // Set the authentication agent in the dialog path\n        mDialogPath.setAuthenticationAgent(getAuthenticationAgent());\n\n        if (mContact != null) {\n            mRemoteDisplayName = mContactManager.getContactDisplayName(mContact);\n        }\n    }\n\n    /**\n     * Create terminating dialog path\n     * \n     * @param invite Incoming invite\n     */\n    public void createTerminatingDialogPath(SipRequest invite) {\n        String callId = invite.getCallId();\n        String target = invite.getContactURI();\n        String localParty = invite.getTo();\n        String remoteParty = invite.getFrom();\n        long cseq = invite.getCSeq();\n        Vector<String> route = SipUtils.routeProcessing(invite, false);\n\n        mDialogPath = new SipDialogPath(getImsService().getImsModule().getSipManager()\n                .getSipStack(), callId, cseq, target, localParty, remoteParty, route, mRcsSettings);\n        mDialogPath.setInvite(invite);\n        mDialogPath.setRemoteTag(invite.getFromTag());\n        mDialogPath.setRemoteContent(invite.getContent());\n        mDialogPath.setSessionExpireTime(invite.getSessionTimerExpire());\n        mRemoteDisplayName = SipUtils.getDisplayNameFromInvite(invite);\n    }\n\n    /**\n     * Add a listener for receiving events\n     * \n     * @param listener Listener\n     */\n    public void addListener(ImsSessionListener listener) {\n        mListeners.add(listener);\n    }\n\n    /**\n     * Remove a listener\n     * \n     * @param listener Listener to remove\n     */\n    public void removeListener(ImsSessionListener listener) {\n        mListeners.remove(listener);\n    }\n\n    /**\n     * Remove all listeners\n     */\n    public void removeListeners() {\n        mListeners.clear();\n    }\n\n    /**\n     * Returns the event listeners\n     * \n     * @return Listeners\n     */\n    public List<ImsSessionListener> getListeners() {\n        return mListeners;\n    }\n\n    /**\n     * Get the session timer manager\n     * \n     * @return Session timer manager\n     */\n    public SessionTimerManager getSessionTimerManager() {\n        return mSessionTimer;\n    }\n\n    /**\n     * Get the update session manager\n     * \n     * @return UpdateSessionManager\n     */\n    public UpdateSessionManager getUpdateSessionManager() {\n        return mUpdateMgr;\n    }\n\n    /**\n     * Is behind a NAT\n     * \n     * @return Boolean\n     */\n    public boolean isBehindNat() {\n        return getImsService().getImsModule().getCurrentNetworkInterface().isBehindNat();\n    }\n\n    /**\n     * Start the session in background\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public abstract void startSession() throws PayloadException, NetworkException;\n\n    /**\n     * Removes the session\n     */\n    public abstract void removeSession();\n\n    /**\n     * Return the IMS service\n     * \n     * @return IMS service\n     */\n    public ImsService getImsService() {\n        return mImsService;\n    }\n\n    /**\n     * Returns the timestamp of the session\n     * \n     * @return timestamp\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Return the session ID\n     * \n     * @return Session ID\n     */\n    public String getSessionID() {\n        return mSessionId;\n    }\n\n    /**\n     * Set the session ID\n     * \n     * @param sessionId <p>\n     *            <b>Be Careful:</b><br />\n     *            Should only be called to resume session (like for FT HTTP).\n     *            </p>\n     */\n    public void setSessionID(String sessionId) {\n        mSessionId = sessionId;\n    }\n\n    /**\n     * Returns the remote contactId\n     * \n     * @return ContactId\n     */\n    public ContactId getRemoteContact() {\n        return mContact;\n    }\n\n    /**\n     * Returns display name of the remote contact\n     * \n     * @return String\n     */\n    public String getRemoteDisplayName() {\n        return mRemoteDisplayName;\n    }\n\n    /**\n     * Set display name of the remote contact\n     * \n     * @param remoteDisplayName The remote display name\n     */\n    public void setRemoteDisplayName(String remoteDisplayName) {\n        mRemoteDisplayName = remoteDisplayName;\n    }\n\n    /**\n     * Get the dialog path of the session\n     * \n     * @return Dialog path object\n     */\n    public SipDialogPath getDialogPath() {\n        return mDialogPath;\n    }\n\n    /**\n     * Returns the authentication agent\n     * \n     * @return Authentication agent\n     */\n    public SessionAuthenticationAgent getAuthenticationAgent() {\n        return mAuthenticationAgent;\n    }\n\n    /**\n     * Reject the session invitation\n     * \n     * @param status InvitationStatus\n     */\n    public void rejectSession(InvitationStatus status) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session invitation has been rejected\");\n        }\n        mInvitationStatus = status;\n\n        synchronized (mWaitUserAnswer) {\n            mWaitUserAnswer.notifyAll();\n        }\n    }\n\n    /**\n     * Accept the session invitation\n     */\n    public void acceptSession() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session invitation has been accepted\");\n        }\n        mInvitationStatus = InvitationStatus.INVITATION_ACCEPTED;\n\n        synchronized (mWaitUserAnswer) {\n            mWaitUserAnswer.notifyAll();\n        }\n    }\n\n    /**\n     * Wait session invitation answer\n     * \n     * @param timeout value\n     * @return Answer\n     */\n    public InvitationStatus waitInvitationAnswer(long timeout) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Wait session invitation answer delay=\".concat(Long.toString(timeout)));\n        }\n        /* Wait until received response or received timeout */\n        try {\n            long timeToWait = (timeout > 0) ? timeout : mRingingPeriod;\n            long startTime = System.currentTimeMillis();\n            while (InvitationStatus.INVITATION_NOT_ANSWERED == mInvitationStatus) {\n                synchronized (mWaitUserAnswer) {\n                    mWaitUserAnswer.wait(timeToWait);\n                    long waitedTime = System.currentTimeMillis() - startTime;\n                    if (waitedTime < timeToWait) {\n                        timeToWait -= waitedTime;\n                    } else if (InvitationStatus.INVITATION_NOT_ANSWERED == mInvitationStatus) {\n                        mInvitationStatus = InvitationStatus.INVITATION_TIMEOUT;\n                    }\n                }\n            }\n            return mInvitationStatus;\n\n        } catch (InterruptedException e) {\n            mSessionInterrupted = true;\n            if (InvitationStatus.INVITATION_DELETED == mInvitationStatus) {\n                return InvitationStatus.INVITATION_DELETED;\n            }\n            return InvitationStatus.INVITATION_REJECTED_BY_SYSTEM;\n        }\n    }\n\n    /**\n     * Wait session invitation answer\n     * \n     * @return Answer\n     */\n    public InvitationStatus waitInvitationAnswer() {\n        return waitInvitationAnswer(mRingingPeriod);\n    }\n\n    /**\n     * Interrupt session\n     */\n    public void interruptSession() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Interrupt the session\");\n        }\n        synchronized (mWaitUserAnswer) {\n            mWaitUserAnswer.notifyAll();\n        }\n\n        if (!isSessionInterrupted()) {\n            mSessionInterrupted = true;\n            interrupt();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Session has been interrupted\");\n            }\n        }\n    }\n\n    /**\n     * This function is used when session needs to terminated in both invitation pending and started\n     * state. If an error has occurred and the session needs to closed, please call\n     * closeSession(TerminationReason).\n     * \n     * @param reason Termination reason\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void terminateSession(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the session \".concat(reason.toString()));\n        }\n        boolean wasEstablished;\n        if (isInitiatedByRemote()) {\n            wasEstablished = mDialogPath != null && isSessionAccepted();\n        } else {\n            wasEstablished = mDialogPath != null && mDialogPath.isSigEstablished();\n        }\n\n        interruptSession();\n\n        closeSession(reason);\n\n        closeMediaSession();\n\n        removeSession();\n\n        Collection<ImsSessionListener> listeners = getListeners();\n        if (wasEstablished) {\n            for (ImsSessionListener listener : listeners) {\n                listener.onSessionAborted(mContact, reason);\n            }\n            return;\n        }\n        for (ImsSessionListener listener : listeners) {\n            listener.onSessionRejected(mContact, reason);\n        }\n    }\n\n    /**\n     * Force terminate and remove the session\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void deleteSession() throws PayloadException, NetworkException {\n        mInvitationStatus = InvitationStatus.INVITATION_DELETED;\n        interruptSession();\n        closeSession(TerminationReason.TERMINATION_BY_USER);\n        closeMediaSession();\n        removeSession();\n    }\n\n    /**\n     * This function is called when an error has occurred in the session and the session needs to be\n     * closed. If you need to actively terminate the session, please call\n     * terminateSession(TerminationReason).\n     * \n     * @param reason Reason\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void closeSession(TerminationReason reason) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Close the session (reason \" + reason + \")\");\n        }\n        if ((mDialogPath == null) || mDialogPath.isSessionTerminated()) {\n            return;\n        }\n        mSessionTimer.stop();\n        if (TerminationReason.TERMINATION_BY_USER == reason) {\n            mDialogPath.setSessionTerminated(Response.OK, \"Call completed\");\n        } else {\n            mDialogPath.setSessionTerminated();\n        }\n        /* Unblock semaphore (used for terminating side only) */\n        synchronized (mWaitUserAnswer) {\n            mWaitUserAnswer.notifyAll();\n        }\n        if (TerminationReason.TERMINATION_BY_CONNECTION_LOST == reason) {\n            /*\n             * Since connection is lost , we should not even try to send a BYE or CANCEL as we will\n             * anyway fail , Hence return from this point.\n             */\n            return;\n        }\n        /* Close the session */\n        if (mDialogPath.isSigEstablished()) {\n            getDialogPath().incrementCseq();\n\n            // @FIXME:Inject SipManager instead\n            /* Send BYE without waiting a response */\n            getImsService().getImsModule().getSipManager().sendSipBye(getDialogPath());\n        } else {\n            /* Send CANCEL without waiting a response */\n            getImsService().getImsModule().getSipManager().sendSipCancel(getDialogPath());\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"SIP session has been closed\");\n        }\n    }\n\n    /**\n     * Receive BYE request\n     * \n     * @param bye BYE request\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Receive a BYE message from the remote\");\n        }\n        closeMediaSession();\n\n        getDialogPath().setSessionTerminated();\n\n        mSessionTerminatedByRemote = true;\n\n        removeSession();\n\n        mSessionTimer.stop();\n    }\n\n    /**\n     * Receive CANCEL request\n     * \n     * @param cancel CANCEL request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Receive a CANCEL message from the remote\");\n        }\n        if (getDialogPath().isSigEstablished()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Ignore the received CANCEL message from the remote (session already established)\");\n            }\n            return;\n        }\n        closeMediaSession();\n        getDialogPath().setSessionCancelled();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send 487 Request terminated\");\n        }\n        getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(getDialogPath().getInvite(),\n                                getDialogPath().getLocalTag(), Response.REQUEST_TERMINATED));\n        removeSession();\n        mInvitationStatus = InvitationStatus.INVITATION_CANCELED;\n        synchronized (mWaitUserAnswer) {\n            mWaitUserAnswer.notifyAll();\n        }\n    }\n\n    /**\n     * Receive re-INVITE request\n     * \n     * @param reInvite re-INVITE request\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void receiveReInvite(SipRequest reInvite) throws PayloadException, NetworkException {\n        // Session refresh management\n        mSessionTimer.receiveReInvite(reInvite);\n    }\n\n    /**\n     * Receive UPDATE request\n     * \n     * @param update UPDATE request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveUpdate(SipRequest update) throws NetworkException, PayloadException {\n        mSessionTimer.receiveUpdate(update);\n    }\n\n    /**\n     * Set session accepted\n     */\n    public void setSessionAccepted() {\n        mSessionAccepted = true;\n    }\n\n    /**\n     * Prepare media session\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public abstract void prepareMediaSession() throws PayloadException, NetworkException;\n\n    /**\n     * Open media session\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public abstract void openMediaSession() throws PayloadException, NetworkException;\n\n    /**\n     * Start media transfer\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws FileAccessException\n     */\n    public abstract void startMediaTransfer() throws PayloadException, NetworkException,\n            FileAccessException;\n\n    /**\n     * Close media session\n     */\n    public abstract void closeMediaSession();\n\n    /**\n     * Send a 180 Ringing response to the remote party\n     * \n     * @param request SIP request\n     * @param localTag Local tag\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void send180Ringing(SipRequest request, String localTag) throws NetworkException,\n            PayloadException {\n        getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(request, localTag, Response.RINGING));\n    }\n\n    /**\n     * Send an error response to the remote party\n     * \n     * @param request SIP request\n     * @param localTag Local tag\n     * @param status InvitationStatus\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendErrorResponse(SipRequest request, String localTag, InvitationStatus status)\n            throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send \" + status + \" error response\");\n        }\n        SipResponse resp;\n        switch (status) {\n            case INVITATION_REJECTED_BUSY_HERE:\n                resp = SipMessageFactory.createResponse(request, localTag, Response.BUSY_HERE);\n                break;\n            case INVITATION_REJECTED_DECLINE:\n                resp = SipMessageFactory.createResponse(request, localTag, Response.DECLINE);\n                break;\n            case INVITATION_REJECTED_FORBIDDEN:\n                resp = SipMessageFactory.createResponse(request, localTag, Response.FORBIDDEN);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown InvitationStatus \" + status);\n        }\n        getImsService().getImsModule().getSipManager().sendSipResponse(resp);\n    }\n\n    /**\n     * Send a 603 \"Decline\" to the remote party\n     * \n     * @param request SIP request\n     * @param localTag Local tag\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void send603Decline(SipRequest request, String localTag) throws NetworkException,\n            PayloadException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send 603 Decline\");\n        }\n        getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(request, localTag, Response.DECLINE));\n    }\n\n    /**\n     * Send a 486 \"Busy\" to the remote party\n     * \n     * @param request SIP request\n     * @param localTag Local tag\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void send486Busy(SipRequest request, String localTag) throws NetworkException,\n            PayloadException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send 486 Busy\");\n        }\n        getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(request, localTag, Response.BUSY_HERE));\n    }\n\n    /**\n     * Send a 415 \"Unsupported Media Type\" to the remote party\n     * \n     * @param request SIP request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void send415Error(SipRequest request) throws NetworkException, PayloadException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send 415 Unsupported Media Type\");\n        }\n        // TODO: set Accept-Encoding header\n        getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.createResponse(request, Response.UNSUPPORTED_MEDIA_TYPE));\n    }\n\n    /**\n     * Create SDP setup offer (see RFC6135, RFC4145)\n     * \n     * @return Setup offer\n     */\n    public String createSetupOffer() {\n        if (isBehindNat()) {\n            /* Active mode by default if there is a NAT */\n            return \"active\";\n        }\n        /*\n         * Active/passive mode is exchanged in order to be compatible with UE not supporting\n         * COMEDIA.\n         */\n        return \"actpass\";\n    }\n\n    /**\n     * Create SDP setup offer for mobile to mobile (see RFC6135, RFC4145)\n     * \n     * @return Setup offer\n     */\n    public String createMobileToMobileSetupOffer() {\n        // Always active mode proposed here\n        return \"active\";\n    }\n\n    /**\n     * Create SDP setup answer (see RFC6135, RFC4145)\n     * \n     * @param offer setup offer\n     * @return Setup answer (\"active\" or \"passive\")\n     */\n    public String createSetupAnswer(String offer) {\n        switch (offer) {\n            case \"actpass\":\n                // Active mode by default if there is a NAT or AS IM\n                return \"active\";\n            case \"active\":\n                // Passive mode\n                return \"passive\";\n            case \"passive\":\n                // Active mode\n                return \"active\";\n            default:\n                // Passive mode by default\n                return \"passive\";\n        }\n    }\n\n    /**\n     * Returns the response timeout (in milliseconds)\n     * \n     * @return Timeout\n     */\n    public long getResponseTimeout() {\n        return mRingingPeriod + SipManager.getTimeout();\n    }\n\n    /**\n     * Is session interrupted\n     * \n     * @return Boolean\n     */\n    public boolean isSessionInterrupted() {\n        return mSessionInterrupted || isInterrupted()\n                || (getDialogPath() != null && getDialogPath().isSessionTerminated());\n    }\n\n    /**\n     * Is session terminated by remote\n     * \n     * @return Boolean\n     */\n    public boolean isSessionTerminatedByRemote() {\n        return mSessionTerminatedByRemote;\n    }\n\n    /**\n     * Is session accepted\n     * \n     * @return Boolean\n     */\n    public boolean isSessionAccepted() {\n        return mSessionAccepted;\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return the INVITE request\n     * @throws PayloadException\n     */\n    public abstract SipRequest createInvite() throws PayloadException;\n\n    /**\n     * Send INVITE message\n     * \n     * @param invite SIP INVITE\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws FileAccessException\n     */\n    public void sendInvite(SipRequest invite) throws PayloadException, NetworkException,\n            FileAccessException {\n        // Send INVITE request\n        SipTransactionContext ctx = getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipMessageAndWait(invite, getResponseTimeout(),\n                        new SipTransactionContext.INotifySipProvisionalResponse() {\n                            public void handle180Ringing(SipResponse response) {\n                                ImsServiceSession.this.handle180Ringing(response);\n                            }\n\n                        });\n\n        // Analyze the received response\n        if (ctx.isSipResponse()) {\n            // A response has been received\n            switch (ctx.getStatusCode()) {\n                case Response.OK:\n                    // 200 OK\n                    handle200OK(ctx.getSipResponse());\n                    break;\n                case Response.NOT_FOUND:\n                    // 404 session not found\n                    handle404SessionNotFound(ctx.getSipResponse());\n                    break;\n                case Response.PROXY_AUTHENTICATION_REQUIRED:\n                    // 407 Proxy Authentication Required\n                    handle407Authentication(ctx.getSipResponse());\n                    break;\n                case SESSION_INTERVAL_TOO_SMALL:\n                    // 422 Session Interval Too Small\n                    handle422SessionTooSmall(ctx.getSipResponse());\n                    break;\n                case Response.TEMPORARILY_UNAVAILABLE:\n                    // 480 Temporarily Unavailable\n                    handle480Unavailable(ctx.getSipResponse());\n                    break;\n                case Response.BUSY_HERE:\n                    // 486 busy\n                    handle486Busy(ctx.getSipResponse());\n                    break;\n                case Response.REQUEST_TERMINATED:\n                    // 487 Invitation cancelled\n                    handle487Cancel(ctx.getSipResponse());\n                    break;\n                case Response.DECLINE:\n                    // 603 Invitation declined\n                    handle603Declined(ctx.getSipResponse());\n                    break;\n                case Response.FORBIDDEN:\n                    // 403 Forbidden\n                    handle403Forbidden(ctx.getSipResponse());\n                    break;\n                default:\n                    // Other error response\n                    handleDefaultError(ctx.getSipResponse());\n                    break;\n            }\n        } else {\n            // No response received: timeout\n            handleError(new ImsSessionBasedServiceError(\n                    ImsSessionBasedServiceError.SESSION_INITIATION_FAILED, \"timeout\"));\n        }\n    }\n\n    /**\n     * Perform next steps once 200 0K response is received\n     * \n     * @param resp 200 OK response\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws FileAccessException\n     */\n    public void handle200OK(SipResponse resp) throws PayloadException, NetworkException,\n            FileAccessException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n        getDialogPath().setSigEstablished();\n\n        getDialogPath().setRemoteTag(resp.getToTag());\n\n        getDialogPath().setTarget(resp.getContactURI());\n\n        /* Set the route path with the Record-Route header */\n        Vector<String> newRoute = SipUtils.routeProcessing(resp, true);\n        getDialogPath().setRoute(newRoute);\n\n        /* Set the remote SDP part */\n        getDialogPath().setRemoteContent(resp.getContent());\n\n        /* Set the remote SIP instance ID */\n        ContactHeader remoteContactHeader = (ContactHeader) resp.getHeader(ContactHeader.NAME);\n        if (remoteContactHeader != null) {\n            getDialogPath().setRemoteSipInstance(\n                    remoteContactHeader.getParameter(SipUtils.SIP_INSTANCE_PARAM));\n        }\n\n        prepareMediaSession();\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send ACK\");\n        }\n        getImsService().getImsModule().getSipManager().sendSipAck(getDialogPath());\n\n        getDialogPath().setSessionEstablished();\n\n        openMediaSession();\n\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionStarted(mContact);\n        }\n\n        /* Start session timer */\n        if (mSessionTimer.isSessionTimerActivated(resp)) {\n            mSessionTimer.start(resp.getSessionTimerRefresher(), resp.getSessionTimerExpire());\n        }\n        startMediaTransfer();\n    }\n\n    /**\n     * Session inactivity event\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public abstract void handleInactivityEvent() throws PayloadException, NetworkException;\n\n    /**\n     * Handle default error\n     * \n     * @param resp Error response\n     */\n    public void handleDefaultError(SipResponse resp) {\n        // Default handle\n        handleError(new ImsSessionBasedServiceError(\n                ImsSessionBasedServiceError.SESSION_INITIATION_FAILED, resp.getStatusCode() + \" \"\n                        + resp.getReasonPhrase()));\n    }\n\n    /**\n     * Handle 403 Forbidden\n     * \n     * @param resp 403 response\n     */\n    public void handle403Forbidden(SipResponse resp) {\n        handleDefaultError(resp);\n    }\n\n    /**\n     * Handle 404 Session Not Found\n     * \n     * @param resp 404 response\n     */\n    public void handle404SessionNotFound(SipResponse resp) {\n        handleDefaultError(resp);\n    }\n\n    /**\n     * Handle 407 Proxy Authentication Required\n     * \n     * @param resp 407 response\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws FileAccessException\n     */\n    public void handle407Authentication(SipResponse resp) throws PayloadException,\n            NetworkException, FileAccessException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"407 response received\");\n            }\n            // Set the remote tag\n            getDialogPath().setRemoteTag(resp.getToTag());\n\n            // Update the authentication agent\n            getAuthenticationAgent().readProxyAuthenticateHeader(resp);\n\n            // Increment the Cseq number of the dialog path\n            getDialogPath().incrementCseq();\n\n            // Create the invite request\n            SipRequest invite = createInvite();\n\n            // Reset initial request in the dialog path\n            getDialogPath().setInvite(invite);\n\n            // Set the Proxy-Authorization header\n            getAuthenticationAgent().setProxyAuthorizationHeader(invite);\n\n            // Send INVITE request\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n        }\n\n    }\n\n    /**\n     * Handle 422 response\n     * \n     * @param resp 422 response\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws FileAccessException\n     */\n    public void handle422SessionTooSmall(SipResponse resp) throws PayloadException,\n            NetworkException, FileAccessException {\n        try {\n            // 422 response received\n            if (sLogger.isActivated()) {\n                sLogger.info(\"422 response received\");\n            }\n            // Extract the Min-SE value\n            long minExpire = SipUtils.getMinSessionExpirePeriod(resp);\n            if (minExpire == -1) {\n                if (sLogger.isActivated()) {\n                    sLogger.error(\"Can't read the Min-SE value\");\n                }\n                handleError(new ImsSessionBasedServiceError(\n                        ImsSessionBasedServiceError.UNEXPECTED_EXCEPTION, \"No Min-SE value found\"));\n                return;\n            }\n            // Set the min expire value\n            SipDialogPath sipDialogPath = getDialogPath();\n            sipDialogPath.setMinSessionExpireTime(minExpire);\n\n            // Set the expire value\n            sipDialogPath.setSessionExpireTime(minExpire);\n\n            // Increment the Cseq number of the dialog path\n            sipDialogPath.incrementCseq();\n\n            // Create a new INVITE with the right expire period\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send new INVITE\");\n            }\n            SipRequest invite = createInvite();\n\n            // Set the Authorization header\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n\n            // Reset initial request in the dialog path\n            sipDialogPath.setInvite(invite);\n\n            // Send INVITE request\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"Unable to handle session too small response!\", e);\n        }\n    }\n\n    /**\n     * Handle 480 Temporarily Unavailable\n     * \n     * @param resp 480 response\n     */\n    public void handle480Unavailable(SipResponse resp) {\n        handleDefaultError(resp);\n    }\n\n    /**\n     * Handle 486 Busy\n     * \n     * @param resp 486 response\n     */\n    public void handle486Busy(SipResponse resp) {\n        handleDefaultError(resp);\n    }\n\n    /**\n     * Handle 487 Cancel\n     * \n     * @param resp 487 response\n     */\n    public void handle487Cancel(SipResponse resp) {\n        handleError(new ImsSessionBasedServiceError(\n                ImsSessionBasedServiceError.SESSION_INITIATION_CANCELLED, resp.getStatusCode()\n                        + \" \" + resp.getReasonPhrase()));\n    }\n\n    /**\n     * Handle 603 Decline\n     * \n     * @param resp 603 response\n     */\n    public void handle603Declined(SipResponse resp) {\n        handleError(new ImsSessionBasedServiceError(\n                ImsSessionBasedServiceError.SESSION_INITIATION_DECLINED, resp.getStatusCode() + \" \"\n                        + resp.getReasonPhrase()));\n    }\n\n    /**\n     * Handle Error\n     * \n     * @param error ImsServiceError\n     */\n    public abstract void handleError(ImsServiceError error);\n\n    /**\n     * Handle ReInvite Sip Response\n     * \n     * @param response Sip response to reInvite\n     * @param code InvitationStatus\n     * @param requestType the request type\n     */\n    public void handleReInviteResponse(InvitationStatus code, SipResponse response, int requestType) {\n    }\n\n    /**\n     * Handle User Answer in Response to Session Update notification\n     * \n     * @param code InvitationStatus\n     * @param requestType reInvite SIP request\n     */\n    public void handleReInviteUserAnswer(InvitationStatus code, int requestType) {\n    }\n\n    /**\n     * Handle ACK sent in Response to 200Ok ReInvite\n     * \n     * @param code InvitationStatus\n     * @param requestType reInvite SIP request\n     */\n    public void handleReInviteAck(InvitationStatus code, int requestType) {\n    }\n\n    /**\n     * Handle 407 Proxy Authent error ReInvite Response\n     * \n     * @param response reInvite SIP response\n     * @param serviceContext context of reInvite\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void handleReInvite407ProxyAuthent(SipResponse response, int serviceContext)\n            throws PayloadException, NetworkException {\n    }\n\n    /**\n     * @param ReInvite the re-invite request\n     * @param serviceContext the service context\n     * @return SDP built\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public String buildReInviteSdpResponse(SipRequest ReInvite, int serviceContext)\n            throws PayloadException, NetworkException {\n        return null;\n    }\n\n    /**\n     * Verify if session is initiated by remote part\n     * \n     * @return true if session is initiated by remote part\n     */\n    abstract public boolean isInitiatedByRemote();\n\n    /**\n     * Handle 180 Ringing\n     * \n     * @param response the response\n     */\n    public void handle180Ringing(SipResponse response) {\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ImsSessionBasedServiceError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\n/**\n * IMS session based service error\n * \n * @author jexa7410\n */\npublic class ImsSessionBasedServiceError extends ImsServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Error code base for chat service\n     */\n    protected static final int CHAT_ERROR_CODES = SESSION_ERROR_CODES + 10;\n\n    /**\n     * Error code base for file transfer service\n     */\n    protected static final int FT_ERROR_CODES = SESSION_ERROR_CODES + 20;\n\n    /**\n     * Error code base for rich call service\n     */\n    protected static final int RICHCALL_ERROR_CODES = SESSION_ERROR_CODES + 30;\n\n    /**\n     * Error code base for SIP generic service\n     */\n    protected static final int SIP_ERROR_CODES = SESSION_ERROR_CODES + 40;\n\n    /**\n     * Error code base for IP call service\n     */\n    protected static final int IPCALL_ERROR_CODES = SESSION_ERROR_CODES + 50;\n\n    /**\n     * Session initiation has failed (e.g. 408 timeout)\n     */\n    public final static int SESSION_INITIATION_FAILED = SESSION_ERROR_CODES + 1;\n\n    /**\n     * Session initiation has been declined (e.g. 603 Decline or 486 Busy)\n     */\n    public final static int SESSION_INITIATION_DECLINED = SESSION_ERROR_CODES + 2;\n\n    /**\n     * Session initiation has been cancelled (e.g. 487 Session terminated)\n     */\n    public final static int SESSION_INITIATION_CANCELLED = SESSION_ERROR_CODES + 3;\n\n    /**\n     * Sending response to an accepted chat session failed (e.g. Failed sending empty packet or\n     * 200OK/ACK responses)\n     */\n    public final static int SEND_RESPONSE_FAILED = SESSION_ERROR_CODES + 4;\n\n    /**\n     * Constructor\n     * \n     * @param error Error\n     */\n    public ImsSessionBasedServiceError(ImsServiceError error) {\n        super(error.getErrorCode(), error);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public ImsSessionBasedServiceError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public ImsSessionBasedServiceError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ImsSessionBasedServiceError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/ImsSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Listener of events sent during an IMS session\n * \n * @author JM. Auffret\n */\npublic interface ImsSessionListener {\n    /**\n     * Session is started\n     * \n     * @param contact Remote contact\n     */\n    public void onSessionStarted(ContactId contact);\n\n    /**\n     * Session has been aborted\n     * \n     * @param contact Remote contact\n     * @param reason Termination reason\n     */\n    public void onSessionAborted(ContactId contact, TerminationReason reason);\n\n    /**\n     * Session is being rejected by user\n     * \n     * @param contact Remote contact\n     * @param reason Termination reason\n     */\n    public void onSessionRejected(ContactId contact, TerminationReason reason);\n\n    /**\n     * Accept has been called and the session is in the process of being started\n     * \n     * @param contact Remote contact\n     */\n    public void onSessionAccepting(ContactId contact);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/SessionActivityManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Session activity manager which manages the idle state of the session. It maintains a timer that\n * is canceled and restarted when the session has activity, i.e. when MSRP chunks are received or\n * emitted. If the timer expires, the session is aborted.\n */\npublic class SessionActivityManager extends PeriodicRefresher {\n    /**\n     * Last activity timestamp\n     */\n    private long mActivityTimestamp = 0L;\n\n    /**\n     * ImsServiceSession\n     */\n    private final ImsServiceSession mSession;\n\n    /**\n     * Timeout\n     */\n    private final long mTimeout;\n\n    private static final Logger sLogger = Logger.getLogger(SessionActivityManager.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param session IM session\n     * @param timeout Idle timeout\n     */\n    public SessionActivityManager(ImsServiceSession session, long timeout) {\n        mSession = session;\n        mTimeout = timeout;\n    }\n\n    /**\n     * Update the session activity\n     */\n    public void updateActivity() {\n        mActivityTimestamp = System.currentTimeMillis();\n    }\n\n    /**\n     * Start manager\n     */\n    public void start() {\n        if (mTimeout == 0) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Activity manager is disabled (no idle timeout)\");\n            }\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Start the activity manager for \" + mTimeout + \"ms\");\n        }\n        // Reset the inactivity timestamp\n        updateActivity();\n\n        // Start a timer to check if the inactivity period has been reach or not each 10seconds\n        startTimer(System.currentTimeMillis(), mTimeout);\n    }\n\n    /**\n     * Stop manager\n     */\n    public void stop() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Stop the activity manager\");\n        }\n        stopTimer();\n    }\n\n    /**\n     * Periodic processing\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void periodicProcessing() throws PayloadException, NetworkException {\n        long timeout = mTimeout;\n        long inactivityPeriod = System.currentTimeMillis() - mActivityTimestamp;\n        long remainingPeriod = timeout - inactivityPeriod;\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Check inactivity period: inactivity=\" + inactivityPeriod\n                    + \", remaining=\" + remainingPeriod);\n        }\n        if (inactivityPeriod >= timeout) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"No activity on the session during \" + timeout\n                        + \"ms: abort the session\");\n            }\n            mSession.handleInactivityEvent();\n        } else {\n            startTimer(System.currentTimeMillis(), remainingPeriod);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/SessionAuthenticationAgent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.registration.HttpDigestRegistrationProcedure;\nimport com.gsma.rcs.core.ims.network.registration.RegistrationProcedure;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.security.HttpDigestMd5Authentication;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ProxyAuthenticateHeader;\nimport javax2.sip.header.ProxyAuthorizationHeader;\n\n/**\n * HTTP Digest MD5 authentication agent for sessions\n * \n * @author JM. Auffret\n */\npublic class SessionAuthenticationAgent {\n\n    /**\n     * HTTP Digest MD5 agent for session\n     */\n    private HttpDigestMd5Authentication mDigest = new HttpDigestMd5Authentication();\n\n    /**\n     * HTTP Digest MD5 agent for register (nonce caching procedure)\n     */\n    private HttpDigestMd5Authentication mRegisterDigest;\n\n    /**\n     * Constructor\n     * \n     * @param imsModule IMS module\n     */\n    public SessionAuthenticationAgent(ImsModule imsModule) {\n        /* Re-use the registration authentication (nonce caching) */\n        RegistrationProcedure procedure = imsModule.getCurrentNetworkInterface()\n                .getRegistrationManager().getRegistrationProcedure();\n        if (procedure instanceof HttpDigestRegistrationProcedure) {\n            mRegisterDigest = ((HttpDigestRegistrationProcedure) procedure).getHttpDigest();\n        }\n    }\n\n    /**\n     * Set the proxy authorization header on the INVITE request\n     * \n     * @param request SIP request\n     * @throws InvalidArgumentException\n     * @throws ParseException\n     */\n    public void setProxyAuthorizationHeader(SipRequest request) throws InvalidArgumentException,\n            ParseException {\n        String realm = mDigest.getRealm();\n        if (realm == null || mDigest.getNextnonce() == null) {\n            return;\n        }\n        mDigest.updateNonceParameters();\n        UserProfile profile = ImsModule.getImsUserProfile();\n        String user = profile.getPrivateID();\n        String password = profile.getPassword();\n        String requestUri = request.getRequestURI();\n        String nonceCounter = mDigest.buildNonceCounter();\n        String response = mDigest.calculateResponse(user, password, request.getMethod(),\n                requestUri, nonceCounter, request.getContent());\n\n        /* Build the Proxy-Authorization header */\n        StringBuilder auth = new StringBuilder(\"Digest username=\\\"\").append(user)\n                .append(\"\\\",uri=\\\"\").append(requestUri).append(\"\\\",algorithm=MD5,realm=\\\"\")\n                .append(realm).append(\"\\\",nc=\").append(nonceCounter).append(\",nonce=\\\"\")\n                .append(mDigest.getNonce()).append(\"\\\",response=\\\"\").append(response)\n                .append(\"\\\",cnonce=\\\"\").append(mDigest.getCnonce()).append(\"\\\"\");\n\n        String qop = mDigest.getQop();\n        if (qop != null) {\n            auth.append(\",qop=\").append(qop);\n        }\n        request.addHeader(ProxyAuthorizationHeader.NAME, auth.toString());\n    }\n\n    /**\n     * Read parameters of the Proxy-Authenticate header\n     * \n     * @param response SIP response\n     */\n    public void readProxyAuthenticateHeader(SipResponse response) {\n        ProxyAuthenticateHeader header = (ProxyAuthenticateHeader) response\n                .getHeader(ProxyAuthenticateHeader.NAME);\n        if (header != null) {\n            mDigest.setRealm(header.getRealm());\n            mDigest.setQop(header.getQop());\n            mDigest.setNextnonce(header.getNonce());\n        }\n    }\n\n    /**\n     * Set the authorization header on the INVITE request\n     * \n     * @param request SIP request\n     * @throws InvalidArgumentException\n     * @throws ParseException\n     */\n    public void setAuthorizationHeader(SipRequest request) throws InvalidArgumentException,\n            ParseException {\n        String nextNonce = mRegisterDigest.getNextnonce();\n        /* Re-use the registration authentication (nonce caching) */\n        if (mRegisterDigest == null || nextNonce == null) {\n            return;\n        }\n        mRegisterDigest.updateNonceParameters();\n\n        /* Calculate response */\n        UserProfile profile = ImsModule.getImsUserProfile();\n        String user = profile.getPrivateID();\n        String password = profile.getPassword();\n        String requestUri = request.getRequestURI();\n        String nonCounter = mRegisterDigest.buildNonceCounter();\n        String response = mRegisterDigest.calculateResponse(user, password, request.getMethod(),\n                requestUri, nonCounter, request.getContent());\n\n        /* Build the Authorization header */\n        StringBuilder auth = new StringBuilder(\"Digest username=\\\"\").append(user)\n                .append(\"\\\",uri=\\\"\").append(requestUri).append(\"\\\",algorithm=MD5,realm=\\\"\")\n                .append(mRegisterDigest.getRealm()).append(\"\\\",nc=\").append(nonCounter)\n                .append(\",nonce=\\\"\").append(nextNonce).append(\"\\\",response=\\\"\").append(response)\n                .append(\"\\\",cnonce=\\\"\").append(mRegisterDigest.getCnonce()).append(\"\\\"\");\n        String qop = mRegisterDigest.getQop();\n        if (qop != null) {\n            auth.append(\",qop=\").append(qop);\n        }\n\n        /* Set header in the SIP message */\n        request.addHeader(ProxyAuthorizationHeader.NAME, auth.toString());\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/SessionIdGenerator.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\n/**\n * Session ID generator\n * \n * @author jexa7410\n */\npublic class SessionIdGenerator {\n    /**\n     * Counter\n     */\n    private static long current = System.currentTimeMillis();\n\n    /**\n     * Returns a unique integer ID\n     * \n     * @return ID\n     */\n    public static synchronized String getNewId() {\n        current++;\n        return \"\" + current;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/SessionNotEstablishedException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.service;\n\n/**\n * To be thrown when the session is not yet established.\n * <p>\n * These exceptions should not be logged as there is not much to do for handling such type of\n * exceptions other then re-trying at later point.\n * </p>\n */\npublic class SessionNotEstablishedException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public SessionNotEstablishedException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public SessionNotEstablishedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/SessionTimerManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipMessage;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.Dialog;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * Session timer manager (see RFC 4028)\n * \n * @author jexa7410\n */\npublic class SessionTimerManager extends PeriodicRefresher {\n    /**\n     * Minimum value of expire period in milliseconds\n     */\n    public final static long MIN_EXPIRE_PERIOD = 90000;\n\n    /**\n     * UAC role\n     */\n    public final static String UAC_ROLE = \"uac\";\n\n    /**\n     * UAC role\n     */\n    public final static String UAS_ROLE = \"uas\";\n\n    /**\n     * Session to be refreshed\n     */\n    private ImsServiceSession mSession;\n\n    /**\n     * Expire period\n     */\n    private long mExpirePeriod;\n\n    /**\n     * Refresher\n     */\n    private String mRefresher = \"uas\";\n\n    /**\n     * Last session refresh time\n     */\n    private long mLastSessionRefresh;\n\n    /**\n     * The logger\n     */\n    private final Logger mLogger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param session Session to be refreshed\n     */\n    public SessionTimerManager(ImsServiceSession session) {\n        mSession = session;\n    }\n\n    /**\n     * Is session timer activated\n     * \n     * @param msg SIP message\n     * @return Boolean\n     */\n    public boolean isSessionTimerActivated(SipMessage msg) {\n        // Check the Session-Expires header\n        if (msg.getSessionTimerExpire() < MIN_EXPIRE_PERIOD) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Session timer not activated\");\n            }\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Start the session timer\n     * \n     * @param refresher Refresher role\n     * @param expirePeriod Expire period in milliseconds\n     */\n    public void start(String refresher, long expirePeriod) {\n        if (mLogger.isActivated()) {\n            mLogger.debug(new StringBuilder(\"Start session timer for session \")\n                    .append(mSession.getId()).append(\" (role=\").append(refresher)\n                    .append(\", expire=\").append(expirePeriod).append(\"ms)\").toString());\n        }\n\n        // If the session timer is set to 0 value, it may have not been set, so take the expire\n        // period as value\n        SipDialogPath path = mSession.getDialogPath();\n        if (path.getSessionExpireTime() == 0) {\n            path.setSessionExpireTime(expirePeriod);\n        }\n\n        // Set refresher role\n        mRefresher = refresher;\n\n        // Set expire period\n        mExpirePeriod = expirePeriod;\n\n        // Reset last session refresh time\n        mLastSessionRefresh = System.currentTimeMillis();\n\n        // Start processing the session timer\n        startProcessing();\n    }\n\n    /**\n     * Start processing the session timer\n     */\n    private void startProcessing() {\n        long currentTime = System.currentTimeMillis();\n        if (UAC_ROLE.equals(mRefresher)) {\n            startTimer(currentTime, mExpirePeriod, 0.5);\n        } else {\n            startTimer(currentTime, mExpirePeriod);\n        }\n    }\n\n    /**\n     * Stop the session timer\n     */\n    public void stop() {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Stop session timer for session \" + mSession.getId());\n        }\n        stopTimer();\n    }\n\n    /**\n     * Periodic session timer processing\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void periodicProcessing() throws PayloadException, NetworkException {\n        if (UAC_ROLE.equals(mRefresher)) {\n            // Refresher role\n            sessionRefreshForUAC();\n        } else {\n            // Refreshee role\n            sessionRefreshForUAS();\n        }\n    }\n\n    /**\n     * Session refresh processing for UAC role. If the refresher never sends a session refresh\n     * request then the session should be terminated.\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sessionRefreshForUAC() throws PayloadException, NetworkException {\n        try {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Session timer refresh (UAC role)\");\n            }\n\n            // Increment the Cseq number of the dialog path\n            mSession.getDialogPath().incrementCseq();\n\n            // Create RE-INVITE request\n            SipRequest reInvite = SipMessageFactory.createReInvite(mSession.getDialogPath());\n\n            // Set the Authorization header\n            mSession.getAuthenticationAgent().setAuthorizationHeader(reInvite);\n\n            // Send RE-INVITE request\n            sendReInvite(reInvite);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Unable to process Session timer refresh (UAC role)!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to process Session timer refresh (UAC role)!\", e);\n        }\n    }\n\n    /**\n     * Send RE-INVITE message\n     * \n     * @param reInvite SIP RE-INVITE\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendReInvite(SipRequest reInvite) throws PayloadException, NetworkException {\n        try {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Send RE-INVITE\");\n            }\n            // Send RE-INVITE request\n            SipTransactionContext ctx = mSession.getImsService().getImsModule().getSipManager()\n                    .sendSipMessageAndWait(reInvite, mSession.getResponseTimeout());\n\n            // Analyze the received response\n            if (ctx.isSipResponse()) {\n                // A response has been received\n                switch (ctx.getStatusCode()) {\n                    case Response.OK:\n                        if (mLogger.isActivated()) {\n                            mLogger.debug(\"Session timer refresh with success\");\n                        }\n\n                        mSession.getDialogPath().setSigEstablished();\n                        mLastSessionRefresh = System.currentTimeMillis();\n\n                        if (mLogger.isActivated()) {\n                            mLogger.debug(\"Send ACK\");\n                        }\n                        mSession.getImsService().getImsModule().getSipManager()\n                                .sendSipAck(mSession.getDialogPath());\n\n                        mSession.getDialogPath().setSessionEstablished();\n\n                        /* Increment internal stack CSeq (NIST stack issue?) */\n                        Dialog dlg = mSession.getDialogPath().getStackDialog();\n                        if (dlg != null) {\n                            dlg.incrementLocalSequenceNumber();\n                        }\n\n                        /* Restart processing the session timer */\n                        startProcessing();\n                        break;\n\n                    case Response.METHOD_NOT_ALLOWED:\n                        if (mLogger.isActivated()) {\n                            mLogger.debug(\"Session timer refresh not supported\");\n                        }\n                        break;\n\n                    case Response.PROXY_AUTHENTICATION_REQUIRED:\n                        if (mLogger.isActivated()) {\n                            mLogger.info(\"407 response received. Send second RE-INVITE\");\n                        }\n                        mSession.getDialogPath().incrementCseq();\n                        SipRequest newReInvite = SipMessageFactory.createReInvite(mSession\n                                .getDialogPath());\n\n                        /* Update the authentication agent */\n                        mSession.getAuthenticationAgent().readProxyAuthenticateHeader(\n                                ctx.getSipResponse());\n\n                        mSession.getAuthenticationAgent().setProxyAuthorizationHeader(newReInvite);\n\n                        sendReInvite(newReInvite);\n                        break;\n\n                    default:\n                        if (mLogger.isActivated()) {\n                            mLogger.debug(\"Session timer refresh has failed: close the session\");\n                        }\n\n                        mSession.terminateSession(TerminationReason.TERMINATION_BY_TIMEOUT);\n\n                        ContactId contact = mSession.getRemoteContact();\n                        mSession.getImsService().getImsModule().getCapabilityService()\n                                .requestContactCapabilities(contact);\n                        break;\n                }\n            } else {\n                /* No response received: timeout */\n                throw new PayloadException(\"No response received: timeout!\");\n            }\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Unable to fetch Authorization header!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to fetch Authorization header!\", e);\n        }\n    }\n\n    /**\n     * Session refresh processing for UAS role. If the refresher never gets a response from the\n     * remote then the session should be terminated.\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    private void sessionRefreshForUAS() throws PayloadException, NetworkException {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Session timer refresh (UAS role)\");\n        }\n        if ((System.currentTimeMillis() - mLastSessionRefresh) >= mExpirePeriod) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Session timer refresh has failed: close the session\");\n            }\n            mSession.terminateSession(TerminationReason.TERMINATION_BY_TIMEOUT);\n\n            ContactId contact = mSession.getRemoteContact();\n            mSession.getImsService().getImsModule().getCapabilityService()\n                    .requestContactCapabilities(contact);\n        } else {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Session timer refresh with success\");\n            }\n            startProcessing();\n        }\n    }\n\n    /**\n     * Receive RE-INVITE request\n     * \n     * @param reInvite RE-INVITE request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveReInvite(SipRequest reInvite) throws PayloadException, NetworkException {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Session refresh request received\");\n        }\n        mLastSessionRefresh = System.currentTimeMillis();\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Send 200 OK\");\n        }\n        SipResponse resp = SipMessageFactory.create200OkReInviteResponse(mSession.getDialogPath(),\n                reInvite);\n        mSession.getDialogPath().setSigEstablished();\n        SipTransactionContext ctx = mSession.getImsService().getImsModule().getSipManager()\n                .sendSipMessageAndWait(resp);\n        if (ctx.isSipAck()) {\n            if (mLogger.isActivated()) {\n                mLogger.info(\"ACK request received\");\n            }\n            mSession.getDialogPath().setSessionEstablished();\n        } else {\n            throw new PayloadException(new StringBuilder(\n                    \"No ACK received for INVITE with sessionId: \").append(mSession.getId())\n                    .toString());\n        }\n    }\n\n    /**\n     * Receive UPDATE request\n     * \n     * @param update UPDATE request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveUpdate(SipRequest update) throws NetworkException, PayloadException {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Session refresh request received\");\n        }\n        mLastSessionRefresh = System.currentTimeMillis();\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"Send 200 OK\");\n        }\n        mSession.getImsService()\n                .getImsModule()\n                .getSipManager()\n                .sendSipResponse(\n                        SipMessageFactory.create200OkUpdateResponse(mSession.getDialogPath(),\n                                update));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/SipIntentManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\n\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityUtils;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.extension.InstantMultimediaMessageIntent;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSessionIntent;\nimport com.gsma.services.rcs.extension.MultimediaStreamingSessionIntent;\n\nimport javax2.sip.message.Request;\n\n/**\n * SIP intent manager\n * \n * @author Jean-Marc AUFFRET\n */\npublic class SipIntentManager {\n\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     */\n    public SipIntentManager() {\n    }\n\n    /**\n     * Is the SIP request may be resolved\n     * \n     * @param request Incoming request\n     * @return Resolved intent or null if not resolved\n     */\n    public Intent isSipRequestResolved(SipRequest request) {\n        Set<String> tags = request.getFeatureTags();\n        for (String featureTag : tags) {\n            Intent intent = generateSipIntent(request, featureTag);\n            if (intent == null) {\n                continue;\n            }\n            if (logger.isActivated()) {\n                logger.debug(\"SIP intent: \" + intent.getAction() + \", \" + intent.getType());\n            }\n            if (isSipIntentResolvedByBroadcastReceiver(intent)) {\n                return intent;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Generate a SIP Intent\n     * \n     * @param request SIP request\n     * @param featureTag Feature tag\n     */\n    private Intent generateSipIntent(SipRequest request, String featureTag) {\n        String content = request.getContent();\n        if (content == null) {\n            return null;\n        }\n        content = content.toLowerCase();\n\n        Intent intent = null;\n        String method = request.getMethod();\n        if (Request.INVITE.equals(method)) {\n            if (content.contains(\"msrp\")) {\n                intent = new Intent(MultimediaMessagingSessionIntent.ACTION_NEW_INVITATION);\n            } else if (content.contains(\"rtp\")) {\n                intent = new Intent(MultimediaStreamingSessionIntent.ACTION_NEW_INVITATION);\n            }\n        } else if (Request.MESSAGE.equals(method)) {\n            intent = new Intent(InstantMultimediaMessageIntent.ACTION_NEW_INSTANT_MESSAGE);\n        } else {\n            return null;\n        }\n\n        if (intent != null) {\n            String mime = formatIntentMimeType(featureTag);\n            intent.addCategory(Intent.CATEGORY_DEFAULT);\n            intent.setType(mime.toLowerCase());\n        }\n\n        return intent;\n    }\n\n    /**\n     * Is the SIP intent may be resolved by at least broadcast receiver\n     * \n     * @param intent The Intent to resolve\n     * @return Returns true if the intent has been resolved, else returns false\n     */\n    private boolean isSipIntentResolvedByBroadcastReceiver(Intent intent) {\n        PackageManager packageManager = AndroidFactory.getApplicationContext().getPackageManager();\n        List<ResolveInfo> list = packageManager.queryBroadcastReceivers(intent,\n                PackageManager.MATCH_DEFAULT_ONLY);\n        return (list.size() > 0);\n    }\n\n    /**\n     * Format intent MIME type\n     * \n     * @param featureTag Feature tag\n     * @return Intent MIME type\n     */\n    private String formatIntentMimeType(String featureTag) {\n        String serviceId = CapabilityUtils.extractServiceId(featureTag);\n        return CapabilityService.EXTENSION_MIME_TYPE + \"/\" + serviceId;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/UpdateSessionManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.text.ParseException;\n\nimport javax2.sip.Dialog;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * Update session manager\n * \n * @author owom5460\n */\npublic class UpdateSessionManager {\n\n    /**\n     * Session to be renegociated\n     */\n    private ImsServiceSession mSession;\n\n    /**\n     * Re-Invite invitation status\n     */\n    private InvitationStatus mReInviteStatus = InvitationStatus.INVITATION_NOT_ANSWERED;\n\n    /**\n     * Wait user answer for reInvite invitation\n     */\n    private Object mWaitUserAnswer = new Object();\n\n    /**\n     * Ringing period (in milliseconds)\n     */\n    private final long mRingingPeriod;\n\n    private static final Logger sLogger = Logger.getLogger(UpdateSessionManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param session Session to be refreshed\n     * @param rcsSettings\n     */\n    public UpdateSessionManager(ImsServiceSession session, RcsSettings rcsSettings) {\n        mSession = session;\n        mRingingPeriod = rcsSettings.getRingingPeriod();\n    }\n\n    /**\n     * Create ReInvite\n     * \n     * @param featureTags featureTags to set in reInvite\n     * @param content reInvite content\n     * @return reInvite request\n     * @throws PayloadException\n     */\n    public SipRequest createReInvite(String[] featureTags, String content)\n            throws PayloadException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"createReInvite()\");\n        }\n        try {\n            mSession.getDialogPath().incrementCseq();\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Increment DialogPath CSeq - DialogPath CSeq =\".concat(String\n                        .valueOf(mSession.getDialogPath().getCseq())));\n            }\n            /* Increment internal stack CSeq (NIST stack issue?) */\n            Dialog dlg = mSession.getDialogPath().getStackDialog();\n            while ((dlg != null) && (dlg.getLocalSeqNumber() < mSession.getDialogPath().getCseq())) {\n                dlg.incrementLocalSequenceNumber();\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Increment LocalSequenceNumber -  Dialog local Seq Number =\"\n                            .concat(String.valueOf(dlg.getLocalSeqNumber())));\n                }\n            }\n            SipRequest reInvite = SipMessageFactory.createReInvite(mSession.getDialogPath(),\n                    featureTags, content);\n            if (sLogger.isActivated()) {\n                sLogger.info(\"reInvite created -  reInvite CSeq =\".concat(String.valueOf(reInvite\n                        .getCSeq())));\n            }\n            mSession.getAuthenticationAgent().setAuthorizationHeader(reInvite);\n            mSession.getAuthenticationAgent().setProxyAuthorizationHeader(reInvite);\n            return reInvite;\n\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Unable to create re-invite request!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to create re-invite request!\", e);\n        }\n\n    }\n\n    /**\n     * Send ReInvite\n     * \n     * @param request ReInvite request\n     * @param serviceContext service context of ReInvite\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void sendReInvite(SipRequest request, int serviceContext) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"sendReInvite()\");\n        }\n        SipTransactionContext ctx = mSession.getImsService().getImsModule().getSipManager()\n                .sendSipMessageAndWait(request, mSession.getResponseTimeout());\n\n        if (ctx.isSipResponse()) {\n            switch (ctx.getStatusCode()) {\n                case Response.OK:\n                    mSession.getDialogPath().setRemoteContent(ctx.getSipResponse().getSdpContent());\n                    mSession.handleReInviteResponse(InvitationStatus.INVITATION_ACCEPTED,\n                            ctx.getSipResponse(), serviceContext);\n\n                    mSession.getImsService().getImsModule().getSipManager()\n                            .sendSipAck(mSession.getDialogPath());\n                    return;\n\n                case Response.DECLINE:\n                    mSession.handleReInviteResponse(InvitationStatus.INVITATION_REJECTED,\n                            ctx.getSipResponse(), serviceContext);\n                    return;\n\n                case Response.REQUEST_TIMEOUT:\n                    mSession.handleReInviteResponse(InvitationStatus.INVITATION_TIMEOUT,\n                            ctx.getSipResponse(), serviceContext);\n                    return;\n\n                case Response.PROXY_AUTHENTICATION_REQUIRED:\n                    mSession.handleReInvite407ProxyAuthent(ctx.getSipResponse(), serviceContext);\n                    return;\n\n                default:\n                    mSession.handleError(new ImsSessionBasedServiceError(\n                            ImsSessionBasedServiceError.SESSION_INITIATION_FAILED));\n                    return;\n            }\n        }\n        mSession.handleReInviteResponse(InvitationStatus.INVITATION_NOT_ANSWERED,\n                ctx.getSipResponse(), serviceContext);\n    }\n\n    /**\n     * Receive RE-INVITE request\n     * \n     * @param request RE-INVITE request\n     * @param featureTags featureTags to set in request\n     * @param sdpResponse\n     * @param serviceContext service context of reInvite request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void send200OkReInviteResp(SipRequest request, String[] featureTags, String sdpResponse,\n            int serviceContext) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"receiveReInvite()\");\n        }\n        SipResponse resp = SipMessageFactory.create200OkReInviteResponse(mSession.getDialogPath(),\n                request, featureTags, sdpResponse);\n        SipTransactionContext ctx = mSession.getImsService().getImsModule().getSipManager()\n                .sendSipMessageAndWait(resp);\n        if (ctx.isSipAck()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"ACK request received\");\n            }\n            mSession.handleReInviteAck(InvitationStatus.INVITATION_ACCEPTED, serviceContext);\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"No ACK received for ReINVITE\");\n            }\n            mSession.handleError(new ImsSessionBasedServiceError(\n                    ImsSessionBasedServiceError.SEND_RESPONSE_FAILED));\n        }\n    }\n\n    /**\n     * Receive RE-INVITE request\n     * \n     * @param request RE-INVITE request\n     * @param featureTags featureTags to set in request\n     * @param serviceContext service context of reInvite request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void waitUserAckAndSendReInviteResp(SipRequest request, String[] featureTags,\n            int serviceContext) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"waitUserAckAndSendReInviteResp()\");\n        }\n        mReInviteStatus = InvitationStatus.INVITATION_NOT_ANSWERED;\n        InvitationStatus answer = waitInvitationAnswer();\n\n        switch (answer) {\n            case INVITATION_REJECTED:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"reInvite has been rejected by user\");\n                }\n                mSession.sendErrorResponse(request, mSession.getDialogPath().getLocalTag(),\n                        InvitationStatus.INVITATION_REJECTED_DECLINE);\n                mSession.handleReInviteUserAnswer(InvitationStatus.INVITATION_REJECTED,\n                        serviceContext);\n                break;\n\n            case INVITATION_NOT_ANSWERED:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been rejected on timeout\");\n                }\n                mSession.sendErrorResponse(request, mSession.getDialogPath().getLocalTag(),\n                        InvitationStatus.INVITATION_REJECTED_DECLINE);\n                mSession.handleReInviteUserAnswer(InvitationStatus.INVITATION_NOT_ANSWERED,\n                        serviceContext);\n                break;\n\n            case INVITATION_ACCEPTED:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Send 200 OK\");\n                }\n                String sdp = mSession.buildReInviteSdpResponse(request, serviceContext);\n                if (sdp == null) {\n                    mSession.handleError(new ImsSessionBasedServiceError(\n                            ImsSessionBasedServiceError.SEND_RESPONSE_FAILED));\n                    return;\n                }\n                mSession.getDialogPath().setLocalContent(sdp);\n\n                mSession.handleReInviteUserAnswer(InvitationStatus.INVITATION_ACCEPTED,\n                        serviceContext);\n                SipResponse resp = SipMessageFactory.create200OkReInviteResponse(\n                        mSession.getDialogPath(), request, featureTags, sdp);\n                SipTransactionContext ctx = mSession.getImsService().getImsModule().getSipManager()\n                        .sendSipMessageAndWait(resp);\n                if (ctx.isSipAck()) {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"ACK request received\");\n                        sLogger.info(\"ACK status code = \" + ctx.getStatusCode());\n                    }\n                    mSession.handleReInviteAck(InvitationStatus.INVITATION_ACCEPTED, serviceContext);\n                } else {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"No ACK received for INVITE\");\n                    }\n                    mSession.handleError(new ImsSessionBasedServiceError(\n                            ImsSessionBasedServiceError.SEND_RESPONSE_FAILED));\n                }\n                break;\n            default:\n                mSession.handleError(new ImsSessionBasedServiceError(\n                        ImsSessionBasedServiceError.SEND_RESPONSE_FAILED));\n                break;\n        }\n    }\n\n    /**\n     * Reject the session invitation\n     * \n     * @param code Error code\n     */\n    public void rejectReInvite(int code) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"ReInvite  has been rejected\");\n        }\n\n        synchronized (mWaitUserAnswer) {\n            mReInviteStatus = InvitationStatus.INVITATION_REJECTED;\n\n            // Unblock semaphore\n            mWaitUserAnswer.notifyAll();\n        }\n\n        // Decline the invitation\n        // session.sendErrorResponse(session.getDialogPath().getInvite(),\n        // session.getDialogPath().getLocalTag(), code);\n    }\n\n    /**\n     * Accept the session invitation\n     */\n    public void acceptReInvite() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"ReInvite has been accepted\");\n        }\n\n        synchronized (mWaitUserAnswer) {\n            mReInviteStatus = InvitationStatus.INVITATION_ACCEPTED;\n\n            // Unblock semaphore\n            mWaitUserAnswer.notifyAll();\n        }\n    }\n\n    /**\n     * Wait session invitation answer\n     * \n     * @return Answer\n     */\n    public InvitationStatus waitInvitationAnswer() {\n        if (InvitationStatus.INVITATION_NOT_ANSWERED != mReInviteStatus) {\n            return mReInviteStatus;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Wait session invitation answer\");\n        }\n\n        try {\n            synchronized (mWaitUserAnswer) {\n                // Wait until received response or received timeout\n                mWaitUserAnswer.wait(mRingingPeriod / 2);\n            }\n        } catch (InterruptedException e) {\n            /* Nothing to be handled here */\n            sLogger.warn(\"Wait for timeout has been interrupted!\", e);\n        }\n\n        return mReInviteStatus;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/UpdateSessionManagerListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service;\n\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\n\n/**\n * Listener of events sent to Update Session Manager\n * \n * @author O. Magnon\n */\npublic interface UpdateSessionManagerListener {\n\n    /**\n     * ReInvite Response received\n     * \n     * @param code Sip response code\n     * @param response Sip response request\n     */\n    public void handleReInviteResponse(InvitationStatus status, SipResponse response);\n\n    /**\n     * User answer received\n     * \n     * @param code user response code\n     */\n    public void handleReInviteUserAnswer(InvitationStatus status);\n\n    /**\n     * ReInvite Ack received\n     * \n     * @param code Sip response code\n     */\n    public void handleReInviteAck(InvitationStatus status);\n\n    /**\n     * Sdp requested for ReInvite Response\n     * \n     * @param reInvite Sip reInvite request received\n     */\n    public String buildReInviteSdpResponse(SipRequest reInvite);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/AnonymousFetchManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.presence.PresenceInfo;\nimport com.gsma.rcs.core.ims.service.presence.PresenceUtils;\nimport com.gsma.rcs.core.ims.service.presence.pidf.PidfDocument;\nimport com.gsma.rcs.core.ims.service.presence.pidf.PidfParser;\nimport com.gsma.rcs.core.ims.service.presence.pidf.Tuple;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport org.xml.sax.InputSource;\n\nimport java.io.ByteArrayInputStream;\n\n/**\n * Capability discovery manager using anonymous fetch procedure\n * \n * @author Jean-Marc AUFFRET\n */\npublic class AnonymousFetchManager implements DiscoveryManager {\n    /**\n     * IMS module\n     */\n    private ImsModule mImsModule;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings RCS settings accessor\n     * @param contactManager Contact manager accessor\n     */\n    public AnonymousFetchManager(ImsModule parent, RcsSettings rcsSettings,\n            ContactManager contactManager) {\n        mImsModule = parent;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n    }\n\n    /**\n     * Request contact capabilities\n     * \n     * @param contact Remote contact identifier\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void requestCapabilities(ContactId contact) throws PayloadException, NetworkException,\n            ContactManagerException {\n        if (logger.isActivated()) {\n            logger.debug(\"Request capabilities in background for \" + contact);\n        }\n        AnonymousFetchRequestTask task = new AnonymousFetchRequestTask(mImsModule, contact,\n                mRcsSettings, mContactManager);\n        task.start();\n    }\n\n    /**\n     * Receive a notification\n     * \n     * @param notify Received notify\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void onNotificationReceived(SipRequest notify) throws PayloadException,\n            ContactManagerException {\n        try {\n            boolean logActivated = logger.isActivated();\n            if (logActivated) {\n                logger.debug(\"Anonymous fetch notification received\");\n            }\n\n            /* Parse XML part */\n            byte[] content = notify.getContentBytes();\n            if (content != null) {\n                if (logActivated) {\n                    logger.debug(\"Anonymous fetch notification with PIDF document\");\n                }\n                InputSource pidfInput = new InputSource(new ByteArrayInputStream(content));\n                PidfParser pidfParser = new PidfParser(pidfInput);\n                PidfDocument presence = pidfParser.getPresence();\n                if (presence == null) {\n                    return;\n                }\n                /* Extract capabilities */\n                Capabilities.CapabilitiesBuilder capaBuilder = new Capabilities.CapabilitiesBuilder();\n\n                /* We queried via anonymous fetch procedure, so set presence discovery to true */\n                capaBuilder.setPresenceDiscovery(true);\n\n                String entity = presence.getEntity();\n                PhoneNumber validPhoneNumber = ContactUtil.getValidPhoneNumberFromUri(entity);\n                if (validPhoneNumber == null) {\n                    if (logActivated) {\n                        logger.error(new StringBuilder(\"Discard XML notification: bad entity '\")\n                                .append(entity).append(\"'\").toString());\n                    }\n                    return;\n                }\n                ContactId contact = ContactUtil.createContactIdFromValidatedData(validPhoneNumber);\n                for (Tuple tuple : presence.getTuplesList()) {\n                    boolean state = false;\n                    if (PresenceInfo.ONLINE.equals(tuple.getStatus().getBasic().getValue())) {\n                        state = true;\n                    }\n                    String id = tuple.getService().getId();\n                    if (PresenceUtils.FEATURE_RCS2_VIDEO_SHARE.equalsIgnoreCase(id)) {\n                        capaBuilder.setVideoSharing(state);\n\n                    } else if (PresenceUtils.FEATURE_RCS2_IMAGE_SHARE.equalsIgnoreCase(id)) {\n                        capaBuilder.setImageSharing(state);\n\n                    } else if (PresenceUtils.FEATURE_RCS2_FT.equalsIgnoreCase(id)) {\n                        capaBuilder.setFileTransferMsrp(state);\n\n                    } else if (PresenceUtils.FEATURE_RCS2_CS_VIDEO.equalsIgnoreCase(id)) {\n                        capaBuilder.setCsVideo(state);\n\n                    } else if (PresenceUtils.FEATURE_RCS2_CHAT.equalsIgnoreCase(id)) {\n                        capaBuilder.setImSession(state);\n                    }\n                }\n\n                Capabilities capabilities = capaBuilder.build();\n                mContactManager.setContactCapabilities(contact, capabilities,\n                        RcsStatus.RCS_CAPABLE, RegistrationState.UNKNOWN);\n\n                mImsModule.getCapabilityService().onReceivedCapabilities(contact, capabilities);\n            } else {\n                if (logActivated) {\n                    logger.debug(\"Anonymous fetch notification is empty\");\n                }\n                String sipAssertedId = SipUtils.getAssertedIdentity(notify);\n                PhoneNumber validPhoneNumber = ContactUtil\n                        .getValidPhoneNumberFromUri(sipAssertedId);\n                if (validPhoneNumber == null) {\n                    if (logActivated) {\n                        logger.error(new StringBuilder(\n                                \"Cannot process notification: invalid SIP id '\")\n                                .append(sipAssertedId).append(\"'\").toString());\n                    }\n                    return;\n                }\n                ContactId contact = ContactUtil.createContactIdFromValidatedData(validPhoneNumber);\n\n                /* Notify content was empty : set default capabilities */\n                mContactManager.setContactCapabilities(contact, Capabilities.sDefaultCapabilities,\n                        RcsStatus.NO_INFO, RegistrationState.UNKNOWN);\n\n                mImsModule.getCapabilityService().onReceivedCapabilities(contact,\n                        Capabilities.sDefaultCapabilities);\n            }\n        } catch (FileAccessException e) {\n            throw new PayloadException(new StringBuilder(\"Can't parse XML notification! CallId=\")\n                    .append(notify.getCallId()).toString(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/AnonymousFetchRequestTask.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.core.ims.service.presence.PresenceError;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\nimport java.util.Vector;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.AcceptHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.message.Response;\n\n/**\n * Anonymous fetch procedure which permits to request the capabilities for a given contact thanks to\n * a one shot subscribe.\n * \n * @author Jean-Marc AUFFRET\n */\npublic class AnonymousFetchRequestTask {\n    /**\n     * IMS module\n     */\n    private ImsModule mImsModule;\n\n    /**\n     * Remote contact\n     */\n    private ContactId mContact;\n\n    /**\n     * Dialog path\n     */\n    private SipDialogPath mDialogPath;\n\n    /**\n     * Authentication agent\n     */\n    private SessionAuthenticationAgent mAuthenticationAgent;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(AnonymousFetchRequestTask.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param contact Remote contact identifier\n     * @param rcsSettings RCS settings accessor\n     * @param contactManager Contact manager accessor\n     */\n    public AnonymousFetchRequestTask(ImsModule parent, ContactId contact, RcsSettings rcsSettings,\n            ContactManager contactManager) {\n        mImsModule = parent;\n        mContact = contact;\n        mAuthenticationAgent = new SessionAuthenticationAgent(mImsModule);\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n    }\n\n    /**\n     * Start task\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void start() throws PayloadException, NetworkException, ContactManagerException {\n        sendSubscribe();\n    }\n\n    /**\n     * Send a SUBSCRIBE request\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    private void sendSubscribe() throws PayloadException, NetworkException, ContactManagerException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send SUBSCRIBE request to \" + mContact);\n        }\n        /* Create a dialog path */\n        // @FIXME: This should be an URI instead of String\n        String contactUri = PhoneUtils.formatContactIdToUri(mContact).toString();\n\n        /* Set Call-Id */\n        String callId = mImsModule.getSipManager().getSipStack().generateCallId();\n\n        /* Set target */\n        String target = contactUri;\n\n        /* Set local party */\n        String localParty = \"sip:anonymous@\".concat(ImsModule.getImsUserProfile().getHomeDomain());\n\n        /* Set remote party */\n        String remoteParty = contactUri;\n\n        /* Set the route path */\n        Vector<String> route = mImsModule.getSipManager().getSipStack().getServiceRoutePath();\n\n        /* Create a dialog path */\n        mDialogPath = new SipDialogPath(mImsModule.getSipManager().getSipStack(), callId, 1,\n                target, localParty, remoteParty, route, mRcsSettings);\n        sendSubscribe(createSubscribe());\n    }\n\n    /**\n     * Create a SUBSCRIBE request\n     * \n     * @return SIP request\n     * @throws PayloadException\n     */\n    private SipRequest createSubscribe() throws PayloadException {\n        try {\n            SipRequest subscribe = SipMessageFactory.createSubscribe(mDialogPath, 0);\n            subscribe.addHeader(SipUtils.HEADER_PRIVACY, \"id\");\n            subscribe.addHeader(EventHeader.NAME, \"presence\");\n            subscribe.addHeader(AcceptHeader.NAME, \"application/pidf+xml\");\n            return subscribe;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create subscribe request!\", e);\n        }\n    }\n\n    /**\n     * Send SUBSCRIBE message\n     * \n     * @param subscribe SIP SUBSCRIBE\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void sendSubscribe(SipRequest subscribe) throws PayloadException, NetworkException,\n            ContactManagerException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(new StringBuilder(\"Send SUBSCRIBE, expire=\")\n                        .append(subscribe.getExpires()).append(\"ms\").toString());\n            }\n\n            /* Send SUBSCRIBE request */\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSipMessageAndWait(subscribe);\n\n            /* Analyze the received response */\n            if (ctx.isSipResponse()) {\n                /* A response has been received */\n                if ((ctx.getStatusCode() >= Response.OK)\n                        && (ctx.getStatusCode() < Response.MULTIPLE_CHOICES)) {\n                    handle200OK(ctx);\n                } else if (Response.PROXY_AUTHENTICATION_REQUIRED == ctx.getStatusCode()) {\n                    /* 407 Proxy Authentication Required */\n                    handle407Authentication(ctx);\n                } else if (Response.NOT_FOUND == ctx.getStatusCode()) {\n                    /* User not found */\n                    handleUserNotFound(ctx);\n                } else {\n                    /* Other error response */\n                    handleError(new PresenceError(PresenceError.SUBSCRIBE_FAILED,\n                            ctx.getStatusCode() + \" \" + ctx.getReasonPhrase()));\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No response received for SUBSCRIBE\");\n                }\n\n                /* No response received: timeout */\n                handleError(new PresenceError(PresenceError.SUBSCRIBE_FAILED));\n            }\n        } catch (FileAccessException e) {\n            throw new PayloadException(\"Failed to send SUBSCRIBE!\", e);\n\n        }\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OK(SipTransactionContext ctx) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n    }\n\n    /**\n     * Handle 407 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void handle407Authentication(SipTransactionContext ctx) throws PayloadException,\n            NetworkException, ContactManagerException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"407 response received\");\n            }\n\n            SipResponse resp = ctx.getSipResponse();\n\n            /* Set the Proxy-Authorization header */\n            mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n\n            /* Increment the Cseq number of the dialog path */\n            mDialogPath.incrementCseq();\n\n            /* Create a second SUBSCRIBE request with the right token */\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send second SUBSCRIBE\");\n            }\n            SipRequest subscribe = createSubscribe();\n\n            /* Set the Authorization header */\n            mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n\n            sendSubscribe(subscribe);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n        }\n    }\n\n    /**\n     * Handle error response\n     * \n     * @param error Error\n     */\n    private void handleError(PresenceError error) {\n        /* On error don't modify the existing capabilities */\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Subscribe has failed: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n\n        /* We update the database capabilities time of last request */\n        mContactManager.updateCapabilitiesTimeLastRequest(mContact);\n    }\n\n    /**\n     * Handle user not found\n     * \n     * @param ctx SIP transaction context\n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    private void handleUserNotFound(SipTransactionContext ctx) throws ContactManagerException,\n            FileAccessException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"User not found (\" + ctx.getStatusCode() + \" error)\");\n        }\n\n        /* We update the database with default capabilities */\n        mContactManager.setContactCapabilities(mContact, Capabilities.sDefaultCapabilities,\n                RcsStatus.NOT_RCS, RegistrationState.UNKNOWN);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/Capabilities.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Capabilities\n * \n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic class Capabilities {\n\n    /**\n     * Invalid timestamp for capabilities\n     */\n    public static final long INVALID_TIMESTAMP = -1;\n\n    private final boolean mImageSharing;\n    private final boolean mVideoSharing;\n    private final boolean mIpVoiceCall;\n    private final boolean mIpVideoCall;\n    private final boolean mImSession;\n    private final boolean mFileTransferMsrp;\n    private final boolean mCsVideo;\n    private final boolean mPresenceDiscovery;\n    private final boolean mSocialPresence;\n    private final boolean mFileTransferHttp;\n    private final boolean mGeolocationPush;\n    private final boolean mFileTransferThumbnail;\n    private final boolean mFileTransferStoreForward;\n    private final boolean mGroupChatStoreForward;\n    /**\n     * SIP automata (@see RFC 3840)\n     */\n    private final boolean mSipAutomata;\n\n    /**\n     * Set of supported extensions\n     */\n    private final Set<String> mExtensions;\n\n    /**\n     * Last timestamp capabilities was requested\n     */\n    private final long mTimestampOfLastRequest;\n\n    /**\n     * Timestamp of when this capabilities was received from network.\n     */\n    private final long mTimestampOfLastResponse;\n\n    /**\n     * The default capabilities applicable to non RCS contacts\n     */\n    public final static Capabilities sDefaultCapabilities = new Capabilities.CapabilitiesBuilder()\n            .build();\n\n    private Capabilities(CapabilitiesBuilder builder) {\n        mImageSharing = builder.mImageSharing;\n        mVideoSharing = builder.mVideoSharing;\n        mIpVoiceCall = builder.mIpVoiceCall;\n        mIpVideoCall = builder.mIpVideoCall;\n        mImSession = builder.mImSession;\n        mFileTransferMsrp = builder.mFileTransferMsrp;\n        mCsVideo = builder.mCsVideo;\n        mPresenceDiscovery = builder.mPresenceDiscovery;\n        mSocialPresence = builder.mSocialPresence;\n        mFileTransferHttp = builder.mFileTransferHttp;\n        mGeolocationPush = builder.mGeolocationPush;\n        mFileTransferThumbnail = builder.mFileTransferThumbnail;\n        mFileTransferStoreForward = builder.mFileTransferStoreForward;\n        mGroupChatStoreForward = builder.mGroupChatStoreForward;\n        mSipAutomata = builder.mSipAutomata;\n        mTimestampOfLastRequest = builder.mTimestampOfLastRequest;\n        mTimestampOfLastResponse = builder.mTimestampOfLastResponse;\n        mExtensions = new HashSet<>(builder.mExtensions);\n    }\n\n    /**\n     * Is image sharing supported\n     * \n     * @return Boolean\n     */\n    public boolean isImageSharingSupported() {\n        return mImageSharing;\n    }\n\n    /**\n     * Is video sharing supported\n     * \n     * @return Boolean\n     */\n    public boolean isVideoSharingSupported() {\n        return mVideoSharing;\n    }\n\n    /**\n     * Is IP voice call supported\n     * \n     * @return Boolean\n     */\n    public boolean isIPVoiceCallSupported() {\n        return mIpVoiceCall;\n    }\n\n    /**\n     * Is IP video call supported\n     * \n     * @return Boolean\n     */\n    public boolean isIPVideoCallSupported() {\n        return mIpVideoCall;\n    }\n\n    /**\n     * Is IM session supported\n     * \n     * @return Boolean\n     */\n    public boolean isImSessionSupported() {\n        return mImSession;\n    }\n\n    /**\n     * Is file transfer MSRP supported\n     * \n     * @return Boolean\n     */\n    public boolean isFileTransferMsrpSupported() {\n        return mFileTransferMsrp;\n    }\n\n    /**\n     * Is CS video supported\n     * \n     * @return Boolean\n     */\n    public boolean isCsVideoSupported() {\n        return mCsVideo;\n    }\n\n    /**\n     * Is presence discovery supported\n     * \n     * @return Boolean\n     */\n    public boolean isPresenceDiscoverySupported() {\n        return mPresenceDiscovery;\n    }\n\n    /**\n     * Is social presence supported\n     * \n     * @return Boolean\n     */\n    public boolean isSocialPresenceSupported() {\n        return mSocialPresence;\n    }\n\n    /**\n     * Is file transfer over HTTP supported\n     * \n     * @return Boolean\n     */\n    public boolean isFileTransferHttpSupported() {\n        return mFileTransferHttp;\n    }\n\n    /**\n     * Is Geolocation Push supported\n     * \n     * @return Boolean\n     */\n    public boolean isGeolocationPushSupported() {\n        return mGeolocationPush;\n    }\n\n    /**\n     * Is file transfer thumbnail supported\n     * \n     * @return Boolean\n     */\n    public boolean isFileTransferThumbnailSupported() {\n        return mFileTransferThumbnail;\n    }\n\n    /**\n     * Is file transfer S&F supported\n     * \n     * @return Boolean\n     */\n    public boolean isFileTransferStoreForwardSupported() {\n        return mFileTransferStoreForward;\n    }\n\n    /**\n     * Is group chat S&F supported\n     * \n     * @return Boolean\n     */\n    public boolean isGroupChatStoreForwardSupported() {\n        return mGroupChatStoreForward;\n    }\n\n    /**\n     * Is device an automata ?\n     * \n     * @return True if automata\n     */\n    public boolean isSipAutomata() {\n        return mSipAutomata;\n    }\n\n    /**\n     * Get set of supported extensions\n     * \n     * @return List\n     */\n    public Set<String> getSupportedExtensions() {\n        return mExtensions;\n    }\n\n    /**\n     * Get timestamp of last request\n     * \n     * @return timetampOfLastRequest (in milliseconds)\n     */\n    public long getTimestampOfLastRequest() {\n        return mTimestampOfLastRequest;\n    }\n\n    // @formatter:off\n    @Override\n    public String toString() {\n        return \"Caps{\" +\n                \"ImageShare=\" + mImageSharing +\n                \", VideoSharing=\" + mVideoSharing +\n                \", IM=\" + mImSession +\n                \", FtMsrp=\" + mFileTransferMsrp +\n                \", FtHttp=\" + mFileTransferHttp +\n                \", GeoPush=\" + mGeolocationPush +\n                \", FtThumbnail=\" + mFileTransferThumbnail +\n                \", FtSF=\" + mFileTransferStoreForward +\n                \", GcSF=\" + mGroupChatStoreForward +\n                \", SipAutomata=\" + mSipAutomata +\n                \", Exts=\" + mExtensions +\n                \", TimeOfLastRequest=\" + mTimestampOfLastRequest +\n                \", TimeOfLastResponse=\" + mTimestampOfLastResponse +\n                '}';\n    }\n    // @formatter:on\n\n    /*\n     * The equals method does not consider the 2 timestamps.\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        Capabilities other = (Capabilities) obj;\n        if (mCsVideo != other.mCsVideo)\n            return false;\n        if (!mExtensions.equals(other.mExtensions))\n            return false;\n        if (mFileTransferMsrp != other.mFileTransferMsrp)\n            return false;\n        if (mFileTransferHttp != other.mFileTransferHttp)\n            return false;\n        if (mFileTransferStoreForward != other.mFileTransferStoreForward)\n            return false;\n        if (mFileTransferThumbnail != other.mFileTransferThumbnail)\n            return false;\n        if (mGeolocationPush != other.mGeolocationPush)\n            return false;\n        if (mGroupChatStoreForward != other.mGroupChatStoreForward)\n            return false;\n        if (mImSession != other.mImSession)\n            return false;\n        if (mImageSharing != other.mImageSharing)\n            return false;\n        if (mIpVideoCall != other.mIpVideoCall)\n            return false;\n        if (mIpVoiceCall != other.mIpVoiceCall)\n            return false;\n        if (mPresenceDiscovery != other.mPresenceDiscovery)\n            return false;\n        if (mSipAutomata != other.mSipAutomata)\n            return false;\n        if (mSocialPresence != other.mSocialPresence)\n            return false;\n        return mVideoSharing == other.mVideoSharing;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (mCsVideo ? 1231 : 1237);\n        result = prime * result + (mExtensions.hashCode());\n        result = prime * result + (mFileTransferHttp ? 1231 : 1237);\n        result = prime * result + (mFileTransferMsrp ? 1231 : 1237);\n        result = prime * result + (mFileTransferStoreForward ? 1231 : 1237);\n        result = prime * result + (mFileTransferThumbnail ? 1231 : 1237);\n        result = prime * result + (mGeolocationPush ? 1231 : 1237);\n        result = prime * result + (mGroupChatStoreForward ? 1231 : 1237);\n        result = prime * result + (mImSession ? 1231 : 1237);\n        result = prime * result + (mImageSharing ? 1231 : 1237);\n        result = prime * result + (mIpVideoCall ? 1231 : 1237);\n        result = prime * result + (mIpVoiceCall ? 1231 : 1237);\n        result = prime * result + (mPresenceDiscovery ? 1231 : 1237);\n        result = prime * result + (mSipAutomata ? 1231 : 1237);\n        result = prime * result + (mSocialPresence ? 1231 : 1237);\n        result = prime * result + (mVideoSharing ? 1231 : 1237);\n        return result;\n    }\n\n    /**\n     * Get timestamp of last response\n     * \n     * @return timestampOfLastResponse (in milliseconds)\n     */\n    public long getTimestampOfLastResponse() {\n        return mTimestampOfLastResponse;\n    }\n\n    /**\n     * Capabilities builder class\n     */\n    public static class CapabilitiesBuilder {\n        private boolean mImageSharing = false;\n        private boolean mVideoSharing = false;\n        private boolean mIpVoiceCall = false;\n        private boolean mIpVideoCall = false;\n        private boolean mImSession = false;\n        private boolean mFileTransferMsrp = false;\n        private boolean mCsVideo = false;\n        private boolean mPresenceDiscovery = false;\n        private boolean mSocialPresence = false;\n        private boolean mFileTransferHttp = false;\n        private boolean mGeolocationPush = false;\n        private boolean mFileTransferThumbnail = false;\n        private boolean mFileTransferStoreForward = false;\n        private boolean mGroupChatStoreForward = false;\n        private boolean mSipAutomata = false;\n        private Set<String> mExtensions = new HashSet<>();\n        private long mTimestampOfLastRequest = INVALID_TIMESTAMP;\n        private long mTimestampOfLastResponse = INVALID_TIMESTAMP;\n\n        /**\n         * Default constructor\n         */\n        public CapabilitiesBuilder() {\n        }\n\n        /**\n         * Copy constructor\n         * \n         * @param capabilities to copy or null if construct with default values\n         */\n        public CapabilitiesBuilder(Capabilities capabilities) {\n            mImageSharing = capabilities.isImageSharingSupported();\n            mVideoSharing = capabilities.isVideoSharingSupported();\n            mIpVoiceCall = capabilities.isIPVoiceCallSupported();\n            mIpVideoCall = capabilities.isIPVideoCallSupported();\n            mImSession = capabilities.isImSessionSupported();\n            mFileTransferMsrp = capabilities.isFileTransferMsrpSupported();\n            mCsVideo = capabilities.isCsVideoSupported();\n            mPresenceDiscovery = capabilities.isPresenceDiscoverySupported();\n            mSocialPresence = capabilities.isSocialPresenceSupported();\n            mFileTransferHttp = capabilities.isFileTransferHttpSupported();\n            mGeolocationPush = capabilities.isGeolocationPushSupported();\n            mFileTransferThumbnail = capabilities.isFileTransferThumbnailSupported();\n            mFileTransferStoreForward = capabilities.isFileTransferStoreForwardSupported();\n            mGroupChatStoreForward = capabilities.isGroupChatStoreForwardSupported();\n            mSipAutomata = capabilities.isSipAutomata();\n            mTimestampOfLastRequest = capabilities.getTimestampOfLastRequest();\n            mTimestampOfLastResponse = capabilities.getTimestampOfLastResponse();\n            mExtensions = new HashSet<>(capabilities.getSupportedExtensions());\n        }\n\n        /**\n         * Sets image sharing support\n         * \n         * @param support the image sharing support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setImageSharing(boolean support) {\n            mImageSharing = support;\n            return this;\n        }\n\n        /**\n         * Is video sharing supported\n         * \n         * @return Boolean\n         */\n        public boolean isImageSharingSupported() {\n            return mImageSharing;\n        }\n\n        /**\n         * Sets video sharing support\n         * \n         * @param support the video sharing support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setVideoSharing(boolean support) {\n            mVideoSharing = support;\n            return this;\n        }\n\n        /**\n         * Is video sharing supported\n         * \n         * @return Boolean\n         */\n        public boolean isVideoSharingSupported() {\n            return mVideoSharing;\n        }\n\n        /**\n         * Sets IP voice call support\n         * \n         * @param support the IP voice call support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setIpVoiceCall(boolean support) {\n            mIpVoiceCall = support;\n            return this;\n        }\n\n        /**\n         * Is IP voice call supported\n         * \n         * @return Boolean\n         */\n        public boolean isIPVoiceCallSupported() {\n            return mIpVoiceCall;\n        }\n\n        /**\n         * Sets IP video call support\n         * \n         * @param support the IP video call support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setIpVideoCall(boolean support) {\n            mIpVideoCall = support;\n            return this;\n        }\n\n        /**\n         * Is IP video call supported\n         * \n         * @return Boolean\n         */\n        public boolean isIPVideoCallSupported() {\n            return mIpVideoCall;\n        }\n\n        /**\n         * Sets Instant Messaging support\n         * \n         * @param support the Instant Messaging support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setImSession(boolean support) {\n            mImSession = support;\n            return this;\n        }\n\n        /**\n         * Is IM session supported\n         * \n         * @return Boolean\n         */\n        public boolean isImSessionSupported() {\n            return mImSession;\n        }\n\n        /**\n         * Sets MSRP File Transfer support\n         * \n         * @param support the File Transfer support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setFileTransferMsrp(boolean support) {\n            mFileTransferMsrp = support;\n            return this;\n        }\n\n        /**\n         * Is MSRP file transfer supported\n         * \n         * @return Boolean\n         */\n        public boolean isFileTransferMsrpSupported() {\n            return mFileTransferMsrp;\n        }\n\n        /**\n         * Sets CS video support\n         * \n         * @param support the CS video support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setCsVideo(boolean support) {\n            mCsVideo = support;\n            return this;\n        }\n\n        /**\n         * Is CS video supported\n         * \n         * @return Boolean\n         */\n        public boolean isCsVideoSupported() {\n            return mCsVideo;\n        }\n\n        /**\n         * Sets Presence Discovery support\n         * \n         * @param support the Presence Discovery support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setPresenceDiscovery(boolean support) {\n            mPresenceDiscovery = support;\n            return this;\n        }\n\n        /**\n         * Is Presence Discovery supported\n         * \n         * @return Boolean\n         */\n        public boolean isPresenceDiscovery() {\n            return mPresenceDiscovery;\n        }\n\n        /**\n         * Sets Social Presence support\n         * \n         * @param support the Social Presence support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setSocialPresence(boolean support) {\n            mSocialPresence = support;\n            return this;\n        }\n\n        /**\n         * Is Social Presence supported\n         * \n         * @return Boolean\n         */\n        public boolean isSocialPresence() {\n            return mSocialPresence;\n        }\n\n        /**\n         * Sets File Transfer HTTP support\n         * \n         * @param support the File Transfer HTTP support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setFileTransferHttp(boolean support) {\n            mFileTransferHttp = support;\n            return this;\n        }\n\n        /**\n         * Is file transfer over HTTP supported\n         * \n         * @return Boolean\n         */\n        public boolean isFileTransferHttpSupported() {\n            return mFileTransferHttp;\n        }\n\n        /**\n         * Sets Geolocation Push support\n         * \n         * @param support the Geolocation Push support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setGeolocationPush(boolean support) {\n            mGeolocationPush = support;\n            return this;\n        }\n\n        /**\n         * Is Geolocation Push supported\n         * \n         * @return Boolean\n         */\n        public boolean isGeolocationPushSupported() {\n            return mGeolocationPush;\n        }\n\n        /**\n         * Sets File Transfer Thumbnail support\n         * \n         * @param support the File Transfer Thumbnail support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setFileTransferThumbnail(boolean support) {\n            mFileTransferThumbnail = support;\n            return this;\n        }\n\n        /**\n         * Is file transfer thumbnail supported\n         * \n         * @return Boolean\n         */\n        public boolean isFileTransferThumbnailSupported() {\n            return mFileTransferThumbnail;\n        }\n\n        /**\n         * Sets File Transfer Thumbnail support\n         * \n         * @param support the File Transfer Thumbnail support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setFileTransferStoreForward(boolean support) {\n            mFileTransferStoreForward = support;\n            return this;\n        }\n\n        /**\n         * Is file transfer S&F supported\n         * \n         * @return Boolean\n         */\n        public boolean isFileTransferStoreForwardSupported() {\n            return mFileTransferStoreForward;\n        }\n\n        /**\n         * Sets Group Chat Store & Forward support\n         * \n         * @param support the Group Chat Store & Forward support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setGroupChatStoreForward(boolean support) {\n            mGroupChatStoreForward = support;\n            return this;\n        }\n\n        /**\n         * Is group chat S&F supported\n         * \n         * @return Boolean\n         */\n        public boolean isGroupChatStoreForwardSupported() {\n            return mGroupChatStoreForward;\n        }\n\n        /**\n         * Sets Sip Automata support\n         * \n         * @param support the Sip Automata support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setSipAutomata(boolean support) {\n            mSipAutomata = support;\n            return this;\n        }\n\n        /**\n         * Is Sip Automata\n         * \n         * @return Boolean\n         */\n        public boolean isSipAutomata() {\n            return mSipAutomata;\n        }\n\n        /**\n         * Sets extensions\n         * \n         * @param extensions the supported extensions\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setExtensions(Set<String> extensions) {\n            mExtensions = extensions;\n            return this;\n        }\n\n        /**\n         * Add extension\n         * \n         * @param extension the extension to add\n         * @return the current instance\n         */\n        public CapabilitiesBuilder addExtension(String extension) {\n            mExtensions.add(extension);\n            return this;\n        }\n\n        /**\n         * Sets the timestamp of last request\n         * \n         * @param time the Timestamp Of Last Request\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setTimestampOfLastRequest(long time) {\n            mTimestampOfLastRequest = time;\n            return this;\n        }\n\n        /**\n         * Gets timestamp of last request\n         * \n         * @return Boolean\n         */\n        public long getTimestampOfLastRequest() {\n            return mTimestampOfLastRequest;\n        }\n\n        /**\n         * Sets the timestamp of last response\n         * \n         * @param time the File Transfer Thumbnail support\n         * @return the current instance\n         */\n        public CapabilitiesBuilder setTimestampOfLastResponse(long time) {\n            mTimestampOfLastResponse = time;\n            return this;\n        }\n\n        /**\n         * Gets timestamp of last response\n         * \n         * @return Boolean\n         */\n        public long getTimestampOfLastResponse() {\n            return mTimestampOfLastResponse;\n        }\n\n        /**\n         * Build the capabilities\n         * \n         * @return the built capabilities instance\n         */\n        public Capabilities build() {\n            return new Capabilities(this);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/CapabilityError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\n\n/**\n * Capability error\n * \n * @author jexa7410\n */\npublic class CapabilityError extends ImsServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Options has failed\n     */\n    public final static int OPTIONS_FAILED = CAPABILITY_ERROR_CODES + 1;\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public CapabilityError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public CapabilityError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public CapabilityError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/CapabilityService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.addressbook.AddressBookEventListener;\nimport com.gsma.rcs.addressbook.AddressBookManager;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.capability.SyncContactTask.ISyncContactTaskListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.api.CapabilityServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.Handler;\nimport android.os.HandlerThread;\n\nimport java.util.Arrays;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * Capability discovery service\n * \n * @author jexa7410\n */\npublic class CapabilityService extends ImsService implements AddressBookEventListener {\n\n    private static final String CAPABILITIES_OPERATION_THREAD_NAME = \"CapabiltiesOps\";\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private OptionsManager mOptionsManager;\n\n    private AnonymousFetchManager mAnonymousFetchManager;\n\n    private PollingManager mPollingManager;\n\n    private ExecutorService mSyncExecutor;\n\n    private final AddressBookManager mAddressBookManager;\n\n    private final static Logger sLogger = Logger.getLogger(CapabilityService.class.getSimpleName());\n\n    private final ISyncContactTaskListener mISyncContactTaskListener;\n\n    private static final int MAX_CONTACTS_TO_DISPLAY = 10;\n\n    /**\n     * This purpose of this handler is to make the request asynchronous with the mechanisms provider\n     * by android by placing the request in the main thread message queue.\n     */\n    private final Handler mCapabilityOperationsHandler;\n\n    private CapabilityServiceImpl mCapabilityService;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings RCS settings accessor\n     * @param contactsManager Contact manager accessor\n     * @param addressBookManager The address book manager instance\n     */\n    public CapabilityService(ImsModule parent, RcsSettings rcsSettings,\n            ContactManager contactsManager, AddressBookManager addressBookManager) {\n        super(parent, true);\n        mRcsSettings = rcsSettings;\n        mContactManager = contactsManager;\n        mAddressBookManager = addressBookManager;\n\n        mCapabilityOperationsHandler = allocateBgHandler(CAPABILITIES_OPERATION_THREAD_NAME);\n        mISyncContactTaskListener = new ISyncContactTaskListener() {\n            @Override\n            public void endOfSyncContactTask() {\n                if (!isServiceStarted()) {\n                    return;\n                }\n                /* Listen to address book changes */\n                mAddressBookManager.addAddressBookListener(CapabilityService.this);\n                mPollingManager.start();\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Capability service initialize\");\n                }\n            }\n        };\n\n        mPollingManager = new PollingManager(this, mRcsSettings, mContactManager);\n        mOptionsManager = new OptionsManager(parent, mRcsSettings, mContactManager);\n        mAnonymousFetchManager = new AnonymousFetchManager(parent, mRcsSettings, mContactManager);\n    }\n\n    private Handler allocateBgHandler(String threadName) {\n        HandlerThread thread = new HandlerThread(threadName);\n        thread.start();\n        return new Handler(thread.getLooper());\n    }\n\n    public void register(CapabilityServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mCapabilityService = service;\n    }\n\n    public void scheduleCapabilityOperation(Runnable runnable) {\n        mCapabilityOperationsHandler.post(runnable);\n    }\n\n    @Override\n    public synchronized void start() {\n        if (isServiceStarted()) {\n            /* Already started */\n            return;\n        }\n        setServiceStarted(true);\n        mOptionsManager.start();\n\n        /* Force a first capability check */\n        mSyncExecutor = Executors.newSingleThreadExecutor();\n        synchronizeContacts();\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Capability service start\");\n        }\n    }\n\n    @Override\n    public synchronized void stop(ImsServiceSession.TerminationReason reasonCode) {\n        if (!isServiceStarted()) {\n            /* Already stopped */\n            return;\n        }\n        setServiceStarted(false);\n\n        mSyncExecutor.shutdownNow();\n\n        mPollingManager.stop();\n        /* Stop listening to address book changes */\n        mAddressBookManager.removeAddressBookListener(this);\n        mOptionsManager.stop();\n\n        if (ImsServiceSession.TerminationReason.TERMINATION_BY_SYSTEM == reasonCode) {\n            mCapabilityOperationsHandler.getLooper().quit();\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Capability service stop\");\n        }\n    }\n\n    /**\n     * Check the IMS service\n     */\n    public void check() {\n    }\n\n    /**\n     * Get the options manager\n     * \n     * @return Options manager\n     */\n    public OptionsManager getOptionsManager() {\n        return mOptionsManager;\n    }\n\n    /**\n     * Get the options manager\n     * \n     * @return Options manager\n     */\n    public AnonymousFetchManager getAnonymousFetchManager() {\n        return mAnonymousFetchManager;\n    }\n\n    /**\n     * Request contact capabilities\n     * \n     * @param contact Contact identifier\n     */\n    public synchronized void requestContactCapabilities(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Request capabilities for \".concat(contact.toString()));\n        }\n        mOptionsManager.requestCapabilities(contact);\n    }\n\n    /**\n     * Request capabilities for a set of contacts\n     * \n     * @param contacts Set of contact identifiers\n     */\n    public void requestContactCapabilities(Set<ContactId> contacts) {\n        if (sLogger.isActivated()) {\n            int nbOfContactsToQuery = contacts.size();\n            if (nbOfContactsToQuery > MAX_CONTACTS_TO_DISPLAY) {\n                sLogger.debug(\"Request capabilities for \" + nbOfContactsToQuery + \" contacts\");\n            } else {\n                sLogger.debug(\"Request capabilities for \".concat(Arrays.toString(contacts.toArray())));\n            }\n        }\n        mOptionsManager.requestCapabilities(contacts);\n    }\n\n    /**\n     * Receive a capability request (options procedure)\n     * \n     * @param options Received options message\n     */\n    public void onCapabilityRequestReceived(final SipRequest options) {\n        scheduleCapabilityOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    mOptionsManager.onCapabilityRequestReceived(options);\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive capability request! (\" + e.getMessage()\n                                + \")\");\n                    }\n                } catch (PayloadException e) {\n                    sLogger.error(\"Failed to receive capability request!\", e);\n                } catch (ContactManagerException e) {\n                    sLogger.error(\"Failed to receive capability request!\", e);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to receive capability request!\", e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Receive a notification (anonymous fetch procedure)\n     * \n     * @param notify Received notify\n     */\n    public void onNotificationReceived(final SipRequest notify) {\n        scheduleCapabilityOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    mAnonymousFetchManager.onNotificationReceived(notify);\n                } catch (ContactManagerException e) {\n                    sLogger.error(\"Failed to receive capability notification!\", e);\n                } catch (PayloadException e) {\n                    sLogger.error(\"Failed to receive capability notification!\", e);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to receive capability notification!\", e);\n                }\n            }\n        });\n    }\n\n    private void synchronizeContacts() {\n        mSyncExecutor.execute(new SyncContactTask(mISyncContactTaskListener, this, mContactManager,\n                mAddressBookManager, mPollingManager, mOptionsManager));\n    }\n\n    /**\n     * Address book content has changed.<br>\n     * This method requests update of capabilities for non RCS contacts (which capabilities are\n     * unknown).<br>\n     * This method set contact information for RCS contacts not yet aggregated.\n     * \n     * @throws ContactManagerException thrown if RCS contact aggregation fails\n     */\n    @Override\n    public void handleAddressBookHasChanged() throws ContactManagerException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"handle address book changes\");\n        }\n        synchronizeContacts();\n    }\n\n    /**\n     * Reset the content sharing capabilities for a given contact identifier\n     * \n     * @param contact Contact identifier\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    public void resetContactCapabilitiesForContentSharing(ContactId contact)\n            throws PayloadException, NetworkException, ContactManagerException {\n        try {\n            Capabilities capabilities = mContactManager.getContactCapabilities(contact);\n            if (capabilities == null\n                    || (!capabilities.isImageSharingSupported() && !capabilities\n                            .isVideoSharingSupported())) {\n                return;\n            }\n            CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder(capabilities);\n            /* Force a reset of content sharing capabilities */\n            capaBuilder.setImageSharing(false);\n            capaBuilder.setVideoSharing(false);\n            capabilities = capaBuilder.build();\n            mContactManager.setContactCapabilities(contact, capabilities);\n\n            onReceivedCapabilities(contact, capabilities);\n\n        } catch (FileAccessException e) {\n            throw new PayloadException(\"Failed to reset content share capabilities for contact : \"\n                    + contact, e);\n        }\n    }\n\n    /**\n     * Capabilities update notification has been received\n     * \n     * @param contact Contact identifier\n     * @param capabilities Capabilities\n     */\n    public void onReceivedCapabilities(ContactId contact, Capabilities capabilities) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle capabilities update notification for \" + contact + \" (\"\n                    + capabilities.toString() + \")\");\n        }\n        mCapabilityService.receiveCapabilities(contact, capabilities);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/CapabilityUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.content.GeolocContent;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.rtp.MediaRegistry;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.video.VideoFormat;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipMessage;\nimport com.gsma.rcs.core.ims.service.richcall.image.ImageTransferSession;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.MimeManager;\nimport com.gsma.rcs.utils.NetworkUtils;\nimport com.gsma.rcs.utils.StringUtils;\n\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.Vector;\n\n/**\n * Capability utility functions\n * \n * @author jexa7410\n */\npublic class CapabilityUtils {\n\n    /**\n     * Get supported feature tags for capability exchange\n     * \n     * @param richcall Rich call supported\n     * @param rcsSettings the accessor to RCS settings\n     * @return List of tags\n     */\n    public static String[] getSupportedFeatureTags(boolean richcall, RcsSettings rcsSettings) {\n        List<String> tags = new ArrayList<>();\n        List<String> icsiTags = new ArrayList<>();\n        List<String> iariTags = new ArrayList<>();\n        // Video share support\n        if (rcsSettings.isVideoSharingSupported() && richcall\n                && (NetworkUtils.getNetworkAccessType() >= NetworkUtils.NETWORK_ACCESS_3G)) {\n            tags.add(FeatureTags.FEATURE_3GPP_VIDEO_SHARE);\n        }\n        // Chat support\n        if (rcsSettings.isImSessionSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_CHAT);\n        }\n        // FT support\n        if (rcsSettings.isFileTransferSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_FT);\n        }\n        // FT over HTTP support\n        if (rcsSettings.isFileTransferHttpSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_FT_HTTP);\n        }\n        // Image share support\n        if (rcsSettings.isImageSharingSupported() && richcall) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_IMAGE_SHARE);\n        }\n        // Presence discovery support\n        if (rcsSettings.isPresenceDiscoverySupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_PRESENCE_DISCOVERY);\n        }\n        // Social presence support\n        if (rcsSettings.isSocialPresenceSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_SOCIAL_PRESENCE);\n        }\n        // Geolocation push support\n        if (rcsSettings.isGeoLocationPushSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_GEOLOCATION_PUSH);\n        }\n        // FT thumbnail support\n        if (rcsSettings.isFileTransferThumbnailSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_FT_THUMBNAIL);\n        }\n        // FT S&F support\n        if (rcsSettings.isFileTransferStoreForwardSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_FT_SF);\n        }\n        // Group chat S&F support\n        if (rcsSettings.isGroupChatStoreForwardSupported()) {\n            iariTags.add(FeatureTags.FEATURE_RCSE_GC_SF);\n        }\n        // IP call support\n        if (rcsSettings.isIPVoiceCallSupported()) {\n            tags.add(FeatureTags.FEATURE_RCSE_IP_VOICE_CALL);\n        }\n        if (rcsSettings.isIPVideoCallSupported()) {\n            tags.add(FeatureTags.FEATURE_RCSE_IP_VIDEO_CALL);\n        }\n        if (rcsSettings.isIPVoiceCallSupported() || rcsSettings.isIPVideoCallSupported()) {\n            icsiTags.add(FeatureTags.FEATURE_3GPP_IP_VOICE_CALL);\n        }\n        // Automata flag\n        if (rcsSettings.isSipAutomata()) {\n            tags.add(FeatureTags.FEATURE_SIP_AUTOMATA);\n        }\n        // Extensions\n        if (rcsSettings.isExtensionsAllowed()) {\n            for (String extension : rcsSettings.getSupportedRcsExtensions()) {\n                if (extension.startsWith(\"gsma.\")) {\n                    icsiTags.add(FeatureTags.FEATURE_RCSE_ICSI_EXTENSION + \".\" + extension);\n                } else {\n                    iariTags.add(FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".\" + extension);\n                }\n            }\n            icsiTags.add(FeatureTags.FEATURE_3GPP_EXTENSION);\n        }\n        // Add IARI prefix\n        if (!iariTags.isEmpty()) {\n            tags.add(FeatureTags.FEATURE_RCSE + \"=\\\"\" + TextUtils.join(\",\", iariTags) + \"\\\"\");\n        }\n        // Add ICSI prefix\n        if (!icsiTags.isEmpty()) {\n            tags.add(FeatureTags.FEATURE_3GPP + \"=\\\"\" + TextUtils.join(\",\", icsiTags) + \"\\\"\");\n        }\n        return tags.toArray(new String[tags.size()]);\n    }\n\n    /**\n     * Extract features tags\n     * \n     * @param msg Message\n     * @return Capabilities\n     */\n    public static Capabilities extractCapabilities(SipMessage msg) {\n        /* Analyze feature tags */\n        Capabilities.CapabilitiesBuilder capaBuilder = new Capabilities.CapabilitiesBuilder();\n        Set<String> tags = msg.getFeatureTags();\n        boolean ipCall_RCSE = false;\n        boolean ipCall_3GPP = false;\n        for (String tag : tags) {\n            if (tag.contains(FeatureTags.FEATURE_3GPP_VIDEO_SHARE)) {\n                capaBuilder.setVideoSharing(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_IMAGE_SHARE)) {\n                capaBuilder.setImageSharing(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_CHAT)) {\n                capaBuilder.setImSession(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_FT)) {\n                capaBuilder.setFileTransferMsrp(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_FT_HTTP)) {\n                capaBuilder.setFileTransferHttp(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_OMA_IM)) {\n                /* Support both IM & FT services */\n                capaBuilder.setImSession(true).setFileTransferMsrp(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_PRESENCE_DISCOVERY)) {\n                capaBuilder.setPresenceDiscovery(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_SOCIAL_PRESENCE)) {\n                capaBuilder.setSocialPresence(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_GEOLOCATION_PUSH)) {\n                capaBuilder.setGeolocationPush(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_FT_THUMBNAIL)) {\n                capaBuilder.setFileTransferThumbnail(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_IP_VOICE_CALL)) {\n                if (ipCall_3GPP) {\n                    capaBuilder.setIpVoiceCall(true);\n                } else {\n                    ipCall_RCSE = true;\n                }\n            } else if (tag.contains(FeatureTags.FEATURE_3GPP_IP_VOICE_CALL)) {\n                if (ipCall_RCSE) {\n                    capaBuilder.setIpVoiceCall(true);\n                } else {\n                    ipCall_3GPP = true;\n                }\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_IP_VIDEO_CALL)) {\n                capaBuilder.setIpVideoCall(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_FT_SF)) {\n                capaBuilder.setFileTransferStoreForward(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_GC_SF)) {\n                capaBuilder.setGroupChatStoreForward(true);\n\n            } else if (tag.contains(FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".ext\")\n                    || tag.contains(FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".mnc\")\n                    || tag.contains(FeatureTags.FEATURE_RCSE_ICSI_EXTENSION + \".gsma\")) {\n                // Support an RCS extension\n                String serviceId = extractServiceId(tag);\n                if (!\"gsma.rcs.extension\".equals(serviceId)) {\n                    capaBuilder.addExtension(serviceId);\n                }\n            } else if (tag.contains(FeatureTags.FEATURE_SIP_AUTOMATA)) {\n                capaBuilder.setSipAutomata(true);\n            }\n        }\n        /* Analyze SDP part */\n        byte[] content = msg.getContentBytes();\n        if (content != null) {\n            SdpParser parser = new SdpParser(content);\n            /* Get supported video codecs */\n            Vector<MediaDescription> mediaVideo = parser.getMediaDescriptions(\"video\");\n            Vector<String> videoCodecs = new Vector<>();\n            for (int i = 0; i < mediaVideo.size(); i++) {\n                MediaDescription desc = mediaVideo.get(i);\n                MediaAttribute attr = desc.getMediaAttribute(\"rtpmap\");\n                if (attr != null) {\n                    String rtpmap = attr.getValue();\n                    String encoding = rtpmap.substring(rtpmap.indexOf(desc.mPayload)\n                            + desc.mPayload.length() + 1);\n                    String codec = encoding.toLowerCase().trim();\n                    int index = encoding.indexOf(\"/\");\n                    if (index != -1) {\n                        codec = encoding.substring(0, index);\n                    }\n                    if (MediaRegistry.isCodecSupported(codec)) {\n                        videoCodecs.add(codec);\n                    }\n                }\n            }\n            if (videoCodecs.size() == 0) {\n                /* No video codec supported between me and the remote contact */\n                capaBuilder.setVideoSharing(false);\n            }\n            // Check supported image formats\n            Vector<MediaDescription> mediaImage = parser.getMediaDescriptions(\"message\");\n            Vector<String> imgFormats = new Vector<>();\n            for (int i = 0; i < mediaImage.size(); i++) {\n                MediaDescription desc = mediaImage.get(i);\n                MediaAttribute attr = desc.getMediaAttribute(\"accept-types\");\n                if (attr != null) {\n                    String[] types = attr.getValue().split(\" \");\n                    for (String fmt : types) {\n                        if ((fmt != null) && MimeManager.getInstance().isMimeTypeSupported(fmt)) {\n                            imgFormats.addElement(fmt);\n                        }\n                    }\n                }\n            }\n            if (imgFormats.size() == 0) {\n                /* No image format supported between me and the remote contact */\n                capaBuilder.setImageSharing(false);\n            }\n        }\n        long timestamp = System.currentTimeMillis();\n        capaBuilder.setTimestampOfLastResponse(timestamp);\n        capaBuilder.setTimestampOfLastRequest(timestamp);\n        return capaBuilder.build();\n    }\n\n    /**\n     * Build supported SDP part\n     * \n     * @param ipAddress Local IP address\n     * @param richcall Rich call supported\n     * @param rcsSettings RCS settings accessor\n     * @return SDP\n     */\n    public static String buildSdp(String ipAddress, boolean richcall, RcsSettings rcsSettings) {\n        String sdp = null;\n        if (richcall) {\n            boolean video = rcsSettings.isVideoSharingSupported()\n                    && NetworkUtils.getNetworkAccessType() >= NetworkUtils.NETWORK_ACCESS_3G;\n            boolean image = rcsSettings.isImageSharingSupported();\n            boolean geoloc = rcsSettings.isGeoLocationPushSupported();\n            if (video | image) {\n                String mimeTypes = null;\n                String protocol = null;\n                String selector = null;\n                long maxSize = 0;\n                String media = null;\n                // Add video config\n                if (video) {\n                    // Get supported video formats\n                    Vector<VideoFormat> videoFormats = MediaRegistry.getSupportedVideoFormats();\n                    StringBuilder videoSharingConfig = new StringBuilder();\n                    for (VideoFormat videoFormat : videoFormats) {\n                        videoSharingConfig.append(\"m=video 0 RTP/AVP \")\n                                .append(videoFormat.getPayload()).append(SipUtils.CRLF);\n                        videoSharingConfig.append(\"a=rtpmap:\").append(videoFormat.getPayload())\n                                .append(\" \").append(videoFormat.getCodec()).append(SipUtils.CRLF);\n                    }\n                    media = videoSharingConfig.toString();\n                }\n                // Add image and geoloc config\n                if (image || geoloc) {\n                    StringBuilder supportedTransferFormats = new StringBuilder();\n                    // Get supported image formats\n                    Set<String> imageMimeTypes = MimeManager.getInstance()\n                            .getSupportedImageMimeTypes();\n                    for (String imageMimeType : imageMimeTypes) {\n                        supportedTransferFormats.append(imageMimeType).append(\" \");\n                    }\n                    // Get supported geoloc\n                    if (geoloc) {\n                        supportedTransferFormats.append(GeolocContent.ENCODING);\n                    }\n                    mimeTypes = supportedTransferFormats.toString().trim();\n                    protocol = SdpUtils.MSRP_PROTOCOL;\n                    selector = \"\";\n                    maxSize = ImageTransferSession.getMaxImageSharingSize(rcsSettings);\n                }\n                sdp = SdpUtils.buildCapabilitySDP(ipAddress, protocol, mimeTypes, selector, media,\n                        maxSize);\n            }\n        }\n        return sdp;\n    }\n\n    /**\n     * Extract service ID from feature tag extension\n     * \n     * @param featureTag Feature tag\n     * @return Service ID\n     */\n    public static String extractServiceId(String featureTag) {\n        String[] values = featureTag.split(\"=\");\n        String value = StringUtils.removeQuotes(values[1]);\n        if (featureTag.contains(FeatureTags.FEATURE_RCSE_IARI_EXTENSION)) {\n            return value.substring(FeatureTags.FEATURE_RCSE_IARI_EXTENSION.length() + 1,\n                    value.length());\n        } else {\n            return value.substring(FeatureTags.FEATURE_RCSE_ICSI_EXTENSION.length() + 1,\n                    value.length());\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/DiscoveryManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Discovery manager interface\n * \n * @author jexa7410\n */\npublic interface DiscoveryManager {\n    /**\n     * Request contact capabilities\n     * \n     * @param contact Remote contact identifier\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void requestCapabilities(ContactId contact) throws PayloadException, NetworkException,\n            ContactManagerException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/ExternalCapabilityMonitoring.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.service.extension.ServiceExtensionManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.capability.CapabilityService;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PackageManager.NameNotFoundException;\nimport android.os.Bundle;\n\n/**\n * External capability monitoring\n * \n * @author jexa7410\n */\npublic class ExternalCapabilityMonitoring extends BroadcastReceiver {\n\n    private final static Logger sLogger = Logger.getLogger(ExternalCapabilityMonitoring.class\n            .getSimpleName());\n\n    private ServiceExtensionManager mExtensionManager;\n\n    private final Core mCore;\n\n    public ExternalCapabilityMonitoring(Core core, ServiceExtensionManager extensionManager) {\n        mExtensionManager = extensionManager;\n        mCore = core;\n    }\n\n    @Override\n    public void onReceive(final Context ctx, final Intent intent) {\n        mCore.scheduleCoreOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    String action = intent.getAction();\n                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);\n                    if (uid == -1) {\n                        return;\n                    }\n                    if (Intent.ACTION_PACKAGE_ADDED.equals(action)\n                            || Intent.ACTION_PACKAGE_REPLACED.equals(action)\n                            || Intent.ACTION_PACKAGE_CHANGED.equals(action)) {\n                        PackageManager pm = ctx.getPackageManager();\n                        String packageName = intent.getData().getSchemeSpecificPart();\n                        ApplicationInfo appInfo = pm.getApplicationInfo(packageName,\n                                PackageManager.GET_META_DATA);\n                        if (appInfo == null) {\n                            return;\n                        }\n                        Bundle appMeta = appInfo.metaData;\n                        if (appMeta == null) {\n                            return;\n                        }\n                        String exts = appMeta.getString(CapabilityService.INTENT_EXTENSIONS);\n                        if (exts == null) {\n                            return;\n                        }\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(new StringBuilder(\"Add extensions \").append(exts)\n                                    .append(\" for application \").append(uid).toString());\n                        }\n                        mExtensionManager.addNewSupportedExtensions();\n                    } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(new StringBuilder(\"Remove extensions for application \")\n                                    .append(uid).append(\"with action \").append(action).toString());\n                        }\n                        mExtensionManager.removeSupportedExtensions();\n                    }\n                } catch (NameNotFoundException e) {\n                    sLogger.error(\n                            new StringBuilder(\"Unable to find application for intent action : \")\n                                    .append(intent.getAction()).toString(), e);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\n                                    \"Unable to handle connection event for intent action : \")\n                                    .append(intent.getAction()).toString(), e);\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/OptionsManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.capability.OptionsRequestTask.IOptionsRequestTaskListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * Capability discovery manager using options procedure\n * \n * @author jexa7410\n */\npublic class OptionsManager implements DiscoveryManager {\n    /**\n     * Max number of threads for background processing\n     */\n    private final static int MAX_PROCESSING_THREADS = 15;\n\n    private ImsModule mImsModule;\n\n    /**\n     * Thread pool to request capabilities in background\n     */\n    private ExecutorService mThreadPool;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private final static Logger sLogger = Logger.getLogger(OptionsManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings RCS settings accessor\n     * @param contactManager Contact manager accessor\n     */\n    public OptionsManager(ImsModule parent, RcsSettings rcsSettings, ContactManager contactManager) {\n        mImsModule = parent;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n    }\n\n    /**\n     * Start the manager\n     */\n    public void start() {\n        mThreadPool = Executors.newFixedThreadPool(MAX_PROCESSING_THREADS);\n    }\n\n    /**\n     * Stop the manager\n     */\n    public void stop() {\n        mThreadPool.shutdownNow();\n    }\n\n    /**\n     * Request capabilities in background\n     * \n     * @param contact Contact ID\n     * @param listener callback to execute when response is received\n     */\n    private void requestCapabilitiesInBackground(ContactId contact,\n            IOptionsRequestTaskListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Request capabilities in background for \".concat(contact.toString()));\n        }\n        boolean richcall = mImsModule.getRichcallService().isCallConnectedWith(contact);\n        OptionsRequestTask task = new OptionsRequestTask(mImsModule, contact,\n                CapabilityUtils.getSupportedFeatureTags(richcall, mRcsSettings), mRcsSettings,\n                mContactManager, listener);\n        if (mThreadPool.isShutdown()) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Request capabilities in background for \" + contact\n                        + \" rejected: manager is stopped!\");\n            }\n            return;\n        }\n        mThreadPool.submit(task);\n    }\n\n    /**\n     * Check if refresh of capability is authorized\n     * \n     * @param timestampOfLastRequest timestamp of last capability request in milliseconds\n     * @return true if capability request is authorized\n     */\n    private boolean isCapabilityRefreshAuthorized(long timestampOfLastRequest) {\n        long currentTime = System.currentTimeMillis();\n        /*\n         * Is current time before last capability request ? (may occur if current time has been\n         * updated)\n         */\n        if (currentTime < timestampOfLastRequest) {\n            return true;\n        }\n        return (currentTime > (timestampOfLastRequest + mRcsSettings.getCapabilityRefreshTimeout()));\n    }\n\n    /**\n     * Request contact capabilities\n     * \n     * @param contact Remote contact identifier\n     */\n    public void requestCapabilities(ContactId contact) {\n        boolean logActivated = sLogger.isActivated();\n        if (contact == null || contact.equals(ImsModule.getImsUserProfile().getUsername())) {\n            return;\n        }\n        Capabilities capabilities = mContactManager.getContactCapabilities(contact);\n        if (capabilities == null) {\n            if (logActivated) {\n                sLogger.debug(\"No capability exist for \".concat(contact.toString()));\n            }\n            requestCapabilitiesInBackground(contact, null);\n            mContactManager.updateCapabilitiesTimeLastRequest(contact);\n        } else {\n            if (logActivated) {\n                sLogger.debug(\"Capabilities exist for \".concat(contact.toString()));\n            }\n            if (isCapabilityRefreshAuthorized(capabilities.getTimestampOfLastRequest())) {\n                if (logActivated) {\n                    sLogger.debug(\"Request capabilities for \".concat(contact.toString()));\n                }\n                requestCapabilitiesInBackground(contact, null);\n                mContactManager.updateCapabilitiesTimeLastRequest(contact);\n            }\n        }\n    }\n\n    /**\n     * Request capabilities for a set of contacts\n     * \n     * @param contacts Contact set\n     */\n    public void requestCapabilities(Set<ContactId> contacts) {\n        for (ContactId contact : contacts) {\n            requestCapabilities(contact);\n        }\n    }\n\n    /**\n     * Receive a capability request (options procedure)\n     * \n     * @param options Received options message\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    public void onCapabilityRequestReceived(SipRequest options) throws PayloadException,\n            NetworkException, ContactManagerException {\n        String sipId = SipUtils.getAssertedIdentity(options);\n        try {\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(sipId);\n            if (number == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(new StringBuilder(\"Invalid contact from capability request '\")\n                            .append(sipId).append(\"'\").toString());\n                }\n                return;\n            }\n            ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"OPTIONS request received from \".concat(contact.toString()));\n            }\n\n            // Create 200 OK response\n            String ipAddress = mImsModule.getCurrentNetworkInterface().getNetworkAccess()\n                    .getIpAddress();\n            boolean richcall = mImsModule.getRichcallService().isCallConnectedWith(contact);\n            SipResponse resp = SipMessageFactory.create200OkOptionsResponse(options, mImsModule\n                    .getSipManager().getSipStack().getContact(),\n                    CapabilityUtils.getSupportedFeatureTags(richcall, mRcsSettings),\n                    CapabilityUtils.buildSdp(ipAddress, richcall, mRcsSettings));\n\n            // Send 200 OK response\n            mImsModule.getSipManager().sendSipResponse(resp);\n            // Read features tag in the request\n            Capabilities capabilities = CapabilityUtils.extractCapabilities(options);\n\n            // Update capabilities in database\n            if (capabilities.isImSessionSupported()) {\n                // RCS-e contact\n                mContactManager.setContactCapabilities(contact, capabilities,\n                        RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE);\n            } else {\n                // Not a RCS-e contact\n                mContactManager.setContactCapabilities(contact, capabilities, RcsStatus.NOT_RCS,\n                        RegistrationState.UNKNOWN);\n            }\n\n            // Notify listener\n            mImsModule.getCapabilityService().onReceivedCapabilities(contact, capabilities);\n\n        } catch (FileAccessException e) {\n            throw new PayloadException(new StringBuilder(\"Failed to receive capability request '\")\n                    .append(sipId).append(\"'\").toString(), e);\n        }\n    }\n\n    /**\n     * Requests capabilities for a set of contacts\n     * \n     * @param contacts Set of contacts to query.\n     * @param callback Callback to execute once all contacts have been queried or null if caller\n     *            does need to be notified\n     */\n    public void requestCapabilities(Set<ContactId> contacts, final IOptionsManagerListener callback) {\n        IOptionsRequestTaskListener listener = null;\n        final Set<ContactId> contactsToQuery = new HashSet<ContactId>(contacts);\n        if (callback != null) {\n            listener = new IOptionsRequestTaskListener() {\n\n                @Override\n                public void endOfOptionsRequestTask(ContactId contact) {\n                    synchronized (contactsToQuery) {\n                        contactsToQuery.remove(contact);\n                        if (contactsToQuery.isEmpty()) {\n                            callback.endOfCapabilitiesRequest();\n                        }\n                    }\n                }\n            };\n        }\n        for (ContactId contact : contacts) {\n            requestCapabilitiesInBackground(contact, listener);\n        }\n    }\n\n    /**\n     * Interface listener for OptionsManager\n     */\n    public interface IOptionsManagerListener {\n        /**\n         * Callback to notify end of capabilities request\n         */\n        public void endOfCapabilitiesRequest();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/OptionsRequestTask.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ContactInfo;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * Options request task\n * \n * @author Jean-Marc AUFFRET\n */\npublic class OptionsRequestTask implements Runnable {\n    private final ImsModule mImsModule;\n\n    private final ContactId mContact;\n\n    private final String[] mFeatureTags;\n\n    private SipDialogPath mDialogPath;\n\n    private final SessionAuthenticationAgent mAuthenticationAgent;\n\n    private final static Logger sLogger = Logger.getLogger(OptionsRequestTask.class.getName());\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private final IOptionsRequestTaskListener mCallback;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param contact Remote contact identifier\n     * @param featureTags Feature tags\n     * @param rcsSettings accessor to RCS settings\n     * @param contactManager accessor to contact manager\n     * @param callback Callback to be executed at end of task\n     */\n    public OptionsRequestTask(ImsModule parent, ContactId contact, String[] featureTags,\n            RcsSettings rcsSettings, ContactManager contactManager,\n            IOptionsRequestTaskListener callback) {\n        mImsModule = parent;\n        mContact = contact;\n        mFeatureTags = featureTags;\n        mAuthenticationAgent = new SessionAuthenticationAgent(mImsModule);\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n        mCallback = callback;\n    }\n\n    @Override\n    public void run() {\n        try {\n            sendOptions();\n        } catch (ContactManagerException | PayloadException e) {\n            sLogger.error(\"Options request failed for contact : \" + mContact, e);\n            handleError(new CapabilityError(CapabilityError.OPTIONS_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new CapabilityError(CapabilityError.OPTIONS_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Options request failed for contact : \" + mContact, e);\n        } finally {\n            if (mCallback != null) {\n                try {\n                    mCallback.endOfOptionsRequestTask(mContact);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to notify end of options request for contact : \"\n                            + mContact, e);\n                }\n            }\n        }\n    }\n\n    /**\n     * Send an OPTIONS request\n     * \n     * @throws PayloadException\n     * @throws ContactManagerException\n     * @throws NetworkException\n     */\n    private void sendOptions() throws PayloadException, NetworkException, ContactManagerException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send an options request to \".concat(mContact.toString()));\n        }\n        if (!mImsModule.getCurrentNetworkInterface().isRegistered()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"IMS not registered, do nothing\");\n            }\n            return;\n        }\n        // @FIXME: This should be an URI instead of String\n        String contactUri = PhoneUtils.formatContactIdToUri(mContact).toString();\n        mDialogPath = new SipDialogPath(mImsModule.getSipManager().getSipStack(), mImsModule\n                .getSipManager().getSipStack().generateCallId(), 1, contactUri, ImsModule\n                .getImsUserProfile().getPublicUri(), contactUri, mImsModule.getSipManager()\n                .getSipStack().getServiceRoutePath(), mRcsSettings);\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send first OPTIONS\");\n        }\n        SipRequest options = SipMessageFactory.createOptions(mDialogPath, mFeatureTags);\n\n        sendAndWaitOptions(options);\n    }\n\n    /**\n     * Sends OPTIONS message and waits for response\n     * \n     * @param options SIP OPTIONS\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void sendAndWaitOptions(SipRequest options) throws PayloadException, NetworkException,\n            ContactManagerException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send OPTIONS\");\n            }\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSipMessageAndWait(options);\n            final int statusCode = ctx.getStatusCode();\n            if (ctx.isSipResponse()) {\n                switch (statusCode) {\n                    case Response.OK:\n                        handle200OK(ctx);\n                        break;\n                    case Response.PROXY_AUTHENTICATION_REQUIRED:\n                        handle407Authentication(ctx);\n                        break;\n                    case Response.REQUEST_TIMEOUT:\n                        /* Intentional fall through */\n                    case Response.TEMPORARILY_UNAVAILABLE:\n                        handleUserNotRegistered();\n                        break;\n                    case Response.NOT_FOUND:\n                        handleUserNotFound();\n                        break;\n                    default:\n                        handleError(new CapabilityError(CapabilityError.OPTIONS_FAILED,\n                                String.valueOf(statusCode) + ' ' + ctx.getReasonPhrase()));\n                        break;\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No response received for OPTIONS\");\n                }\n                /* No response received: timeout */\n                handleError(new CapabilityError(CapabilityError.OPTIONS_FAILED,\n                        String.valueOf(statusCode) + ' ' + ctx.getReasonPhrase()));\n            }\n        } catch (FileAccessException e) {\n            throw new PayloadException(\"Failed to send OPTIONS!\", e);\n        }\n    }\n\n    /**\n     * Handle user not registered\n     * \n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    private void handleUserNotRegistered() throws ContactManagerException, FileAccessException {\n        /* 408 or 480 response received */\n        if (sLogger.isActivated()) {\n            sLogger.info(\"User \" + mContact + \" is not registered\");\n        }\n        ContactInfo info = mContactManager.getContactInfo(mContact);\n        if (RcsStatus.NO_INFO.equals(info.getRcsStatus())) {\n            /*\n             * If there is no info on this contact: update the database with default capabilities\n             */\n            mContactManager.setContactCapabilities(mContact, Capabilities.sDefaultCapabilities,\n                    RcsStatus.NO_INFO, RegistrationState.OFFLINE);\n        } else {\n            /*\n             * There are info on this contact: update the database with its previous info and set\n             * the registration state to offline.\n             */\n            mContactManager.setContactCapabilities(mContact, info.getCapabilities(),\n                    info.getRcsStatus(), RegistrationState.OFFLINE);\n\n            mImsModule.getCapabilityService().onReceivedCapabilities(mContact,\n                    info.getCapabilities());\n        }\n    }\n\n    /**\n     * Handle user not found\n     * \n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    private void handleUserNotFound() throws ContactManagerException, FileAccessException {\n        /* 404 response received */\n        if (sLogger.isActivated()) {\n            sLogger.info(\"User \" + mContact + \" is not found\");\n        }\n        /* The contact is not RCS */\n        mContactManager.setContactCapabilities(mContact, Capabilities.sDefaultCapabilities,\n                RcsStatus.NOT_RCS, RegistrationState.UNKNOWN);\n        mImsModule.getCapabilityService().onReceivedCapabilities(mContact,\n                Capabilities.sDefaultCapabilities);\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param ctx SIP transaction context\n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    private void handle200OK(SipTransactionContext ctx) throws ContactManagerException,\n            FileAccessException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received for \" + mContact);\n        }\n\n        /* Read capabilities */\n        SipResponse resp = ctx.getSipResponse();\n        Capabilities capabilities = CapabilityUtils.extractCapabilities(resp);\n\n        /* Update the database capabilities */\n        if (capabilities.isImSessionSupported()) {\n            /* The contact is RCS capable */\n\n            /*\n             * Note RCS5.1 chapter 2.7.1.1: \"a user shall be considered as unregistered when ... a\n             * response that included the automata tag defined in [RFC3840]\".\n             */\n            if (capabilities.isSipAutomata()) {\n                mContactManager.setContactCapabilities(mContact, capabilities,\n                        RcsStatus.RCS_CAPABLE, RegistrationState.OFFLINE);\n            } else {\n                mContactManager.setContactCapabilities(mContact, capabilities,\n                        RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE);\n            }\n        } else {\n            /* The contact is not RCS */\n            mContactManager.setContactCapabilities(mContact, capabilities, RcsStatus.NOT_RCS,\n                    RegistrationState.UNKNOWN);\n        }\n        mImsModule.getCapabilityService().onReceivedCapabilities(mContact, capabilities);\n    }\n\n    /**\n     * Handle 407 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private void handle407Authentication(SipTransactionContext ctx) throws PayloadException,\n            NetworkException, ContactManagerException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"407 response received\");\n            }\n\n            SipResponse resp = ctx.getSipResponse();\n\n            mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n\n            mDialogPath.incrementCseq();\n\n            /* Create a second OPTIONS request with the right token */\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send second OPTIONS\");\n            }\n            SipRequest options = SipMessageFactory.createOptions(mDialogPath, mFeatureTags);\n\n            mAuthenticationAgent.setProxyAuthorizationHeader(options);\n\n            sendAndWaitOptions(options);\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n\n        }\n    }\n\n    /**\n     * Handle error response\n     * \n     * @param error Error\n     */\n    private void handleError(CapabilityError error) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Options has failed for contact \" + mContact + \": \"\n                        + error.getErrorCode() + \", reason=\" + error.getMessage());\n            }\n            ContactInfo info = mContactManager.getContactInfo(mContact);\n            if (RcsStatus.NO_INFO.equals(info.getRcsStatus())) {\n                /*\n                 * If there is no info on this contact: update the database with default\n                 * capabilities\n                 */\n                mContactManager.setContactCapabilities(mContact, Capabilities.sDefaultCapabilities,\n                        RcsStatus.NO_INFO, RegistrationState.OFFLINE);\n            } else {\n                /*\n                 * There are info on this contact: update the database capabilities time of last\n                 * request\n                 */\n                mContactManager.updateCapabilitiesTimeLastRequest(mContact);\n            }\n        } catch (ContactManagerException | FileAccessException e) {\n            sLogger.error(\n                    \"Failed to handle Options error for contact \" + mContact + \": \"\n                            + error.getErrorCode() + \", reason=\" + error.getMessage(), e);\n        }\n    }\n\n    /**\n     * Interface listener for OptionRequestTask\n     */\n    public interface IOptionsRequestTaskListener {\n        /**\n         * Callback to notify end of options request task\n         * \n         * @param contact ID\n         */\n        void endOfOptionsRequestTask(ContactId contact);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/PollingManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\n/**\n * Polling manager which updates capabilities periodically\n * \n * @author Jean-Marc AUFFRET\n */\npublic class PollingManager extends PeriodicRefresher {\n\n    /**\n     * Capability service\n     */\n    private final CapabilityService mImsService;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContatManager;\n\n    /**\n     * The logger\n     */\n    private final static Logger sLogger = Logger.getLogger(PollingManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS service\n     * @param rcsSettings\n     * @param contactManager\n     */\n    public PollingManager(CapabilityService parent, RcsSettings rcsSettings,\n            ContactManager contactManager) {\n        mImsService = parent;\n        mRcsSettings = rcsSettings;\n        mContatManager = contactManager;\n    }\n\n    /**\n     * Start polling\n     */\n    public void start() {\n        long pollingPeriod = mRcsSettings.getCapabilityPollingPeriod();\n        if (pollingPeriod == 0) {\n            return;\n        }\n        startTimer(System.currentTimeMillis(), pollingPeriod);\n    }\n\n    /**\n     * Stop polling\n     */\n    public void stop() {\n        stopTimer();\n    }\n\n    /**\n     * Update processing\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public void periodicProcessing() throws PayloadException, NetworkException,\n            ContactManagerException {\n        // Make a registration\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Execute new capabilities update\");\n        }\n\n        // Update all contacts capabilities if refresh timeout has not expired\n        Set<ContactId> contacts = mContatManager.getAllContactsFromRcsContactProvider();\n        for (ContactId contact : contacts) {\n            requestContactCapabilities(contact);\n        }\n\n        // Restart timer\n        startTimer(System.currentTimeMillis(), mRcsSettings.getCapabilityPollingPeriod());\n    }\n\n    /**\n     * Request contact capabilities\n     * \n     * @param contact Contact identifier\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    private void requestContactCapabilities(ContactId contact) throws PayloadException,\n            NetworkException, ContactManagerException {\n        // Read capabilities from the database\n        Capabilities capabilities = mContatManager.getContactCapabilities(contact);\n        boolean locActivated = sLogger.isActivated();\n        if (capabilities == null) {\n            if (locActivated) {\n                sLogger.debug(\"No capability exist for \".concat(contact.toString()));\n            }\n\n            // New contact: request capabilities from the network\n            mImsService.getOptionsManager().requestCapabilities(contact);\n            return;\n\n        }\n        if (isCapabilityRefreshRequired(capabilities.getTimestampOfLastResponse(), mRcsSettings)) {\n            if (locActivated) {\n                sLogger.debug(\"Capabilities have expired for \".concat(contact.toString()));\n            }\n\n            // Capabilities are too old: request capabilities from the network\n            if (capabilities.isPresenceDiscoverySupported()) {\n                // If contact supports capability discovery via presence, use the selected\n                // discoveryManager\n                mImsService.getAnonymousFetchManager().requestCapabilities(contact);\n            } else {\n                // The contact only supports OPTIONS requests\n                mImsService.getOptionsManager().requestCapabilities(contact);\n            }\n        } else {\n            if (locActivated) {\n                sLogger.debug(\"Capabilities exist for \".concat(contact.toString()));\n            }\n        }\n    }\n\n    /**\n     * Check if refresh of capability is required\n     * \n     * @param timestampOfLastResponse time of last capability response in milliseconds\n     * @param rcsSettings\n     * @return true if capability refresh is required\n     */\n    private boolean isCapabilityRefreshRequired(long timestampOfLastResponse,\n            RcsSettings rcsSettings) {\n        long now = System.currentTimeMillis();\n        // Is current time before last capability response ? (may occur if system time has been\n        // modified)\n        if (now < timestampOfLastResponse) {\n            return true;\n        }\n        // Is current time after capability expiration time ?\n        return (now > (timestampOfLastResponse + rcsSettings.getCapabilityExpiryTimeout()));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/capability/SyncContactTask.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.capability;\n\nimport com.gsma.rcs.addressbook.AddressBookEventListener;\nimport com.gsma.rcs.addressbook.AddressBookManager;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.service.ContactInfo;\nimport com.gsma.rcs.core.ims.service.capability.OptionsManager.IOptionsManagerListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * A task to request options to new contacts.\n */\npublic class SyncContactTask implements Runnable {\n\n    private final ContactManager mContactManager;\n\n    private final AddressBookManager mAddressBookManager;\n\n    private final PollingManager mPollingManager;\n\n    private final OptionsManager mOptionsManager;\n\n    private final AddressBookEventListener mAddressBookEventListener;\n\n    private final ISyncContactTaskListener mSyncContactTaskListener;\n\n    private static final int MAX_CONTACTS_TO_DISPLAY = 10;\n\n    private final static Logger sLogger = Logger.getLogger(SyncContactTask.class.getSimpleName());\n\n    /**\n     * A task to synchronize capabilities for new contacts\n     * \n     * @param syncContactTaskListener Listener on this task\n     * @param addressBookEventListener Listener on address book events\n     * @param contactManager Contact manager accessor\n     * @param addressBookManager Address book manager instance\n     * @param pollingManager Polling manager instance\n     * @param optionsManager Options manager instance\n     */\n    public SyncContactTask(ISyncContactTaskListener syncContactTaskListener,\n            AddressBookEventListener addressBookEventListener, ContactManager contactManager,\n            AddressBookManager addressBookManager, PollingManager pollingManager,\n            OptionsManager optionsManager) {\n        super();\n        mSyncContactTaskListener = syncContactTaskListener;\n        mAddressBookEventListener = addressBookEventListener;\n        mContactManager = contactManager;\n        mAddressBookManager = addressBookManager;\n        mPollingManager = pollingManager;\n        mOptionsManager = optionsManager;\n    }\n\n    @Override\n    public void run() {\n        try {\n            /* Stop listening to address book changes */\n            mAddressBookManager.removeAddressBookListener(mAddressBookEventListener);\n\n            mPollingManager.stop();\n\n            final Set<ContactId> treatedContacts = new HashSet<ContactId>();\n            do {\n                final Set<ContactId> unqueriedContacts = aggregateNewContactsAndGetUnqueriedOnes();\n                unqueriedContacts.removeAll(treatedContacts);\n                if (unqueriedContacts.isEmpty()) {\n                    /*\n                     * All contacts are synchronized.\n                     */\n                    mSyncContactTaskListener.endOfSyncContactTask();\n                    return;\n                }\n\n                if (sLogger.isActivated()) {\n                    int nbOfContactsToQuery = unqueriedContacts.size();\n                    if (nbOfContactsToQuery > MAX_CONTACTS_TO_DISPLAY) {\n                        sLogger.debug(\"Synchronize capabilities for \" + nbOfContactsToQuery\n                                + \" contacts\");\n                    } else {\n                        sLogger.debug(\"Synchronize capabilities for contacts \".concat(Arrays\n                                .toString(unqueriedContacts.toArray())));\n                    }\n                }\n                mOptionsManager.requestCapabilities(unqueriedContacts,\n                        new IOptionsManagerListener() {\n\n                            @Override\n                            public void endOfCapabilitiesRequest() {\n                                synchronized (unqueriedContacts) {\n                                    unqueriedContacts.notify();\n                                }\n                            }\n                        });\n                synchronized (unqueriedContacts) {\n                    try {\n                        unqueriedContacts.wait();\n                        treatedContacts.addAll(unqueriedContacts);\n                    } catch (InterruptedException e) {\n                        return;\n                    }\n                }\n            } while (true);\n        } catch (ContactManagerException e) {\n            sLogger.error(\"Failed to synchronize contacts!\", e);\n        } catch (FileAccessException e) {\n            sLogger.error(\"Failed to synchronize contacts!\", e);\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to synchronize contacts!\", e);\n        }\n    }\n\n    /**\n     * Interface listener for Sync contact task\n     */\n    public interface ISyncContactTaskListener {\n        /**\n         * Callback to notify end of contact synchronization\n         */\n        public void endOfSyncContactTask();\n    }\n\n    /**\n     * Gets contacts not associated with RCS raw contact (i.e. existing in native address book but\n     * without entry in RCS aggregation table)\n     * \n     * @param nativeContacts map of contact IDs from the native address book\n     * @param rcsContacts set of contact from the RCS contact provider\n     * @return\n     */\n    private Set<ContactId> getContactsNotAssociatedWithRcsRawContact(\n            Map<ContactId, Set<Long>> nativeContacts, Set<ContactId> rcsContacts) {\n        Set<ContactId> result = new HashSet<ContactId>();\n        for (Entry<ContactId, Set<Long>> nativeContactEntry : nativeContacts.entrySet()) {\n            ContactId nativeContact = nativeContactEntry.getKey();\n            if (rcsContacts.contains(nativeContact)) {\n                Set<Long> nativeRawContactIds = nativeContactEntry.getValue();\n                for (Long nativeRawContactId : nativeRawContactIds) {\n                    if (!mContactManager.isAssociatedRcsRawContact(nativeRawContactId,\n                            nativeContact)) {\n                        /*\n                         * Contact is known from RCS contact but without association between RCS raw\n                         * contact and native row contact.\n                         */\n                        result.add(nativeContact);\n                        break;\n                    }\n                }\n            } else {\n                /* Contact is not known from RCS contact */\n                result.add(nativeContact);\n            }\n        }\n        return result;\n    }\n\n    private Set<ContactId> aggregateNewContactsAndGetUnqueriedOnes()\n            throws ContactManagerException, FileAccessException {\n        Map<ContactId, Set<Long>> nativeContacts = mContactManager.getAllRawIdsInPhoneAddressBook();\n        /*\n         * Remove my contact since already created in native address book and no need to query for\n         * capabilities.\n         */\n        nativeContacts.remove(ImsModule.getImsUserProfile().getUsername());\n\n        Set<ContactId> rcsContacts = mContactManager.getAllContactsFromRcsContactProvider();\n\n        /*\n         * Get contacts for which RCS contact aggregation is not done.\n         */\n        Set<ContactId> contactsWithNoRcsAggregation = getContactsNotAssociatedWithRcsRawContact(\n                nativeContacts, rcsContacts);\n\n        Set<ContactId> contactsOnlySimAssociated = mContactManager\n                .getContactsOnlySimAssociated(nativeContacts);\n\n        /* Remove contacts which are only SIM associated since they cannot be aggregated */\n        contactsWithNoRcsAggregation.removeAll(contactsOnlySimAssociated);\n\n        for (ContactId contact : contactsWithNoRcsAggregation) {\n            ContactInfo contactInfo = mContactManager.getContactInfo(contact);\n            if (!contactInfo.isRcsContact()) {\n                /* Do not aggregate non RCS contact */\n                continue;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"handleAddressBookHasChanged: aggregate contact \".concat(contact\n                        .toString()));\n            }\n            mContactManager.aggregateContactWithRcsRawContact(contactInfo);\n        }\n\n        Set<ContactId> unqueriedContacts = nativeContacts.keySet();\n        /* Remove all contacts known from RCS contact provider to keep only un-queried contacts */\n        unqueriedContacts.removeAll(rcsContacts);\n        return unqueriedContacts;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/extension/ServiceExtensionManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.extension;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.service.capability.ExternalCapabilityMonitoring;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.text.TextUtils;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * Service extension manager which adds supported extension after having verified some authorization\n * rules.\n * \n * @author Jean-Marc AUFFRET\n * @author YPLO6403\n */\npublic class ServiceExtensionManager {\n\n    private static final String EXTENSION_SEPARATOR = \";\";\n\n    private final static Logger sLogger = Logger.getLogger(ServiceExtensionManager.class\n            .getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    private final Context mCtx;\n\n    private final Core mCore;\n\n    private ExternalCapabilityMonitoring mExternalCapabilityMonitoring;\n\n    private ExecutorService mUpdateExecutor;\n\n    private final SupportedExtensionUpdater mSupportedExtensionUpdater;\n\n    /**\n     * Monitor the application package changes to update RCS supported extensions\n     * \n     * @param imsModule The IMS module\n     * @param ctx The app context\n     * @param core The core instance\n     * @param rcsSettings The RCS settigns accessor\n     */\n    public ServiceExtensionManager(ImsModule imsModule, Context ctx, Core core,\n            RcsSettings rcsSettings) {\n        mCtx = ctx;\n        mCore = core;\n        mRcsSettings = rcsSettings;\n        mSupportedExtensionUpdater = new SupportedExtensionUpdater(mCtx, imsModule, mRcsSettings,\n                this);\n    }\n\n    /**\n     * Starts extension manager\n     */\n    public void start() {\n        mUpdateExecutor = Executors.newSingleThreadExecutor();\n        updateSupportedExtensions();\n        if (mExternalCapabilityMonitoring == null) {\n            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);\n            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);\n            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);\n            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);\n            filter.addDataScheme(\"package\");\n            mExternalCapabilityMonitoring = new ExternalCapabilityMonitoring(mCore, this);\n            mCtx.registerReceiver(mExternalCapabilityMonitoring, filter);\n        }\n    }\n\n    /**\n     * Stops extension manager\n     */\n    public void stop() {\n        if (mExternalCapabilityMonitoring != null) {\n            mCtx.unregisterReceiver(mExternalCapabilityMonitoring);\n            mExternalCapabilityMonitoring = null;\n        }\n        mUpdateExecutor.shutdownNow();\n    }\n\n    /**\n     * Save supported extensions in database\n     * \n     * @param supportedExts List of supported extensions\n     */\n    public void saveSupportedExtensions(Set<String> supportedExts) {\n        /* Update supported extensions in database */\n        mRcsSettings.setSupportedRcsExtensions(supportedExts);\n    }\n\n    private void updateSupportedExtensions() {\n        mUpdateExecutor.execute(mSupportedExtensionUpdater);\n    }\n\n    /**\n     * Is extension authorized\n     * \n     * @param ext Extension ID\n     * @return Boolean\n     */\n    public boolean isExtensionAuthorized(String ext) {\n        if (!mRcsSettings.isExtensionsAllowed()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Extensions are not allowed\");\n            }\n            return false;\n        }\n        if (mRcsSettings.isExtensionAuthorized(ext)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"No control on extension \".concat(ext));\n            }\n            return true;\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Extension \" + ext + \" is not allowed\");\n            }\n            return false;\n        }\n    }\n\n    /**\n     * Remove supported extensions\n     */\n    public void removeSupportedExtensions() {\n        updateSupportedExtensions();\n    }\n\n    /**\n     * Add supported extensions\n     */\n    public void addNewSupportedExtensions() {\n        updateSupportedExtensions();\n    }\n\n    /**\n     * Extract set of extensions from String\n     * \n     * @param extensions String where extensions are concatenated with a \";\" separator\n     * @return the set of extensions\n     */\n    public static Set<String> getExtensions(String extensions) {\n        Set<String> result = new HashSet<>();\n        if (TextUtils.isEmpty(extensions)) {\n            return result;\n        }\n        String[] extensionList = extensions.split(ServiceExtensionManager.EXTENSION_SEPARATOR);\n        for (String extension : extensionList) {\n            if (!TextUtils.isEmpty(extension) && extension.trim().length() > 0) {\n                result.add(extension);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Concatenate set of extensions into a string\n     * \n     * @param extensions set of extensions\n     * @return String where extensions are concatenated with a \";\" separator\n     */\n    public static String getExtensions(Set<String> extensions) {\n        if (extensions == null || extensions.isEmpty()) {\n            return \"\";\n\n        }\n        StringBuilder result = new StringBuilder();\n        int size = extensions.size();\n        for (String extension : extensions) {\n            if (extension.trim().length() == 0) {\n                --size;\n                continue;\n\n            }\n            result.append(extension);\n            if (--size != 0) {\n                // Not last item : add separator\n                result.append(EXTENSION_SEPARATOR);\n            }\n        }\n        return result.toString();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/extension/SupportedExtensionUpdater.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.extension;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.registration.RegistrationManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.capability.CapabilityService;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * A class to update the supported extensions\n * \n * @author yplo6403\n */\npublic class SupportedExtensionUpdater implements Runnable {\n\n    private final static Logger sLogger = Logger.getLogger(SupportedExtensionUpdater.class\n            .getSimpleName());\n\n    private final Context mCtx;\n\n    private final ServiceExtensionManager mExtensionManager;\n\n    private final ImsModule mImsModule;\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param ctx\n     * @param imsModule\n     * @param rcsSettings\n     * @param extensionManager\n     */\n    public SupportedExtensionUpdater(Context ctx, ImsModule imsModule, RcsSettings rcsSettings,\n            ServiceExtensionManager extensionManager) {\n        mCtx = ctx;\n        mImsModule = imsModule;\n        mRcsSettings = rcsSettings;\n        mExtensionManager = extensionManager;\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Update supported extensions\");\n        }\n        try {\n            Set<String> supportedExts = new HashSet<String>();\n            Set<String> oldSupportedExts = mRcsSettings.getSupportedRcsExtensions();\n            /* Intent query on current installed activities */\n            PackageManager pm = mCtx.getPackageManager();\n            List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_META_DATA);\n            for (ApplicationInfo appInfo : apps) {\n                Bundle appMeta = appInfo.metaData;\n                if (appMeta == null) {\n                    continue;\n                }\n                String exts = appMeta.getString(CapabilityService.INTENT_EXTENSIONS);\n                if (TextUtils.isEmpty(exts)) {\n                    continue;\n                }\n                Set<String> extensions = ServiceExtensionManager.getExtensions(exts);\n                for (String extension : extensions) {\n                    if (mExtensionManager.isExtensionAuthorized(extension)) {\n                        supportedExts.add(extension);\n                    }\n                }\n            }\n            if (oldSupportedExts.equals(supportedExts)) {\n                /* No change in supported extensions: exit */\n                return;\n            }\n            if (sLogger.isActivated()) {\n                StringBuilder sb = new StringBuilder(\"Supported extensions changed!\");\n                Set<String> newExtensions = new HashSet<String>(supportedExts);\n                newExtensions.removeAll(oldSupportedExts);\n                if (!newExtensions.isEmpty()) {\n                    sb.append(\" new=\".concat(Arrays.toString(newExtensions.toArray())));\n                }\n                Set<String> removedExtensions = new HashSet<String>(oldSupportedExts);\n                removedExtensions.removeAll(supportedExts);\n                if (!removedExtensions.isEmpty()) {\n                    sb.append(\" removed=\".concat(Arrays.toString(removedExtensions.toArray())));\n                }\n                sLogger.debug(sb.toString());\n            }\n            /* Update supported extensions in database */\n            mExtensionManager.saveSupportedExtensions(supportedExts);\n            if (!mImsModule.getCore().isStarted()) {\n                /* Stack is not started, don't process this event */\n                return;\n            }\n            RegistrationManager registrationManager = mImsModule.getSipManager()\n                    .getNetworkInterface().getRegistrationManager();\n            if (registrationManager.isRegistered()) {\n                registrationManager.restart();\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to update supported extensions!\", e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/InstantMessagingService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im;\n\nimport static com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession.isFileCapacityAcceptable;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatAutoRejoinTask;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.OriginatingAdhocGroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.OriginatingOneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.RejoinGroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.RestartGroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.TerminatingAdhocGroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.TerminatingOneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.DeliveryExpirationManager;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.core.ims.service.im.chat.standfw.StoreAndForwardManager;\nimport com.gsma.rcs.core.ims.service.im.chat.standfw.TerminatingStoreAndForwardOneToOneChatMessageSession;\nimport com.gsma.rcs.core.ims.service.im.chat.standfw.TerminatingStoreAndForwardOneToOneChatNotificationSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.ImsFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.DownloadFromInviteFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpThumbnail;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FtHttpResumeManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.HttpFileTransferSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.OriginatingHttpFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.OriginatingHttpGroupFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.msrp.OriginatingMsrpFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.msrp.TerminatingMsrpFileSharingSession;\nimport com.gsma.rcs.core.ims.service.upload.FileUploadSession;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.history.GroupChatDequeueTask;\nimport com.gsma.rcs.provider.history.GroupChatTerminalExceptionTask;\nimport com.gsma.rcs.provider.history.HistoryLog;\nimport com.gsma.rcs.provider.history.OneToOneChatDequeueTask;\nimport com.gsma.rcs.provider.messaging.DelayedDisplayNotificationDispatcher;\nimport com.gsma.rcs.provider.messaging.FileTransferDequeueTask;\nimport com.gsma.rcs.provider.messaging.GroupChatDeleteTask;\nimport com.gsma.rcs.provider.messaging.GroupChatMessageDeleteTask;\nimport com.gsma.rcs.provider.messaging.GroupFileTransferDeleteTask;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.messaging.OneToOneChatMessageDeleteTask;\nimport com.gsma.rcs.provider.messaging.OneToOneChatMessageDequeueTask;\nimport com.gsma.rcs.provider.messaging.OneToOneFileTransferDeleteTask;\nimport com.gsma.rcs.provider.messaging.RecreateDeliveryExpirationAlarms;\nimport com.gsma.rcs.provider.messaging.UpdateFileTransferStateAfterUngracefulTerminationTask;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImMsgTech;\nimport com.gsma.rcs.service.GroupChatInviteQueuedParticipantsTask;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.ServerApiMaxAllowedSessionLimitReachedException;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\n\nimport org.xml.sax.SAXException;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.UUID;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.message.Response;\n\n/**\n * Instant messaging services (1-1 chat, group chat and file transfer)\n * \n * @author Jean-Marc AUFFRET\n */\npublic class InstantMessagingService extends ImsService {\n\n    private static final String IM_OPERATION_THREAD_NAME = \"ImOperations\";\n\n    private static final String IM_DELETE_OPERATION_THREAD_NAME = \"ImDeleteOperations\";\n\n    private final Core mCore;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private final MessagingLog mMessagingLog;\n\n    private final HistoryLog mHistoryLog;\n\n    /**\n     * OneToOneChatSessionCache with ContactId as key\n     */\n    private Map<ContactId, OneToOneChatSession> mOneToOneChatSessionCache = new HashMap<>();\n\n    /**\n     * StoreAndForwardMsgSessionCache with ContactId as key\n     */\n    private Map<ContactId, TerminatingStoreAndForwardOneToOneChatMessageSession> mStoreAndForwardMsgSessionCache = new HashMap<>();\n\n    /**\n     * GroupChatSessionCache with ChatId as key\n     */\n    private Map<String, GroupChatSession> mGroupChatSessionCache = new HashMap<>();\n\n    /**\n     * FileSharingSessionCache with FileTransferId as key\n     */\n    private Map<String, FileSharingSession> mFileTransferSessionCache = new HashMap<>();\n\n    /**\n     * FileUploadSessionCache with UploadId as key\n     */\n    private Map<String, FileUploadSession> mFileUploadSessionCache = new HashMap<>();\n\n    /**\n     * GroupChatConferenceSubscriberCache with Conference subscriber's dialog path CallId as key\n     */\n    private Map<String, GroupChatSession> mGroupChatConferenceSubscriberCache = new HashMap<>();\n\n    /**\n     * Group Chat composing status to notify upon MSRP session restart\n     */\n    private final Map<String, Boolean> mGroupChatComposingStatusToNotify = new HashMap<>();\n\n    /**\n     * One-to-One Chat composing status to notify upon MSRP session restart\n     */\n    private final Map<ContactId, Boolean> mOneToOneChatComposingStatusToNotify = new HashMap<>();\n\n    /**\n     * Chat features tags\n     */\n    public final static String[] CHAT_FEATURE_TAGS = {\n        FeatureTags.FEATURE_OMA_IM\n    };\n\n    /**\n     * File transfer features tags\n     */\n    public final static String[] FT_FEATURE_TAGS = {\n        FeatureTags.FEATURE_OMA_IM\n    };\n\n    private final ImdnManager mImdnManager;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final Context mCtx;\n\n    private final StoreAndForwardManager mStoreAndFwdMgr;\n\n    private final DeliveryExpirationManager mDeliveryExpirationManager;\n\n    private static final Logger sLogger = Logger.getLogger(InstantMessagingService.class.getName());\n\n    private static final String sSizeExceededMsg = \"133 Size exceeded\";\n\n    private final Handler mImOperationHandler;\n\n    private final Handler mImDeleteOperationHandler;\n\n    private ChatServiceImpl mChatService;\n\n    private FileTransferServiceImpl mFileTransferService;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings RcsSettings\n     * @param contactsManager ContactManager\n     * @param messagingLog Messaging log accessor\n     * @param historyLog History log accessor\n     * @param localContentResolver local content resolver\n     * @param core Core\n     */\n    public InstantMessagingService(ImsModule parent, RcsSettings rcsSettings,\n            ContactManager contactsManager, MessagingLog messagingLog, HistoryLog historyLog,\n            LocalContentResolver localContentResolver, Context ctx, Core core) {\n        super(parent, true);\n        mCtx = ctx;\n        mCore = core;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactsManager;\n        mMessagingLog = messagingLog;\n        mHistoryLog = historyLog;\n        mLocalContentResolver = localContentResolver;\n        mImOperationHandler = allocateBgHandler(IM_OPERATION_THREAD_NAME);\n        mImDeleteOperationHandler = allocateBgHandler(IM_DELETE_OPERATION_THREAD_NAME);\n        mStoreAndFwdMgr = new StoreAndForwardManager(this, mRcsSettings, mContactManager,\n                mMessagingLog);\n        mImdnManager = new ImdnManager(this, mRcsSettings, mMessagingLog);\n        mDeliveryExpirationManager = new DeliveryExpirationManager(this, ctx, mMessagingLog);\n    }\n\n    private Handler allocateBgHandler(String threadName) {\n        HandlerThread thread = new HandlerThread(threadName);\n        thread.start();\n        return new Handler(thread.getLooper());\n    }\n\n    public void register(ChatServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mChatService = service;\n    }\n\n    public void register(FileTransferServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mFileTransferService = service;\n    }\n\n    /**\n     * Initializes instant messaging service\n     */\n    public void initialize() {\n        mImdnManager.start();\n    }\n\n    public void scheduleImOperation(Runnable runnable) {\n        mImOperationHandler.post(runnable);\n    }\n\n    public void onCoreLayerStarted() {\n        /* Update interrupted file transfer status */\n        scheduleImOperation(new UpdateFileTransferStateAfterUngracefulTerminationTask(\n                mMessagingLog, mFileTransferService));\n        /*\n         * Recreate delivery expiration alarm for one-one chat messages and one-one file transfers\n         * after boot\n         */\n        scheduleImOperation(new RecreateDeliveryExpirationAlarms(mMessagingLog,\n                mDeliveryExpirationManager));\n    }\n\n    private void send403Forbidden(SipRequest request, String warning) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send 403 Forbidden (warning=\" + warning + \")\");\n        }\n        getImsModule().getSipManager().sendSipResponse(\n                SipMessageFactory.createResponse(request, null, Response.FORBIDDEN, warning));\n    }\n\n    @Override\n    public synchronized void start() {\n        if (isServiceStarted()) {\n            return;\n        }\n        setServiceStarted(true);\n        /* Try to auto-rejoin group chats that are still marked as active. */\n        mImOperationHandler.post(new GroupChatAutoRejoinTask(this, mMessagingLog));\n        /* Try to start auto resuming of HTTP file transfers marked as PAUSED_BY_SYSTEM */\n        mImOperationHandler.post(new FtHttpResumeManager(this, mRcsSettings, mMessagingLog,\n                mContactManager));\n        /* Try to dequeue one-to-one chat messages and one-to-one file transfers. */\n        mImOperationHandler.post(new OneToOneChatDequeueTask(mCtx, mCore, mMessagingLog,\n                mRcsSettings, mChatService, mFileTransferService, mContactManager, mHistoryLog));\n\n        if (mImdnManager.isSendOneToOneDeliveryDisplayedReportsEnabled()\n                || mImdnManager.isSendGroupDeliveryDisplayedReportsEnabled()) {\n            /*\n             * Try to send delayed displayed notifications for read messages if they were not sent\n             * before already. This only attempts to send report and in case of failure the report\n             * will be sent later as postponed delivery report\n             */\n            mImOperationHandler.post(new DelayedDisplayNotificationDispatcher(\n                    mLocalContentResolver, mChatService));\n        }\n    }\n\n    @Override\n    public synchronized void stop(ImsServiceSession.TerminationReason reasonCode) {\n        if (!isServiceStarted()) {\n            return;\n        }\n        setServiceStarted(false);\n\n        mImdnManager.terminate();\n        mImdnManager.interrupt();\n\n        if (ImsServiceSession.TerminationReason.TERMINATION_BY_SYSTEM == reasonCode) {\n            mImOperationHandler.getLooper().quit();\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n                mImDeleteOperationHandler.getLooper().quitSafely();\n            } else {\n                mImDeleteOperationHandler.getLooper().quit();\n            }\n        }\n    }\n\n    @Override\n    public void check() {\n    }\n\n    /**\n     * Returns the IMDN manager\n     * \n     * @return IMDN manager\n     */\n    public ImdnManager getImdnManager() {\n        return mImdnManager;\n    }\n\n    /**\n     * Get Store & Forward manager\n     */\n    public StoreAndForwardManager getStoreAndForwardManager() {\n        return mStoreAndFwdMgr;\n    }\n\n    /**\n     * Get the delivery expiration manager\n     */\n    public DeliveryExpirationManager getDeliveryExpirationManager() {\n        return mDeliveryExpirationManager;\n    }\n\n    public void addSession(OneToOneChatSession session) {\n        ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add OneToOneChatSession with contact '\" + contact + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mOneToOneChatSessionCache.put(contact, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final OneToOneChatSession session) {\n        final ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove OneToOneChatSession with contact '\" + contact + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mOneToOneChatSessionCache.remove(contact);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public OneToOneChatSession getOneToOneChatSession(ContactId contact) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mOneToOneChatSessionCache.get(contact);\n        }\n    }\n\n    public void addSession(TerminatingStoreAndForwardOneToOneChatMessageSession session) {\n        ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add StoreAndForwardMsgSession with contact '\" + contact + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mStoreAndForwardMsgSessionCache.put(contact, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final TerminatingStoreAndForwardOneToOneChatMessageSession session) {\n        final ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove StoreAndForwardMsgSession with contact '\" + contact + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mStoreAndForwardMsgSessionCache.remove(contact);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public TerminatingStoreAndForwardOneToOneChatMessageSession getStoreAndForwardMsgSession(\n            ContactId contact) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mStoreAndForwardMsgSessionCache.get(contact);\n        }\n    }\n\n    public void addSession(TerminatingStoreAndForwardOneToOneChatNotificationSession session) {\n        ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add StoreAndForwardNotifSessionCache with contact '\" + contact + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(\n            final TerminatingStoreAndForwardOneToOneChatNotificationSession session) {\n        final ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove StoreAndForwardNotifSessionCache with contact '\" + contact + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            removeImsServiceSession(session);\n        }\n    }\n\n    public void addSession(GroupChatSession session) {\n        String chatId = session.getContributionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add GroupChatSession with chatId '\" + chatId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGroupChatSessionCache.put(chatId, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final GroupChatSession session) {\n        final String chatId = session.getContributionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove GroupChatSession with chatId '\" + chatId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            SipDialogPath conferenceSubscriberDialogPath = session.getConferenceEventSubscriber()\n                    .getDialogPath();\n            if (conferenceSubscriberDialogPath != null) {\n                mGroupChatConferenceSubscriberCache.remove(conferenceSubscriberDialogPath\n                        .getCallId());\n            }\n            mGroupChatSessionCache.remove(chatId);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public GroupChatSession getGroupChatSession(String chatId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGroupChatSessionCache.get(chatId);\n        }\n    }\n\n    public void addGroupChatConferenceSubscriber(String callId, GroupChatSession session) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add GroupChatConferenceSubscriber with callId '\" + callId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGroupChatConferenceSubscriberCache.put(callId, session);\n        }\n    }\n\n    public void removeGroupChatConferenceSubscriber(final String callId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove GroupChatConferenceSubscriber with callId '\" + callId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGroupChatConferenceSubscriberCache.remove(callId);\n        }\n    }\n\n    public GroupChatSession getGroupChatSessionOfConferenceSubscriber(String callId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGroupChatConferenceSubscriberCache.get(callId);\n        }\n    }\n\n    public boolean isChatSessionAvailable() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            /*\n             * maxChatSessions == 0 means that the allowed number of chat sessions in use is\n             * disabled\n             */\n            int maxChatSessions = mRcsSettings.getMaxChatSessions();\n            return maxChatSessions == 0\n                    || mOneToOneChatSessionCache.size() + mGroupChatSessionCache.size() < maxChatSessions;\n        }\n    }\n\n    /**\n     * Assert if it is allowed to initiate a new chat session right now or the allowed limit has\n     * been reached.\n     * \n     * @param errorMessage The error message\n     */\n    public void assertAvailableChatSession(String errorMessage) {\n        if (!isChatSessionAvailable()) {\n            throw new ServerApiMaxAllowedSessionLimitReachedException(errorMessage);\n        }\n    }\n\n    public void addSession(FileSharingSession session) {\n        String fileTransferId = session.getFileTransferId();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add FileSharingSession with fileTransfer ID '\" + fileTransferId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mFileTransferSessionCache.put(fileTransferId, session);\n            /*\n             * Only FileSharingSessions of type ImsFileSharingSession has a dialog path. Hence add\n             * only those type of sessions to the ImsServiceSession cache and add\n             * HttpFileTransferSession to ImsServiceSessionWithoutDialogPath cache.\n             */\n            if (session instanceof ImsFileSharingSession) {\n                addImsServiceSession(session);\n            } else if (session instanceof HttpFileTransferSession) {\n                addImsServiceSessionWithoutDialogPath(session);\n            }\n        }\n    }\n\n    public void removeSession(final FileSharingSession session) {\n        final String fileTransferId = session.getFileTransferId();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove FileSharingSession with fileTransfer ID '\" + fileTransferId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mFileTransferSessionCache.remove(fileTransferId);\n            /*\n             * Only FileSharingSessions of type ImsFileSharingSession has a dialog path. Hence it is\n             * possible to remove only those type of sessions from the ImsServiceSession cache and\n             * remove HttpFileTransferSession from ImsServiceSessionWithoutDialogPath cache.\n             */\n            if (session instanceof ImsFileSharingSession) {\n                removeImsServiceSession(session);\n            } else if (session instanceof HttpFileTransferSession) {\n                removeImsServiceSessionWithoutDialogPath(session);\n            }\n        }\n    }\n\n    public FileSharingSession getFileSharingSession(String fileTransferId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mFileTransferSessionCache.get(fileTransferId);\n        }\n    }\n\n    public void addSession(FileUploadSession session) {\n        String uploadId = session.getUploadID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add FileUploadSession with upload ID '\" + uploadId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mFileUploadSessionCache.put(uploadId, session);\n        }\n    }\n\n    public void removeSession(final FileUploadSession session) {\n        final String uploadId = session.getUploadID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove FileUploadSession with upload ID '\" + uploadId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mFileUploadSessionCache.remove(uploadId);\n        }\n    }\n\n    public FileUploadSession getFileUploadSession(String uploadId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mFileUploadSessionCache.get(uploadId);\n        }\n    }\n\n    public boolean isFileTransferSessionAvailable() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            /*\n             * maxFtSessions == 0 means that the checking of allowed number of file transfer\n             * sessions in use is disabled\n             */\n            int maxFileTransferSessions = mRcsSettings.getMaxFileTransferSessions();\n            return maxFileTransferSessions == 0\n                    || mFileTransferSessionCache.size() + mFileUploadSessionCache.size() < maxFileTransferSessions;\n        }\n    }\n\n    public void assertAvailableFileTransferSession(String errorMessage) {\n        if (!isFileTransferSessionAvailable()) {\n            throw new ServerApiMaxAllowedSessionLimitReachedException(errorMessage);\n        }\n    }\n\n    public void assertFileSizeNotExceedingMaxLimit(long size, String errorMessage) {\n        /*\n         * maxFtSize == 0 means that the checking of allowed number of file transfer size in use is\n         * disabled\n         */\n        long maxFileTransferSize = mRcsSettings.getMaxFileTransferSize();\n        if (maxFileTransferSize > 0 && size > maxFileTransferSize) {\n            throw new ServerApiPersistentStorageException(errorMessage);\n        }\n    }\n\n    /**\n     * Checks if max number of concurrent outgoing file transfer sessions reached\n     * \n     * @return boolean\n     */\n    public boolean isMaxConcurrentOutgoingFileTransfersReached() {\n        int nrOfConcurrentOutgoingFileTransferSessions = 0;\n        synchronized (getImsServiceSessionOperationLock()) {\n            for (FileSharingSession session : mFileTransferSessionCache.values()) {\n                if (!session.isInitiatedByRemote()) {\n                    nrOfConcurrentOutgoingFileTransferSessions++;\n                }\n            }\n            /*\n             * maxConcurrentOutgoingFilrTransferSessions == 0 means that the checking of allowed\n             * concurrent number of outgoing file transfers in use is disabled\n             */\n            int maxConcurrentOutgoingFileTransferSessions = mRcsSettings\n                    .getMaxConcurrentOutgoingFileTransferSessions();\n            if (maxConcurrentOutgoingFileTransferSessions == 0) {\n                return false;\n            }\n            if (nrOfConcurrentOutgoingFileTransferSessions >= maxConcurrentOutgoingFileTransferSessions) {\n                return true;\n            }\n            nrOfConcurrentOutgoingFileTransferSessions += mFileUploadSessionCache.size();\n            return nrOfConcurrentOutgoingFileTransferSessions >= maxConcurrentOutgoingFileTransferSessions;\n        }\n    }\n\n    /**\n     * Initiate a file transfer session\n     * \n     * @param fileTransferId File transfer Id\n     * @param contact Remote contact identifier\n     * @param content Content of file to sent\n     * @param fileIcon Content of fileicon\n     * @param timestamp the local timestamp when initiating the file transfer\n     * @param ftProtocol FileTransferProtocol\n     * @return File transfer session\n     */\n    public FileSharingSession createFileTransferSession(String fileTransferId, ContactId contact,\n            MmContent content, MmContent fileIcon, long timestamp, FileTransferProtocol ftProtocol) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a file transfer session with contact \" + contact + \", file \"\n                    + content.toString());\n        }\n        switch (ftProtocol) {\n            case HTTP:\n                return new OriginatingHttpFileSharingSession(this, fileTransferId, content,\n                        contact, fileIcon, UUID.randomUUID().toString(), mMessagingLog,\n                        mRcsSettings, timestamp, mContactManager);\n            case MSRP:\n                /*\n                 * Since in MSRP communication we do not have a timestampSent to be sent in payload,\n                 * then we don't need to pass the timestampSent to OriginatingMsrpFileSharingSession\n                 */\n                return new OriginatingMsrpFileSharingSession(this, fileTransferId, content,\n                        contact, fileIcon, mRcsSettings, timestamp, mContactManager);\n            default:\n                throw new IllegalArgumentException(\"Unknown FileTransferProtocol \" + ftProtocol);\n        }\n    }\n\n    /**\n     * Initiate a group file transfer session\n     * \n     * @param fileTransferId File transfer Id\n     * @param content The file content to be sent\n     * @param fileIcon Content of fileicon\n     * @param groupChatId Chat contribution ID\n     * @param timestamp the local timestamp when initiating the file transfer\n     * @return File transfer session\n     */\n    public FileSharingSession createGroupFileTransferSession(String fileTransferId,\n            MmContent content, MmContent fileIcon, String groupChatId, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send file \" + content.toString() + \" to \" + groupChatId);\n        }\n        return new OriginatingHttpGroupFileSharingSession(this, fileTransferId, content, fileIcon,\n                ImsModule.getImsUserProfile().getImConferenceUri(), groupChatId, UUID.randomUUID()\n                        .toString(), mRcsSettings, mMessagingLog, timestamp, mContactManager);\n    }\n\n    /**\n     * Receive a MSRP file transfer invitation\n     * \n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onMsrpFileTransferInvitationReceived(final SipRequest invite, final long timestamp) {\n        final InstantMessagingService imService = this;\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    String assertedId = SipUtils.getAssertedIdentity(invite);\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(assertedId);\n                    if (number == null) {\n                        if (logActivated) {\n                            sLogger.error(\"Discard MSRP FileTransfer Invitation: invalid remote ID '\"\n                                    + assertedId + \"'\");\n                        }\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n\n                    }\n                    ContactId remote = ContactUtil.createContactIdFromValidatedData(number);\n                    if (logActivated) {\n                        sLogger.debug(\"Receive a file transfer session invitation from \"\n                                .concat(remote.toString()));\n                    }\n                    String displayName = SipUtils.getDisplayNameFromInvite(invite);\n                    /*\n                     * Update the remote contact's capabilities to include at least MSRP FT\n                     * capabilities as we have just received a MSRP file transfer session invitation\n                     * from this contact so he/she must at least have this capability. We do not\n                     * need any capability exchange response to determine that.\n                     */\n                    mContactManager.mergeContactCapabilities(remote, new CapabilitiesBuilder()\n                            .setFileTransferMsrp(true).setTimestampOfLastResponse(timestamp)\n                            .build(), RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE, displayName);\n\n                    /**\n                     * Since in MSRP communication we do not have a timestampSent to be extracted\n                     * from the payload then we need to fake that by using the local timestamp even\n                     * if this is not the real proper timestamp from the remote side in this case.\n                     */\n                    long timestampSent = timestamp;\n                    if (mContactManager.isBlockedForContact(remote)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \"\n                                    + remote\n                                    + \" is blocked: automatically reject the file transfer invitation\");\n                        }\n                        MmContent content = ContentManager.createMmContentFromSdp(invite,\n                                mRcsSettings);\n                        MmContent fileIcon = FileTransferUtils\n                                .extractFileIcon(invite, mRcsSettings);\n                        addFileTransferInvitationRejected(remote, content, fileIcon,\n                                FileTransfer.ReasonCode.REJECTED_SPAM, timestamp, timestampSent);\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n                    }\n\n                    if (!isFileTransferSessionAvailable()) {\n                        if (logActivated) {\n                            sLogger.debug(\"The max number of file transfer sessions is achieved: reject the invitation from \"\n                                    .concat(remote.toString()));\n                        }\n                        MmContent content = ContentManager.createMmContentFromSdp(invite,\n                                mRcsSettings);\n                        MmContent fileIcon = FileTransferUtils\n                                .extractFileIcon(invite, mRcsSettings);\n                        addFileTransferInvitationRejected(remote, content, fileIcon,\n                                FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                timestampSent);\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n                    }\n                    /*\n                     * Reject if file is too big or size exceeds device storage capacity. This\n                     * control should be done on UI. It is done after end user accepts invitation to\n                     * enable prior handling by the application.\n                     */\n                    MmContent content = ContentManager.createMmContentFromSdp(invite, mRcsSettings);\n                    FileSharingError error = isFileCapacityAcceptable(content.getSize(),\n                            mRcsSettings);\n                    if (error != null) {\n                        /*\n                         * Extract of GSMA specification: If the file is bigger than FT MAX SIZE, a\n                         * warning message is displayed when trying to send or receive a file larger\n                         * than the mentioned limit and the transfer will be cancelled (that is at\n                         * protocol level, the SIP INVITE request will never be sent or an automatic\n                         * rejection response SIP 403 Forbidden with a Warning header set to 133\n                         * Size exceeded will be sent by the entity that detects that the file size\n                         * is too big to the other end depending on the scenario).\n                         */\n                        send403Forbidden(invite, sSizeExceededMsg);\n                        int errorCode = error.getErrorCode();\n                        MmContent fileIcon = FileTransferUtils\n                                .extractFileIcon(invite, mRcsSettings);\n                        switch (errorCode) {\n                            case FileSharingError.MEDIA_SIZE_TOO_BIG:\n                                addFileTransferInvitationRejected(remote, content, fileIcon,\n                                        FileTransfer.ReasonCode.REJECTED_MAX_SIZE, timestamp,\n                                        timestampSent);\n                                break;\n                            case FileSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                                addFileTransferInvitationRejected(remote, content, fileIcon,\n                                        FileTransfer.ReasonCode.REJECTED_LOW_SPACE, timestamp,\n                                        timestampSent);\n                                break;\n                            default:\n                                sLogger.error(\"Unexpected error while receiving MSRP file transfer invitation\"\n                                        .concat(Integer.toString(errorCode)));\n                        }\n                        return;\n                    }\n\n                    FileSharingSession session = new TerminatingMsrpFileSharingSession(imService,\n                            invite, remote, mRcsSettings, timestamp, timestampSent, mContactManager);\n                    mFileTransferService.receiveFileTransferInvitation(session, false, remote,\n                            displayName);\n                    session.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive msrp file transfer invitation! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (FileAccessException | ContactManagerException | PayloadException\n                        | RuntimeException e) {\n                    sLogger.error(\"Failed to receive msrp file transfer invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Initiate a one-to-one chat session\n     * \n     * @param contact Remote contact identifier\n     * @param firstMsg First message\n     * @return IM session\n     */\n    public OneToOneChatSession createOneToOneChatSession(ContactId contact, ChatMessage firstMsg) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate 1-1 chat session with \" + contact + \".\");\n        }\n        long timestamp = firstMsg.getTimestamp();\n        return new OriginatingOneToOneChatSession(this, contact, firstMsg, mRcsSettings,\n                mMessagingLog, timestamp, mContactManager);\n    }\n\n    /**\n     * Receive a one-to-one chat session invitation\n     * \n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onOne2OneChatSessionReceived(final SipRequest invite, final long timestamp) {\n        final InstantMessagingService imService = this;\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    /*\n                     * Invitation will be rejected if it is OMA SIMPLE IM solution but it doesn't\n                     * contains first message. Reference to spec: Rich Communication Suite 5.1\n                     * Advanced Communications Services and Client Specification Version 4.0 Page\n                     * 187 3.3.4.2 Technical Realization of 1-to-1 Chat features when using OMA\n                     * SIMPLE IM At the technical level the 1-to-1 Chat service implemented using\n                     * OMA SIMPLE IM extends the concepts described in section 3.3.4.1 with the\n                     * following concepts: For OMA SIMPLE IM, first message is always included in a\n                     * CPIM/IMDN wrapper carried in the SIP INVITE request. So the configuration\n                     * parameter FIRST MSG IN INVITE defined in Table 80 is always set to 1.\n                     */\n                    if (!ChatUtils.isContainingFirstMessage(invite)) {\n                        ImMsgTech mode = mRcsSettings.getImMsgTech();\n                        switch (mode) {\n                            case CPM:\n                                /* Only reject the invitation when FirstMessageInInvite is true. */\n                                if (mRcsSettings.isFirstMessageInInvite()) {\n                                    if (logActivated) {\n                                        sLogger.error(\"Currently in Cpm mode, Reject 1-1 chat invition due to it doesn't\"\n                                                .concat(\"carry first message.\"));\n                                    }\n                                    sendErrorResponse(invite, Response.DECLINE);\n                                    return;\n                                }\n                                break;\n                            case SIMPLE_IM:\n                                if (logActivated) {\n                                    sLogger.error(\"Currently in SIMPLE_IM mode, Reject 1-1 chat invition due to it doesn't\"\n                                            .concat(\"carry first message.\"));\n                                }\n                                sendErrorResponse(invite, Response.DECLINE);\n                                return;\n                            default:\n                                if (sLogger.isActivated()) {\n                                    sLogger.error(\"Unexpected ImMsgTech code:\".concat(String\n                                            .valueOf(mode)));\n                                }\n                                return;\n                        }\n                    }\n                    String referredId = ChatUtils.getReferredIdentityAsContactUri(invite);\n                    ContactId remote = ChatUtils.getReferredIdentityAsContactId(invite);\n                    String displayName = SipUtils.getDisplayNameFromInvite(invite);\n                    if (remote == null) {\n                        if (logActivated) {\n                            sLogger.error(\"Discard One2OneChatSession: invalid remote ID '\"\n                                    + referredId + \"'\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n\n                    }\n                    if (logActivated) {\n                        sLogger.debug(\"Receive a 1-1 chat session invitation from \".concat(remote\n                                .toString()));\n                    }\n                    /*\n                     * Update the remote contact's capabilities to include at least IM session\n                     * capabilities as we have just received a one-one chat session invitation from\n                     * this contact so he/she must at least have this capability. We do not need any\n                     * capability exchange response to determine that.\n                     */\n                    mContactManager.mergeContactCapabilities(remote, new CapabilitiesBuilder()\n                            .setImSession(true).setTimestampOfLastResponse(timestamp).build(),\n                            RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE, displayName);\n\n                    ChatMessage firstMsg = ChatUtils.getFirstMessage(invite, timestamp);\n                    if (mContactManager.isBlockedForContact(remote)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + remote\n                                    + \" is blocked: automatically reject the chat invitation\");\n                        }\n\n                        if (firstMsg != null\n                                && !mMessagingLog.isMessagePersisted(firstMsg.getMessageId())) {\n                            mMessagingLog.addOneToOneSpamMessage(firstMsg);\n                        }\n\n                        if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n                            String msgId = ChatUtils.getMessageId(invite);\n                            if (msgId != null) {\n                                String remoteInstanceId = null;\n                                ContactHeader inviteContactHeader = (ContactHeader) invite\n                                        .getHeader(ContactHeader.NAME);\n                                if (inviteContactHeader != null) {\n                                    remoteInstanceId = inviteContactHeader\n                                            .getParameter(SipUtils.SIP_INSTANCE_PARAM);\n                                }\n                                mImdnManager.sendMessageDeliveryStatusImmediately(\n                                        remote.toString(), remote, msgId,\n                                        ImdnDocument.DeliveryStatus.DELIVERED, remoteInstanceId,\n                                        timestamp);\n                            }\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n\n                    /*\n                     * Save the message if it was not already persisted in the DB. We don't have to\n                     * reject the session if the message was a duplicate one as the session\n                     * rejection/keeping will be handled in\n                     * TerminatingOneToOneChatSession.startSession() in an uniform way as according\n                     * to the defined race conditions in the specification document.\n                     */\n                    if (firstMsg != null\n                            && !mMessagingLog.isMessagePersisted(firstMsg.getMessageId())) {\n                        boolean imdnDisplayRequested = mImdnManager\n                                .isSendOneToOneDeliveryDisplayedReportsEnabled()\n                                && ChatUtils.isImdnDisplayedRequested(invite);\n                        mMessagingLog\n                                .addIncomingOneToOneChatMessage(firstMsg, imdnDisplayRequested);\n                    }\n\n                    if (!isChatSessionAvailable()) {\n                        if (logActivated) {\n                            sLogger.debug(\"The max number of chat sessions is achieved: reject the invitation from \"\n                                    .concat(remote.toString()));\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n\n                    TerminatingOneToOneChatSession session = new TerminatingOneToOneChatSession(\n                            imService, invite, remote, mRcsSettings, mMessagingLog, timestamp,\n                            mContactManager);\n                    mChatService.receiveOneToOneChatInvitation(session);\n                    session.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive o2o chat invitation! (\" + e.getMessage()\n                                + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (FileAccessException | ContactManagerException | PayloadException\n                        | RuntimeException e) {\n                    sLogger.error(\"Failed to receive o2o chat invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Create an ad-hoc group chat session\n     * \n     * @param contacts List of contact identifiers\n     * @param subject Subject\n     * @param timestamp Local timestamp\n     * @return GroupChatSession\n     */\n    public GroupChatSession createOriginatingAdHocGroupChatSession(Set<ContactId> contacts,\n            String subject, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate an ad-hoc group chat session\");\n        }\n        Map<ContactId, ParticipantStatus> participants = ChatUtils.getParticipants(contacts,\n                ParticipantStatus.INVITING);\n        return new OriginatingAdhocGroupChatSession(this, ImsModule.getImsUserProfile()\n                .getImConferenceUri(), subject, participants, mRcsSettings, mMessagingLog,\n                timestamp, mContactManager);\n    }\n\n    /**\n     * Receive ad-hoc group chat session invitation\n     * \n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onAdHocGroupChatSessionReceived(final SipRequest invite, final long timestamp) {\n        final InstantMessagingService imService = this;\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    ContactId contact = ChatUtils.getReferredIdentityAsContactId(invite);\n                    if (logActivated) {\n                        sLogger.debug(\"Receive an ad-hoc group chat session invitation from \"\n                                + contact);\n                    }\n                    String displayName = SipUtils.getDisplayNameFromInvite(invite);\n                    /*\n                     * Update the remote contact's capabilities to include at least IM session\n                     * capabilities as we have just received a group chat session invitation from\n                     * this contact so he/she must at least have this capability. We do not need any\n                     * capability exchange response to determine that.\n                     */\n                    mContactManager.mergeContactCapabilities(contact, new CapabilitiesBuilder()\n                            .setImSession(true).setTimestampOfLastResponse(timestamp).build(),\n                            RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE, displayName);\n\n                    String chatId = ChatUtils.getContributionId(invite);\n                    String subject = ChatUtils.getSubject(invite);\n                    Map<ContactId, ParticipantStatus> participants = ChatUtils.getParticipants(\n                            invite, ParticipantStatus.FAILED);\n                    if (mContactManager.isBlockedForContact(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + contact\n                                    + \" is blocked: automatically reject the chat invitation\");\n                        }\n                        mChatService.addGroupChatInvitationRejected(chatId, contact, subject,\n                                participants, GroupChat.ReasonCode.REJECTED_SPAM, timestamp);\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n                    if (!isChatSessionAvailable()) {\n                        if (logActivated) {\n                            sLogger.debug(\"The max number of chat sessions is achieved: reject the invitation from \"\n                                    + contact);\n                        }\n                        mChatService.addGroupChatInvitationRejected(chatId, contact, subject,\n                                participants, GroupChat.ReasonCode.REJECTED_MAX_CHATS, timestamp);\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n                    /*\n                     * Get the list of participants from the invite, give them the initial status\n                     * INVITED as the actual status was not included in the invite.\n                     */\n                    Map<ContactId, ParticipantStatus> inviteParticipants = ChatUtils\n                            .getParticipants(invite, ParticipantStatus.INVITED);\n                    // @FIXME: This method should return an URI\n                    String remoteUri = ChatUtils.getReferredIdentityAsContactUri(invite);\n\n                    TerminatingAdhocGroupChatSession session = new TerminatingAdhocGroupChatSession(\n                            imService, invite, contact, inviteParticipants, Uri.parse(remoteUri),\n                            mRcsSettings, mMessagingLog, timestamp, mContactManager);\n\n                    /*--\n                     * 6.3.3.1 Leaving a Group Chat that is idle\n                     * In case the user expresses their desire to leave the Group Chat while it is inactive, the device will not offer the user\n                     * the possibility any more to enter new messages and restart the chat and automatically decline the first incoming INVITE\n                     * request for the chat with a SIP 603 DECLINE response. Subsequent INVITE requests should not be rejected as they may be\n                     * received when the user is added again to the Chat by one of the participants.\n                     */\n                    boolean reject = mMessagingLog.isGroupChatNextInviteRejected(session\n                            .getContributionID());\n                    if (reject) {\n                        if (logActivated) {\n                            sLogger.debug(\"Chat Id \"\n                                    + session.getContributionID()\n                                    + \" is declined since previously terminated by user while disconnected\");\n                        }\n                        sendErrorResponse(invite, Response.DECLINE);\n                        mMessagingLog.acceptGroupChatNextInvitation(session.getContributionID());\n                        return;\n                    }\n                    mChatService.receiveGroupChatInvitation(session);\n                    session.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive group chat invitation! (\" + e.getMessage()\n                                + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (FileAccessException | ContactManagerException | PayloadException\n                        | RuntimeException e) {\n                    sLogger.error(\"Failed to receive group chat invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejoin a group chat session\n     * \n     * @param chatId Chat ID\n     * @return RejoinGroupChat session\n     */\n    public RejoinGroupChatSession rejoinGroupChatSession(String chatId) {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Rejoin group chat session\");\n        }\n        assertAvailableChatSession(\"Max chat sessions reached\");\n\n        /* Get the group chat info from database */\n        GroupChatInfo groupChat = mMessagingLog.getGroupChatInfo(chatId);\n        if (groupChat == null) {\n            if (logActivated) {\n                sLogger.warn(\"Group chat \" + chatId + \" can't be rejoined: conversation not found\");\n            }\n            throw new ServerApiPersistentStorageException(\n                    \"Group chat conversation not found in database\");\n        }\n        if (groupChat.getRejoinId() == null) {\n            if (logActivated) {\n                sLogger.warn(\"Group chat \" + chatId + \" can't be rejoined: rejoin ID not found\");\n            }\n            throw new ServerApiPersistentStorageException(\"Rejoin ID not found in database\");\n        }\n        if (logActivated) {\n            sLogger.debug(\"Rejoin group chat: \" + groupChat.toString());\n        }\n        long timestamp = groupChat.getTimestamp();\n        return new RejoinGroupChatSession(this, groupChat, mRcsSettings, mMessagingLog, timestamp,\n                mContactManager);\n    }\n\n    /**\n     * Restart a group chat session\n     * \n     * @param chatId Chat ID\n     * @return RestartGroupChat session\n     */\n    public RestartGroupChatSession restartGroupChatSession(String chatId) {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Restart group chat session\");\n        }\n        assertAvailableChatSession(\"Max chat sessions reached\");\n        /* Get the group chat info from database */\n        GroupChatInfo groupChat = mMessagingLog.getGroupChatInfo(chatId);\n        if (groupChat == null) {\n            if (logActivated) {\n                sLogger.warn(\"Group chat \" + chatId + \" can't be restarted: conversation not found\");\n            }\n            throw new ServerApiPersistentStorageException(\n                    \"Group chat conversation not found in database\");\n        }\n        if (logActivated) {\n            sLogger.debug(\"Restart group chat: \" + groupChat.toString());\n        }\n        Map<ContactId, ParticipantStatus> storedParticipants = groupChat.getParticipants();\n        if (storedParticipants.isEmpty()) {\n            if (logActivated) {\n                sLogger.warn(\"Group chat \" + chatId + \" can't be restarted: participants not found\");\n            }\n            throw new ServerApiPersistentStorageException(\n                    \"No connected group chat participants found in database\");\n        }\n        long timestamp = groupChat.getTimestamp();\n        return new RestartGroupChatSession(this,\n                ImsModule.getImsUserProfile().getImConferenceUri(), groupChat.getSubject(), chatId,\n                storedParticipants, mRcsSettings, mMessagingLog, timestamp, mContactManager);\n    }\n\n    /**\n     * Receive a conference notification\n     * \n     * @param notify Received notify\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onConferenceNotificationReceived(final SipRequest notify, final long timestamp) {\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    GroupChatSession session = getGroupChatSessionOfConferenceSubscriber(notify\n                            .getCallId());\n                    if (session != null) {\n                        session.getConferenceEventSubscriber().receiveNotification(notify,\n                                timestamp);\n                    }\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive group conference notification!\", e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Receive a message delivery status\n     * \n     * @param message Received message\n     */\n    public void onMessageDeliveryStatusReceived(final SipRequest message) {\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    /*\n                     * Begin by sending 200 OK, a failure before doing that may cause the sender to\n                     * re-send the report and if reception fails again we are stuck in a loop.\n                     */\n                    getImsModule().getSipManager().sendSipResponse(\n                            SipMessageFactory.createResponse(message, IdGenerator.getIdentifier(),\n                                    Response.OK));\n\n                    ImdnDocument imdn = ChatUtils.parseCpimDeliveryReport(message.getContent());\n                    String assertedId = SipUtils.getAssertedIdentity(message);\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(assertedId);\n\n                    if (number == null) {\n                        sLogger.error(\"Invalid remote ID \" + assertedId);\n                        return;\n                    }\n\n                    ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                    String msgId = imdn.getMsgId();\n\n                    String chatId = mMessagingLog.getMessageChatId(msgId);\n                    if (chatId != null) {\n                        if (chatId.equals(contact.toString())) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Handle one to one message delivery status\");\n                            }\n                            mChatService.onOneToOneMessageDeliveryStatusReceived(contact, imdn);\n                            return;\n                        }\n                        mChatService.getOrCreateGroupChat(chatId).onMessageDeliveryStatusReceived(\n                                contact, imdn);\n                        return;\n                    }\n                    chatId = mMessagingLog.getFileTransferChatId(msgId);\n                    if (chatId != null) {\n                        if (chatId.equals(contact.toString())) {\n                            receiveOneToOneFileDeliveryStatus(contact, imdn);\n                            return;\n                        }\n                        receiveGroupFileDeliveryStatus(chatId, contact, imdn);\n                        return;\n                    }\n                    sLogger.warn(\"SIP IMDN delivery report received referencing a message that was \"\n                            + \"not found in our database. Message id \" + msgId + \", ignoring.\");\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive chat message delivery report! (\"\n                                + e.getMessage() + \")\");\n                    }\n                } catch (ParserConfigurationException | ParseFailureException | SAXException\n                        | PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive chat message delivery report!\", e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Receive S&F push messages\n     * \n     * @param invite Received invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onStoreAndForwardPushMessagesReceived(final SipRequest invite, final long timestamp) {\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    String referredId = ChatUtils.getReferredIdentityAsContactUri(invite);\n                    ContactId remote = ChatUtils.getReferredIdentityAsContactId(invite);\n                    if (remote == null) {\n                        if (logActivated) {\n                            sLogger.error(\"Discard S&F PushMessages: invalid remote ID '\"\n                                    + referredId + \"'\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n                    if (logActivated) {\n                        sLogger.debug(\"Receive S&F push messages invitation\");\n                    }\n                    ChatMessage firstMsg = ChatUtils.getFirstMessage(invite, timestamp);\n\n                    if (mContactManager.isBlockedForContact(remote)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + remote\n                                    + \" is blocked: automatically reject the S&F invitation\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n                    /*\n                     * Save the message if it was not already persisted in the DB. We don't have to\n                     * reject the session if the message was a duplicate one as the session\n                     * rejection/keeping will be handled in\n                     * TerminatingOneToOneChatSession.startSession() in an uniform way as according\n                     * to the defined race conditions in the specification document.\n                     */\n                    if (firstMsg != null\n                            && !mMessagingLog.isMessagePersisted(firstMsg.getMessageId())) {\n                        boolean imdnDisplayRequested = mImdnManager\n                                .isSendOneToOneDeliveryDisplayedReportsEnabled()\n                                && ChatUtils.isImdnDisplayedRequested(invite);\n                        mMessagingLog\n                                .addIncomingOneToOneChatMessage(firstMsg, imdnDisplayRequested);\n                    }\n                    getStoreAndForwardManager().receiveStoreAndForwardMessageInvitation(invite,\n                            remote, timestamp);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive s&f chat messages! (\" + e.getMessage()\n                                + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive s&f chat messages!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Receive S&F push notifications\n     * \n     * @param invite Received invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onStoredAndForwardPushNotificationReceived(final SipRequest invite,\n            final long timestamp) {\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    String referredId = ChatUtils.getReferredIdentityAsContactUri(invite);\n                    ContactId remote = ChatUtils.getReferredIdentityAsContactId(invite);\n                    if (remote == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.error(\"Discard S&F PushNotifications: invalid remote ID '\"\n                                    + referredId + \"'\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Receive S&F push notifications invitation\");\n                    }\n                    if (mContactManager.isBlockedForContact(remote)) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Contact \" + remote\n                                    + \" is blocked: automatically reject the S&F invitation\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n                    getStoreAndForwardManager().receiveStoreAndForwardNotificationInvitation(\n                            invite, remote, timestamp);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive s&f push notifications! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive s&f push notifications!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n\n    }\n\n    /**\n     * Receive HTTP file transfer invitation\n     * \n     * @param invite Received invite\n     * @param ftinfo File transfer info document\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onOneToOneHttpFileTranferInvitationReceived(final SipRequest invite,\n            final FileTransferHttpInfoDocument ftinfo, final long timestamp) {\n        final InstantMessagingService imService = this;\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    String referredId = ChatUtils.getReferredIdentityAsContactUri(invite);\n                    ContactId remote = ChatUtils.getReferredIdentityAsContactId(invite);\n                    String displayName = SipUtils.getDisplayNameFromInvite(invite);\n                    if (remote == null) {\n                        if (logActivated) {\n                            sLogger.error(\"Discard OneToOne HttpFileTranferInvitation: invalid remote ID '\"\n                                    + referredId + \"'\");\n                        }\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n\n                    }\n                    if (logActivated) {\n                        sLogger.debug(\"Receive a single HTTP file transfer invitation from \"\n                                .concat(remote.toString()));\n                    }\n                    /*\n                     * Update the remote contact's capabilities to include at least HTTP FT and IM\n                     * session capabilities as we have just received a HTTP file transfer invitation\n                     * from this contact so he/she must at least have this capability. We do not\n                     * need any capability exchange response to determine that.\n                     */\n                    mContactManager.mergeContactCapabilities(remote, new CapabilitiesBuilder()\n                            .setImSession(true).setFileTransferHttp(true)\n                            .setTimestampOfLastResponse(timestamp).build(), RcsStatus.RCS_CAPABLE,\n                            RegistrationState.ONLINE, displayName);\n\n                    String fileTransferId = ChatUtils.getMessageId(invite);\n                    if (isFileTransferAlreadyOngoing(fileTransferId)) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"File transfer with fileTransferId '\" + fileTransferId\n                                    + \"' already ongoing, so ignoring this one.\");\n                        }\n                        return;\n                    }\n                    CpimMessage cpimMessage = ChatUtils.extractCpimMessage(invite);\n                    long timestampSent = cpimMessage.getTimestampSent();\n                    boolean fileResent = isFileTransferResentAndNotAlreadyOngoing(fileTransferId);\n                    if (mContactManager.isBlockedForContact(remote)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + remote\n                                    + \" is blocked, automatically reject the HTTP File transfer\");\n                        }\n                        sendErrorResponse(invite, Response.DECLINE);\n                        if (fileResent) {\n                            setResendFileTransferInvitationRejected(fileTransferId,\n                                    FileTransfer.ReasonCode.REJECTED_SPAM, timestamp, timestampSent);\n                            return;\n                        }\n                        MmContent fileContent = ftinfo.getLocalMmContent();\n                        FileTransferHttpThumbnail thumbnail = ftinfo.getFileThumbnail();\n                        MmContent fileIconContent = thumbnail == null ? null : thumbnail\n                                .getLocalMmContent(fileTransferId);\n                        addFileTransferInvitationRejected(remote, fileContent, fileIconContent,\n                                FileTransfer.ReasonCode.REJECTED_SPAM, timestamp, timestampSent);\n                        return;\n                    }\n\n                    if (!isChatSessionAvailable()) {\n                        if (logActivated) {\n                            sLogger.debug(\"The max number of chat sessions is achieved: reject the invitation from \"\n                                    .concat(remote.toString()));\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        /*\n                         * The more abstracted reason code REJECTED_MAX_FILE_TRANSFERS is used since\n                         * the client need not be aware of chat session dependency here.\n                         */\n                        if (fileResent) {\n                            setResendFileTransferInvitationRejected(fileTransferId,\n                                    FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                    timestampSent);\n                            return;\n                        }\n                        MmContent fileContent = ftinfo.getLocalMmContent();\n                        FileTransferHttpThumbnail thumbnail = ftinfo.getFileThumbnail();\n                        MmContent fileIconContent = thumbnail == null ? null : thumbnail\n                                .getLocalMmContent(fileTransferId);\n                        addFileTransferInvitationRejected(remote, fileContent, fileIconContent,\n                                FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                timestampSent);\n                        return;\n                    }\n\n                    TerminatingOneToOneChatSession oneToOneChatSession = new TerminatingOneToOneChatSession(\n                            imService, invite, remote, mRcsSettings, mMessagingLog, timestamp,\n                            mContactManager);\n                    receiveOneOneChatSessionInitiation(oneToOneChatSession);\n                    oneToOneChatSession.startSession();\n\n                    if (!isFileTransferSessionAvailable()) {\n                        if (logActivated) {\n                            sLogger.debug(\"The max number of FT sessions is achieved, reject the HTTP File transfer from \"\n                                    .concat(remote.toString()));\n                        }\n                        sendErrorResponse(invite, Response.DECLINE);\n                        if (fileResent) {\n                            setResendFileTransferInvitationRejected(fileTransferId,\n                                    FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                    timestampSent);\n                            return;\n                        }\n                        setResendFileTransferInvitationRejected(fileTransferId,\n                                FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                timestampSent);\n                        return;\n                    }\n                    /*\n                     * Reject if file is too big or size exceeds device storage capacity. This\n                     * control should be done on UI. It is done after end user accepts invitation to\n                     * enable prior handling by the application.\n                     */\n                    FileSharingError error = isFileCapacityAcceptable(ftinfo.getSize(),\n                            mRcsSettings);\n                    if (error != null) {\n                        sendErrorResponse(invite, Response.DECLINE);\n                        int errorCode = error.getErrorCode();\n                        MmContent fileContent = ftinfo.getLocalMmContent();\n                        FileTransferHttpThumbnail thumbnail = ftinfo.getFileThumbnail();\n                        MmContent fileIconContent = thumbnail == null ? null : thumbnail\n                                .getLocalMmContent(fileTransferId);\n                        switch (errorCode) {\n                            case FileSharingError.MEDIA_SIZE_TOO_BIG:\n                                if (fileResent) {\n                                    setResendFileTransferInvitationRejected(fileTransferId,\n                                            FileTransfer.ReasonCode.REJECTED_MAX_SIZE, timestamp,\n                                            timestampSent);\n                                    break;\n                                }\n                                addFileTransferInvitationRejected(remote, fileContent,\n                                        fileIconContent, FileTransfer.ReasonCode.REJECTED_MAX_SIZE,\n                                        timestamp, timestampSent);\n                                break;\n                            case FileSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                                if (fileResent) {\n                                    setResendFileTransferInvitationRejected(fileTransferId,\n                                            FileTransfer.ReasonCode.REJECTED_LOW_SPACE, timestamp,\n                                            timestampSent);\n                                    break;\n                                }\n                                addFileTransferInvitationRejected(remote, fileContent,\n                                        fileIconContent,\n                                        FileTransfer.ReasonCode.REJECTED_LOW_SPACE, timestamp,\n                                        timestampSent);\n                                break;\n                            default:\n                                sLogger.error(\"Unexpected error while receiving HTTP file transfer invitation from \"\n                                        + remote + \" error : \" + Integer.toString(errorCode));\n                        }\n                        return;\n                    }\n                    DownloadFromInviteFileSharingSession fileSharingSession = new DownloadFromInviteFileSharingSession(\n                            imService, oneToOneChatSession, ftinfo, fileTransferId,\n                            oneToOneChatSession.getRemoteContact(),\n                            oneToOneChatSession.getRemoteDisplayName(), mRcsSettings,\n                            mMessagingLog, timestamp, timestampSent, mContactManager);\n                    if (fileSharingSession.getFileicon() != null) {\n                        try {\n                            fileSharingSession.downloadFileIcon();\n                        } catch (NetworkException e) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Failed to download file icon! (\" + e.getMessage()\n                                        + \")\");\n                            }\n                            sendErrorResponse(invite, Response.DECLINE);\n                            if (fileResent) {\n                                setResendFileTransferInvitationRejected(fileTransferId,\n                                        FileTransfer.ReasonCode.REJECTED_MEDIA_FAILED, timestamp,\n                                        timestampSent);\n                                return;\n                            }\n                            MmContent fileContent = ftinfo.getLocalMmContent();\n                            FileTransferHttpThumbnail thumbnail = ftinfo.getFileThumbnail();\n                            MmContent fileIconContent = thumbnail == null ? null : thumbnail\n                                    .getLocalMmContent(fileTransferId);\n                            addFileTransferInvitationRejected(remote, fileContent, fileIconContent,\n                                    FileTransfer.ReasonCode.REJECTED_MEDIA_FAILED, timestamp,\n                                    timestampSent);\n                            return;\n                        } catch (FileAccessException e) {\n                            sLogger.error(\"Failed to download file icon\", e);\n                            sendErrorResponse(invite, Response.DECLINE);\n                            if (fileResent) {\n                                setResendFileTransferInvitationRejected(fileTransferId,\n                                        FileTransfer.ReasonCode.REJECTED_MEDIA_FAILED, timestamp,\n                                        timestampSent);\n                                return;\n                            }\n                            MmContent fileContent = ftinfo.getLocalMmContent();\n                            FileTransferHttpThumbnail thumbnail = ftinfo.getFileThumbnail();\n                            MmContent fileIconContent = thumbnail == null ? null : thumbnail\n                                    .getLocalMmContent(fileTransferId);\n                            addFileTransferInvitationRejected(remote, fileContent, fileIconContent,\n                                    FileTransfer.ReasonCode.REJECTED_MEDIA_FAILED, timestamp,\n                                    timestampSent);\n                            return;\n                        }\n                    }\n                    if (fileResent) {\n                        receiveResendFileTransferInvitation(fileSharingSession, remote, displayName);\n                    } else {\n                        mFileTransferService.receiveFileTransferInvitation(fileSharingSession,\n                                false, oneToOneChatSession.getRemoteContact(),\n                                oneToOneChatSession.getRemoteDisplayName());\n                    }\n                    fileSharingSession.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive http o2o file transfer invitation! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (FileAccessException | PayloadException | ContactManagerException\n                        | RuntimeException e) {\n                    sLogger.error(\"Failed to receive http o2o file transfer invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Receive S&F HTTP file transfer invitation\n     * \n     * @param invite Received invite\n     * @param ftinfo File transfer info document\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onStoreAndForwardOneToOneHttpFileTranferInvitationReceived(final SipRequest invite,\n            final FileTransferHttpInfoDocument ftinfo, final long timestamp) {\n        final InstantMessagingService imService = this;\n        scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    String referredId = ChatUtils.getReferredIdentityAsContactUri(invite);\n                    ContactId remote = ChatUtils.getReferredIdentityAsContactId(invite);\n                    String displayName = SipUtils.getDisplayNameFromInvite(invite);\n                    if (remote == null) {\n                        sLogger.error(\"Discard S&F OneToOne HttpFileTranfer Invitation. Invalid remote ID \"\n                                .concat(referredId));\n                        /* We cannot refuse a S&F File transfer invitation */\n                        // TODO normally send a deliver to enable transmission of awaiting messages\n                        return;\n                    }\n                    if (logActivated) {\n                        sLogger.debug(\"Receive a single S&F HTTP file transfer invitation from \"\n                                .concat(remote.toString()));\n                    }\n                    CpimMessage cpimMessage = ChatUtils.extractCpimMessage(invite);\n                    long timestampSent = cpimMessage.getTimestampSent();\n                    String fileTransferId = ChatUtils.getMessageId(invite);\n                    boolean fileResent = isFileTransferResentAndNotAlreadyOngoing(fileTransferId);\n                    if (!isChatSessionAvailable()) {\n                        if (logActivated) {\n                            sLogger.debug(\"The max number of chat sessions is achieved: reject the invitation from \"\n                                    .concat(remote.toString()));\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        /*\n                         * The more abstracted reason code REJECTED_MAX_FILE_TRANSFERS is used since\n                         * the client need not be aware of chat session dependency here.\n                         */\n                        if (fileResent) {\n                            setResendFileTransferInvitationRejected(fileTransferId,\n                                    FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                    timestampSent);\n                            return;\n                        }\n                        MmContent fileContent = ftinfo.getLocalMmContent();\n                        FileTransferHttpThumbnail thumbnail = ftinfo.getFileThumbnail();\n                        MmContent fileIconContent = thumbnail == null ? null : thumbnail\n                                .getLocalMmContent(fileTransferId);\n                        addFileTransferInvitationRejected(remote, fileContent, fileIconContent,\n                                FileTransfer.ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                                timestampSent);\n                        return;\n                    }\n\n                    TerminatingStoreAndForwardOneToOneChatMessageSession oneToOneChatSession = new TerminatingStoreAndForwardOneToOneChatMessageSession(\n                            imService, invite, remote, mRcsSettings, mMessagingLog, timestamp,\n                            mContactManager);\n                    receiveOneOneChatSessionInitiation(oneToOneChatSession);\n                    oneToOneChatSession.startSession();\n\n                    if (isFileTransferAlreadyOngoing(fileTransferId)) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"File transfer with fileTransferId '\" + fileTransferId\n                                    + \"' already ongoing, so ignoring this one from \" + remote);\n                        }\n                        return;\n                    }\n                    if (isFileSizeExceeded(ftinfo.getSize())) {\n                        if (logActivated) {\n                            sLogger.debug(\"File is too big, reject file transfer invitation from \"\n                                    .concat(remote.toString()));\n                        }\n                        // TODO add warning header \"xxx Size exceeded\"\n                        oneToOneChatSession.sendErrorResponse(invite, oneToOneChatSession\n                                .getDialogPath().getLocalTag(),\n                                InvitationStatus.INVITATION_REJECTED_FORBIDDEN);\n                        // Close session\n                        oneToOneChatSession.handleError(new FileSharingError(\n                                FileSharingError.MEDIA_SIZE_TOO_BIG));\n                        return;\n                    }\n                    DownloadFromInviteFileSharingSession filetransferSession = new DownloadFromInviteFileSharingSession(\n                            imService, oneToOneChatSession, ftinfo, fileTransferId,\n                            oneToOneChatSession.getRemoteContact(),\n                            oneToOneChatSession.getRemoteDisplayName(), mRcsSettings,\n                            mMessagingLog, timestamp, timestampSent, mContactManager);\n                    if (filetransferSession.getFileicon() != null) {\n                        try {\n                            filetransferSession.downloadFileIcon();\n                        } catch (FileAccessException e) {\n                            sLogger.error(\"Failed to download file icon\", e);\n                            oneToOneChatSession.sendErrorResponse(invite, oneToOneChatSession\n                                    .getDialogPath().getLocalTag(),\n                                    InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                            /* Close session */\n                            oneToOneChatSession.handleError(new FileSharingError(\n                                    FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n                            return;\n                        }\n\n                    }\n                    if (fileResent) {\n                        receiveResendFileTransferInvitation(filetransferSession, remote,\n                                displayName);\n                    } else {\n                        mFileTransferService.receiveFileTransferInvitation(filetransferSession,\n                                false, oneToOneChatSession.getRemoteContact(),\n                                oneToOneChatSession.getRemoteDisplayName());\n                    }\n                    filetransferSession.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive s&f o2o http file transfer invitation! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive s&f o2o file http transfer invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Check whether file size exceeds the limit\n     * \n     * @param size of file\n     * @return {@code true} if file size limit is exceeded, otherwise {@code false}\n     */\n    public boolean isFileSizeExceeded(long size) {\n        // Auto reject if file too big\n        long maxSize = mRcsSettings.getMaxFileTransferSize();\n        return maxSize > 0 && size > maxSize;\n    }\n\n    /**\n     * Check if the capabilities are valid based on msgCapValidity paramter\n     * \n     * @param capabilities The capabilities\n     * @return {@code true} if valid, otherwise {@code false}\n     */\n    public boolean isCapabilitiesValid(Capabilities capabilities) {\n        long msgCapValidityPeriod = mRcsSettings.getMsgCapValidityPeriod();\n        return System.currentTimeMillis() <= capabilities.getTimestampOfLastResponse()\n                + msgCapValidityPeriod;\n    }\n\n    /**\n     * Removes the group chat composing status from the map\n     * \n     * @param chatId The chat ID\n     */\n    public void removeGroupChatComposingStatus(final String chatId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGroupChatComposingStatusToNotify.remove(chatId);\n        }\n    }\n\n    /**\n     * Adds the group chat composing status to the map to enable re-sending upon media session\n     * restart\n     * \n     * @param chatId the group chat identifier\n     * @param status the composing status which failed to be notified\n     */\n    public void addGroupChatComposingStatus(String chatId, boolean status) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGroupChatComposingStatusToNotify.put(chatId, status);\n        }\n    }\n\n    /**\n     * Gets the group chat composing status\n     * \n     * @param chatId the chat ID\n     * @return the group chat composing status if previous sending failed or null if network is\n     *         aligned with client composing status\n     */\n    public Boolean getGroupChatComposingStatus(String chatId) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGroupChatComposingStatusToNotify.get(chatId);\n        }\n    }\n\n    /**\n     * Removes the one-to-one chat composing status from the map\n     * \n     * @param contact the remote contact\n     */\n    public void removeOneToOneChatComposingStatus(final ContactId contact) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            mOneToOneChatComposingStatusToNotify.remove(contact);\n        }\n    }\n\n    /**\n     * Adds the one-to-one chat composing status to the map to enable re-sending upon media session\n     * restart\n     * \n     * @param contact the remote contact\n     * @param status the composing status which failed to be notified\n     */\n    public void addOneToOneChatComposingStatus(ContactId contact, boolean status) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            mOneToOneChatComposingStatusToNotify.put(contact, status);\n        }\n    }\n\n    /**\n     * Gets the one-to-one chat composing status\n     * \n     * @param contact the remote contact\n     * @return the one-to-one chat composing status if previous sending failed or null if network is\n     *         aligned with client composing status\n     */\n    public Boolean getOneToOneChatComposingStatus(ContactId contact) {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mOneToOneChatComposingStatusToNotify.get(contact);\n        }\n    }\n\n    /**\n     * Accept store and forward message session with this remoteContact that is not yet accepted.\n     * \n     * @param remoteContact The remote contact\n     */\n    public void acceptStoreAndForwardMessageSessionIfSuchExists(ContactId remoteContact) {\n        TerminatingStoreAndForwardOneToOneChatMessageSession session = getStoreAndForwardMsgSession(remoteContact);\n        if (session == null) {\n            return;\n        }\n        if (session.getDialogPath().isSessionEstablished()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Accept store and forward message session with contact \"\n                    .concat(remoteContact.toString()));\n        }\n        session.acceptSession();\n    }\n\n    /**\n     * Is file transfer already ongoing with specific fileTransferId.\n     * \n     * @param fileTransferId the file transfer ID\n     * @return boolean\n     */\n    public boolean isFileTransferAlreadyOngoing(String fileTransferId) {\n        return getFileSharingSession(fileTransferId) != null;\n    }\n\n    /**\n     * Is file transfer resent and not already ongoing.\n     * \n     * @param fileTransferId the file transfer ID\n     * @return boolean\n     */\n    public boolean isFileTransferResentAndNotAlreadyOngoing(String fileTransferId) {\n        return !isFileTransferAlreadyOngoing(fileTransferId)\n                && mMessagingLog.isFileTransfer(fileTransferId);\n    }\n\n    /**\n     * Try to dequeue of one-to-one chat messages for specific contact\n     * \n     * @param contact the contact ID\n     */\n    public void tryToDequeueOneToOneChatMessages(ContactId contact) {\n        mImOperationHandler.post(new OneToOneChatMessageDequeueTask(mCtx, mCore, contact,\n                mMessagingLog, mChatService, mRcsSettings, mContactManager, mFileTransferService));\n    }\n\n    /**\n     * Try to dequeue group chat messages and group file transfers\n     * \n     * @param chatId the chat ID\n     */\n    public void tryToDequeueGroupChatMessagesAndGroupFileTransfers(String chatId) {\n        mImOperationHandler.post(new GroupChatDequeueTask(mCtx, mCore, mMessagingLog, mChatService,\n                mFileTransferService, mRcsSettings, mContactManager, mHistoryLog, chatId));\n    }\n\n    /**\n     * Try to dequeue all one-to-one chat messages and one-one file transfers\n     */\n    public void tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers() {\n        mImOperationHandler.post(new OneToOneChatDequeueTask(mCtx, mCore, mMessagingLog,\n                mRcsSettings, mChatService, mFileTransferService, mContactManager, mHistoryLog));\n    }\n\n    /**\n     * Try to dequeue one-to-one and group file transfers\n     */\n    public void tryToDequeueFileTransfers() {\n        mImOperationHandler.post(new FileTransferDequeueTask(mCtx, mCore, mMessagingLog,\n                mChatService, mFileTransferService, mContactManager, mRcsSettings));\n    }\n\n    /**\n     * Try to mark all queued group chat messages and group file transfers corresponding to contact\n     * as failed\n     * \n     * @param chatId the chat ID\n     */\n    public void tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(String chatId) {\n        mImOperationHandler.post(new GroupChatTerminalExceptionTask(chatId, mChatService,\n                mFileTransferService, mHistoryLog));\n    }\n\n    /**\n     * Try to send delayed displayed notification after service reconnection\n     */\n    public void tryToDispatchAllPendingDisplayNotifications() {\n        mImOperationHandler.post(new DelayedDisplayNotificationDispatcher(mLocalContentResolver,\n                mChatService));\n    }\n\n    /**\n     * Try to invite queued group chat participants\n     * \n     * @param chatId the chat ID\n     */\n    public void tryToInviteQueuedGroupChatParticipantInvitations(String chatId) {\n        mImOperationHandler.post(new GroupChatInviteQueuedParticipantsTask(chatId, mChatService,\n                this));\n    }\n\n    /**\n     * Handle auto rejoin group chat\n     * \n     * @param chatId the chat ID\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void rejoinGroupChat(String chatId) throws PayloadException, NetworkException {\n        mChatService.rejoinGroupChat(chatId);\n    }\n\n    /**\n     * Handle rejoin group chat as part of send operation\n     * \n     * @param chatId the chat ID\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void rejoinGroupChatAsPartOfSendOperation(String chatId) throws PayloadException,\n            NetworkException {\n        mChatService.rejoinGroupChatAsPartOfSendOperation(chatId);\n    }\n\n    /**\n     * Handle one-one file transfer failure\n     * \n     * @param fileTransferId the file transfer ID\n     * @param contact the contact\n     * @param reasonCode the reason code\n     */\n    public void setOneToOneFileTransferFailureReasonCode(String fileTransferId, ContactId contact,\n            FileTransfer.ReasonCode reasonCode) {\n        mFileTransferService.setOneToOneFileTransferStateAndReasonCode(fileTransferId, contact,\n                FileTransfer.State.FAILED, reasonCode);\n    }\n\n    /**\n     * Deletes all one to one chat from history and abort/reject any associated ongoing session if\n     * such exists.\n     */\n    public void tryToDeleteOneToOneChats() {\n        mImDeleteOperationHandler.post(new OneToOneFileTransferDeleteTask(mFileTransferService,\n                this, mLocalContentResolver));\n        mImDeleteOperationHandler.post(new OneToOneChatMessageDeleteTask(mChatService, this,\n                mLocalContentResolver));\n    }\n\n    /**\n     * Deletes all group chat from history and abort/reject any associated ongoing session if such\n     * exists.\n     */\n    public void tryToDeleteGroupChats() {\n        mImDeleteOperationHandler.post(new GroupFileTransferDeleteTask(mFileTransferService, this,\n                mLocalContentResolver));\n        mImDeleteOperationHandler.post(new GroupChatMessageDeleteTask(mChatService, this,\n                mLocalContentResolver));\n        mImDeleteOperationHandler.post(new GroupChatDeleteTask(mChatService, this,\n                mLocalContentResolver));\n    }\n\n    /**\n     * Deletes a one to one chat with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param contact the contact ID\n     */\n    public void tryToDeleteOneToOneChat(ContactId contact) {\n        mImDeleteOperationHandler.post(new OneToOneFileTransferDeleteTask(mFileTransferService,\n                this, mLocalContentResolver, contact));\n        mImDeleteOperationHandler.post(new OneToOneChatMessageDeleteTask(mChatService, this,\n                mLocalContentResolver, contact));\n    }\n\n    /**\n     * Delete a group chat by its chat id from history and abort/reject any associated ongoing\n     * session if such exists.\n     * \n     * @param chatId the chat ID\n     */\n    public void tryToDeleteGroupChat(String chatId) {\n        mImDeleteOperationHandler.post(new GroupChatMessageDeleteTask(mChatService, this,\n                mLocalContentResolver, chatId));\n        mImDeleteOperationHandler.post(new GroupFileTransferDeleteTask(mFileTransferService, this,\n                mLocalContentResolver, chatId));\n        mImDeleteOperationHandler.post(new GroupChatDeleteTask(mChatService, this,\n                mLocalContentResolver, chatId));\n    }\n\n    /**\n     * Delete a message from its message id from history. Will resolve if the message is one to one\n     * or from a group chat.\n     * \n     * @param msgId the message ID\n     */\n    public void tryToDeleteChatMessage(String msgId) {\n        if (mMessagingLog.isOneToOneChatMessage(msgId)) {\n            mImDeleteOperationHandler.post(new OneToOneChatMessageDeleteTask(mChatService, this,\n                    mLocalContentResolver, msgId));\n        } else {\n            mImDeleteOperationHandler.post(new GroupChatMessageDeleteTask(mChatService, this,\n                    mLocalContentResolver, null, msgId));\n        }\n    }\n\n    /**\n     * Delete a file transfer from its transfer id from history. Will resolve if the message is one\n     * to one or from a group chat.\n     * \n     * @param transferId the file transfer ID\n     */\n    public void tryToDeleteFileTransfer(String transferId) {\n        if (mMessagingLog.isGroupFileTransfer(transferId)) {\n            mImDeleteOperationHandler.post(new GroupFileTransferDeleteTask(mFileTransferService,\n                    this, mLocalContentResolver, mMessagingLog.getFileTransferChatId(transferId),\n                    transferId));\n        } else {\n            mImDeleteOperationHandler.post(new OneToOneFileTransferDeleteTask(mFileTransferService,\n                    this, mLocalContentResolver, transferId));\n        }\n    }\n\n    /**\n     * Try to delete file transfer corresponding to a given one to one chat specified by contact\n     * from history and abort/reject any associated ongoing session if such exists.\n     * \n     * @param contact the contact ID\n     */\n    public void tryToDeleteFileTransfers(ContactId contact) {\n        mImDeleteOperationHandler.post(new OneToOneFileTransferDeleteTask(mFileTransferService,\n                this, mLocalContentResolver, contact));\n    }\n\n    /**\n     * Try to delete all one to one file transfer from history and abort/reject any associated\n     * ongoing session if such exists.\n     */\n    public void tryToDeleteOneToOneFileTransfers() {\n        mImDeleteOperationHandler.post(new OneToOneFileTransferDeleteTask(mFileTransferService,\n                this, mLocalContentResolver));\n    }\n\n    /**\n     * Try to delete all group file transfer from history and abort/reject any associated ongoing\n     * session if such exists.\n     */\n    public void tryToDeleteGroupFileTransfers() {\n        mImDeleteOperationHandler.post(new GroupFileTransferDeleteTask(mFileTransferService, this,\n                mLocalContentResolver));\n    }\n\n    /**\n     * A new file transfer invitation has been received when already in a chat session\n     * \n     * @param fileSharingSession File transfer session\n     * @param isGroup is Group file transfer\n     * @param contact Contact ID\n     * @param displayName the display name of the remote contact\n     */\n    public void receiveFileTransferInvitation(FileSharingSession fileSharingSession,\n            boolean isGroup, ContactId contact, String displayName) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event file transfer invitation\");\n        }\n        mFileTransferService.receiveFileTransferInvitation(fileSharingSession, isGroup, contact,\n                displayName);\n    }\n\n    /**\n     * Handle resend file transfer invitation\n     * \n     * @param session the session\n     * @param contact the contact ID\n     * @param displayName the display name of the remote contact\n     */\n    public void receiveResendFileTransferInvitation(FileSharingSession session, ContactId contact,\n            String displayName) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event file transfer resend invitation\");\n        }\n        mFileTransferService.receiveResendFileTransferInvitation(session, contact, displayName);\n    }\n\n    /**\n     * An incoming file transfer has been resumed\n     * \n     * @param session File transfer session\n     * @param isGroup is group file transfer\n     */\n    public void resumeIncomingFileTransfer(FileSharingSession session, boolean isGroup) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event incoming file transfer resuming\");\n        }\n        mFileTransferService.resumeIncomingFileTransfer(session, isGroup);\n    }\n\n    /**\n     * An outgoing file transfer has been resumed\n     * \n     * @param session File transfer session\n     * @param isGroup is group file transfer\n     */\n    public void resumeOutgoingFileTransfer(FileSharingSession session, boolean isGroup) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event outgoing file transfer resuming\");\n        }\n        mFileTransferService.resumeOutgoingFileTransfer(session, isGroup);\n    }\n\n    /**\n     * Store and Forward messages session invitation\n     * \n     * @param session Chat session\n     */\n    public void receiveStoreAndForwardMsgSessionInvitation(\n            TerminatingStoreAndForwardOneToOneChatMessageSession session) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event S&F messages session invitation\");\n        }\n        mChatService.receiveOneToOneChatInvitation(session);\n    }\n\n    /**\n     * Handle store and forward notification session invitation\n     * \n     * @param session the session\n     */\n    public void receiveStoreAndForwardNotificationSessionInvitation(\n            TerminatingStoreAndForwardOneToOneChatNotificationSession session) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event S&F notification session invitation\");\n        }\n        mChatService.receiveOneToOneChatInvitation(session);\n    }\n\n    /**\n     * New file delivery status\n     * \n     * @param contact who notified status\n     * @param imdn IMDN document\n     */\n    public void receiveOneToOneFileDeliveryStatus(ContactId contact, ImdnDocument imdn) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle file delivery status: fileTransferId=\" + imdn.getMsgId()\n                    + \" notification_type=\" + imdn.getNotificationType() + \" status=\"\n                    + imdn.getStatus() + \" contact=\" + contact);\n        }\n        mFileTransferService.receiveOneToOneFileDeliveryStatus(imdn, contact);\n    }\n\n    /**\n     * New group file delivery status\n     * \n     * @param chatId Chat Id\n     * @param contact who notified status\n     * @param imdn IMDN document\n     */\n    public void receiveGroupFileDeliveryStatus(String chatId, ContactId contact, ImdnDocument imdn) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle group file delivery status: fileTransferId=\" + imdn.getMsgId()\n                    + \" notification_type=\" + imdn.getNotificationType() + \" status=\"\n                    + imdn.getStatus() + \" contact=\" + contact);\n        }\n        mFileTransferService.receiveGroupFileDeliveryStatus(chatId, imdn, contact);\n    }\n\n    /**\n     * Handle imdn DISPLAY report sent for message\n     * \n     * @param chatId the chat ID\n     * @param remote the remote contact\n     * @param msgId the message ID\n     */\n    public void onChatMessageDisplayReportSent(String chatId, ContactId remote, String msgId) {\n        mChatService.onDisplayReportSent(chatId, remote, msgId);\n    }\n\n    /**\n     * Handle one-to-one chat session initiation\n     * \n     * @param session Chat session\n     */\n    public void receiveOneOneChatSessionInitiation(OneToOneChatSession session) {\n        mChatService.receiveOneToOneChatSessionInitiation(session);\n    }\n\n    /**\n     * Handle the case of rejected resend file transfer\n     * \n     * @param fileTransferId the file transfer ID\n     * @param reasonCode Rejected reason code\n     * @param timestamp Local timestamp when got file transfer invitation\n     * @param timestampSent Remote timestamp sent in payload for the file transfer\n     */\n    public void setResendFileTransferInvitationRejected(String fileTransferId,\n            FileTransfer.ReasonCode reasonCode, long timestamp, long timestampSent) {\n        mFileTransferService.setResendFileTransferInvitationRejected(fileTransferId, reasonCode,\n                timestamp, timestampSent);\n    }\n\n    /**\n     * Handle the case of rejected file transfer\n     * \n     * @param remoteContact Remote contact\n     * @param content File content\n     * @param fileIcon File icon content\n     * @param reasonCode Rejected reason code\n     * @param timestamp Local timestamp when got file transfer invitation\n     * @param timestampSent Remote timestamp sent in payload for the file transfer\n     */\n    public void addFileTransferInvitationRejected(ContactId remoteContact, MmContent content,\n            MmContent fileIcon, FileTransfer.ReasonCode reasonCode, long timestamp,\n            long timestampSent) {\n        mFileTransferService.addFileTransferInvitationRejected(remoteContact, content, fileIcon,\n                reasonCode, timestamp, timestampSent);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ChatError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionBasedServiceError;\n\n/**\n * Chat error\n * \n * @author jexa7410\n */\npublic class ChatError extends ImsSessionBasedServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Media session has failed (e.g. MSRP failure)\n     */\n    public final static int MEDIA_SESSION_FAILED = CHAT_ERROR_CODES + 1;\n\n    /**\n     * Subscription to conference package has failed\n     */\n    public final static int SUBSCRIBE_CONFERENCE_FAILED = CHAT_ERROR_CODES + 2;\n\n    /**\n     * Group chat session not found in the server\n     */\n    public final static int SESSION_NOT_FOUND = CHAT_ERROR_CODES + 3;\n\n    /**\n     * Group chat restart has failed\n     */\n    public final static int SESSION_RESTART_FAILED = CHAT_ERROR_CODES + 4;\n\n    /**\n     * Media session can't be used for sending any longer (e.g. MSRP error report received)\n     */\n    public final static int MEDIA_SESSION_BROKEN = CHAT_ERROR_CODES + 5;\n\n    /**\n     * Group chat rejoin has failed\n     */\n    public final static int SESSION_REJOIN_FAILED = CHAT_ERROR_CODES + 6;\n\n    /**\n     * Constructor\n     * \n     * @param error Error code\n     */\n    public ChatError(ImsServiceError error) {\n        super(error.getErrorCode(), error);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public ChatError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public ChatError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ChatError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ChatMessage.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\npublic class ChatMessage {\n\n    private final ContactId mRemote;\n\n    private final String mDisplayName;\n\n    private final String mContent;\n\n    private final String mMimeType;\n\n    /**\n     * Local timestamp for both incoming and outgoing message\n     */\n    private final long mTimestamp;\n\n    /**\n     * Timestamp sent in payload for both incoming and outgoing chat message\n     */\n    private final long mTimestampSent;\n\n    private final String mMsgId;\n\n    /**\n     * Constructor for incoming message\n     * \n     * @param msgId Message ID\n     * @param remote Remote contact\n     * @param content Text message\n     * @param mimeType MIME type\n     * @param timestamp Local timestamp for both incoming and outgoing chat message\n     * @param timestampSent Timestamp sent in payload for both incoming and outgoing chat message\n     * @param displayName the name to display\n     */\n    public ChatMessage(String msgId, ContactId remote, String content, String mimeType,\n            long timestamp, long timestampSent, String displayName) {\n        mMsgId = msgId;\n        mRemote = remote;\n        mContent = content;\n        mMimeType = mimeType;\n        mTimestamp = timestamp;\n        mTimestampSent = timestampSent;\n        mDisplayName = displayName;\n    }\n\n    /**\n     * Gets the message MIME-type\n     * \n     * @return MIME-type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    /**\n     * Gets the message content\n     * \n     * @return message content\n     */\n    public String getContent() {\n        return mContent;\n    }\n\n    /**\n     * Gets the message ID\n     * \n     * @return message ID\n     */\n    public String getMessageId() {\n        return mMsgId;\n    }\n\n    /**\n     * Gets the remote user\n     * \n     * @return the remote contact\n     */\n    public ContactId getRemoteContact() {\n        return mRemote;\n    }\n\n    /**\n     * Gets the local timestamp of when the chat message was sent and/or queued for outgoing\n     * messages or the local timestamp of when the chat message was received for incoming messages..\n     * \n     * @return timestamp\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Get the local timestamp of when the chat message was sent and/or queued for outgoing messages\n     * or the remote timestamp of when the chat message was sent for incoming messages.\n     * \n     * @return timestamp sent in payload\n     */\n    public long getTimestampSent() {\n        return mTimestampSent;\n    }\n\n    /**\n     * Gets the remote display name\n     * \n     * @return remote display name\n     */\n    public String getDisplayName() {\n        return mDisplayName;\n    }\n\n    @Override\n    public String toString() {\n        if (mContent != null && mContent.length() < 30) {\n            return \"IM [from=\" + mRemote + \", pseudo='\" + mDisplayName + \"', msg='\" + mContent\n                    + \"', msgId=\" + mMsgId + \"', mimeType='\" + mMimeType + \"']\" + \"]\";\n        }\n        return \"IM [from=\" + mRemote + \", pseudo='\" + mDisplayName + \"', msgId=\" + mMsgId\n                + \"', mimeType='\" + mMimeType + \"']\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession.isFileCapacityAcceptable;\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionActivityManager;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.core.ims.service.im.chat.iscomposing.IsComposingManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.DownloadFromInviteFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpThumbnail;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\n\nimport android.net.Uri;\n\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n/**\n * Chat session\n *\n * @author jexa7410\n */\npublic abstract class ChatSession extends ImsServiceSession implements MsrpEventListener {\n\n    private String mSubject;\n    private final MsrpManager mMsrpMgr;\n    private final IsComposingManager mIsComposingMgr = new IsComposingManager(this);\n    private final SessionActivityManager mActivityMgr;\n    private String mContributionId;\n    private List<String> mFeatureTags = new ArrayList<>();\n    private List<String> mAcceptContactTags = new ArrayList<>();\n    private String mAcceptTypes = \"\";\n    private String mWrappedTypes = \"\";\n    private static final Logger sLogger = Logger.getLogger(ChatSession.class.getSimpleName());\n\n    protected final MessagingLog mMessagingLog;\n\n    /**\n     * First chat message\n     */\n    private final ChatMessage mFirstMsg;\n\n    protected final InstantMessagingService mImService;\n\n    protected final ImdnManager mImdnManager;\n\n    /**\n     * Receive chat message\n     *\n     * @param msg Chat message\n     * @param msgSupportsImdnReport True if the message type supports imdn reports\n     * @param imdnDisplayedRequested Indicates whether display report was requested\n     * @param cpimMsgId Cpim message Id\n     * @param timestamp Message receive time\n     */\n    protected void receive(ChatMessage msg, ContactId remoteId, boolean msgSupportsImdnReport,\n            boolean imdnDisplayedRequested, String cpimMsgId, long timestamp) {\n        if (mMessagingLog.isMessagePersisted(msg.getMessageId())) {\n            // Message already received\n            return;\n        }\n        // Is composing event is reset\n        mIsComposingMgr.receiveIsComposingEvent(msg.getRemoteContact(), false);\n        if (msgSupportsImdnReport && mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n            try {\n                sendMsrpMessageDeliveryStatus(remoteId, cpimMsgId,\n                        ImdnDocument.DeliveryStatus.DELIVERED, timestamp);\n                for (ImsSessionListener listener : getListeners()) {\n                    ((ChatSessionListener) listener).onMessageReceived(msg, imdnDisplayedRequested,\n                            true);\n                }\n            } catch (NetworkException e) {\n                for (ImsSessionListener listener : getListeners()) {\n                    ((ChatSessionListener) listener).onMessageReceived(msg, imdnDisplayedRequested,\n                            false);\n                }\n            }\n        }\n    }\n\n    /**\n     * Constructor\n     *\n     * @param imService InstantMessagingService\n     * @param contact Remote contactId\n     * @param remoteContact Remote Contact URI\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param firstMsg First message in session\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     */\n    public ChatSession(InstantMessagingService imService, ContactId contact, Uri remoteContact,\n            RcsSettings rcsSettings, MessagingLog messagingLog, ChatMessage firstMsg,\n            long timestamp, ContactManager contactManager) {\n        super(imService, contact, remoteContact, rcsSettings, timestamp, contactManager);\n\n        mImService = imService;\n        mImdnManager = imService.getImdnManager();\n        mMessagingLog = messagingLog;\n        mActivityMgr = new SessionActivityManager(this, mRcsSettings.getChatIdleDuration());\n\n        // Create the MSRP manager\n        int localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(rcsSettings);\n        String localIpAddress = mImService.getImsModule().getCurrentNetworkInterface()\n                .getNetworkAccess().getIpAddress();\n        mMsrpMgr = new MsrpManager(localIpAddress, localMsrpPort, imService, rcsSettings);\n        mFirstMsg = firstMsg;\n    }\n\n    /**\n     * Get feature tags\n     *\n     * @return Feature tags\n     */\n    public String[] getFeatureTags() {\n        return mFeatureTags.toArray(new String[mFeatureTags.size()]);\n    }\n\n    /**\n     * Get Accept-Contact tags\n     *\n     * @return Feature tags\n     */\n    public String[] getAcceptContactTags() {\n        return mAcceptContactTags.toArray(new String[mAcceptContactTags.size()]);\n    }\n\n    /**\n     * Set feature tags\n     *\n     * @param tags Feature tags\n     */\n    public void setFeatureTags(List<String> tags) {\n        mFeatureTags = tags;\n    }\n\n    /**\n     * Set Accept-Contact tags\n     *\n     * @param tags Feature tags\n     */\n    public void setAcceptContactTags(List<String> tags) {\n        mAcceptContactTags = tags;\n    }\n\n    /**\n     * Get accept types\n     *\n     * @return Accept types\n     */\n    protected String getAcceptTypes() {\n        return mAcceptTypes;\n    }\n\n    /**\n     * Add types to accept types\n     *\n     * @param types Accept types\n     */\n    protected void addAcceptTypes(String types) {\n        if (mAcceptTypes.isEmpty()) {\n            mAcceptTypes = types;\n        } else {\n            mAcceptTypes += \" \" + types;\n        }\n    }\n\n    /**\n     * Get wrapped types\n     *\n     * @return Wrapped types\n     */\n    protected String getWrappedTypes() {\n        return mWrappedTypes;\n    }\n\n    /**\n     * Add types to wrapped types\n     *\n     * @param types Wrapped types\n     */\n    protected void addWrappedTypes(String types) {\n        if (mWrappedTypes.isEmpty()) {\n            mWrappedTypes = types;\n        } else {\n            mWrappedTypes += \" \" + types;\n        }\n    }\n\n    /**\n     * Returns the subject of the session\n     *\n     * @return String\n     */\n    public String getSubject() {\n        return mSubject;\n    }\n\n    /**\n     * Set the subject of the session\n     *\n     * @param subject Subject\n     */\n    public void setSubject(String subject) {\n        mSubject = subject;\n    }\n\n    /**\n     * Returns the session activity manager\n     *\n     * @return Activity manager\n     */\n    public SessionActivityManager getActivityManager() {\n        return mActivityMgr;\n    }\n\n    /**\n     * Return the contribution ID\n     *\n     * @return Contribution ID\n     */\n    public String getContributionID() {\n        return mContributionId;\n    }\n\n    /**\n     * Set the contribution ID\n     *\n     * @param id Contribution ID\n     */\n    public void setContributionID(String id) {\n        mContributionId = id;\n    }\n\n    /**\n     * Returns the IM session identity\n     *\n     * @return Identity (e.g. SIP-URI)\n     */\n    public String getImSessionIdentity() {\n        if (getDialogPath() != null) {\n            return getDialogPath().getTarget();\n        }\n        return null;\n    }\n\n    /**\n     * Returns the MSRP manager\n     *\n     * @return MSRP manager\n     */\n    public MsrpManager getMsrpMgr() {\n        return mMsrpMgr;\n    }\n\n    /**\n     * Get first message.\n     *\n     * @return first message\n     */\n    public ChatMessage getFirstMessage() {\n        return mFirstMsg;\n    }\n\n    /**\n     * Close the MSRP session\n     */\n    public void closeMsrpSession() {\n        if (getMsrpMgr() != null) {\n            getMsrpMgr().closeSession();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"MSRP session has been closed\");\n            }\n        }\n    }\n\n    /**\n     * Handle 480 Temporarily Unavailable\n     *\n     * @param resp 480 response\n     */\n    public void handle480Unavailable(SipResponse resp) {\n        handleError(new ChatError(ChatError.SESSION_INITIATION_DECLINED, resp.getReasonPhrase()));\n    }\n\n    /**\n     * Handle 486 Busy\n     *\n     * @param resp 486 response\n     */\n    public void handle486Busy(SipResponse resp) {\n        handleError(new ChatError(ChatError.SESSION_INITIATION_DECLINED, resp.getReasonPhrase()));\n    }\n\n    /**\n     * Handle 603 Decline\n     *\n     * @param resp 603 response\n     */\n    public void handle603Declined(SipResponse resp) {\n        handleDefaultError(resp);\n    }\n\n    /**\n     * Data has been transferred\n     *\n     * @param msgId Message ID\n     */\n    public void msrpDataTransferred(String msgId) {\n        // Update the activity manager\n        mActivityMgr.updateActivity();\n    }\n\n    /**\n     * Session inactivity event\n     *\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    @Override\n    public void handleInactivityEvent() throws PayloadException, NetworkException {\n        terminateSession(TerminationReason.TERMINATION_BY_INACTIVITY);\n    }\n\n    /**\n     * Data transfer has been received\n     *\n     * @param msgId Message ID\n     * @param data Received data\n     * @param mimeType Data mime-type\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public abstract void receiveMsrpData(String msgId, byte[] data, String mimeType)\n            throws PayloadException, NetworkException, ContactManagerException;\n\n    /**\n     * Data transfer in progress\n     *\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size in bytes\n     */\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used by chat\n    }\n\n    /**\n     * Data transfer in progress\n     *\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size in bytes\n     * @param data received data chunk\n     * @return always false TODO\n     */\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        // Not used by chat\n        return false;\n    }\n\n    /**\n     * Data transfer has been aborted\n     */\n    public void msrpTransferAborted() {\n        // Not used by chat\n    }\n\n    /**\n     * Receive is composing event\n     *\n     * @param contact Contact\n     * @param event Event\n     * @throws PayloadException\n     */\n    protected void receiveIsComposing(ContactId contact, byte[] event) throws PayloadException {\n        mIsComposingMgr.receiveIsComposingEvent(contact, event);\n    }\n\n    /**\n     * Send an empty data chunk\n     *\n     * @throws NetworkException\n     */\n    public void sendEmptyDataChunk() throws NetworkException {\n        mMsrpMgr.sendEmptyChunk();\n    }\n\n    private void handleFileTransferInvitationRejected(ContactId contact, MmContent content,\n            MmContent fileIcon, FileTransfer.ReasonCode reasonCode, long timestamp,\n            long timestampSent) {\n        mImService.addFileTransferInvitationRejected(contact, content, fileIcon, reasonCode,\n                timestamp, timestampSent);\n    }\n\n    private void handleResendFileTransferInvitationRejected(String fileTransferId,\n            FileTransfer.ReasonCode reasonCode, long timestamp, long timestampSent) {\n        mImService.setResendFileTransferInvitationRejected(fileTransferId, reasonCode, timestamp,\n                timestampSent);\n    }\n\n    /**\n     * Receive HTTP file transfer event\n     *\n     * @param contact the remote contact\n     * @param displayName Display Name\n     * @param fileTransferInfo Information of on file to transfer over HTTP\n     * @param msgId Message ID\n     * @param timestamp The local timestamp of the message for receiving a HttpFileTransfer\n     * @param timestampSent Remote timestamp sent in payload for receiving a HttpFileTransfer\n     * @throws PayloadException\n     * @throws ContactManagerException\n     * @throws NetworkException\n     */\n    protected void receiveHttpFileTransfer(ContactId contact, String displayName,\n            FileTransferHttpInfoDocument fileTransferInfo, String msgId, long timestamp,\n            long timestampSent) throws PayloadException, ContactManagerException, NetworkException {\n        try {\n            /*\n             * Update the remote contact's capabilities to include at least HTTP FT and IM session\n             * capabilities as we have just received a HTTP file transfer invitation from this\n             * contact so he/she must at least have this capability. We do not need any capability\n             * exchange response to determine that.\n             */\n            mContactManager.mergeContactCapabilities(contact,\n                    new CapabilitiesBuilder().setImSession(true).setFileTransferHttp(true)\n                            .setTimestampOfLastResponse(timestamp).build(), RcsStatus.RCS_CAPABLE,\n                    RegistrationState.ONLINE, displayName);\n\n            FileTransferHttpThumbnail fileTransferHttpThumbnail = fileTransferInfo\n                    .getFileThumbnail();\n            if (mImService.isFileTransferAlreadyOngoing(msgId)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"File transfer with fileTransferId '\" + msgId\n                            + \"' already ongoing, so ignoring this one.\");\n                }\n                return;\n            }\n            boolean fileResent = mImService.isFileTransferResentAndNotAlreadyOngoing(msgId);\n            if (mContactManager.isBlockedForContact(contact)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Contact \" + contact\n                            + \" is blocked, reject the HTTP File transfer\");\n                }\n                if (fileResent) {\n                    handleResendFileTransferInvitationRejected(msgId, ReasonCode.REJECTED_SPAM,\n                            timestamp, timestampSent);\n                    return;\n                }\n                MmContent fileIconContent = (fileTransferHttpThumbnail == null) ? null\n                        : fileTransferHttpThumbnail.getLocalMmContent(msgId);\n                handleFileTransferInvitationRejected(contact, fileTransferInfo.getLocalMmContent(),\n                        fileIconContent, ReasonCode.REJECTED_SPAM, timestamp, timestampSent);\n                return;\n            }\n\n            /* Auto reject if file too big or size exceeds device storage capacity. */\n            FileSharingError error = isFileCapacityAcceptable(fileTransferInfo.getSize(),\n                    mRcsSettings);\n            if (error != null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"File is too big or exceeds storage capacity, \"\n                            .concat(\"reject the HTTP File transfer.\"));\n                }\n                MmContent fileIconContent = (fileTransferHttpThumbnail == null) ? null\n                        : fileTransferHttpThumbnail.getLocalMmContent(msgId);\n\n                int errorCode = error.getErrorCode();\n                switch (errorCode) {\n                    case FileSharingError.MEDIA_SIZE_TOO_BIG:\n                        if (fileResent) {\n                            handleResendFileTransferInvitationRejected(msgId,\n                                    ReasonCode.REJECTED_MAX_SIZE, timestamp, timestampSent);\n                            break;\n                        }\n                        handleFileTransferInvitationRejected(contact,\n                                fileTransferInfo.getLocalMmContent(), fileIconContent,\n                                ReasonCode.REJECTED_MAX_SIZE, timestamp, timestampSent);\n                        break;\n                    case FileSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                        if (fileResent) {\n                            handleResendFileTransferInvitationRejected(msgId,\n                                    ReasonCode.REJECTED_LOW_SPACE, timestamp, timestampSent);\n                            break;\n                        }\n                        handleFileTransferInvitationRejected(contact,\n                                fileTransferInfo.getLocalMmContent(), fileIconContent,\n                                ReasonCode.REJECTED_LOW_SPACE, timestamp, timestampSent);\n                        break;\n                    default:\n                        if (sLogger.isActivated()) {\n                            sLogger.error(\"Unexpected error while receiving HTTP file transfer.\"\n                                    .concat(Integer.toString(errorCode)));\n                        }\n                }\n                return;\n            }\n            if (!mImService.getImsModule().getInstantMessagingService()\n                    .isFileTransferSessionAvailable()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Max number of File Transfer reached, reject the HTTP File transfer\");\n                }\n                MmContent fileIconContent = (fileTransferHttpThumbnail == null) ? null\n                        : fileTransferHttpThumbnail.getLocalMmContent(msgId);\n                if (fileResent) {\n                    handleResendFileTransferInvitationRejected(msgId,\n                            ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp, timestampSent);\n                    return;\n                }\n                handleFileTransferInvitationRejected(contact, fileTransferInfo.getLocalMmContent(),\n                        fileIconContent, ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp,\n                        timestampSent);\n                return;\n            }\n            DownloadFromInviteFileSharingSession fileSession = new DownloadFromInviteFileSharingSession(\n                    mImService, this, fileTransferInfo, msgId, contact, displayName, mRcsSettings,\n                    mMessagingLog, timestamp, timestampSent, mContactManager);\n            if (fileTransferHttpThumbnail != null) {\n                try {\n                    fileSession.downloadFileIcon();\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to download file icon! (\" + e.getMessage() + \")\");\n                    }\n                    MmContent fileIconContent = fileTransferHttpThumbnail.getLocalMmContent(msgId);\n                    if (fileResent) {\n                        handleResendFileTransferInvitationRejected(msgId,\n                                ReasonCode.REJECTED_MAX_FILE_TRANSFERS, timestamp, timestampSent);\n                        return;\n                    }\n                    handleFileTransferInvitationRejected(contact,\n                            fileTransferInfo.getLocalMmContent(), fileIconContent,\n                            ReasonCode.REJECTED_MEDIA_FAILED, timestamp, timestampSent);\n                    return;\n                }\n            }\n            if (fileResent) {\n                mImService.receiveResendFileTransferInvitation(fileSession, contact, displayName);\n            } else {\n                mImService.receiveFileTransferInvitation(fileSession, isGroupChat(), contact,\n                        displayName);\n            }\n\n            if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n                sendMsrpMessageDeliveryStatus(contact, msgId,\n                        ImdnDocument.DeliveryStatus.DELIVERED, timestamp);\n            }\n            fileSession.startSession();\n\n        } catch (FileAccessException e) {\n            throw new PayloadException(\"Failed to receive file transfer with fileTransferId : \"\n                    + msgId + \"for contact : \" + contact, e);\n        }\n    }\n\n    /**\n     * Send data chunk with a specified MIME type\n     *\n     * @param msgId Message ID\n     * @param data Data\n     * @param mime MIME type\n     * @param typeMsrpChunk Type of MSRP chunk\n     * @throws NetworkException\n     */\n    public void sendDataChunks(String msgId, String data, String mime, TypeMsrpChunk typeMsrpChunk)\n            throws NetworkException {\n        byte[] bytes = data.getBytes(UTF8);\n        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);\n        mMsrpMgr.sendChunks(stream, msgId, mime, bytes.length, typeMsrpChunk);\n    }\n\n    /**\n     * Is group chat\n     *\n     * @return Boolean\n     */\n    public abstract boolean isGroupChat();\n\n    /**\n     * Send a chat message\n     *\n     * @param msg Chat message\n     * @throws NetworkException\n     */\n    public abstract void sendChatMessage(ChatMessage msg) throws NetworkException;\n\n    /**\n     * Send is composing status\n     *\n     * @param status Status\n     * @throws NetworkException\n     */\n    public abstract void sendIsComposingStatus(boolean status) throws NetworkException;\n\n    /**\n     * Send message delivery status via MSRP\n     *\n     * @param remote Contact that requested the delivery status\n     * @param msgId Message ID\n     * @param status Status\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     * @throws NetworkException\n     */\n    public abstract void sendMsrpMessageDeliveryStatus(ContactId remote, String msgId,\n            ImdnDocument.DeliveryStatus status, long timestamp) throws NetworkException;\n\n    /**\n     * Receive a message delivery status from an XML document\n     *\n     * @param contact Contact identifier\n     * @param xml XML document\n     * @throws PayloadException\n     */\n    public void onDeliveryStatusReceived(ContactId contact, String xml) throws PayloadException {\n        try {\n            ImdnDocument imdn = ChatUtils.parseDeliveryReport(xml);\n            for (ImsSessionListener listener : getListeners()) {\n                ((ChatSessionListener) listener).onDeliveryStatusReceived(mContributionId, contact,\n                        imdn);\n            }\n        } catch (SAXException | ParserConfigurationException | ParseFailureException e) {\n            throw new PayloadException(\"Failed to parse IMDN document for contact : \" + contact, e);\n        }\n    }\n\n    /**\n     * Prepare media session\n     */\n    public void prepareMediaSession() {\n        // Get the remote SDP part\n        byte[] sdp = getDialogPath().getRemoteContent().getBytes(UTF8);\n        // Create the MSRP session\n        MsrpSession session = getMsrpMgr().createMsrpSession(sdp, this);\n        session.setFailureReportOption(false);\n        session.setSuccessReportOption(false);\n    }\n\n    /**\n     * Open media session\n     *\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void openMediaSession() throws PayloadException, NetworkException {\n        getMsrpMgr().openMsrpSession();\n        sendEmptyDataChunk();\n    }\n\n    /**\n     * Start media transfer\n     */\n    public void startMediaTransfer() {\n        /* Not used here */\n    }\n\n    /**\n     * Reject the session invitation\n     */\n    public abstract void rejectSession();\n\n    /**\n     * Is media session established\n     *\n     * @return true If the empty packet was sent successfully\n     */\n    public boolean isMediaEstablished() {\n        return getMsrpMgr().isEstablished() && !getDialogPath().isSessionTerminated();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ChatSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Chat session listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface ChatSessionListener extends ImsSessionListener {\n    /**\n     * New message received\n     * \n     * @param msg Chat message\n     * @param imdnDisplayedRequested Indicates whether display notification is requested\n     * @param deliverySuccess True is delivery report succeeded\n     */\n    void onMessageReceived(ChatMessage msg, boolean imdnDisplayedRequested,\n            boolean deliverySuccess);\n\n    /**\n     * Is composing event\n     * \n     * @param contact Contact identifier\n     * @param status Status\n     */\n    void onIsComposingEventReceived(ContactId contact, boolean status);\n\n    /**\n     * Notifying that a message has been sent\n     * \n     * @param msgId Message ID\n     * @param mimeType MIME type\n     */\n    void onMessageSent(String msgId, String mimeType);\n\n    /**\n     * Notifying failure of sending message\n     * \n     * @param msgId Message ID\n     * @param mimeType MIME type\n     */\n    void onMessageFailedSend(String msgId, String mimeType);\n\n    /**\n     * New message delivery status that are received as part of imdn notification\n     * \n     * @param contact the remote contact identifier\n     * @param imdn Imdn document\n     */\n    void onMessageDeliveryStatusReceived(ContactId contact, ImdnDocument imdn);\n\n    /**\n     * New message or file transfer delivery status that are received as part of imdn notification\n     * \n     * @param contributionId Contribution ID\n     * @param contact the remote contact identifier\n     * @param imdn Imdn Document\n     */\n    void onDeliveryStatusReceived(String contributionId, ContactId contact, ImdnDocument imdn);\n\n    /**\n     * Handle imdn DISPLAY report sent for message\n     * \n     * @param msgId Message ID\n     */\n    void onChatMessageDisplayReportSent(String msgId);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ChatUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\nimport static com.gsma.rcs.utils.StringUtils.UTF8_STR;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimParser;\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoParser;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnParser;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.iscomposing.IsComposingInfo;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpResumeInfo;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpResumeInfoParser;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.text.TextUtils;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n * Chat utility functions\n * \n * @author jexa7410\n */\npublic class ChatUtils {\n    /**\n     * Anonymous URI\n     */\n    public final static String ANONYMOUS_URI = \"sip:anonymous@anonymous.invalid\";\n\n    /**\n     * Contribution ID header\n     */\n    public static final String HEADER_CONTRIBUTION_ID = \"Contribution-ID\";\n\n    private static final String CRLF = \"\\r\\n\";\n\n    private static final Logger sLogger = Logger.getLogger(ChatUtils.class.getName());\n\n    /**\n     * Get supported feature tags for a group chat\n     * \n     * @param rcsSettings the RCS settings accessor\n     * @return List of tags\n     */\n    public static List<String> getSupportedFeatureTagsForGroupChat(RcsSettings rcsSettings) {\n        List<String> tags = new ArrayList<>();\n        tags.add(FeatureTags.FEATURE_OMA_IM);\n        List<String> additionalRcseTags = new ArrayList<>();\n        if (rcsSettings.isGeoLocationPushSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_GEOLOCATION_PUSH);\n        }\n        if (rcsSettings.isFileTransferSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_FT);\n        }\n        if (rcsSettings.isFileTransferHttpSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_FT_HTTP);\n        }\n        if (rcsSettings.isFileTransferStoreForwardSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_FT_SF);\n        }\n        if (!additionalRcseTags.isEmpty()) {\n            tags.add(FeatureTags.FEATURE_RCSE + \"=\\\"\" + TextUtils.join(\",\", additionalRcseTags)\n                    + \"\\\"\");\n        }\n        return tags;\n    }\n\n    /**\n     * Get Accept-Contact tags for a group chat\n     * \n     * @return List of tags\n     */\n    public static List<String> getAcceptContactTagsForGroupChat() {\n        List<String> tags = new ArrayList<>();\n        tags.add(FeatureTags.FEATURE_OMA_IM);\n        return tags;\n    }\n\n    /**\n     * Get supported feature tags for a chat\n     * \n     * @param rcsSettings the RCS settings accessor\n     * @return List of tags\n     */\n    public static List<String> getSupportedFeatureTagsForChat(RcsSettings rcsSettings) {\n        List<String> tags = new ArrayList<>();\n        tags.add(FeatureTags.FEATURE_OMA_IM);\n        List<String> additionalRcseTags = new ArrayList<>();\n        if (rcsSettings.isGeoLocationPushSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_GEOLOCATION_PUSH);\n        }\n        if (rcsSettings.isFileTransferSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_FT);\n        }\n        if (rcsSettings.isFileTransferHttpSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_FT_HTTP);\n        }\n        if (rcsSettings.isFileTransferStoreForwardSupported()) {\n            additionalRcseTags.add(FeatureTags.FEATURE_RCSE_FT_SF);\n        }\n        if (!additionalRcseTags.isEmpty()) {\n            tags.add(FeatureTags.FEATURE_RCSE + \"=\\\"\" + TextUtils.join(\",\", additionalRcseTags)\n                    + \"\\\"\");\n        }\n        return tags;\n    }\n\n    /**\n     * Get contribution ID\n     * \n     * @param request the SIP request\n     * @return String\n     */\n    public static String getContributionId(SipRequest request) {\n        ExtensionHeader contribHeader = (ExtensionHeader) request.getHeader(HEADER_CONTRIBUTION_ID);\n        if (contribHeader != null) {\n            return contribHeader.getValue();\n        }\n        return null;\n    }\n\n    /**\n     * Is a group chat session invitation\n     * \n     * @param request Request\n     * @return Boolean\n     */\n    public static boolean isGroupChatInvitation(SipRequest request) {\n        ContactHeader contactHeader = (ContactHeader) request.getHeader(ContactHeader.NAME);\n        String param = contactHeader.getParameter(\"isfocus\");\n        return param != null;\n    }\n\n    /**\n     * Get referred identity as a ContactId\n     * \n     * @param request SIP request\n     * @return ContactId\n     */\n    public static ContactId getReferredIdentityAsContactId(SipRequest request) {\n        /* First use the Referred-By header */\n        String referredBy = SipUtils.getReferredByHeader(request);\n        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(referredBy);\n        if (number == null) {\n            /* Use the Asserted-Identity header if parsing of Referred-By header failed */\n            String assertedId = SipUtils.getAssertedIdentity(request);\n            number = ContactUtil.getValidPhoneNumberFromUri(assertedId);\n            if (number == null) {\n                return null;\n            }\n        }\n        return ContactUtil.createContactIdFromValidatedData(number);\n    }\n\n    /**\n     * Get referred identity as a contact URI\n     * \n     * @param request SIP request\n     * @return SIP URI\n     */\n    public static String getReferredIdentityAsContactUri(SipRequest request) {\n        String referredBy = SipUtils.getReferredByHeader(request);\n        if (referredBy != null) {\n            // Use the Referred-By header\n            return referredBy;\n        }\n        // Use the Asserted-Identity header\n        return SipUtils.getAssertedIdentity(request);\n    }\n\n    /**\n     * Is a plain text type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isTextPlainType(String mime) {\n        return mime != null && mime.toLowerCase().startsWith(MimeType.TEXT_MESSAGE);\n    }\n\n    /**\n     * Is a composing event type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isApplicationIsComposingType(String mime) {\n        return mime != null && mime.toLowerCase().startsWith(IsComposingInfo.MIME_TYPE);\n    }\n\n    /**\n     * Is a CPIM message type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isMessageCpimType(String mime) {\n        return mime != null && mime.toLowerCase().startsWith(CpimMessage.MIME_TYPE);\n    }\n\n    /**\n     * Is an IMDN message type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isMessageImdnType(String mime) {\n        return mime != null && mime.toLowerCase().startsWith(ImdnDocument.MIME_TYPE);\n    }\n\n    /**\n     * Is a geolocation event type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isGeolocType(String mime) {\n        return mime != null && mime.toLowerCase().startsWith(GeolocInfoDocument.MIME_TYPE);\n    }\n\n    /**\n     * Generate resource-list for a chat session\n     * \n     * @param participants Set of participants\n     * @return XML document\n     */\n    public static String generateChatResourceList(Set<ContactId> participants) {\n        StringBuilder resources = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\")\n                .append(UTF8_STR).append(\"\\\"?>\").append(CRLF)\n                .append(\"<resource-lists xmlns=\\\"urn:ietf:params:xml:ns:resource-lists\\\" \")\n                .append(\"xmlns:cp=\\\"urn:ietf:params:xml:ns:copycontrol\\\">\").append(\"<list>\")\n                .append(CRLF);\n        for (ContactId contact : participants) {\n            resources.append(\" <entry uri=\\\"\").append(PhoneUtils.formatContactIdToUri(contact))\n                    .append(\"\\\" cp:copyControl=\\\"to\\\"/>\").append(CRLF);\n        }\n        return resources.append(\"</list></resource-lists>\").toString();\n    }\n\n    /**\n     * Get participants from contacts\n     * \n     * @param contacts contacts\n     * @param status status\n     * @return participants\n     */\n    public static Map<ContactId, ParticipantStatus> getParticipants(Set<ContactId> contacts,\n            ParticipantStatus status) {\n        Map<ContactId, ParticipantStatus> participants = new HashMap<>();\n        for (ContactId contact : contacts) {\n            participants.put(contact, status);\n        }\n        return participants;\n    }\n\n    /**\n     * Is IMDN service\n     * \n     * @param request Request\n     * @return Boolean\n     */\n    public static boolean isImdnService(SipRequest request) {\n        String content = request.getContent();\n        String contentType = request.getContentType();\n        return (content != null) && (content.contains(ImdnDocument.IMDN_NAMESPACE))\n                && (contentType != null) && (contentType.equalsIgnoreCase(CpimMessage.MIME_TYPE));\n    }\n\n    /**\n     * Is IMDN notification \"displayed\" requested\n     * \n     * @param request Request\n     * @return Boolean\n     * @throws PayloadException\n     */\n    public static boolean isImdnDisplayedRequested(SipRequest request) throws PayloadException {\n        /* Read ID from multipart content */\n        String content = request.getContent();\n        SipUtils.assertContentIsNotNull(content, request);\n        int index = content.indexOf(ImdnUtils.HEADER_IMDN_DISPO_NOTIF);\n        if (index == -1) {\n            return false;\n        }\n        index = index + ImdnUtils.HEADER_IMDN_DISPO_NOTIF.length() + 1;\n        String part = content.substring(index);\n        String notif = part.substring(0, part.indexOf(CRLF));\n        return notif.indexOf(ImdnDocument.DISPLAY) != -1;\n    }\n\n    /**\n     * Returns the message ID from a SIP request\n     * \n     * @param request Request\n     * @return Message ID\n     * @throws PayloadException\n     */\n    public static String getMessageId(SipRequest request) throws PayloadException {\n        /* Read ID from multipart content */\n        String content = request.getContent();\n        SipUtils.assertContentIsNotNull(content, request);\n        int index = content.indexOf(ImdnUtils.HEADER_IMDN_MSG_ID);\n        if (index == -1) {\n            return null;\n        }\n        index = index + ImdnUtils.HEADER_IMDN_MSG_ID.length() + 1;\n        String part = content.substring(index);\n        return part.substring(0, part.indexOf(CRLF)).trim();\n    }\n\n    // @FIXME: This method should have URI as parameter instead of String\n    private static String addUriDelimiters(String uri) {\n        return PhoneUtils.URI_START_DELIMITER + uri + PhoneUtils.URI_END_DELIMITER;\n    }\n\n    /**\n     * Format to a SIP-URI for CPIM message\n     * \n     * @param input Input\n     * @return SIP-URI\n     */\n    private static String formatCpimSipUri(String input) {\n        input = input.trim();\n        if (input.startsWith(PhoneUtils.URI_START_DELIMITER)) {\n            /* Already a SIP-URI format */\n            return input;\n        }\n        /* It's already a SIP address with display name */\n        if (input.startsWith(\"\\\"\")) {\n            return input;\n        }\n        if (input.startsWith(PhoneUtils.SIP_URI_HEADER)\n                || input.startsWith(PhoneUtils.TEL_URI_HEADER)) {\n            /* It is already a SIP or TEL URI: just add URI delimiters */\n            return addUriDelimiters(input);\n        }\n        PhoneNumber validatedNumber = ContactUtil.getValidPhoneNumberFromUri(input);\n        if (validatedNumber == null) {\n            /* It's not a valid phone number: just add URI delimiters */\n            return addUriDelimiters(input);\n        }\n        /* It's a valid phone number, format it to URI and add delimiters */\n        ContactId contact = ContactUtil.createContactIdFromValidatedData(validatedNumber);\n        // @FIXME: This method should have URI as parameter instead of String\n        return addUriDelimiters(PhoneUtils.formatContactIdToUri(contact).toString());\n    }\n\n    /**\n     * Build a CPIM message\n     * \n     * @param from From\n     * @param to To\n     * @param content Content\n     * @param contentType Content type\n     * @param timestampSent Timestamp sent in payload for CPIM DateTimes\n     * @return String\n     */\n    public static String buildCpimMessage(String from, String to, String content,\n            String contentType, long timestampSent) {\n        return CpimMessage.HEADER_FROM + \": \" + formatCpimSipUri(from) + CRLF\n                + CpimMessage.HEADER_TO + \": \" + formatCpimSipUri(to) + CRLF\n                + CpimMessage.HEADER_DATETIME + \": \" + DateUtils.encodeDate(timestampSent) + CRLF\n                + CRLF + CpimMessage.HEADER_CONTENT_TYPE + \": \" + contentType + \";charset=\"\n                + UTF8_STR + CRLF + CRLF + content;\n    }\n\n    /**\n     * Build a CPIM message with full IMDN headers\n     * \n     * @param from From URI\n     * @param to To URI\n     * @param messageId Message ID\n     * @param content Content\n     * @param contentType Content type\n     * @param timestampSent Timestamp sent in payload for CPIM DateTime\n     * @return String\n     */\n    public static String buildCpimMessageWithImdn(String from, String to, String messageId,\n            String content, String contentType, long timestampSent) {\n        return CpimMessage.HEADER_FROM + \": \" + formatCpimSipUri(from) + CRLF\n                + CpimMessage.HEADER_TO + \": \" + formatCpimSipUri(to) + CRLF\n                + CpimMessage.HEADER_NS + \": \" + ImdnDocument.IMDN_NAMESPACE + CRLF\n                + ImdnUtils.HEADER_IMDN_MSG_ID + \": \" + messageId + CRLF\n                + CpimMessage.HEADER_DATETIME + \": \" + DateUtils.encodeDate(timestampSent) + CRLF\n                + ImdnUtils.HEADER_IMDN_DISPO_NOTIF + \": \" + ImdnDocument.POSITIVE_DELIVERY + \", \"\n                + ImdnDocument.DISPLAY + CRLF + CRLF + CpimMessage.HEADER_CONTENT_TYPE + \": \"\n                + contentType + \";charset=\" + UTF8_STR + CRLF + CpimMessage.HEADER_CONTENT_LENGTH\n                + \": \" + content.getBytes(UTF8).length + CRLF + CRLF + content;\n    }\n\n    /**\n     * Build a CPIM message with IMDN delivered header\n     * \n     * @param from From URI\n     * @param to To URI\n     * @param messageId Message ID\n     * @param content Content\n     * @param contentType Content type\n     * @param timestampSent Timestamp sent in payload for CPIM DateTime\n     * @return String\n     */\n    public static String buildCpimMessageWithoutDisplayedImdn(String from, String to,\n            String messageId, String content, String contentType, long timestampSent) {\n        return CpimMessage.HEADER_FROM + \": \" + formatCpimSipUri(from) + CRLF\n                + CpimMessage.HEADER_TO + \": \" + formatCpimSipUri(to) + CRLF\n                + CpimMessage.HEADER_NS + \": \" + ImdnDocument.IMDN_NAMESPACE + CRLF\n                + ImdnUtils.HEADER_IMDN_MSG_ID + \": \" + messageId + CRLF\n                + CpimMessage.HEADER_DATETIME + \": \" + DateUtils.encodeDate(timestampSent) + CRLF\n                + ImdnUtils.HEADER_IMDN_DISPO_NOTIF + \": \" + ImdnDocument.POSITIVE_DELIVERY + CRLF\n                + CRLF + CpimMessage.HEADER_CONTENT_TYPE + \": \" + contentType + \";charset=\"\n                + UTF8_STR + CRLF + CpimMessage.HEADER_CONTENT_LENGTH + \": \"\n                + content.getBytes(UTF8).length + CRLF + CRLF + content;\n    }\n\n    /**\n     * Build a CPIM delivery report\n     * \n     * @param from From\n     * @param to To\n     * @param imdn IMDN report\n     * @param timestampSent Timestamp sent in payload for CPIM DateTime\n     * @return String\n     */\n    public static String buildCpimDeliveryReport(String from, String to, String imdn,\n            long timestampSent) {\n        return CpimMessage.HEADER_FROM + \": \" + formatCpimSipUri(from) + CRLF\n                + CpimMessage.HEADER_TO + \": \" + formatCpimSipUri(to) + CRLF\n                + CpimMessage.HEADER_NS + \": \" + ImdnDocument.IMDN_NAMESPACE + CRLF\n                + ImdnUtils.HEADER_IMDN_MSG_ID + \": \" + IdGenerator.generateMessageID() + CRLF\n                + CpimMessage.HEADER_DATETIME + \": \" + DateUtils.encodeDate(timestampSent) + CRLF\n                + CRLF + CpimMessage.HEADER_CONTENT_TYPE + \": \" + ImdnDocument.MIME_TYPE + CRLF\n                + CpimMessage.HEADER_CONTENT_DISPOSITION + \": \" + ImdnDocument.NOTIFICATION + CRLF\n                + CpimMessage.HEADER_CONTENT_LENGTH + \": \" + imdn.getBytes(UTF8).length + CRLF\n                + CRLF + imdn;\n    }\n\n    /**\n     * Parse a CPIM delivery report\n     * \n     * @param cpim CPIM document\n     * @return IMDN document\n     * @throws ParseFailureException\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     */\n    public static ImdnDocument parseCpimDeliveryReport(String cpim) throws SAXException,\n            ParserConfigurationException, ParseFailureException {\n        ImdnDocument imdn = null;\n        // Parse CPIM document\n        CpimParser cpimParser = new CpimParser(cpim);\n        CpimMessage cpimMsg = cpimParser.getCpimMessage();\n        if (cpimMsg != null) {\n            // Check if the content is a IMDN message\n            String contentType = cpimMsg.getContentType();\n            if ((contentType != null) && isMessageImdnType(contentType)) {\n                // Parse the IMDN document\n                imdn = parseDeliveryReport(cpimMsg.getMessageContent());\n            }\n        }\n        return imdn;\n    }\n\n    /**\n     * Parse a delivery report\n     * \n     * @param xml XML document\n     * @return IMDN document\n     * @throws ParseFailureException\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     */\n    public static ImdnDocument parseDeliveryReport(String xml) throws SAXException,\n            ParserConfigurationException, ParseFailureException {\n        InputSource input = new InputSource(new ByteArrayInputStream(xml.getBytes()));\n        ImdnParser parser = new ImdnParser(input).parse();\n        return parser.getImdnDocument();\n    }\n\n    /**\n     * Build a delivery report\n     * \n     * @param msgId Message ID\n     * @param status Status\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     * @return XML document\n     */\n    public static String buildImdnDeliveryReport(String msgId, ImdnDocument.DeliveryStatus status,\n            long timestamp) {\n        String method;\n        switch (status) {\n            case DISPLAYED:\n                method = \"display-notification\";\n                break;\n            case DELIVERED:\n                method = \"delivery-notification\";\n                break;\n            default:\n                method = \"processing-notification\";\n                break;\n        }\n        return \"<?xml version=\\\"1.0\\\" encoding=\\\"\" + UTF8_STR + \"\\\"?>\" + CRLF\n                + \"<imdn xmlns=\\\"urn:ietf:params:xml:ns:imdn\\\">\" + CRLF + \"<message-id>\" + msgId\n                + \"</message-id>\" + CRLF + \"<datetime>\" + DateUtils.encodeDate(timestamp)\n                + \"</datetime>\" + CRLF + \"<\" + method + \"><status><\" + status + \"/></status></\"\n                + method + \">\" + CRLF + \"</imdn>\";\n    }\n\n    /**\n     * Build a geoloc document\n     * \n     * @param geoloc Geolocation\n     * @param contact Contact\n     * @param msgId Message ID\n     * @param timestamp Local timestamp\n     * @return XML document\n     */\n    public static String buildGeolocDocument(Geoloc geoloc, String contact, String msgId,\n            long timestamp) {\n        String expire = DateUtils.encodeDate(geoloc.getExpiration());\n        String label = geoloc.getLabel();\n        if (label == null) {\n            label = \"\";\n        }\n        return \"<?xml version=\\\"1.0\\\" encoding=\\\"\" + UTF8_STR + \"\\\"?>\" + CRLF\n                + \"<rcsenvelope xmlns=\\\"urn:gsma:params:xml:ns:rcs:rcs:geolocation\\\"\"\n                + \" xmlns:rpid=\\\"urn:ietf:params:xml:ns:pidf:rpid\\\"\"\n                + \" xmlns:gp=\\\"urn:ietf:params:xml:ns:pidf:geopriv10\\\"\"\n                + \" xmlns:gml=\\\"http://www.opengis.net/gml\\\"\"\n                + \" xmlns:gs=\\\"http://www.opengis.net/pidflo/1.0\\\"\" + \" entity=\\\"\" + contact\n                + \"\\\">\" + CRLF + \"<rcspushlocation id=\\\"\" + msgId + \"\\\" label=\\\"\" + label + \"\\\" >\"\n                + \"<rpid:place-type rpid:until=\\\"\" + expire + \"\\\">\" + \"</rpid:place-type>\" + CRLF\n                + \"<rpid:time-offset rpid:until=\\\"\" + expire + \"\\\"></rpid:time-offset>\" + CRLF\n                + \"<gp:geopriv>\" + CRLF + \"<gp:location-info>\" + CRLF\n                + \"<gs:Circle srsName=\\\"urn:ogc:def:crs:EPSG::4326\\\">\" + CRLF + \"<gml:pos>\"\n                + geoloc.getLatitude() + \" \" + geoloc.getLongitude() + \"</gml:pos>\" + CRLF\n                + \"<gs:radius uom=\\\"urn:ogc:def:uom:EPSG::9001\\\">\" + geoloc.getAccuracy()\n                + \"</gs:radius>\" + CRLF + \"</gs:Circle>\" + CRLF + \"</gp:location-info>\" + CRLF\n                + \"<gp:usage-rules>\" + CRLF + \"<gp:retention-expiry>\" + expire\n                + \"</gp:retention-expiry>\" + CRLF + \"</gp:usage-rules>\" + CRLF + \"</gp:geopriv>\"\n                + CRLF + \"<timestamp>\" + DateUtils.encodeDate(timestamp) + \"</timestamp>\" + CRLF\n                + \"</rcspushlocation>\" + CRLF + \"</rcsenvelope>\" + CRLF;\n    }\n\n    /**\n     * Parse a geoloc document\n     * \n     * @param xml XML document\n     * @return Geolocation\n     * @throws PayloadException\n     */\n    public static Geoloc parseGeolocDocument(String xml) throws PayloadException {\n        try {\n            InputSource geolocInput = new InputSource(new ByteArrayInputStream(xml.getBytes(UTF8)));\n            GeolocInfoParser geolocParser = new GeolocInfoParser(geolocInput).parse();\n            GeolocInfoDocument geolocDocument = geolocParser.getGeoLocInfo();\n            if (geolocDocument == null) {\n                throw new PayloadException(\"Unable to parse geoloc document!\");\n            }\n            return new Geoloc(geolocDocument.getLabel(), geolocDocument.getLatitude(),\n                    geolocDocument.getLongitude(), geolocDocument.getExpiration(),\n                    geolocDocument.getRadius());\n\n        } catch (ParserConfigurationException | ParseFailureException | SAXException e) {\n            throw new PayloadException(\"Unable to parse geoloc document!\", e);\n        }\n    }\n\n    /**\n     * Parse a file transfer resume info\n     * \n     * @param xml XML document\n     * @return File transfer resume info\n     * @throws IOException\n     * @throws SAXException\n     * @throws ParserConfigurationException\n     */\n    public static FileTransferHttpResumeInfo parseFileTransferHttpResumeInfo(byte[] xml)\n            throws ParserConfigurationException, SAXException, IOException {\n        return new FileTransferHttpResumeInfoParser(new InputSource(new ByteArrayInputStream(xml)))\n                .getResumeInfo();\n    }\n\n    /**\n     * Create a text message\n     * \n     * @param remote Remote contact identifier\n     * @param msg Text message\n     * @param timestamp Local timestamp\n     * @param timestampSent Timestamp sent in payload\n     * @return Text message\n     */\n    public static ChatMessage createTextMessage(ContactId remote, String msg, long timestamp,\n            long timestampSent) {\n        String msgId = IdGenerator.generateMessageID();\n        return new ChatMessage(msgId, remote, msg, MimeType.TEXT_MESSAGE, timestamp, timestampSent,\n                null);\n    }\n\n    /**\n     * Create a file transfer message\n     * \n     * @param remote Remote contact identifier\n     * @param fileInfo File XML description\n     * @param msgId Message ID\n     * @param timestamp The local timestamp for the file transfer\n     * @param timestampSent The timestamp sent in payload for the file transfer\n     * @return File message\n     */\n    public static ChatMessage createFileTransferMessage(ContactId remote, String fileInfo,\n            String msgId, long timestamp, long timestampSent) {\n        return new ChatMessage(msgId, remote, fileInfo, FileTransferHttpInfoDocument.MIME_TYPE,\n                timestamp, timestampSent, null);\n    }\n\n    /**\n     * Create a geoloc message\n     * \n     * @param remote Remote contact\n     * @param geoloc Geolocation\n     * @param timestamp Local timestamp\n     * @param timestampSent Timestamp sent in payload\n     * @return Geolocation message\n     */\n    public static ChatMessage createGeolocMessage(ContactId remote, Geoloc geoloc, long timestamp,\n            long timestampSent) {\n        String msgId = IdGenerator.generateMessageID();\n        return new ChatMessage(msgId, remote, geoloc.toString(), MimeType.GEOLOC_MESSAGE,\n                timestamp, timestampSent, null);\n    }\n\n    /**\n     * Get the first message\n     * \n     * @param invite Request\n     * @param timestamp Local timestamp\n     * @return First message\n     * @throws PayloadException\n     */\n    public static ChatMessage getFirstMessage(SipRequest invite, long timestamp)\n            throws PayloadException {\n        ChatMessage msg = getFirstMessageFromCpim(invite, timestamp);\n        if (msg != null) {\n            return msg;\n        }\n        return getFirstMessageFromSubject(invite, timestamp);\n    }\n\n    public static boolean isContainingFirstMessage(SipRequest invite) {\n        return invite.getContent() != null || invite.getSubject().length() > 0;\n    }\n\n    /**\n     * Get the subject\n     * \n     * @param invite Request\n     * @return String\n     */\n    public static String getSubject(SipRequest invite) {\n        return invite.getSubject();\n    }\n\n    /**\n     * Get the first message from CPIM content\n     * \n     * @param invite Request\n     * @param timestamp Local timestamp\n     * @return First message\n     * @throws PayloadException\n     */\n    private static ChatMessage getFirstMessageFromCpim(SipRequest invite, long timestamp)\n            throws PayloadException {\n        CpimMessage cpimMsg = extractCpimMessage(invite);\n        if (cpimMsg == null) {\n            return null;\n        }\n        ContactId remote = getReferredIdentityAsContactId(invite);\n        if (remote == null) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"getFirstMessageFromCpim: cannot parse contact\");\n            }\n            return null;\n        }\n        String msgId = getMessageId(invite);\n        String content = cpimMsg.getMessageContent();\n        long timestampSent = cpimMsg.getTimestampSent();\n        String mime = cpimMsg.getContentType();\n        if (msgId == null || content == null || mime == null) {\n            return null;\n        }\n        if (isGeolocType(mime)) {\n            return new ChatMessage(msgId, remote,\n                    ChatUtils.networkGeolocContentToPersistedGeolocContent(content),\n                    MimeType.GEOLOC_MESSAGE, timestamp, timestampSent, null);\n\n        } else if (FileTransferUtils.isFileTransferHttpType(mime)) {\n            return new ChatMessage(msgId, remote, content, FileTransferHttpInfoDocument.MIME_TYPE,\n                    timestamp, timestampSent, null);\n\n        } else if (isTextPlainType(mime)) {\n            return new ChatMessage(msgId, remote, content, MimeType.TEXT_MESSAGE, timestamp,\n                    timestampSent, null);\n        }\n        sLogger.warn(\"Unknown MIME-type in first message; msgId=\" + msgId + \", mime='\" + mime\n                + \"'.\");\n        return null;\n    }\n\n    /**\n     * Get the first message from the Subject header\n     * \n     * @param invite Request\n     * @param timestamp Local timestamp\n     * @return First message\n     * @throws PayloadException\n     */\n    private static ChatMessage getFirstMessageFromSubject(SipRequest invite, long timestamp)\n            throws PayloadException {\n        String subject = invite.getSubject();\n        if (TextUtils.isEmpty(subject)) {\n            return null;\n        }\n        ContactId remote = getReferredIdentityAsContactId(invite);\n        if (remote == null) {\n            throw new PayloadException(\"Cannot parse contact from message subject!\");\n        }\n        /**\n         * Since in subject, there is no DateTime or datetime included, then we need to fake that by\n         * using the local timestamp even if this is not the real proper timestamp from the remote\n         * side in this case.\n         */\n        return new ChatMessage(IdGenerator.generateMessageID(), remote, subject,\n                MimeType.TEXT_MESSAGE, timestamp, timestamp, null);\n    }\n\n    /**\n     * Extract CPIM message from incoming INVITE request\n     * \n     * @param request Request\n     * @return CpimMessage\n     */\n    public static CpimMessage extractCpimMessage(SipRequest request) {\n        Multipart multi = new Multipart(request.getContent(), request.getBoundaryContentType());\n        if (!multi.isMultipart()) {\n            return null;\n        }\n        String cpimPart = multi.getPart(CpimMessage.MIME_TYPE);\n        if (cpimPart == null) {\n            return null;\n        }\n        return new CpimParser(cpimPart.getBytes(UTF8)).getCpimMessage();\n    }\n\n    /**\n     * Get participants from 'resource-list' present in XML document and include the 'remote' as\n     * participant.\n     * \n     * @param request Request\n     * @param status Status to assign to created participants\n     * @return Participants based on contacts in the request\n     * @throws PayloadException\n     */\n    public static Map<ContactId, ParticipantStatus> getParticipants(SipRequest request,\n            ParticipantStatus status) throws PayloadException {\n        Map<ContactId, ParticipantStatus> participants = new HashMap<>();\n        String content = request.getContent();\n        String boundary = request.getBoundaryContentType();\n        Multipart multi = new Multipart(content, boundary);\n        if (multi.isMultipart()) {\n            String listPart = multi.getPart(\"application/resource-lists+xml\");\n            if (listPart != null) {\n                participants = ParticipantInfoUtils.parseResourceList(listPart, status);\n                ContactId remote = getReferredIdentityAsContactId(request);\n                if (remote == null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"getParticipants: cannot parse contact\");\n                    }\n                } else {\n                    /* Include remote contact if format if correct */\n                    if (!remote.equals(ImsModule.getImsUserProfile().getUsername())) {\n                        participants.put(remote, status);\n                    }\n                }\n            }\n        }\n        return participants;\n    }\n\n    /**\n     * Is request is for FToHTTP\n     * \n     * @param request SIP request\n     * @return true if FToHTTP\n     */\n    public static boolean isFileTransferOverHttp(SipRequest request) {\n        CpimMessage message = extractCpimMessage(request);\n        if (message == null) {\n            return false;\n        }\n        String contentType = message.getContentType();\n        return contentType != null\n                && contentType.startsWith(FileTransferHttpInfoDocument.MIME_TYPE);\n    }\n\n    /**\n     * Generate persisted MIME-type from network pay-load\n     * \n     * @param apiMimeType Network pay-load MIME-type\n     * @return API MIME-type\n     */\n    public static String apiMimeTypeToNetworkMimeType(String apiMimeType) {\n        /*\n         * Geolocation chat messages does not have the same mimetype in the payload as in the TAPI.\n         * Text chat messages do.\n         */\n        if (apiMimeType.startsWith(MimeType.GEOLOC_MESSAGE)) {\n            return GeolocInfoDocument.MIME_TYPE;\n        } else if (isTextPlainType(apiMimeType)) {\n            return MimeType.TEXT_MESSAGE;\n        } else if (apiMimeType.startsWith(FileTransferHttpInfoDocument.MIME_TYPE)) {\n            return FileTransferHttpInfoDocument.MIME_TYPE;\n        }\n        throw new IllegalArgumentException(\"Unsupported input mimetype detected : \" + apiMimeType);\n    }\n\n    /**\n     * Generate persisted content from network pay-load\n     * \n     * @param content the content from network payload\n     * @return Persisted content\n     * @throws PayloadException\n     */\n    public static String networkGeolocContentToPersistedGeolocContent(String content)\n            throws PayloadException {\n        Geoloc geoloc = parseGeolocDocument(content);\n        return geoloc.toString();\n    }\n\n    /**\n     * Generate network pay-load content from persisted content\n     * \n     * @param content the persisted content\n     * @param msgId the message ID\n     * @param timestamp the timestamp\n     * @return Network payload content\n     */\n    public static String persistedGeolocContentToNetworkGeolocContent(String content, String msgId,\n            long timestamp) {\n        Geoloc geoloc = new Geoloc(content);\n        return ChatUtils.buildGeolocDocument(geoloc, ImsModule.getImsUserProfile().getPublicUri(),\n                msgId, timestamp);\n    }\n\n    /**\n     * Create a chat message either text or geolocation.\n     * \n     * @param msgId the message ID\n     * @param apiMimeType The mime-type as exposed to client applications\n     * @param content the content\n     * @param contact The remote contact\n     * @param displayName the display name\n     * @param timestamp the timestamp\n     * @param timestampSent The timestamp sent in payload for the chat message\n     * @return ChatMessage\n     */\n    public static ChatMessage createChatMessage(String msgId, String apiMimeType, String content,\n            ContactId contact, String displayName, long timestamp, long timestampSent) {\n        if (MimeType.TEXT_MESSAGE.equals(apiMimeType)) {\n            return new ChatMessage(msgId, contact, content, MimeType.TEXT_MESSAGE, timestamp,\n                    timestampSent, displayName);\n\n        } else if (MimeType.GEOLOC_MESSAGE.equals(apiMimeType)) {\n            return new ChatMessage(msgId, contact, content, MimeType.GEOLOC_MESSAGE, timestamp,\n                    timestampSent, displayName);\n        }\n        throw new IllegalArgumentException(\"Unable to create message, Invalid mimetype \"\n                + apiMimeType);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ContributionIdGenerator.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.DeviceUtils;\n\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\n\n/**\n * Contribution ID generator based on RFC draft-kaplan-dispatch-session-id-03\n * \n * @author jexa7410\n */\npublic class ContributionIdGenerator {\n\n    private static final String ALOGIRITHM_HMACSHA1 = \"HmacSHA1\";\n\n    /**\n     * Secret Key generator.\n     */\n    private static byte[] generateSecretKey() {\n        final byte[] rawKey = generateRawKey();\n        /**\n         * Keep only 128 bits\n         */\n        byte[] secretKey = new byte[16];\n        for (int i = 0; i < 16; i++) {\n            if (rawKey != null && rawKey.length >= 16) {\n                secretKey[i] = rawKey[i];\n            } else {\n                secretKey[i] = '0';\n            }\n        }\n        return secretKey;\n    }\n\n    /**\n     * Raw Key generator.\n     */\n    private static byte[] generateRawKey() {\n        return DeviceUtils.getDeviceUUID(AndroidFactory.getApplicationContext()).toString()\n                .getBytes(UTF8);\n    }\n\n    /**\n     * Returns the Contribution ID\n     * \n     * @param callId Call-ID header value\n     * @return the Contribution ID\n     */\n    public synchronized static String getContributionId(String callId) {\n        try {\n            // HMAC-SHA1 operation\n            SecretKeySpec sks = new SecretKeySpec(generateSecretKey(), ALOGIRITHM_HMACSHA1);\n            Mac mac = Mac.getInstance(ALOGIRITHM_HMACSHA1);\n            mac.init(sks);\n            byte[] contributionId = mac.doFinal(callId.getBytes(UTF8));\n\n            // Convert to Hexa and keep only 128 bits\n            StringBuilder hexString = new StringBuilder(32);\n            for (int i = 0; i < 16 && i < contributionId.length; i++) {\n                String hex = Integer.toHexString(0xFF & contributionId[i]);\n                if (hex.length() == 1) {\n                    hexString.append('0');\n                }\n                hexString.append(hex);\n            }\n\n            String id = hexString.toString();\n            return id;\n\n        } catch (NoSuchAlgorithmException e) {\n            throw new IllegalArgumentException(\"Not able to generate Contribution Id\", e);\n\n        } catch (InvalidKeyException e) {\n            throw new IllegalArgumentException(\"Not able to generate Contribution Id\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/GroupChatAutoRejoinTask.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.utils.logger.Logger;\n\npublic class GroupChatAutoRejoinTask implements Runnable {\n\n    private final MessagingLog mMessagingLog;\n\n    private final InstantMessagingService mImService;\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatAutoRejoinTask.class.getName());\n\n    public GroupChatAutoRejoinTask(InstantMessagingService imService, MessagingLog messagingLog) {\n        mMessagingLog = messagingLog;\n        mImService = imService;\n    }\n\n    @Override\n    public void run() {\n        for (String chatId : mMessagingLog.getChatIdsOfActiveGroupChatsForAutoRejoin()) {\n            try {\n                mImService.rejoinGroupChat(chatId);\n\n            } catch (PayloadException e) {\n                sLogger.error(new StringBuilder(\"Could not auto-rejoin group chat with chatID '\")\n                        .append(chatId).append(\"' due to: \").append(e.getMessage()).toString(), e);\n            } catch (NetworkException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            } catch (RuntimeException e) {\n                /*\n                 * Intentionally catch runtime exceptions as else it will abruptly end the thread\n                 * and eventually bring the whole system down, which is not intended.\n                 */\n                sLogger.error(new StringBuilder(\"Could not auto-rejoin group chat with chatID '\")\n                        .append(chatId).append(\"' due to: \").append(e.getMessage()).toString(), e);\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/GroupChatInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.util.Map;\n\n/**\n * Group chat info\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GroupChatInfo {\n\n    /**\n     * Rejoin ID\n     */\n    private Uri mRejoinId;\n\n    /**\n     * Contribution Id\n     */\n    private String mContributionId;\n\n    /**\n     * Set of initial participants\n     */\n    private Map<ContactId, ParticipantStatus> mParticipants;\n\n    /**\n     * Subject\n     */\n    private String mSubject;\n\n    /**\n     * Local timestamp\n     */\n    private long mTimestamp;\n\n    /**\n     * Constructor\n     * \n     * @param rejoindId Rejoin ID\n     * @param contributionId Contribution ID\n     * @param particpants Participants\n     * @param subject Subject\n     * @param timestamp Local timestamp\n     */\n    public GroupChatInfo(Uri rejoinId, String contributionId,\n            Map<ContactId, ParticipantStatus> participants, String subject, long timestamp) {\n        mRejoinId = rejoinId;\n        mContributionId = contributionId;\n        mParticipants = participants;\n        mSubject = subject;\n        mTimestamp = timestamp;\n    }\n\n    /**\n     * Returns the rejoin ID\n     * \n     * @return ID\n     */\n    public Uri getRejoinId() {\n        return mRejoinId;\n    }\n\n    /**\n     * Returns the contribution ID\n     * \n     * @return ID\n     */\n    public String getContributionId() {\n        return mContributionId;\n    }\n\n    /**\n     * Returns set of participants\n     * \n     * @return Participants\n     */\n    public Map<ContactId, ParticipantStatus> getParticipants() {\n        return mParticipants;\n    }\n\n    /**\n     * Returns the subject\n     * \n     * @return Subject\n     */\n    public String getSubject() {\n        return mSubject;\n    }\n\n    /**\n     * Returns the timestamp\n     * \n     * @return Timestamp\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    /**\n     * Returns a string representation of the object\n     * \n     * @return String\n     */\n    public String toString() {\n        return \"Contribution ID=\" + mContributionId + \", Rejoin ID=\" + mRejoinId + \", Subject=\"\n                + mSubject + \", Participants=\" + mParticipants.size() + \", Timestamp=\" + mTimestamp;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/GroupChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimIdentity;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimParser;\nimport com.gsma.rcs.core.ims.service.im.chat.event.ConferenceEventSubscribeManager;\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.iscomposing.IsComposingInfo;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.api.GroupFileTransferImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport gov2.nist.javax2.sip.header.Reason;\n\nimport java.text.ParseException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * Abstract Group chat session\n * \n * @author Jean-Marc AUFFRET\n * @author YPLO6403\n */\npublic abstract class GroupChatSession extends ChatSession {\n\n    private final ConferenceEventSubscribeManager mConferenceSubscriber;\n\n    /**\n     * List of participants as reported by the network via conference events or invited by us. These\n     * are persisted in the database. mParticipants should be in sync with the provider at all\n     * times.\n     */\n    private final Map<ContactId, ParticipantStatus> mParticipants;\n\n    /**\n     * Boolean variable indicating that the session is no longer marked as the active one for\n     * outgoing operations and pending to be removed when it times out.\n     */\n    private boolean mPendingRemoval = false;\n\n    private final ImsModule mImsModule;\n\n    /**\n     * Max number of participants allowed in the group chat including the current user.\n     */\n    private int mMaxParticipants;\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatSession.class.getSimpleName());\n\n    /**\n     * Constructor for originating side\n     * \n     * @param imService InstantMessagingService\n     * @param contact remote contact identifier\n     * @param conferenceId Conference id\n     * @param participants Initial set of participants\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     */\n    public GroupChatSession(InstantMessagingService imService, ContactId contact, Uri conferenceId,\n            Map<ContactId, ParticipantStatus> participants, RcsSettings rcsSettings,\n            MessagingLog messagingLog, long timestamp, ContactManager contactManager) {\n        super(imService, contact, conferenceId, rcsSettings, messagingLog, null, timestamp,\n                contactManager);\n        mMaxParticipants = rcsSettings.getMaxChatParticipants();\n        mParticipants = participants;\n        mConferenceSubscriber = new ConferenceEventSubscribeManager(this, rcsSettings, messagingLog);\n        mImsModule = imService.getImsModule();\n        setFeatureTags(ChatUtils.getSupportedFeatureTagsForGroupChat(rcsSettings));\n        setAcceptContactTags(ChatUtils.getAcceptContactTagsForGroupChat());\n        addAcceptTypes(CpimMessage.MIME_TYPE);\n        addWrappedTypes(MimeType.TEXT_MESSAGE);\n        addWrappedTypes(IsComposingInfo.MIME_TYPE);\n        addWrappedTypes(ImdnDocument.MIME_TYPE);\n        if (rcsSettings.isGeoLocationPushSupported()) {\n            addWrappedTypes(GeolocInfoDocument.MIME_TYPE);\n        }\n        if (rcsSettings.isFileTransferHttpSupported()) {\n            addWrappedTypes(FileTransferHttpInfoDocument.MIME_TYPE);\n        }\n    }\n\n    @Override\n    public boolean isGroupChat() {\n        return true;\n    }\n\n    /**\n     * Get max number of participants in the session including the initiator\n     * \n     * @return Maximum number of participants\n     */\n    public int getMaxParticipants() {\n        return mMaxParticipants;\n    }\n\n    /**\n     * Set max number of participants in the session including the initiator\n     * \n     * @param maxParticipants Max number\n     */\n    public void setMaxParticipants(int maxParticipants) {\n        mMaxParticipants = maxParticipants;\n    }\n\n    /**\n     * Returns all participants associated with the session.\n     * \n     * @return Set of participants associated with the session.\n     */\n    public Map<ContactId, ParticipantStatus> getParticipants() {\n        synchronized (mParticipants) {\n            return new HashMap<>(mParticipants);\n        }\n    }\n\n    /**\n     * Returns participants with specified status.\n     * \n     * @param status of participants to be returned.\n     * @return Set of participants with status participantStatus.\n     */\n    public Map<ContactId, ParticipantStatus> getParticipants(ParticipantStatus status) {\n        synchronized (mParticipants) {\n            Map<ContactId, ParticipantStatus> matchingParticipants = new HashMap<>();\n            for (Map.Entry<ContactId, ParticipantStatus> participant : mParticipants.entrySet()) {\n                ParticipantStatus participantStatus = participant.getValue();\n                if (participantStatus == status) {\n                    matchingParticipants.put(participant.getKey(), participantStatus);\n                }\n            }\n            return matchingParticipants;\n        }\n    }\n\n    /**\n     * Returns participants that matches any of the specified statues.\n     * \n     * @param statuses of participants to be returned.\n     * @return Set of participants which has any one the statuses specified.\n     */\n    public Map<ContactId, ParticipantStatus> getParticipants(Set<ParticipantStatus> statuses) {\n        synchronized (mParticipants) {\n            Map<ContactId, ParticipantStatus> matchingParticipants = new HashMap<>();\n            for (Map.Entry<ContactId, ParticipantStatus> participant : mParticipants.entrySet()) {\n                if (statuses.contains(participant.getValue())) {\n                    matchingParticipants.put(participant.getKey(), participant.getValue());\n                }\n            }\n            return matchingParticipants;\n        }\n    }\n\n    /**\n     * Get participants for which status has changed and require update\n     * \n     * @param participants Participants\n     * @return participants for which status has changed\n     */\n    public Map<ContactId, ParticipantStatus> getParticipantsToUpdate(\n            Map<ContactId, ParticipantStatus> participants) {\n        synchronized (mParticipants) {\n            Map<ContactId, ParticipantStatus> participantsToUpdate = new HashMap<>();\n            for (Map.Entry<ContactId, ParticipantStatus> participantUpdate : participants\n                    .entrySet()) {\n                ContactId contact = participantUpdate.getKey();\n                ParticipantStatus status = participantUpdate.getValue();\n                if (status != mParticipants.get(contact)) {\n                    participantsToUpdate.put(contact, status);\n                }\n            }\n            return participantsToUpdate;\n        }\n    }\n\n    /**\n     * Apply updates or additions to participants of the group chat.\n     * \n     * @param participants Participants\n     */\n    public void updateParticipants(Map<ContactId, ParticipantStatus> participants) {\n        synchronized (mParticipants) {\n            Map<ContactId, ParticipantStatus> participantsToUpdate = getParticipantsToUpdate(participants);\n            if (participantsToUpdate.isEmpty()) {\n                return;\n            }\n            for (Map.Entry<ContactId, ParticipantStatus> participant : participantsToUpdate\n                    .entrySet()) {\n                mParticipants.put(participant.getKey(), participant.getValue());\n            }\n            for (ImsSessionListener listener : getListeners()) {\n                ((GroupChatSessionListener) listener).onParticipantsUpdated(participantsToUpdate,\n                        mParticipants);\n            }\n        }\n    }\n\n    /**\n     * Set a status for group chat participants.\n     * \n     * @param contacts The contacts that should have their status set.\n     * @param status The status to set.\n     */\n    private void updateParticipants(final Set<ContactId> contacts, ParticipantStatus status) {\n        Map<ContactId, ParticipantStatus> participants = new HashMap<>();\n        for (ContactId contact : contacts) {\n            participants.put(contact, status);\n        }\n        updateParticipants(participants);\n    }\n\n    /**\n     * Returns the conference event subscriber\n     * \n     * @return Subscribe manager\n     */\n    public ConferenceEventSubscribeManager getConferenceEventSubscriber() {\n        return mConferenceSubscriber;\n    }\n\n    @Override\n    public void closeMediaSession() {\n        closeMsrpSession();\n    }\n\n    @Override\n    public void closeSession(TerminationReason reason) throws PayloadException, NetworkException {\n        if (TerminationReason.TERMINATION_BY_CONNECTION_LOST == reason) {\n            /*\n             * As there is no connection, So we should not even make an attempt to send un-subscribe\n             * as it will anyway fail , However we should still do the cleanup , like : Stopping\n             * periodic subscription timer\n             */\n            mConferenceSubscriber.stopTimer();\n        } else {\n            mConferenceSubscriber.terminate();\n        }\n        super.closeSession(reason);\n    }\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        mConferenceSubscriber.terminate();\n        super.receiveBye(bye);\n        /*\n         * When group chat reaches the minimum number of active participants, the Controlling\n         * Function indicates this by including a Reason header field with the protocol set to SIP\n         * and the protocol-cause set to 410 (e.g. SIP;cause=410;text=\"Gone\") in the SIP BYE request\n         * that it sends to the remaining participants.\n         */\n        TerminationReason reason = TerminationReason.TERMINATION_BY_INACTIVITY;\n        Reason sipByeReason = bye.getReason();\n        if (sipByeReason != null && Response.GONE == sipByeReason.getCause()) {\n            reason = TerminationReason.TERMINATION_BY_REMOTE;\n        }\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionAborted(getRemoteContact(), reason);\n        }\n    }\n\n    @Override\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        mConferenceSubscriber.terminate();\n        super.receiveCancel(cancel);\n    }\n\n    @Override\n    public void sendChatMessage(ChatMessage msg) throws NetworkException {\n        String from = ImsModule.getImsUserProfile().getPublicAddress();\n        String to = ChatUtils.ANONYMOUS_URI;\n        String msgId = msg.getMessageId();\n        String mimeType = msg.getMimeType();\n        String networkMimeType = ChatUtils.apiMimeTypeToNetworkMimeType(mimeType);\n        long timestampSent = msg.getTimestampSent();\n        String networkContent = msg.getContent();\n        String data;\n        if (MimeType.GEOLOC_MESSAGE.equals(mimeType)) {\n            networkContent = ChatUtils.persistedGeolocContentToNetworkGeolocContent(networkContent,\n                    msgId, timestampSent);\n        }\n        if (mImdnManager.isRequestGroupDeliveryDisplayedReportsEnabled()) {\n            data = ChatUtils.buildCpimMessageWithImdn(from, to, msgId, networkContent,\n                    networkMimeType, timestampSent);\n\n        } else if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n            data = ChatUtils.buildCpimMessageWithoutDisplayedImdn(from, to, msgId, networkContent,\n                    networkMimeType, timestampSent);\n\n        } else {\n            data = ChatUtils.buildCpimMessage(from, to, networkContent, networkMimeType,\n                    timestampSent);\n        }\n        if (ChatUtils.isGeolocType(networkMimeType)) {\n            sendDataChunks(IdGenerator.generateMessageID(), data, CpimMessage.MIME_TYPE,\n                    TypeMsrpChunk.GeoLocation);\n        } else {\n            sendDataChunks(IdGenerator.generateMessageID(), data, CpimMessage.MIME_TYPE,\n                    TypeMsrpChunk.TextMessage);\n        }\n        for (ImsSessionListener listener : getListeners()) {\n            ((ChatSessionListener) listener).onMessageSent(msgId, mimeType);\n        }\n    }\n\n    @Override\n    public void sendIsComposingStatus(boolean status) throws NetworkException {\n        String from = ImsModule.getImsUserProfile().getPublicUri();\n        String to = ChatUtils.ANONYMOUS_URI;\n        String msgId = IdGenerator.generateMessageID();\n        String content = ChatUtils.buildCpimMessage(from, to,\n                IsComposingInfo.buildIsComposingInfo(status), IsComposingInfo.MIME_TYPE,\n                System.currentTimeMillis());\n        sendDataChunks(msgId, content, CpimMessage.MIME_TYPE, TypeMsrpChunk.IsComposing);\n    }\n\n    @Override\n    public void sendMsrpMessageDeliveryStatus(ContactId remote, String msgId,\n            ImdnDocument.DeliveryStatus status, long timestamp) throws NetworkException {\n        String fromUri = ImsModule.getImsUserProfile().getPublicUri();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send delivery status \" + status + \" for message \" + msgId);\n        }\n        // Send status in CPIM + IMDN headers\n        /* Timestamp for IMDN datetime */\n        String imdn = ChatUtils.buildImdnDeliveryReport(msgId, status, timestamp);\n        /* Timestamp for CPIM DateTime */\n        String content = ChatUtils.buildCpimDeliveryReport(fromUri, remote.toString(), imdn,\n                System.currentTimeMillis());\n\n        TypeMsrpChunk typeMsrpChunk = TypeMsrpChunk.OtherMessageDeliveredReportStatus;\n        if (ImdnDocument.DeliveryStatus.DISPLAYED == status) {\n            typeMsrpChunk = TypeMsrpChunk.MessageDisplayedReport;\n        } else if (ImdnDocument.DeliveryStatus.DELIVERED == status) {\n            typeMsrpChunk = TypeMsrpChunk.MessageDeliveredReport;\n        }\n        sendDataChunks(IdGenerator.generateMessageID(), content, CpimMessage.MIME_TYPE,\n                typeMsrpChunk);\n        if (ImdnDocument.DeliveryStatus.DISPLAYED == status) {\n            if (mMessagingLog.getMessageChatId(msgId) != null) {\n                for (ImsSessionListener listener : getListeners()) {\n                    ((ChatSessionListener) listener).onChatMessageDisplayReportSent(msgId);\n                }\n            }\n        }\n    }\n\n    /**\n     * Send file info on group chat session\n     * \n     * @param fileTransfer the file transfer API implementation\n     * @param fileTransferId the file transfer ID\n     * @param fileInfo the file transfer information\n     * @param displayedReportEnabled is displayed report enabled\n     * @param deliveredReportEnabled is delivered report enabled\n     * @throws NetworkException\n     */\n    public void sendFileInfo(GroupFileTransferImpl fileTransfer, String fileTransferId,\n            String fileInfo, boolean displayedReportEnabled, boolean deliveredReportEnabled)\n            throws NetworkException {\n        String from = ImsModule.getImsUserProfile().getPublicAddress();\n        String networkContent;\n        long timestamp = System.currentTimeMillis();\n        /* For outgoing file transfer, timestampSent = timestamp */\n        long timestampSent = timestamp;\n        mMessagingLog.setFileTransferTimestamps(fileTransferId, timestamp, timestampSent);\n        if (displayedReportEnabled) {\n            networkContent = ChatUtils\n                    .buildCpimMessageWithImdn(from, ChatUtils.ANONYMOUS_URI, fileTransferId,\n                            fileInfo, FileTransferHttpInfoDocument.MIME_TYPE, timestampSent);\n\n        } else if (deliveredReportEnabled) {\n            networkContent = ChatUtils.buildCpimMessageWithoutDisplayedImdn(from,\n                    ChatUtils.ANONYMOUS_URI, fileTransferId, fileInfo,\n                    FileTransferHttpInfoDocument.MIME_TYPE, timestampSent);\n\n        } else {\n            networkContent = ChatUtils.buildCpimMessage(from, ChatUtils.ANONYMOUS_URI, fileInfo,\n                    FileTransferHttpInfoDocument.MIME_TYPE, timestampSent);\n        }\n        sendDataChunks(IdGenerator.generateMessageID(), networkContent, CpimMessage.MIME_TYPE,\n                TypeMsrpChunk.HttpFileSharing);\n        fileTransfer.onFileInfoDequeued();\n    }\n\n    /**\n     * Get the number of participants that can be added to the group chat without exceeding its max\n     * number of participants.\n     * \n     * @return the max number of participants that can be added.\n     */\n    public int getMaxNumberOfAdditionalParticipants() {\n        synchronized (mParticipants) {\n            int currentParticipants = 0;\n            for (ParticipantStatus status : mParticipants.values()) {\n                switch (status) {\n                    case INVITE_QUEUED:\n                    case INVITING:\n                    case INVITED:\n                    case CONNECTED:\n                        currentParticipants++;\n                        break;\n                    default:\n                        break;\n                }\n            }\n            return mMaxParticipants - currentParticipants - 1;\n        }\n    }\n\n    /**\n     * Add a set of participants to the session\n     * \n     * @param contacts set of participants\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void inviteParticipants(Set<ContactId> contacts) throws PayloadException,\n            NetworkException {\n        try {\n            int nbrOfContacts = contacts.size();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Add \" + nbrOfContacts + \" participants to the session\");\n            }\n            updateParticipants(contacts, ParticipantStatus.INVITING);\n            SessionAuthenticationAgent authenticationAgent = getAuthenticationAgent();\n            getDialogPath().incrementCseq();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Send REFER\");\n            }\n            SipRequest refer;\n            if (nbrOfContacts == 1) {\n                Uri singleContact = PhoneUtils.formatContactIdToUri(contacts.iterator().next());\n                refer = SipMessageFactory.createRefer(getDialogPath(), singleContact, getSubject(),\n                        getContributionID());\n            } else {\n                refer = SipMessageFactory.createRefer(getDialogPath(), contacts, getSubject(),\n                        getContributionID());\n            }\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSubsequentRequest(\n                    getDialogPath(), refer);\n            int statusCode = ctx.getStatusCode();\n            if (statusCode == 407) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"407 response received\");\n                }\n                authenticationAgent.readProxyAuthenticateHeader(ctx.getSipResponse());\n                getDialogPath().incrementCseq();\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Send second REFER\");\n                }\n                if (nbrOfContacts == 1) {\n                    Uri singleContact = PhoneUtils.formatContactIdToUri(contacts.iterator().next());\n                    refer = SipMessageFactory.createRefer(getDialogPath(), singleContact,\n                            getSubject(), getContributionID());\n                } else {\n                    refer = SipMessageFactory.createRefer(getDialogPath(), contacts, getSubject(),\n                            getContributionID());\n                }\n                authenticationAgent.setProxyAuthorizationHeader(refer);\n                ctx = mImsModule.getSipManager().sendSubsequentRequest(getDialogPath(), refer);\n                statusCode = ctx.getStatusCode();\n                if ((statusCode >= 200) && (statusCode < 300)) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"20x OK response received\");\n                    }\n                    updateParticipants(contacts, ParticipantStatus.INVITED);\n                } else {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"REFER has failed (\" + statusCode + \")\");\n                    }\n                    updateParticipants(contacts, ParticipantStatus.FAILED);\n                }\n\n            } else if ((statusCode >= 200) && (statusCode < 300)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"20x OK response received\");\n                }\n                updateParticipants(contacts, ParticipantStatus.INVITED);\n\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No response received\");\n                }\n                updateParticipants(contacts, ParticipantStatus.FAILED);\n            }\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"REFER request has failed for contacts : \" + contacts, e);\n        }\n    }\n\n    @Override\n    public void rejectSession() {\n        rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n    }\n\n    @Override\n    public SipRequest createInvite() throws PayloadException {\n        // Nothing to do in terminating side\n        return null;\n    }\n\n    @Override\n    public void handle200OK(SipResponse resp) throws PayloadException, NetworkException,\n            FileAccessException {\n        super.handle200OK(resp);\n        mConferenceSubscriber.subscribe();\n    }\n\n    private boolean shouldSendDisplayReport(String dispositionNotification) {\n        return mImdnManager.isSendGroupDeliveryDisplayedReportsEnabled()\n                && (dispositionNotification != null && dispositionNotification\n                        .contains(ImdnDocument.DISPLAY));\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType)\n            throws PayloadException, NetworkException, ContactManagerException {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"MSRP data received (type \" + mimeType + \")\");\n        }\n        if (data == null || data.length == 0) {\n            // By-pass empty data\n            if (logActivated) {\n                sLogger.debug(\"By-pass received empty data\");\n            }\n            return;\n        }\n        if (ChatUtils.isApplicationIsComposingType(mimeType)) {\n            // Is composing event\n            receiveIsComposing(getRemoteContact(), data);\n            return;\n\n        } else if (ChatUtils.isTextPlainType(mimeType)) {\n            long timestamp = getTimestamp();\n            /**\n             * Since legacy server can send non CPIM data (like plain text without timestamp) in the\n             * payload, we need to fake timesampSent by using the local timestamp even if this is\n             * not the real proper timestamp from the remote side in this case.\n             */\n            ChatMessage msg = new ChatMessage(msgId, getRemoteContact(), new String(data, UTF8),\n                    MimeType.TEXT_MESSAGE, timestamp, timestamp, null);\n            boolean imdnDisplayedRequested = false;\n            boolean msgSupportsImdnReport = false;\n            receive(msg, null, msgSupportsImdnReport, imdnDisplayedRequested, null, timestamp);\n            return;\n\n        } else if (!ChatUtils.isMessageCpimType(mimeType)) {\n            // Not supported content\n            if (logActivated) {\n                sLogger.debug(\"Not supported content \" + mimeType + \" in chat session\");\n            }\n            return;\n        }\n        CpimMessage cpimMsg = new CpimParser(data).getCpimMessage();\n        if (cpimMsg == null) {\n            return;\n        }\n        String cpimMsgId = cpimMsg.getHeader(ImdnUtils.HEADER_IMDN_MSG_ID);\n        if (cpimMsgId == null) {\n            cpimMsgId = msgId;\n        }\n        String contentType = cpimMsg.getContentType();\n        ContactId remoteId = getRemoteContact();\n        /*\n         * In GC, the MSRP 'FROM' header of the SEND message is set to the remote URI. Extract URI\n         * and optional display name to get pseudo and remoteId.\n         */\n        CpimIdentity cpimIdentity = new CpimIdentity(cpimMsg.getHeader(CpimMessage.HEADER_FROM));\n        String pseudo = cpimIdentity.getDisplayName();\n        PhoneNumber remoteNumber = ContactUtil.getValidPhoneNumberFromUri(cpimIdentity.getUri());\n        if (remoteNumber == null) {\n            if (logActivated) {\n                sLogger.warn(\"Cannot parse FROM CPIM Identity: \".concat(cpimIdentity.toString()));\n            }\n        } else {\n            remoteId = ContactUtil.createContactIdFromValidatedData(remoteNumber);\n            if (logActivated) {\n                sLogger.info(\"CPIM FROM Identity: \".concat(cpimIdentity.toString()));\n            }\n        }\n        // Extract local contactId from \"TO\" header\n        ContactId localId = null;\n        cpimIdentity = new CpimIdentity(cpimMsg.getHeader(CpimMessage.HEADER_TO));\n        PhoneNumber localNumber = ContactUtil.getValidPhoneNumberFromUri(cpimIdentity.getUri());\n        if (localNumber == null) {\n            /* purposely left blank */\n        } else {\n            localId = ContactUtil.createContactIdFromValidatedData(localNumber);\n            if (logActivated) {\n                sLogger.info(\"CPIM TO Identity: \".concat(cpimIdentity.toString()));\n            }\n        }\n        String dispositionNotification = cpimMsg.getHeader(ImdnUtils.HEADER_IMDN_DISPO_NOTIF);\n        boolean msgSupportsImdnReport = true;\n        /**\n         * Set message's timestamp to the System.currentTimeMillis, not the session's itself\n         * timestamp\n         */\n        long timestamp = System.currentTimeMillis();\n        long timestampSent = cpimMsg.getTimestampSent();\n        // Analyze received message thanks to the MIME type\n        if (FileTransferUtils.isFileTransferHttpType(contentType)) {\n            // File transfer over HTTP message\n            // Parse HTTP document\n            FileTransferHttpInfoDocument fileInfo = FileTransferUtils\n                    .parseFileTransferHttpDocument(cpimMsg.getMessageContent().getBytes(UTF8),\n                            mRcsSettings);\n            if (fileInfo != null) {\n                receiveHttpFileTransfer(remoteId, pseudo, fileInfo, cpimMsgId, timestamp,\n                        timestampSent);\n            } else {\n                // TODO : else return error to Originating side\n            }\n        } else {\n            if (ChatUtils.isTextPlainType(contentType)) {\n                ChatMessage msg = new ChatMessage(cpimMsgId, remoteId, cpimMsg.getMessageContent(),\n                        MimeType.TEXT_MESSAGE, timestamp, timestampSent, pseudo);\n                receive(msg, remoteId, msgSupportsImdnReport,\n                        shouldSendDisplayReport(dispositionNotification), cpimMsgId, timestamp);\n            } else {\n                if (ChatUtils.isApplicationIsComposingType(contentType)) {\n                    // Is composing event\n                    receiveIsComposing(remoteId, cpimMsg.getMessageContent().getBytes(UTF8));\n\n                } else {\n                    if (ChatUtils.isMessageImdnType(contentType)) {\n                        // Delivery report\n                        String publicUri = ImsModule.getImsUserProfile().getPublicUri();\n                        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(publicUri);\n                        if (number == null) {\n                            if (logActivated) {\n                                sLogger.error(\"Cannot parse user contact \" + publicUri);\n                            }\n                        } else {\n                            ContactId me = ContactUtil.createContactIdFromValidatedData(number);\n                            // Only consider delivery report if sent to me\n                            if (localId != null && localId.equals(me)) {\n                                onDeliveryStatusReceived(remoteId, cpimMsg.getMessageContent());\n                            } else {\n                                if (logActivated) {\n                                    sLogger.debug(\"Discard delivery report send to \" + localId);\n                                }\n                            }\n                        }\n                    } else {\n                        if (ChatUtils.isGeolocType(contentType)) {\n                            ChatMessage msg = new ChatMessage(cpimMsgId, remoteId,\n                                    ChatUtils.networkGeolocContentToPersistedGeolocContent(cpimMsg\n                                            .getMessageContent()), MimeType.GEOLOC_MESSAGE,\n                                    timestamp, timestampSent, pseudo);\n                            receive(msg, remoteId, msgSupportsImdnReport,\n                                    shouldSendDisplayReport(dispositionNotification), cpimMsgId,\n                                    timestamp);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Since the session is no longer used it is marked to be removed when it times out.\n     */\n    public void markForPendingRemoval() {\n        mPendingRemoval = true;\n    }\n\n    /**\n     * Returns true if this session is no longer used and it is pending to be removed upon timeout.\n     * \n     * @return true if this session is no longer used and it is pending to be removed upon timeout.\n     */\n    public boolean isPendingForRemoval() {\n        return mPendingRemoval;\n    }\n\n    @Override\n    public void terminateSession(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        /*\n         * If there is an ongoing group chat session with same chatId, this session has to be\n         * silently aborted so after aborting the session we make sure to not call the rest of this\n         * method that would otherwise abort the \"current\" session also and the GroupChat as a whole\n         * which is of course not the intention here\n         */\n        if (!isPendingForRemoval()) {\n            super.terminateSession(reason);\n            return;\n        }\n        interruptSession();\n        closeSession(reason);\n        closeMediaSession();\n    }\n\n    @Override\n    public void removeSession() {\n        mImsModule.getInstantMessagingService().removeSession(this);\n    }\n\n    @Override\n    public void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk) {\n        try {\n            if (isSessionInterrupted()) {\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transfer error \" + error + \" for message \" + msgId\n                        + \" (MSRP chunk type: \" + typeMsrpChunk + \")\");\n            }\n            String chatId = getContributionID();\n            if (TypeMsrpChunk.MessageDeliveredReport.equals(typeMsrpChunk)\n                    || TypeMsrpChunk.MessageDisplayedReport.equals(typeMsrpChunk)) {\n                for (ImsSessionListener listener : getListeners()) {\n                    ((GroupChatSessionListener) listener).onDeliveryReportSendViaMsrpFailure(msgId,\n                            chatId, typeMsrpChunk);\n                }\n            } else if ((msgId != null) && TypeMsrpChunk.TextMessage.equals(typeMsrpChunk)) {\n                for (ImsSessionListener listener : getListeners()) {\n                    ImdnDocument imdn = new ImdnDocument(msgId, ImdnDocument.DELIVERY_NOTIFICATION,\n                            ImdnDocument.DeliveryStatus.FAILED, ImdnDocument.IMDN_DATETIME_NOT_SET);\n                    ((ChatSessionListener) listener).onMessageDeliveryStatusReceived(null, imdn);\n                }\n            } else {\n                // do nothing\n                sLogger.error(\"MSRP transfer error not handled for message '\" + msgId\n                        + \"' and chunk type : '\" + typeMsrpChunk + \"'!\");\n            }\n            int errorCode;\n            if ((error != null)\n                    && (error.contains(String.valueOf(Response.REQUEST_ENTITY_TOO_LARGE)) || error\n                            .contains(String.valueOf(Response.REQUEST_TIMEOUT)))) {\n                /*\n                 * Session should not be torn down immediately as there may be more errors to come\n                 * but as errors occurred we shouldn't use it for sending any longer RFC 4975 408:\n                 * An endpoint MUST treat a 408 response in the same manner as it would treat a\n                 * local timeout. 413: If a message sender receives a 413 in a response, or in a\n                 * REPORT request, it MUST NOT send any further chunks in the message, that is, any\n                 * further chunks with the same Message-ID value. If the sender receives the 413\n                 * while in the process of sending a chunk, and the chunk is interruptible, the\n                 * sender MUST interrupt it.\n                 */\n                errorCode = ChatError.MEDIA_SESSION_BROKEN;\n\n            } else {\n                /*\n                 * Default error; used e.g. for 481 or any other error RFC 4975 481: A 481 response\n                 * indicates that the indicated session does not exist. The sender should terminate\n                 * the session.\n                 */\n\n                errorCode = ChatError.MEDIA_SESSION_FAILED;\n            }\n            ChatError chatError = new ChatError(errorCode, error);\n            for (ImsSessionListener listener : getListeners()) {\n                ((GroupChatSessionListener) listener).onImError(chatError);\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to handle msrp error\" + error + \" for message \" + msgId, e);\n        }\n    }\n\n    @Override\n    public void handleError(ImsServiceError error) {\n        try {\n            if (isSessionInterrupted()) {\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Session error: \" + error.getErrorCode() + \", reason=\"\n                        + error.getMessage());\n            }\n            closeMediaSession();\n            removeSession();\n            ChatError chatError = new ChatError(error);\n            for (ImsSessionListener listener : getListeners()) {\n                ((GroupChatSessionListener) listener).onImError(chatError);\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to handle error\" + error + \"!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/GroupChatSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Map;\n\n/**\n * Group chat session listener\n */\npublic interface GroupChatSessionListener extends ChatSessionListener {\n\n    /**\n     * New conference event\n     * \n     * @param contact Contact identifier\n     * @param status ParticipantStatus for the contact\n     * @param timestamp Local timestamp when got notification\n     */\n    void onConferenceEventReceived(ContactId contact, ParticipantStatus status, long timestamp);\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     * @param subject the subject\n     * @param participants Participants\n     * @param timestamp Local timestamp when got invitation\n     */\n    void onSessionInvited(ContactId contact, String subject,\n            Map<ContactId, GroupChat.ParticipantStatus> participants, long timestamp);\n\n    /**\n     * Chat is auto-accepted and the session is in the process of being started\n     * \n     * @param contact Remote contact\n     * @param subject the subject\n     * @param participants Participants\n     * @param timestamp Local timestamp when got invitation\n     */\n    void onSessionAutoAccepted(ContactId contact, String subject,\n            Map<ContactId, GroupChat.ParticipantStatus> participants, long timestamp);\n\n    /**\n     * One or several participants has been updated\n     * \n     * @param updatedParticipants Updated participants\n     * @param allParticipants All group participants\n     */\n    void onParticipantsUpdated(Map<ContactId, ParticipantStatus> updatedParticipants,\n            Map<ContactId, ParticipantStatus> allParticipants);\n\n    /**\n     * Handle Delivery report send via MSRP Failure\n     * \n     * @param msgId the message ID\n     * @param chatId the chat ID\n     * @param chunktype the chunk type\n     */\n    void onDeliveryReportSendViaMsrpFailure(String msgId, String chatId, TypeMsrpChunk chunktype);\n\n    /**\n     * Handle IM error\n     * \n     * @param error Error\n     */\n    void onImError(ChatError error);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/OneToOneChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimParser;\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.iscomposing.IsComposingInfo;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.api.OneToOneFileTransferImpl;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.text.ParseException;\nimport java.util.List;\n\nimport javax2.sip.message.Response;\n\n/**\n * Abstract 1-1 chat session\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class OneToOneChatSession extends ChatSession {\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    private static final Logger sLogger = Logger.getLogger(OneToOneChatSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param contact Remote contact identifier\n     * @param remoteContact Remote Contact URI\n     * @param firstMsg First chat message\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager accessor\n     */\n    public OneToOneChatSession(InstantMessagingService imService, ContactId contact,\n            Uri remoteContact, ChatMessage firstMsg, RcsSettings rcsSettings,\n            MessagingLog messagingLog, long timestamp, ContactManager contactManager) {\n        super(imService, contact, remoteContact, rcsSettings, messagingLog, firstMsg, timestamp,\n                contactManager);\n        List<String> featureTags = ChatUtils.getSupportedFeatureTagsForChat(rcsSettings);\n        setFeatureTags(featureTags);\n        setAcceptContactTags(featureTags);\n        addAcceptTypes(CpimMessage.MIME_TYPE);\n        addAcceptTypes(IsComposingInfo.MIME_TYPE);\n        addWrappedTypes(MimeType.TEXT_MESSAGE);\n        addWrappedTypes(ImdnDocument.MIME_TYPE);\n        if (mRcsSettings.isGeoLocationPushSupported()) {\n            addWrappedTypes(GeolocInfoDocument.MIME_TYPE);\n        }\n        if (mRcsSettings.isFileTransferHttpSupported()) {\n            addWrappedTypes(FileTransferHttpInfoDocument.MIME_TYPE);\n        }\n    }\n\n    /**\n     * Is group chat\n     * \n     * @return Boolean\n     */\n    public boolean isGroupChat() {\n        return false;\n    }\n\n    /**\n     * Close media session\n     */\n    public void closeMediaSession() {\n        getActivityManager().stop();\n        closeMsrpSession();\n    }\n\n    /**\n     * Send a text message\n     * \n     * @param msg Chat message\n     * @throws NetworkException\n     */\n    @Override\n    public void sendChatMessage(ChatMessage msg) throws NetworkException {\n        String from = ChatUtils.ANONYMOUS_URI;\n        String to = ChatUtils.ANONYMOUS_URI;\n        String msgId = msg.getMessageId();\n        String mimeType = msg.getMimeType();\n        String networkMimeType = ChatUtils.apiMimeTypeToNetworkMimeType(mimeType);\n        long timestampSent = msg.getTimestampSent();\n        String networkContent = msg.getContent();\n        String data;\n        if (MimeType.GEOLOC_MESSAGE.equals(mimeType)) {\n            networkContent = ChatUtils.persistedGeolocContentToNetworkGeolocContent(networkContent,\n                    msgId, timestampSent);\n        }\n        if (mImdnManager.isRequestOneToOneDeliveryDisplayedReportsEnabled()) {\n            data = ChatUtils.buildCpimMessageWithImdn(from, to, msgId, networkContent,\n                    networkMimeType, timestampSent);\n        } else if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n            data = ChatUtils.buildCpimMessageWithoutDisplayedImdn(from, to, msgId, networkContent,\n                    networkMimeType, timestampSent);\n        } else {\n            data = ChatUtils.buildCpimMessage(from, to, networkContent, networkMimeType,\n                    timestampSent);\n        }\n        if (ChatUtils.isGeolocType(networkMimeType)) {\n            sendDataChunks(IdGenerator.generateMessageID(), data, CpimMessage.MIME_TYPE,\n                    TypeMsrpChunk.GeoLocation);\n        } else {\n            sendDataChunks(IdGenerator.generateMessageID(), data, CpimMessage.MIME_TYPE,\n                    TypeMsrpChunk.TextMessage);\n        }\n        for (ImsSessionListener listener : getListeners()) {\n            ((ChatSessionListener) listener).onMessageSent(msgId, mimeType);\n        }\n    }\n\n    /**\n     * Send file info within a 1-1 chat session\n     * \n     * @param fileTransfer the file transfer API implementation\n     * @param fileTransferId the file transfer ID\n     * @param fileInfo the file transfer information\n     * @param displayedReportEnabled is displayed report enabled\n     * @param deliveredReportEnabled is delivered report enabled\n     * @throws NetworkException\n     */\n    public void sendFileInfo(OneToOneFileTransferImpl fileTransfer, String fileTransferId,\n            String fileInfo, boolean displayedReportEnabled, boolean deliveredReportEnabled)\n            throws NetworkException {\n        String networkContent;\n        long timestamp = System.currentTimeMillis();\n        /* For outgoing file transfer, timestampSent = timestamp */\n        long timestampSent = timestamp;\n        mMessagingLog.setFileTransferTimestamps(fileTransferId, timestamp, timestampSent);\n        if (displayedReportEnabled) {\n            networkContent = ChatUtils.buildCpimMessageWithImdn(ChatUtils.ANONYMOUS_URI,\n                    ChatUtils.ANONYMOUS_URI, fileTransferId, fileInfo,\n                    FileTransferHttpInfoDocument.MIME_TYPE, timestampSent);\n        } else if (deliveredReportEnabled) {\n            networkContent = ChatUtils.buildCpimMessageWithoutDisplayedImdn(\n                    ChatUtils.ANONYMOUS_URI, ChatUtils.ANONYMOUS_URI, fileTransferId, fileInfo,\n                    FileTransferHttpInfoDocument.MIME_TYPE, timestampSent);\n        } else {\n            networkContent = ChatUtils.buildCpimMessage(ChatUtils.ANONYMOUS_URI,\n                    ChatUtils.ANONYMOUS_URI, fileInfo, FileTransferHttpInfoDocument.MIME_TYPE,\n                    timestampSent);\n        }\n        sendDataChunks(IdGenerator.generateMessageID(), networkContent, CpimMessage.MIME_TYPE,\n                MsrpSession.TypeMsrpChunk.HttpFileSharing);\n        fileTransfer.onFileInfoDequeued(getRemoteContact());\n    }\n\n    /**\n     * Send is composing status\n     * \n     * @param status Status\n     * @throws NetworkException\n     */\n    public void sendIsComposingStatus(boolean status) throws NetworkException {\n        String content = IsComposingInfo.buildIsComposingInfo(status);\n        String msgId = IdGenerator.generateMessageID();\n        sendDataChunks(msgId, content, IsComposingInfo.MIME_TYPE,\n                MsrpSession.TypeMsrpChunk.IsComposing);\n    }\n\n    @Override\n    public void sendMsrpMessageDeliveryStatus(ContactId remote, String msgId,\n            ImdnDocument.DeliveryStatus status, long timestamp) throws NetworkException {\n        String fromUri = ChatUtils.ANONYMOUS_URI;\n        String toUri = ChatUtils.ANONYMOUS_URI;\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send delivery status \" + status + \" for message \" + msgId);\n        }\n        // Send status in CPIM + IMDN headers\n        /* Timestamp fo IMDN datetime */\n        String imdn = ChatUtils.buildImdnDeliveryReport(msgId, status, timestamp);\n        /* Timestamp for CPIM DateTime */\n        String content = ChatUtils.buildCpimDeliveryReport(fromUri, toUri, imdn,\n                System.currentTimeMillis());\n\n        TypeMsrpChunk typeMsrpChunk = TypeMsrpChunk.OtherMessageDeliveredReportStatus;\n        if (ImdnDocument.DeliveryStatus.DISPLAYED == status) {\n            typeMsrpChunk = TypeMsrpChunk.MessageDisplayedReport;\n        } else {\n            if (ImdnDocument.DeliveryStatus.DELIVERED == status) {\n                typeMsrpChunk = TypeMsrpChunk.MessageDeliveredReport;\n            }\n        }\n        sendDataChunks(IdGenerator.generateMessageID(), content, CpimMessage.MIME_TYPE,\n                typeMsrpChunk);\n        if (ImdnDocument.DeliveryStatus.DISPLAYED == status) {\n            if (mMessagingLog.isMessagePersisted(msgId)) {\n                for (ImsSessionListener listener : getListeners()) {\n                    ((ChatSessionListener) listener).onChatMessageDisplayReportSent(msgId);\n                }\n            }\n        }\n    }\n\n    /**\n     * Reject the session invitation\n     */\n    public void rejectSession() {\n        rejectSession(InvitationStatus.INVITATION_REJECTED_BUSY_HERE);\n    }\n\n    /**\n     * Create INVITE request\n     * \n     * @param content Content part\n     * @return Request\n     * @throws PayloadException\n     */\n    private SipRequest createMultipartInviteRequest(String content) throws PayloadException {\n        try {\n            SipRequest invite = SipMessageFactory.createMultipartInvite(getDialogPath(),\n                    getFeatureTags(), content, BOUNDARY_TAG);\n            invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID());\n            return invite;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create multipart invite request!\", e);\n        }\n    }\n\n    /**\n     * Create INVITE request\n     * \n     * @param content Content part\n     * @return Request\n     * @throws PayloadException\n     */\n    private SipRequest createInviteRequest(String content) throws PayloadException {\n        try {\n            SipRequest invite = SipMessageFactory.createInvite(getDialogPath(),\n                    InstantMessagingService.CHAT_FEATURE_TAGS, content);\n            invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID());\n            return invite;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create invite request!\", e);\n        }\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return the INVITE request\n     * @throws PayloadException\n     */\n    public SipRequest createInvite() throws PayloadException {\n        String content = getDialogPath().getLocalContent();\n        if (getFirstMessage() != null) {\n            return createMultipartInviteRequest(content);\n        }\n        return createInviteRequest(content);\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param resp 200 OK response\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws FileAccessException\n     */\n    public void handle200OK(SipResponse resp) throws PayloadException, NetworkException,\n            FileAccessException {\n        super.handle200OK(resp);\n        getActivityManager().start();\n    }\n\n    /**\n     * Get SDP direction\n     * \n     * @return Direction\n     * @see com.gsma.rcs.core.ims.protocol.sdp.SdpUtils#DIRECTION_RECVONLY\n     * @see com.gsma.rcs.core.ims.protocol.sdp.SdpUtils#DIRECTION_SENDONLY\n     * @see com.gsma.rcs.core.ims.protocol.sdp.SdpUtils#DIRECTION_SENDRECV\n     */\n    public abstract String getSdpDirection();\n\n    @Override\n    public void msrpTransferError(String msgId, String error,\n            MsrpSession.TypeMsrpChunk typeMsrpChunk) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer error \" + error + \" for message \" + msgId\n                    + \" (MSRP chunk type: \" + typeMsrpChunk + \")\");\n        }\n        ContactId remote = getRemoteContact();\n        if (TypeMsrpChunk.MessageDeliveredReport.equals(typeMsrpChunk)) {\n            for (ImsSessionListener listener : getListeners()) {\n                ((OneToOneChatSessionListener) listener).onDeliveryReportSendViaMsrpFailure(msgId,\n                        remote, typeMsrpChunk);\n            }\n        } else if (TypeMsrpChunk.MessageDisplayedReport.equals(typeMsrpChunk)) {\n            for (ImsSessionListener listener : getListeners()) {\n                ((OneToOneChatSessionListener) listener).onDeliveryReportSendViaMsrpFailure(msgId,\n                        remote, typeMsrpChunk);\n            }\n        } else if (msgId != null && TypeMsrpChunk.TextMessage.equals(typeMsrpChunk)) {\n            for (ImsSessionListener listener : getListeners()) {\n                ImdnDocument imdn = new ImdnDocument(msgId, ImdnDocument.DELIVERY_NOTIFICATION,\n                        ImdnDocument.DeliveryStatus.FAILED, ImdnDocument.IMDN_DATETIME_NOT_SET);\n                ((ChatSessionListener) listener).onMessageDeliveryStatusReceived(null, imdn);\n            }\n        } else {\n            // do nothing\n            sLogger.error(\"MSRP transfer error not handled for message '\" + msgId\n                    + \"' and chunk type : '\" + typeMsrpChunk + \"'!\");\n        }\n        int errorCode;\n        if ((error != null)\n                && (error.contains(String.valueOf(Response.REQUEST_ENTITY_TOO_LARGE)) || error\n                        .contains(String.valueOf(Response.REQUEST_TIMEOUT)))) {\n            /*\n             * Session should not be torn down immediately as there may be more errors to come but\n             * as errors occurred we shouldn't use it for sending any longer. RFC 4975 408: An\n             * endpoint MUST treat a 408 response in the same manner as it would treat a local\n             * timeout. 413: If a message sender receives a 413 in a response, or in a REPORT\n             * request, it MUST NOT send any further chunks in the message, that is, any further\n             * chunks with the same Message-ID value. If the sender receives the 413 while in the\n             * process of sending a chunk, and the chunk is interruptible, the sender MUST interrupt\n             * it.\n             */\n\n            errorCode = ChatError.MEDIA_SESSION_BROKEN;\n        } else {\n            /*\n             * Default error; used e.g. for 481 or any other error RFC 4975 481: A 481 response\n             * indicates that the indicated session does not exist. The sender should terminate the\n             * session.\n             */\n\n            errorCode = ChatError.MEDIA_SESSION_FAILED;\n        }\n        handleError(getFirstMessage(), new ChatError(errorCode, error));\n        /* Request capabilities to the remote */\n        getImsService().getImsModule().getCapabilityService()\n                .requestContactCapabilities(getRemoteContact());\n\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType)\n            throws PayloadException, NetworkException, ContactManagerException {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"MSRP data received (type \" + mimeType + \")\");\n        }\n        getActivityManager().updateActivity();\n        if (data == null || data.length == 0) {\n            if (logActivated) {\n                sLogger.debug(\"By-pass received empty data\");\n            }\n            return;\n        }\n        if (ChatUtils.isApplicationIsComposingType(mimeType)) {\n            receiveIsComposing(getRemoteContact(), data);\n            return;\n        }\n        if (ChatUtils.isTextPlainType(mimeType)) {\n            /**\n             * Set message's timestamp to the System.currentTimeMillis, not the session's itself\n             * timestamp\n             */\n            long timestamp = System.currentTimeMillis();\n            /**\n             * Since legacy server can send non CPIM data (like plain text without timestamp) in the\n             * payload, we need to fake timesampSent by using the local timestamp even if this is\n             * not the real proper timestamp from the remote side in this case.\n             */\n            ChatMessage msg = new ChatMessage(msgId, getRemoteContact(), new String(data, UTF8),\n                    MimeType.TEXT_MESSAGE, timestamp, timestamp, null);\n            boolean imdnDisplayedRequested = false;\n            boolean msgSupportsImdnReport = false;\n            receive(msg, null, msgSupportsImdnReport, imdnDisplayedRequested, null, timestamp);\n            return;\n        }\n        if (ChatUtils.isMessageCpimType(mimeType)) {\n            CpimParser cpimParser = new CpimParser(data);\n            CpimMessage cpimMsg = cpimParser.getCpimMessage();\n            if (cpimMsg != null) {\n                String cpimMsgId = cpimMsg.getHeader(ImdnUtils.HEADER_IMDN_MSG_ID);\n                if (cpimMsgId == null) {\n                    cpimMsgId = msgId;\n                }\n                String contentType = cpimMsg.getContentType();\n                ContactId contact = getRemoteContact();\n                /*\n                 * In One to One chat, the MSRP 'from' header is '<sip:anonymous@anonymous.invalid>'\n                 */\n                boolean imdnDisplayedRequested = false;\n                boolean msgSupportsImdnReport = true;\n                String dispositionNotification = cpimMsg\n                        .getHeader(ImdnUtils.HEADER_IMDN_DISPO_NOTIF);\n                if (dispositionNotification != null\n                        && dispositionNotification.contains(ImdnDocument.DISPLAY)\n                        && mImdnManager.isSendOneToOneDeliveryDisplayedReportsEnabled()) {\n                    imdnDisplayedRequested = true;\n                }\n                boolean isFToHTTP = FileTransferUtils.isFileTransferHttpType(contentType);\n                /**\n                 * Set message's timestamp to the System.currentTimeMillis, not the session's itself\n                 * timestamp\n                 */\n                long timestamp = System.currentTimeMillis();\n                long timestampSent = cpimMsg.getTimestampSent();\n                if (isFToHTTP) {\n                    FileTransferHttpInfoDocument fileInfo = FileTransferUtils\n                            .parseFileTransferHttpDocument(\n                                    cpimMsg.getMessageContent().getBytes(UTF8), mRcsSettings);\n                    if (fileInfo != null) {\n                        receiveHttpFileTransfer(contact, getRemoteDisplayName(), fileInfo,\n                                cpimMsgId, timestamp, timestampSent);\n                        if (imdnDisplayedRequested) {\n                            // TODO set File Transfer status to DISPLAY_REPORT_REQUESTED ??\n                        }\n                    } else {\n                        // TODO : else return error to Originating side\n                    }\n                } else {\n                    if (ChatUtils.isTextPlainType(contentType)) {\n                        ChatMessage msg = new ChatMessage(cpimMsgId, contact,\n                                cpimMsg.getMessageContent(), MimeType.TEXT_MESSAGE, timestamp,\n                                timestampSent, null);\n                        receive(msg, null, msgSupportsImdnReport, imdnDisplayedRequested,\n                                cpimMsgId, timestamp);\n\n                    } else if (ChatUtils.isApplicationIsComposingType(contentType)) {\n                        receiveIsComposing(contact, cpimMsg.getMessageContent().getBytes(UTF8));\n\n                    } else if (ChatUtils.isMessageImdnType(contentType)) {\n                        onDeliveryStatusReceived(contact, cpimMsg.getMessageContent());\n\n                    } else if (ChatUtils.isGeolocType(contentType)) {\n                        ChatMessage msg = new ChatMessage(cpimMsgId, contact,\n                                ChatUtils.networkGeolocContentToPersistedGeolocContent(cpimMsg\n                                        .getMessageContent()), MimeType.GEOLOC_MESSAGE, timestamp,\n                                timestampSent, null);\n                        receive(msg, null, msgSupportsImdnReport, imdnDisplayedRequested,\n                                cpimMsgId, timestamp);\n                    }\n                }\n            }\n        } else {\n            if (logActivated) {\n                sLogger.debug(\"Not supported content \" + mimeType + \" in chat session\");\n            }\n        }\n    }\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        super.receiveBye(bye);\n        ContactId remote = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionAborted(remote, TerminationReason.TERMINATION_BY_REMOTE);\n        }\n        getImsService().getImsModule().getCapabilityService().requestContactCapabilities(remote);\n    }\n\n    @Override\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        super.receiveCancel(cancel);\n        getImsService().getImsModule().getCapabilityService()\n                .requestContactCapabilities(getRemoteContact());\n    }\n\n    /**\n     * Handle error\n     * \n     * @param error Error\n     */\n    @Override\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session error: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        closeMediaSession();\n        removeSession();\n        handleError(getFirstMessage(), new ChatError(error));\n    }\n\n    /**\n     * Handle error\n     * \n     * @param msg ChatMessage that errored\n     * @param error Error\n     */\n    private void handleError(ChatMessage msg, ChatError error) {\n        String msgId = msg.getMessageId();\n        for (ImsSessionListener listener : getListeners()) {\n            ((OneToOneChatSessionListener) listener).onImError(error, msgId, msg.getMimeType());\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/OneToOneChatSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * One to one chat session listener\n */\npublic interface OneToOneChatSessionListener extends ChatSessionListener {\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     */\n    void onSessionInvited(ContactId contact);\n\n    /**\n     * Chat is auto-accepted and the session is in the process of being started\n     * \n     * @param contact Remote contact\n     */\n    void onSessionAutoAccepted(ContactId contact);\n\n    /**\n     * Handle Delivery report send via MSRP Failure\n     * \n     * @param msgId the message ID\n     * @param contact the remote contact\n     * @param chunktype the type of chunk\n     */\n    void onDeliveryReportSendViaMsrpFailure(String msgId, ContactId contact, TypeMsrpChunk chunktype);\n\n    /**\n     * Handle IM error\n     * \n     * @param error Error\n     * @param msgId the message ID\n     * @param mimeType the mime type\n     */\n    void onImError(ChatError error, String msgId, String mimeType);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/OriginatingAdhocGroupChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.text.ParseException;\nimport java.util.Map;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.RequireHeader;\nimport javax2.sip.header.SubjectHeader;\n\n/**\n * Originating ad-hoc group chat session\n * \n * @author jexa7410\n */\npublic class OriginatingAdhocGroupChatSession extends GroupChatSession {\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingAdhocGroupChatSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param conferenceId Conference ID\n     * @param subject Subject associated to the session\n     * @param participantsToInvite Map of participants to invite\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     */\n    public OriginatingAdhocGroupChatSession(InstantMessagingService imService, Uri conferenceId,\n            String subject, Map<ContactId, ParticipantStatus> participantsToInvite,\n            RcsSettings rcsSettings, MessagingLog messagingLog, long timestamp,\n            ContactManager contactManager) {\n        super(imService, null, conferenceId, participantsToInvite, rcsSettings, messagingLog,\n                timestamp, contactManager);\n\n        if (!TextUtils.isEmpty(subject)) {\n            setSubject(subject);\n        }\n\n        createOriginatingDialogPath();\n\n        String id = ContributionIdGenerator.getContributionId(getDialogPath().getCallId());\n        setContributionID(id);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new ad-hoc group chat session as originating\");\n            }\n\n            String localSetup = createSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n\n            int localMsrpPort;\n            if (\"active\".equals(localSetup)) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildGroupChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), SdpUtils.DIRECTION_SENDRECV);\n\n            String resourceList = ChatUtils.generateChatResourceList(getParticipants().keySet());\n\n            String multipart = new StringBuilder(Multipart.BOUNDARY_DELIMITER).append(BOUNDARY_TAG)\n                    .append(SipUtils.CRLF).append(\"Content-Type: application/sdp\")\n                    .append(SipUtils.CRLF).append(\"Content-Length: \")\n                    .append(sdp.getBytes(UTF8).length).append(SipUtils.CRLF).append(SipUtils.CRLF)\n                    .append(sdp).append(SipUtils.CRLF).append(Multipart.BOUNDARY_DELIMITER)\n                    .append(BOUNDARY_TAG).append(SipUtils.CRLF)\n                    .append(\"Content-Type: application/resource-lists+xml\").append(SipUtils.CRLF)\n                    .append(\"Content-Length: \").append(resourceList.getBytes(UTF8).length)\n                    .append(SipUtils.CRLF).append(\"Content-Disposition: recipient-list\")\n                    .append(SipUtils.CRLF).append(SipUtils.CRLF).append(resourceList)\n                    .append(SipUtils.CRLF).append(Multipart.BOUNDARY_DELIMITER)\n                    .append(BOUNDARY_TAG).append(Multipart.BOUNDARY_DELIMITER).toString();\n\n            getDialogPath().setLocalContent(multipart);\n\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInviteRequest(multipart);\n\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n\n            getDialogPath().setInvite(invite);\n\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException e) {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (ParseException e) {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (FileAccessException e) {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException e) {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    /**\n     * Create INVITE request\n     * \n     * @param content Content part\n     * @return Request\n     * @throws PayloadException\n     */\n    private SipRequest createInviteRequest(String content) throws PayloadException {\n        try {\n            SipRequest invite = SipMessageFactory.createMultipartInvite(getDialogPath(),\n                    getFeatureTags(), getAcceptContactTags(), content, BOUNDARY_TAG);\n            if (getSubject() != null) {\n                invite.addHeader(SubjectHeader.NAME, getSubject());\n            }\n            invite.addHeader(RequireHeader.NAME, \"recipient-list-invite\");\n            invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID());\n            return invite;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create invite request!\", e);\n        }\n    }\n\n    @Override\n    public SipRequest createInvite() throws PayloadException {\n        return createInviteRequest(getDialogPath().getLocalContent());\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/OriginatingOneToOneChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * Originating one-to-one chat session\n * \n * @author jexa7410\n */\npublic class OriginatingOneToOneChatSession extends OneToOneChatSession {\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    private final static Logger sLogger = Logger.getLogger(OriginatingOneToOneChatSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param contact Remote contact identifier\n     * @param msg First message of the session\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     */\n    public OriginatingOneToOneChatSession(InstantMessagingService imService, ContactId contact,\n            ChatMessage msg, RcsSettings rcsSettings, MessagingLog messagingLog, long timestamp,\n            ContactManager contactManager) {\n        super(imService, contact, PhoneUtils.formatContactIdToUri(contact), msg, rcsSettings,\n                messagingLog, timestamp, contactManager);\n        // Create dialog path\n        createOriginatingDialogPath();\n        // Set contribution ID\n        String id = ContributionIdGenerator.getContributionId(getDialogPath().getCallId());\n        setContributionID(id);\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new 1-1 chat session as originating\");\n            }\n            // Set setup mode\n            String localSetup = createSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \" + localSetup);\n            }\n            // Set local port\n            int localMsrpPort;\n            if (\"active\".equals(localSetup)) {\n                localMsrpPort = 9; // See RFC4145, Page 4\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n            // Build SDP part\n            // String ntpTime =\n            // SipUtils.constructNTPtime(System.currentTimeMillis());\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), getSdpDirection());\n            // If there is a first message then builds a multipart content else\n            // builds a SDP content\n            ChatMessage chatMessage = getFirstMessage();\n            if (chatMessage != null) {\n                // Build CPIM part\n                String from = ChatUtils.ANONYMOUS_URI;\n                String to = ChatUtils.ANONYMOUS_URI;\n\n                String cpim;\n                String mimeType = chatMessage.getMimeType();\n                String networkMimeType = ChatUtils.apiMimeTypeToNetworkMimeType(mimeType);\n                String networkContent = chatMessage.getContent();\n                String msgId = chatMessage.getMessageId();\n                long timestampSent = chatMessage.getTimestampSent();\n                if (MimeType.GEOLOC_MESSAGE.equals(mimeType)) {\n                    networkContent = ChatUtils.persistedGeolocContentToNetworkGeolocContent(\n                            networkContent, msgId, timestampSent);\n                }\n                if (mImdnManager.isRequestOneToOneDeliveryDisplayedReportsEnabled()) {\n                    cpim = ChatUtils.buildCpimMessageWithImdn(from, to, msgId, networkContent,\n                            networkMimeType, timestampSent);\n                } else if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n                    cpim = ChatUtils.buildCpimMessageWithoutDisplayedImdn(from, to, msgId,\n                            networkContent, networkMimeType, timestampSent);\n                } else {\n                    cpim = ChatUtils.buildCpimMessage(from, to, networkContent, networkMimeType,\n                            timestampSent);\n                }\n                String multipart = Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                        + \"Content-Type: application/sdp\" + SipUtils.CRLF + \"Content-Length: \"\n                        + sdp.getBytes(UTF8).length + SipUtils.CRLF + SipUtils.CRLF + sdp\n                        + SipUtils.CRLF + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG\n                        + SipUtils.CRLF + \"Content-Type: \" + CpimMessage.MIME_TYPE + SipUtils.CRLF\n                        + \"Content-Length: \" + cpim.getBytes(UTF8).length + SipUtils.CRLF\n                        + SipUtils.CRLF + cpim + SipUtils.CRLF + Multipart.BOUNDARY_DELIMITER\n                        + BOUNDARY_TAG + Multipart.BOUNDARY_DELIMITER;\n\n                // Set the local SDP part in the dialog path\n                getDialogPath().setLocalContent(multipart);\n\n            } else {\n                // Set the local SDP part in the dialog path\n                getDialogPath().setLocalContent(sdp);\n            }\n            SipRequest invite = createInvite();\n            // Set the Authorization header\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n            // Set initial request in the dialog path\n            getDialogPath().setInvite(invite);\n            // Send INVITE request\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException e) {\n            sLogger.error(\"Unable to set authorization header for chat invite!\", e);\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (FileAccessException | PayloadException e) {\n            sLogger.error(\"Unable to send 200OK response!\", e);\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed initiating chat session!\", e);\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public String getSdpDirection() {\n        return SdpUtils.DIRECTION_SENDRECV;\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getImsService().getImsModule().getInstantMessagingService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/ParticipantInfoUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.chat.resourcelist.ResourceListDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.resourcelist.ResourceListParser;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n/**\n * Utilities for ParticipantInfo\n * \n * @author YPLO6403\n */\npublic class ParticipantInfoUtils {\n\n    private static final Logger sLogger = Logger.getLogger(ParticipantInfoUtils.class\n            .getSimpleName());\n\n    /**\n     * Create a set of participant info from XML\n     * \n     * @param xml Resource-list document in XML\n     * @param status Participant info status\n     * @return the set of participants\n     * @throws PayloadException\n     */\n    public static Map<ContactId, ParticipantStatus> parseResourceList(String xml,\n            ParticipantStatus status) throws PayloadException {\n        Map<ContactId, ParticipantStatus> participants = new HashMap<ContactId, ParticipantStatus>();\n        try {\n            InputSource pidfInput = new InputSource(new ByteArrayInputStream(xml.getBytes(UTF8)));\n            ResourceListParser listParser = new ResourceListParser(pidfInput).parse();\n            ResourceListDocument resList = listParser.getResourceList();\n            if (resList != null) {\n                for (String entry : resList.getEntries()) {\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(entry);\n                    if (number == null) {\n                        continue;\n                    }\n                    ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                    if (!contact.equals(ImsModule.getImsUserProfile().getUsername())) {\n                        participants.put(contact, status);\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Add participant \" + contact + \" to the list\");\n                        }\n                    }\n                }\n            }\n        } catch (ParserConfigurationException e) {\n            throw new PayloadException(\"Can't parse resource-list document!\", e);\n\n        } catch (SAXException e) {\n            throw new PayloadException(\"Can't parse resource-list document!\", e);\n\n        } catch (ParseFailureException e) {\n            throw new PayloadException(\"Can't parse resource-list document!\", e);\n        }\n        return participants;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/RejoinGroupChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.text.TextUtils;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.SubjectHeader;\n\n/**\n * Rejoin a group chat session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RejoinGroupChatSession extends GroupChatSession {\n\n    private final static Logger sLogger = Logger.getLogger(RejoinGroupChatSession.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param groupChatInfo Group Chat information\n     * @param rcsSettings Rcs settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     */\n    public RejoinGroupChatSession(InstantMessagingService imService, GroupChatInfo groupChatInfo,\n            RcsSettings rcsSettings, MessagingLog messagingLog, long timestamp,\n            ContactManager contactManager) {\n        super(imService, null, groupChatInfo.getRejoinId(), groupChatInfo.getParticipants(),\n                rcsSettings, messagingLog, timestamp, contactManager);\n\n        if (!TextUtils.isEmpty(groupChatInfo.getSubject())) {\n            setSubject(groupChatInfo.getSubject());\n        }\n        createOriginatingDialogPath();\n        setContributionID(groupChatInfo.getContributionId());\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Rejoin an existing group chat session\");\n            }\n\n            String localSetup = createSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n\n            int localMsrpPort;\n            if (\"active\".equals(localSetup)) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildGroupChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), SdpUtils.DIRECTION_SENDRECV);\n\n            getDialogPath().setLocalContent(sdp);\n\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInviteRequest(sdp);\n\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n\n            getDialogPath().setInvite(invite);\n\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException | FileAccessException | PayloadException\n                | NetworkException | RuntimeException e) {\n            handleError(new ChatError(ChatError.SESSION_REJOIN_FAILED, e));\n        }\n    }\n\n    /**\n     * Create INVITE request\n     * \n     * @param content Content part\n     * @return Request\n     * @throws PayloadException\n     */\n    private SipRequest createInviteRequest(String content) throws PayloadException {\n        try {\n            SipRequest invite = SipMessageFactory.createInvite(getDialogPath(), getFeatureTags(),\n                    getAcceptContactTags(), content);\n            final String subject = getSubject();\n            if (subject != null) {\n                invite.addHeader(SubjectHeader.NAME, subject);\n            }\n            invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID());\n            return invite;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create invite request!\", e);\n        }\n    }\n\n    @Override\n    public SipRequest createInvite() throws PayloadException {\n        return createInviteRequest(getDialogPath().getLocalContent());\n    }\n\n    @Override\n    public void handle404SessionNotFound(SipResponse resp) {\n        handleError(new ChatError(ChatError.SESSION_NOT_FOUND, resp.getReasonPhrase()));\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/RestartGroupChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.text.ParseException;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.RequireHeader;\nimport javax2.sip.header.SubjectHeader;\nimport javax2.sip.header.WarningHeader;\n\n/**\n * Restart group chat session\n * \n * @author jexa7410\n */\npublic class RestartGroupChatSession extends GroupChatSession {\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    private static final Logger sLogger = Logger.getLogger(RestartGroupChatSession.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param conferenceId Conference ID\n     * @param subject Subject associated to the session\n     * @param storedParticipants map of invited participants\n     * @param contributionId Contribution ID\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     */\n    public RestartGroupChatSession(InstantMessagingService imService, Uri conferenceId,\n            String subject, String contributionId,\n            Map<ContactId, ParticipantStatus> storedParticipants, RcsSettings rcsSettings,\n            MessagingLog messagingLog, long timestamp, ContactManager contactManager) {\n        super(imService, null, conferenceId, storedParticipants, rcsSettings, messagingLog,\n                timestamp, contactManager);\n\n        if (!TextUtils.isEmpty(subject)) {\n            setSubject(subject);\n        }\n        createOriginatingDialogPath();\n        setContributionID(contributionId);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Restart a group chat session\");\n            }\n            String localSetup = createSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            int localMsrpPort;\n            if (\"active\".equals(localSetup)) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildGroupChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), SdpUtils.DIRECTION_SENDRECV);\n            Set<ContactId> invitees = new HashSet<>();\n            Map<ContactId, ParticipantStatus> participants = getParticipants();\n            for (Map.Entry<ContactId, ParticipantStatus> participant : participants.entrySet()) {\n                switch (participant.getValue()) {\n                    case INVITE_QUEUED:\n                    case INVITING:\n                    case INVITED:\n                    case CONNECTED:\n                    case DISCONNECTED:\n                        invitees.add(participant.getKey());\n                        break;\n\n                    default:\n                        break;\n                }\n            }\n            String resourceList = ChatUtils.generateChatResourceList(invitees);\n            String multipart = Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                    + \"Content-Type: application/sdp\" + SipUtils.CRLF + \"Content-Length: \"\n                    + sdp.getBytes(UTF8).length + SipUtils.CRLF + SipUtils.CRLF + sdp\n                    + SipUtils.CRLF + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                    + \"Content-Type: application/resource-lists+xml\" + SipUtils.CRLF\n                    + \"Content-Length: \" + resourceList.getBytes(UTF8).length + SipUtils.CRLF\n                    + \"Content-Disposition: recipient-list\" + SipUtils.CRLF + SipUtils.CRLF\n                    + resourceList + SipUtils.CRLF + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG\n                    + Multipart.BOUNDARY_DELIMITER;\n            getDialogPath().setLocalContent(multipart);\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInviteRequest(multipart);\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n            getDialogPath().setInvite(invite);\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | FileAccessException | PayloadException\n                | NetworkException | RuntimeException | ParseException e) {\n            handleError(new ChatError(ChatError.SESSION_RESTART_FAILED, e));\n        }\n    }\n\n    /**\n     * Create INVITE request\n     * \n     * @param content Content part\n     * @return Request\n     * @throws PayloadException\n     */\n    private SipRequest createInviteRequest(String content) throws PayloadException {\n        try {\n            SipRequest invite = SipMessageFactory.createMultipartInvite(getDialogPath(),\n                    getFeatureTags(), getAcceptContactTags(), content, BOUNDARY_TAG);\n            final String subject = getSubject();\n            if (subject != null) {\n                invite.addHeader(SubjectHeader.NAME, subject);\n            }\n            invite.addHeader(RequireHeader.NAME, \"recipient-list-invite\");\n            invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID());\n            return invite;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create invite request!\", e);\n        }\n    }\n\n    @Override\n    public SipRequest createInvite() throws PayloadException {\n        return createInviteRequest(getDialogPath().getLocalContent());\n    }\n\n    @Override\n    public void handle403Forbidden(SipResponse resp) {\n        WarningHeader warn = (WarningHeader) resp.getHeader(WarningHeader.NAME);\n        if ((warn != null) && (warn.getText() != null)\n                && (warn.getText().contains(\"127 Service not authorised\"))) {\n            handleError(new ChatError(ChatError.SESSION_RESTART_FAILED, resp.getReasonPhrase()));\n        } else {\n            handleError(new ChatError(ChatError.SESSION_INITIATION_FAILED, resp.getStatusCode()\n                    + \" \" + resp.getReasonPhrase()));\n        }\n    }\n\n    /**\n     * Handle 404 Session Not Found\n     * \n     * @param resp 404 response\n     */\n    public void handle404SessionNotFound(SipResponse resp) {\n        handleError(new ChatError(ChatError.SESSION_NOT_FOUND, resp.getReasonPhrase()));\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/SessionUnavailableException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\n/**\n * To be thrown when there is no session available to perform an operation.\n * <p>\n * These exceptions should not be logged as there is not much to do for handling such type of\n * exceptions other then re-trying once there is an availability for a session.\n * </p>\n */\npublic class SessionUnavailableException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public SessionUnavailableException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public SessionUnavailableException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n}\n\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/TerminatingAdhocGroupChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Vector;\n\n/**\n * Terminating ad-hoc group chat session\n * \n * @author jexa7410\n */\npublic class TerminatingAdhocGroupChatSession extends GroupChatSession {\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingAdhocGroupChatSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param invite Initial INVITE request\n     * @param contact remote contact\n     * @param participantsFromInvite Map of participants\n     * @param remoteContact the remote contact Uri\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager accessor\n     * @throws PayloadException Thrown if constructor fails to get information from payload\n     */\n    public TerminatingAdhocGroupChatSession(InstantMessagingService imService, SipRequest invite,\n            ContactId contact, Map<ContactId, ParticipantStatus> participantsFromInvite,\n            Uri remoteContact, RcsSettings rcsSettings, MessagingLog messagingLog, long timestamp,\n            ContactManager contactManager) throws PayloadException {\n        super(imService, contact, remoteContact, participantsFromInvite, rcsSettings, messagingLog,\n                timestamp, contactManager);\n        String subject = ChatUtils.getSubject(invite);\n        setSubject(subject);\n        createTerminatingDialogPath(invite);\n        setRemoteDisplayName(SipUtils.getDisplayNameFromInvite(invite));\n        String chatId = ChatUtils.getContributionId(invite);\n        setContributionID(chatId);\n        if (shouldBeAutoAccepted()) {\n            setSessionAccepted();\n        }\n    }\n\n    /**\n     * Check is session should be auto accepted. This method should only be called once per session\n     * \n     * @return true if group chat session should be auto accepted\n     * @throws PayloadException\n     */\n    private boolean shouldBeAutoAccepted() throws PayloadException {\n        /*\n         * In case the invite contains a http file transfer info the chat session should be\n         * auto-accepted so that the file transfer session can be started.\n         */\n        return FileTransferUtils.getHttpFTInfo(getDialogPath().getInvite(), mRcsSettings) != null\n                || mRcsSettings.isGroupChatAutoAccepted();\n    }\n\n    @Override\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        try {\n            if (logActivated) {\n                sLogger.info(\"Initiate a new ad-hoc group chat session as terminating\");\n            }\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            String subject = getSubject();\n            Map<ContactId, ParticipantStatus> participants = getParticipants();\n            /* Check if session should be auto-accepted once */\n            long timestamp = getTimestamp();\n            SipDialogPath dialogPath = getDialogPath();\n            if (isSessionAccepted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Received group chat invitation marked for auto-accept\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((GroupChatSessionListener) listener).onSessionAutoAccepted(contact, subject,\n                            participants, timestamp);\n                }\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"Received group chat invitation marked for manual accept\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((GroupChatSessionListener) listener).onSessionInvited(contact, subject,\n                            participants, timestamp);\n                }\n                send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n                InvitationStatus answer = waitInvitationAnswer();\n                switch (answer) {\n                    case INVITATION_REJECTED_DECLINE:\n                        /* Intentional fall through */\n                    case INVITATION_REJECTED_BUSY_HERE:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected by user\");\n                        }\n                        sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_USER);\n                        }\n                        return;\n\n                    case INVITATION_TIMEOUT:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected on timeout\");\n                        }\n                        /* Ringing period timeout */\n                        send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_TIMEOUT);\n                        }\n                        return;\n\n                    case INVITATION_REJECTED_BY_SYSTEM:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been aborted by system\");\n                        }\n                        removeSession();\n                        return;\n\n                    case INVITATION_CANCELED:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected by remote\");\n                        }\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_REMOTE);\n                        }\n                        return;\n\n                    case INVITATION_ACCEPTED:\n                        setSessionAccepted();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionAccepting(contact);\n                        }\n                        break;\n\n                    case INVITATION_DELETED:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been deleted\");\n                        }\n                        removeSession();\n                        return;\n\n                    default:\n                        throw new IllegalArgumentException(\n                                \"Unknown invitation answer in run; answer=\" + answer);\n                }\n            }\n            /* Parse the remote SDP part */\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            MediaAttribute attr1 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr1.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n            /* Extract the \"setup\" parameter */\n            String remoteSetup = \"passive\";\n            MediaAttribute attr2 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr2 != null) {\n                remoteSetup = attr2.getValue();\n            }\n            if (logActivated) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n            /* Set setup mode */\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (logActivated) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            /* Set local port */\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n            /* Build SDP part */\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildGroupChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), SdpUtils.DIRECTION_SENDRECV);\n            /* Set the local SDP part in the dialog path */\n            dialogPath.setLocalContent(sdp);\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Create a 200 OK response */\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    getFeatureTags(), getAcceptContactTags(), sdp);\n            dialogPath.setSigEstablished();\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n            /* Create the MSRP server session */\n            if (localSetup.equals(\"passive\")) {\n                /* Passive mode: client wait a connection */\n                MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this);\n                session.setFailureReportOption(false);\n                session.setSuccessReportOption(false);\n                getMsrpMgr().openMsrpSession();\n                /*\n                 * Even if local setup is passive, an empty packet must be sent to open the NAT and\n                 * so enable the active endpoint to initiate a MSRP connection.\n                 */\n                sendEmptyDataChunk();\n            }\n            /* wait a response */\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (logActivated) {\n                    sLogger.info(\"ACK request received\");\n                }\n                dialogPath.setSessionEstablished();\n                /* Create the MSRP client session */\n                if (localSetup.equals(\"active\")) {\n                    /* Active mode: client should connect */\n                    MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost,\n                            remotePort, remotePath, this, fingerprint);\n                    session.setFailureReportOption(false);\n                    session.setSuccessReportOption(false);\n                    getMsrpMgr().openMsrpSession();\n                    sendEmptyDataChunk();\n                }\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(contact);\n                }\n                getConferenceEventSubscriber().subscribe();\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n            } else {\n                /* No response received: timeout */\n                handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED));\n            }\n        } catch (PayloadException | RuntimeException | NetworkException e) {\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n    @Override\n    public void startSession() {\n        final boolean logActivated = sLogger.isActivated();\n        String chatId = getContributionID();\n        if (logActivated) {\n            sLogger.debug(\"Start GroupChatSession with chatID: \".concat(chatId));\n        }\n        InstantMessagingService imService = getImsService().getImsModule()\n                .getInstantMessagingService();\n        GroupChatSession currentSession = imService.getGroupChatSession(chatId);\n        if (currentSession != null) {\n            /*\n             * If there is already a groupchat session with same chatId existing, we should not\n             * reject the new session but update cache with this groupchat session and mark the old\n             * groupchat session pending for removal which will timeout eventually\n             */\n            if (logActivated) {\n                sLogger.debug(\"Ongoing GrooupChat session detected for chatId '\" + chatId\n                        + \"' marking that session pending for removal\");\n            }\n            currentSession.markForPendingRemoval();\n            /*\n             * Since the current session was already established and we are now replacing that\n             * session with a new session then we make sure to auto-accept that new replacement\n             * session also so to leave the client in the same situation for the replacement session\n             * as for the original \"current\" session regardless if the the provisioning setting for\n             * chat is set to non-auto-accept or not.\n             */\n            if (currentSession.getDialogPath().isSessionEstablished()) {\n                setSessionAccepted();\n            }\n        }\n        imService.addSession(this);\n        start();\n    }\n\n    /**\n     * Request capabilities to contact\n     * \n     * @param contact the contact\n     */\n    private void requestContactCapabilities(String contact) {\n        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(contact);\n        if (number != null) {\n            ContactId remote = ContactUtil.createContactIdFromValidatedData(number);\n            getImsService().getImsModule().getCapabilityService()\n                    .requestContactCapabilities(remote);\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to request capabilities: invalid contact '\" + contact + \"'\");\n            }\n        }\n    }\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        super.receiveBye(bye);\n        requestContactCapabilities(getDialogPath().getRemoteParty());\n    }\n\n    /**\n     * Receive CANCEL request\n     * \n     * @param cancel CANCEL request\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        super.receiveCancel(cancel);\n        requestContactCapabilities(getDialogPath().getRemoteParty());\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/TerminatingOneToOneChatSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Collection;\nimport java.util.Vector;\n\n/**\n * Terminating one-to-one chat session\n * \n * @author jexa7410\n */\npublic class TerminatingOneToOneChatSession extends OneToOneChatSession {\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingOneToOneChatSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param invite Initial INVITE request\n     * @param contact the remote contactId\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     * @throws PayloadException\n     */\n    public TerminatingOneToOneChatSession(InstantMessagingService imService, SipRequest invite,\n            ContactId contact, RcsSettings rcsSettings, MessagingLog messagingLog, long timestamp,\n            ContactManager contactManager) throws PayloadException {\n        super(imService, contact, PhoneUtils.formatContactIdToUri(contact), ChatUtils\n                .getFirstMessage(invite, timestamp), rcsSettings, messagingLog, timestamp,\n                contactManager);\n        // Create dialog path\n        createTerminatingDialogPath(invite);\n        // Set contribution ID\n        String id = ChatUtils.getContributionId(invite);\n        setContributionID(id);\n        if (shouldBeAutoAccepted()) {\n            setSessionAccepted();\n        }\n    }\n\n    /**\n     * Check is session should be auto accepted. This method should only be called once per session\n     * \n     * @return true if one-to-one chat session should be auto accepted\n     * @throws PayloadException\n     */\n    private boolean shouldBeAutoAccepted() throws PayloadException {\n        /*\n         * In case the invite contains a http file transfer info the chat session should be\n         * auto-accepted so that the file transfer session can be started.\n         */\n        return FileTransferUtils.getHttpFTInfo(getDialogPath().getInvite(), mRcsSettings) != null\n                || mRcsSettings.isChatAutoAccepted();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        try {\n            if (logActivated) {\n                sLogger.info(\"Initiate a new 1-1 chat session as terminating\");\n            }\n            ContactId remote = getRemoteContact();\n            SipDialogPath dialogPath = getDialogPath();\n            if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n                /* Check notification disposition */\n                String msgId = ChatUtils.getMessageId(dialogPath.getInvite());\n                if (msgId != null) {\n                    /* Send message delivery status via a SIP MESSAGE */\n                    mImdnManager.sendMessageDeliveryStatusImmediately(remote.toString(), remote,\n                            msgId, ImdnDocument.DeliveryStatus.DELIVERED,\n                            SipUtils.getRemoteInstanceId(dialogPath.getInvite()), getTimestamp());\n                }\n            }\n            Collection<ImsSessionListener> listeners = getListeners();\n            /* Check if session should be auto-accepted once */\n            if (isSessionAccepted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Received one-to-one chat invitation marked for auto-accept\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((OneToOneChatSessionListener) listener).onSessionAutoAccepted(remote);\n                }\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"Received one-to-one chat invitation marked for manual accept\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((OneToOneChatSessionListener) listener).onSessionInvited(remote);\n                }\n                send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n                InvitationStatus answer = waitInvitationAnswer();\n                switch (answer) {\n                    case INVITATION_REJECTED_DECLINE:\n                        /* Intentional fall through */\n                    case INVITATION_REJECTED_BUSY_HERE:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected by user\");\n                        }\n                        sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(remote,\n                                    TerminationReason.TERMINATION_BY_USER);\n                        }\n                        return;\n\n                    case INVITATION_TIMEOUT:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected on timeout\");\n                        }\n                        /* Ringing period timeout */\n                        send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(remote,\n                                    TerminationReason.TERMINATION_BY_TIMEOUT);\n                        }\n                        return;\n\n                    case INVITATION_REJECTED_BY_SYSTEM:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been aborted by system\");\n                        }\n                        removeSession();\n                        return;\n\n                    case INVITATION_CANCELED:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected by remote\");\n                        }\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(remote,\n                                    TerminationReason.TERMINATION_BY_REMOTE);\n                        }\n                        return;\n\n                    case INVITATION_ACCEPTED:\n                        setSessionAccepted();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionAccepting(remote);\n                        }\n                        break;\n\n                    case INVITATION_DELETED:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been deleted\");\n                        }\n                        removeSession();\n                        return;\n\n                    default:\n                        if (logActivated) {\n                            sLogger.debug(\"Unknown invitation answer in run; answer=\".concat(String\n                                    .valueOf(answer)));\n                        }\n                        break;\n                }\n            }\n            /* Parse the remote SDP part */\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            MediaAttribute attr1 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr1.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n            /* Extract the \"setup\" parameter */\n            String remoteSetup = \"passive\";\n            MediaAttribute attr2 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr2 != null) {\n                remoteSetup = attr2.getValue();\n            }\n            if (logActivated) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n            /* Set setup mode */\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (logActivated) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            /* Set local port */\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n            /* Build SDP part */\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), getSdpDirection());\n            /* Set the local SDP part in the dialog path */\n            dialogPath.setLocalContent(sdp);\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Create a 200 OK response */\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    getFeatureTags(), sdp);\n            dialogPath.setSigEstablished();\n            /* Send response */\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n            /* Create the MSRP server session */\n            if (localSetup.equals(\"passive\")) {\n                /* Passive mode: client wait a connection */\n                MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this);\n                session.setFailureReportOption(false);\n                session.setSuccessReportOption(false);\n                getMsrpMgr().openMsrpSession();\n                /*\n                 * Even if local setup is passive, an empty chunk must be sent to open the NAT and\n                 * so enable the active endpoint to initiate a MSRP connection.\n                 */\n                sendEmptyDataChunk();\n            }\n            /* wait a response */\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (logActivated) {\n                    sLogger.info(\"ACK request received\");\n                }\n                dialogPath.setSessionEstablished();\n                /* Create the MSRP client session */\n                if (localSetup.equals(\"active\")) {\n                    /* Active mode: client should connect */\n                    MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost,\n                            remotePort, remotePath, this, fingerprint);\n                    session.setFailureReportOption(false);\n                    session.setSuccessReportOption(false);\n                    getMsrpMgr().openMsrpSession();\n                    sendEmptyDataChunk();\n                }\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(remote);\n                }\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n                getActivityManager().start();\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n                /* No response received: timeout */\n                handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED));\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Unable to send 200OK response!\", e);\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to initiate chat session as terminating!\", e);\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n        }\n    }\n\n    // Changed by Deutsche Telekom\n    @Override\n    public String getSdpDirection() {\n        return SdpUtils.DIRECTION_SENDRECV;\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n    @Override\n    public void startSession() throws PayloadException, NetworkException {\n        final boolean logActivated = sLogger.isActivated();\n        ContactId remote = getRemoteContact();\n        if (logActivated) {\n            sLogger.debug(\"Start OneToOneChatSession with '\" + remote + \"'\");\n        }\n        InstantMessagingService imService = getImsService().getImsModule()\n                .getInstantMessagingService();\n        OneToOneChatSession currentSession = imService.getOneToOneChatSession(remote);\n        if (currentSession != null) {\n            boolean currentSessionInitiatedByRemote = currentSession.isInitiatedByRemote();\n            boolean currentSessionEstablished = currentSession.getDialogPath()\n                    .isSessionEstablished();\n            if (!currentSessionEstablished && !currentSessionInitiatedByRemote) {\n                /*\n                 * Rejecting the NEW invitation since there is already a PENDING OneToOneChatSession\n                 * that was locally originated with the same contact.\n                 */\n                if (logActivated) {\n                    sLogger.warn(\"Rejecting OneToOneChatSession (session id '\" + getSessionID()\n                            + \"') with '\" + remote + \"'\");\n                }\n                rejectSession();\n                return;\n            }\n            /*\n             * If this oneToOne session does NOT already contain another oneToOne chat session which\n             * in state PENDING and also LOCALLY originating we should leave (reject or abort) the\n             * CURRENT rcs chat session if there is one and replace it with the new one.\n             */\n            if (logActivated) {\n                sLogger.warn(\"Rejecting/Aborting existing OneToOneChatSession (session id '\"\n                        + getSessionID() + \"') with '\" + remote + \"'\");\n            }\n            if (currentSessionInitiatedByRemote) {\n                if (currentSessionEstablished) {\n                    currentSession.terminateSession(TerminationReason.TERMINATION_BY_SYSTEM);\n                } else {\n                    currentSession.rejectSession();\n                }\n            } else {\n                currentSession.terminateSession(TerminationReason.TERMINATION_BY_SYSTEM);\n            }\n            /*\n             * Since the current session was already established and we are now replacing that\n             * session with a new session then we make sure to auto-accept that new replacement\n             * session also so to leave the client in the same situation for the replacement session\n             * as for the original \"current\" session regardless if the the provisioning setting for\n             * chat is set to non-auto-accept or not.\n             */\n            if (currentSessionEstablished) {\n                setSessionAccepted();\n            }\n        }\n        imService.addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getImsService().getImsModule().getInstantMessagingService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/cpim/CpimHeader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.cpim;\n\n/**\n * CPIM header\n * \n * @author jexa7410\n */\npublic class CpimHeader {\n    /***\n     * Header name\n     */\n    private String name;\n\n    /**\n     * Header value\n     */\n    private String value;\n\n    /**\n     * Constructor\n     * \n     * @param name Header name\n     * @param value Header value\n     */\n    public CpimHeader(String name, String value) {\n        this.name = name;\n        this.value = value;\n    }\n\n    /**\n     * Returns header name\n     * \n     * @return String\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns header value\n     * \n     * @return String\n     */\n    public String getValue() {\n        return value;\n    }\n\n    /**\n     * Parse CPIM header\n     * \n     * @param data Input data\n     * @return Header\n     */\n    public static CpimHeader parseHeader(String data) {\n        int index = data.indexOf(\":\");\n        String key = data.substring(0, index);\n        String value = data.substring(index + 1);\n        return new CpimHeader(key.trim(), value.trim());\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/cpim/CpimIdentity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.cpim;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Immutable class to decode the content of the CPIM identity header according to RFC3862\n * \n * @author Philippe LEMORDANT\n */\npublic class CpimIdentity {\n    /**\n     * Pattern to extract display name and Uri from CPIM 'From' header using a regular expression of\n     * the CPIM 'From' header.\n     * <p>\n     * Extract of RFC3862 <b>Common Presence and Instant Messaging (CPIM): Message Format</b> <br>\n     * From-header = \"From\" \": \" [ Formal-name ] \"<\" URI \">\" ; \"From\" is case-sensitive\n     */\n    private final static Pattern PATTERN_URI_WITH_OPTIONAL_DISPLAY_NAME = Pattern\n            .compile(\"^\\\\s*?\\\"?([^\\\"<]*)\\\"?\\\\s*?<([^>]*)>$\");\n\n    /**\n     * The optional display name (may be null)\n     */\n    private final String mDisplayName;\n\n    private final String mUri;\n\n    /**\n     * Constructor\n     * \n     * @param identity the CPIM identity\n     */\n    public CpimIdentity(final String identity) {\n        if (identity == null)\n            throw new IllegalArgumentException(\"Null argument\");\n        Matcher matcher = PATTERN_URI_WITH_OPTIONAL_DISPLAY_NAME.matcher(identity);\n        if (matcher.find()) {\n            if (matcher.groupCount() == 2) {\n                String result = matcher.group(1).trim();\n                mDisplayName = (result.length() == 0) ? null : result;\n                mUri = matcher.group(2);\n                return;\n            }\n        }\n        throw new IllegalArgumentException(\"Invalid uri: \" + identity);\n    }\n\n    public String getDisplayName() {\n        return mDisplayName;\n    }\n\n    public String getUri() {\n        return mUri;\n    }\n\n    @Override\n    public String toString() {\n        return \"CpimIdentity [displayName=\" + mDisplayName + \", uri=\" + mUri + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/cpim/CpimMessage.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.cpim;\n\nimport com.gsma.rcs.utils.DateUtils;\n\nimport java.util.Hashtable;\n\n/**\n * CPIM message\n * \n * @author jexa7410\n */\npublic class CpimMessage {\n    /**\n     * MIME type\n     */\n    public static final String MIME_TYPE = \"message/cpim\";\n\n    /**\n     * Header \"Content-type\"\n     */\n    public static final String HEADER_CONTENT_TYPE = \"Content-type\";\n    public static final String HEADER_CONTENT_TYPE2 = \"Content-Type\";\n\n    /**\n     * Header \"From\"\n     */\n    public static final String HEADER_FROM = \"From\";\n\n    /**\n     * Header \"To\"\n     */\n    public static final String HEADER_TO = \"To\";\n\n    /**\n     * Header \"DateTime\"\n     */\n    public static final String HEADER_DATETIME = \"DateTime\";\n\n    /**\n     * Header \"NS\"\n     */\n    public static final String HEADER_NS = \"NS\";\n\n    /**\n     * Header \"Content-length\"\n     */\n    public static final String HEADER_CONTENT_LENGTH = \"Content-length\";\n\n    /**\n     * Header \"Content-Disposition\"\n     */\n    public static final String HEADER_CONTENT_DISPOSITION = \"Content-Disposition\";\n\n    /**\n     * Message content\n     */\n    private final String mMsgContent;\n\n    /**\n     * MIME headers\n     */\n    private final Hashtable<String, String> mHeaders;\n\n    /**\n     * MIME content headers\n     */\n    private final Hashtable<String, String> mContentHeaders;\n\n    /**\n     * Constructor\n     * \n     * @param headers MIME headers\n     * @param contentHeaders MIME content headers\n     * @param msgContent Content\n     */\n    public CpimMessage(Hashtable<String, String> headers, Hashtable<String, String> contentHeaders,\n            String msgContent) {\n        mHeaders = headers;\n        mContentHeaders = contentHeaders;\n        mMsgContent = msgContent;\n    }\n\n    /**\n     * Returns content type\n     * \n     * @return Content type\n     */\n    public String getContentType() {\n        String type = mContentHeaders.get(CpimMessage.HEADER_CONTENT_TYPE);\n        if (type == null) {\n            return mContentHeaders.get(CpimMessage.HEADER_CONTENT_TYPE2);\n        }\n        return type;\n    }\n\n    /**\n     * Returns MIME header\n     * \n     * @param name Header name\n     * @return Header value\n     */\n    public String getHeader(String name) {\n        return mHeaders.get(name);\n    }\n\n    /**\n     * Returns MIME content header\n     * \n     * @param name Header name\n     * @return Header value\n     */\n    public String getContentHeader(String name) {\n        return mContentHeaders.get(name);\n    }\n\n    /**\n     * Returns message content\n     * \n     * @return Content\n     */\n    public String getMessageContent() {\n        return mMsgContent;\n    }\n\n    /**\n     * Returns message timestamp sent\n     * \n     * @return timestamp sent in payload\n     */\n    public long getTimestampSent() {\n        String header = getHeader(CpimMessage.HEADER_DATETIME);\n        if (header != null) {\n            return DateUtils.decodeDate(header);\n        }\n        return 0;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/cpim/CpimParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.cpim;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport java.util.Hashtable;\nimport java.util.StringTokenizer;\n\n/**\n * CPIM parser (see RFC3862)\n * \n * @author jexa7410\n */\npublic class CpimParser {\n    /**\n     * CRLF constant\n     */\n    private static final String CRLF = \"\\r\\n\";\n\n    /**\n     * Double CRLF constant\n     */\n    private static final String DOUBLE_CRLF = CRLF + CRLF;\n\n    private CpimMessage mMessage;\n\n    /**\n     * Constructor\n     * \n     * @param data Input data\n     */\n    public CpimParser(byte data[]) {\n        parse(new String(data, UTF8));\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Input data\n     */\n    public CpimParser(String data) {\n        parse(data);\n    }\n\n    /***\n     * Returns the CPIM message\n     * \n     * @return CPIM message\n     */\n    public CpimMessage getCpimMessage() {\n        return mMessage;\n    }\n\n    /**\n     * Parse message/CPIM document\n     * \n     * @param data Input data\n     */\n    private void parse(String data) {\n        /*\n         * CPIM sample: From: MR SANDERS <im:piglet@100akerwood.com> To: Depressed Donkey\n         * <im:eeyore@100akerwood.com> DateTime: 2000-12-13T13:40:00-08:00 Subject: the weather will\n         * be fine today Content-type: text/plain Content-ID: <1234567890@foo.com> Here is the text\n         * of my message.\n         */\n        /* Read message headers */\n        int begin = 0;\n        int end = data.indexOf(DOUBLE_CRLF, begin);\n        String block2 = data.substring(begin, end);\n        StringTokenizer lines = new StringTokenizer(block2, CRLF);\n        Hashtable<String, String> headers = new Hashtable<>();\n        while (lines.hasMoreTokens()) {\n            String token = lines.nextToken();\n            CpimHeader hd = CpimHeader.parseHeader(token);\n            headers.put(hd.getName(), hd.getValue());\n        }\n        /* Read the MIME-encapsulated content header */\n        begin = end + 4;\n        end = data.indexOf(DOUBLE_CRLF, begin);\n        String block3 = data.substring(begin, end);\n        lines = new StringTokenizer(block3, CRLF);\n        Hashtable<String, String> contentHeaders = new Hashtable<>();\n        while (lines.hasMoreTokens()) {\n            String token = lines.nextToken();\n            CpimHeader hd = CpimHeader.parseHeader(token);\n            contentHeaders.put(hd.getName(), hd.getValue());\n        }\n        /* Read the message content */\n        begin = end + 4;\n        String content = data.substring(begin);\n        mMessage = new CpimMessage(headers, contentHeaders, content);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/event/ConferenceEventSubscribeManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.event;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatError;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSessionListener;\nimport com.gsma.rcs.platform.registry.RegistryFactory;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.text.ParseException;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Vector;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.SubscriptionStateHeader;\nimport javax2.sip.message.Response;\n\n/**\n * Conference event subscribe manager\n * \n * @author jexa7410\n */\npublic class ConferenceEventSubscribeManager extends PeriodicRefresher {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Last min expire period (in milliseconds)\n     */\n    private static final String REGISTRY_MIN_EXPIRE_PERIOD = \"MinSubscribeConferenceEventExpirePeriod\";\n\n    /**\n     * IMS module\n     */\n    private ImsModule mImsModule;\n\n    /**\n     * Group chat session\n     */\n    private GroupChatSession mSession;\n\n    /**\n     * Dialog path\n     */\n    private SipDialogPath mDialogPath;\n\n    /**\n     * Expire period in milliseconds\n     */\n    private long mExpirePeriod;\n\n    /**\n     * Subscription flag\n     */\n    private boolean mSubscribed = false;\n\n    /**\n     * Authentication agent\n     */\n    private SessionAuthenticationAgent mAuthenticationAgent;\n\n    private final RcsSettings mRcsSettings;\n\n    private final MessagingLog mMessagingLog;\n\n    private final static Logger sLogger = Logger.getLogger(ConferenceEventSubscribeManager.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param session Group chat session\n     * @param rcsSettings\n     * @param messagingLog\n     */\n    public ConferenceEventSubscribeManager(GroupChatSession session, RcsSettings rcsSettings,\n            MessagingLog messagingLog) {\n        mSession = session;\n        mImsModule = session.getImsService().getImsModule();\n        mAuthenticationAgent = new SessionAuthenticationAgent(mImsModule);\n        mRcsSettings = rcsSettings;\n        mMessagingLog = messagingLog;\n\n        long defaultExpirePeriod = mRcsSettings.getSubscribeExpirePeriod();\n        long minExpireValue = RegistryFactory.getFactory().readLong(REGISTRY_MIN_EXPIRE_PERIOD, -1);\n        if ((minExpireValue != -1) && (defaultExpirePeriod < minExpireValue)) {\n            mExpirePeriod = minExpireValue;\n        } else {\n            mExpirePeriod = defaultExpirePeriod;\n        }\n    }\n\n    /**\n     * Is subscribed\n     * \n     * @return Boolean\n     */\n    public boolean isSubscribed() {\n        return mSubscribed;\n    }\n\n    /**\n     * Returns the identity.\n     * \n     * @return Identity\n     */\n    public String getIdentity() {\n        return mSession.getImSessionIdentity();\n    }\n\n    /**\n     * Returns the dialog path of the conference subscriber\n     * \n     * @return SipDialogPath\n     */\n    public SipDialogPath getDialogPath() {\n        return mDialogPath;\n    }\n\n    /**\n     * Receive a notification\n     * \n     * @param notify Received notify\n     * @param timestamp Local timestamp when got SipRequest\n     * @throws PayloadException\n     */\n    public void receiveNotification(SipRequest notify, long timestamp) throws PayloadException {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"New conference event notification received\");\n        }\n\n        // Parse XML part\n        byte[] content = notify.getContentBytes();\n        if (content != null) {\n            try {\n                InputSource pidfInput = new InputSource(new ByteArrayInputStream(content));\n                ConferenceInfoParser confParser = new ConferenceInfoParser(pidfInput).parse();\n                ConferenceInfoDocument conference = confParser.getConferenceInfo();\n                if (conference != null) {\n                    int maxParticipants = conference.getMaxUserCount();\n                    if (maxParticipants > 0) {\n                        if (logActivated) {\n                            sLogger.debug(\"Set max number of participants to \" + maxParticipants);\n                        }\n                        mSession.setMaxParticipants(maxParticipants);\n                    }\n\n                    Map<ContactId, ParticipantStatus> participants = new HashMap<ContactId, ParticipantStatus>();\n                    Vector<User> users = conference.getUsers();\n                    for (User user : users) {\n                        String phonenumber = user.getEntity();\n                        ContactId contact;\n                        PhoneNumber validPhoneNumber = ContactUtil\n                                .getValidPhoneNumberFromUri(phonenumber);\n                        if (validPhoneNumber != null) {\n                            contact = ContactUtil\n                                    .createContactIdFromValidatedData(validPhoneNumber);\n                        } else {\n                            // Invalid entity\n                            continue;\n                        }\n\n                        if (logActivated) {\n                            sLogger.debug(\"Conference info notification for \" + contact);\n                        }\n\n                        if (user.isMe()\n                                || contact.equals(ImsModule.getImsUserProfile().getUsername())) {\n                            // By-pass me\n                            continue;\n                        }\n\n                        if (logActivated) {\n                            sLogger.debug(\"User conference info: \" + user);\n                        }\n\n                        /*\n                         * Collect contact updates to be able to apply them in a one-shot operation\n                         * outside the loop.\n                         */\n                        participants.put(contact, getStatus(user));\n\n                    }\n\n                    if (!participants.isEmpty()) {\n                        updateParticipantStatus(participants, timestamp);\n                    }\n                }\n            } catch (ParserConfigurationException e) {\n                throw new PayloadException(\"Can't parse XML notification\", e);\n\n            } catch (SAXException e) {\n                throw new PayloadException(\"Can't parse XML notification\", e);\n\n            } catch (ParseFailureException e) {\n                throw new PayloadException(\"Can't parse XML notification\", e);\n            }\n        }\n\n        // Check subscription state\n        SubscriptionStateHeader stateHeader = (SubscriptionStateHeader) notify\n                .getHeader(SubscriptionStateHeader.NAME);\n        if ((stateHeader != null) && stateHeader.getState().equalsIgnoreCase(\"terminated\")) {\n            if (logActivated) {\n                sLogger.info(\"Conference event subscription has been terminated by server\");\n            }\n            terminatedByServer();\n        }\n    }\n\n    private void updateParticipantStatus(Map<ContactId, ParticipantStatus> participants,\n            long timestamp) {\n        Map<ContactId, ParticipantStatus> participantsToUpdate = mSession\n                .getParticipantsToUpdate(participants);\n\n        if (participantsToUpdate.isEmpty()) {\n            return;\n        }\n        Map<ContactId, GroupChatEvent.Status> groupChatEventsInDB = mMessagingLog\n                .getGroupChatEvents(mSession.getContributionID());\n\n        for (Map.Entry<ContactId, ParticipantStatus> participant : participantsToUpdate.entrySet()) {\n            ContactId contact = participant.getKey();\n            ParticipantStatus status = participant.getValue();\n            if (isGroupChatEventRequired(contact, status, groupChatEventsInDB))\n                for (ImsSessionListener listener : mSession.getListeners()) {\n                    ((GroupChatSessionListener) listener).onConferenceEventReceived(contact,\n                            status, timestamp);\n                }\n        }\n        mSession.updateParticipants(participantsToUpdate);\n    }\n\n    /*\n     * Check if a new group chat event is required. It is required if there was none before for this\n     * contact or if switch from JOINED to DEPARTED (or reverse) is detected.\n     */\n    private boolean isGroupChatEventRequired(ContactId contact, ParticipantStatus status,\n            Map<ContactId, Status> groupChatEvents) {\n        if (groupChatEvents == null) {\n            /* there is no group chat event in provider for the session */\n            return true;\n        }\n        if (!groupChatEvents.containsKey(contact)) {\n            /* there is no group chat event in provider for the contact */\n            return true;\n        }\n        GroupChatEvent.Status statusInDB = groupChatEvents.get(contact);\n\n        if (ParticipantStatus.CONNECTED == status) {\n            if (GroupChatEvent.Status.JOINED != statusInDB) {\n                /* Contact is not already marked as joined in provider */\n                return true;\n            }\n        } else if (ParticipantStatus.DEPARTED == status) {\n            if (GroupChatEvent.Status.DEPARTED != statusInDB) {\n                /* Contact is already marked as departed in provider */\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Check if the received notification if for this subscriber\n     * \n     * @param notify\n     * @return Boolean\n     */\n    public boolean isNotifyForThisSubscriber(SipRequest notify) {\n        boolean result = false;\n        if ((mDialogPath != null) && notify.getCallId().equals(mDialogPath.getCallId())) {\n            result = true;\n        }\n        return result;\n    }\n\n    /**\n     * Subscription has been terminated by server\n     */\n    public synchronized void terminatedByServer() {\n        if (!mSubscribed) {\n            // Already unsubscribed\n            return;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Subscription has been terminated by server\");\n        }\n\n        // Stop periodic subscription\n        stopTimer();\n\n        // Reset dialog path attributes\n        resetDialogPath();\n\n        // Force subscription flag to false\n        mSubscribed = false;\n    }\n\n    /**\n     * Terminate manager\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void terminate() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the subscribe manager\");\n        }\n\n        // Stop periodic subscription\n        stopTimer();\n\n        // Unsubscribe before to quit\n        if ((mImsModule.getCurrentNetworkInterface() != null)\n                && mImsModule.getCurrentNetworkInterface().isRegistered() && mSubscribed) {\n            unSubscribe();\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Subscribe manager is terminated\");\n        }\n    }\n\n    /**\n     * Create a SUBSCRIBE request\n     * \n     * @param dialog SIP dialog path\n     * @param expirePeriod Expiration period in milliseconds\n     * @return SIP request\n     * @throws PayloadException\n     */\n    private SipRequest createSubscribe(SipDialogPath dialog, long expirePeriod)\n            throws PayloadException {\n        try {\n            // Create SUBSCRIBE message\n            SipRequest subscribe = SipMessageFactory.createSubscribe(dialog, expirePeriod);\n\n            // Set feature tags\n            SipUtils.setFeatureTags(subscribe.getStackMessage(),\n                    InstantMessagingService.CHAT_FEATURE_TAGS);\n\n            // Set the Event header\n            subscribe.addHeader(\"Event\", \"conference\");\n\n            // Set the Accept header\n            subscribe.addHeader(\"Accept\", \"application/conference-info+xml\");\n\n            return subscribe;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\n                    \"Unable to form subscribe message with featureTags : \".concat(Arrays.asList(\n                            InstantMessagingService.CHAT_FEATURE_TAGS).toString()), e);\n        }\n    }\n\n    /**\n     * Subscription refresh processing\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void periodicProcessing() throws PayloadException, NetworkException {\n        // Make a subscribe\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Execute re-subscribe\");\n        }\n\n        // Send SUBSCRIBE request\n        subscribe();\n    }\n\n    /**\n     * Subscribe\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public synchronized void subscribe() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Subscribe to \" + getIdentity());\n        }\n        if (mDialogPath == null) {\n            String callId = mImsModule.getSipManager().getSipStack().generateCallId();\n\n            String target = getIdentity();\n\n            String localParty = ImsModule.getImsUserProfile().getPublicUri();\n\n            String remoteParty = getIdentity();\n\n            Vector<String> route = mImsModule.getSipManager().getSipStack().getServiceRoutePath();\n\n            mDialogPath = new SipDialogPath(mImsModule.getSipManager().getSipStack(), callId, 1,\n                    target, localParty, remoteParty, route, mRcsSettings);\n        } else {\n            mDialogPath.incrementCseq();\n        }\n\n        SipRequest subscribe = createSubscribe(mDialogPath, mExpirePeriod);\n\n        sendSubscribe(subscribe);\n    }\n\n    /**\n     * Unsubscribe\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public synchronized void unSubscribe() throws PayloadException, NetworkException {\n        if (!mSubscribed) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Unsubscribe to \".concat(getIdentity()));\n        }\n        stopTimer();\n        mDialogPath.incrementCseq();\n        /* Create a SUBSCRIBE with expire 0 */\n        SipRequest subscribe = createSubscribe(mDialogPath, 0);\n        sendSubscribe(subscribe);\n        mSubscribed = false;\n        resetDialogPath();\n    }\n\n    /**\n     * Reset the dialog path\n     */\n    private void resetDialogPath() {\n        if (mDialogPath != null) {\n            Core.getInstance().getImService()\n                    .removeGroupChatConferenceSubscriber(mDialogPath.getCallId());\n            mDialogPath = null;\n        }\n    }\n\n    /**\n     * Retrieve the expire period\n     * \n     * @param resp SIP response\n     */\n    private void retrieveExpirePeriod(SipResponse response) {\n        // Extract expire value from Expires header\n        ExpiresHeader expiresHeader = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME);\n        if (expiresHeader != null) {\n            int expires = expiresHeader.getExpires();\n            if (expires != -1) {\n                mExpirePeriod = expires * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            }\n        }\n    }\n\n    /**\n     * Send SUBSCRIBE message\n     * \n     * @param subscribe SIP SUBSCRIBE\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendSubscribe(SipRequest subscribe) throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(new StringBuilder(\"Send SUBSCRIBE, expire=\")\n                        .append(subscribe.getExpires()).append(\"ms\").toString());\n            }\n\n            if (mSubscribed) {\n                // Set the Authorization header\n                mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n            }\n\n            // Send SUBSCRIBE request\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSipMessageAndWait(subscribe);\n\n            // Analyze the received response\n            if (ctx.isSipResponse()) {\n                final int statusCode = ctx.getStatusCode();\n                switch (statusCode) {\n                    case Response.OK:\n                        if (subscribe.getExpires() != 0) {\n                            handle200OK(ctx);\n                        } else {\n                            handle200OkUnsubscribe(ctx);\n                        }\n                        break;\n                    case Response.ACCEPTED:\n                        handle200OK(ctx);\n                        break;\n                    case Response.PROXY_AUTHENTICATION_REQUIRED:\n                        handle407Authentication(ctx);\n                        break;\n                    case Response.INTERVAL_TOO_BRIEF:\n                        handle423IntervalTooBrief(ctx);\n                        break;\n                    default:\n                        handleError(new ChatError(ChatError.SUBSCRIBE_CONFERENCE_FAILED,\n                                new StringBuilder(String.valueOf(statusCode)).append(' ')\n                                        .append(ctx.getReasonPhrase()).toString()));\n                        break;\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No response received for SUBSCRIBE\");\n                }\n\n                // No response received: timeout\n                handleError(new ChatError(ChatError.SUBSCRIBE_CONFERENCE_FAILED));\n            }\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Unable to set authorization header for subscribe!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Unable to set authorization header for subscribe!\", e);\n        }\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OK(SipTransactionContext ctx) {\n        // 200 OK response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n        mSubscribed = true;\n\n        SipResponse resp = ctx.getSipResponse();\n\n        // Set the route path with the Record-Route header\n        Vector<String> newRoute = SipUtils.routeProcessing(resp, true);\n        mDialogPath.setRoute(newRoute);\n\n        // Set the remote tag\n        mDialogPath.setRemoteTag(resp.getToTag());\n\n        // Set the target\n        mDialogPath.setTarget(resp.getContactURI());\n\n        // Set the Proxy-Authorization header\n        mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n\n        // Retrieve the expire value in the response\n        retrieveExpirePeriod(resp);\n\n        // Start the periodic subscribe\n        startTimer(System.currentTimeMillis(), mExpirePeriod, 0.5);\n\n        Core.getInstance().getImService()\n                .addGroupChatConferenceSubscriber(mDialogPath.getCallId(), mSession);\n    }\n\n    /**\n     * Handle 200 0K response of UNSUBSCRIBE\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OkUnsubscribe(SipTransactionContext ctx) {\n        // 200 OK response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n    }\n\n    /**\n     * Handle 407 response\n     * \n     * @param ctx SIP transaction context\n     * @throws InvalidArgumentException\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle407Authentication(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"407 response received\");\n            }\n\n            SipResponse resp = ctx.getSipResponse();\n            mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n            mDialogPath.incrementCseq();\n\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send second SUBSCRIBE\");\n            }\n            SipRequest subscribe = createSubscribe(mDialogPath, ctx.getTransaction().getRequest()\n                    .getExpires().getExpires()\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n\n            mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n            sendSubscribe(subscribe);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n        }\n    }\n\n    /**\n     * Handle 423 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle423IntervalTooBrief(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"423 interval too brief response received\");\n            }\n\n            SipResponse resp = ctx.getSipResponse();\n            mDialogPath.incrementCseq();\n\n            long minExpire = SipUtils.getMinExpiresPeriod(resp);\n            if (minExpire == -1) {\n                if (sLogger.isActivated()) {\n                    sLogger.error(\"Can't read the Min-Expires value\");\n                }\n                handleError(new ChatError(ChatError.SUBSCRIBE_CONFERENCE_FAILED,\n                        \"No Min-Expires value found\"));\n                return;\n            }\n\n            RegistryFactory.getFactory().writeLong(REGISTRY_MIN_EXPIRE_PERIOD, minExpire);\n\n            mExpirePeriod = minExpire;\n\n            SipRequest subscribe = createSubscribe(mDialogPath, mExpirePeriod);\n\n            mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n\n            sendSubscribe(subscribe);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Failed to handle interval too brief response!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to handle interval too brief response!\", e);\n        }\n    }\n\n    /**\n     * Handle error response\n     * \n     * @param error Error\n     */\n    private void handleError(ChatError error) {\n        // Error\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Subscribe has failed: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        mSubscribed = false;\n\n        // Subscribe has failed, stop the periodic subscribe\n        stopTimer();\n\n        // Reset dialog path attributes\n        resetDialogPath();\n    }\n\n    /**\n     * Convert the user status into integer\n     * \n     * @param user the user\n     * @return the integer status\n     */\n    private static ParticipantStatus getStatus(User user) {\n        String state = user.getState();\n        /*\n         * Manage \"pending-out\" and \"pending-in\" status like \"pending\" status. See RFC 4575\n         * dialing-in: Endpoint is dialing into the conference, not yet in the roster (probably\n         * being authenticated). dialing-out: Focus has dialed out to connect the endpoint to the\n         * conference, but the endpoint is not yet in the roster (probably being authenticated).\n         */\n        if (\"dialing-out\".equalsIgnoreCase(state)) {\n            return ParticipantStatus.INVITED;\n\n        } else if (\"dialing-in\".equalsIgnoreCase(state)) {\n            return ParticipantStatus.INVITED;\n\n        } else if (User.STATE_DISCONNECTED.equals(state)) {\n            /*\n             * For the disconnected state, override state with the more detailed\n             * disconnection-method field (if available).\n             */\n            String disconnectionMethod = user.getDisconnectionMethod();\n            if (disconnectionMethod != null) {\n                /* Detect declined by remote from failure-reason field. */\n                if (User.STATE_FAILED.equals(disconnectionMethod)) {\n                    String reason = user.getFailureReason();\n                    if ((reason != null) && reason.contains(\"603\")) {\n                        return ParticipantStatus.DECLINED;\n                    }\n                }\n                return getStatus(disconnectionMethod);\n            }\n        }\n        return getStatus(state);\n    }\n\n    /**\n     * Convert the status into integer\n     * \n     * @param status the string status\n     * @return the integer status\n     */\n    private static ParticipantStatus getStatus(final String status) {\n        if (User.STATE_CONNECTED.equals(status)) {\n            return ParticipantStatus.CONNECTED;\n\n        } else if (User.STATE_DISCONNECTED.equals(status)) {\n            return ParticipantStatus.DISCONNECTED;\n\n        } else if (User.STATE_DEPARTED.equals(status)) {\n            return ParticipantStatus.DEPARTED;\n\n        } else if (User.STATE_BOOTED.equals(status)) {\n            return ParticipantStatus.DISCONNECTED;\n\n        } else if (User.STATE_FAILED.equals(status)) {\n            return ParticipantStatus.FAILED;\n\n        } else if (User.STATE_BUSY.equals(status)) {\n            return ParticipantStatus.DISCONNECTED;\n\n        } else if (User.STATE_DECLINED.equals(status)) {\n            return ParticipantStatus.DECLINED;\n\n        } else if (User.STATE_PENDING.equals(status)) {\n            return ParticipantStatus.INVITED;\n        }\n        throw new IllegalArgumentException(new StringBuilder(\"Unknown status \").append(status)\n                .append(\" passed to getStatus!\").toString());\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/event/ConferenceInfoDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.event;\n\nimport java.util.Vector;\n\n/**\n * Conference-Info document\n * \n * @author jexa7410\n */\npublic class ConferenceInfoDocument {\n    /**\n     * State values\n     */\n    public final static String STATE_PARTIAL = \"partial\";\n    public final static String STATE_FULL = \"full\";\n    public final static String STATE_DELETED = \"deleted\";\n\n    /**\n     * Conference URI\n     */\n    private String entity;\n\n    /**\n     * State attribute\n     */\n    private String state;\n\n    /**\n     * List of users\n     */\n    private Vector<User> users = new Vector<User>();\n\n    /**\n     * Maximum number of participants for the chat session\n     */\n    private int maxUserCount = 0;\n\n    /**\n     * Current number of participants in the chat session\n     */\n    private int userCount = 0;\n\n    /**\n     * Constructor\n     * \n     * @param entity Conference URI\n     * @param state State attribute\n     */\n    public ConferenceInfoDocument(String entity, String state) {\n        this.entity = entity;\n        this.state = state;\n    }\n\n    /**\n     * Return the conference URI\n     * \n     * @return Conference URI\n     */\n    public String getEntity() {\n        return entity;\n    }\n\n    /**\n     * Reeturn the state\n     * \n     * @return State\n     */\n    public String getState() {\n        return state;\n    }\n\n    /**\n     * Add a user\n     * \n     * @param user User\n     */\n    public void addUser(User user) {\n        users.addElement(user);\n    }\n\n    /**\n     * Get the list of users\n     * \n     * @return List of users\n     */\n    public Vector<User> getUsers() {\n        return users;\n    }\n\n    /**\n     * Get the maximum user count\n     * \n     * @return Max user count or 0 if not contained in the conference info\n     */\n    public int getMaxUserCount() {\n        return maxUserCount;\n    }\n\n    /**\n     * Set the maximum user count\n     * \n     * @param maxUserCount Max user to set\n     */\n    public void setMaxUserCount(int maxUserCount) {\n        this.maxUserCount = maxUserCount;\n    }\n\n    /**\n     * Get the user count\n     * \n     * @return User count or 0 if not contained in the conference info\n     */\n    public int getUserCount() {\n        return userCount;\n    }\n\n    /**\n     * Set the user count\n     * \n     * @param userCount User count\n     */\n    public void setUserCount(int userCount) {\n        this.userCount = userCount;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/event/ConferenceInfoParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.event;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Conference-Info parser\n * \n * @author jexa7410\n */\npublic class ConferenceInfoParser extends DefaultHandler {\n\n    /*\n     * Conference-Info SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <conference-info\n     * xmlns=\"urn:ietf:params:xml:ns:conference-info\" entity=\"sips:conf233@example.com\" state=\"full\"\n     * version=\"1\"> <!-- CONFERENCE INFO --> <conference-description> <subject>Agenda: This month's\n     * goals</subject> <service-uris> <entry> <uri>http://sharepoint/salesgroup/</uri>\n     * <purpose>web-page</purpose> </entry> </service-uris>\n     * <maximum-user-count>50</maximum-user-count> </conference-description> <!-- CONFERENCE STATE\n     * --> <conference-state> <user-count>33</user-count> </conference-state> <!-- USERS --> <users>\n     * <!-- USER 1 --> <user entity=\"sip:bob@example.com\" state=\"full\"> <display-text>Bob\n     * Hoskins</display-text> <!-- ENDPOINTS --> <endpoint entity=\"sip:bob@pc33.example.com\">\n     * <display-text>Bob's Laptop</display-text> <status>disconnected</status>\n     * <disconnection-method>departed</disconnection-method> <disconnection-info>\n     * <when>2005-03-04T20:00:00Z</when> <reason>bad voice quality</reason>\n     * <by>sip:mike@example.com</by> </disconnection-info> <!-- MEDIA --> <media id=\"1\">\n     * <display-text>main audio</display-text> <type>audio</type> <label>34567</label>\n     * <src-id>432424</src-id> <status>sendrecv</status> </media> </endpoint> </user> <!-- USER 2\n     * --> <user entity=\"sip:alice@example.com\" state=\"full\"> <display-text>Alice</display-text>\n     * <!-- ENDPOINTS --> <endpoint entity=\"sip:4kfk4j392jsu@example.com;grid=433kj4j3u\">\n     * <status>connected</status> <joining-method>dialed-out</joining-method> <joining-info>\n     * <when>2005-03-04T20:00:00Z</when> <by>sip:mike@example.com</by> </joining-info> <!-- MEDIA\n     * --> <media id=\"1\"> <display-text>main audio</display-text> <type>audio</type>\n     * <label>34567</label> <src-id>534232</src-id> <status>sendrecv</status> </media> </endpoint>\n     * </user> </users> </conference-info>\n     */\n\n    private StringBuffer mAccumulator;\n\n    private ConferenceInfoDocument mConference;\n\n    private String mEntity;\n\n    private boolean mMe;\n\n    private String mStatus;\n\n    private String mDisplayName;\n\n    private String mDisconnectionMethod;\n\n    private String mFailureReason;\n\n    private static final Logger sLogger = Logger.getLogger(ConferenceInfoParser.class.getName());\n\n    private final InputSource mInputSource;\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public ConferenceInfoParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the Conference info input\n     * \n     * @return ConferenceInfoParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public ConferenceInfoParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public ConferenceInfoDocument getConferenceInfo() {\n        return mConference;\n    }\n\n    @Override\n    public void startDocument() {\n        mAccumulator = new StringBuffer();\n    }\n\n    @Override\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    @Override\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n        if (localName.equals(\"conference-info\")) {\n            String entity = attr.getValue(\"entity\").trim();\n            String state = attr.getValue(\"state\").trim();\n            mConference = new ConferenceInfoDocument(entity, state);\n\n        } else if (localName.equals(\"user\")) {\n            mEntity = attr.getValue(\"entity\").trim();\n            String yourown = attr.getValue(\"yourown\");\n            mMe = false;\n            mStatus = null;\n            mDisplayName = null;\n            mDisconnectionMethod = null;\n            mFailureReason = null;\n            if (yourown != null) {\n                mMe = Boolean.parseBoolean(yourown);\n            }\n        }\n    }\n\n    @Override\n    public void endElement(String namespaceURL, String localName, String qname) {\n        switch (localName) {\n            case \"user\":\n                if (mConference != null) {\n                    User user = new User(mEntity, mMe, mStatus, mDisplayName, mDisconnectionMethod,\n                            mFailureReason);\n                    mConference.addUser(user);\n                }\n                break;\n            case \"display-text\":\n                mDisplayName = mAccumulator.toString().trim();\n                break;\n            case \"status\":\n                mStatus = mAccumulator.toString().trim();\n                break;\n            case \"maximum-user-count\":\n                if (mConference != null) {\n                    mConference.setMaxUserCount(Integer.parseInt(mAccumulator.toString().trim()));\n                }\n                break;\n            case \"user-count\":\n                if (mConference != null) {\n                    mConference.setUserCount(Integer.parseInt(mAccumulator.toString().trim()));\n                }\n                break;\n            case \"conference-info\":\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Conference-Info document complete\");\n                }\n                break;\n            case \"disconnection-method\":\n                mDisconnectionMethod = mAccumulator.toString().trim();\n                break;\n            case \"reason\":\n                mFailureReason = mAccumulator.toString().trim();\n                break;\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/event/User.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.event;\n\n/**\n * @author YPLO6403\n */\npublic class User {\n\n    public final static String STATE_CONNECTED = \"connected\";\n\n    public final static String STATE_DISCONNECTED = \"disconnected\";\n\n    public final static String STATE_DEPARTED = \"departed\";\n\n    public final static String STATE_BOOTED = \"booted\";\n\n    public final static String STATE_FAILED = \"failed\";\n\n    public final static String STATE_BUSY = \"busy\";\n\n    public final static String STATE_DECLINED = \"declined\";\n\n    public final static String STATE_PENDING = \"pending\";\n\n    private final String mEntity;\n\n    private final boolean mMe;\n\n    private final String mState;\n\n    private final String mDisplayName;\n\n    private final String mDisconnectionMethod;\n\n    private final String mFailureReason;\n\n    public User(String entity, boolean me, String state, String displayName,\n            String disconnectionMethod, String failureReason) {\n        mEntity = entity;\n        mMe = me;\n        mState = state;\n        mDisplayName = displayName;\n        mDisconnectionMethod = disconnectionMethod;\n        mFailureReason = failureReason;\n    }\n\n    public String getEntity() {\n        return mEntity;\n    }\n\n    public boolean isMe() {\n        return mMe;\n    }\n\n    public String getState() {\n        return mState;\n    }\n\n    public String getDisplayName() {\n        return mDisplayName;\n    }\n\n    public String getDisconnectionMethod() {\n        return mDisconnectionMethod;\n    }\n\n    public String getFailureReason() {\n        return mFailureReason;\n    }\n\n    public String toString() {\n        StringBuilder result = new StringBuilder(\"user=\").append(mEntity).append(\", state=\")\n                .append(mState);\n        if (mDisconnectionMethod != null) {\n            result.append(\", method=\").append(mDisconnectionMethod);\n        }\n        if (mFailureReason != null) {\n            result.append(\", reason=\").append(mFailureReason);\n        }\n        return result.toString();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/geoloc/GeolocInfoDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.geoloc;\n\n/**\n * Geolocation info document\n * \n * @author vfml3370\n */\npublic class GeolocInfoDocument {\n    /**\n     * MIME type\n     */\n    public static final String MIME_TYPE = \"application/vnd.gsma.rcspushlocation+xml\";\n\n    /**\n     * Entity\n     */\n    private String entity = null;\n\n    /**\n     * Label\n     */\n    private String label = null;\n\n    /**\n     * Latitude\n     */\n    private double latitude = 0;\n\n    /**\n     * Longitude\n     */\n    private double longitude = 0;\n\n    /**\n     * Expiration date\n     */\n    private long expiration = 0;\n\n    /**\n     * Radius in meters\n     */\n    private float radius = 0;\n\n    /**\n     * Constructor\n     * \n     * @param entity Entity\n     */\n    public GeolocInfoDocument(String entity) {\n        this.entity = entity;\n    }\n\n    public String getLabel() {\n        return label;\n    }\n\n    public void setLabel(String label) {\n        this.label = label;\n    }\n\n    public String getEntity() {\n        return entity;\n    }\n\n    public void setEntity(String entity) {\n        this.entity = entity;\n    }\n\n    public long getExpiration() {\n        return expiration;\n    }\n\n    public void setExpiration(long expiration) {\n        this.expiration = expiration;\n    }\n\n    public double getLatitude() {\n        return latitude;\n    }\n\n    public void setLatitude(double l) {\n        latitude = l;\n    }\n\n    public double getLongitude() {\n        return longitude;\n    }\n\n    public void setLongitude(double l) {\n        longitude = l;\n    }\n\n    public float getRadius() {\n        return radius;\n    }\n\n    public void setRadius(float r) {\n        radius = r;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/geoloc/GeolocInfoParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.geoloc;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\nimport java.util.StringTokenizer;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Geolocation info parser\n * \n * @author vfml3370\n */\npublic class GeolocInfoParser extends DefaultHandler {\n\n    /*\n     * Geoloc-Info SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <rcsenvelope\n     * xmlns=\"urn:gsma:params:xml:ns:rcs:rcs:geolocation\"\n     * xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\"\n     * xmlns:gp=\"urn:ietf:params:xml:ns:pidf:geopriv10\" xmlns:gml=\"http://www.opengis.net/gml\"\n     * xmlns:gs=\"http://www.opengis.net/pidflo/1.0\" entity=\"tel:+12345678901\"> <rcspushlocation\n     * id=\"a123\" label =\"meeting location\" > <rpid:place-type\n     * rpid:until=\"2012-03-15T21:00:00-05:00\"> </rpid:place-type> <rpid:time-offset\n     * rpid:until=\"2012-03-15T21:00:00-05:00\"></rpid:time-offset> <gp:geopriv> <gp:location-info>\n     * <gs:Circle srsName=\"urn:ogc:def:crs:EPSG::4326\"> <gml:pos>48.731964 -3.45829</gml:pos>\n     * <gs:radius uom=\"urn:ogc:def:uom:EPSG::9001\">10</gs:radius> </gs:Circle> </gp:location-info>\n     * <gp:usage-rules> <gp:retention-expiry>2012-03-15T21:00:00-05:00</gp:retention-expiry>\n     * </gp:usage-rules> </gp:geopriv> <timestamp>2012-03-15T16:09:44-05:00</timestamp>\n     * </rcspushlocation> </rcsenvelope>\n     */\n\n    private StringBuilder mAccumulator;\n    private GeolocInfoDocument mGeoloc;\n    private static Logger sLogger = Logger.getLogger(GeolocInfoParser.class.getName());\n    private final InputSource mInputSource;\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public GeolocInfoParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the PIDF input\n     * \n     * @return GeolocInfoParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public GeolocInfoParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public GeolocInfoDocument getGeoLocInfo() {\n        return mGeoloc;\n    }\n\n    @Override\n    public void startDocument() {\n        mAccumulator = new StringBuilder();\n    }\n\n    @Override\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    @Override\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n        if (\"rcsenvelope\".equals(localName)) {\n            String entity = attr.getValue(\"entity\").trim();\n            mGeoloc = new GeolocInfoDocument(entity);\n\n        } else if (\"rcspushlocation\".equals(localName)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"rcspushlocation\");\n            }\n            if (mGeoloc != null) {\n                String label = attr.getValue(\"label\").trim();\n                mGeoloc.setLabel(label);\n            }\n        }\n    }\n\n    @Override\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (\"radius\".equals(localName)) {\n            if (mGeoloc != null) {\n                mGeoloc.setRadius(Float.parseFloat(mAccumulator.toString().trim()));\n            }\n\n        } else if (\"retention-expiry\".equals(localName)) {\n            if (mGeoloc != null) {\n                mGeoloc.setExpiration(DateUtils.decodeDate(mAccumulator.toString().trim()));\n            }\n\n        } else if (\"pos\".equals(localName)) {\n            if (mGeoloc != null) {\n                StringTokenizer st = new StringTokenizer(mAccumulator.toString().trim());\n                if (st.hasMoreTokens()) {\n                    mGeoloc.setLatitude(Double.parseDouble(st.nextToken()));\n                }\n                if (st.hasMoreTokens()) {\n                    mGeoloc.setLongitude(Double.parseDouble(st.nextToken()));\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/imdn/DeliveryExpirationManager.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.service.im.chat.imdn;\n\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.service.api.OneToOneDeliveryExpirationService;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.TimerUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.OneToOneChatIntent;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Parcelable;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class DeliveryExpirationManager {\n\n    public static final String ACTION_CHAT_MESSAGE_DELIVERY_TIMEOUT = \"com.gsma.rcs.action.ONE_TO_ONE_CHAT_MESSAGE_DELIVERY_TIMEOUT\";\n\n    public static final String ACTION_FILE_TRANSFER_DELIVERY_TIMEOUT = \"com.gsma.rcs.action.ONE_TO_ONE_FILE_TRANSFER_DELIVERY_TIMEOUT\";\n\n    private static final String EXTRA_ID = \"id\";\n\n    private static final String EXTRA_CONTACT = \"contact\";\n\n    private final Map<String, PendingIntent> mUndeliveredImAlarms = new HashMap<String, PendingIntent>();\n\n    private final AlarmManager mAlarmManager;\n\n    private final Context mCtx;\n\n    private final MessagingLog mMessagingLog;\n\n    private final InstantMessagingService mImService;\n\n    private static final Logger sLogger = Logger.getLogger(DeliveryExpirationManager.class\n            .getSimpleName());\n\n    public DeliveryExpirationManager(InstantMessagingService imService, Context ctx,\n            MessagingLog messagingLog) {\n        mCtx = ctx;\n        mMessagingLog = messagingLog;\n        mImService = imService;\n        mAlarmManager = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);\n    }\n\n    private void cancelTimeOutAlarm(PendingIntent pendingIntent) {\n        mAlarmManager.cancel(pendingIntent);\n    }\n\n    public void cleanup() {\n        synchronized (mUndeliveredImAlarms) {\n            for (String msgId : mUndeliveredImAlarms.keySet()) {\n                cancelTimeOutAlarm(mUndeliveredImAlarms.get(msgId));\n            }\n            mUndeliveredImAlarms.clear();\n        }\n    }\n\n    private PendingIntent createUndeliveredChatMessagePendingIntent(ContactId contact, String msgId) {\n        Intent undeliveredMessage = new Intent(mCtx, OneToOneDeliveryExpirationService.class);\n        undeliveredMessage.setAction(ACTION_CHAT_MESSAGE_DELIVERY_TIMEOUT);\n        undeliveredMessage.putExtra(EXTRA_ID, msgId);\n        /*\n         * Passing contact as a string due to issues in deserializing parcelable extra from the\n         * PendingIntent\n         */\n        undeliveredMessage.putExtra(EXTRA_CONTACT, contact.toString());\n        undeliveredMessage.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(undeliveredMessage);\n        int requestCode = msgId.hashCode();\n        return PendingIntent.getService(mCtx, requestCode, undeliveredMessage,\n                PendingIntent.FLAG_ONE_SHOT);\n    }\n\n    private PendingIntent createUndeliveredFileTransferPendingIntent(ContactId contact, String msgId) {\n        Intent undeliveredFile = new Intent(mCtx, OneToOneDeliveryExpirationService.class);\n        undeliveredFile.setAction(ACTION_FILE_TRANSFER_DELIVERY_TIMEOUT);\n        undeliveredFile.putExtra(EXTRA_ID, msgId);\n        /*\n         * Passing contact as a string due to issues in deserializing parcelable extra from the\n         * PendingIntent\n         */\n        undeliveredFile.putExtra(EXTRA_CONTACT, contact.toString());\n        undeliveredFile.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(undeliveredFile);\n        int requestCode = msgId.hashCode();\n        return PendingIntent.getService(mCtx, requestCode, undeliveredFile,\n                PendingIntent.FLAG_ONE_SHOT);\n    }\n\n    private void scheduleDeliveryTimeoutAlarm(String id, long triggerTime,\n            PendingIntent undeliveredIntent) {\n        synchronized (mUndeliveredImAlarms) {\n            if (!mUndeliveredImAlarms.containsKey(id)) {\n                mUndeliveredImAlarms.put(id, undeliveredIntent);\n                TimerUtils.setExactTimer(mAlarmManager, triggerTime, undeliveredIntent);\n            }\n        }\n    }\n\n    public void cancelDeliveryTimeoutAlarm(String id) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Cancel delivery expiration timer for Id \".concat(id));\n        }\n        synchronized (mUndeliveredImAlarms) {\n            PendingIntent undeliveredMessageAlarm = mUndeliveredImAlarms.remove(id);\n            if (undeliveredMessageAlarm != null) {\n                cancelTimeOutAlarm(undeliveredMessageAlarm);\n            }\n        }\n    }\n\n    public void scheduleOneToOneChatMessageDeliveryTimeoutAlarm(ContactId contact, String msgId,\n            long triggerTime) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Schedule delivery expiration timer for message with msgId \"\n                    .concat(msgId));\n        }\n        scheduleDeliveryTimeoutAlarm(msgId, triggerTime,\n                createUndeliveredChatMessagePendingIntent(contact, msgId));\n    }\n\n    public void scheduleOneToOneFileTransferDeliveryTimeoutAlarm(ContactId contact,\n            String fileTransferId, long triggerTime) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Schedule delivery expiration timer for file with fileTransferId \"\n                    .concat(fileTransferId));\n        }\n        scheduleDeliveryTimeoutAlarm(fileTransferId, triggerTime,\n                createUndeliveredFileTransferPendingIntent(contact, fileTransferId));\n    }\n\n    public void onChatMessageDeliveryExpirationReceived(ContactId contact, String msgId) {\n        cancelDeliveryTimeoutAlarm(msgId);\n        mMessagingLog.setChatMessageDeliveryExpired(msgId);\n        mImService.getImsModule().getCapabilityService().requestContactCapabilities(contact);\n\n        Intent undeliveredMessage = new Intent(OneToOneChatIntent.ACTION_MESSAGE_DELIVERY_EXPIRED);\n        undeliveredMessage.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(undeliveredMessage);\n        undeliveredMessage.putExtra(OneToOneChatIntent.EXTRA_CONTACT, (Parcelable) contact);\n        undeliveredMessage.putExtra(OneToOneChatIntent.EXTRA_MESSAGE_ID, msgId);\n        mCtx.sendBroadcast(undeliveredMessage);\n    }\n\n    public void onFileTransferDeliveryExpirationReceived(ContactId contact, String fileTransferId) {\n        cancelDeliveryTimeoutAlarm(fileTransferId);\n        mMessagingLog.setFileTransferDeliveryExpired(fileTransferId);\n        mImService.getImsModule().getCapabilityService().requestContactCapabilities(contact);\n\n        Intent undeliveredFile = new Intent(\n                FileTransferIntent.ACTION_FILE_TRANSFER_DELIVERY_EXPIRED);\n        undeliveredFile.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(undeliveredFile);\n        undeliveredFile.putExtra(FileTransferIntent.EXTRA_CONTACT, (Parcelable) contact);\n        undeliveredFile.putExtra(FileTransferIntent.EXTRA_TRANSFER_ID, fileTransferId);\n        mCtx.sendBroadcast(undeliveredFile);\n    }\n\n    /**\n     * Handle one-one chat message delivery expiration\n     *\n     * @param intent\n     */\n    public void onChatMessageDeliveryExpirationReceived(Intent intent) {\n        ContactId contact = ContactUtil.createContactIdFromTrustedData(intent\n                .getStringExtra(EXTRA_CONTACT));\n        String msgId = intent.getStringExtra(EXTRA_ID);\n        onChatMessageDeliveryExpirationReceived(contact, msgId);\n    }\n\n    /**\n     * Handle one-one file transfer delivery expiration\n     *\n     * @param intent\n     */\n    public void onFileTransferDeliveryExpirationReceived(Intent intent) {\n        ContactId contact = ContactUtil.createContactIdFromTrustedData(intent\n                .getStringExtra(EXTRA_CONTACT));\n        String fileTransferId = intent.getStringExtra(EXTRA_ID);\n        onFileTransferDeliveryExpirationReceived(contact, fileTransferId);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/imdn/ImdnDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.imdn;\n\n/**\n * IMDN document\n *\n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic class ImdnDocument {\n    /**\n     * MIME type\n     */\n    public static final String MIME_TYPE = \"message/imdn+xml\";\n\n    /**\n     * Imdn tag indicating delivery notification\n     */\n    public static final String DELIVERY_NOTIFICATION = \"delivery-notification\";\n\n    /**\n     * Imdn tag indicating display notification\n     */\n    public static final String DISPLAY_NOTIFICATION = \"display-notification\";\n\n    public enum DeliveryStatus {\n        DELIVERED(\"delivered\"), DISPLAYED(\"displayed\"), FAILED(\"failed\"), ERROR(\"error\"), FORBIDDEN(\n                \"forbidden\");\n\n        private final String mName;\n\n        DeliveryStatus(String name) {\n            mName = name;\n        }\n\n        public boolean equalsName(String otherName) {\n            return (otherName != null) && mName.equals(otherName);\n        }\n\n        public String toString() {\n            return mName;\n        }\n    }\n\n    public static final String MESSAGE_ID_TAG = \"message-id\";\n\n    public static final String IMDN_DATETIME = \"datetime\";\n\n    public static final String IMDN_NAMESPACE = \"imdn <urn:ietf:params:imdn>\";\n\n    public static final int IMDN_DATETIME_NOT_SET = 0;\n\n    /**\n     * Disposition notification header positive delivery value\n     */\n    public static final String POSITIVE_DELIVERY = \"positive-delivery\";\n\n    /**\n     * Disposition notification header display value\n     */\n    public static final String DISPLAY = \"display\";\n\n    /**\n     * Content-Disposition header notification value\n     */\n    public static final String NOTIFICATION = \"notification\";\n\n    private final String mMsgId;\n\n    private final DeliveryStatus mStatus;\n\n    private final String mNotificationType;\n\n    private final long mDateTime;\n\n    public ImdnDocument(String msgId, String notificationType, DeliveryStatus status, long dateTime) {\n        mMsgId = msgId;\n        mNotificationType = notificationType;\n        mStatus = status;\n        mDateTime = dateTime;\n    }\n\n    /**\n     * Get message ID\n     *\n     * @return Message ID\n     */\n    public String getMsgId() {\n        return mMsgId;\n    }\n\n    /**\n     * Get status\n     *\n     * @return Status\n     */\n    public DeliveryStatus getStatus() {\n        return mStatus;\n    }\n\n    /**\n     * Get notification type\n     *\n     * @return Notification type\n     */\n    public String getNotificationType() {\n        return mNotificationType;\n    }\n\n    /**\n     * Get DateTime\n     *\n     * @return DateTime\n     */\n    public long getDateTime() {\n        return mDateTime;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/imdn/ImdnManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.imdn;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.FifoBuffer;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * IMDN manager (see RFC5438)\n * \n * @author jexa7410\n */\npublic class ImdnManager extends Thread {\n\n    private final InstantMessagingService mImService;\n    private final MessagingLog mMessagingLog;\n    private FifoBuffer mBuffer = new FifoBuffer();\n    private final RcsSettings mRcsSettings;\n    private final static Logger sLogger = Logger.getLogger(ImdnManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param imService IM service\n     * @param rcsSettings the RCS settings accessor\n     * @param messagingLog the messaging log accessor\n     */\n    public ImdnManager(InstantMessagingService imService, RcsSettings rcsSettings,\n            MessagingLog messagingLog) {\n        mImService = imService;\n        mRcsSettings = rcsSettings;\n        mMessagingLog = messagingLog;\n    }\n\n    /**\n     * Terminate manager\n     */\n    public void terminate() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the IMDN manager\");\n        }\n        mBuffer.close();\n    }\n\n    /**\n     * Should we request and send delivery delivered reports\n     */\n    public boolean isDeliveryDeliveredReportsEnabled() {\n        return mRcsSettings.isImReportsActivated();\n    }\n\n    /**\n     * Should we send one to one delivery displayed reports\n     */\n    public boolean isSendOneToOneDeliveryDisplayedReportsEnabled() {\n        return mRcsSettings.isImReportsActivated() && !mRcsSettings.isAlbatrosRelease()\n                && mRcsSettings.isRespondToDisplayReports();\n    }\n\n    /**\n     * Should we request one to one delivery displayed reports\n     */\n    public boolean isRequestOneToOneDeliveryDisplayedReportsEnabled() {\n        return mRcsSettings.isImReportsActivated() && !mRcsSettings.isAlbatrosRelease();\n    }\n\n    /**\n     * Should we send group delivery displayed reports\n     */\n    public boolean isSendGroupDeliveryDisplayedReportsEnabled() {\n        return mRcsSettings.isImReportsActivated() && !mRcsSettings.isAlbatrosRelease()\n                && mRcsSettings.isRespondToDisplayReports()\n                && mRcsSettings.isRequestAndRespondToGroupDisplayReportsEnabled();\n    }\n\n    /**\n     * Should we send group delivery displayed reports\n     */\n    public boolean isRequestGroupDeliveryDisplayedReportsEnabled() {\n        return mRcsSettings.isImReportsActivated() && !mRcsSettings.isAlbatrosRelease()\n                && mRcsSettings.isRequestAndRespondToGroupDisplayReportsEnabled();\n    }\n\n    @Override\n    public void run() {\n        DeliveryStatus delivery;\n        while ((delivery = (DeliveryStatus) mBuffer.getObject()) != null) {\n            try {\n                boolean imdnDisplay = ImdnDocument.DeliveryStatus.DISPLAYED == delivery.getStatus();\n                String msgId = delivery.getMsgId();\n                if (imdnDisplay) {\n                    /*\n                     * Display notification are processed asynchronously from the server API.\n                     * Therefore the IMDN message may have already been processed. Here we need to\n                     * check if the Display Report is still requested.\n                     */\n                    ChatLog.Message.Content.Status status = mMessagingLog.getMessageStatus(msgId);\n                    if (ChatLog.Message.Content.Status.DISPLAY_REPORT_REQUESTED != status) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Display report for ID: \" + msgId + \" already processed!\");\n                        }\n                        continue;\n                    }\n                }\n                sendSipMessageDeliveryStatus(delivery, null); // TODO: add sip.instance\n                /*\n                 * Update rich messaging history when sending DISPLAYED report Since the requested\n                 * display report was now successfully send we mark this message as fully received\n                 */\n                if (imdnDisplay) {\n                    mImService.onChatMessageDisplayReportSent(delivery.getChatId(),\n                            delivery.getRemote(), msgId);\n                }\n            } catch (PayloadException | RuntimeException e) {\n                sLogger.error(\"Failed to send delivery status for chatId: \" + delivery.getChatId(),\n                        e);\n\n            } catch (NetworkException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            }\n        }\n    }\n\n    /**\n     * Send a message delivery status\n     * \n     * @param chatId ChatId\n     * @param remote the remote contact\n     * @param msgId Message ID\n     * @param status Delivery status\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     */\n    public void sendMessageDeliveryStatus(String chatId, ContactId remote, String msgId,\n            ImdnDocument.DeliveryStatus status, long timestamp) {\n        // Add request in the buffer for background processing\n        DeliveryStatus delivery = new DeliveryStatus(chatId, remote, msgId, status, timestamp);\n        mBuffer.addObject(delivery);\n    }\n\n    /**\n     * Send a message delivery status immediately\n     * \n     * @param chatId ChatId when targeting a group chat message, otherwise null\n     * @param remote Remote contact\n     * @param msgId Message ID\n     * @param status Delivery status\n     * @param remoteInstanceId the remote instance ID\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void sendMessageDeliveryStatusImmediately(String chatId, ContactId remote, String msgId,\n            ImdnDocument.DeliveryStatus status, final String remoteInstanceId, long timestamp)\n            throws PayloadException, NetworkException {\n        // Execute request in background\n        final DeliveryStatus delivery = new DeliveryStatus(chatId, remote, msgId, status, timestamp);\n        sendSipMessageDeliveryStatus(delivery, remoteInstanceId);\n    }\n\n    private void analyzeSipResponse(SipTransactionContext ctx,\n            SessionAuthenticationAgent authenticationAgent, SipDialogPath dialogPath, String cpim)\n            throws NetworkException, PayloadException, InvalidArgumentException, ParseException {\n        int statusCode = ctx.getStatusCode();\n        switch (statusCode) {\n            case Response.PROXY_AUTHENTICATION_REQUIRED:\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"407 response received\");\n                }\n                /* Set the Proxy-Authorization header */\n                authenticationAgent.readProxyAuthenticateHeader(ctx.getSipResponse());\n                /* Increment the Cseq number of the dialog path */\n                dialogPath.incrementCseq();\n                /* Create a second MESSAGE request with the right token */\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Send second MESSAGE\");\n                }\n                SipRequest msg = SipMessageFactory.createMessage(dialogPath,\n                        FeatureTags.FEATURE_OMA_IM, CpimMessage.MIME_TYPE, cpim.getBytes(UTF8));\n                /* Set the Authorization header */\n                authenticationAgent.setProxyAuthorizationHeader(msg);\n                ctx = mImService.getImsModule().getSipManager().sendSipMessageAndWait(msg);\n                analyzeSipResponse(ctx, authenticationAgent, dialogPath, cpim);\n                break;\n\n            case Response.OK:\n            case Response.ACCEPTED:\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"20x OK response received\");\n                }\n                break;\n\n            default:\n                throw new NetworkException(\"Delivery report has failed: \" + statusCode\n                        + \" response received\");\n        }\n    }\n\n    /**\n     * Send message delivery status via SIP MESSAGE\n     * \n     * @param deliveryStatus Delivery status\n     * @param remoteInstanceId Remote SIP instance\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendSipMessageDeliveryStatus(DeliveryStatus deliveryStatus, String remoteInstanceId)\n            throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Send delivery status \" + deliveryStatus.getStatus()\n                        + \" for message \" + deliveryStatus.getMsgId());\n            }\n            // Create CPIM/IDMN document\n            String from = ChatUtils.ANONYMOUS_URI;\n            String to = ChatUtils.ANONYMOUS_URI;\n            /* Timestamp for IMDN datetime */\n            String imdn = ChatUtils.buildImdnDeliveryReport(deliveryStatus.getMsgId(),\n                    deliveryStatus.getStatus(), deliveryStatus.getTimestamp());\n            /* Timestamp for CPIM DateTime */\n            String cpim = ChatUtils.buildCpimDeliveryReport(from, to, imdn,\n                    System.currentTimeMillis());\n            // Create authentication agent\n            SessionAuthenticationAgent authenticationAgent = new SessionAuthenticationAgent(\n                    mImService.getImsModule());\n            // @FIXME: This should be an URI instead of String\n            String toUri = PhoneUtils.formatContactIdToUri(deliveryStatus.getRemote()).toString();\n            // Create a dialog path\n            SipDialogPath dialogPath = new SipDialogPath(mImService.getImsModule().getSipManager()\n                    .getSipStack(), mImService.getImsModule().getSipManager().getSipStack()\n                    .generateCallId(), 1, toUri, ImsModule.getImsUserProfile().getPublicUri(),\n                    toUri, mImService.getImsModule().getSipManager().getSipStack()\n                            .getServiceRoutePath(), mRcsSettings);\n            dialogPath.setRemoteSipInstance(remoteInstanceId);\n            // Create MESSAGE request\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send first MESSAGE\");\n            }\n            SipRequest msg = SipMessageFactory.createMessage(dialogPath,\n                    FeatureTags.FEATURE_OMA_IM, CpimMessage.MIME_TYPE, cpim.getBytes(UTF8));\n            // Send MESSAGE request\n            SipTransactionContext ctx = mImService.getImsModule().getSipManager()\n                    .sendSipMessageAndWait(msg);\n            // Analyze received message\n            analyzeSipResponse(ctx, authenticationAgent, dialogPath, cpim);\n\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"Unable to set authorization header for remoteInstanceId: \"\n                    + remoteInstanceId, e);\n        }\n    }\n\n    /**\n     * Delivery status\n     */\n    private static class DeliveryStatus {\n        private final String mChatId;\n        private final ContactId mRemote;\n        private final String mMsgId;\n        private final ImdnDocument.DeliveryStatus mStatus;\n        private final long mTimestamp;\n\n        public DeliveryStatus(String chatId, ContactId remote, String msgId,\n                ImdnDocument.DeliveryStatus status, long timestamp) {\n            mChatId = chatId;\n            mRemote = remote;\n            mMsgId = msgId;\n            mStatus = status;\n            mTimestamp = timestamp;\n        }\n\n        public String getChatId() {\n            return mChatId;\n        }\n\n        public ContactId getRemote() {\n            return mRemote;\n        }\n\n        public String getMsgId() {\n            return mMsgId;\n        }\n\n        public ImdnDocument.DeliveryStatus getStatus() {\n            return mStatus;\n        }\n\n        public long getTimestamp() {\n            return mTimestamp;\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/imdn/ImdnParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010 France Telecom S.A.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.imdn;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXParseException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * IMDN parser (RFC5438)\n */\npublic class ImdnParser extends DefaultHandler {\n    /*\n     * IMDN SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <imdn\n     * xmlns=\"urn:ietf:params:xml:ns:imdn\"> <message-id>34jk324j</message-id>\n     * <datetime>2008-04-04T12:16:49-05:00</datetime> <display-notification> <status> <displayed/>\n     * </status> </display-notification> </imdn>\n     */\n    private StringBuffer accumulator;\n    private String mNotificationType;\n    private ImdnDocument.DeliveryStatus mStatus;\n    private String mMsgId;\n    private long mDateTime;\n    private final InputSource mInputSource;\n\n    private static final Logger sLogger = Logger.getLogger(ImdnParser.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public ImdnParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the imdn parser\n     * \n     * @return ImdnParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public ImdnParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public void startDocument() {\n        accumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        accumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        accumulator.setLength(0);\n        if (ImdnDocument.DELIVERY_NOTIFICATION.equals(localName)) {\n            mNotificationType = ImdnDocument.DELIVERY_NOTIFICATION;\n\n        } else if (ImdnDocument.DISPLAY_NOTIFICATION.equals(localName)) {\n            mNotificationType = ImdnDocument.DISPLAY_NOTIFICATION;\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (ImdnDocument.MESSAGE_ID_TAG.equals(localName)) {\n            mMsgId = accumulator.toString();\n\n        } else if (ImdnDocument.IMDN_DATETIME.equals(localName)) {\n            mDateTime = DateUtils.decodeDate(accumulator.toString());\n\n        } else if (ImdnDocument.DeliveryStatus.DELIVERED.equalsName(localName)) {\n            mStatus = ImdnDocument.DeliveryStatus.DELIVERED;\n\n        } else if (ImdnDocument.DeliveryStatus.DISPLAYED.equalsName(localName)) {\n            mStatus = ImdnDocument.DeliveryStatus.DISPLAYED;\n\n        } else if (ImdnDocument.DeliveryStatus.FAILED.equalsName(localName)) {\n            mStatus = ImdnDocument.DeliveryStatus.FAILED;\n\n        } else if (ImdnDocument.DeliveryStatus.ERROR.equalsName(localName)) {\n            mStatus = ImdnDocument.DeliveryStatus.ERROR;\n\n        } else if (ImdnDocument.DeliveryStatus.FORBIDDEN.equalsName(localName)) {\n            mStatus = ImdnDocument.DeliveryStatus.FORBIDDEN;\n        }\n    }\n\n    public void warning(SAXParseException exception) {\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Warning: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n    }\n\n    public void error(SAXParseException exception) {\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Error: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n    }\n\n    public void fatalError(SAXParseException exception) throws SAXException {\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Fatal: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n        throw exception;\n    }\n\n    public ImdnDocument getImdnDocument() {\n        if (mMsgId == null || mNotificationType == null || mStatus == null) {\n            return null;\n        }\n        return new ImdnDocument(mMsgId, mNotificationType, mStatus, mDateTime);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/imdn/ImdnUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.imdn;\n\n/**\n * IMDN utility functions\n */\npublic class ImdnUtils {\n\n    /**\n     * IMDN notification disposition header\n     */\n    public static final String HEADER_IMDN_DISPO_NOTIF = \"imdn.Disposition-Notification\";\n\n    /**\n     * IMDN message ID header\n     */\n    public static final String HEADER_IMDN_MSG_ID = \"imdn.Message-ID\";\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/iscomposing/IsComposingInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.iscomposing;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8_STR;\n\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\n\n/**\n * Is composing info document (see RFC3994)\n */\npublic class IsComposingInfo {\n\n    public static String MIME_TYPE = \"application/im-iscomposing+xml\";\n\n    private static final String CRLF = \"\\r\\n\";\n\n    private boolean mActive;\n\n    private long mLastActiveDate;\n\n    private long mRefreshTime;\n\n    private String mContentType;\n\n    /**\n     * Constructor\n     */\n    public IsComposingInfo() {\n        mContentType = \"\";\n    }\n\n    public void setState(String state) {\n        mActive = state.equalsIgnoreCase(\"active\");\n    }\n\n    /**\n     * Sets the last active timestamp\n     * \n     * @param lastActiveTimestamp the last active timestamp\n     */\n    public void setLastActiveDate(String lastActiveTimestamp) {\n        mLastActiveDate = DateUtils.decodeDate(lastActiveTimestamp);\n    }\n\n    /**\n     * Sets the refresh time\n     *\n     * @param refreshTime in milliseconds\n     */\n    public void setRefreshTime(long refreshTime) {\n        mRefreshTime = refreshTime;\n    }\n\n    /**\n     * Sets the content type\n     * \n     * @param contentType the content type\n     */\n    public void setContentType(String contentType) {\n        mContentType = contentType;\n    }\n\n    public boolean isStateActive() {\n        return mActive;\n    }\n\n    public long getLastActiveDate() {\n        return mLastActiveDate;\n    }\n\n    /**\n     * Gets the refresh time\n     *\n     * @return refresh time in milliseconds\n     */\n    public long getRefreshTime() {\n        return mRefreshTime;\n    }\n\n    /**\n     * Gets the content type\n     * \n     * @return the content type\n     */\n    public String getContentType() {\n        return mContentType;\n    }\n\n    /**\n     * Build is composing document\n     *\n     * @param status Status\n     * @return XML document\n     */\n    public static String buildIsComposingInfo(boolean status) {\n        return new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\")\n                .append(UTF8_STR)\n                .append(\"\\\"?>\")\n                .append(CRLF)\n                .append(\"<isComposing xmlns=\\\"urn:ietf:params:xml:ns:im-iscomposing\\\"\")\n                .append(CRLF)\n                .append(\"xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"\")\n                .append(CRLF)\n                .append(\"xsi:schemaLocation=\\\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\\\">\")\n                .append(CRLF).append(\"<state>\").append(status ? \"active\" : \"idle\")\n                .append(\"</state>\").append(CRLF).append(\"<contenttype>\")\n                .append(MimeType.TEXT_MESSAGE).append(\"</contenttype>\").append(CRLF)\n                .append(\"<lastactive>\").append(DateUtils.encodeDate(System.currentTimeMillis()))\n                .append(\"</lastactive>\").append(CRLF).append(\"<refresh>60</refresh>\").append(CRLF)\n                .append(\"</isComposing>\").toString();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/iscomposing/IsComposingManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.iscomposing;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatSessionListener;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.List;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n/**\n * Is Composing manager which manages \"is composing\" events as per RFC3994. It handles the status\n * (idle or active) of contact according to received messages and timers.\n */\npublic class IsComposingManager {\n\n    private static final long DEFAULT_REFESH_TIMEOUT = 120000;\n\n    /**\n     * Expiration timer task\n     */\n    private ExpirationTimer mTimerTask;\n\n    private final ChatSession mSession;\n\n    private static final Logger sLogger = Logger.getLogger(IsComposingManager.class.getName());\n\n    /**\n     * Constructor\n     *\n     * @param session IM session\n     */\n    public IsComposingManager(ChatSession session) {\n        mSession = session;\n    }\n\n    /**\n     * Receive is-composing event\n     *\n     * @param contact Contact identifier\n     * @param event Event\n     * @throws PayloadException\n     */\n    public void receiveIsComposingEvent(ContactId contact, byte[] event) throws PayloadException {\n        try {\n            InputSource input = new InputSource(new ByteArrayInputStream(event));\n            IsComposingParser parser = new IsComposingParser(input).parse();\n            IsComposingInfo isComposingInfo = parser.getIsComposingInfo();\n            List<ImsSessionListener> sessionListeners = mSession.getListeners();\n            if (isComposingInfo != null && isComposingInfo.isStateActive()) {\n                for (ImsSessionListener sessionListener : sessionListeners) {\n                    ((ChatSessionListener) sessionListener).onIsComposingEventReceived(contact,\n                            true);\n                }\n                long timeout = isComposingInfo.getRefreshTime();\n                if (timeout == 0) {\n                    timeout = DEFAULT_REFESH_TIMEOUT;\n                }\n                startExpirationTimer(timeout, contact);\n            } else {\n                for (ImsSessionListener sessionListener : sessionListeners) {\n                    ((ChatSessionListener) sessionListener).onIsComposingEventReceived(contact,\n                            false);\n                }\n                stopExpirationTimer(contact);\n            }\n        } catch (ParserConfigurationException | SAXException | ParseFailureException e) {\n            throw new PayloadException(\"Can't parse is-composing event for session ID : \"\n                    + mSession.getSessionID(), e);\n        }\n    }\n\n    /**\n     * Receive is-composing event\n     *\n     * @param contact Contact identifier\n     * @param state State\n     */\n    public void receiveIsComposingEvent(ContactId contact, boolean state) {\n        /*\n         * We just received an instant message, so if composing info was active, it must be changed\n         * to idle. If it was already idle, no need to notify listener again.\n         */\n        for (ImsSessionListener listener : mSession.getListeners()) {\n            ((ChatSessionListener) listener).onIsComposingEventReceived(contact, state);\n        }\n        stopExpirationTimer(contact);\n    }\n\n    /**\n     * Start the expiration timer for a given contact\n     *\n     * @param duration Timer period in milliseconds\n     * @param contact Contact identifier\n     */\n    public synchronized void startExpirationTimer(long duration, ContactId contact) {\n        // Remove old timer\n        if (mTimerTask != null) {\n            mTimerTask.cancel();\n            mTimerTask = null;\n        }\n        // Start timer\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start is-composing timer for \" + duration + \"ms\");\n        }\n        mTimerTask = new ExpirationTimer(contact);\n        new Timer().schedule(mTimerTask, duration);\n    }\n\n    /**\n     * Stop the expiration timer for a given contact\n     *\n     * @param contact Contact identifier\n     */\n    public synchronized void stopExpirationTimer(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop is-composing timer\");\n        }\n        // TODO : stop timer for a given contact\n        if (mTimerTask != null) {\n            mTimerTask.cancel();\n            mTimerTask = null;\n        }\n    }\n\n    /**\n     * Internal expiration timer\n     */\n    private class ExpirationTimer extends TimerTask {\n\n        private ContactId mContact;\n\n        public ExpirationTimer(ContactId contact) {\n            mContact = contact;\n        }\n\n        public void run() {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Is-composing timer has expired: \" + mContact\n                        + \" is now considered idle\");\n            }\n            for (ImsSessionListener sessionListener : mSession.getListeners()) {\n                ((ChatSessionListener) sessionListener).onIsComposingEventReceived(mContact, false);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/iscomposing/IsComposingParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.iscomposing;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXParseException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Is composing event parser (RFC3994)\n */\npublic class IsComposingParser extends DefaultHandler {\n    // @formatter:off\n    /* Example of CPIM message having application/im-iscomposing+xml for content type:\n    <?xml version=\"1.0\" encoding=\"utf-8\"?>\n        <isComposing xmlns=\"urn:ietf:params:xml:ns:im-iscomposing\"\n        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n        xsi:schemaLocation=\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\">\n            <state>active</state>\n            <contenttype>text/plain</contenttype>\n            <lastactive>2012-02-22T17:53:49.000Z</lastactive>\n            <refresh>60</refresh>\n    </isComposing>\n*/    // @formatter:on\n\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    private StringBuilder mAccumulator;\n\n    private IsComposingInfo mComposingInfo;\n\n    private static final Logger sLogger = Logger.getLogger(IsComposingParser.class.getSimpleName());\n\n    private final InputSource mInputSource;\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public IsComposingParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the is composing input\n     * \n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public IsComposingParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public void startDocument() {\n        mAccumulator = new StringBuilder();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n        if (\"isComposing\".equals(localName)) {\n            mComposingInfo = new IsComposingInfo();\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        switch (localName) {\n            case \"state\":\n                if (mComposingInfo != null) {\n                    mComposingInfo.setState(mAccumulator.toString());\n                }\n                break;\n            case \"lastactive\":\n                if (mComposingInfo != null) {\n                    mComposingInfo.setLastActiveDate(mAccumulator.toString());\n                }\n                break;\n            case \"contenttype\":\n                if (mComposingInfo != null) {\n                    mComposingInfo.setContentType(mAccumulator.toString());\n                }\n                break;\n            case \"refresh\":\n                if (mComposingInfo != null) {\n                    long time = Long.parseLong(mAccumulator.toString())\n                            * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n                    mComposingInfo.setRefreshTime(time);\n                }\n                break;\n            case \"isComposing\":\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Watcher document is complete\");\n                }\n                break;\n        }\n    }\n\n    public void endDocument() {\n    }\n\n    public void warning(SAXParseException exception) {\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Warning: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n    }\n\n    public void error(SAXParseException exception) {\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Error: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n    }\n\n    public void fatalError(SAXParseException exception) throws SAXException {\n        if (sLogger.isActivated()) {\n            sLogger.error(\"Fatal: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n        throw exception;\n    }\n\n    public IsComposingInfo getIsComposingInfo() {\n        return mComposingInfo;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/resourcelist/ResourceListDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.resourcelist;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Resource-list document\n * \n * @author jexa7410\n * @author YPLO6403\n */\npublic class ResourceListDocument {\n    private Set<String> entries = new HashSet<String>();\n\n    public ResourceListDocument() {\n    }\n\n    public void addEntry(String uri) {\n        entries.add(uri);\n    }\n\n    public Set<String> getEntries() {\n        return entries;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/resourcelist/ResourceListParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.resourcelist;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Resource list parser\n * \n * @author jexa7410\n */\npublic class ResourceListParser extends DefaultHandler {\n\n    /*\n     * Resource-List SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <resource-lists\n     * xmlns=\"urn:ietf:params:xml:ns:resource-lists\" xmlns:cp=\"urn:ietf:params:xml:ns:copycontrol\">\n     * <list> <entry uri=\"sip:bill@example.com\" cp:copyControl=\"to\" /> <entry\n     * uri=\"sip:joe@example.org\" cp:copyControl=\"cc\" /> <entry uri=\"sip:ted@example.net\"\n     * cp:copyControl=\"bcc\" /> </list> </resource-lists>\n     */\n\n    private StringBuffer mAccumulator;\n    private ResourceListDocument mList;\n\n    private final InputSource mInputSource;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(ResourceListParser.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public ResourceListParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the resource list\n     * \n     * @return ResourceListParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public ResourceListParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public ResourceListDocument getResourceList() {\n        return mList;\n    }\n\n    @Override\n    public void startDocument() {\n        mAccumulator = new StringBuffer();\n    }\n\n    @Override\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    @Override\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n        if (\"resource-lists\".equals(localName)) {\n            mList = new ResourceListDocument();\n\n        } else if (\"entry\".equals(localName)) {\n            String uri = attr.getValue(\"uri\").trim();\n            mList.addEntry(uri);\n        }\n    }\n\n    @Override\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (\"resource-lists\".equals(localName)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Resource-list document complete\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/standfw/StoreAndForwardManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.standfw;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Store & forward manager\n */\npublic class StoreAndForwardManager {\n    /**\n     * Store & forward service URI\n     */\n    public final static String SERVICE_URI = \"rcse-standfw@\";\n\n    private final InstantMessagingService mImService;\n\n    private final RcsSettings mRcsSettings;\n\n    private final MessagingLog mMessagingLog;\n\n    private final ContactManager mContactManager;\n\n    private final static Logger sLogger = Logger.getLogger(StoreAndForwardManager.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param imService IMS service\n     * @param rcsSettings the RCS settings accessor\n     * @param contactManager the contact manager\n     * @param messagingLog the messaging log accessor\n     */\n    public StoreAndForwardManager(InstantMessagingService imService, RcsSettings rcsSettings,\n            ContactManager contactManager, MessagingLog messagingLog) {\n        mImService = imService;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n        mMessagingLog = messagingLog;\n    }\n\n    /**\n     * Receive stored messages\n     * \n     * @param invite Received invite\n     * @param contact Contact identifier\n     * @param timestamp Local timestamp when got SipRequest\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveStoreAndForwardMessageInvitation(SipRequest invite, ContactId contact, long timestamp)\n throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Receive stored messages\");\n        }\n        TerminatingStoreAndForwardOneToOneChatMessageSession session = new TerminatingStoreAndForwardOneToOneChatMessageSession(\n                mImService, invite, contact, mRcsSettings, mMessagingLog, timestamp,\n                mContactManager);\n        mImService.receiveStoreAndForwardMsgSessionInvitation(session);\n        session.startSession();\n    }\n\n    /**\n     * Receive stored notifications\n     *\n     * @param invite Received invite\n     * @param contact Contact identifier\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void receiveStoreAndForwardNotificationInvitation(SipRequest invite, ContactId contact, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Receive stored notifications\");\n        }\n        TerminatingStoreAndForwardOneToOneChatNotificationSession session = new TerminatingStoreAndForwardOneToOneChatNotificationSession(\n                mImService, invite, contact, mRcsSettings, mMessagingLog, timestamp,\n                mContactManager);\n        mImService.receiveStoreAndForwardNotificationSessionInvitation(session);\n        session.startSession();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/standfw/TerminatingStoreAndForwardOneToOneChatMessageSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.standfw;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatError;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSessionListener;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Collection;\nimport java.util.Vector;\n\n/**\n * Terminating Store & Forward session for one-one messages\n * \n * @author jexa7410\n */\npublic class TerminatingStoreAndForwardOneToOneChatMessageSession extends OneToOneChatSession {\n\n    private static final Logger sLogger = Logger\n            .getLogger(TerminatingStoreAndForwardOneToOneChatMessageSession.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param invite Initial INVITE request\n     * @param contact the remote ContactId\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact Manager\n     * @throws PayloadException\n     */\n    public TerminatingStoreAndForwardOneToOneChatMessageSession(InstantMessagingService imService,\n            SipRequest invite, ContactId contact, RcsSettings rcsSettings,\n            MessagingLog messagingLog, long timestamp, ContactManager contactManager)\n            throws PayloadException {\n        super(imService, contact, PhoneUtils.formatContactIdToUri(contact), ChatUtils\n                .getFirstMessage(invite, timestamp), rcsSettings, messagingLog, timestamp,\n                contactManager);\n        setFeatureTags(ChatUtils.getSupportedFeatureTagsForChat(rcsSettings));\n        createTerminatingDialogPath(invite);\n        String id = ChatUtils.getContributionId(invite);\n        setContributionID(id);\n        if (shouldBeAutoAccepted()) {\n            setSessionAccepted();\n        }\n    }\n\n    /**\n     * Check is session should be auto accepted. This method should only be called once per session\n     * \n     * @return true if one-to-one chat session should be auto accepted\n     * @throws PayloadException\n     */\n    private boolean shouldBeAutoAccepted() throws PayloadException {\n        /*\n         * In case the invite contains a http file transfer info the chat session should be\n         * auto-accepted so that the file transfer session can be started.\n         */\n        return FileTransferUtils.getHttpFTInfo(getDialogPath().getInvite(), mRcsSettings) != null\n                || mRcsSettings.isChatAutoAccepted();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        try {\n            if (logActivated) {\n                sLogger.info(\"Initiate a store & forward session for messages\");\n            }\n            SipDialogPath dialogPath = getDialogPath();\n            if (mImdnManager.isDeliveryDeliveredReportsEnabled()) {\n                /* Check notification disposition */\n                String msgId = ChatUtils.getMessageId(dialogPath.getInvite());\n                if (msgId != null) {\n                    /* Send message delivery status via a SIP MESSAGE */\n                    ContactId remote = getRemoteContact();\n                    mImdnManager.sendMessageDeliveryStatusImmediately(remote.toString(), remote,\n                            msgId, ImdnDocument.DeliveryStatus.DELIVERED,\n                            SipUtils.getRemoteInstanceId(dialogPath.getInvite()), getTimestamp());\n                }\n            }\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            /* Check if session should be auto-accepted once */\n            if (isSessionAccepted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Auto accept store and forward chat invitation\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((OneToOneChatSessionListener) listener).onSessionAutoAccepted(contact);\n                }\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"Accept manually store and forward chat invitation\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((OneToOneChatSessionListener) listener).onSessionInvited(contact);\n                }\n                send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n                InvitationStatus answer = waitInvitationAnswer();\n                switch (answer) {\n                    case INVITATION_REJECTED_DECLINE:\n                        /* Intentional fall through */\n                    case INVITATION_REJECTED_BUSY_HERE:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected by user\");\n                        }\n                        sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_USER);\n                        }\n                        return;\n\n                    case INVITATION_TIMEOUT:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected on timeout\");\n                        }\n                        /* Ringing period timeout */\n                        send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_TIMEOUT);\n                        }\n                        return;\n\n                    case INVITATION_REJECTED_BY_SYSTEM:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been aborted by system\");\n                        }\n                        removeSession();\n                        return;\n\n                    case INVITATION_CANCELED:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been rejected by remote\");\n                        }\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_REMOTE);\n                        }\n                        return;\n\n                    case INVITATION_ACCEPTED:\n                        setSessionAccepted();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionAccepting(contact);\n                        }\n                        break;\n\n                    case INVITATION_DELETED:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been deleted\");\n                        }\n                        removeSession();\n                        return;\n\n                    default:\n                        throw new IllegalArgumentException(\n                                \"Unknown invitation answer in run; answer=\" + answer);\n                }\n            }\n            /* Parse the remote SDP part */\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            MediaAttribute attr1 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr1.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n            /* Extract the \"setup\" parameter */\n            String remoteSetup = \"passive\";\n            MediaAttribute attr2 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr2 != null) {\n                remoteSetup = attr2.getValue();\n            }\n            if (logActivated) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n            /* Set setup mode */\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (logActivated) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            /* Set local port */\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            }\n            /* Build SDP part */\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), getSdpDirection());\n            /* Set the local SDP part in the dialog path */\n            dialogPath.setLocalContent(sdp);\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Create a 200 OK response */\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    getFeatureTags(), sdp);\n            dialogPath.setSigEstablished();\n            /* Send response */\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n            /* Create the MSRP server session */\n            if (localSetup.equals(\"passive\")) {\n                /* Passive mode: client wait a connection */\n                MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this);\n                session.setFailureReportOption(false);\n                session.setSuccessReportOption(false);\n                getMsrpMgr().openMsrpSession();\n                /*\n                 * Even if local setup is passive, an empty chunk must be sent to open the NAT and\n                 * so enable the active endpoint to initiate a MSRP connection.\n                 */\n                sendEmptyDataChunk();\n            }\n            /* wait a response */\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            // Test if the session should be interrupted\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (logActivated) {\n                    sLogger.info(\"ACK request received\");\n                }\n                dialogPath.setSessionEstablished();\n                /* Create the MSRP client session */\n                if (localSetup.equals(\"active\")) {\n                    /* Active mode: client should connect */\n                    MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost,\n                            remotePort, remotePath, this, fingerprint);\n                    session.setFailureReportOption(false);\n                    session.setSuccessReportOption(false);\n                    getMsrpMgr().openMsrpSession();\n                    sendEmptyDataChunk();\n                }\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(contact);\n                }\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n                getActivityManager().start();\n\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n\n                /* No response received: timeout */\n                handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED));\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Unable to send 200OK response!\", e);\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed initiating a store & forward session for messages!\", e);\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n        }\n    }\n\n    @Override\n    public String getSdpDirection() {\n        return SdpUtils.DIRECTION_RECVONLY;\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getImsService().getImsModule().getInstantMessagingService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/chat/standfw/TerminatingStoreAndForwardOneToOneChatNotificationSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.chat.standfw;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatError;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimParser;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Vector;\n\n/**\n * Terminating Store & Forward session for one-one push notifications\n * \n * @author jexa7410\n */\npublic class TerminatingStoreAndForwardOneToOneChatNotificationSession extends OneToOneChatSession {\n\n    private MsrpManager mMsrpMgr;\n    private static final Logger sLogger = Logger\n            .getLogger(TerminatingStoreAndForwardOneToOneChatNotificationSession.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param invite Initial INVITE request\n     * @param contact the remote ContactId\n     * @param rcsSettings RCS settings\n     * @param messagingLog Messaging log\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     */\n    public TerminatingStoreAndForwardOneToOneChatNotificationSession(\n            InstantMessagingService imService, SipRequest invite, ContactId contact,\n            RcsSettings rcsSettings, MessagingLog messagingLog, long timestamp,\n            ContactManager contactManager) {\n        super(imService, contact, PhoneUtils.formatContactIdToUri(contact), null, rcsSettings,\n                messagingLog, timestamp, contactManager);\n\n        int localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(rcsSettings);\n        String localIpAddress = imService.getImsModule().getCurrentNetworkInterface()\n                .getNetworkAccess().getIpAddress();\n        mMsrpMgr = new MsrpManager(localIpAddress, localMsrpPort, imService, rcsSettings);\n        createTerminatingDialogPath(invite);\n    }\n\n    @Override\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        try {\n            if (logActivated) {\n                sLogger.info(\"Initiate a new store & forward session for notifications\");\n            }\n            /* Parse the remote SDP part */\n            SdpParser parser = new SdpParser(getDialogPath().getRemoteContent().getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            MediaAttribute attr1 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr1.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n\n            /* Extract the \"setup\" parameter */\n            String remoteSetup = \"passive\";\n            MediaAttribute attr2 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr2 != null) {\n                remoteSetup = attr2.getValue();\n            }\n            if (logActivated) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n            /* Set setup mode */\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (logActivated) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            /* Set local port */\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = getMsrpMgr().getLocalMsrpPort();\n            } else {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            }\n            /* Build SDP part */\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String sdp = SdpUtils.buildChatSDP(ipAddress, localMsrpPort, getMsrpMgr()\n                    .getLocalSocketProtocol(), getAcceptTypes(), getWrappedTypes(), localSetup,\n                    getMsrpMgr().getLocalMsrpPath(), getSdpDirection());\n            /* Set the local SDP part in the dialog path */\n            getDialogPath().setLocalContent(sdp);\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Create a 200 OK response */\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(getDialogPath(),\n                    InstantMessagingService.CHAT_FEATURE_TAGS, sdp);\n            getDialogPath().setSigEstablished();\n            /* Send response */\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n            // Create the MSRP server session\n            if (localSetup.equals(\"passive\")) {\n                // Passive mode: client wait a connection\n                MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this);\n                session.setFailureReportOption(false);\n                session.setSuccessReportOption(false);\n                getMsrpMgr().openMsrpSession();\n                /*\n                 * Even if local setup is passive, an empty chunk must be sent to open the NAT and\n                 * so enable the active endpoint to initiate a MSRP connection.\n                 */\n                sendEmptyDataChunk();\n            }\n            /* wait a response */\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            // Test if the session should be interrupted\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (logActivated) {\n                    sLogger.info(\"ACK request received\");\n                }\n                getDialogPath().setSessionEstablished();\n                /* Create the MSRP client session */\n                if (localSetup.equals(\"active\")) {\n                    /* Active mode: client should connect */\n                    MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost,\n                            remotePort, remotePath, this, fingerprint);\n                    session.setFailureReportOption(false);\n                    session.setSuccessReportOption(false);\n                    getMsrpMgr().openMsrpSession();\n                    sendEmptyDataChunk();\n                }\n                getActivityManager().start();\n\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n\n                /* No response received: timeout */\n                handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED));\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Unable to send 200OK response!\", e);\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed initiating a store & forward session for notifications!\", e);\n            handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n        }\n    }\n\n    @Override\n    public MsrpManager getMsrpMgr() {\n        return mMsrpMgr;\n    }\n\n    @Override\n    public void closeMsrpSession() {\n        if (getMsrpMgr() != null) {\n            getMsrpMgr().closeSession();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"MSRP session has been closed\");\n            }\n        }\n    }\n\n    @Override\n    public void handleError(ImsServiceError error) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session error: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        closeMediaSession();\n        removeSession();\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        // Not used in terminating side\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType)\n            throws PayloadException, NetworkException {\n        final boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Data received (type \" + mimeType + \")\");\n        }\n        getActivityManager().updateActivity();\n        if ((data == null) || (data.length == 0)) {\n            if (logActivated) {\n                sLogger.debug(\"By-pass received empty data\");\n            }\n            return;\n        }\n        if (ChatUtils.isMessageCpimType(mimeType)) {\n            CpimParser cpimParser = new CpimParser(data);\n            CpimMessage cpimMsg = cpimParser.getCpimMessage();\n            if (cpimMsg == null) {\n                return;\n            }\n            String contentType = cpimMsg.getContentType();\n            if (!ChatUtils.isMessageImdnType(contentType)) {\n                return;\n            }\n            String from = cpimMsg.getHeader(CpimMessage.HEADER_FROM);\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(from);\n            if (number != null) {\n                ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                onDeliveryStatusReceived(contact, cpimMsg.getMessageContent());\n            } else {\n                onDeliveryStatusReceived(getRemoteContact(), cpimMsg.getMessageContent());\n            }\n        } else {\n            if (logActivated) {\n                sLogger.debug(\"Not supported content \" + mimeType + \" in chat session\");\n            }\n        }\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used by S&F\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        // Not used by S&F\n    }\n\n    /**\n     * Data transfer error\n     * \n     * @param msgId Message ID\n     * @param error Error code\n     */\n    public void msrpTransferError(String msgId, String error) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer error \" + error + \" for message ID=\" + msgId);\n        }\n    }\n\n    @Override\n    public void sendEmptyDataChunk() throws NetworkException {\n        mMsrpMgr.sendEmptyChunk();\n    }\n\n    @Override\n    public String getSdpDirection() {\n        return SdpUtils.DIRECTION_RECVONLY;\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getImsService().getImsModule().getInstantMessagingService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/FileSharingError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionBasedServiceError;\n\n/**\n * File transfer error\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileSharingError extends ImsSessionBasedServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Media transfer has failed (e.g. MSRP failure)\n     */\n    public final static int MEDIA_TRANSFER_FAILED = FT_ERROR_CODES + 1;\n\n    /**\n     * Media saving has failed (e.g. sdcard is not correctly mounted)\n     */\n    public final static int MEDIA_SAVING_FAILED = FT_ERROR_CODES + 2;\n\n    /**\n     * Media file is too big\n     */\n    public final static int MEDIA_SIZE_TOO_BIG = FT_ERROR_CODES + 3;\n\n    /**\n     * Media upload has failed\n     */\n    public final static int MEDIA_UPLOAD_FAILED = FT_ERROR_CODES + 4;\n\n    /**\n     * Media download has failed\n     */\n    public final static int MEDIA_DOWNLOAD_FAILED = FT_ERROR_CODES + 5;\n\n    /**\n     * Linked chat session doesn't exist anymore\n     */\n    public final static int NO_CHAT_SESSION = FT_ERROR_CODES + 6;\n\n    /**\n     * The storage capacity is too small\n     */\n    public final static int NOT_ENOUGH_STORAGE_SPACE = FT_ERROR_CODES + 7;\n\n    /**\n     * Constructor\n     * \n     * @param error Error\n     */\n    public FileSharingError(ImsServiceError error) {\n        super(error.getErrorCode(), error.getMessage());\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public FileSharingError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public FileSharingError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public FileSharingError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/FileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.StorageUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\n\nimport android.net.Uri;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Abstract file sharing session\n *\n * @author jexa7410\n */\npublic abstract class FileSharingSession extends ImsServiceSession {\n    /**\n     * File render disposition which means the file is player automatically\n     */\n    public final static String FILE_DISPOSITION_RENDER = \"render\";\n\n    /**\n     * File attachment disposition which means the file should be opened manually\n     */\n    public final static String FILE_DISPOSITION_ATTACH = \"attachment\";\n\n    private String mContributionId;\n\n    /**\n     * Content to be shared\n     */\n    private MmContent mContent;\n\n    private boolean mFileTransferred = false;\n\n    protected final Map<ContactId, ParticipantStatus> mParticipants;\n\n    private final MmContent mFileIcon;\n\n    private boolean mFileTransferPaused = false;\n\n    private final String mFileTransferId;\n\n    protected final ImdnManager mImdnManager;\n\n    private static final Logger sLogger = Logger.getLogger(FileSharingSession.class.getName());\n\n    /**\n     * Constructor\n     *\n     * @param imService InstantMessagingService\n     * @param content Content to be shared\n     * @param contact Remote contactId\n     * @param remoteContact the remote contact URI\n     * @param fileIcon File icon\n     * @param fileTransferId File transfer identifier\n     * @param rcsSettings RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager accessor\n     */\n    public FileSharingSession(InstantMessagingService imService, MmContent content,\n            ContactId contact, Uri remoteContact, MmContent fileIcon, String fileTransferId,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager) {\n        super(imService, contact, remoteContact, rcsSettings, timestamp, contactManager);\n        mContent = content;\n        mFileIcon = fileIcon;\n        mFileTransferId = fileTransferId;\n        mImdnManager = imService.getImdnManager();\n        mParticipants = new HashMap<>();\n    }\n\n    /**\n     * Check if the file sharing session is a HTTP transfer\n     *\n     * @return {@code true} if HTTP transfer, otherwise {@code false}\n     */\n    public abstract boolean isHttpTransfer();\n\n    /**\n     * Return the contribution ID\n     *\n     * @return Contribution ID\n     */\n    public String getContributionID() {\n        return mContributionId;\n    }\n\n    /**\n     * Set the contribution ID\n     *\n     * @param id Contribution ID\n     */\n    public void setContributionID(String id) {\n        mContributionId = id;\n    }\n\n    /**\n     * Returns the content\n     *\n     * @return Content\n     */\n    public MmContent getContent() {\n        return mContent;\n    }\n\n    /**\n     * Returns the list of participants involved in the transfer\n     *\n     * @return List of participants\n     */\n    public Map<ContactId, ParticipantStatus> getParticipants() {\n        return mParticipants;\n    }\n\n    /**\n     * Set the content\n     *\n     * @param content Content\n     */\n    public void setContent(MmContent content) {\n        mContent = content;\n    }\n\n    /**\n     * Returns the unique id for file transfer\n     *\n     * @return filetransferId String\n     */\n    public String getFileTransferId() {\n        return mFileTransferId;\n    }\n\n    /**\n     * Set file as being transferred\n     */\n    public void setFileTransferred() {\n        mFileTransferred = true;\n    }\n\n    /**\n     * Is file transferred\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferred() {\n        return mFileTransferred;\n    }\n\n    /**\n     * File has been paused\n     */\n    public void setFileTransferPaused() {\n        mFileTransferPaused = true;\n    }\n\n    /**\n     * File is resuming\n     */\n    public void setFileTransferResumed() {\n        mFileTransferPaused = false;\n    }\n\n    /**\n     * Is file transfer paused\n     *\n     * @return fileTransferPaused\n     */\n    public boolean isFileTransferPaused() {\n        return mFileTransferPaused;\n    }\n\n    /**\n     * Returns the fileIcon content\n     *\n     * @return Fileicon\n     */\n    public MmContent getFileicon() {\n        return mFileIcon;\n    }\n\n    /**\n     * Check if file capacity is acceptable\n     *\n     * @param fileSize File size in bytes\n     * @param rcsSettings RCS settings accessor\n     * @return Error or null if file capacity is acceptable\n     */\n    public static FileSharingError isFileCapacityAcceptable(long fileSize, RcsSettings rcsSettings) {\n        long maxFileSharingSize = rcsSettings.getMaxFileTransferSize();\n        boolean fileIsToBig = (maxFileSharingSize > 0) && fileSize > maxFileSharingSize;\n        boolean storageIsTooSmall = (StorageUtils.getExternalStorageFreeSpace() > 0)\n                && fileSize > StorageUtils.getExternalStorageFreeSpace();\n        if (fileIsToBig) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"File is too big, reject the file transfer\");\n            }\n            return new FileSharingError(FileSharingError.MEDIA_SIZE_TOO_BIG);\n        }\n        if (storageIsTooSmall) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Not enough storage capacity, reject the file transfer\");\n            }\n            return new FileSharingError(FileSharingError.NOT_ENOUGH_STORAGE_SPACE);\n        }\n        return null;\n    }\n\n    /**\n     * Session inactivity event\n     */\n    public void handleInactivityEvent() {\n        /* Not need in this class */\n    }\n\n    @Override\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        super.receiveCancel(cancel);\n        getImsService().getImsModule().getCapabilityService()\n                .requestContactCapabilities(getRemoteContact());\n    }\n\n    @Override\n    public void startSession() {\n        getImsService().getImsModule().getInstantMessagingService().addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getImsService().getImsModule().getInstantMessagingService().removeSession(this);\n    }\n\n    /**\n     * Returns the time when the file on the content server is no longer valid to download.\n     *\n     * @return time\n     */\n    public abstract long getFileExpiration();\n\n    /**\n     * Returns the time when the file icon on the content server is no longer valid to download.\n     *\n     * @return time\n     */\n    public abstract long getIconExpiration();\n\n    /**\n     * Returns the file-disposition\n     *\n     * @return string for payload insertion.\n     */\n    public String getFileDisposition() {\n        return getContent().isPlayable() ? FileSharingSession.FILE_DISPOSITION_RENDER\n                : FileSharingSession.FILE_DISPOSITION_ATTACH;\n    }\n\n    /**\n     * Convert Disposition to string for payload insertion.\n     *\n     * @param disposition the disposition\n     * @return the string for payload insertion.\n     */\n    /* package private */static String DispositionToString(FileTransfer.Disposition disposition) {\n        return FileTransfer.Disposition.ATTACH == disposition ? FILE_DISPOSITION_ATTACH\n                : FILE_DISPOSITION_RENDER;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/FileSharingSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * File transfer session listener\n * \n * @author jexa7410\n */\npublic interface FileSharingSessionListener extends ImsSessionListener {\n    /**\n     * File transfer progress\n     * \n     * @param contact Remote contact\n     * @param currentSize Data size transfered\n     * @param totalSize Total size to be transfered\n     */\n    void onTransferProgress(ContactId contact, long currentSize, long totalSize);\n\n    /**\n     * File transfer not allowed to send\n     * \n     * @param contact Remote contact\n     */\n    void onTransferNotAllowedToSend(ContactId contact);\n\n    /**\n     * File transfer error\n     * \n     * @param error Error\n     * @param contact Remote contact\n     */\n    void onTransferError(FileSharingError error, ContactId contact);\n\n    /**\n     * File has been transferred In case of file transfer over MSRP, the terminating side has\n     * received the file, but in case of file transfer over HTTP, only the content server has\n     * received the file.\n     * \n     * @param content MmContent associated to the received file\n     * @param contact Remote contact\n     * @param fileExpiration the time when file on the content server is no longer valid to download\n     * @param fileIconExpiration the time when file icon on the content server is no longer valid to\n     *            download\n     * @param ftProtocol FileTransferProtocol\n     */\n    void onFileTransferred(MmContent content, ContactId contact, long fileExpiration,\n            long fileIconExpiration, FileTransferProtocol ftProtocol);\n\n    /**\n     * File transfer has been paused by user\n     * \n     * @param contact Remote contact\n     */\n    void onFileTransferPausedByUser(ContactId contact);\n\n    /**\n     * File transfer has been paused by system\n     * \n     * @param contact Remote contact\n     */\n    void onFileTransferPausedBySystem(ContactId contact);\n\n    /**\n     * File transfer has been resumed\n     * \n     * @param contact Remote contact\n     */\n    void onFileTransferResumed(ContactId contact);\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     * @param file the file content\n     * @param fileIcon the file icon\n     * @param timestamp Local timestamp when got file sharing\n     * @param timestampSent Remote timestamp sent in payload for the file sharing\n     * @param fileExpiration the file expiration\n     * @param fileIconExpiration the file icon expiration\n     */\n    void onSessionInvited(ContactId contact, MmContent file, MmContent fileIcon, long timestamp,\n            long timestampSent, long fileExpiration, long fileIconExpiration);\n\n    /**\n     * Session is auto-accepted and the session is in the process of being started\n     * \n     * @param contact Remote contact\n     * @param file the file content\n     * @param fileIcon the file icon\n     * @param timestamp Local timestamp when got file sharing\n     * @param timestampSent Remote timestamp sent in payload for the file sharing\n     * @param fileExpiration the file expiration\n     * @param fileIconExpiration the file icon expiration\n     */\n    void onSessionAutoAccepted(ContactId contact, MmContent file, MmContent fileIcon,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration);\n\n    /**\n     * HTTP download information is available\n     */\n    void onHttpDownloadInfoAvailable();\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/FileTransferUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\nimport static com.gsma.rcs.utils.StringUtils.UTF8_STR;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpThumbnail;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferXmlParser;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.platform.file.FileDescription;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.Base64;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.MimeManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.CompressFormat;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Matrix;\nimport android.net.Uri;\n\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n/**\n * Utility class to manage File Transfer\n * \n * @author Philippe LEMORDANT\n */\npublic class FileTransferUtils {\n\n    private static final Logger sLogger = Logger.getLogger(FileTransferUtils.class.getName());\n\n    private static final String FILEICON_INFO = \"thumbnail\";\n\n    private static final String FILE_INFO = \"file\";\n\n    private static final String FILEICON_MIMETYPE = \"image/jpeg\";\n\n    /**\n     * Is a file transfer HTTP event type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isFileTransferHttpType(String mime) {\n        return mime != null\n                && mime.toLowerCase().startsWith(FileTransferHttpInfoDocument.MIME_TYPE);\n    }\n\n    /**\n     * Create a content of fileIcon from a file\n     * \n     * @param file Uri of the image\n     * @param fileIconId the identifier of the file icon\n     * @param rcsSettings the RCS settings accessor\n     * @return the content of the file icon\n     * @throws FileAccessException\n     */\n    public static MmContent createFileicon(Uri file, String fileIconId, RcsSettings rcsSettings)\n            throws FileAccessException {\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        InputStream in = null;\n        MmContent fileIcon = null;\n        try {\n            in = AndroidFactory.getApplicationContext().getContentResolver().openInputStream(file);\n            Bitmap bitmap = BitmapFactory.decodeStream(in);\n            if (bitmap == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Cannot decode image \" + file);\n                }\n                return null;\n            }\n            int width = bitmap.getWidth();\n            int height = bitmap.getHeight();\n            long size = FileUtils.getFileSize(AndroidFactory.getApplicationContext(), file);\n            // Resize the bitmap\n            float scale = 0.05f;\n            Matrix matrix = new Matrix();\n            matrix.postScale(scale, scale);\n            // Recreate the new bitmap\n            Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);\n            // Compress the file to be under the limit\n            int quality = 90;\n            long maxSize = rcsSettings.getMaxFileIconSize();\n            while (size > maxSize) {\n                out = new ByteArrayOutputStream();\n                resizedBitmap.compress(CompressFormat.JPEG, quality, out);\n                out.flush();\n                out.close();\n                size = out.size();\n                quality -= 10;\n            }\n            // Create fileIcon URL\n            String fileIconName = buildFileiconUrl(fileIconId, FILEICON_MIMETYPE);\n            // Get the fileIcon data\n            byte[] fileIconData = out.toByteArray();\n\n            // Generate fileIcon content\n            Uri fileIconUri = Uri.fromFile(new File(rcsSettings.getFileIconRootDirectory().concat(\n                    fileIconName)));\n            fileIcon = ContentManager.createMmContent(fileIconUri, FILEICON_MIMETYPE,\n                    fileIconData.length, fileIconName);\n            // persist the fileIcon content\n            fileIcon.writeData2File(fileIconData);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Generate Icon \" + fileIconName + \" for image \" + file);\n            }\n            return fileIcon;\n\n        } catch (IOException e) {\n            throw new FileAccessException(\"Failed to create icon for uri: \" + file, e);\n\n        } finally {\n            CloseableUtils.tryToClose(in);\n            if (fileIcon != null) {\n                fileIcon.closeFile();\n            }\n        }\n    }\n\n    /**\n     * Generate a filename for the file icon\n     * \n     * @param msgId the message ID of the File Transfer\n     * @param mimeType the mime-type\n     * @return the filename of the file icon\n     */\n    public static String buildFileiconUrl(String msgId, String mimeType) {\n        StringBuilder iconName = new StringBuilder(\"thumbnail_\");\n        iconName.append(msgId);\n        String extension = MimeManager.getInstance().getExtensionFromMimeType(mimeType);\n        if (extension != null) {\n            iconName.append(\".\");\n            iconName.append(extension);\n            return iconName.toString();\n        }\n        throw new IllegalArgumentException(\"Invalid mime type for image\");\n    }\n\n    /**\n     * Extract file icon from incoming INVITE request\n     * \n     * @param request Request\n     * @param rcsSettings the RCS settings accessor\n     * @return fileIcon the file icon content persisted on disk\n     * @throws FileAccessException\n     */\n    public static MmContent extractFileIcon(SipRequest request, RcsSettings rcsSettings)\n            throws FileAccessException {\n        MmContent result = null;\n        try {\n            String content = request.getContent();\n            String boundary = request.getBoundaryContentType();\n            Multipart multi = new Multipart(content, boundary);\n            if (!multi.isMultipart()) {\n                return null;\n            }\n            String mimeType = FILEICON_MIMETYPE;\n            String data = multi.getPart(mimeType);\n            if (data == null) {\n                mimeType = \"image/png\";\n                data = multi.getPart(mimeType);\n            }\n            if (data == null) {\n                return null;\n            }\n            String iconName = buildFileiconUrl(ChatUtils.getContributionId(request), mimeType);\n            Uri fileIconUri = Uri.fromFile(new File(rcsSettings.getFileIconRootDirectory().concat(\n                    iconName)));\n            byte[] fileIconData = Base64.decodeBase64(mimeType.getBytes(UTF8));\n            result = ContentManager.createMmContent(fileIconUri, mimeType, fileIconData.length,\n                    iconName);\n            result.writeData2File(fileIconData);\n            return result;\n\n        } finally {\n            if (result != null) {\n                result.closeFile();\n            }\n        }\n    }\n\n    /**\n     * Parse a file transfer over HTTP document\n     * \n     * @param xml XML document\n     * @param rcsSettings RCS settings\n     * @return File transfer document\n     * @throws PayloadException\n     */\n    public static FileTransferHttpInfoDocument parseFileTransferHttpDocument(byte[] xml,\n            RcsSettings rcsSettings) throws PayloadException {\n        try {\n            FileTransferXmlParser ftHttpParser = new FileTransferXmlParser(xml, rcsSettings);\n            ftHttpParser.parse();\n            return ftHttpParser.getFileTransferInfo();\n\n        } catch (ParserConfigurationException | ParseFailureException | SAXException e) {\n            throw new PayloadException(\"Can't parse FT HTTP document!\", e);\n        }\n    }\n\n    /**\n     * Get the HTTP file transfer info document\n     * \n     * @param request Request\n     * @param rcsSettings RCS settings\n     * @return FT HTTP info\n     * @throws PayloadException\n     */\n    public static FileTransferHttpInfoDocument getHttpFTInfo(SipRequest request,\n            RcsSettings rcsSettings) throws PayloadException {\n        /* Not a valid timestamp here as the message is just for temp use */\n        long timestamp = -1;\n        ChatMessage message = ChatUtils.getFirstMessage(request, timestamp);\n        if (message == null || !FileTransferUtils.isFileTransferHttpType(message.getMimeType())) {\n            return null;\n        }\n        return parseFileTransferHttpDocument(message.getContent().getBytes(UTF8), rcsSettings);\n    }\n\n    /**\n     * Create a content object from URI\n     *\n     * @param uri Uri of file\n     * @param mimeType the mime type\n     * @param disposition File disposition\n     * @return Content instance\n     */\n    public static MmContent createMmContent(Uri uri, String mimeType, Disposition disposition) {\n        final FileDescription desc = FileFactory.getFactory().getFileDescription(uri);\n        MmContent content = ContentManager.createMmContent(uri, mimeType, desc.getSize(),\n                desc.getName());\n        if (Disposition.RENDER == disposition) {\n            content.setPlayable(true);\n        }\n        return content;\n    }\n\n    /**\n     * Create a content object for icon\n     *\n     * @param uri Uri of file\n     * @return Content instance\n     */\n    public static MmContent createIconContent(Uri uri) {\n        final FileDescription desc = FileFactory.getFactory().getFileDescription(uri);\n        String mime = FileUtils.getMimeTypeFromExtension(uri.getPath());\n        return ContentManager.createMmContent(uri, mime, desc.getSize(), desc.getName());\n    }\n\n    private static String createHttpFileInfoXml(String fileType, Uri downloadUri, String name,\n            String mimeType, long size, long expiration, String disposition, int playingLength) {\n        String expirationAsIso = DateUtils.encodeDate(expiration);\n        StringBuilder info = new StringBuilder(\"<file-info type=\\\"\").append(fileType).append(\"\\\"\");\n        if (disposition != null) {\n            info.append(\" file-disposition=\\\"\").append(disposition).append(\"\\\"\");\n        }\n        info.append(\">\");\n        info.append(\"<file-size>\").append(size).append(\"</file-size>\");\n        if (name != null) {\n            info.append(\"<file-name>\").append(name).append(\"</file-name>\");\n        }\n        info.append(\"<content-type>\").append(mimeType).append(\"</content-type>\");\n        if (playingLength != -1) {\n            info.append(\"<am:playing-length>\").append(playingLength).append(\"</am:playing-length>\");\n        }\n        info.append(\"<data url = \\\"\").append(downloadUri.toString()).append(\"\\\"  until=\\\"\")\n                .append(expirationAsIso).append(\"\\\"/></file-info>\");\n        return info.toString();\n    }\n\n    /**\n     * Create HTTP file transfer xml descriptor\n     *\n     * @param fileTransferData File transfer information\n     * @return a string representing the HTTP file transfer xml descriptor\n     */\n    public static String createHttpFileTransferXml(FileTransferHttpInfoDocument fileTransferData) {\n        FileTransferHttpThumbnail fileIcon = fileTransferData.getFileThumbnail();\n        StringBuilder info = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\")\n                .append(UTF8_STR).append(\"\\\"?><file>\");\n        if (fileIcon != null) {\n            String fileIconInfo = createHttpFileInfoXml(FILEICON_INFO, fileIcon.getUri(), null,\n                    fileIcon.getMimeType(), fileIcon.getSize(), fileIcon.getExpiration(), null, -1);\n            info.append(fileIconInfo);\n        }\n        String fileInfo = createHttpFileInfoXml(FILE_INFO, fileTransferData.getUri(),\n                fileTransferData.getFilename(), fileTransferData.getMimeType(),\n                fileTransferData.getSize(), fileTransferData.getExpiration(),\n                FileSharingSession.DispositionToString(fileTransferData.getFileDisposition()),\n                fileTransferData.getPlayingLength());\n        info.append(fileInfo);\n        info.append(\"</file>\");\n        return info.toString();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/ImsFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.text.ParseException;\n\n/**\n * Abstract IMS file transfer session\n * \n * @author jexa7410\n */\npublic abstract class ImsFileSharingSession extends FileSharingSession {\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    /**\n     * Default SO_TIMEOUT value (in milliseconds)\n     */\n    public final static long DEFAULT_SO_TIMEOUT = 30000;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(ImsFileSharingSession.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param content Content of file to be shared\n     * @param contact Remote contact identifier\n     * @param fileIcon Content of file icon\n     * @param filetransferId File transfer Id\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     */\n    public ImsFileSharingSession(InstantMessagingService imService, MmContent content,\n            ContactId contact, MmContent fileIcon, String filetransferId, RcsSettings rcsSettings,\n            long timestamp, ContactManager contactManager) {\n        super(imService, content, contact, PhoneUtils.formatContactIdToUri(contact), fileIcon,\n                filetransferId, rcsSettings, timestamp, contactManager);\n    }\n\n    @Override\n    public boolean isHttpTransfer() {\n        return false;\n    }\n\n    /**\n     * Returns the \"file-transfer-id\" attribute\n     * \n     * @return String\n     */\n    public String getFileTransferIdAttribute() {\n        return Long.toString(System.currentTimeMillis());\n    }\n\n    /**\n     * Returns the \"file-selector\" attribute\n     * \n     * @return String\n     */\n    public String getFileSelectorAttribute() {\n        return \"name:\\\"\" + getContent().getName() + \"\\\"\" + \" type:\" + getContent().getEncoding()\n                + \" size:\" + getContent().getSize();\n    }\n\n    /**\n     * Returns the \"file-location\" attribute\n     * \n     * @return Uri\n     */\n    public Uri getFileLocationAttribute() {\n        Uri file = getContent().getUri();\n        if ((file != null) && file.getScheme().startsWith(\"http\")) {\n            return file;\n        }\n        return null;\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return the INVITE request\n     * @throws PayloadException\n     */\n    public SipRequest createInvite() throws PayloadException {\n        try {\n            SipRequest invite;\n            SipDialogPath dialogPath = getDialogPath();\n            if (getFileicon() != null) {\n                invite = SipMessageFactory.createMultipartInvite(dialogPath,\n                        InstantMessagingService.FT_FEATURE_TAGS, dialogPath.getLocalContent(),\n                        BOUNDARY_TAG);\n            } else {\n                invite = SipMessageFactory.createInvite(dialogPath,\n                        InstantMessagingService.FT_FEATURE_TAGS, dialogPath.getLocalContent());\n            }\n            invite.addHeader(ChatUtils.HEADER_CONTRIBUTION_ID, getContributionID());\n            return invite;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create invite request!\", e);\n        }\n    }\n\n    /**\n     * Handle error\n     * \n     * @param error Error\n     */\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Session error: \").append(error.getErrorCode())\n                    .append(\", reason=\").append(error.getMessage()).toString());\n        }\n        closeMediaSession();\n        removeSession();\n\n        ContactId contact = getRemoteContact();\n        for (int j = 0; j < getListeners().size(); j++) {\n            ((FileSharingSessionListener) getListeners().get(j)).onTransferError(\n                    new FileSharingError(error), contact);\n        }\n    }\n\n    /**\n     * Data transfer error\n     * \n     * @param msgId Message ID\n     * @param error Error code\n     * @param typeMsrpChunk\n     */\n    public void msrpTransferError(String msgId, String error,\n            MsrpSession.TypeMsrpChunk typeMsrpChunk) {\n        try {\n            if (isSessionInterrupted() || getDialogPath().isSessionTerminated()) {\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Data transfer error: \".concat(error));\n            }\n            closeSession(ImsServiceSession.TerminationReason.TERMINATION_BY_SYSTEM);\n            closeMediaSession();\n\n            getImsService().getImsModule().getCapabilityService()\n                    .requestContactCapabilities(getRemoteContact());\n\n            removeSession();\n\n            if (isFileTransferred()) {\n                return;\n            }\n            ContactId contact = getRemoteContact();\n            for (ImsSessionListener listener : getListeners()) {\n                ((FileSharingSessionListener) listener).onTransferError(new FileSharingError(\n                        FileSharingError.MEDIA_TRANSFER_FAILED, error), contact);\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n        }\n    }\n\n    @Override\n    public long getFileExpiration() {\n        return FileTransferData.UNKNOWN_EXPIRATION;\n    }\n\n    @Override\n    public long getIconExpiration() {\n        return FileTransferData.UNKNOWN_EXPIRATION;\n    }\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        super.receiveBye(bye);\n        ContactId contact = getRemoteContact();\n        /*\n         * SIP BYE can be received from the sender if either the sender wishes to abort the session\n         * or when the transfer of file is completed. In both cases, we need to close the session\n         * and perform the clean up activities of the session. We will broadcast the state as\n         * ABORTED and ABORTED_BY_REMOTE only if the file was not received successfully.\n         */\n        if (!isFileTransferred()) {\n            for (ImsSessionListener listener : getListeners()) {\n                listener.onSessionAborted(contact, TerminationReason.TERMINATION_BY_REMOTE);\n            }\n        }\n        getImsService().getImsModule().getCapabilityService().requestContactCapabilities(contact);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/DownloadFromAcceptFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeDownload;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Terminating file transfer HTTP session starting from user acceptance (after core was restarted).\n */\npublic class DownloadFromAcceptFileSharingSession extends TerminatingHttpFileSharingSession {\n\n    private static final Logger sLogger = Logger\n            .getLogger(DownloadFromAcceptFileSharingSession.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param content the content to be transferred\n     * @param resume the Data Object to access FT HTTP table in DB\n     * @param rcsSettings the RCS settings accessor\n     * @param messagingLog the messaging log accessor\n     * @param contactManager the contact manager\n     */\n    public DownloadFromAcceptFileSharingSession(InstantMessagingService imService,\n            MmContent content, FtHttpResumeDownload resume, RcsSettings rcsSettings,\n            MessagingLog messagingLog, ContactManager contactManager) {\n        // @formatter:off\n        super(imService,\n                content,\n                resume.getFileExpiration(),\n                resume.getFileicon() != null ? FileTransferUtils.createIconContent(resume.getFileicon()) : null,\n                resume.getFileicon() != null ? resume.getIconExpiration() : FileTransferData.UNKNOWN_EXPIRATION,\n                resume.getContact(),\n                resume.getChatId(),\n                resume.getFileTransferId(),\n                resume.isGroupTransfer(),\n                resume.getServerAddress(),\n                rcsSettings,\n                messagingLog,\n                resume.getTimestamp(),\n                resume.getRemoteSipInstance(),\n                contactManager);\n        // @formatter:on\n        setSessionAccepted();\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Accept HTTP file transfer session\");\n        }\n        try {\n            onHttpTransferStarted();\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Download failed for a file sessionId : \" + getSessionID()\n                    + \" with transferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n            return;\n        }\n        super.run();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/DownloadFromInviteFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.util.List;\n\nimport javax2.sip.header.ContactHeader;\n\n/**\n * Terminating file transfer HTTP session starting from invitation\n * \n * @author vfml3370\n */\npublic class DownloadFromInviteFileSharingSession extends TerminatingHttpFileSharingSession {\n\n    private final Uri mIconRemoteUri;\n\n    private static final Logger sLogger = Logger\n            .getLogger(DownloadFromInviteFileSharingSession.class.getSimpleName());\n\n    private final long mTimestampSent;\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param chatSession the chat session\n     * @param fileTransferInfo the File transfer info document\n     * @param fileTransferId the File transfer Id\n     * @param contact the remote contact Id\n     * @param displayName the display name of the remote contact\n     * @param rcsSettings the RCS settings accessor\n     * @param messagingLog the messaging log accessor\n     * @param timestamp the timestamp\n     * @param timestampSent the timestamp sent\n     * @param contactManager the contact manager\n     */\n    public DownloadFromInviteFileSharingSession(InstantMessagingService imService,\n            ChatSession chatSession, FileTransferHttpInfoDocument fileTransferInfo,\n            String fileTransferId, ContactId contact, String displayName, RcsSettings rcsSettings,\n            MessagingLog messagingLog, long timestamp, long timestampSent,\n            ContactManager contactManager) {\n        // @formatter:off\n        super(imService,\n                fileTransferInfo.getLocalMmContent(),\n                fileTransferInfo.getExpiration(),\n                fileTransferInfo.getFileThumbnail() == null ? null : fileTransferInfo.getFileThumbnail().getLocalMmContent(fileTransferId),\n                getFileIconExpiration(fileTransferInfo.getFileThumbnail()),\n                contact,\n                chatSession.getContributionID(),\n                fileTransferId,\n                chatSession.isGroupChat(),\n                fileTransferInfo.getUri(),\n                rcsSettings,\n                messagingLog,\n                timestamp,\n                getRemoteSipId(chatSession),\n                contactManager);\n        // @formatter:on\n        mTimestampSent = timestampSent;\n        setRemoteDisplayName(displayName);\n        if (fileTransferInfo.getFileThumbnail() != null) {\n            mIconRemoteUri = fileTransferInfo.getFileThumbnail().getUri();\n        } else {\n            mIconRemoteUri = null;\n        }\n        if (shouldBeAutoAccepted()) {\n            setSessionAccepted();\n        }\n    }\n\n    private static long getFileIconExpiration(FileTransferHttpThumbnail thumbnailInfo) {\n        if (thumbnailInfo != null) {\n            return thumbnailInfo.getExpiration();\n        }\n        return FileTransferData.UNKNOWN_EXPIRATION;\n    }\n\n    /**\n     * Check if session should be auto accepted depending on settings and roaming conditions This\n     * method should only be called once per session\n     * \n     * @return true if file transfer should be auto accepted\n     */\n    private boolean shouldBeAutoAccepted() {\n        long ftWarnSize = mRcsSettings.getWarningMaxFileTransferSize();\n        if (ftWarnSize > 0 && getContent().getSize() > ftWarnSize) {\n            /*\n             * User should be warned about the potential charges associated to the transfer of a\n             * large file. Hence do not auto accept if file size is above the warning limit.\n             */\n            return false;\n        }\n        if (getImsService().getImsModule().isInRoaming()) {\n            return mRcsSettings.isFileTransferAutoAcceptedInRoaming();\n        }\n        return mRcsSettings.isFileTransferAutoAccepted();\n    }\n\n    /**\n     * Download file icon from network server.<br>\n     * Throws an exception if download fails.\n     * \n     * @throws FileAccessException\n     * @throws NetworkException\n     */\n    public void downloadFileIcon() throws NetworkException, FileAccessException {\n        mDownloadManager.downloadThumbnail(mIconRemoteUri, getFileicon());\n    }\n\n    @Override\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Initiate a HTTP file transfer session as terminating\");\n        }\n        List<ImsSessionListener> listeners = getListeners();\n        ContactId contact = getRemoteContact();\n        long fileExpiration = getFileExpiration();\n        try {\n            /* Check if session should be auto-accepted once */\n            if (isSessionAccepted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Received HTTP file transfer invitation marked for auto-accept\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((FileSharingSessionListener) listener).onSessionAutoAccepted(contact,\n                            getContent(), getFileicon(), getTimestamp(), mTimestampSent,\n                            fileExpiration, getIconExpiration());\n                }\n                Uri downloadServerAddress = mDownloadManager.getHttpServerAddr();\n                mMessagingLog.setFileDownloadAddress(getFileTransferId(), downloadServerAddress);\n                if (mRemoteInstanceId != null) {\n                    mMessagingLog.setRemoteSipId(getFileTransferId(), mRemoteInstanceId);\n                }\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"Received HTTP file transfer invitation marked for manual accept\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((FileSharingSessionListener) listener).onSessionInvited(contact, getContent(),\n                            getFileicon(), getTimestamp(), mTimestampSent, fileExpiration,\n                            getIconExpiration());\n                }\n                Uri downloadServerAddress = mDownloadManager.getHttpServerAddr();\n                mMessagingLog.setFileDownloadAddress(getFileTransferId(), downloadServerAddress);\n                if (mRemoteInstanceId != null) {\n                    mMessagingLog.setRemoteSipId(getFileTransferId(), mRemoteInstanceId);\n                }\n                /* Compute the delay before file validity expiration */\n                long delay = fileExpiration - System.currentTimeMillis();\n                if (delay <= 0) {\n                    if (logActivated) {\n                        sLogger.debug(\"File no more available on server: transfer rejected on timeout\");\n                    }\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact,\n                                TerminationReason.TERMINATION_BY_TIMEOUT);\n                    }\n                    return;\n                }\n                if (logActivated) {\n                    sLogger.debug(\"Accept manually file transfer tiemout=\".concat(Long\n                            .toString(delay)));\n                }\n                /* Wait invitation answer */\n                InvitationStatus answer = waitInvitationAnswer(delay);\n                switch (answer) {\n                    case INVITATION_REJECTED_DECLINE:\n                        /* Intentional fall through */\n                    case INVITATION_REJECTED_BUSY_HERE:\n                        if (logActivated) {\n                            sLogger.debug(\"Transfer has been rejected by user\");\n                        }\n                        /*\n                         * If session is rejected by user, session cannot be rejected at SIP level\n                         * (already accepted200OK)\n                         */\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_USER);\n                        }\n                        return;\n\n                    case INVITATION_TIMEOUT:\n                        if (logActivated) {\n                            sLogger.debug(\"Transfer has been rejected on timeout\");\n                        }\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_TIMEOUT);\n                        }\n                        return;\n\n                    case INVITATION_CANCELED:\n                        if (logActivated) {\n                            sLogger.debug(\"Http transfer has been rejected by remote.\");\n                        }\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_REMOTE);\n                        }\n                        return;\n\n                    case INVITATION_ACCEPTED:\n                        setSessionAccepted();\n                        for (ImsSessionListener listener : listeners) {\n                            (listener).onSessionAccepting(contact);\n                        }\n                        break;\n\n                    case INVITATION_REJECTED_BY_SYSTEM:\n                        if (logActivated) {\n                            sLogger.debug(\"Http transfer has aborted by system\");\n                        }\n                        removeSession();\n                        return;\n\n                    case INVITATION_DELETED:\n                        if (logActivated) {\n                            sLogger.debug(\"Session has been deleted\");\n                        }\n                        removeSession();\n                        return;\n\n                    default:\n                        throw new IllegalArgumentException(\n                                \"Unknown invitation answer in run; answer=\" + answer);\n\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Download failed for a file sessionId : \" + getSessionID()\n                    + \" with transferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n            return;\n\n        }\n        super.run();\n    }\n\n    private static String getRemoteSipId(ChatSession session) {\n        ContactHeader inviteContactHeader = (ContactHeader) session.getDialogPath().getInvite()\n                .getHeader(ContactHeader.NAME);\n        if (inviteContactHeader == null) {\n            return null;\n        }\n        return inviteContactHeader.getParameter(SipUtils.SIP_INSTANCE_PARAM);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/DownloadFromResumeFileSharingSession.java",
    "content": "/*******************************************************************************\nw * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeDownload;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Terminating file transfer HTTP session starting from system resuming (because core was\n * restarted).\n */\npublic class DownloadFromResumeFileSharingSession extends TerminatingHttpFileSharingSession {\n\n    private static final Logger sLogger = Logger\n            .getLogger(DownloadFromResumeFileSharingSession.class.getSimpleName());\n\n    private final FtHttpResumeDownload mResume;\n\n    /**\n     * Constructor create instance of session object to resume download\n     * \n     * @param imService InstantMessagingService\n     * @param content the content (url, mime-type and size)\n     * @param resume the data object in DB\n     * @param rcsSettings the RCS settings accessor\n     * @param messagingLog the messaging log accessor\n     * @param contactManager the contact manager\n     */\n    public DownloadFromResumeFileSharingSession(InstantMessagingService imService,\n            MmContent content, FtHttpResumeDownload resume, RcsSettings rcsSettings,\n            MessagingLog messagingLog, ContactManager contactManager) {\n        // @formatter:off\n        super(imService,\n                content,\n                resume.getFileExpiration(),\n                resume.getFileicon() != null ? FileTransferUtils.createIconContent(resume.getFileicon()) : null,\n                resume.getFileicon() != null ? resume.getIconExpiration() : FileTransferData.UNKNOWN_EXPIRATION,\n                resume.getContact(),\n                resume.getChatId(),\n                resume.getFileTransferId(),\n                resume.isGroupTransfer(),\n                resume.getServerAddress(),\n                rcsSettings,\n                messagingLog,\n                resume.getTimestamp(),\n                resume.getRemoteSipInstance(),\n                contactManager);\n        // @formatter:on\n        mResume = resume;\n        setSessionAccepted();\n    }\n\n    @Override\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Resume a HTTP file transfer session as terminating\");\n        }\n        try {\n            onHttpTransferStarted();\n            /* Resume download file from the HTTP server */\n            mDownloadManager.resumeDownload();\n            if (logActivated) {\n                sLogger.debug(\"Resume download success for \".concat(mResume.toString()));\n            }\n            /* Set file URL */\n            getContent().setUri(mDownloadManager.getDownloadedFileUri());\n            handleFileTransferred();\n            if (mImdnManager.isSendOneToOneDeliveryDisplayedReportsEnabled()) {\n                /* Send delivery report \"displayed\" */\n                sendDeliveryReport(ImdnDocument.DeliveryStatus.DISPLAYED,\n                        System.currentTimeMillis());\n            }\n        } catch (FileNotDownloadedException | IOException e) {\n            sLogger.error(\"Resume Download file has failed for \" + mResume, e);\n            /* Don't call handleError in case of Pause or Cancel */\n            if (mDownloadManager.isCancelled() || mDownloadManager.isPaused()) {\n                return;\n            }\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Resume Download file has failed for \" + mResume, e);\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/FileNotDownloadedException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\n\n/**\n * File Not Downloaded Exception\n */\npublic class FileNotDownloadedException extends Exception {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public FileNotDownloadedException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public FileNotDownloadedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/FileTransferHttpInfoDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\n\nimport android.net.Uri;\n\n/**\n * File transfer over HTTP info document\n * \n * @author vfml3370\n */\npublic class FileTransferHttpInfoDocument {\n    /**\n     * MIME type\n     */\n    public static final String MIME_TYPE = \"application/vnd.gsma.rcs-ft-http+xml\";\n\n    private int mSize = 0;\n    private String mMimeType;\n    private Uri mFile;\n    private long mExpiration = FileTransferData.UNKNOWN_EXPIRATION;\n    private FileTransferHttpThumbnail mFileIcon;\n    private String mFileName;\n    private Disposition mFileDisposition = FileTransfer.Disposition.ATTACH;\n    private int mPlayingLength = -1;\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings the RCS settings accessor\n     */\n    public FileTransferHttpInfoDocument(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    public FileTransferHttpInfoDocument(RcsSettings rcsSettings, Uri file, String fileName,\n            int size, String mimeType, long expiration, FileTransferHttpThumbnail fileIcon) {\n        this(rcsSettings);\n        mFile = file;\n        mFileName = fileName;\n        mSize = size;\n        mMimeType = mimeType;\n        mExpiration = expiration;\n        mFileIcon = fileIcon;\n    }\n\n    /**\n     * Sets file thumbnail\n     * \n     * @param thumbnail Thumbnail\n     */\n    public void setFileThumbnail(FileTransferHttpThumbnail thumbnail) {\n        mFileIcon = thumbnail;\n    }\n\n    /**\n     * Gets file thumbnail\n     * \n     * @return File thumbnail\n     */\n    public FileTransferHttpThumbnail getFileThumbnail() {\n        return mFileIcon;\n    }\n\n    /**\n     * Gets expiration\n     * \n     * @return expiration in milliseconds\n     */\n    public long getExpiration() {\n        return mExpiration;\n    }\n\n    /**\n     * Sets file expiration\n     * \n     * @param expiration in milliseconds\n     */\n    public void setExpiration(long expiration) {\n        mExpiration = expiration;\n    }\n\n    /**\n     * Gets file URI\n     * \n     * @return File URI\n     */\n    public Uri getUri() {\n        return mFile;\n    }\n\n    /**\n     * Sets file URI\n     * \n     * @param file the file Uri\n     */\n    public void setUri(Uri file) {\n        mFile = file;\n    }\n\n    /**\n     * Gets file mime type\n     * \n     * @return File mime type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    /**\n     * Sets file mime type\n     * \n     * @param mimeType File mime type\n     */\n    public void setMimeType(String mimeType) {\n        mMimeType = mimeType;\n    }\n\n    /**\n     * Gets file size\n     * \n     * @return File size\n     */\n    public int getSize() {\n        return mSize;\n    }\n\n    /**\n     * Sets file size\n     * \n     * @param size File size\n     */\n    public void setSize(int size) {\n        mSize = size;\n    }\n\n    /**\n     * Sets the fileName\n     * \n     * @param fileName FileName\n     */\n    public void setFilename(String fileName) {\n        mFileName = fileName;\n    }\n\n    /**\n     * Gets the fileName\n     * \n     * @return FileName\n     */\n    public String getFilename() {\n        return mFileName;\n    }\n\n    /**\n     * Sets the file disposition\n     *\n     * @param disposition File disposition\n     */\n    public void setFileDisposition(Disposition disposition) {\n        mFileDisposition = disposition;\n    }\n\n    /**\n     * Gets the file disposition\n     *\n     * @return File disposition\n     */\n    public Disposition getFileDisposition() {\n        return mFileDisposition;\n    }\n\n    /**\n     * Sets the playing length\n     *\n     * @param length Length in seconds\n     */\n    public void setPlayingLength(int length) {\n        mPlayingLength = length;\n    }\n\n    /**\n     * Gets the playing length or -1 if not set\n     *\n     * @return playing length in seconds\n     */\n    public int getPlayingLength() {\n        return mPlayingLength;\n    }\n\n    /**\n     * Gets local MmContent\n     * \n     * @return local MmContent\n     */\n    public MmContent getLocalMmContent() {\n        Uri file = ContentManager.generateUriForReceivedContent(mFileName, mMimeType, mRcsSettings);\n        MmContent content = ContentManager.createMmContent(file, mMimeType, mSize, mFileName);\n        if (Disposition.RENDER == mFileDisposition) {\n            content.setPlayable(true);\n        }\n        return content;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/FileTransferHttpResumeInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport android.net.Uri;\n\n/**\n * File transfer over HTTP info document\n * \n * @author hhff3235\n */\npublic class FileTransferHttpResumeInfo {\n    /**\n     * start-offset in bytes\n     */\n    private int mStart = 0;\n\n    /**\n     * end-offset in bytes\n     */\n    private int mEnd = 0;\n\n    /**\n     * HTTP upload Uri for the file\n     */\n    private Uri mFile;\n\n    /**\n     * @return the start\n     */\n    protected int getStart() {\n        return mStart;\n    }\n\n    /**\n     * @param start the start to set\n     */\n    protected void setStart(int start) {\n        mStart = start;\n    }\n\n    /**\n     * @return the end\n     */\n    protected int getEnd() {\n        return mEnd;\n    }\n\n    /**\n     * @param end the end to set\n     */\n    protected void setEnd(int end) {\n        mEnd = end;\n    }\n\n    /**\n     * @return the Uri\n     */\n    protected Uri getUri() {\n        return mFile;\n    }\n\n    /**\n     * @param file the Uri to set\n     */\n    protected void setUri(Uri file) {\n        mFile = file;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/FileTransferHttpThumbnail.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport android.net.Uri;\n\nimport java.io.File;\n\n/**\n * File transfer over HTTP thumbnail\n * \n * @author vfml3370\n */\npublic class FileTransferHttpThumbnail {\n\n    private int mSize = 0;\n\n    private String mMimeType;\n\n    private Uri mFileIcon;\n\n    private long mExpiration = FileTransferData.UNKNOWN_EXPIRATION;\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings the RCS settings accessor\n     */\n    public FileTransferHttpThumbnail(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    public FileTransferHttpThumbnail(RcsSettings rcsSettings, Uri fileIcon, String mimeType,\n            int size, long expiration) {\n        mRcsSettings = rcsSettings;\n        mFileIcon = fileIcon;\n        mMimeType = mimeType;\n        mSize = size;\n        mExpiration = expiration;\n    }\n\n    /**\n     * Gets expiration\n     * \n     * @return expiration in milliseconds\n     */\n    public long getExpiration() {\n        return mExpiration;\n    }\n\n    /**\n     * Sets expiration\n     * \n     * @param expiration the expiration\n     */\n    public void setExpiration(long expiration) {\n        mExpiration = expiration;\n    }\n\n    /**\n     * Gets URI\n     * \n     * @return URI\n     */\n    public Uri getUri() {\n        return mFileIcon;\n    }\n\n    /**\n     * Sets URI\n     * \n     * @param fileIcon URI\n     */\n    public void setUri(Uri fileIcon) {\n        mFileIcon = fileIcon;\n    }\n\n    /**\n     * Gets mime type\n     * \n     * @return mime type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    /**\n     * Sets mime type\n     * \n     * @param mimetype the mime-type\n     */\n    public void setMimeType(String mimetype) {\n        mMimeType = mimetype;\n    }\n\n    /**\n     * Gets size\n     * \n     * @return size\n     */\n    public int getSize() {\n        return mSize;\n    }\n\n    /**\n     * Sets size\n     * \n     * @param size the size\n     */\n    public void setSize(int size) {\n        mSize = size;\n    }\n\n    /**\n     * Gets local MmContent\n     * \n     * @param fileTransferId the file transfer ID\n     * @return local content\n     */\n    public MmContent getLocalMmContent(String fileTransferId) {\n        String iconName = FileTransferUtils.buildFileiconUrl(fileTransferId, mMimeType);\n        Uri file = Uri.fromFile(new File(mRcsSettings.getFileIconRootDirectory().concat(iconName)));\n        return ContentManager.createMmContent(file, mMimeType, mSize, iconName);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/FileTransferXmlParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2015 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\n\nimport android.net.Uri;\n\nimport org.xml.sax.SAXException;\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlPullParserFactory;\n\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.nio.charset.Charset;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n/**\n * A class to parse the XML descriptor containing the HTTP file transfer information.\n *\n * @author Philippe LEMORDANT\n */\npublic class FileTransferXmlParser {\n    // @formatter:off\n\n    /*\n    <?xml version=\"1.0\" encoding=UTF-8>\n    <file>\n    <file-info type=\"thumbnail\">\n                <file-size>[thumbnail size in bytes]</file-size>\n                <content-type>[MIME-type for thumbnail]</content-type>\n                <data url = \"[HTTPS URL for the thumbnail]\" until = \"[validity of the thumbnail]\"/>\n    </file-info>\n    <file-info type=\"file\" file-disposition=\"attach|render\">\n                <file-size>[file size in bytes]</file-size>\n                <file-name>[original file name]</file-name>\n                <content-type>[MIME-type for file]</content-type>\n                <am:playing-length>[duration of the rram]</am:playing-length>\n               <data url = \"[HTTPS URL for the file]\" until = \"[validity of the file]\"/>\n    </file-info>\n    <file>\n    */\n    /*\n     * Note: in the specification 'validity' refers to a timestamp.\n     * Term 'validity' is more suitable for a duration so we call it instead 'expiration' in the code.\n     *\n     */\n    // @formatter:on\n\n    private final RcsSettings mRcsSettings;\n    private final String mXmlSource;\n    private FileTransferHttpInfoDocument mFtInfo;\n    private FileTransferHttpThumbnail mThumbnailInfo;\n    private boolean mThumbnailProcessed;\n\n    /**\n     * Constructor\n     *\n     * @param xml the XML to be parsed\n     * @param rcsSettings the RCS settings accessor\n     */\n    public FileTransferXmlParser(byte[] xml, RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n        mXmlSource = new String(xml, Charset.forName(\"UTF8\"));\n    }\n\n    /**\n     * Parses the XML file transfer document\n     * \n     * @return FileTransferXmlParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n\n    public FileTransferXmlParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();\n            factory.setNamespaceAware(false);\n            XmlPullParser xpp = factory.newPullParser();\n            xpp.setInput(new StringReader(mXmlSource));\n            int eventType = xpp.getEventType();\n            String text = null;\n            while (eventType != XmlPullParser.END_DOCUMENT) {\n                String tagName = xpp.getName();\n                switch (eventType) {\n                    case XmlPullParser.START_TAG:\n                        if (\"file\".equalsIgnoreCase(tagName)) {\n                            if (mFtInfo == null) {\n                                mFtInfo = new FileTransferHttpInfoDocument(mRcsSettings);\n                            }\n                        } else if (\"file-info\".equalsIgnoreCase(tagName)) {\n                            if (mFtInfo == null) {\n                                break;\n                            }\n                            String type = xpp.getAttributeValue(null, \"type\");\n                            if (\"thumbnail\".equalsIgnoreCase(type)) {\n                                mThumbnailInfo = new FileTransferHttpThumbnail(mRcsSettings);\n\n                            } else if (\"file\".equalsIgnoreCase(type)) {\n                                mThumbnailProcessed = true;\n                                String typeDispo = xpp.getAttributeValue(null, \"file-disposition\");\n                                if (typeDispo != null) {\n                                    switch (typeDispo) {\n                                        case FileSharingSession.FILE_DISPOSITION_ATTACH:\n                                            mFtInfo.setFileDisposition(FileTransfer.Disposition.ATTACH);\n                                            break;\n                                        case FileSharingSession.FILE_DISPOSITION_RENDER:\n                                            mFtInfo.setFileDisposition(FileTransfer.Disposition.RENDER);\n                                            break;\n                                    }\n                                }\n                            }\n                        } else if (\"data\".equalsIgnoreCase(tagName)) {\n                            if (mFtInfo == null) {\n                                break;\n                            }\n                            String url = xpp.getAttributeValue(null, \"url\");\n                            String expiration = xpp.getAttributeValue(null, \"until\");\n                            if (mThumbnailProcessed) {\n                                mFtInfo.setUri(Uri.parse(url));\n                                mFtInfo.setExpiration(DateUtils.decodeDate(expiration));\n\n                            } else if (mThumbnailInfo != null) {\n                                mThumbnailProcessed = true;\n                                mThumbnailInfo.setUri(Uri.parse(url));\n                                mThumbnailInfo.setExpiration(DateUtils.decodeDate(expiration));\n                                mFtInfo.setFileThumbnail(mThumbnailInfo);\n                            }\n                        }\n                        break;\n\n                    case XmlPullParser.TEXT:\n                        text = xpp.getText().trim();\n                        break;\n\n                    case XmlPullParser.END_TAG:\n                        if (mFtInfo == null) {\n                            break;\n                        }\n                        if (text == null) {\n                            throw new ParseFailureException(\"Bad HTTP file transfer information \"\n                                    + mXmlSource);\n                        }\n                        if (\"file-name\".equalsIgnoreCase(tagName)) {\n                            if (mThumbnailProcessed) {\n                                mFtInfo.setFilename(text);\n                            }\n                        } else if (\"file-size\".equalsIgnoreCase(tagName)) {\n                            if (mThumbnailProcessed) {\n                                mFtInfo.setSize(Integer.parseInt(text));\n                            } else if (mThumbnailInfo != null) {\n                                mThumbnailInfo.setSize(Integer.parseInt(text));\n                            }\n                        } else if (\"content-type\".equalsIgnoreCase(tagName)) {\n                            if (mThumbnailProcessed) {\n                                mFtInfo.setMimeType(text);\n                            } else if (mThumbnailInfo != null) {\n                                mThumbnailInfo.setMimeType(text);\n                            }\n                        } else if (\"am:playing-length\".equalsIgnoreCase(tagName)) {\n                            mFtInfo.setPlayingLength(Integer.parseInt(text));\n                        }\n                        break;\n\n                    default:\n                        break;\n                }\n                eventType = xpp.next();\n            }\n            return this;\n\n        } catch (XmlPullParserException | IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    /**\n     * Get the file transfer information\n     * \n     * @return FileTransferHttpInfoDocument\n     */\n    public FileTransferHttpInfoDocument getFileTransferInfo() {\n        return mFtInfo;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/FtHttpResumeManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeDownload;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * File Transfer HTTP resume manager\n */\npublic class FtHttpResumeManager implements Runnable {\n\n    private static final Logger sLogger = Logger.getLogger(FtHttpResumeManager.class.getName());\n\n    private InstantMessagingService mImsService;\n    /**\n     * List of pending sessions to resume\n     */\n    private LinkedList<FtHttpResume> mListOfFtHttpResume;\n    private final RcsSettings mRcsSettings;\n    private final MessagingLog mMessagingLog;\n    private final ContactManager mContactManager;\n\n    /**\n     * Constructor\n     *\n     * @param instantMessagingService IMS service\n     * @param rcsSettings the RCS setting accessor\n     * @param messagingLog the messaging log accessor\n     * @param contactManager the contact manager accessor\n     */\n    public FtHttpResumeManager(InstantMessagingService instantMessagingService,\n            RcsSettings rcsSettings, MessagingLog messagingLog, ContactManager contactManager) {\n        mRcsSettings = rcsSettings;\n        mImsService = instantMessagingService;\n        mMessagingLog = messagingLog;\n        mContactManager = contactManager;\n    }\n\n    @Override\n    public void run() {\n        try {\n            /* Retrieve all resumable sessions */\n            List<FtHttpResume> transfersToResume = mMessagingLog\n                    .retrieveFileTransfersPausedBySystem();\n            if (!transfersToResume.isEmpty()) {\n                mListOfFtHttpResume = new LinkedList<>(transfersToResume);\n                processNext();\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Error retrieving resumable sessions!\", e);\n        }\n    }\n\n    /**\n     * resume next pending session\n     */\n    private void processNext() {\n        if (mListOfFtHttpResume.isEmpty())\n            return;\n        // Remove the oldest session from the list\n        /*\n         * FT HTTP session being resumed\n         */\n        FtHttpResume ftHttpResume = mListOfFtHttpResume.poll();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Resume FT HTTP \".concat(ftHttpResume.toString()));\n        }\n        switch (ftHttpResume.getDirection()) {\n            case INCOMING:\n                FtHttpResumeDownload downloadInfo = (FtHttpResumeDownload) ftHttpResume;\n                MmContent downloadContent = ContentManager.createMmContent(ftHttpResume.getFile(),\n                        ftHttpResume.getMimeType(), downloadInfo.getSize(),\n                        downloadInfo.getFileName());\n                final DownloadFromResumeFileSharingSession resumeDownload = new DownloadFromResumeFileSharingSession(\n                        mImsService, downloadContent, downloadInfo, mRcsSettings, mMessagingLog,\n                        mContactManager);\n                resumeDownload.addListener(getFileSharingSessionListener());\n                mImsService.resumeIncomingFileTransfer(resumeDownload,\n                        resumeDownload.isGroupFileTransfer());\n                resumeDownload.startSession();\n                break;\n\n            case OUTGOING:\n                FtHttpResumeUpload uploadInfo = (FtHttpResumeUpload) ftHttpResume;\n                MmContent uploadContent = ContentManager.createMmContent(uploadInfo.getFile(),\n                        uploadInfo.getMimeType(), uploadInfo.getSize(), uploadInfo.getFileName());\n                if (!ftHttpResume.isGroupTransfer()) {\n                    final ResumeUploadFileSharingSession resumeUpload = new ResumeUploadFileSharingSession(\n                            mImsService, uploadContent, uploadInfo, mRcsSettings, mMessagingLog,\n                            mContactManager);\n                    resumeUpload.addListener(getFileSharingSessionListener());\n                    mImsService.resumeOutgoingFileTransfer(resumeUpload, false);\n                    resumeUpload.startSession();\n                } else {\n                    final ResumeUploadGroupFileSharingSession resumeUpload = new ResumeUploadGroupFileSharingSession(\n                            mImsService, uploadContent, uploadInfo, mRcsSettings, mMessagingLog,\n                            mContactManager);\n                    resumeUpload.addListener(getFileSharingSessionListener());\n                    mImsService.resumeOutgoingFileTransfer(resumeUpload, true);\n                    resumeUpload.startSession();\n                }\n                break;\n\n            default:\n                break;\n        }\n    }\n\n    /**\n     * Create an event listener to handle end of session\n     * \n     * @return the File sharing event listener\n     */\n    private FileSharingSessionListener getFileSharingSessionListener() {\n        return new FileSharingSessionListener() {\n            AtomicBoolean fired = new AtomicBoolean(false);\n\n            @Override\n            public void onSessionStarted(ContactId contact) {\n            }\n\n            @Override\n            public void onSessionAborted(ContactId contact, TerminationReason reason) {\n                if (fired.compareAndSet(false, true)) {\n                    processNext();\n                }\n            }\n\n            @Override\n            public void onTransferProgress(ContactId contact, long currentSize, long totalSize) {\n            }\n\n            @Override\n            public void onTransferNotAllowedToSend(ContactId contact) {\n            }\n\n            @Override\n            public void onTransferError(FileSharingError error, ContactId contact) {\n                if (fired.compareAndSet(false, true)) {\n                    processNext();\n                }\n            }\n\n            @Override\n            public void onFileTransferred(MmContent content, ContactId contact,\n                    long fileExpiration, long fileIconExpiration, FileTransferProtocol ftProtocol) {\n                if (fired.compareAndSet(false, true)) {\n                    processNext();\n                }\n            }\n\n            @Override\n            public void onFileTransferResumed(ContactId contact) {\n            }\n\n            @Override\n            public void onSessionAccepting(ContactId contact) {\n            }\n\n            @Override\n            public void onFileTransferPausedByUser(ContactId contact) {\n            }\n\n            @Override\n            public void onFileTransferPausedBySystem(ContactId contact) {\n            }\n\n            @Override\n            public void onSessionRejected(ContactId contact, TerminationReason reason) {\n            }\n\n            @Override\n            public void onSessionInvited(ContactId contact, MmContent file, MmContent fileIcon,\n                    long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration) {\n            }\n\n            @Override\n            public void onSessionAutoAccepted(ContactId contact, MmContent file,\n                    MmContent fileIcon, long timestamp, long timestampSent, long fileExpiration,\n                    long fileIconExpiration) {\n            }\n\n            @Override\n            public void onHttpDownloadInfoAvailable() {\n\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/HttpDownloadManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.net.Uri;\n\nimport java.io.BufferedOutputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLHandshakeException;\n\n/**\n * HTTP upload manager\n * \n * @author jexa7410\n * @author yplo6403\n */\npublic class HttpDownloadManager extends HttpTransferManager {\n    /**\n     * Maximum value of retry\n     */\n    private final static int RETRY_MAX = 3;\n\n    /**\n     * File content to download\n     */\n    private final MmContent mContent;\n\n    /**\n     * File to be created\n     */\n    private final File mFile;\n\n    /**\n     * URI of file to be created\n     */\n    private final Uri mDownloadedFile;\n\n    /**\n     * Stream that writes the file\n     */\n    private BufferedOutputStream mFileDownloadStream;\n\n    private int mRetryCount = 0;\n\n    private static final Logger sLogger = Logger.getLogger(HttpDownloadManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param content File content to download\n     * @param listener HTTP transfer event listener\n     * @param httpServerAddress Server address from where file is downloaded\n     * @param rcsSettings the RCS settings accessor\n     */\n    public HttpDownloadManager(MmContent content, HttpTransferEventListener listener,\n            Uri httpServerAddress, RcsSettings rcsSettings) {\n        super(listener, httpServerAddress, rcsSettings);\n        mContent = content;\n        mDownloadedFile = content.getUri();\n        mFile = new File(mDownloadedFile.getPath());\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"HttpDownloadManager file from \" + httpServerAddress + \" length=\"\n                    + content.getSize());\n        }\n    }\n\n    /**\n     * Open output stream for download file\n     * \n     * @param file file path\n     * @return BufferedOutputStream\n     * @throws FileNotFoundException\n     */\n    private BufferedOutputStream openStreamForFile(File file) throws FileNotFoundException {\n        return new BufferedOutputStream(new FileOutputStream(file, true));\n    }\n\n    /**\n     * Returns complete file URI\n     * \n     * @return Uri of downloaded file\n     */\n    public Uri getDownloadedFileUri() {\n        return mDownloadedFile;\n    }\n\n    /**\n     * Download file\n     * \n     * @throws IOException\n     * @throws FileNotDownloadedException\n     * @throws NetworkException\n     */\n    public void downloadFile() throws IOException, FileNotDownloadedException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Download file \" + getHttpServerAddr());\n        }\n        if (mFileDownloadStream == null) {\n            mFileDownloadStream = openStreamForFile(mFile);\n        }\n        /* Send GET request */\n        if (isHttpTraceEnabled()) {\n            System.out.println(\">>> Send HTTP request:\\nGET \" + getHttpServerAddr());\n        }\n        try {\n            writeHttpContentToFile(new URL(getHttpServerAddr().toString()),\n                    new HashMap<String, String>());\n\n        } catch (SSLHandshakeException e) {\n            /*\n             * If there are issues during handshake between UE and server then we should not proceed\n             * any further with file download, we should immediately cancel the transfer, One on the\n             * possible case would be a certificate mismatch\n             */\n            throw e;\n\n        } catch (IOException e) {\n            /*\n             * Either the stream is currently not open or there has been a connection time out, In\n             * either cases we should pause downloading the file.\n             */\n            if (!isPaused() && !isCancelled()) {\n                pauseTransferBySystem();\n            }\n            throw e;\n\n        } catch (FileNotDownloadedException e) {\n            /* Execute request with retry procedure */\n            /*\n             * Something went wrong during file download, either the HTTP response was not as\n             * expected one or the file was corrupted, In either case we should retry file download\n             * for RETRY_MAX\n             */\n            if (mRetryCount < RETRY_MAX && !isCancelled() && !isPaused()) {\n                mRetryCount++;\n                downloadFile();\n            } else {\n                throw e;\n            }\n        }\n    }\n\n    /**\n     * Write the content fetched from HTTP request onto file\n     * \n     * @param url the URL of the file to download on the content server\n     * @param properties the HTTP properties\n     * @throws IOException\n     * @throws FileNotDownloadedException\n     * @throws NetworkException\n     */\n    private void writeHttpContentToFile(URL url, Map<String, String> properties)\n            throws IOException, FileNotDownloadedException, NetworkException {\n        HttpURLConnection urlConnection = null;\n        try {\n            /* Execute HTTP Request */\n            urlConnection = openHttpConnection(url, properties);\n            int statusCode = urlConnection.getResponseCode();\n            String message = urlConnection.getResponseMessage();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"HTTP get file response: \" + statusCode + \" (\" + message + \")\");\n            }\n            if (isHttpTraceEnabled()) {\n                System.out.println(\"<<< Receive HTTP response: \\n\" + statusCode + \" \" + statusCode);\n            }\n            int receivedBytes = 0;\n            /* Analyze HTTP response */\n            switch (statusCode) {\n                case HttpURLConnection.HTTP_OK:\n                    break;\n                case HttpURLConnection.HTTP_PARTIAL:\n                    receivedBytes = Long.valueOf(mFile.length()).intValue();\n                    break;\n                default:\n                    throw new FileNotDownloadedException(\"Unhandled http response code : \"\n                            + statusCode + \" for file download from server!\");\n            }\n            /* Read content */\n            byte[] buffer = new byte[CHUNK_MAX_SIZE];\n            InputStream input = urlConnection.getInputStream();\n            int num;\n            while ((num = input.read(buffer)) != -1 && !isCancelled() && !isPaused()) {\n                receivedBytes += num;\n                getListener().onHttpTransferProgress(receivedBytes, mContent.getSize());\n                mFileDownloadStream.write(buffer, 0, num);\n            }\n            /*\n             * Check if the file is already paused, If it is then its still a partial download and\n             * hence we should not delete the file.\n             */\n            if (isPaused()) {\n                throw new FileNotDownloadedException(\n                        \"Download file paused, the file is not complete!\");\n            }\n            /*\n             * Check if we are able to download the file properly by comparing the file content\n             * size, also make sure that the download is not cancelled\n             */\n            if (!isCancelled() && receivedBytes != mContent.getSize()) {\n                /* Delete file as download is not successful */\n                mFile.delete();\n                throw new FileNotDownloadedException(\n                        \"Download file error, the file is not complete!\");\n            }\n            FileFactory.getFactory().updateMediaStorage(mDownloadedFile.getEncodedPath());\n        } finally {\n            CloseableUtils.tryToClose(mFileDownloadStream);\n            mFileDownloadStream = null;\n            if (urlConnection != null) {\n                urlConnection.disconnect();\n            }\n        }\n    }\n\n    /**\n     * Download the thumbnail and save it\n     * \n     * @param iconUri the remote URI of the file icon\n     * @param fileIcon the local descriptor\n     * @throws NetworkException\n     * @throws FileAccessException\n     */\n    public void downloadThumbnail(Uri iconUri, MmContent fileIcon) throws NetworkException,\n            FileAccessException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Download file icon from \".concat(getHttpServerAddr().toString()));\n        }\n        if (isHttpTraceEnabled()) {\n            System.out.println(\">>> Send HTTP request:\\nGET \" + iconUri);\n        }\n        ByteArrayOutputStream baos = null;\n        try {\n            baos = getThumbnail(new URL(iconUri.toString()));\n            /* Save data to file on disk */\n            fileIcon.writeData2File(baos.toByteArray());\n\n        } catch (MalformedURLException e) {\n            throw new IllegalArgumentException(\"Failed to download thumbnail for uri : \" + iconUri,\n                    e);\n\n        } finally {\n            CloseableUtils.tryToClose(baos);\n            if (fileIcon != null) {\n                fileIcon.closeFile();\n            }\n        }\n    }\n\n    /**\n     * Get the thumbnail\n     * \n     * @param url the URL of the file icon on the content server\n     * @throws NetworkException\n     */\n    private ByteArrayOutputStream getThumbnail(URL url) throws NetworkException {\n        HttpURLConnection urlConnection = null;\n        ByteArrayOutputStream bOutputStream = null;\n        try {\n            urlConnection = openHttpConnection(url, new HashMap<String, String>());\n            int statusCode = urlConnection.getResponseCode();\n            String message = urlConnection.getResponseMessage();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"HTTP get thumbnail response: \" + statusCode + \" (\" + message + \")\");\n            }\n            if (isHttpTraceEnabled()) {\n                System.out.println(\"<<< Receive HTTP response:\\n\" + statusCode + \" \" + statusCode);\n            }\n            if (HttpURLConnection.HTTP_OK == statusCode) {\n                byte[] buffer = new byte[CHUNK_MAX_SIZE];\n                bOutputStream = new ByteArrayOutputStream();\n                InputStream input = urlConnection.getInputStream();\n                int num;\n                while ((num = input.read(buffer)) != -1) {\n                    bOutputStream.write(buffer, 0, num);\n                    if (isCancelled()) {\n                        break;\n                    }\n                }\n                return bOutputStream;\n            }\n            throw new NetworkException(\"Invalid statuscode '\" + statusCode\n                    + \"' received from server!\");\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to get thumbnail!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(bOutputStream);\n            if (urlConnection != null) {\n                urlConnection.disconnect();\n            }\n        }\n    }\n\n    /**\n     * Resume FToHTTP download\n     * \n     * @throws IOException\n     * @throws FileNotDownloadedException\n     * @throws NetworkException\n     */\n    public void resumeDownload() throws IOException, FileNotDownloadedException, NetworkException {\n        if (mFileDownloadStream == null) {\n            mFileDownloadStream = openStreamForFile(mFile);\n        }\n        resumeTransfer();\n        Uri serverAddress = getHttpServerAddr();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Resume Download file \" + serverAddress + \" from byte \" + mFile.length());\n        }\n        /* Send GET request */\n        long downloadedLength = mFile.length();\n        long completeSize = mContent.getSize();\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"Range\", \"bytes=\" + downloadedLength + \"-\" + completeSize);\n        if (isHttpTraceEnabled()) {\n            System.out.println(\">>> Send HTTP request:\\n GET \" + serverAddress);\n        }\n        try {\n            writeHttpContentToFile(new URL(serverAddress.toString()), properties);\n\n        } catch (SSLHandshakeException e) {\n            /*\n             * If there are issues during handshake between UE and server then we should not proceed\n             * any further with file download, we should immediately cancel the transfer, One on the\n             * possible case would be a certificate mismatch\n             */\n            throw e;\n\n        } catch (IOException e) {\n            /*\n             * Either the stream is currently not open or there has been a connection time out, In\n             * either cases we should pause downloading the file.\n             */\n            if (!isPaused() && !isCancelled()) {\n                pauseTransferBySystem();\n            }\n            throw e;\n\n        } catch (FileNotDownloadedException e) {\n            /* Execute request with retry procedure */\n            /*\n             * Something went wrong during file download, either the HTTP response was not as\n             * expected one or the file was corrupted, In either case we should retry file download\n             * for RETRY_MAX\n             */\n            if (mRetryCount < RETRY_MAX && !isCancelled() && !isPaused()) {\n                mRetryCount++;\n                downloadFile();\n            } else {\n                throw e;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/HttpFileTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\n/**\n * Abstract file transfer HTTP session\n * \n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic abstract class HttpFileTransferSession extends FileSharingSession implements\n        HttpTransferEventListener {\n\n    /**\n     * HttpFileTransferSession state\n     */\n    public enum State {\n\n        /**\n         * Session is pending (not yet accepted by a final response by the remote)\n         */\n        PENDING,\n\n        /**\n         * Session has been established (i.e. 200 OK/ACK exchanged)\n         */\n        ESTABLISHED\n    }\n\n    private State mSessionState;\n\n    protected long mFileExpiration;\n\n    protected long mIconExpiration;\n\n    protected final MessagingLog mMessagingLog;\n\n    private static final Logger sLogger = Logger.getLogger(HttpFileTransferSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param content Content to share\n     * @param contact Remote contact identifier\n     * @param remoteContact the remote contact URI\n     * @param fileIcon Content of file icon\n     * @param chatContributionId Chat contribution Id\n     * @param fileTransferId File transfer Id\n     * @param rcsSettings The RCS settings accessor\n     * @param messagingLog The messaging log accessor\n     * @param timestamp Local timestamp for the session\n     * @param fileExpiration The file expiration\n     * @param iconExpiration The file icon expiration\n     * @param contactManager The contact manager accessor\n     */\n    public HttpFileTransferSession(InstantMessagingService imService, MmContent content,\n            ContactId contact, Uri remoteContact, MmContent fileIcon, String chatContributionId,\n            String fileTransferId, RcsSettings rcsSettings, MessagingLog messagingLog,\n            long timestamp, long fileExpiration, long iconExpiration, ContactManager contactManager) {\n        super(imService, content, contact, remoteContact, fileIcon, fileTransferId, rcsSettings,\n                timestamp, contactManager);\n\n        setContributionID(chatContributionId);\n        mSessionState = State.PENDING;\n        mFileExpiration = fileExpiration;\n        mIconExpiration = iconExpiration;\n        mMessagingLog = messagingLog;\n    }\n\n    @Override\n    public boolean isHttpTransfer() {\n        return true;\n    }\n\n    @Override\n    public long getFileExpiration() {\n        return mFileExpiration;\n    }\n\n    @Override\n    public long getIconExpiration() {\n        return mIconExpiration;\n    }\n\n    @Override\n    public SipRequest createInvite() throws PayloadException {\n        // Not used here\n        return null;\n    }\n\n    protected void closeHttpSession(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        interruptSession();\n        closeSession(reason);\n        removeSession();\n    }\n\n    @Override\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer error: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        removeSession();\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onTransferError(new FileSharingError(error),\n                    contact);\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Not used here */\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Not used here */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        /* Not used here */\n    }\n\n    @Override\n    public void closeMediaSession() {\n        /* Not used here */\n    }\n\n    /**\n     * Handle file transfered. In case of file transfer over MSRP, the terminating side has received\n     * the file, but in case of file transfer over HTTP, only the content server has received the\n     * file.\n     */\n    public void handleFileTransferred() {\n        setFileTransferred();\n        removeSession();\n\n        ContactId contact = getRemoteContact();\n        MmContent content = getContent();\n        long fileExpiration = getFileExpiration();\n        long fileIconExpiration = getIconExpiration();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onFileTransferred(content, contact,\n                    fileExpiration, fileIconExpiration, FileTransferProtocol.HTTP);\n        }\n    }\n\n    @Override\n    public void onHttpTransferProgress(long currentSize, long totalSize) {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onTransferProgress(contact, currentSize,\n                    totalSize);\n        }\n    }\n\n    @Override\n    public void onHttpTransferNotAllowedToSend() {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onTransferNotAllowedToSend(contact);\n        }\n    }\n\n    @Override\n    public void onHttpTransferStarted() {\n        mSessionState = State.ESTABLISHED;\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionStarted(contact);\n        }\n    }\n\n    @Override\n    public void onHttpTransferPausedByUser() {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onFileTransferPausedByUser(contact);\n        }\n    }\n\n    @Override\n    public void onHttpTransferPausedBySystem() {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onFileTransferPausedBySystem(contact);\n        }\n    }\n\n    @Override\n    public void onHttpTransferResumed() {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onFileTransferResumed(contact);\n        }\n    }\n\n    /**\n     * Handle the HTTP download information availability event for upload file transfer.\n     */\n    public void handleHttpDownloadInfoAvailable() {\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onHttpDownloadInfoAvailable();\n        }\n    }\n\n    /**\n     * Get session state\n     * \n     * @return State\n     */\n    public State getSessionState() {\n        return mSessionState;\n    }\n\n    /**\n     * Pausing file transfer Implementation should be overridden in subclasses\n     */\n    public abstract void onPause();\n\n    /**\n     * Resuming file transfer Implementation should be overridden in subclasses\n     */\n    public abstract void onResume();\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        super.receiveBye(bye);\n        ContactId remote = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionAborted(remote, TerminationReason.TERMINATION_BY_REMOTE);\n        }\n        getImsService().getImsModule().getCapabilityService().requestContactCapabilities(remote);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/HttpTransferEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\n/**\n * HTTP transfer event listener\n * \n * @author B. JOGUET\n */\npublic interface HttpTransferEventListener {\n    /**\n     * HTTP transfer started\n     */\n    void onHttpTransferStarted();\n\n    /**\n     * HTTP transfer paused by user\n     */\n    void onHttpTransferPausedByUser();\n\n    /**\n     * HTTP transfer paused by system\n     */\n    void onHttpTransferPausedBySystem();\n\n    /**\n     * HTTP transfer resumed\n     */\n    void onHttpTransferResumed();\n\n    /**\n     * HTTP transfer progress\n     * \n     * @param currentSize Current transfered size in bytes\n     * @param totalSize Total size in bytes\n     */\n    void onHttpTransferProgress(long currentSize, long totalSize);\n\n    /**\n     * HTTP transfer not allowed to send\n     */\n    void onHttpTransferNotAllowedToSend();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/HttpTransferManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.net.Uri;\n\nimport java.io.IOException;\nimport java.net.CookieHandler;\nimport java.net.CookieManager;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * Abstract HTTP transfer manager\n * \n * @author vfml3370\n */\npublic abstract class HttpTransferManager {\n    /**\n     * Max chunk size\n     */\n    public static final int CHUNK_MAX_SIZE = 10 * 1024;\n\n    private static boolean sHttpTraceEnabled = false;\n\n    private final Uri mServerAddr;\n\n    private final String mServerLogin;\n\n    private final String mServerPwd;\n\n    /**\n     * HTTP transfer event listener\n     */\n    private final HttpTransferEventListener mListener;\n\n    /**\n     * Cancellation flag\n     */\n    private boolean mIsCancelled = false;\n\n    /**\n     * Pause flag\n     */\n    private boolean mIsPaused = false;\n\n    protected final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(HttpTransferManager.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param listener HTTP event listener\n     * @param rcsSettings the RCS settings accessor\n     */\n    public HttpTransferManager(HttpTransferEventListener listener, RcsSettings rcsSettings) {\n        this(listener, rcsSettings.getFtHttpServer(), rcsSettings);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param listener HTTP event listener\n     * @param address HTTP server address\n     * @param rcsSettings the RCS settings accessor\n     */\n    public HttpTransferManager(HttpTransferEventListener listener, Uri address,\n            RcsSettings rcsSettings) {\n        mListener = listener;\n        mServerAddr = address;\n        mServerLogin = rcsSettings.getFtHttpLogin();\n        mServerPwd = rcsSettings.getFtHttpPassword();\n        mRcsSettings = rcsSettings;\n        CookieManager cookieManager = new CookieManager();\n        CookieHandler.setDefault(cookieManager);\n    }\n\n    /**\n     * Returns the transfer event listener\n     * \n     * @return Listener\n     */\n    public HttpTransferEventListener getListener() {\n        return mListener;\n    }\n\n    /**\n     * Returns HTTP server address\n     * \n     * @return Address\n     */\n    public Uri getHttpServerAddr() {\n        return mServerAddr;\n    }\n\n    /**\n     * Returns HTTP server login\n     * \n     * @return Login\n     */\n    public String getHttpServerLogin() {\n        return mServerLogin;\n    }\n\n    /**\n     * Returns HTTP server password\n     * \n     * @return Password\n     */\n    public String getHttpServerPwd() {\n        return mServerPwd;\n    }\n\n    /**\n     * Interrupts file transfer\n     */\n    public void interrupt() {\n        if (sLogger.isActivated()) {\n            sLogger.warn(\"interrupting transfer\");\n        }\n        mIsCancelled = true;\n    }\n\n    /**\n     * Interrupts file transfer\n     */\n    public void pauseTransferByUser() {\n        if (sLogger.isActivated()) {\n            sLogger.warn(\"User is pausing transfer\");\n        }\n        mIsPaused = true;\n        getListener().onHttpTransferPausedByUser();\n    }\n\n    /**\n     * Interrupts file transfer\n     */\n    public void pauseTransferBySystem() {\n        if (sLogger.isActivated()) {\n            sLogger.warn(\"System is pausing transfer\");\n        }\n        mIsPaused = true;\n        getListener().onHttpTransferPausedBySystem();\n    }\n\n    /**\n     * Resuming upload so resetting cancelled boolean\n     */\n    public void resumeTransfer() {\n        if (sLogger.isActivated()) {\n            sLogger.warn(\"Transfer is resuming\");\n        }\n        mIsCancelled = false;\n        mIsPaused = false;\n        getListener().onHttpTransferResumed();\n    }\n\n    /**\n     * Return whether or not the file transfer has been cancelled\n     * \n     * @return Boolean\n     */\n    public boolean isCancelled() {\n        return mIsCancelled;\n    }\n\n    /**\n     * Return whether or not the file transfer has been cancelled\n     * \n     * @return Boolean\n     */\n    public boolean isPaused() {\n        return mIsPaused;\n    }\n\n    /**\n     * Open HTTP connection\n     * \n     * @param url the URL to connect\n     * @param properties HTTP properties to set\n     * @return HttpURLConnection\n     * @throws NetworkException\n     */\n    protected HttpURLConnection openHttpConnection(URL url, Map<String, String> properties)\n            throws NetworkException {\n        try {\n            HttpURLConnection cnx = (HttpURLConnection) url.openConnection();\n            for (Entry<String, String> header : properties.entrySet()) {\n                cnx.setRequestProperty(header.getKey(), header.getValue());\n            }\n            cnx.setRequestProperty(\"User-Agent\", SipUtils.userAgentString());\n            return cnx;\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to open http connection with url : \" + url, e);\n        }\n    }\n\n    /**\n     * Checks if HTTP trace is enabled\n     * \n     * @return True if HTTP trace is enabled\n     */\n    public static boolean isHttpTraceEnabled() {\n        return sHttpTraceEnabled;\n    }\n\n    /**\n     * Sets HTTP trace enabled\n     * \n     * @param enabled True if HTTP trace is enabled\n     */\n    public static void setHttpTraceEnabled(boolean enabled) {\n        sHttpTraceEnabled = enabled;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/HttpUploadManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\nimport static com.gsma.rcs.utils.StringUtils.UTF8_STR;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.http.HttpAuthenticationAgent;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.StringUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.net.Uri;\n\nimport org.xml.sax.SAXException;\n\nimport java.io.BufferedReader;\nimport java.io.DataOutputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.net.URLEncoder;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n/**\n * HTTP upload manager\n * \n * @author jexa7410\n * @author hhff3235\n * @author YPLO6403\n */\npublic class HttpUploadManager extends HttpTransferManager {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    /**\n     * Two hyphens\n     */\n    private final static String TWO_HYPENS = \"--\";\n\n    /**\n     * End of line\n     */\n    private final static String LINE_END = \"\\r\\n\";\n\n    /**\n     * Maximum value of retry\n     */\n    private final static int RETRY_MAX = 3;\n\n    /**\n     * GET is to get Download info (use for resume call flow)\n     */\n    private static final String DOWNLOAD_INFO_REQUEST = \"&get_download_info\";\n\n    /**\n     * GET is to get upload resume info\n     */\n    private static final String UPLOAD_INFO_REQUEST = \"&get_upload_info\";\n\n    private static final int HTTP_READ_TIMEOUT = 5000;\n\n    /**\n     * File content to upload\n     */\n    private final MmContent mContent;\n\n    /**\n     * File icon content to upload\n     */\n    private final MmContent mFileIcon;\n\n    /**\n     * TID of the upload transfer\n     */\n    private final String mTId;\n\n    private int mRetryCount = 0;\n\n    private HttpAuthenticationAgent mAuth;\n\n    private static final Logger sLogger = Logger.getLogger(HttpUploadManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param content File content to upload\n     * @param fileIcon content of the file icon\n     * @param listener HTTP transfer event listener\n     * @param tId TID of the upload\n     * @param rcsSettings the RCS settings accessor\n     */\n    public HttpUploadManager(MmContent content, MmContent fileIcon,\n            HttpUploadTransferEventListener listener, String tId, RcsSettings rcsSettings) {\n        super(listener, rcsSettings);\n        mContent = content;\n        mFileIcon = fileIcon;\n        mTId = tId;\n    }\n\n    private long getRetryTimeout(URLConnection connection) {\n        try {\n            return Long.parseLong(connection.getHeaderField(\"Retry-After\"))\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n        } catch (NumberFormatException e) {\n            return 0L;\n        }\n    }\n\n    /**\n     * Upload a file\n     * \n     * @return XML result or null if upload failed\n     * @throws IOException\n     * @throws NetworkException\n     */\n    public byte[] uploadFile() throws IOException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Upload file \" + mContent.getUri() + \" TID=\" + mTId);\n        }\n        /* Send a first POST request */\n        URL url = new URL(getHttpServerAddr().toString());\n        HttpURLConnection urlConnection = null;\n        try {\n            urlConnection = openHttpConnection(url, new HashMap<String, String>());\n            urlConnection.setDoInput(true);\n            urlConnection.setDoOutput(true);\n            urlConnection.setRequestMethod(\"POST\");\n            urlConnection.setReadTimeout(HTTP_READ_TIMEOUT);\n            urlConnection.setChunkedStreamingMode(CHUNK_MAX_SIZE);\n            if (isHttpTraceEnabled()) {\n                System.out.println(\">>> Send HTTP request:\\nPOST \" + url);\n            }\n            int statusCode = urlConnection.getResponseCode();\n            String message = urlConnection.getResponseMessage();\n            /* Check response status code */\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"First POST response: \" + statusCode + \" (\" + message + \")\");\n            }\n            switch (statusCode) {\n                case HttpURLConnection.HTTP_UNAUTHORIZED:\n                    /* AUTHENTICATION REQUIRED: 401 */\n                    String authHeader = urlConnection.getHeaderField(\"www-authenticate\");\n                    if (StringUtils.isEmpty(authHeader)) {\n                        throw new IOException(\"headers malformed in 401 response\");\n                    }\n                    mAuth = new HttpAuthenticationAgent(getHttpServerLogin(), getHttpServerPwd());\n                    mAuth.readWwwAuthenticateHeader(authHeader);\n                    break;\n\n                case HttpURLConnection.HTTP_NO_CONTENT:\n                    /* NO CONTENT : 204 response if authentication is not required */\n                    break;\n\n                case HttpURLConnection.HTTP_UNAVAILABLE:\n                    /* SERVICE_UNAVAILABLE : 503 - check retry-after header */\n                    long retryAfter = getRetryTimeout(urlConnection);\n                    if (retryAfter > 0) {\n                        try {\n                            Thread.sleep(retryAfter);\n                        } catch (InterruptedException e) {\n                            /* Nothing to do */\n                        }\n                    }\n                    /* No break to do the retry */\n                    //$FALL-THROUGH$\n                default:\n                    /* Retry procedure */\n                    if (mRetryCount < RETRY_MAX) {\n                        mRetryCount++;\n                        return uploadFile();\n                    }\n                    throw new IOException(\"Unable to upload file URI \" + mContent.getUri() + \"!\");\n            }\n            if (isCancelled()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"File transfer cancelled by user\");\n                }\n                return null;\n            }\n            /* Send a second POST request */\n            return sendMultipartPost(url);\n\n        } finally {\n            if (urlConnection != null) {\n                urlConnection.disconnect();\n            }\n        }\n    }\n\n    /**\n     * Create and Send the second POST\n     * \n     * @return byte[] the response containing the download file\n     * @throws IOException\n     * @throws NetworkException\n     */\n    private byte[] sendMultipartPost(URL url) throws IOException, NetworkException {\n        boolean httpTraceEnabled = isHttpTraceEnabled();\n        DataOutputStream outputStream = null;\n        HttpURLConnection connection = null;\n        Map<String, String> headers = new HashMap<>();\n        headers.put(\"Connection\", \"Keep-Alive\");\n        headers.put(\"Content-Type\", \"multipart/form-data; boundary=\" + BOUNDARY_TAG);\n        try {\n            connection = openHttpConnection(url, headers);\n            connection.setDoInput(true);\n            connection.setReadTimeout(HTTP_READ_TIMEOUT);\n            connection.setChunkedStreamingMode(CHUNK_MAX_SIZE);\n            connection.setRequestMethod(\"POST\");\n            /* Construct the Body */\n            String body = generateTidMultipart();\n            /* Update authentication agent */\n            if (mAuth != null) {\n                String authValue = mAuth.generateAuthorizationHeaderValue(\"POST\", url.getPath(),\n                        body);\n                connection.setRequestProperty(\"Authorization\", authValue);\n            }\n            if (httpTraceEnabled) {\n                StringBuilder trace = new StringBuilder(\">>> Send HTTP request:\\nPOST \")\n                        .append(url);\n                Map<String, List<String>> properties = connection.getRequestProperties();\n                for (Entry<String, List<String>> property : properties.entrySet()) {\n                    trace.append(\"\\n\").append(property.getKey()).append(\": \")\n                            .append(property.getValue());\n                }\n                trace.append(\"\\n\").append(body);\n                System.out.println(trace);\n            }\n            /* Create the DataOutputStream and start writing its body */\n            outputStream = new DataOutputStream(connection.getOutputStream());\n            outputStream.writeBytes(body);\n            /* Add file icon */\n            if (mFileIcon != null && mFileIcon.getSize() > 0) {\n                writeThumbnailMultipart(outputStream);\n            }\n            HttpTransferEventListener listeners = getListener();\n            /* Save Transfer ID into provider: from this point, resuming is possible. */\n            ((HttpUploadTransferEventListener) listeners).uploadStarted();\n            /*\n             * Upload resume can only be managed by HTTP Content Server if a transaction id (TID)\n             * has been defined during initial upload.\n             */\n            listeners.onHttpTransferStarted();\n            try {\n                /* Add File */\n                writeFileMultipart(outputStream, mContent.getUri());\n                if (isCancelled() || isPaused()) {\n                    return null;\n                }\n                /*\n                 * if the upload is cancelled or paused, we don't send the last boundary to get bad\n                 * request\n                 */\n                outputStream.writeBytes(TWO_HYPENS + BOUNDARY_TAG + TWO_HYPENS);\n                /* Check response status code */\n                int responseCode = connection.getResponseCode();\n                String message = connection.getResponseMessage();\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Second POST response \" + responseCode + \" (\" + message + \")\");\n                }\n                byte[] result = null;\n                boolean success = false;\n                boolean retry = false;\n                if (httpTraceEnabled) {\n                    String trace = \"<<< Receive HTTP response:\" + responseCode + \" \" + message;\n                    System.out.println(trace);\n                }\n                switch (responseCode) {\n                    case HttpURLConnection.HTTP_OK:\n                        success = true;\n                        InputStream inputStream = connection.getInputStream();\n                        result = convertStreamToString(inputStream);\n                        if (httpTraceEnabled) {\n                            System.out.println(\"\\n\" + new String(result));\n                        }\n                        break;\n                    case HttpURLConnection.HTTP_UNAVAILABLE:\n                        long retryAfter = getRetryTimeout(connection);\n                        if (retryAfter > 0) {\n                            try {\n                                Thread.sleep(retryAfter);\n                                /* Retry procedure */\n                                if (mRetryCount < RETRY_MAX) {\n                                    mRetryCount++;\n                                    retry = true;\n                                }\n                            } catch (InterruptedException ignore) {\n                                /* Nothing to do, ignore the exception */\n                            }\n                        }\n                        break;\n                    default:\n                        break; /* no success, no retry */\n                }\n                if (success) {\n                    return result;\n                } else if (retry) {\n                    return sendMultipartPost(url);\n                } else {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"File Upload aborted, Received \" + responseCode\n                                + \" from server\");\n                    }\n                    return null;\n                }\n            } catch (IOException e) {\n                /*\n                 * When there is a connection problem causing transfer terminated, state should be\n                 * set to paused.\n                 */\n                if (!isPaused() && !isCancelled()) {\n                    pauseTransferBySystem();\n                }\n                throw e;\n\n            } catch (SecurityException e) {\n                /*\n                 * Note! This is needed since this can be called during dequeuing.\n                 */\n                if (sLogger.isActivated()) {\n                    sLogger.error(\"Upload has failed due to that the file is not accessible!\", e);\n                }\n                listeners.onHttpTransferNotAllowedToSend();\n                return null;\n            }\n        } finally {\n            CloseableUtils.tryToClose(outputStream);\n            if (connection != null) {\n                connection.disconnect();\n            }\n        }\n    }\n\n    /**\n     * Write the thumbnail multipart\n     * \n     * @param outputStream DataOutputStream to write to\n     * @throws IOException\n     */\n    private void writeThumbnailMultipart(DataOutputStream outputStream) throws IOException {\n        long size = mFileIcon.getSize();\n        Uri fileIcon = mFileIcon.getUri();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Write file icon \" + fileIcon + \" (size=\" + size + \")\");\n        }\n        FileInputStream fileInputStream = null;\n        try {\n            fileInputStream = (FileInputStream) AndroidFactory.getApplicationContext()\n                    .getContentResolver().openInputStream(fileIcon);\n            int bufferSize = (int) size;\n            byte[] fileIconData = new byte[bufferSize];\n            if (size != fileInputStream.read(fileIconData, 0, bufferSize)) {\n                throw new IOException(\"Unable to read fileIcon from '\" + fileIcon + \"'!\");\n            }\n            outputStream.writeBytes(TWO_HYPENS + BOUNDARY_TAG + LINE_END);\n            outputStream\n                    .writeBytes(\"Content-Disposition: form-data; name=\\\"Thumbnail\\\"; filename=\\\"thumb_\"\n                            + mContent.getName() + \"\\\"\" + LINE_END);\n            outputStream.writeBytes(\"Content-Type: image/jpeg\".concat(LINE_END));\n            outputStream.writeBytes(\"Content-Length: \".concat(Long.toString(size)));\n            outputStream.writeBytes(LINE_END.concat(LINE_END));\n            outputStream.write(fileIconData);\n            outputStream.writeBytes(LINE_END);\n        } finally {\n            CloseableUtils.tryToClose(fileInputStream);\n        }\n    }\n\n    /**\n     * Generate the TID multipart\n     * \n     * @return tid TID header\n     */\n    private String generateTidMultipart() {\n        return TWO_HYPENS + BOUNDARY_TAG + LINE_END\n                + \"Content-Disposition: form-data; name=\\\"tid\\\"\" + LINE_END\n                + \"Content-Type: text/plain\" + LINE_END + \"Content-Length: \" + mTId.length()\n                + LINE_END + LINE_END + mTId + LINE_END;\n    }\n\n    /**\n     * Write the file multipart\n     * \n     * @param outputStream DataOutputStream to write to\n     * @param file File Uri\n     * @throws IOException\n     */\n    private void writeFileMultipart(DataOutputStream outputStream, Uri file) throws IOException {\n        // Check file path\n        String filename = mContent.getName();\n        long fileSize = mContent.getSize();\n        // Build and write headers\n        String filePartHeader = TWO_HYPENS + BOUNDARY_TAG + LINE_END\n                + \"Content-Disposition: form-data; name=\\\"File\\\"; filename=\\\"\"\n                + URLEncoder.encode(filename, UTF8_STR) + \"\\\"\" + LINE_END + \"Content-Type: \"\n                + mContent.getEncoding() + LINE_END + \"Content-Length: \" + fileSize + LINE_END\n                + LINE_END;\n        outputStream.writeBytes(filePartHeader);\n        // Write file content\n        InputStream fileInputStream = null;\n        try {\n            fileInputStream = AndroidFactory.getApplicationContext().getContentResolver()\n                    .openInputStream(file);\n            int bytesAvailable = fileInputStream.available();\n            int bufferSize = Math.min(bytesAvailable, CHUNK_MAX_SIZE);\n            byte[] buffer = new byte[bufferSize];\n            int bytesRead = fileInputStream.read(buffer, 0, bufferSize);\n            int progress = 0;\n\n            while (bytesRead > 0 && !isCancelled() && !isPaused()) {\n                progress += bytesRead;\n                outputStream.write(buffer, 0, bytesRead);\n                bytesAvailable = fileInputStream.available();\n                getListener().onHttpTransferProgress(progress, fileSize);\n                bufferSize = Math.min(bytesAvailable, CHUNK_MAX_SIZE);\n                buffer = new byte[bufferSize];\n                bytesRead = fileInputStream.read(buffer, 0, bufferSize);\n            }\n        } finally {\n            CloseableUtils.tryToClose(fileInputStream);\n        }\n        if (!isCancelled()) {\n            outputStream.writeBytes(LINE_END);\n        }\n    }\n\n    /**\n     * Stream conversion\n     * \n     * @param is Input stream\n     * @return Byte array\n     * @throws IOException\n     */\n    private static byte[] convertStreamToString(InputStream is) throws IOException {\n        BufferedReader reader = new BufferedReader(new InputStreamReader(is));\n        StringBuilder sb = new StringBuilder();\n        String line;\n        try {\n            while ((line = reader.readLine()) != null) {\n                sb.append(line).append('\\n');\n            }\n            return sb.toString().getBytes(UTF8);\n\n        } finally {\n            CloseableUtils.tryToClose(is);\n        }\n    }\n\n    /**\n     * Resume the upload\n     * \n     * @return byte[] contains the info to send to terminating side\n     * @throws IOException\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public byte[] resumeUpload() throws IOException, PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"User resumes transfer (TID=\" + mTId + \")\");\n        }\n        /* Try to get upload info */\n        byte[] resp = sendGetInfo(UPLOAD_INFO_REQUEST, false);\n        resumeTransfer();\n        if (resp == null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unexpected Server response, will restart upload from beginning\");\n            }\n            return uploadFile();\n        }\n        try {\n            if (isHttpTraceEnabled()) {\n                String trace = \"Get Upload Info response:\\n\".concat(Arrays.toString(resp));\n                System.out.println(trace);\n            }\n            FileTransferHttpResumeInfo ftResumeInfo = ChatUtils\n                    .parseFileTransferHttpResumeInfo(resp);\n            if (ftResumeInfo == null) {\n                sLogger.error(\"Cannot parse resume info! restart upload\");\n                return uploadFile();\n            }\n            if ((ftResumeInfo.getEnd() - ftResumeInfo.getStart()) >= (mContent.getSize() - 1)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Nothing to resume: uploaded complete\");\n                }\n                return sendGetDownloadInfo(); /* The file has already been uploaded completely */\n            }\n            if (sendPutForResumingUpload(ftResumeInfo) != null) {\n                return sendGetDownloadInfo();\n            }\n            return null;\n\n        } catch (ParserConfigurationException | SAXException e) {\n            throw new PayloadException(\"Unable to parse file transfer resume info!\", e);\n        }\n    }\n\n    /**\n     * Write a part of the file in a PUT request for resuming upload\n     * \n     * @param resumeInfo info on already uploaded content\n     * @return byte[] containing the server's response\n     * @throws IOException\n     * @throws NetworkException\n     */\n    private byte[] sendPutForResumingUpload(FileTransferHttpResumeInfo resumeInfo)\n            throws IOException, NetworkException {\n        int endByte = resumeInfo.getEnd();\n        long totalSize = mContent.getSize();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"sendPutForResumingUpload. Already sent from \" + resumeInfo.getStart()\n                    + \" to \" + endByte);\n        }\n        URL url = new URL(resumeInfo.getUri().toString());\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"Connection\", \"Keep-Alive\");\n        properties.put(\"Content-Type\", mContent.getEncoding());\n        properties.put(\"Content-Length\", String.valueOf(totalSize - (endByte + 1)));\n        /*\n         * According to RFC 2616, section 14.16 the Content-Range header must contain an element\n         * bytes-unit.\n         */\n        properties.put(\"Content-Range\", \"bytes \" + (endByte + 1) + \"-\" + (totalSize - 1) + \"/\"\n                + totalSize);\n        if (mAuth != null) {\n            String authValue = mAuth.generateAuthorizationHeaderValue(\"PUT\", url.getPath(), \"\");\n            properties.put(\"Authorization\", authValue);\n        }\n        DataOutputStream outputStream = null;\n        HttpURLConnection connection = null;\n        boolean httpTraceEnabled = isHttpTraceEnabled();\n        try {\n            connection = openHttpConnection(url, properties);\n            connection.setDoInput(true);\n            connection.setDoOutput(true);\n            connection.setReadTimeout(HTTP_READ_TIMEOUT);\n            connection.setRequestMethod(\"PUT\");\n            String body = \"\";\n            // Update authentication agent from response\n            if (httpTraceEnabled) {\n                StringBuilder trace = new StringBuilder(\">>> Send HTTP request:\\nPUT \").append(url);\n                Map<String, List<String>> headers = connection.getRequestProperties();\n                for (Entry<String, List<String>> property : headers.entrySet()) {\n                    trace.append(\"\\n\").append(property.getKey()).append(\": \")\n                            .append(property.getValue());\n                }\n                trace.append(\"\\n\").append(body);\n                System.out.println(trace);\n            }\n            // Create the DataOutputStream and start writing its body\n            outputStream = new DataOutputStream(connection.getOutputStream());\n            outputStream.writeBytes(body);\n            // Add File\n            writeRemainingFileData(outputStream, mContent.getUri(), endByte);\n            if (!isCancelled()) {\n                // Check response status code\n                int responseCode = connection.getResponseCode();\n                String message = connection.getResponseMessage();\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"PUT response \" + responseCode + \" (\" + message + \")\");\n                }\n                byte[] result = null;\n                boolean success = false;\n                boolean retry = false; // TODO PLM check why no retry ?\n                switch (responseCode) {\n                    case HttpURLConnection.HTTP_OK:\n                        success = true;\n                        InputStream inputStream = connection.getInputStream();\n                        result = convertStreamToString(inputStream);\n                        if (httpTraceEnabled) {\n                            System.out.println(\"\\n\" + new String(result));\n                        }\n                        break;\n                    default:\n                        break; // no success, no retry\n                }\n                if (success) {\n                    return result;\n                } else if (retry) {\n                    return sendPutForResumingUpload(resumeInfo);\n                } else {\n                    throw new IOException(\"Received \" + responseCode + \" from server\");\n                }\n            } else if (isPaused()) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"File transfer paused by user\");\n                }\n                // Sent data are bufferized. Must wait for response to enable sending to\n                // server.\n                int responseCode = connection.getResponseCode();\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"PUT response \" + responseCode + \" \"\n                            + connection.getResponseMessage());\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"File transfer cancelled by user\");\n                }\n            }\n            return null;\n\n        } catch (SecurityException e) {\n            /*\n             * Note! This is needed since this can be called during dequeuing.\n             */\n            sLogger.error(\"Upload reasume has failed due to that the file is not accessible!\", e);\n            getListener().onHttpTransferNotAllowedToSend();\n            return null;\n        } finally {\n            CloseableUtils.tryToClose(outputStream);\n            if (connection != null) {\n                connection.disconnect();\n            }\n        }\n    }\n\n    /**\n     * write remaining file data\n     * \n     * @param outputStream the output stream\n     * @param file the Uri of file to be uploaded\n     * @param offset the offset in bytes\n     * @throws IOException\n     */\n    private void writeRemainingFileData(DataOutputStream outputStream, Uri file, int offset)\n            throws IOException {\n        // Write file content\n        FileInputStream fileInputStream = null;\n        try {\n            fileInputStream = (FileInputStream) AndroidFactory.getApplicationContext()\n                    .getContentResolver().openInputStream(file);\n            // Skip bytes already received\n            int bytesRead = (int) fileInputStream.skip(offset + 1);\n            int bytesAvailable = fileInputStream.available();\n            int bufferSize = Math.min(bytesAvailable, CHUNK_MAX_SIZE);\n            byte[] buffer = new byte[bufferSize];\n            int progress = bytesRead;\n            bytesRead = fileInputStream.read(buffer, 0, bufferSize);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Send \" + bytesAvailable + \" remaining bytes starting from \"\n                        + progress);\n            }\n            // Send remaining bytes\n            while (bytesRead > 0 && !isCancelled() && !isPaused()) {\n                progress += bytesRead;\n                outputStream.write(buffer, 0, bytesRead);\n                bytesAvailable = fileInputStream.available();\n                getListener().onHttpTransferProgress(progress, mContent.getSize());\n                bufferSize = Math.min(bytesAvailable, CHUNK_MAX_SIZE);\n                buffer = new byte[bufferSize];\n                bytesRead = fileInputStream.read(buffer, 0, bufferSize);\n            }\n        } finally {\n            CloseableUtils.tryToClose(fileInputStream);\n        }\n    }\n\n    /**\n     * Send a get for info on the upload\n     * \n     * @param suffix String that specifies if it is for upload or download info\n     * @param authRequired Boolean that indicates whether or not the request has to be authenticated\n     *            with a authorization header\n     * @return byte[] contains the response of the server or null (401 UNAUTHORIZED is hidden)\n     * @throws IOException\n     * @throws NetworkException\n     */\n    private byte[] sendGetInfo(String suffix, boolean authRequired) throws IOException,\n            NetworkException {\n        URL url = new URL(getHttpServerAddr().toString());\n        String protocol = url.getProtocol();\n        String host = url.getHost();\n        String path = url.getPath();\n        String query = \"tid=\" + mTId + suffix;\n        Uri uri = new Uri.Builder().scheme(protocol).encodedAuthority(host).encodedPath(path)\n                .encodedQuery(query).build();\n        url = new URL(uri.toString());\n        Map<String, String> properties = new HashMap<>();\n        if (authRequired && mAuth != null) {\n            String authValue = mAuth.generateAuthorizationHeaderValue(\"GET\", url.getPath(), \"\");\n            properties.put(\"Authorization\", authValue);\n        }\n        HttpURLConnection connection = null;\n        boolean httpTraceEnabled = isHttpTraceEnabled();\n        try {\n            connection = openHttpConnection(url, properties);\n            connection.setReadTimeout(HTTP_READ_TIMEOUT);\n            if (httpTraceEnabled) {\n                StringBuilder trace = new StringBuilder(\">>> Send HTTP request:\\nGET \").append(url);\n                Map<String, List<String>> headers = connection.getHeaderFields();\n                for (Entry<String, List<String>> header : headers.entrySet()) {\n                    trace.append(\"\\n\").append(header.getKey()).append(\" \")\n                            .append(header.getValue());\n                }\n                System.out.println(trace);\n            }\n            int statusCode = connection.getResponseCode();\n            String message = connection.getResponseMessage();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Get info (\" + suffix + \") Response: \" + statusCode + \"(\" + message\n                        + \")\");\n            }\n            if (httpTraceEnabled) {\n                StringBuilder trace = new StringBuilder(\"<<< Receive HTTP response: \")\n                        .append(statusCode).append(\" \").append(message);\n                Map<String, List<String>> headers = connection.getHeaderFields();\n                for (Entry<String, List<String>> header : headers.entrySet()) {\n                    trace.append(\"\\n\").append(header.getKey()).append(\" \")\n                            .append(header.getValue());\n                }\n                System.out.println(trace);\n            }\n            switch (statusCode) {\n                case HttpURLConnection.HTTP_UNAUTHORIZED:\n                    if (authRequired) {\n                        throw new IOException(\"Unexpected response from server, got \" + statusCode\n                                + \" for the second time. Authentication rejected.\");\n                    }\n                    String authHeader = connection.getHeaderField(\"www-authenticate\");\n                    if (StringUtils.isEmpty(authHeader)) {\n                        throw new IOException(\"headers malformed in 401 response\");\n                    }\n                    if (mAuth == null) {\n                        mAuth = new HttpAuthenticationAgent(getHttpServerLogin(),\n                                getHttpServerPwd());\n                    }\n                    mAuth.readWwwAuthenticateHeader(authHeader);\n                    return sendGetInfo(suffix, true);\n\n                case HttpURLConnection.HTTP_OK:\n                    String resp = readStream(connection.getInputStream());\n                    return resp.getBytes(UTF8);\n\n                default:\n                    return null;\n            }\n        } finally {\n            if (connection != null) {\n                connection.disconnect();\n            }\n        }\n    }\n\n    private static String readStream(InputStream in) throws IOException {\n        StringBuilder sb = new StringBuilder();\n        try {\n            BufferedReader r = new BufferedReader(new InputStreamReader(in, UTF8), CHUNK_MAX_SIZE);\n            for (String line = r.readLine(); line != null; line = r.readLine()) {\n                sb.append(line);\n            }\n            return sb.toString();\n        } finally {\n            CloseableUtils.tryToClose(in);\n        }\n    }\n\n    /**\n     * Send a request to get info on the upload for download purpose on terminating\n     * \n     * @return byte[] contains the response of the server to the upload\n     * @throws NetworkException\n     * @throws IOException\n     */\n    private byte[] sendGetDownloadInfo() throws IOException, NetworkException {\n        return sendGetInfo(DOWNLOAD_INFO_REQUEST, false);\n    }\n\n    /**\n     * Gets TId\n     * \n     * @return TId\n     */\n    public String getTId() {\n        return mTId;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/HttpUploadTransferEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\n/**\n * Class HTTP Upload Transfer Event Listener\n * \n * @author Philippe LEMORDANT\n */\npublic interface HttpUploadTransferEventListener extends HttpTransferEventListener {\n    /**\n     * Notifies the start of the HTTP Upload transfer (once the thumbnail transfer is done) <br>\n     * The upload resume is only possible once thumbnail is transferred.\n     */\n    void uploadStarted();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/OriginatingHttpFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.io.IOException;\n\n/**\n * Originating file transfer HTTP session\n * \n * @author vfml3370\n * @author yplo6403\n */\npublic class OriginatingHttpFileSharingSession extends HttpFileTransferSession implements\n        HttpUploadTransferEventListener {\n\n    protected HttpUploadManager mUploadManager;\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingHttpFileSharingSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param fileTransferId File transfer Id\n     * @param imService InstantMessagingService\n     * @param content Content of file to share\n     * @param contact Remote contact identifier\n     * @param fileIcon Content of file icon\n     * @param tId TID of the upload\n     * @param messagingLog The messaging log accessor\n     * @param rcsSettings The RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     */\n    public OriginatingHttpFileSharingSession(InstantMessagingService imService,\n            String fileTransferId, MmContent content, ContactId contact, MmContent fileIcon,\n            String tId, MessagingLog messagingLog, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager) {\n        // @formatter:off\n        super(imService, \n                content,\n                contact,\n                PhoneUtils.formatContactIdToUri(contact),\n                fileIcon,\n                null,\n                fileTransferId,\n                rcsSettings,\n                messagingLog,\n                timestamp,\n                FileTransferData.UNKNOWN_EXPIRATION,\n                FileTransferData.UNKNOWN_EXPIRATION,\n                contactManager);\n        // @formatter:on\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"OriginatingHttpFileSharingSession contact=\".concat(contact.toString()));\n        }\n        mUploadManager = new HttpUploadManager(getContent(), fileIcon, this, tId, rcsSettings);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new HTTP file transfer session as originating\");\n            }\n            /* Upload the file to the HTTP server and process result */\n            processHttpUploadResponse(mUploadManager.uploadFile());\n\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (IOException e) {\n            /* Don't call handleError in case of Pause or Cancel */\n            if (mUploadManager.isCancelled() || mUploadManager.isPaused()) {\n                return;\n            }\n            sLogger.error(\"Failed to initiate file transfer session for sessionId : \"\n                    + getSessionID() + \" with fileTransferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to initiate file transfer session for sessionId : \"\n                    + getSessionID() + \" with fileTransferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    /**\n     * Process the HTTP upload response\n     * \n     * @param response byte[] which contains the result of the 200 OK from the content server\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    protected void processHttpUploadResponse(byte[] response) throws PayloadException,\n            NetworkException {\n        /* Check if upload has been cancelled */\n        if (mUploadManager.isCancelled() || mUploadManager.isPaused()) {\n            return;\n        }\n        FileTransferHttpInfoDocument infoDocument;\n        if (response == null\n                || (infoDocument = FileTransferUtils.parseFileTransferHttpDocument(response,\n                        mRcsSettings)) == null) {\n            handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED));\n            return;\n        }\n        mMessagingLog.setFileTransferDownloadInfo(getFileTransferId(), infoDocument);\n        removeSession();\n        handleHttpDownloadInfoAvailable();\n    }\n\n    @Override\n    public void interrupt() {\n        super.interrupt();\n        mUploadManager.interrupt();\n    }\n\n    @Override\n    public void onPause() {\n        new Thread(new Runnable() {\n            public void run() {\n                try {\n                    setFileTransferPaused();\n                    interruptSession();\n                    mUploadManager.pauseTransferByUser();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to pause upload for sessionId : \" + getSessionID()\n                            + \" with fileTransferId : \" + getFileTransferId(), e);\n                    handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED, e));\n                }\n            }\n        }).start();\n    }\n\n    @Override\n    public void onResume() {\n        new Thread(new Runnable() {\n            public void run() {\n                try {\n                    setFileTransferResumed();\n                    FtHttpResumeUpload upload = mMessagingLog\n                            .retrieveFtHttpResumeUpload(mUploadManager.getTId());\n                    if (upload != null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Resume: \".concat(upload.toString()));\n                        }\n                        processHttpUploadResponse(mUploadManager.resumeUpload());\n                    } else {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"No result for resuming file transfer\");\n                        }\n                        processHttpUploadResponse(null);\n                    }\n                } catch (NetworkException e) {\n                    handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED, e));\n\n                } catch (IOException | PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to resume upload for sessionId : \" + getSessionID()\n                            + \" with fileTransferId : \" + getFileTransferId(), e);\n                    handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED, e));\n                }\n            }\n        }).start();\n    }\n\n    @Override\n    public void uploadStarted() {\n        mMessagingLog.setFileUploadTId(getFileTransferId(), mUploadManager.getTId());\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    /**\n     * Sets the timestamp when file on the content server is no longer valid to download.\n     * \n     * @param timestamp The timestamp\n     */\n    public void setFileExpiration(long timestamp) {\n        mFileExpiration = timestamp;\n    }\n\n    @Override\n    public void terminateSession(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"terminateSession reason=\".concat(reason.toString()));\n        }\n        closeHttpSession(reason);\n        /*\n         * If reason is TERMINATION_BY_SYSTEM or TERMINATION_BY_CONNECTION_LOST and session already\n         * started, then it's a pause\n         */\n        ContactId contact = getRemoteContact();\n        State state = getSessionState();\n        switch (reason) {\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                if (isFileTransferPaused()) {\n                    return;\n                }\n                /*\n                 * TId id needed for resuming the file transfer. Hence pausing the file transfer\n                 * only if TId is present.\n                 */\n                if (State.ESTABLISHED == state && mUploadManager.getTId() != null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Pause the session (session terminated, but can be resumed)\");\n                    }\n                    for (ImsSessionListener listener : getListeners()) {\n                        ((FileSharingSessionListener) listener)\n                                .onFileTransferPausedBySystem(contact);\n                    }\n                    return;\n                }\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            default:\n                if (State.ESTABLISHED == state) {\n                    for (ImsSessionListener listener : getListeners()) {\n                        listener.onSessionAborted(contact, reason);\n                    }\n                } else {\n                    for (ImsSessionListener listener : getListeners()) {\n                        listener.onSessionRejected(contact, reason);\n                    }\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/OriginatingHttpGroupFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.io.IOException;\n\n/**\n * Originating file transfer HTTP session\n * \n * @author vfml3370\n */\npublic class OriginatingHttpGroupFileSharingSession extends HttpFileTransferSession implements\n        HttpUploadTransferEventListener {\n\n    protected HttpUploadManager mUploadManager;\n\n    private static final Logger sLogger = Logger\n            .getLogger(OriginatingHttpGroupFileSharingSession.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param fileTransferId File transfer Id\n     * @param content The file content to share\n     * @param fileIcon Content of file icon\n     * @param conferenceId Conference ID\n     * @param chatContributionId Chat contribution Id\n     * @param tId TID of the upload\n     * @param rcsSettings The RCS settings accessor\n     * @param messagingLog The messaging log accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     */\n    public OriginatingHttpGroupFileSharingSession(InstantMessagingService imService,\n            String fileTransferId, MmContent content, MmContent fileIcon, Uri conferenceId,\n            String chatContributionId, String tId, RcsSettings rcsSettings,\n            MessagingLog messagingLog, long timestamp, ContactManager contactManager) {\n        // @formatter:off\n        super(imService, \n                content, \n                null, \n                conferenceId, \n                fileIcon, \n                chatContributionId,\n                fileTransferId, \n                rcsSettings, \n                messagingLog, \n                timestamp,\n                FileTransferData.UNKNOWN_EXPIRATION, \n                FileTransferData.UNKNOWN_EXPIRATION,\n                contactManager);\n        // @formatter:on\n        mUploadManager = new HttpUploadManager(getContent(), fileIcon, this, tId, rcsSettings);\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a new HTTP group file transfer session as originating\");\n        }\n        try {\n            processHttpUploadResponse(mUploadManager.uploadFile());\n\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (IOException e) {\n            /* Don't call handleError in case of Pause or Cancel */\n            if (mUploadManager.isCancelled() || mUploadManager.isPaused()) {\n                return;\n            }\n            sLogger.error(\"Failed to initiate file transfer session for sessionId : \"\n                    + getSessionID() + \" with fileTransferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to initiate file transfer session for sessionId : \"\n                    + getSessionID() + \" with fileTransferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public void interrupt() {\n        super.interrupt();\n        mUploadManager.interrupt();\n    }\n\n    /**\n     * Process the HTTP upload response\n     * \n     * @param response byte[] which contains the result of the 200 OK from the content server\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    protected void processHttpUploadResponse(byte[] response) throws PayloadException,\n            NetworkException {\n        if (mUploadManager.isCancelled()) {\n            return;\n        }\n        FileTransferHttpInfoDocument infoDocument;\n        if (response == null\n                || (infoDocument = FileTransferUtils.parseFileTransferHttpDocument(response,\n                        mRcsSettings)) == null) {\n            handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED));\n            return;\n        }\n        mMessagingLog.setFileTransferDownloadInfo(getFileTransferId(), infoDocument);\n        removeSession();\n        handleHttpDownloadInfoAvailable();\n    }\n\n    @Override\n    public void onPause() {\n        new Thread(new Runnable() {\n            public void run() {\n                try {\n                    setFileTransferPaused();\n                    interruptSession();\n                    mUploadManager.pauseTransferByUser();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to pause upload for sessionId : \" + getSessionID()\n                            + \" with fileTransferId : \" + getFileTransferId(), e);\n                    handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED, e));\n                }\n            }\n        }).start();\n    }\n\n    @Override\n    public void onResume() {\n        new Thread(new Runnable() {\n            public void run() {\n                try {\n                    setFileTransferResumed();\n                    FtHttpResumeUpload upload = mMessagingLog\n                            .retrieveFtHttpResumeUpload(mUploadManager.getTId());\n                    if (upload != null) {\n                        processHttpUploadResponse(mUploadManager.resumeUpload());\n                    } else {\n                        processHttpUploadResponse(null);\n                    }\n                } catch (NetworkException e) {\n                    handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED, e));\n\n                } catch (IOException | PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to resume upload for sessionId : \" + getSessionID()\n                            + \" with fileTransferId : \" + getFileTransferId(), e);\n                    handleError(new FileSharingError(FileSharingError.MEDIA_UPLOAD_FAILED, e));\n                }\n            }\n        }).start();\n    }\n\n    @Override\n    public void uploadStarted() {\n        mMessagingLog.setFileUploadTId(getFileTransferId(), mUploadManager.getTId());\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    /**\n     * Sets the timestamp when file on the content server is no longer valid to download.\n     * \n     * @param timestamp The timestamp\n     */\n    public void setFileExpiration(long timestamp) {\n        mFileExpiration = timestamp;\n    }\n\n    @Override\n    public void terminateSession(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"terminateSession reason=\".concat(reason.toString()));\n        }\n        closeHttpSession(reason);\n        /*\n         * If reason is TERMINATION_BY_SYSTEM or TERMINATION_BY_CONNECTION_LOST and session already\n         * started, then it's a pause\n         */\n        ContactId contact = getRemoteContact();\n        State state = getSessionState();\n        switch (reason) {\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                if (isFileTransferPaused()) {\n                    return;\n                }\n                /*\n                 * TId id needed for resuming the file transfer. Hence pausing the file transfer\n                 * only if TId is present.\n                 */\n                if (State.ESTABLISHED == state && mUploadManager.getTId() != null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Pause the session (session terminated, but can be resumed)\");\n                    }\n                    for (ImsSessionListener listener : getListeners()) {\n                        ((FileSharingSessionListener) listener)\n                                .onFileTransferPausedBySystem(contact);\n                    }\n                    return;\n                }\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            default:\n                if (State.ESTABLISHED == state) {\n                    for (ImsSessionListener listener : getListeners()) {\n                        listener.onSessionAborted(contact, reason);\n                    }\n                } else {\n                    for (ImsSessionListener listener : getListeners()) {\n                        listener.onSessionRejected(contact, reason);\n                    }\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/ResumeUploadFileSharingSession.java",
    "content": "/*******************************************************************************\nw * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Resuming session of OriginatingHttpFileSharingSession\n * \n * @author Benoit JOGUET\n */\npublic class ResumeUploadFileSharingSession extends OriginatingHttpFileSharingSession {\n\n    private final static Logger sLogger = Logger.getLogger(ResumeUploadFileSharingSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor create instance of session object to resume download\n     * \n     * @param imService InstantMessagingService\n     * @param content the content (url, mime-type and size)\n     * @param resumeUpload the data object in DB\n     * @param rcsSettings The RCS settings accessor\n     * @param messagingLog The messaging log accessor\n     * @param contactManager The contact manager accessor\n     */\n    public ResumeUploadFileSharingSession(InstantMessagingService imService, MmContent content,\n            FtHttpResumeUpload resumeUpload, RcsSettings rcsSettings, MessagingLog messagingLog,\n            ContactManager contactManager) {\n        // @formatter:off\n        super(imService, \n                resumeUpload.getFileTransferId(), \n                content, resumeUpload.getContact(),\n                resumeUpload.getFileicon() != null ? FileTransferUtils.createIconContent(resumeUpload.getFileicon()) : null,\n                resumeUpload.getTId(), \n                messagingLog, \n                rcsSettings,\n                resumeUpload.getTimestamp(), \n                contactManager);\n        // @formatter:on\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Resume a HTTP file transfer session as originating\");\n        }\n        try {\n            onHttpTransferStarted();\n            /* Resume the file upload to the HTTP server */\n            processHttpUploadResponse(mUploadManager.resumeUpload());\n\n        } catch (IOException e) {\n            /* Don't call handleError in case of Pause or Cancel */\n            if (mUploadManager.isCancelled() || mUploadManager.isPaused()) {\n                return;\n            }\n            sLogger.error(\"Failed to resume a file transfer session for sessionId : \"\n                    + getSessionID() + \" with fileTransferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to resume a file transfer session for sessionId : \"\n                    + getSessionID() + \" with fileTransferId : \" + getFileTransferId(), e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public void uploadStarted() {\n        /* Upload entry already created */\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/ResumeUploadGroupFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\n\n/**\n * Resuming session of OriginatingHttpGroupFileSharingSession\n * \n * @author Philippe LEMORDANT\n */\npublic class ResumeUploadGroupFileSharingSession extends OriginatingHttpGroupFileSharingSession {\n\n    private final static Logger sLogger = Logger\n            .getLogger(ResumeUploadGroupFileSharingSession.class.getSimpleName());\n\n    /**\n     * Constructor create instance of session object to resume download\n     * \n     * @param imService InstantMessagingService\n     * @param content the content (url, mime-type and size)\n     * @param resumeUpload the data object in DB\n     * @param rcsSettings The RCS settings accessor\n     * @param messagingLog The messaging log accessor\n     * @param contactManager The contact manager accessor\n     */\n    public ResumeUploadGroupFileSharingSession(InstantMessagingService imService,\n            MmContent content, FtHttpResumeUpload resumeUpload, RcsSettings rcsSettings,\n            MessagingLog messagingLog, ContactManager contactManager) {\n        // @formatter:off\n        super(imService, \n                resumeUpload.getFileTransferId(),\n                content,\n                resumeUpload.getFileicon() != null ? FileTransferUtils.createIconContent(\n                        resumeUpload.getFileicon()) : null,\n                ImsModule.getImsUserProfile().getImConferenceUri(), \n                resumeUpload.getChatId(),\n                resumeUpload.getTId(), \n                rcsSettings, \n                messagingLog, \n                resumeUpload.getTimestamp(),\n                contactManager);\n        // @formatter:on\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Resume a HTTP group file transfer upload\");\n        }\n        try {\n            onHttpTransferStarted();\n            /* Resume the file upload to the HTTP server */\n            processHttpUploadResponse(mUploadManager.resumeUpload());\n\n        } catch (IOException e) {\n            /* Don't call handleError in case of Pause or Cancel */\n            if (mUploadManager.isCancelled() || mUploadManager.isPaused()) {\n                return;\n            }\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException | NetworkException | RuntimeException e) {\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public void uploadStarted() {\n        /* Upload entry already created */\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/http/TerminatingHttpFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.http;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.io.IOException;\n\n/**\n * Terminating file transfer HTTP session\n * \n * @author vfml3370\n */\npublic abstract class TerminatingHttpFileSharingSession extends HttpFileTransferSession {\n\n    protected final HttpDownloadManager mDownloadManager;\n\n    protected final String mRemoteInstanceId;\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingHttpFileSharingSession.class\n            .getSimpleName());\n\n    /**\n     * Is File Transfer initiated from a GC\n     */\n    protected final boolean mGroupFileTransfer;\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param fileTransferId the File transfer Id\n     * @param remote the remote contact Id\n     * @param content the file content\n     * @param fileExpiration the file expiration timestamp\n     * @param fileIcon the file icon content\n     * @param iconExpiration the file icon expiration timestamp\n     * @param chatContributionId the contribution ID\n     * @param isGroup True if group file transfer\n     * @param httpServerAddress the HTTP address of the content server\n     * @param rcsSettings the RCS settings accessor\n     * @param messagingLog the message log accessor\n     * @param timestamp Local timestamp for the session\n     * @param remoteInstanceId the remote instance ID\n     * @param contactManager the contact manager\n     */\n    public TerminatingHttpFileSharingSession(InstantMessagingService imService, MmContent content,\n            long fileExpiration, MmContent fileIcon, long iconExpiration, ContactId remote,\n            String chatContributionId, String fileTransferId, boolean isGroup,\n            Uri httpServerAddress, RcsSettings rcsSettings, MessagingLog messagingLog,\n            long timestamp, String remoteInstanceId, ContactManager contactManager) {\n        // @formatter:off\n        super(imService,\n                content,\n                remote,\n                PhoneUtils.formatContactIdToUri(remote),\n                fileIcon,\n                chatContributionId,\n                fileTransferId,\n                rcsSettings,\n                messagingLog,\n                timestamp,\n                fileExpiration,\n                iconExpiration,\n                contactManager);\n        // @formatter:on\n        mGroupFileTransfer = isGroup;\n        mRemoteInstanceId = remoteInstanceId;\n        mDownloadManager = new HttpDownloadManager(content, this, httpServerAddress, rcsSettings);\n    }\n\n    protected boolean isGroupFileTransfer() {\n        return mGroupFileTransfer;\n    }\n\n    @Override\n    public void interrupt() {\n        super.interrupt();\n        mDownloadManager.interrupt();\n    }\n\n    @Override\n    public void run() {\n        try {\n            onHttpTransferStarted();\n            Uri file = mDownloadManager.getDownloadedFileUri();\n            /* Download file from the HTTP server */\n            mDownloadManager.downloadFile();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Download file with success\");\n            }\n            getContent().setUri(file);\n            handleFileTransferred();\n            if (mImdnManager.isSendOneToOneDeliveryDisplayedReportsEnabled()) {\n                sendDeliveryReport(ImdnDocument.DeliveryStatus.DISPLAYED,\n                        System.currentTimeMillis());\n            }\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n        } catch (FileNotDownloadedException | IOException e) {\n            sLogger.error(\"Download of file has failed for mRemoteInstanceId : \"\n                    + mRemoteInstanceId, e);\n            /* Don't call handleError in case of Pause or Cancel */\n            if (mDownloadManager.isCancelled() || mDownloadManager.isPaused()) {\n                return;\n            }\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Download of file has failed for mRemoteInstanceId : \"\n                    + mRemoteInstanceId, e);\n            handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n        }\n    }\n\n    /**\n     * Send delivery report\n     * \n     * @param status Report status\n     * @param timestamp Local timestamp\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    protected void sendDeliveryReport(ImdnDocument.DeliveryStatus status, long timestamp)\n            throws PayloadException, NetworkException {\n        String msgId = getFileTransferId();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send delivery report \".concat(status.toString()));\n        }\n        ChatSession chatSession;\n        ContactId remote = getRemoteContact();\n        InstantMessagingService imService = Core.getInstance().getImService();\n        if (mGroupFileTransfer) {\n            chatSession = imService.getGroupChatSession(getContributionID());\n        } else {\n            chatSession = imService.getOneToOneChatSession(remote);\n        }\n        if (chatSession != null && chatSession.isMediaEstablished()) {\n            chatSession.sendMsrpMessageDeliveryStatus(remote, msgId, status, timestamp);\n        } else {\n            String chatId = mGroupFileTransfer ? getContributionID() : remote.toString();\n            mImdnManager.sendMessageDeliveryStatusImmediately(chatId, remote, msgId, status,\n                    mRemoteInstanceId, timestamp);\n        }\n    }\n\n    /**\n     * Pause File Transfer\n     */\n    @Override\n    public void onPause() {\n        new Thread(new Runnable() {\n            public void run() {\n                try {\n                    setFileTransferPaused();\n                    interruptSession();\n                    mDownloadManager.pauseTransferByUser();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Pause of download of file has failed for mRemoteInstanceId : \"\n                            + mRemoteInstanceId, e);\n                    handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n                }\n            }\n        }).start();\n    }\n\n    /**\n     * Resume File Transfer\n     */\n    @Override\n    public void onResume() {\n        new Thread(new Runnable() {\n            public void run() {\n                try {\n                    setFileTransferResumed();\n                    mDownloadManager.getListener().onHttpTransferResumed();\n                    /* Download file from the HTTP server */\n                    mDownloadManager.resumeDownload();\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Download file with success\");\n                    }\n                    getContent().setUri(mDownloadManager.getDownloadedFileUri());\n                    handleFileTransferred();\n                    if (mImdnManager.isSendOneToOneDeliveryDisplayedReportsEnabled()) {\n                        sendDeliveryReport(ImdnDocument.DeliveryStatus.DISPLAYED,\n                                System.currentTimeMillis());\n                    }\n                } catch (NetworkException e) {\n                    handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n                } catch (FileNotDownloadedException | IOException e) {\n                    sLogger.error(\"Download of file has failed for mRemoteInstanceId : \"\n                            + mRemoteInstanceId, e);\n                    /* Don't call handleError in case of Pause or Cancel */\n                    if (mDownloadManager.isCancelled() || mDownloadManager.isPaused()) {\n                        return;\n                    }\n                    handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Download of file has failed for mRemoteInstanceId : \"\n                            + mRemoteInstanceId, e);\n                    handleError(new FileSharingError(FileSharingError.MEDIA_DOWNLOAD_FAILED, e));\n                }\n            }\n        }).start();\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n    @Override\n    public void terminateSession(TerminationReason reason) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"terminateSession reason=\".concat(reason.toString()));\n        }\n        closeHttpSession(reason);\n        /*\n         * If reason is TERMINATION_BY_SYSTEM or TERMINATION_BY_CONNECTION_LOST and session already\n         * started, then it's a pause\n         */\n        boolean sessionAccepted = isSessionAccepted();\n        ContactId remote = getRemoteContact();\n        switch (reason) {\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                if (isFileTransferPaused()) {\n                    return;\n                }\n                /*\n                 * File transfer invitation is valid until file transfer validity expires and hence\n                 * the state of file transfer is not altered if the invitation was not yet answered.\n                 */\n                if (!sessionAccepted) {\n                    return;\n                }\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Pause the session (session terminated, but can be resumed)\");\n                }\n                for (ImsSessionListener listener : getListeners()) {\n                    ((FileSharingSessionListener) listener).onFileTransferPausedBySystem(remote);\n                }\n                return;\n            default:\n                break;\n        }\n        if (sessionAccepted) {\n            for (ImsSessionListener listener : getListeners()) {\n                listener.onSessionAborted(remote, reason);\n            }\n            return;\n        }\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionRejected(remote, reason);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/msrp/OriginatingMsrpFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.msrp;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ContributionIdGenerator;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.ImsFileSharingSession;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.utils.Base64;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentLengthHeader;\nimport javax2.sip.header.ContentTypeHeader;\n\n/**\n * Originating file transfer session\n * \n * @author jexa7410\n */\npublic class OriginatingMsrpFileSharingSession extends ImsFileSharingSession implements\n        MsrpEventListener {\n    /**\n     * Boundary tag\n     */\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    private MsrpManager mMsrpMgr;\n\n    private final InstantMessagingService mImService;\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingMsrpFileSharingSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param fileTransferId File transfer Id\n     * @param imService InstantMessagingService\n     * @param content Content to be shared\n     * @param contact Remote contact identifier\n     * @param fileIcon Content of file icon\n     * @param rcsSettings The RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     */\n    public OriginatingMsrpFileSharingSession(InstantMessagingService imService,\n            String fileTransferId, MmContent content, ContactId contact, MmContent fileIcon,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager) {\n        super(imService, content, contact, fileIcon, fileTransferId, rcsSettings, timestamp,\n                contactManager);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"OriginatingFileSharingSession contact=\" + contact + \" filename=\"\n                    + content.getName());\n        }\n        mImService = imService;\n        // Create dialog path\n        createOriginatingDialogPath();\n        // Set contribution ID\n        String id = ContributionIdGenerator.getContributionId(getDialogPath().getCallId());\n        setContributionID(id);\n    }\n\n    private byte[] getFileData(Uri file, int size) throws NetworkException {\n        FileInputStream fileInputStream = null;\n        try {\n            fileInputStream = (FileInputStream) AndroidFactory.getApplicationContext()\n                    .getContentResolver().openInputStream(file);\n            byte[] data = new byte[size];\n            if (size != fileInputStream.read(data, 0, size)) {\n                throw new NetworkException(\"Unable to retrive data from \" + file);\n            }\n            return data;\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to get file data for uri : \" + file, e);\n\n        } finally {\n            CloseableUtils.tryToClose(fileInputStream);\n        }\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a file transfer session as originating\");\n            }\n            /* Set setup mode */\n            String localSetup = createSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            /* Set local port */\n            int localMsrpPort;\n            if (\"active\".equals(localSetup)) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(mRcsSettings);\n            }\n            /* Create the MSRP manager */\n            String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                    .getNetworkAccess().getIpAddress();\n            mMsrpMgr = new MsrpManager(localIpAddress, localMsrpPort, getImsService(), mRcsSettings);\n            /* Build SDP part */\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String encoding = getContent().getEncoding();\n            long maxSize = mRcsSettings.getMaxFileTransferSize();\n            /* Set File-selector attribute */\n            String selector = getFileSelectorAttribute();\n            StringBuilder sdp = new StringBuilder(SdpUtils.buildFileSDP(ipAddress, localMsrpPort,\n                    mMsrpMgr.getLocalSocketProtocol(), encoding, getFileTransferIdAttribute(),\n                    selector, getFileDisposition(), localSetup, mMsrpMgr.getLocalMsrpPath(),\n                    SdpUtils.DIRECTION_SENDONLY, maxSize));\n            /* Set File-location attribute */\n            Uri location = getFileLocationAttribute();\n            if (location != null) {\n                sdp.append(\"a=file-location:\").append(location.toString()).append(SipUtils.CRLF);\n            }\n            MmContent fileIcon = getFileicon();\n            if (fileIcon == null) {\n                /* Set the local SDP part in the dialog path */\n                getDialogPath().setLocalContent(sdp.toString());\n\n            } else {\n                Capabilities remoteCapabilities = mContactManager\n                        .getContactCapabilities(getRemoteContact());\n                boolean fileIconSupported = remoteCapabilities != null\n                        && remoteCapabilities.isFileTransferThumbnailSupported();\n                if (fileIconSupported) {\n                    sdp.append(\"a=file-icon:cid:image@joyn.com\").append(SipUtils.CRLF);\n\n                    /* Encode the file icon file */\n                    String imageEncoded = Base64.encodeBase64ToString(getFileData(\n                            fileIcon.getUri(), (int) fileIcon.getSize()));\n                    String sdpContent = sdp.toString();\n                    String multipart = Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                            + ContentTypeHeader.NAME + \": application/sdp\" + SipUtils.CRLF\n                            + ContentLengthHeader.NAME + \": \" + sdpContent.getBytes(UTF8).length\n                            + SipUtils.CRLF + SipUtils.CRLF + sdpContent + SipUtils.CRLF\n                            + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                            + ContentTypeHeader.NAME + \": \" + fileIcon.getEncoding()\n                            + SipUtils.CRLF + SipUtils.HEADER_CONTENT_TRANSFER_ENCODING\n                            + \": base64\" + SipUtils.CRLF + SipUtils.HEADER_CONTENT_ID\n                            + \": <image@joyn.com>\" + SipUtils.CRLF + ContentLengthHeader.NAME\n                            + \": \" + imageEncoded.length() + SipUtils.CRLF\n                            + ContentDispositionHeader.NAME + \": icon\" + SipUtils.CRLF\n                            + SipUtils.CRLF + imageEncoded + SipUtils.CRLF\n                            + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG\n                            + Multipart.BOUNDARY_DELIMITER;\n\n                    /* Set the local SDP part in the dialog path */\n                    getDialogPath().setLocalContent(multipart);\n\n                } else {\n                    /* Set the local SDP part in the dialog path */\n                    getDialogPath().setLocalContent(sdp.toString());\n                }\n            }\n            /* Create an INVITE request */\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInvite();\n            /* Set the Authorization header */\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n            /* Set initial request in the dialog path */\n            getDialogPath().setInvite(invite);\n            /* Send INVITE request */\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException e) {\n            sLogger.error(\"Unable to set authorization header!\", e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (FileAccessException | PayloadException e) {\n            sLogger.error(\"Unable to set and send initial invite!\", e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to initiate a file transfer session!\", e);\n            handleError(new FileSharingError(FileSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        // Get the remote SDP part\n        byte[] sdp = getDialogPath().getRemoteContent().getBytes(UTF8);\n        // Create the MSRP session\n        MsrpSession session = mMsrpMgr.createMsrpSession(sdp, this);\n        session.setFailureReportOption(true);\n        session.setSuccessReportOption(false);\n        // Do not use right now the mapping to do not increase memory and cpu consumption\n        session.setMapMsgIdFromTransationId(false);\n    }\n\n    @Override\n    public void openMediaSession() throws PayloadException, NetworkException {\n        mMsrpMgr.openMsrpSession();\n    }\n\n    @Override\n    public void startMediaTransfer() throws NetworkException, FileAccessException {\n        try {\n            /* Start sending data chunks */\n            InputStream stream = AndroidFactory.getApplicationContext().getContentResolver()\n                    .openInputStream(getContent().getUri());\n            mMsrpMgr.sendChunks(stream, IdGenerator.generateMessageID(),\n                    getContent().getEncoding(), getContent().getSize(), TypeMsrpChunk.FileSharing);\n\n        } catch (FileNotFoundException e) {\n            throw new FileAccessException(\"Failed to initiate media transfer!\", e);\n\n        } catch (SecurityException e) {\n            sLogger.error(\"Session initiation has failed due to that the file is not accessible!\",\n                    e);\n            ContactId contact = getRemoteContact();\n            for (ImsSessionListener listener : getListeners()) {\n                ((FileSharingSessionListener) listener).onTransferNotAllowedToSend(contact);\n            }\n        }\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transferred\");\n            }\n            long timestamp = System.currentTimeMillis();\n            setFileTransferred();\n            closeMediaSession();\n            closeSession(TerminationReason.TERMINATION_BY_USER);\n            removeSession();\n            ContactId contact = getRemoteContact();\n            MmContent content = getContent();\n            for (ImsSessionListener listener : getListeners()) {\n                ((FileSharingSessionListener) listener).onFileTransferred(content, contact,\n                        FileTransferData.UNKNOWN_EXPIRATION, FileTransferData.UNKNOWN_EXPIRATION,\n                        FileTransferProtocol.MSRP);\n            }\n            mImService.receiveOneToOneFileDeliveryStatus(contact, new ImdnDocument(\n                    getFileTransferId(), ImdnDocument.DISPLAY,\n                    ImdnDocument.DeliveryStatus.DISPLAYED, timestamp));\n\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to notify MSRP data transferred for msgId : \" + msgId, e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to notify msrp data transfered for msgId : \" + msgId, e);\n        }\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) {\n        // Not used in originating side\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((FileSharingSessionListener) listener).onTransferProgress(contact, currentSize,\n                    totalSize);\n        }\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        // Not used in originating side\n        return false;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer aborted\");\n        }\n    }\n\n    @Override\n    public void closeMediaSession() {\n        // Close MSRP session\n        if (mMsrpMgr != null) {\n            mMsrpMgr.closeSession();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"MSRP session has been closed\");\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void handle200OK(SipResponse resp) throws PayloadException, NetworkException,\n            FileAccessException {\n        long timestamp = System.currentTimeMillis();\n        mImService.receiveOneToOneFileDeliveryStatus(getRemoteContact(), new ImdnDocument(\n                getFileTransferId(), ImdnDocument.POSITIVE_DELIVERY,\n                ImdnDocument.DeliveryStatus.DELIVERED, timestamp));\n        super.handle200OK(resp);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/im/filetransfer/msrp/TerminatingMsrpFileSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.im.filetransfer.msrp;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpConstants;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.ImsFileSharingSession;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Vector;\n\n/**\n * Terminating file transfer session\n * \n * @author jexa7410\n */\npublic class TerminatingMsrpFileSharingSession extends ImsFileSharingSession implements\n        MsrpEventListener {\n\n    private MsrpManager mMsrpMgr;\n\n    /**\n     * Since in MSRP communication we do not have a timestampSent to be extracted from the payload\n     * then we need to fake that by using the local timestamp even if this is not the real proper\n     * timestamp from the remote side in this case.\n     */\n    private long mTimestampSent;\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingMsrpFileSharingSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param invite Initial INVITE request\n     * @param remote contact\n     * @param rcsSettings RCS settings\n     * @param timestamp Local timestamp for the session\n     * @param timestampSent the remote timestamp sent in payload for the file sharing\n     * @param contactManager The contact manager accessor\n     * @throws PayloadException\n     * @throws FileAccessException\n     */\n    public TerminatingMsrpFileSharingSession(InstantMessagingService imService, SipRequest invite,\n            ContactId remote, RcsSettings rcsSettings, long timestamp, long timestampSent,\n            ContactManager contactManager) throws PayloadException, FileAccessException {\n        super(imService, ContentManager.createMmContentFromSdp(invite, rcsSettings), remote,\n                FileTransferUtils.extractFileIcon(invite, rcsSettings), IdGenerator\n                        .generateMessageID(), rcsSettings, timestamp, contactManager);\n        mTimestampSent = timestampSent;\n        // Create dialog path\n        createTerminatingDialogPath(invite);\n        // Set contribution ID\n        String id = ChatUtils.getContributionId(invite);\n        setContributionID(id);\n        if (shouldBeAutoAccepted()) {\n            setSessionAccepted();\n        }\n    }\n\n    /**\n     * Check if session should be auto accepted depending on settings and roaming conditions This\n     * method should only be called once per session\n     * \n     * @return true if file transfer should be auto accepted\n     */\n    private boolean shouldBeAutoAccepted() {\n        long ftWarnSize = mRcsSettings.getWarningMaxFileTransferSize();\n        if (ftWarnSize > 0 && getContent().getSize() > ftWarnSize) {\n            /*\n             * User should be warned about the potential charges associated to the transfer of a\n             * large file. Hence do not auto accept if file size is above the warning limit.\n             */\n            return false;\n        }\n        if (getImsService().getImsModule().isInRoaming()) {\n            return mRcsSettings.isFileTransferAutoAcceptedInRoaming();\n        }\n        return mRcsSettings.isFileTransferAutoAccepted();\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new file transfer session as terminating\");\n            }\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            MmContent file = getContent();\n            MmContent fileIcon = getFileicon();\n            long timestamp = getTimestamp();\n            SipDialogPath dialogPath = getDialogPath();\n            /* Check if session should be auto-accepted once */\n            if (isSessionAccepted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Auto accept file transfer invitation\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((FileSharingSessionListener) listener).onSessionAutoAccepted(contact, file,\n                            fileIcon, timestamp, mTimestampSent,\n                            FileTransferData.UNKNOWN_EXPIRATION,\n                            FileTransferData.UNKNOWN_EXPIRATION);\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Accept manually file transfer invitation\");\n                }\n                for (ImsSessionListener listener : listeners) {\n                    ((FileSharingSessionListener) listener).onSessionInvited(contact, file,\n                            fileIcon, timestamp, mTimestampSent,\n                            FileTransferData.UNKNOWN_EXPIRATION,\n                            FileTransferData.UNKNOWN_EXPIRATION);\n                }\n                send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n                InvitationStatus answer = waitInvitationAnswer();\n                switch (answer) {\n                    case INVITATION_REJECTED_DECLINE:\n                        /* Intentional fall through */\n                    case INVITATION_REJECTED_BUSY_HERE:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been rejected by user\");\n                        }\n                        sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_USER);\n                        }\n                        return;\n\n                    case INVITATION_TIMEOUT:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been rejected on timeout\");\n                        }\n                        /* Ringing period timeout */\n                        send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_TIMEOUT);\n                        }\n                        return;\n\n                    case INVITATION_REJECTED_BY_SYSTEM:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been aborted by system\");\n                        }\n                        removeSession();\n                        return;\n\n                    case INVITATION_CANCELED:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been rejected by remote\");\n                        }\n                        removeSession();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionRejected(contact,\n                                    TerminationReason.TERMINATION_BY_REMOTE);\n                        }\n                        return;\n\n                    case INVITATION_ACCEPTED:\n                        setSessionAccepted();\n                        for (ImsSessionListener listener : listeners) {\n                            listener.onSessionAccepting(contact);\n                        }\n                        break;\n\n                    case INVITATION_DELETED:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session has been deleted\");\n                        }\n                        removeSession();\n                        return;\n\n                    default:\n                        throw new IllegalArgumentException(\n                                \"Unknown invitation answer in run; answer=\" + answer);\n                }\n            }\n            /* Parse the remote SDP part */\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            String protocol = mediaDesc.mProtocol;\n            boolean isSecured = false;\n            if (protocol != null) {\n                isSecured = protocol.equalsIgnoreCase(MsrpConstants.SOCKET_MSRP_SECURED_PROTOCOL);\n            }\n            String fileSelector = mediaDesc.getMediaAttribute(\"file-selector\").getValue();\n            String fileTransferId = mediaDesc.getMediaAttribute(\"file-transfer-id\").getValue();\n            MediaAttribute attr3 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr3.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n            /* Extract the \"setup\" parameter */\n            String remoteSetup = \"passive\";\n            MediaAttribute attr4 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr4 != null) {\n                remoteSetup = attr4.getValue();\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Remote setup attribute is \" + remoteSetup);\n            }\n            /* Set setup mode */\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \" + localSetup);\n            }\n            /* Set local port */\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = 9; /* See RFC4145, Page 4 */\n            } else {\n                localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(mRcsSettings);\n            }\n            /* Create the MSRP manager */\n            String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                    .getNetworkAccess().getIpAddress();\n            mMsrpMgr = new MsrpManager(localIpAddress, localMsrpPort, getImsService(), mRcsSettings);\n            mMsrpMgr.setSecured(isSecured);\n            /* Build SDP part */\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            long maxSize = mRcsSettings.getMaxFileTransferSize();\n            String sdp = SdpUtils.buildFileSDP(ipAddress, localMsrpPort,\n                    mMsrpMgr.getLocalSocketProtocol(), getContent().getEncoding(), fileTransferId,\n                    fileSelector, getFileDisposition(), localSetup, mMsrpMgr.getLocalMsrpPath(),\n                    SdpUtils.DIRECTION_RECVONLY, maxSize);\n            /* Set the local SDP part in the dialog path */\n            dialogPath.setLocalContent(sdp);\n            // Test if the session should be interrupted\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Create a 200 OK response */\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    InstantMessagingService.FT_FEATURE_TAGS, sdp);\n            /* The signalisation is established */\n            dialogPath.setSigEstablished();\n            /* Send response */\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n            /* Create the MSRP server session */\n            if (localSetup.equals(\"passive\")) {\n                /* Passive mode: client wait a connection */\n                MsrpSession session = mMsrpMgr.createMsrpServerSession(remotePath, this);\n                /* Do not use right now the mapping to do not increase memory and cpu consumption */\n                session.setMapMsgIdFromTransationId(false);\n                mMsrpMgr.openMsrpSession(ImsFileSharingSession.DEFAULT_SO_TIMEOUT);\n                mMsrpMgr.sendEmptyChunk();\n            }\n            /* wait a response */\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            // Test if the session should be interrupted\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"ACK request received\");\n                }\n                /* / Create the MSRP client session */\n                if (localSetup.equals(\"active\")) {\n                    /* Active mode: client should connect */\n                    MsrpSession session = mMsrpMgr.createMsrpClientSession(remoteHost, remotePort,\n                            remotePath, this, fingerprint);\n                    session.setMapMsgIdFromTransationId(false);\n                    mMsrpMgr.openMsrpSession(ImsFileSharingSession.DEFAULT_SO_TIMEOUT);\n                    mMsrpMgr.sendEmptyChunk();\n                }\n                /* The session is established */\n                dialogPath.setSessionEstablished();\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(contact);\n                }\n                /* Start session timer */\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n                /* No response received: timeout */\n                handleError(new FileSharingError(FileSharingError.SEND_RESPONSE_FAILED));\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Unable to send 200OK response!\", e);\n            handleError(new FileSharingError(FileSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new FileSharingError(FileSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to initiate chat session as terminating!\", e);\n            handleError(new FileSharingError(FileSharingError.SEND_RESPONSE_FAILED, e));\n        }\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        // Not used in terminating side\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data received\");\n        }\n        setFileTransferred();\n        ContactId contact = getRemoteContact();\n        MmContent file = getContent();\n        Collection<ImsSessionListener> listeners = getListeners();\n        try {\n            file.writeData2File(data);\n            file.closeFile();\n            for (ImsSessionListener listener : listeners) {\n                ((FileSharingSessionListener) listener).onFileTransferred(file, contact,\n                        FileTransferData.UNKNOWN_EXPIRATION, FileTransferData.UNKNOWN_EXPIRATION,\n                        FileTransferProtocol.MSRP);\n            }\n        } catch (FileAccessException e) {\n            deleteFile();\n            for (ImsSessionListener listener : listeners) {\n                ((FileSharingSessionListener) listener).onTransferError(new FileSharingError(\n                        FileSharingError.MEDIA_SAVING_FAILED), contact);\n            }\n        }\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        if (isSessionInterrupted() || isInterrupted()) {\n            return true;\n        }\n        ContactId contact = getRemoteContact();\n        Collection<ImsSessionListener> listeners = getListeners();\n        try {\n            getContent().writeData2File(data);\n            for (ImsSessionListener listener : listeners) {\n                ((FileSharingSessionListener) listener).onTransferProgress(contact, currentSize,\n                        totalSize);\n            }\n        } catch (FileAccessException e) {\n            deleteFile();\n            for (ImsSessionListener listener : listeners) {\n                ((FileSharingSessionListener) listener).onTransferError(new FileSharingError(\n                        FileSharingError.MEDIA_SAVING_FAILED, e.getMessage()), contact);\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer aborted\");\n        }\n        if (!isFileTransferred()) {\n            deleteFile();\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void closeMediaSession() {\n        if (mMsrpMgr != null) {\n            mMsrpMgr.closeSession();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"MSRP session has been closed\");\n            }\n        }\n        if (!isFileTransferred()) {\n            deleteFile();\n        }\n    }\n\n    /**\n     * Delete file\n     */\n    private void deleteFile() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Delete incomplete received file\");\n        }\n        try {\n            getContent().deleteFile();\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.error(\"Can't delete received file\", e);\n            }\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/FavoriteLink.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\n/**\n * Favorite link\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FavoriteLink {\n    /**\n     * Link\n     */\n    private String link = null;\n\n    /**\n     * Name\n     */\n    private String name = null;\n\n    /**\n     * Constructor\n     * \n     * @param link Web link\n     */\n    public FavoriteLink(String link) {\n        this.link = link;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param name Name associated to the link\n     * @param link Web link\n     */\n    public FavoriteLink(String name, String link) {\n        this.name = name;\n        this.link = link;\n    }\n\n    /**\n     * Returns the name associated to the link\n     * \n     * @return\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Set the name associated to the link\n     * \n     * @param name Name\n     */\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    /**\n     * Returns the web link\n     * \n     * @return\n     */\n    public String getLink() {\n        return link;\n    }\n\n    /**\n     * Set the web link\n     * \n     * @param link Web link\n     */\n    public void setLink(String link) {\n        this.link = link;\n    }\n\n    /**\n     * Returns a string representation of the object\n     * \n     * @return String\n     */\n    public String toString() {\n        return \"link=\" + link + \", name=\" + name;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/Geoloc.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\n/**\n * Geoloc info\n * \n * @author Jean-Marc AUFFRET\n */\npublic class Geoloc {\n    /**\n     * Latitude\n     */\n    private double latitude;\n\n    /**\n     * Longitude\n     */\n    private double longitude;\n\n    /**\n     * Altitude\n     */\n    private double altitude;\n\n    /**\n     * Constructor\n     * \n     * @param latitude Latitude\n     * @param longitude Longitude\n     * @param altitude Altitude\n     */\n    public Geoloc(double latitude, double longitude, double altitude) {\n        this.latitude = latitude;\n        this.longitude = longitude;\n        this.altitude = altitude;\n    }\n\n    /**\n     * Returns the latitude\n     * \n     * @return Latitude\n     */\n    public double getLatitude() {\n        return latitude;\n    }\n\n    /**\n     * Set the latitude\n     * \n     * @param latitude Latitude\n     */\n    public void setLatitude(double latitude) {\n        this.latitude = latitude;\n    }\n\n    /**\n     * Returns the longitude\n     * \n     * @return Longitude\n     */\n    public double getLongitude() {\n        return longitude;\n    }\n\n    /**\n     * Set the longitude\n     * \n     * @param longitude Longitude\n     */\n    public void setLongitude(double longitude) {\n        this.longitude = longitude;\n    }\n\n    /**\n     * Returns the altitude\n     * \n     * @return Altitude\n     */\n    public double getAltitude() {\n        return altitude;\n    }\n\n    /**\n     * Set the altitude\n     * \n     * @param altitude Altitude\n     */\n    public void setAltitude(double altitude) {\n        this.altitude = altitude;\n    }\n\n    /**\n     * Returns a string representation of the object\n     * \n     * @return String\n     */\n    public String toString() {\n        return \"latitude=\" + latitude + \", longitude=\" + longitude + \", altitude=\" + altitude;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PhotoIcon.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\n/**\n * Photo icon\n * \n * @author Jean-Marc AUFFRET\n */\npublic class PhotoIcon {\n    /**\n     * Photo content\n     */\n    private byte[] content = null;\n\n    /**\n     * Image type\n     */\n    private String type = \"image/jpeg\";\n\n    /**\n     * Width\n     */\n    private int width = 0;\n\n    /**\n     * Height\n     */\n    private int height = 0;\n\n    /**\n     * Etag\n     */\n    private String etag = null;\n\n    /**\n     * Constructor\n     * \n     * @param content Photo content\n     * @param width Width\n     * @param height Height\n     * @param etag Etag value\n     */\n    public PhotoIcon(byte[] content, int width, int height, String etag) {\n        this.content = content;\n        this.width = width;\n        this.height = height;\n        this.etag = etag;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param content Photo content\n     * @param width Width\n     * @param height Height\n     */\n    public PhotoIcon(byte[] content, int width, int height) {\n        this(content, width, height, null);\n    }\n\n    /**\n     * Returns the Etag value\n     * \n     * @return Tag\n     */\n    public String getEtag() {\n        return etag;\n    }\n\n    /**\n     * Set the Etag value\n     * \n     * @param etag Etag\n     */\n    public void setEtag(String etag) {\n        this.etag = etag;\n    }\n\n    /**\n     * Returns the image type\n     * \n     * @return Type\n     */\n    public String getType() {\n        return type;\n    }\n\n    /**\n     * Returns the icon width\n     * \n     * @return Width in pixel\n     */\n    public int getWidth() {\n        return width;\n    }\n\n    /**\n     * Returns the icon height\n     * \n     * @return Height in pixel\n     */\n    public int getHeight() {\n        return height;\n    }\n\n    /**\n     * Returns the icon size\n     * \n     * @return Size in bytes\n     */\n    public long getSize() {\n        if (content != null) {\n            return content.length;\n        }\n        return 0L;\n    }\n\n    /**\n     * Returns the photo content\n     * \n     * @return Photo content\n     */\n    public byte[] getContent() {\n        return content;\n    }\n\n    /**\n     * Returns the resolution\n     * \n     * @return String as [width]x[height]\n     */\n    public String getResolution() {\n        return width + \"x\" + height;\n    }\n\n    /**\n     * Returns a string representation of the object\n     * \n     * @return String\n     */\n    public String toString() {\n        return \"width=\" + width + \", height=\" + height + \", size=\" + getSize() + \", etag=\" + etag;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PresenceError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\n\n/**\n * Presence error\n * \n * @author jexa7410\n */\npublic class PresenceError extends ImsServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Subscription has failed (e.g. 404 not found)\n     */\n    public final static int SUBSCRIBE_FAILED = PRESENCE_ERROR_CODES + 1;\n\n    /**\n     * Publish has failed (e.g. 408 timeout)\n     */\n    public final static int PUBLISH_FAILED = PRESENCE_ERROR_CODES + 2;\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public PresenceError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public PresenceError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public PresenceError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PresenceInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\n/**\n * Presence info\n * \n * @author Jean-Marc AUFFRET\n */\npublic class PresenceInfo {\n    /**\n     * Presence status \"unknown\"\n     */\n    public final static String UNKNOWN = \"unknown\";\n\n    /**\n     * Presence status \"online\"\n     */\n    public final static String ONLINE = \"open\";\n\n    /**\n     * Presence status \"offline\"\n     */\n    public final static String OFFLINE = \"closed\";\n\n    /**\n     * Presence relationship: contact 'rcs granted' with the user\n     */\n    public final static String RCS_ACTIVE = \"active\";\n\n    /**\n     * Presence relationship: the user has revoked the contact\n     */\n    public final static String RCS_REVOKED = \"revoked\";\n\n    /**\n     * Presence relationship: the user has blocked the contact\n     */\n    public final static String RCS_BLOCKED = \"blocked\";\n\n    /**\n     * Presence relationship: the user has sent an invitation to the contact without response for\n     * now\n     */\n    public final static String RCS_PENDING_OUT = \"pending_out\";\n\n    /**\n     * Presence relationship: the contact has sent an invitation to the user without response for\n     * now\n     */\n    public final static String RCS_PENDING = \"pending\";\n\n    /**\n     * Presence relationship: the contact has sent an invitation to the user and cancel it\n     */\n    public final static String RCS_CANCELLED = \"cancelled\";\n\n    /**\n     * Presence timestamp\n     */\n    private long timestamp = System.currentTimeMillis();\n\n    /**\n     * Presence status\n     */\n    private String status = PresenceInfo.ONLINE;\n\n    /**\n     * Free text\n     */\n    private String freetext = null;\n\n    /**\n     * Favorite link\n     */\n    private FavoriteLink favoriteLink = null;\n\n    /**\n     * Photo icon\n     */\n    private PhotoIcon photo = null;\n\n    /**\n     * Geoloc\n     */\n    private Geoloc geoloc = null;\n\n    /**\n     * Constructor\n     */\n    public PresenceInfo() {\n    }\n\n    /**\n     * Set the timestamp\n     * \n     * @param timestamp Timestamp\n     */\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    /**\n     * Returns the timestamp\n     * \n     * @return Timestamp\n     */\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    /**\n     * Reset the timestamp\n     */\n    public void resetTimestamp() {\n        timestamp = PresenceInfo.getNewTimestamp();\n    }\n\n    /**\n     * Returns a new timestamp\n     * \n     * @return Timestamp\n     */\n    public static long getNewTimestamp() {\n        return System.currentTimeMillis();\n    }\n\n    /**\n     * Returns the presence status\n     * \n     * @return Status\n     */\n    public String getPresenceStatus() {\n        return status;\n    }\n\n    /**\n     * Set the presence status\n     * \n     * @param status New status\n     */\n    public void setPresenceStatus(String status) {\n        this.status = status;\n    }\n\n    /**\n     * Is status online\n     * \n     * @return Boolean\n     */\n    public boolean isOnline() {\n        return (ONLINE.equals(status));\n    }\n\n    /**\n     * Is status offline\n     * \n     * @return Boolean\n     */\n    public boolean isOffline() {\n        return (OFFLINE.equals(status));\n    }\n\n    /**\n     * Returns the free text\n     * \n     * @return Free text\n     */\n    public String getFreetext() {\n        return freetext;\n    }\n\n    /**\n     * Set the free text\n     * \n     * @param freetext New free text\n     */\n    public void setFreetext(String freetext) {\n        this.freetext = freetext;\n    }\n\n    /**\n     * Get the favorite link\n     * \n     * @return Favorite link\n     */\n    public FavoriteLink getFavoriteLink() {\n        return favoriteLink;\n    }\n\n    /**\n     * Get the favorite link URL\n     * \n     * @return Favorite link URL\n     */\n    public String getFavoriteLinkUrl() {\n        String url = null;\n        if (favoriteLink != null) {\n            url = favoriteLink.getLink();\n        }\n        return url;\n    }\n\n    /**\n     * Set the favorite link\n     * \n     * @param favoriteLink Favorite link\n     */\n    public void setFavoriteLink(FavoriteLink favoriteLink) {\n        this.favoriteLink = favoriteLink;\n    }\n\n    /**\n     * Set the favorite link URL\n     * \n     * @param url Favorite link URL\n     */\n    public void setFavoriteLinkUrl(String url) {\n        if (favoriteLink == null) {\n            favoriteLink = new FavoriteLink(url);\n        }\n        favoriteLink.setLink(url);\n    }\n\n    /**\n     * Get the photo-icon\n     */\n    public PhotoIcon getPhotoIcon() {\n        return photo;\n    }\n\n    /**\n     * Set the photo-icon\n     * \n     * @param photo Photo-icon\n     */\n    public void setPhotoIcon(PhotoIcon photo) {\n        this.photo = photo;\n    }\n\n    /**\n     * Get the geoloc\n     * \n     * @return Geoloc\n     */\n    public Geoloc getGeoloc() {\n        return geoloc;\n    }\n\n    /**\n     * Set the geoloc\n     * \n     * @param geoloc Geoloc\n     */\n    public void setGeoloc(Geoloc geoloc) {\n        this.geoloc = geoloc;\n    }\n\n    /**\n     * Returns a string representation of the object\n     * \n     * @return String\n     */\n    public String toString() {\n        String result = \"- Timestamp: \" + timestamp + \"\\n\" + \"- Status: \" + status + \"\\n\"\n                + \"- Freetext: \" + freetext + \"\\n\";\n        if (favoriteLink != null) {\n            result += \"- Favorite link: \" + favoriteLink.toString() + \"\\n\";\n        }\n        if (photo != null) {\n            result += \"- Photo-icon: \" + photo.toString() + \"\\n\";\n        }\n        if (geoloc != null) {\n            result += \"- Geoloc: \" + geoloc.toString() + \"\\n\";\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PresenceService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8_STR;\n\nimport com.gsma.rcs.addressbook.AddressBookEventListener;\nimport com.gsma.rcs.addressbook.AddressBookManager;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.http.HttpResponse;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.presence.pidf.PidfDocument;\nimport com.gsma.rcs.core.ims.service.presence.xdm.XdmManager;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.StartService;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.StringUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\nimport android.content.OperationApplicationException;\nimport android.os.RemoteException;\n\nimport java.util.Set;\n\n/**\n * Presence service\n * \n * @author Jean-Marc AUFFRET\n */\npublic class PresenceService extends ImsService implements AddressBookEventListener {\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    public final boolean mPermanentState;\n\n    private PresenceInfo mPresenceInfo = new PresenceInfo();\n\n    private final PublishManager mPublisher;\n\n    private final XdmManager mXdm;\n\n    private final SubscribeManager mWatcherInfoSubscriber;\n\n    private final SubscribeManager mPresenceSubscriber;\n\n    private static final Logger sLogger = Logger.getLogger(PresenceService.class.getSimpleName());\n\n    private final AddressBookManager mAddressBookManager;\n\n    private final Context mCtx;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param ctx Context\n     * @param rcsSettings RcsSettings\n     * @param addressBookManager The address book manager\n     * @param contactsManager ContactManager\n     */\n    public PresenceService(ImsModule parent, Context ctx, RcsSettings rcsSettings,\n            ContactManager contactsManager, AddressBookManager addressBookManager) {\n        super(parent, rcsSettings.isSocialPresenceSupported());\n        mCtx = ctx;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactsManager;\n        mAddressBookManager = addressBookManager;\n\n        // Set presence service options\n        mPermanentState = mRcsSettings.isPermanentStateModeActivated();\n\n        // Instantiate the XDM manager\n        mXdm = new XdmManager(ctx);\n\n        // Instantiate the publish manager\n        mPublisher = new PublishManager(parent, mRcsSettings);\n\n        // Instantiate the subscribe manager for watcher info\n        mWatcherInfoSubscriber = new WatcherInfoSubscribeManager(parent, mRcsSettings);\n\n        // Instantiate the subscribe manager for presence\n        mPresenceSubscriber = new PresenceSubscribeManager(parent, mRcsSettings);\n\n    }\n\n    public void initialize() {\n        mPublisher.initialize();\n        mWatcherInfoSubscriber.initialize();\n        mPresenceSubscriber.initialize();\n    }\n\n    @Override\n    public synchronized void start() throws PayloadException, NetworkException {\n        if (isServiceStarted()) {\n            // Already started\n            return;\n        }\n        setServiceStarted(true);\n\n        mAddressBookManager.addAddressBookListener(this);\n\n        // Restore the last presence info from the contacts database\n        mPresenceInfo = mContactManager.getMyPresenceInfo();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Last presence info:\\n\" + mPresenceInfo.toString());\n        }\n\n        // Initialize the XDM interface\n        mXdm.initialize();\n\n        // Add me in the granted set if necessary\n        Set<ContactId> grantedContacts = mXdm.getGrantedContacts();\n\n        ContactId me = ImsModule.getImsUserProfile().getUsername();\n\n        if (!grantedContacts.contains(me)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"The enduser is not in the granted set: add it now\");\n            }\n            mXdm.addContactToGrantedList(me);\n        }\n\n        // It may be necessary to initiate the address book first launch or account check procedure\n        if (StartService.getNewUserAccount(mCtx)) {\n            Set<ContactId> blockedContacts = mXdm.getBlockedContacts();\n            firstLaunchOrAccountChangedCheck(grantedContacts, blockedContacts);\n        }\n\n        // Subscribe to watcher-info events\n        if (mWatcherInfoSubscriber.subscribe()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Subscribe manager is started with success for watcher-info\");\n            }\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Subscribe manager can't be started for watcher-info\");\n            }\n        }\n\n        // Subscribe to presence events\n        if (mPresenceSubscriber.subscribe()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Subscribe manager is started with success for presence\");\n            }\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Subscribe manager can't be started for presence\");\n            }\n        }\n\n        // Publish initial presence info\n        String xml;\n        if (mPermanentState) {\n            xml = buildPartialPresenceInfoDocument(mPresenceInfo);\n        } else {\n            xml = buildPresenceInfoDocument(mPresenceInfo);\n        }\n        if (mPublisher.publish(xml)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Publish manager is started with success\");\n            }\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Publish manager can't be started\");\n            }\n        }\n\n        // Force a presence check\n        handleAddressBookHasChanged();\n    }\n\n    /**\n     * First launch or account changed check <br>\n     * Check done at first launch of the service on the phone after install of the application or\n     * when the user account changed <br>\n     * We create a new contact with the adequate state for each RCS number in the XDM lists that is\n     * not already existing on the phone\n     * \n     * @param grantedContacts of granted contacts\n     * @param blockedContacts of blocked contacts\n     * @throws PayloadException\n     */\n    private void firstLaunchOrAccountChangedCheck(Set<ContactId> grantedContacts,\n            Set<ContactId> blockedContacts) throws PayloadException {\n        final String publicUri = ImsModule.getImsUserProfile().getPublicUri();\n        try {\n            boolean logActivated = sLogger.isActivated();\n            if (logActivated) {\n                sLogger.debug(\"First launch or account change check procedure\");\n            }\n            mContactManager.flushRcsContactProvider();\n            ContactId me = null;\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(publicUri);\n            if (number == null) {\n                if (logActivated) {\n                    sLogger.error(\"Cannot parse user contact \".concat(publicUri));\n                }\n            } else {\n                me = ContactUtil.createContactIdFromValidatedData(number);\n            }\n\n            for (ContactId contact : grantedContacts) {\n                if (me != null && !contact.equals(me)) {\n                    if (!PresenceUtils.isNumberInAddressBook(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(new StringBuilder(\"The RCS number \").append(contact)\n                                    .append(\" was not found in the address book: add it\")\n                                    .toString());\n                        }\n                        PresenceUtils.createRcsContactIfNeeded(mCtx, contact);\n                    }\n                    mContactManager.updateRcsStatusOrCreateNewContact(contact,\n                            RcsStatus.PENDING_OUT);\n                }\n            }\n\n            for (ContactId contact : blockedContacts) {\n                if (!PresenceUtils.isNumberInAddressBook(contact)) {\n                    if (logActivated) {\n                        sLogger.debug(new StringBuilder(\"The RCS number \").append(contact)\n                                .append(\" was not found in the address book: add it\").toString());\n                    }\n                    PresenceUtils.createRcsContactIfNeeded(mCtx, contact);\n                    mContactManager.blockContact(contact);\n                    mContactManager.updateRcsStatusOrCreateNewContact(contact, RcsStatus.BLOCKED);\n                }\n            }\n        } catch (OperationApplicationException e) {\n            throw new PayloadException(new StringBuilder(\"Failed creating contact for URI : \")\n                    .append(publicUri).toString(), e);\n\n        } catch (ContactManagerException e) {\n            throw new PayloadException(new StringBuilder(\"Failed creating contact for URI : \")\n                    .append(publicUri).toString(), e);\n\n        } catch (FileAccessException e) {\n            throw new PayloadException(new StringBuilder(\"Failed creating contact for URI : \")\n                    .append(publicUri).toString(), e);\n\n        } catch (RemoteException e) {\n            throw new PayloadException(new StringBuilder(\"Failed creating contact for URI : \")\n                    .append(publicUri).toString(), e);\n        }\n    }\n\n    @Override\n    public synchronized void stop(ImsServiceSession.TerminationReason reasonCode)\n            throws PayloadException, NetworkException {\n        if (!isServiceStarted()) {\n            // Already stopped\n            return;\n        }\n        setServiceStarted(false);\n\n        mAddressBookManager.removeAddressBookListener(this);\n\n        if (!mPermanentState) {\n            // If not permanent state mode: publish a last presence info before\n            // to quit\n            if ((getImsModule().getCurrentNetworkInterface() != null)\n                    && getImsModule().getCurrentNetworkInterface().isRegistered()\n                    && mPublisher.isPublished()) {\n                String xml = buildPresenceInfoDocument(mPresenceInfo);\n                mPublisher.publish(xml);\n            }\n        }\n\n        // Stop publish\n        mPublisher.terminate();\n\n        // Stop subscriptions\n        mWatcherInfoSubscriber.terminate();\n        mPresenceSubscriber.terminate();\n    }\n\n    /**\n     * Check the IMS service\n     */\n    public void check() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Check presence service\");\n        }\n\n        // Check subscribe manager status for watcher-info events\n        if (!mWatcherInfoSubscriber.isSubscribed()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Subscribe manager not yet started for watcher-info\");\n            }\n\n            if (mWatcherInfoSubscriber.subscribe()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Subscribe manager is started with success for watcher-info\");\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Subscribe manager can't be started for watcher-info\");\n                }\n            }\n        }\n\n        // Check subscribe manager status for presence events\n        if (!mPresenceSubscriber.isSubscribed()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Subscribe manager not yet started for presence\");\n            }\n\n            if (mPresenceSubscriber.subscribe()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Subscribe manager is started with success for presence\");\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Subscribe manager can't be started for presence\");\n                }\n            }\n        }\n    }\n\n    /**\n     * Is permanent state procedure\n     * \n     * @return Boolean\n     */\n    public boolean isPermanentState() {\n        return mPermanentState;\n    }\n\n    /**\n     * Set the presence info\n     * \n     * @param info Presence info\n     */\n    public void setPresenceInfo(PresenceInfo info) {\n        mPresenceInfo = info;\n    }\n\n    /**\n     * Returns the presence info\n     * \n     * @return Presence info\n     */\n    public PresenceInfo getPresenceInfo() {\n        return mPresenceInfo;\n    }\n\n    /**\n     * Returns the publish manager\n     * \n     * @return Publish manager\n     */\n    public PublishManager getPublishManager() {\n        return mPublisher;\n    }\n\n    /**\n     * Returns the watcher-info subscribe manager\n     * \n     * @return Subscribe manager\n     */\n    public SubscribeManager getWatcherInfoSubscriber() {\n        return mWatcherInfoSubscriber;\n    }\n\n    /**\n     * Returns the presence subscribe manager\n     * \n     * @return Subscribe manager\n     */\n    public SubscribeManager getPresenceSubscriber() {\n        return mPresenceSubscriber;\n    }\n\n    /**\n     * Returns the XDM manager\n     * \n     * @return XDM manager\n     */\n    public XdmManager getXdmManager() {\n        return mXdm;\n    }\n\n    /**\n     * Build boolean status value\n     * \n     * @param state Boolean state\n     * @return String\n     */\n    private String buildBooleanStatus(boolean state) {\n        if (state) {\n            return \"open\";\n        }\n        return \"closed\";\n    }\n\n    /**\n     * Build capabilities document\n     * \n     * @param timestamp Timestamp\n     * @param capabilities Capabilities\n     * @return Document\n     */\n    private String buildCapabilities(String timestamp, Capabilities capabilities) {\n        String publicUri = ImsModule.getImsUserProfile().getPublicUri();\n        return new StringBuilder(\"<tuple id=\\\"t1\\\">\").append(SipUtils.CRLF)\n                .append(\"  <status><basic>\")\n                .append(buildBooleanStatus(capabilities.isFileTransferMsrpSupported()))\n                .append(\"</basic></status>\").append(SipUtils.CRLF)\n                .append(\"  <op:service-description>\").append(SipUtils.CRLF)\n                .append(\"    <op:service-id>\").append(PresenceUtils.FEATURE_RCS2_FT)\n                .append(\"</op:service-id>\").append(SipUtils.CRLF)\n                .append(\"    <op:version>1.0</op:version>\").append(SipUtils.CRLF)\n                .append(\"  </op:service-description>\").append(SipUtils.CRLF).append(\"  <contact>\")\n                .append(publicUri).append(\"</contact>\").append(SipUtils.CRLF)\n                .append(\"  <timestamp>\").append(timestamp).append(\"</timestamp>\")\n                .append(SipUtils.CRLF).append(\"</tuple>\").append(SipUtils.CRLF)\n                .append(\"<tuple id=\\\"t2\\\">\").append(SipUtils.CRLF).append(\"  <status><basic>\")\n                .append(buildBooleanStatus(capabilities.isImageSharingSupported()))\n                .append(\"</basic></status>\").append(SipUtils.CRLF)\n                .append(\"  <op:service-description>\").append(SipUtils.CRLF)\n                .append(\"    <op:service-id>\").append(PresenceUtils.FEATURE_RCS2_IMAGE_SHARE)\n                .append(\"</op:service-id>\").append(SipUtils.CRLF)\n                .append(\"    <op:version>1.0</op:version>\").append(SipUtils.CRLF)\n                .append(\"  </op:service-description>\").append(SipUtils.CRLF).append(\"  <contact>\")\n                .append(publicUri).append(\"</contact>\").append(SipUtils.CRLF)\n                .append(\"  <timestamp>\").append(timestamp).append(\"</timestamp>\")\n                .append(SipUtils.CRLF).append(\"</tuple>\").append(SipUtils.CRLF)\n                .append(\"<tuple id=\\\"t3\\\">\").append(SipUtils.CRLF).append(\"  <status><basic>\")\n                .append(buildBooleanStatus(capabilities.isVideoSharingSupported()))\n                .append(\"</basic></status>\").append(SipUtils.CRLF)\n                .append(\"  <op:service-description>\").append(SipUtils.CRLF)\n                .append(\"    <op:service-id>\").append(PresenceUtils.FEATURE_RCS2_VIDEO_SHARE)\n                .append(\"</op:service-id>\").append(SipUtils.CRLF)\n                .append(\"    <op:version>1.0</op:version>\").append(SipUtils.CRLF)\n                .append(\"  </op:service-description>\").append(SipUtils.CRLF).append(\"  <contact>\")\n                .append(publicUri).append(\"</contact>\").append(SipUtils.CRLF)\n                .append(\"  <timestamp>\").append(timestamp).append(\"</timestamp>\")\n                .append(SipUtils.CRLF).append(\"</tuple>\").append(SipUtils.CRLF)\n                .append(\"<tuple id=\\\"t4\\\">\").append(SipUtils.CRLF).append(\"  <status><basic>\")\n                .append(buildBooleanStatus(capabilities.isImSessionSupported()))\n                .append(\"</basic></status>\").append(SipUtils.CRLF)\n                .append(\"  <op:service-description>\").append(SipUtils.CRLF)\n                .append(\"    <op:service-id>\").append(PresenceUtils.FEATURE_RCS2_CHAT)\n                .append(\"</op:service-id>\").append(SipUtils.CRLF)\n                .append(\"    <op:version>1.0</op:version>\").append(SipUtils.CRLF)\n                .append(\"  </op:service-description>\").append(SipUtils.CRLF).append(\"  <contact>\")\n                .append(publicUri).append(\"</contact>\").append(SipUtils.CRLF)\n                .append(\"  <timestamp>\").append(timestamp).append(\"</timestamp>\")\n                .append(SipUtils.CRLF).append(\"</tuple>\").append(SipUtils.CRLF)\n                .append(\"<tuple id=\\\"t5\\\">\").append(SipUtils.CRLF).append(\"  <status><basic>\")\n                .append(buildBooleanStatus(capabilities.isCsVideoSupported()))\n                .append(\"</basic></status>\").append(SipUtils.CRLF)\n                .append(\"  <op:service-description>\").append(SipUtils.CRLF)\n                .append(\"    <op:service-id>\").append(PresenceUtils.FEATURE_RCS2_CS_VIDEO)\n                .append(\"</op:service-id>\").append(SipUtils.CRLF)\n                .append(\"    <op:version>1.0</op:version>\").append(SipUtils.CRLF)\n                .append(\"  </op:service-description>\").append(SipUtils.CRLF).append(\"  <contact>\")\n                .append(publicUri).append(\"</contact>\").append(SipUtils.CRLF)\n                .append(\"  <timestamp>\").append(timestamp).append(\"</timestamp>\")\n                .append(SipUtils.CRLF).append(\"</tuple>\").append(SipUtils.CRLF).toString();\n    }\n\n    /**\n     * Build geoloc document\n     * \n     * @param timestamp Timestamp\n     * @param geolocInfo Geoloc info\n     * @return Document\n     */\n    private String buildGeoloc(String timestamp, Geoloc geolocInfo) {\n        String document = \"\";\n        if (geolocInfo != null) {\n            document += \"<tuple id=\\\"g1\\\">\" + SipUtils.CRLF\n                    + \"  <status><basic>open</basic></status>\" + SipUtils.CRLF + \"   <gp:geopriv>\"\n                    + SipUtils.CRLF + \"    <gp:location-info><gml:location>\" + SipUtils.CRLF\n                    + \"        <gml:Point srsDimension=\\\"3\\\"><gml:pos>\" + geolocInfo.getLatitude()\n                    + \" \" + geolocInfo.getLongitude() + \" \" + geolocInfo.getAltitude()\n                    + \"</gml:pos>\" + SipUtils.CRLF + \"        </gml:Point></gml:location>\"\n                    + SipUtils.CRLF + \"    </gp:location-info>\" + SipUtils.CRLF\n                    + \"    <gp:method>GPS</gp:method>\" + SipUtils.CRLF + \"   </gp:geopriv>\"\n                    + SipUtils.CRLF + \"  <contact>\" + ImsModule.getImsUserProfile().getPublicUri()\n                    + \"</contact>\" + SipUtils.CRLF + \"  <timestamp>\" + timestamp + \"</timestamp>\"\n                    + SipUtils.CRLF + \"</tuple>\" + SipUtils.CRLF;\n        }\n        return document;\n    }\n\n    /**\n     * Build person info document\n     * \n     * @param info Presence info\n     * @return Document\n     */\n    private String buildPersonInfo(PresenceInfo info) {\n        StringBuilder document = new StringBuilder(\"  <op:overriding-willingness>\")\n                .append(SipUtils.CRLF).append(\"    <op:basic>\").append(info.getPresenceStatus())\n                .append(\"</op:basic>\").append(SipUtils.CRLF)\n                .append(\"  </op:overriding-willingness>\").append(SipUtils.CRLF);\n\n        FavoriteLink favoriteLink = info.getFavoriteLink();\n        if ((favoriteLink != null) && (favoriteLink.getLink() != null)) {\n            document.append(\"  <ci:homepage>\")\n                    .append(StringUtils.encodeXML(favoriteLink.getLink())).append(\"</ci:homepage>\")\n                    .append(SipUtils.CRLF);\n        }\n\n        PhotoIcon photoIcon = info.getPhotoIcon();\n        String eTag = (photoIcon != null) ? photoIcon.getEtag() : null;\n        if (photoIcon != null && eTag != null) {\n            document.append(\"  <rpid:status-icon opd:etag=\\\"\").append(eTag)\n                    .append(\"\\\" opd:fsize=\\\"\").append(photoIcon.getSize())\n                    .append(\"\\\" opd:contenttype=\\\"\").append(photoIcon.getType())\n                    .append(\"\\\" opd:resolution=\\\"\").append(photoIcon.getResolution()).append(\"\\\">\")\n                    .append(mXdm.getEndUserPhotoIconUrl()).append(\"</rpid:status-icon>\")\n                    .append(SipUtils.CRLF);\n        }\n\n        String freetext = info.getFreetext();\n        if (freetext != null) {\n            document.append(\"  <pdm:note>\").append(StringUtils.encodeXML(freetext))\n                    .append(\"</pdm:note>\").append(SipUtils.CRLF);\n        }\n\n        return document.toString();\n    }\n\n    /**\n     * Build presence info document (RCS 1.0)\n     * \n     * @param info Presence info\n     * @return Document\n     */\n    private String buildPresenceInfoDocument(PresenceInfo info) {\n        String document = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\").append(UTF8_STR)\n                .append(\"\\\"?>\").append(SipUtils.CRLF)\n                .append(\"<presence xmlns=\\\"urn:ietf:params:xml:ns:pidf\\\"\")\n                .append(\" xmlns:op=\\\"urn:oma:xml:prs:pidf:oma-pres\\\"\")\n                .append(\" xmlns:opd=\\\"urn:oma:xml:pde:pidf:ext\\\"\")\n                .append(\" xmlns:pdm=\\\"urn:ietf:params:xml:ns:pidf:data-model\\\"\")\n                .append(\" xmlns:ci=\\\"urn:ietf:params:xml:ns:pidf:cipid\\\"\")\n                .append(\" xmlns:rpid=\\\"urn:ietf:params:xml:ns:pidf:rpid\\\"\")\n                .append(\" xmlns:gp=\\\"urn:ietf:params:xml:ns:pidf:geopriv10\\\"\")\n                .append(\" xmlns:gml=\\\"urn:opengis:specification:gml:schema-xsd:feature:v3.0\\\"\")\n                .append(\" entity=\\\"\").append(ImsModule.getImsUserProfile().getPublicUri())\n                .append(\"\\\">\").append(SipUtils.CRLF).toString();\n\n        // Encode timestamp\n        String timestamp = DateUtils.encodeDate(info.getTimestamp());\n\n        // Build capabilities\n        document += buildCapabilities(timestamp, mRcsSettings.getMyCapabilities());\n\n        // Build geoloc\n        document += buildGeoloc(timestamp, info.getGeoloc());\n\n        // Build person info\n        document += \"<pdm:person id=\\\"p1\\\">\" + SipUtils.CRLF + buildPersonInfo(info)\n                + \"  <pdm:timestamp>\" + timestamp + \"</pdm:timestamp>\" + SipUtils.CRLF\n                + \"</pdm:person>\" + SipUtils.CRLF;\n\n        // Add last header\n        document += \"</presence>\" + SipUtils.CRLF;\n\n        return document;\n    }\n\n    /**\n     * Build partial presence info document (all presence info except permanent state info)\n     * \n     * @param info Presence info\n     * @return Document\n     */\n    private String buildPartialPresenceInfoDocument(PresenceInfo info) {\n        String document = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\").append(UTF8_STR)\n                .append(\"\\\"?>\").append(SipUtils.CRLF)\n                .append(\"<presence xmlns=\\\"urn:ietf:params:xml:ns:pidf\\\"\")\n                .append(\" xmlns:op=\\\"urn:oma:xml:prs:pidf:oma-pres\\\"\")\n                .append(\" xmlns:opd=\\\"urn:oma:xml:pde:pidf:ext\\\"\")\n                .append(\" xmlns:pdm=\\\"urn:ietf:params:xml:ns:pidf:data-model\\\"\")\n                .append(\" xmlns:ci=\\\"urn:ietf:params:xml:ns:pidf:cipid\\\"\")\n                .append(\" xmlns:rpid=\\\"urn:ietf:params:xml:ns:pidf:rpid\\\"\")\n                .append(\" xmlns:gp=\\\"urn:ietf:params:xml:ns:pidf:geopriv10\\\"\")\n                .append(\" xmlns:gml=\\\"urn:opengis:specification:gml:schema-xsd:feature:v3.0\\\"\")\n                .append(\" entity=\\\"\").append(ImsModule.getImsUserProfile().getPublicUri())\n                .append(\"\\\">\").append(SipUtils.CRLF).toString();\n\n        // Encode timestamp\n        String timestamp = DateUtils.encodeDate(info.getTimestamp());\n\n        // Build capabilities\n        document += buildCapabilities(timestamp, mRcsSettings.getMyCapabilities());\n\n        // Build geoloc\n        document += buildGeoloc(timestamp, info.getGeoloc());\n\n        // Add last header\n        document += \"</presence>\" + SipUtils.CRLF;\n\n        return document;\n    }\n\n    /**\n     * Build permanent presence info document (RCS R2.0)\n     * \n     * @param info Presence info\n     * @return Document\n     */\n    private String buildPermanentPresenceInfoDocument(PresenceInfo info) {\n        String document = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\").append(UTF8_STR)\n                .append(\"\\\"?>\").append(SipUtils.CRLF)\n                .append(\"<presence xmlns=\\\"urn:ietf:params:xml:ns:pidf\\\"\")\n                .append(\" xmlns:op=\\\"urn:oma:xml:prs:pidf:oma-pres\\\"\")\n                .append(\" xmlns:opd=\\\"urn:oma:xml:pde:pidf:ext\\\"\")\n                .append(\" xmlns:pdm=\\\"urn:ietf:params:xml:ns:pidf:data-model\\\"\")\n                .append(\" xmlns:ci=\\\"urn:ietf:params:xml:ns:pidf:cipid\\\"\")\n                .append(\" xmlns:rpid=\\\"urn:ietf:params:xml:ns:pidf:rpid\\\"\").append(\" entity=\\\"\")\n                .append(ImsModule.getImsUserProfile().getPublicUri()).append(\"\\\">\")\n                .append(SipUtils.CRLF).toString();\n\n        // Encode timestamp\n        String timestamp = DateUtils.encodeDate(info.getTimestamp());\n\n        // Build person info (freetext, favorite link and photo-icon)\n        document += \"<pdm:person id=\\\"p1\\\">\" + SipUtils.CRLF + buildPersonInfo(info)\n                + \"  <pdm:timestamp>\" + timestamp + \"</pdm:timestamp>\" + SipUtils.CRLF\n                + \"</pdm:person>\" + SipUtils.CRLF;\n\n        // Add last header\n        document += \"</presence>\" + SipUtils.CRLF;\n\n        return document;\n    }\n\n    /**\n     * Update photo-icon\n     * \n     * @param photoIcon Photo-icon\n     * @return Boolean result\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    private boolean updatePhotoIcon(PhotoIcon photoIcon) throws PayloadException, NetworkException {\n        boolean result = false;\n\n        // Photo-icon management\n        PhotoIcon currentPhoto = mPresenceInfo.getPhotoIcon();\n        if ((photoIcon != null) && (photoIcon.getEtag() == null)) {\n            // Test photo icon size\n            long maxSize = mRcsSettings.getMaxPhotoIconSize();\n            if ((maxSize != 0) && (photoIcon.getSize() > maxSize)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Max photo size achieved\");\n                }\n                return false;\n            }\n\n            // Upload the new photo-icon\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Upload the photo-icon\");\n            }\n            result = uploadPhotoIcon(photoIcon);\n        } else if ((photoIcon == null) && (currentPhoto != null)) {\n            // Delete the current photo-icon\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Delete the photo-icon\");\n            }\n            result = deletePhotoIcon();\n        } else {\n            // Nothing to do\n            result = true;\n        }\n\n        return result;\n    }\n\n    /**\n     * Publish presence info\n     * \n     * @param info Presence info\n     * @return true if the presence info has been publish with success, else returns false\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean publishPresenceInfo(PresenceInfo info) throws PayloadException, NetworkException {\n        boolean result = false;\n\n        // Photo-icon management\n        result = updatePhotoIcon(info.getPhotoIcon());\n        if (!result) {\n            // Can't update the photo-icon in the XDM server\n            return result;\n        }\n\n        // Reset timestamp\n        info.resetTimestamp();\n\n        // Publish presence info\n        if (mPermanentState) {\n            // Permanent state procedure: publish the new presence info via XCAP\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Publish presence info via XDM request (permanent state)\");\n            }\n            String xml = buildPermanentPresenceInfoDocument(info);\n            HttpResponse response = mXdm.setPresenceInfo(xml);\n            if ((response != null) && response.isSuccessfullResponse()) {\n                result = true;\n            } else {\n                result = false;\n            }\n        } else {\n            // SIP procedure: publish the new presence info via SIP\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Publish presence info via SIP request\");\n            }\n            String xml = buildPresenceInfoDocument(info);\n            result = mPublisher.publish(xml);\n        }\n\n        // If server updated with success then update contact info cache\n        if (result) {\n            mPresenceInfo = info;\n        }\n\n        return result;\n    }\n\n    /**\n     * Upload photo icon\n     * \n     * @param photo Photo icon\n     * @return Boolean result\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean uploadPhotoIcon(PhotoIcon photo) throws PayloadException, NetworkException {\n        // Upload the photo to the XDM server\n        HttpResponse response = mXdm.uploadEndUserPhoto(photo);\n        if ((response != null) && response.isSuccessfullResponse()) {\n            // Extract the Etag value in the 200 OK response\n            String etag = response.getHeader(\"Etag\");\n            if (etag != null) {\n                // Removed quotes\n                etag = StringUtils.removeQuotes(etag);\n            } else {\n                etag = \"\" + System.currentTimeMillis();\n            }\n\n            // Set the Etag of the photo-icon\n            photo.setEtag(etag);\n\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Delete photo icon\n     * \n     * @return Boolean result\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean deletePhotoIcon() throws PayloadException, NetworkException {\n        // Delete the photo from the XDM server\n        HttpResponse response = mXdm.deleteEndUserPhoto();\n        if ((response != null)\n                && (response.isSuccessfullResponse() || response.isNotFoundResponse())) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Invite a contact to share its presence\n     * \n     * @param contact Contact\n     * @return Returns true if XDM request was successful, else false\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean inviteContactToSharePresence(ContactId contact) throws PayloadException,\n            NetworkException {\n        // Remove contact from the blocked contacts list\n        mXdm.removeContactFromBlockedList(contact);\n\n        // Remove contact from the revoked contacts list\n        mXdm.removeContactFromRevokedList(contact);\n\n        // Add contact in the granted contacts list\n        HttpResponse response = mXdm.addContactToGrantedList(contact);\n        if ((response != null) && response.isSuccessfullResponse()) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Revoke a shared contact\n     * \n     * @param contact Contact\n     * @return Returns true if XDM request was successful, else false\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean revokeSharedContact(ContactId contact) throws PayloadException, NetworkException {\n        // Add contact in the revoked contacts list\n        HttpResponse response = mXdm.addContactToRevokedList(contact);\n        if ((response == null) || (!response.isSuccessfullResponse())) {\n            return false;\n        }\n\n        // Remove contact from the granted contacts list\n        response = mXdm.removeContactFromGrantedList(contact);\n        if ((response != null)\n                && (response.isSuccessfullResponse() || response.isNotFoundResponse())) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Remove a revoked contact\n     * \n     * @param contact Contact\n     * @return Returns true if XDM request was successful, else false\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean removeRevokedContact(ContactId contact) throws PayloadException,\n            NetworkException {\n        // Remove contact from the revoked contacts list\n        HttpResponse response = mXdm.removeContactFromRevokedList(contact);\n        if ((response != null)\n                && (response.isSuccessfullResponse() || response.isNotFoundResponse())) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Remove a blocked contact\n     * \n     * @param contact Contact\n     * @return Returns true if XDM request was successful, else false\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public boolean removeBlockedContact(ContactId contact) throws PayloadException,\n            NetworkException {\n        // Remove contact from the blocked contacts list\n        HttpResponse response = mXdm.removeContactFromBlockedList(contact);\n        if ((response != null)\n                && (response.isSuccessfullResponse() || response.isNotFoundResponse())) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Address book content has changed\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void handleAddressBookHasChanged() throws PayloadException, NetworkException {\n        // If a contact used to be in a RCS relationship with us but is not in the address book any\n        // more, we may have to remove or\n        // unblock it\n        // Get a list of all RCS numbers\n        Set<ContactId> rcsNumbers = mContactManager.getRcsContactsWithSocialPresence();\n        // For each RCS number\n        for (ContactId contact : rcsNumbers) {\n            if (!PresenceUtils.isNumberInAddressBook(contact)) {\n                // If it is not present in the address book\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The RCS number \" + contact\n                            + \" was not found in the address book any more.\");\n                }\n\n                if (mContactManager.isNumberShared(contact)\n                        || mContactManager.isNumberInvited(contact)) {\n                    // Active or Invited\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(contact + \" is either active or invited\");\n                        sLogger.debug(\"We remove it from the buddy list\");\n                    }\n                    // We revoke it\n                    boolean result = revokeSharedContact(contact);\n                    if (result) {\n                        // The contact should be automatically unrevoked after a given timeout. Here\n                        // the\n                        // timeout period is 0, so the contact can receive invitations again now\n                        result = removeRevokedContact(contact);\n                        if (result) {\n                            // Remove entry from rich address book provider\n                            mContactManager.updateRcsStatusOrCreateNewContact(contact,\n                                    RcsStatus.RCS_CAPABLE);\n                        } else {\n                            if (sLogger.isActivated()) {\n                                sLogger.error(\"Something went wrong when revoking shared contact\");\n                            }\n                        }\n                    }\n                } else if (mContactManager.isNumberBlocked(contact)) {\n                    // Blocked\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(contact + \" is blocked\");\n                        sLogger.debug(\"We remove it from the blocked list\");\n                    }\n                    // We unblock it\n                    boolean result = removeBlockedContact(contact);\n                    if (result) {\n                        // Remove entry from rich address book provider\n                        mContactManager.updateRcsStatusOrCreateNewContact(contact,\n                                RcsStatus.RCS_CAPABLE);\n                    } else {\n                        if (sLogger.isActivated()) {\n                            sLogger.error(\"Something went wrong when removing blocked contact\");\n                        }\n                    }\n                } else {\n                    if (mContactManager.isNumberWilling(contact)) {\n                        // Willing\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(contact + \" is willing\");\n                            sLogger.debug(\"Nothing to do\");\n                        }\n                    } else {\n                        if (mContactManager.isNumberCancelled(contact)) {\n                            // Cancelled\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(contact + \" is cancelled\");\n                                sLogger.debug(\"We remove it from rich address book provider\");\n                            }\n                            // Remove entry from rich address book provider\n                            mContactManager.updateRcsStatusOrCreateNewContact(contact,\n                                    RcsStatus.RCS_CAPABLE);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * A new presence sharing notification has been received\n     * \n     * @param contact Contact identifier\n     * @param status Status\n     * @param reason Reason\n     */\n    public void handlePresenceSharingNotification(ContactId contact, String status, String reason) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event presence sharing notification for \" + contact + \" (\"\n                    + status + \":\" + reason + \")\");\n        }\n        // Not used\n    }\n\n    /**\n     * A new presence info notification has been received\n     * \n     * @param contact Contact identifier\n     * @param presence Presence info document\n     */\n    public void handlePresenceInfoNotification(ContactId contact, PidfDocument presence) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event presence info notification for \" + contact);\n        }\n        // Not used\n    }\n\n    /**\n     * A new presence sharing invitation has been received\n     * \n     * @param contact Contact identifier\n     */\n    public void handlePresenceSharingInvitation(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event presence sharing invitation\");\n        }\n        // Not used\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PresenceSubscribeManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.presence.pidf.PidfDocument;\nimport com.gsma.rcs.core.ims.service.presence.pidf.PidfParser;\nimport com.gsma.rcs.core.ims.service.presence.rlmi.ResourceInstance;\nimport com.gsma.rcs.core.ims.service.presence.rlmi.RlmiDocument;\nimport com.gsma.rcs.core.ims.service.presence.rlmi.RlmiParser;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.text.TextUtils;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.text.ParseException;\nimport java.util.Vector;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport javax2.sip.header.AcceptHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.header.SubscriptionStateHeader;\nimport javax2.sip.header.SupportedHeader;\n\n/**\n * Subscribe manager for presence event\n * \n * @author jexa7410\n */\npublic class PresenceSubscribeManager extends SubscribeManager {\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger\n            .getLogger(PresenceSubscribeManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings\n     */\n    public PresenceSubscribeManager(ImsModule parent, RcsSettings rcsSettings) {\n        super(parent, rcsSettings);\n    }\n\n    /**\n     * Returns the presentity\n     * \n     * @return Presentity\n     */\n    public String getPresentity() {\n        return ImsModule.getImsUserProfile().getPublicUri().concat(\";pres-list=rcs\");\n    }\n\n    /**\n     * Create a SUBSCRIBE request\n     * \n     * @param dialog SIP dialog path\n     * @param expirePeriod Expiration period in milliseconds\n     * @return SIP request\n     * @throws PayloadException\n     */\n    @Override\n    public SipRequest createSubscribe(SipDialogPath dialog, long expirePeriod)\n            throws PayloadException {\n        try {\n            SipRequest subscribe = SipMessageFactory.createSubscribe(dialog, expirePeriod);\n            subscribe.addHeader(EventHeader.NAME, \"presence\");\n            subscribe.addHeader(AcceptHeader.NAME,\n                    \"application/pidf+xml, application/rlmi+xml, multipart/related\");\n            subscribe.addHeader(SupportedHeader.NAME, \"eventlist\");\n            return subscribe;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create subscribe request!\", e);\n        }\n    }\n\n    /**\n     * Receive a notification\n     * \n     * @param notify Received notify\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveNotification(SipRequest notify) throws PayloadException, NetworkException {\n        if (!isNotifyForThisSubscriber(notify)) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"New presence notification received\");\n        }\n        String content = notify.getContent();\n        if (TextUtils.isEmpty(content)) {\n            throw new PayloadException(\"Presence notification content should not be null or empty!\");\n        }\n        try {\n            String boundary = notify.getBoundaryContentType();\n            Multipart multi = new Multipart(content, boundary);\n            if (!multi.isMultipart()) {\n                throw new PayloadException(\"Presence notification content not multipart!\");\n            }\n            String rlmiPart = multi.getPart(\"application/rlmi+xml\");\n            if (rlmiPart != null) {\n                InputSource rlmiInput = new InputSource(new ByteArrayInputStream(\n                        rlmiPart.getBytes(UTF8)));\n                RlmiParser rlmiParser = new RlmiParser(rlmiInput).parse();\n                RlmiDocument rlmiInfo = rlmiParser.getResourceInfo();\n                Vector<ResourceInstance> list = rlmiInfo.getResourceList();\n                for (ResourceInstance res : list) {\n                    String uri = res.getUri();\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(uri);\n                    if (number == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Invalid uri '\" + uri + \"'\");\n                        }\n                        continue;\n                    }\n                    ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                    String state = res.getState();\n                    String reason = res.getReason();\n\n                    if ((state != null) && (reason != null)) {\n                        if (state.equalsIgnoreCase(\"terminated\")\n                                && reason.equalsIgnoreCase(\"rejected\")) {\n                            /*\n                             * It's a \"terminated\" event with status \"rejected\" the contact should\n                             * be removed from the \"rcs\" list\n                             */\n                            getImsModule().getPresenceService().getXdmManager()\n                                    .removeContactFromGrantedList(contact);\n                        }\n                        getImsModule().getPresenceService().handlePresenceSharingNotification(\n                                contact, state, reason);\n                    }\n                }\n            }\n            String pidfPart = multi.getPart(\"application/pidf+xml\");\n            InputSource pidfInput = new InputSource(new ByteArrayInputStream(\n                    pidfPart.getBytes(UTF8)));\n            PidfParser pidfParser = new PidfParser(pidfInput).parse();\n            PidfDocument presenceInfo = pidfParser.getPresence();\n            String entity = presenceInfo.getEntity();\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(entity);\n            if (number == null) {\n                throw new PayloadException(new StringBuilder(\"Invalid entity :\").append(entity)\n                        .toString());\n            }\n            ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n            getImsModule().getPresenceService().handlePresenceInfoNotification(contact,\n                    presenceInfo);\n        } catch (ParserConfigurationException e) {\n            throw new PayloadException(\"Can't parse presence notification!\", e);\n\n        } catch (SAXException e) {\n            throw new PayloadException(\"Can't parse presence notification!\", e);\n\n        } catch (ParseFailureException e) {\n            throw new PayloadException(\"Can't parse presence notification!\", e);\n        }\n\n        SubscriptionStateHeader stateHeader = (SubscriptionStateHeader) notify\n                .getHeader(SubscriptionStateHeader.NAME);\n        if ((stateHeader != null) && stateHeader.getState().equalsIgnoreCase(\"terminated\")) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Presence subscription has been terminated by server\");\n            }\n            terminatedByServer();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PresenceUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ContentProviderOperation;\nimport android.content.ContentProviderResult;\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.OperationApplicationException;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.provider.ContactsContract;\nimport android.provider.ContactsContract.CommonDataKinds.Phone;\nimport android.provider.ContactsContract.CommonDataKinds.StructuredName;\nimport android.provider.ContactsContract.Data;\nimport android.provider.ContactsContract.RawContacts;\n\nimport java.util.ArrayList;\n\n/**\n * Presence utility functions\n * \n * @author jexa7410\n */\npublic class PresenceUtils {\n    /**\n     * RCS 2.0 video share feature tag\n     */\n    public final static String FEATURE_RCS2_VIDEO_SHARE = \"org.gsma.videoshare\";\n\n    /**\n     * RCS 2.0 image share feature tag\n     */\n    public final static String FEATURE_RCS2_IMAGE_SHARE = \"org.gsma.imageshare\";\n\n    /**\n     * RCS 2.0 file transfer feature tag\n     */\n    public final static String FEATURE_RCS2_FT = \"org.openmobilealliance:File-Transfer\";\n\n    /**\n     * RCS 2.0 chat feature tag\n     */\n    public final static String FEATURE_RCS2_CHAT = \"org.openmobilealliance:IM-session\";\n\n    /**\n     * RCS 2.0 CS video feature tag\n     */\n    public final static String FEATURE_RCS2_CS_VIDEO = \"org.3gpp.cs-videotelephony\";\n\n    private static final String[] PROJECTION_CONTACTID_NUMBER = new String[] {\n            ContactsContract.CommonDataKinds.Phone.CONTACT_ID,\n            ContactsContract.CommonDataKinds.Phone.NUMBER\n    };\n\n    private static final String[] PROJECTION_RAW_CONTACT_ID = new String[] {\n        Data.RAW_CONTACT_ID\n    };\n\n    private static final String SELECTION_LOOSE = new StringBuilder(Data.MIMETYPE)\n            .append(\"=? AND PHONE_NUMBERS_EQUAL(\").append(Phone.NUMBER).append(\", ?)\").toString();\n\n    private static final String SELECTION_STRICT = new StringBuilder(Data.MIMETYPE)\n            .append(\"=? AND (NOT PHONE_NUMBERS_EQUAL(\").append(Phone.NUMBER)\n            .append(\", ?) AND PHONE_NUMBERS_EQUAL(\").append(Phone.NUMBER).append(\", ?, 1))\")\n            .toString();\n\n    private static final String[] PROJECTION_DATA_CONTACTID = new String[] {\n        Data.CONTACT_ID\n    };\n\n    private static final String WHERE_DATA_ID = new StringBuilder(Data._ID).append(\"=?\").toString();\n\n    private static int INVALID_CONTACT_ID = -1;\n\n    /**\n     * Returns the contact id associated to a contact number in the Address Book\n     * \n     * @param context Application context\n     * @param contact Contact ID\n     * @return Id or -1 if the contact number does not exist\n     */\n    private static int getContactIdOfAddressBook(Context context, ContactId contact) {\n        Cursor cursor = null;\n        try {\n            cursor = context.getContentResolver().query(\n                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,\n                    PROJECTION_CONTACTID_NUMBER, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor,\n                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return INVALID_CONTACT_ID;\n            }\n            int columnIdxContactId = cursor\n                    .getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.CONTACT_ID);\n            int columnIdxNumber = cursor\n                    .getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);\n            do {\n                PhoneNumber number = ContactUtil.getValidPhoneNumberFromAndroid(cursor\n                        .getString(columnIdxNumber));\n                if (number == null) {\n                    continue;\n                }\n                ContactId contactInAddressBook = ContactUtil\n                        .createContactIdFromValidatedData(number);\n                if (contactInAddressBook.equals(contact)) {\n                    return cursor.getInt(columnIdxContactId);\n                }\n            } while (cursor.moveToNext());\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n        return INVALID_CONTACT_ID;\n    }\n\n    /**\n     * Create a contact in address book <br>\n     * This is done with Contacts 2.0 API, and new contact is a \"Phone\" contact, not associated with\n     * any particular account type\n     * \n     * @param context Application context\n     * @param values Contact values\n     * @return URI of the created contact\n     * @throws OperationApplicationException\n     * @throws RemoteException\n     */\n    private static Uri createContact(Context context, ContentValues values) throws RemoteException,\n            OperationApplicationException {\n        ContentResolver mResolver = context.getContentResolver();\n        /* We will associate the newly created contact to the null contact account (Phone) */\n        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();\n        int backRefIndex = 0;\n        operations.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)\n                .withValue(RawContacts.ACCOUNT_TYPE, null)\n                .withValue(RawContacts.ACCOUNT_NAME, null).build());\n\n        /* Set the name */\n        operations.add(ContentProviderOperation\n                .newInsert(Data.CONTENT_URI)\n                .withValueBackReference(Data.RAW_CONTACT_ID, backRefIndex)\n                .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)\n                .withValue(StructuredName.DISPLAY_NAME,\n                        values.get(ContactsContract.Contacts.DISPLAY_NAME)).build());\n\n        operations.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                .withValueBackReference(Data.RAW_CONTACT_ID, backRefIndex)\n                .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)\n                .withValue(Phone.NUMBER, values.get(Phone.NUMBER))\n                .withValue(Phone.TYPE, values.get(Phone.TYPE)).build());\n\n        long rawContactId = 0;\n        ContentProviderResult[] result = mResolver.applyBatch(ContactsContract.AUTHORITY,\n                operations);\n        rawContactId = ContentUris.parseId(result[1].uri);\n        long contactId = 0;\n        /* Search the corresponding contact id */\n        Cursor c = null;\n        String[] whereArgs = new String[] {\n            String.valueOf(rawContactId)\n        };\n        try {\n            c = mResolver.query(Data.CONTENT_URI, PROJECTION_DATA_CONTACTID, WHERE_DATA_ID,\n                    whereArgs, null);\n            CursorUtil.assertCursorIsNotNull(c, Data.CONTENT_URI);\n            if (c.moveToFirst()) {\n                int columnIdxContactId = c.getColumnIndexOrThrow(Data.CONTACT_ID);\n                contactId = c.getLong(columnIdxContactId);\n            }\n\n        } finally {\n            if (c != null) {\n                c.close();\n            }\n        }\n        /* Return the resulting contact uri */\n        return ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);\n    }\n\n    /**\n     * Create a RCS contact if the given contact is not already present in the address book\n     * \n     * @param context Application context\n     * @param contactId Contact ID\n     * @return URI of the newly created contact or URI of the corresponding contact if there is\n     *         already a match\n     * @throws OperationApplicationException\n     * @throws RemoteException\n     */\n    /* package private */static Uri createRcsContactIfNeeded(Context context, ContactId contactId)\n            throws RemoteException, OperationApplicationException {\n        /* Check if contact is already in address book */\n        int phoneId = getContactIdOfAddressBook(context, contactId);\n        if (phoneId != INVALID_CONTACT_ID) {\n            /* Contact already in address book */\n            return ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, phoneId);\n        }\n        /* If the contact is not present in address book, create an entry with this number */\n        ContentValues values = new ContentValues();\n        values.putNull(ContactsContract.Contacts.DISPLAY_NAME);\n        values.put(Phone.NUMBER, contactId.toString());\n        values.put(Phone.TYPE, Phone.TYPE_MOBILE);\n        return createContact(context, values);\n    }\n\n    /**\n     * Check if the given number is present in the address book\n     * \n     * @param contact Contact ID to be checked\n     * @return boolean indicating if number is present in the address book or not\n     */\n    /* package private */static boolean isNumberInAddressBook(ContactId contact) {\n        String[] selectionArgs = {\n                Phone.CONTENT_ITEM_TYPE, contact.toString()\n        };\n        ContentResolver contentResolver = AndroidFactory.getApplicationContext()\n                .getContentResolver();\n\n        /* Starting query phone_numbers_equal */\n        Cursor cur = null;\n        try {\n            cur = contentResolver.query(Data.CONTENT_URI, PROJECTION_RAW_CONTACT_ID,\n                    SELECTION_LOOSE, selectionArgs, Data.RAW_CONTACT_ID);\n            CursorUtil.assertCursorIsNotNull(cur, Data.CONTENT_URI);\n            /* We found at least one data with this number */\n            if (cur.getCount() > 0) {\n                return true;\n            }\n        } finally {\n            if (cur != null) {\n                cur.close();\n                cur = null;\n            }\n        }\n\n        /* No match found using LOOSE equals, try using STRICT equals. */\n        String[] selectionArgsStrict = {\n                Phone.CONTENT_ITEM_TYPE, contact.toString(), contact.toString()\n        };\n        try {\n            cur = contentResolver.query(Data.CONTENT_URI, PROJECTION_RAW_CONTACT_ID,\n                    SELECTION_STRICT, selectionArgsStrict, Data.RAW_CONTACT_ID);\n            CursorUtil.assertCursorIsNotNull(cur, Data.CONTENT_URI);\n            /* We found at least one data with this number */\n            if (cur.getCount() > 0) {\n                return true;\n            }\n        } finally {\n            if (cur != null) {\n                cur.close();\n            }\n        }\n        /* We found no contact with this number */\n        return false;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/PublishManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.platform.registry.RegistryFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.text.ParseException;\nimport java.util.Vector;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.SIPETagHeader;\nimport javax2.sip.message.Response;\n\n/**\n * Publish manager for sending current user presence status\n * \n * @author JM. Auffret\n */\npublic class PublishManager extends PeriodicRefresher {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Last min expire period (in milliseconds)\n     */\n    private static final String REGISTRY_MIN_EXPIRE_PERIOD = \"MinPublishExpirePeriod\";\n\n    /**\n     * Last SIP Etag\n     */\n    private static final String REGISTRY_SIP_ETAG = \"SipEntityTag\";\n\n    /**\n     * SIP Etag expiration (in milliseconds)\n     */\n    private static final String REGISTRY_SIP_ETAG_EXPIRATION = \"SipETagExpiration\";\n\n    private ImsModule mImsModule;\n\n    private long mExpirePeriod;\n\n    private SipDialogPath mDialogPath;\n\n    private String mEntityTag;\n\n    private boolean mPublished = false;\n\n    private SessionAuthenticationAgent mAuthenticationAgent;\n\n    private static final Logger sLogger = Logger.getLogger(PublishManager.class.getName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings\n     */\n    public PublishManager(ImsModule parent, RcsSettings rcsSettings) {\n        mImsModule = parent;\n        mRcsSettings = rcsSettings;\n    }\n\n    public void initialize() {\n        mAuthenticationAgent = new SessionAuthenticationAgent(mImsModule);\n        long defaultExpirePeriod = mRcsSettings.getPublishExpirePeriod();\n        long minExpireValue = RegistryFactory.getFactory().readLong(REGISTRY_MIN_EXPIRE_PERIOD, -1);\n        if ((minExpireValue != -1) && (defaultExpirePeriod < minExpireValue)) {\n            mExpirePeriod = minExpireValue;\n        } else {\n            mExpirePeriod = defaultExpirePeriod;\n        }\n\n        // Restore the last SIP-ETag from the registry\n        readEntityTag();\n    }\n\n    /**\n     * Is published\n     * \n     * @return Return True if the terminal has published, else return False\n     */\n    public boolean isPublished() {\n        return mPublished;\n    }\n\n    /**\n     * Terminate manager\n     */\n    public void terminate() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the publish manager\");\n        }\n\n        // Do not unpublish for RCS, just stop timer\n        if (mPublished) {\n            // Stop timer\n            stopTimer();\n            mPublished = false;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Publish manager is terminated\");\n        }\n    }\n\n    /**\n     * Publish refresh processing\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void periodicProcessing() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Execute re-publish\");\n        }\n        mDialogPath = createDialogPath();\n        SipRequest publish = SipMessageFactory.createPublish(createDialogPath(), mExpirePeriod,\n                mEntityTag, null);\n        sendPublish(publish);\n    }\n\n    /**\n     * Publish presence status\n     * \n     * @param info Presence info\n     * @return Boolean\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public synchronized boolean publish(String info) throws PayloadException,\n            NetworkException {\n        mDialogPath = createDialogPath();\n        mDialogPath.setLocalContent(info);\n        SipRequest publish = SipMessageFactory.createPublish(mDialogPath, mExpirePeriod,\n                mEntityTag, info);\n        sendPublish(publish);\n        return mPublished;\n    }\n\n    /**\n     * Unpublish\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public synchronized void unPublish() throws PayloadException, NetworkException {\n        if (!mPublished) {\n            return;\n        }\n        stopTimer();\n        mDialogPath = createDialogPath();\n        SipRequest publish = SipMessageFactory.createPublish(mDialogPath, 0, mEntityTag, null);\n        sendPublish(publish);\n        mPublished = false;\n    }\n\n    /**\n     * Send PUBLISH message\n     * \n     * @param publish SIP PUBLISH\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    private void sendPublish(SipRequest publish) throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(new StringBuilder(\"Send PUBLISH, expire=\")\n                        .append(publish.getExpires()).append(\"ms\").toString());\n            }\n            if (mPublished) {\n                mAuthenticationAgent.setProxyAuthorizationHeader(publish);\n            }\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSipMessageAndWait(publish);\n\n            if (ctx.isSipResponse()) {\n                final int statusCode = ctx.getStatusCode();\n                switch (statusCode) {\n                    case Response.OK:\n                        if (publish.getExpires() != 0) {\n                            handle200OK(ctx);\n                        } else {\n                            handle200OkUnpublish(ctx);\n                        }\n                        break;\n                    case Response.PROXY_AUTHENTICATION_REQUIRED:\n                        handle407Authentication(ctx);\n                        break;\n                    case Response.CONDITIONAL_REQUEST_FAILED:\n                        handle412ConditionalRequestFailed(ctx);\n                        break;\n                    case Response.INTERVAL_TOO_BRIEF:\n                        handle423IntervalTooBrief(ctx);\n                        break;\n                    default:\n                        handleError(new PresenceError(PresenceError.PUBLISH_FAILED,\n                                ctx.getStatusCode() + \" \" + ctx.getReasonPhrase()));\n                        break;\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No response received for PUBLISH\");\n                }\n                handleError(new PresenceError(PresenceError.PUBLISH_FAILED));\n            }\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Publish has failed!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Publish has failed!\", e);\n        }\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OK(SipTransactionContext ctx) {\n        // 200 OK response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n        mPublished = true;\n\n        SipResponse resp = ctx.getSipResponse();\n\n        // Set the Proxy-Authorization header\n        mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n\n        // Retrieve the expire value in the response\n        retrieveExpirePeriod(resp);\n\n        // Retrieve the entity tag in the response\n        saveEntityTag((SIPETagHeader) resp.getHeader(SIPETagHeader.NAME));\n\n        // Start the periodic publish\n        startTimer(System.currentTimeMillis(), mExpirePeriod, 0.5);\n    }\n\n    /**\n     * Handle 200 0K response of UNPUBLISH\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OkUnpublish(SipTransactionContext ctx) {\n        // 200 OK response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"200 OK response received\");\n        }\n\n        SipResponse resp = ctx.getSipResponse();\n\n        // Retrieve the entity tag in the response\n        saveEntityTag((SIPETagHeader) resp.getHeader(SIPETagHeader.NAME));\n    }\n\n    /**\n     * Handle 407 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle407Authentication(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        try {\n            // 407 response received\n            if (sLogger.isActivated()) {\n                sLogger.info(\"407 response received\");\n            }\n\n            SipResponse resp = ctx.getSipResponse();\n\n            // Set the Proxy-Authorization header\n            mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n\n            // Increment the Cseq number of the dialog path\n            mDialogPath.incrementCseq();\n\n            // Create a second PUBLISH request with the right token\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send second PUBLISH\");\n            }\n            SipRequest publish = SipMessageFactory.createPublish(mDialogPath, ctx.getTransaction()\n                    .getRequest().getExpires().getExpires()\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE, mEntityTag,\n                    mDialogPath.getLocalContent());\n\n            // Set the Authorization header\n            mAuthenticationAgent.setProxyAuthorizationHeader(publish);\n\n            // Send PUBLISH request\n            sendPublish(publish);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n        }\n    }\n\n    /**\n     * Handle 412 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle412ConditionalRequestFailed(SipTransactionContext ctx)\n            throws PayloadException, NetworkException {\n        // 412 response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"412 conditional response received\");\n        }\n\n        // Increment the Cseq number of the dialog path\n        mDialogPath.incrementCseq();\n\n        // Reset Sip-Etag\n        saveEntityTag(null);\n\n        // Create a PUBLISH request without ETag\n        SipRequest publish = SipMessageFactory.createPublish(mDialogPath, mExpirePeriod,\n                mEntityTag, mDialogPath.getLocalContent());\n\n        // Send PUBLISH request\n        sendPublish(publish);\n    }\n\n    /**\n     * Handle 423 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle423IntervalTooBrief(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        // 423 response received\n        if (sLogger.isActivated()) {\n            sLogger.info(\"423 interval too brief response received\");\n        }\n\n        SipResponse resp = ctx.getSipResponse();\n\n        // Increment the Cseq number of the dialog path\n        mDialogPath.incrementCseq();\n\n        // Extract the Min-Expire value\n        long minExpire = SipUtils.getMinExpiresPeriod(resp);\n        if (minExpire == -1) {\n            if (sLogger.isActivated()) {\n                sLogger.error(\"Can't read the Min-Expires value\");\n            }\n            handleError(new PresenceError(PresenceError.PUBLISH_FAILED,\n                    \"No Min-Expires value found\"));\n            return;\n        }\n\n        // Save the min expire value in the terminal registry\n        RegistryFactory.getFactory().writeLong(REGISTRY_MIN_EXPIRE_PERIOD, minExpire);\n\n        // Set the default expire value\n        mExpirePeriod = minExpire;\n\n        // Create a new PUBLISH request with the right expire period\n        SipRequest publish = SipMessageFactory.createPublish(mDialogPath, mExpirePeriod,\n                mEntityTag, mDialogPath.getLocalContent());\n\n        // Send a PUBLISH request\n        sendPublish(publish);\n    }\n\n    /**\n     * Handle error response\n     * \n     * @param error Error\n     */\n    private void handleError(PresenceError error) {\n        // Error\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Publish has failed: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        mPublished = false;\n\n        // Publish has failed, stop the periodic publish\n        stopTimer();\n\n        // Error\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Publish has failed\");\n        }\n    }\n\n    /**\n     * Retrieve the expire period\n     * \n     * @param response SIP response\n     */\n    private void retrieveExpirePeriod(SipResponse response) {\n        // Extract expire value from Expires header\n        ExpiresHeader expiresHeader = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME);\n        if (expiresHeader != null) {\n            int expires = expiresHeader.getExpires();\n            if (expires != -1) {\n                mExpirePeriod = expires * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            }\n        }\n    }\n\n    /**\n     * Save the SIP entity tag\n     * \n     * @param etagHeader Header tag\n     */\n    private void saveEntityTag(SIPETagHeader etagHeader) {\n        if (etagHeader == null) {\n            mEntityTag = null;\n        } else {\n            mEntityTag = etagHeader.getETag();\n        }\n        if (mEntityTag != null) {\n            RegistryFactory.getFactory().writeString(REGISTRY_SIP_ETAG, mEntityTag);\n            long etagExpiration = System.currentTimeMillis() + mExpirePeriod;\n            RegistryFactory.getFactory().writeLong(REGISTRY_SIP_ETAG_EXPIRATION, etagExpiration);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"New entity tag: \" + mEntityTag + \", expire at=\" + etagExpiration);\n            }\n        } else {\n            RegistryFactory.getFactory().removeParameter(REGISTRY_SIP_ETAG);\n            RegistryFactory.getFactory().removeParameter(REGISTRY_SIP_ETAG_EXPIRATION);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Entity tag has been reset\");\n            }\n        }\n    }\n\n    /**\n     * Read the SIP entity tag\n     */\n    private void readEntityTag() {\n        mEntityTag = RegistryFactory.getFactory().readString(REGISTRY_SIP_ETAG, null);\n        long etagExpiration = RegistryFactory.getFactory().readLong(REGISTRY_SIP_ETAG_EXPIRATION,\n                -1);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"New entity tag: \" + mEntityTag + \", expire at=\" + etagExpiration);\n        }\n    }\n\n    /**\n     * Create a new dialog path\n     * \n     * @return Dialog path\n     */\n    private SipDialogPath createDialogPath() {\n        // Set Call-Id\n        String callId = mImsModule.getSipManager().getSipStack().generateCallId();\n\n        // Set target\n        String target = ImsModule.getImsUserProfile().getPublicUri();\n\n        // Set local party\n        String localParty = target;\n\n        // Set remote party\n        String remoteParty = target;\n\n        // Set the route path\n        Vector<String> route = mImsModule.getSipManager().getSipStack().getServiceRoutePath();\n\n        // Create a dialog path\n        SipDialogPath dialog = new SipDialogPath(mImsModule.getSipManager().getSipStack(), callId,\n                1, target, localParty, remoteParty, route, mRcsSettings);\n        return dialog;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/SubscribeManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.platform.registry.RegistryFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PeriodicRefresher;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.text.ParseException;\nimport java.util.Vector;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.message.Response;\n\n/**\n * Generic subscribe manager\n * \n * @author jexa7410\n */\npublic abstract class SubscribeManager extends PeriodicRefresher {\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Last min expire period (in milliseconds)\n     */\n    private static final String REGISTRY_MIN_EXPIRE_PERIOD = \"MinSubscribeExpirePeriod\";\n\n    /**\n     * IMS module\n     */\n    private ImsModule mImsModule;\n\n    /**\n     * Dialog path\n     */\n    private SipDialogPath mDialogPath;\n\n    /**\n     * Expire period in milliseconds\n     */\n    private long mExpirePeriod;\n\n    /**\n     * Subscription flag\n     */\n    private boolean mSubscribed = false;\n\n    /**\n     * Authentication agent\n     */\n    private SessionAuthenticationAgent mAuthenticationAgent;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings\n     */\n    public SubscribeManager(ImsModule parent, RcsSettings rcsSettings) {\n        mImsModule = parent;\n        mRcsSettings = rcsSettings;\n\n        long defaultExpirePeriod = rcsSettings.getSubscribeExpirePeriod();\n        long minExpireValue = RegistryFactory.getFactory().readLong(REGISTRY_MIN_EXPIRE_PERIOD, -1);\n        if ((minExpireValue != -1) && (defaultExpirePeriod < minExpireValue)) {\n            mExpirePeriod = minExpireValue;\n        } else {\n            mExpirePeriod = defaultExpirePeriod;\n        }\n    }\n\n    public void initialize() {\n        mAuthenticationAgent = new SessionAuthenticationAgent(mImsModule);\n    }\n\n    /**\n     * Returns the IMS module\n     * \n     * @return IMS module\n     */\n    public ImsModule getImsModule() {\n        return mImsModule;\n    }\n\n    /**\n     * Is subscribed\n     * \n     * @return Boolean\n     */\n    public boolean isSubscribed() {\n        return mSubscribed;\n    }\n\n    /**\n     * Returns the presentity\n     * \n     * @return Presentity\n     */\n    public abstract String getPresentity();\n\n    /**\n     * Receive a notification\n     * \n     * @param notify Received notify\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public abstract void receiveNotification(SipRequest notify) throws PayloadException,\n            NetworkException;\n\n    /**\n     * Check if the received notification if for this subscriber\n     * \n     * @param notify\n     * @return Boolean\n     */\n    public boolean isNotifyForThisSubscriber(SipRequest notify) {\n        boolean result = false;\n        if ((mDialogPath != null) && notify.getCallId().equals(mDialogPath.getCallId())) {\n            result = true;\n        }\n        return result;\n    }\n\n    /**\n     * Subscription has been terminated by server\n     */\n    public void terminatedByServer() {\n        if (!mSubscribed) {\n            // Already unsubscribed\n            return;\n        }\n\n        if (logger.isActivated()) {\n            logger.info(\"Subscription has been terminated by server\");\n        }\n\n        // Stop periodic subscription\n        stopTimer();\n\n        // Reset dialog path attributes\n        resetDialogPath();\n\n        // Force subscription flag to false\n        mSubscribed = false;\n    }\n\n    /**\n     * Terminate manager\n     */\n    public void terminate() {\n        if (logger.isActivated()) {\n            logger.info(\"Terminate the subscribe manager\");\n        }\n\n        // Stop periodic subscription\n        stopTimer();\n\n        // Unsubscribe before to quit\n        if ((mImsModule.getCurrentNetworkInterface() != null)\n                && mImsModule.getCurrentNetworkInterface().isRegistered()) {\n            unSubscribe();\n        }\n\n        if (logger.isActivated()) {\n            logger.info(\"Subscribe manager is terminated\");\n        }\n    }\n\n    /**\n     * Create a SUBSCRIBE request\n     * \n     * @param dialog SIP dialog path\n     * @param expirePeriod Expiration period in milliseconds\n     * @return SIP request\n     * @throws PayloadException\n     */\n    public abstract SipRequest createSubscribe(SipDialogPath dialog, long expirePeriod)\n            throws PayloadException;\n\n    /**\n     * Subscription refresh processing\n     */\n    public void periodicProcessing() {\n        // Make a subscribe\n        if (logger.isActivated()) {\n            logger.info(\"Execute re-subscribe\");\n        }\n\n        // Send SUBSCRIBE request\n        subscribe();\n    }\n\n    /**\n     * Subscribe\n     * \n     * @return Boolean\n     */\n    public synchronized boolean subscribe() {\n        if (logger.isActivated()) {\n            logger.info(\"Subscribe to \" + getPresentity());\n        }\n\n        try {\n            // Create a dialog path if necessary\n            if (mDialogPath == null) {\n                // Set Call-Id\n                String callId = mImsModule.getSipManager().getSipStack().generateCallId();\n\n                // Set target\n                String target = getPresentity();\n\n                // Set local party\n                String localParty = ImsModule.getImsUserProfile().getPublicUri();\n\n                // Set remote party\n                String remoteParty = getPresentity();\n\n                // Set the route path\n                Vector<String> route = mImsModule.getSipManager().getSipStack()\n                        .getServiceRoutePath();\n\n                // Create a dialog path\n                mDialogPath = new SipDialogPath(mImsModule.getSipManager().getSipStack(), callId,\n                        1, target, localParty, remoteParty, route, mRcsSettings);\n            } else {\n                // Increment the Cseq number of the dialog path\n                mDialogPath.incrementCseq();\n            }\n\n            // Create a SUBSCRIBE request\n            SipRequest subscribe = createSubscribe(mDialogPath, mExpirePeriod);\n\n            // Send SUBSCRIBE request\n            sendSubscribe(subscribe);\n\n        } catch (Exception e) {\n            if (logger.isActivated()) {\n                logger.error(\"Subscribe has failed\", e);\n            }\n            handleError(new PresenceError(PresenceError.UNEXPECTED_EXCEPTION, e.getMessage()));\n        }\n        return mSubscribed;\n    }\n\n    /**\n     * Unsubscribe\n     */\n    public synchronized void unSubscribe() {\n        if (!mSubscribed) {\n            // Already unsubscribed\n            return;\n        }\n\n        if (logger.isActivated()) {\n            logger.info(\"Unsubscribe to \" + getPresentity());\n        }\n\n        try {\n            // Stop periodic subscription\n            stopTimer();\n\n            // Increment the Cseq number of the dialog path\n\n            mDialogPath.incrementCseq();\n\n            // Create a SUBSCRIBE with expire 0\n            SipRequest subscribe = createSubscribe(mDialogPath, 0);\n\n            // Send SUBSCRIBE request\n            sendSubscribe(subscribe);\n\n        } catch (Exception e) {\n            if (logger.isActivated()) {\n                logger.error(\"UnSubscribe has failed\", e);\n            }\n        }\n\n        // Force subscription flag to false\n        mSubscribed = false;\n\n        // Reset dialog path attributes\n        resetDialogPath();\n    }\n\n    /**\n     * Reset the dialog path\n     */\n    private void resetDialogPath() {\n        mDialogPath = null;\n    }\n\n    /**\n     * Retrieve the expire period\n     * \n     * @param resp SIP response\n     */\n    private void retrieveExpirePeriod(SipResponse response) {\n        // Extract expire value from Expires header\n        ExpiresHeader expiresHeader = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME);\n        if (expiresHeader != null) {\n            int expires = expiresHeader.getExpires();\n            if (expires != -1) {\n                mExpirePeriod = expires * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n            }\n        }\n    }\n\n    /**\n     * Send SUBSCRIBE message\n     * \n     * @param subscribe SIP SUBSCRIBE\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    private void sendSubscribe(SipRequest subscribe) throws PayloadException,\n            NetworkException {\n        try {\n            if (logger.isActivated()) {\n                logger.info(new StringBuilder(\"Send SUBSCRIBE, expire=\")\n                        .append(subscribe.getExpires()).append(\"ms\").toString());\n            }\n\n            if (mSubscribed) {\n                mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n            }\n\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSipMessageAndWait(subscribe);\n            if (ctx.isSipResponse()) {\n                switch (ctx.getStatusCode()) {\n                    case Response.OK:\n                        if (subscribe.getExpires() != 0) {\n                            handle200OK(ctx);\n                        } else {\n                            handle200OkUnsubscribe(ctx);\n                        }\n                        return;\n                    case Response.ACCEPTED:\n                        handle200OK(ctx);\n                        return;\n                    case Response.PROXY_AUTHENTICATION_REQUIRED:\n                        handle407Authentication(ctx);\n                        return;\n                    case Response.INTERVAL_TOO_BRIEF:\n                        handle423IntervalTooBrief(ctx);\n                        return;\n                    default:\n                        handleError(new PresenceError(PresenceError.SUBSCRIBE_FAILED,\n                                ctx.getStatusCode() + \" \" + ctx.getReasonPhrase()));\n                        return;\n                }\n            }\n            if (logger.isActivated()) {\n                logger.debug(\"No response received for SUBSCRIBE\");\n            }\n            handleError(new PresenceError(PresenceError.SUBSCRIBE_FAILED));\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Can't send sip subscribe!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Can't send sip subscribe!\", e);\n        }\n    }\n\n    /**\n     * Handle 200 0K response\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OK(SipTransactionContext ctx) {\n        // 200 OK response received\n        if (logger.isActivated()) {\n            logger.info(\"200 OK response received\");\n        }\n        mSubscribed = true;\n\n        SipResponse resp = ctx.getSipResponse();\n\n        // Set the remote tag\n        mDialogPath.setRemoteTag(resp.getToTag());\n\n        // Set the target\n        mDialogPath.setTarget(resp.getContactURI());\n\n        // Set the Proxy-Authorization header\n        mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n\n        // Retrieve the expire value in the response\n        retrieveExpirePeriod(resp);\n\n        // Start the periodic subscribe\n        startTimer(System.currentTimeMillis(), mExpirePeriod, 0.5);\n    }\n\n    /**\n     * Handle 200 0K response of UNSUBSCRIBE\n     * \n     * @param ctx SIP transaction context\n     */\n    private void handle200OkUnsubscribe(SipTransactionContext ctx) {\n        // 200 OK response received\n        if (logger.isActivated()) {\n            logger.info(\"200 OK response received\");\n        }\n    }\n\n    /**\n     * Handle 407 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle407Authentication(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        try {\n            if (logger.isActivated()) {\n                logger.info(\"407 response received\");\n            }\n            SipResponse resp = ctx.getSipResponse();\n            mAuthenticationAgent.readProxyAuthenticateHeader(resp);\n            mDialogPath.incrementCseq();\n\n            if (logger.isActivated()) {\n                logger.info(\"Send second SUBSCRIBE\");\n            }\n            SipRequest subscribe = createSubscribe(mDialogPath, ctx.getTransaction().getRequest()\n                    .getExpires().getExpires()\n                    * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n            mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n            sendSubscribe(subscribe);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n        }\n    }\n\n    /**\n     * Handle 423 response\n     * \n     * @param ctx SIP transaction context\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void handle423IntervalTooBrief(SipTransactionContext ctx) throws PayloadException,\n            NetworkException {\n        try {\n            if (logger.isActivated()) {\n                logger.info(\"423 interval too brief response received\");\n            }\n            SipResponse resp = ctx.getSipResponse();\n            mDialogPath.incrementCseq();\n\n            long minExpire = SipUtils.getMinExpiresPeriod(resp);\n            if (minExpire == -1) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't read the Min-Expires value\");\n                }\n                handleError(new PresenceError(PresenceError.SUBSCRIBE_FAILED,\n                        \"No Min-Expires value found\"));\n                return;\n            }\n            RegistryFactory.getFactory().writeLong(REGISTRY_MIN_EXPIRE_PERIOD, minExpire);\n            mExpirePeriod = minExpire;\n            SipRequest subscribe = createSubscribe(mDialogPath, mExpirePeriod);\n            mAuthenticationAgent.setProxyAuthorizationHeader(subscribe);\n            sendSubscribe(subscribe);\n        } catch (InvalidArgumentException e) {\n            throw new PayloadException(\"Failed to handle 423 interval too brief response!\", e);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to handle 423 interval too brief response!\", e);\n        }\n    }\n\n    /**\n     * Handle error response\n     * \n     * @param error Error\n     */\n    private void handleError(PresenceError error) {\n        // Error\n        if (logger.isActivated()) {\n            logger.info(\"Subscribe has failed: \" + error.getErrorCode() + \", reason=\"\n                    + error.getMessage());\n        }\n        mSubscribed = false;\n\n        // Subscribe has failed, stop the periodic subscribe\n        stopTimer();\n\n        // Reset dialog path attributes\n        resetDialogPath();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/WatcherInfoSubscribeManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.presence.watcherinfo.Watcher;\nimport com.gsma.rcs.core.ims.service.presence.watcherinfo.WatcherInfoDocument;\nimport com.gsma.rcs.core.ims.service.presence.watcherinfo.WatcherInfoParser;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.text.ParseException;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport javax2.sip.header.SubscriptionStateHeader;\n\n/**\n * Subscribe manager for presence watcher info event\n * \n * @author jexa7410\n */\npublic class WatcherInfoSubscribeManager extends SubscribeManager {\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings\n     */\n    public WatcherInfoSubscribeManager(ImsModule parent, RcsSettings rcsSettings) {\n        super(parent, rcsSettings);\n    }\n\n    /**\n     * Returns the presentity\n     * \n     * @return Presentity\n     */\n    public String getPresentity() {\n        return ImsModule.getImsUserProfile().getPublicUri();\n    }\n\n    /**\n     * Create a SUBSCRIBE request\n     * \n     * @param dialog SIP dialog path\n     * @param expirePeriod Expiration period in milliseconds\n     * @return SIP request\n     * @throws PayloadException\n     */\n    @Override\n    public SipRequest createSubscribe(SipDialogPath dialog, long expirePeriod)\n            throws PayloadException {\n        try {\n            SipRequest subscribe = SipMessageFactory.createSubscribe(dialog, expirePeriod);\n            subscribe.addHeader(\"Event\", \"presence.winfo\");\n            subscribe.addHeader(\"Accept\", \"application/watcherinfo+xml\");\n            return subscribe;\n\n        } catch (ParseException e) {\n            throw new PayloadException(\"Failed to create subscribe request!\", e);\n        }\n    }\n\n    /**\n     * Receive a notification\n     * \n     * @param notify Received notify\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void receiveNotification(SipRequest notify) throws PayloadException,\n            NetworkException {\n        // Check notification\n        if (!isNotifyForThisSubscriber(notify)) {\n            return;\n        }\n\n        if (logger.isActivated()) {\n            logger.debug(\"New watcher-info notification received\");\n        }\n\n        // Parse XML part\n        byte[] content = notify.getContentBytes();\n        if (content != null) {\n            try {\n                InputSource input = new InputSource(new ByteArrayInputStream(content));\n                WatcherInfoParser parser = new WatcherInfoParser(input);\n                WatcherInfoDocument watcherinfo = parser.getWatcherInfo();\n                if (watcherinfo != null) {\n                    for (Watcher watcher : watcherinfo.getWatcherList()) {\n                        String uri = watcher.getUri();\n                        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(uri);\n                        if (number == null) {\n                            if (logger.isActivated()) {\n                                logger.warn(\"Invalid URI '\" + uri + \"'\");\n                            }\n                            continue;\n                        }\n                        ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                        String status = watcher.getStatus();\n                        String event = watcher.getEvent();\n\n                        if ((status != null) && (event != null)) {\n                            if (status.equalsIgnoreCase(\"pending\")) {\n                                // It's an invitation or a new status\n                                getImsModule().getPresenceService()\n                                        .handlePresenceSharingInvitation(contact);\n                            }\n\n                            // Notify listener\n                            getImsModule().getPresenceService().handlePresenceSharingNotification(\n                                    contact, status, event);\n                        }\n                    }\n                }\n            } catch (ParserConfigurationException e) {\n                throw new PayloadException(\"Can't parse watcher-info notification!\", e);\n\n            } catch (SAXException e) {\n                throw new PayloadException(\"Can't parse watcher-info notification!\", e);\n\n            } catch (IOException e) {\n                throw new NetworkException(\"Can't parse watcher-info notification!\", e);\n            }\n        }\n\n        // Check subscription state\n        SubscriptionStateHeader stateHeader = (SubscriptionStateHeader) notify\n                .getHeader(SubscriptionStateHeader.NAME);\n        if ((stateHeader != null) && stateHeader.getState().equalsIgnoreCase(\"terminated\")) {\n            if (logger.isActivated()) {\n                logger.info(\"Watcher-info subscription has been terminated by server\");\n            }\n            terminatedByServer();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/directory/Entry.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.directory;\n\npublic class Entry {\n    private String uri;\n    private String etag;\n    private long lastModified = -1;\n\n    public Entry(String uri) {\n        this.uri = uri;\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public String getEtag() {\n        return etag;\n    }\n\n    public void setEtag(String etag) {\n        this.etag = etag;\n    }\n\n    public long getLastModified() {\n        return lastModified;\n    }\n\n    public void setLastModified(long lastModified) {\n        this.lastModified = lastModified;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/directory/Folder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.directory;\n\npublic class Folder {\n    private String auid;\n    private Entry entry;\n\n    public Folder(String auid) {\n        this.auid = auid;\n    }\n\n    public String getAuid() {\n        return auid;\n    }\n\n    public Entry getEntry() {\n        return entry;\n    }\n\n    public void setEntry(Entry entry) {\n        this.entry = entry;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/directory/XcapDirectoryParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.directory;\n\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\nimport java.util.Hashtable;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * XCAP directory parser\n * \n * @author jexa7410\n */\npublic class XcapDirectoryParser extends DefaultHandler {\n\n    private StringBuffer accumulator;\n    private Folder folder = null;\n    private Entry entry = null;\n\n    private Hashtable<String, Folder> docs = new Hashtable<String, Folder>();\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     * @throws SAXException\n     * @throws ParserConfigurationException\n     * @throws IOException\n     */\n    public XcapDirectoryParser(InputSource inputSource) throws ParserConfigurationException,\n            SAXException, IOException {\n        SAXParserFactory factory = SAXParserFactory.newInstance();\n        SAXParser parser = factory.newSAXParser();\n        parser.parse(inputSource, this);\n    }\n\n    public void startDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start document\");\n        }\n        accumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        accumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        accumulator.setLength(0);\n\n        if (localName.equals(\"folder\")) {\n            String auid = attr.getValue(\"auid\").trim();\n            folder = new Folder(auid);\n        } else if (localName.equals(\"entry\")) {\n            String uri = attr.getValue(\"uri\").trim();\n            entry = new Entry(uri);\n\n            String etag = attr.getValue(\"etag\");\n            if (etag != null) {\n                entry.setEtag(etag.trim());\n            }\n\n            String lastModified = attr.getValue(\"last-modified\");\n            if (lastModified != null) {\n                long ts = DateUtils.decodeDate(lastModified.trim());\n                entry.setLastModified(ts);\n            }\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (localName.equals(\"folder\")) {\n            if (folder != null) {\n                docs.put(folder.getAuid(), folder);\n            }\n            folder = null;\n        } else if (localName.equals(\"entry\")) {\n            if ((folder != null) && (entry != null)) {\n                folder.setEntry(entry);\n            }\n            entry = null;\n        } else if (localName.equals(\"xcap-directory\")) {\n            if (logger.isActivated()) {\n                logger.debug(\"XCAP directory document is complete\");\n            }\n        }\n    }\n\n    public void endDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"End document\");\n        }\n    }\n\n    public Hashtable<String, Folder> getDocuments() {\n        return docs;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Basic.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\npublic class Basic {\n\n    private String value = null;\n\n    public Basic(String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Contact.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\npublic class Contact {\n\n    private String uri = null;\n    private String priority = null;\n    private String contactType = null;\n\n    public Contact() {\n    }\n\n    public Contact(String priority) {\n        this.priority = priority;\n    }\n\n    public String getPriority() {\n        return priority;\n    }\n\n    public void setPriority(String priority) {\n        this.priority = priority;\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\n    }\n\n    public String getContactType() {\n        return contactType;\n    }\n\n    public void setContactType(String contactType) {\n        this.contactType = contactType;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Note.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\npublic class Note {\n\n    private String value = null;\n    private String lang = null;\n\n    public Note() {\n    }\n\n    public Note(String lang, String value) {\n        this.value = value;\n        this.lang = lang;\n    }\n\n    public String getLang() {\n        return lang;\n    }\n\n    public void setLang(String lang) {\n        this.lang = lang;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/OverridingWillingness.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\nimport com.gsma.rcs.utils.DateUtils;\n\npublic class OverridingWillingness {\n\n    private Basic basic = null;\n\n    private long until = -1;\n\n    public OverridingWillingness(Basic basic) {\n        this.basic = basic;\n    }\n\n    public OverridingWillingness() {\n    }\n\n    public Basic getBasic() {\n        return basic;\n    }\n\n    public void setBasic(Basic basic) {\n        this.basic = basic;\n    }\n\n    public long getUntilTimestamp() {\n        return until;\n    }\n\n    public void setUntilTimestamp(String ts) {\n        this.until = DateUtils.decodeDate(ts);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Person.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\npublic class Person {\n    private String id = null;\n    private Note note = null;\n    private OverridingWillingness willingness = null;\n    private StatusIcon statusIcon = null;\n    private String homePage = null;\n    private long timestamp = -1;\n\n    public Person(String id) {\n        this.id = id;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public Note getNote() {\n        return note;\n    }\n\n    public void setNote(Note note) {\n        this.note = note;\n    }\n\n    public OverridingWillingness getOverridingWillingness() {\n        return willingness;\n    }\n\n    public void setOverridingWillingness(OverridingWillingness status) {\n        this.willingness = status;\n    }\n\n    public StatusIcon getStatusIcon() {\n        return statusIcon;\n    }\n\n    public void setStatusIcon(StatusIcon statusIcon) {\n        this.statusIcon = statusIcon;\n    }\n\n    public String getHomePage() {\n        return homePage;\n    }\n\n    public void setHomePage(String homePage) {\n        this.homePage = homePage;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long ts) {\n        this.timestamp = ts;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/PidfDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\nimport com.gsma.rcs.core.ims.service.presence.pidf.geoloc.Geopriv;\n\nimport java.util.Vector;\n\n/**\n * PIDF presence document\n * \n * @author jexa7410\n */\npublic class PidfDocument {\n    private String entity = null;\n    private Vector<Tuple> tuplesList = new Vector<Tuple>();\n    private Geopriv geopriv = null;\n    private Person person = null;\n\n    public PidfDocument(String entity) {\n        this.entity = entity;\n    }\n\n    public String getEntity() {\n        return entity;\n    }\n\n    public Person getPerson() {\n        return person;\n    }\n\n    public void setPerson(Person newPerson) {\n        if ((person == null) || (newPerson.getTimestamp() >= person.getTimestamp())) {\n            person = newPerson;\n        }\n    }\n\n    public void addTuple(Tuple newTuple) {\n        Tuple foundTuple = null;\n        String newServiceId = newTuple.getService().getId();\n        for (int i = 0; i < tuplesList.size(); i++) {\n            Tuple tuple = tuplesList.elementAt(i);\n            String serviceId = tuple.getService().getId();\n            if (serviceId.equalsIgnoreCase(newServiceId)) {\n                foundTuple = tuple;\n                break;\n            }\n        }\n\n        if (foundTuple == null) {\n            tuplesList.addElement(newTuple);\n        } else if (newTuple.getTimestamp() >= foundTuple.getTimestamp()) {\n            tuplesList.remove(foundTuple);\n            tuplesList.addElement(newTuple);\n        }\n    }\n\n    public Vector<Tuple> getTuplesList() {\n        return tuplesList;\n    }\n\n    public void setTuplesList(Vector<Tuple> tuplesList) {\n        this.tuplesList = tuplesList;\n    }\n\n    public void setGeopriv(Geopriv geopriv) {\n        this.geopriv = geopriv;\n    }\n\n    public Geopriv getGeopriv() {\n        return geopriv;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/PidfParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.presence.pidf.geoloc.Geopriv;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.StringUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\nimport java.util.StringTokenizer;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * PDIF parser\n * \n * @author jexa7410\n */\npublic class PidfParser extends DefaultHandler {\n\n    /*\n     * PIDF SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <presence\n     * xmlns=\"urn:ietf:params:xml:ns:pidf\" xmlns:op=\"urn:oma:xml:prs:pidf:oma-pres\"\n     * xmlns:rt=\"urn:ietf:params:xml:ns:pidf:rpid\" xmlns:gp=\"urn:ietf:params:xml:ns:pidf:geopriv10\"\n     * xmlns:pdm=\"urn:ietf:params:xml:ns:pidf:data-model\"\n     * xmlns:rs=\"urn:ietf:params:xml:ns:pidf:status:rpid-status\"\n     * entity=\"sip:+33960810101@domain.com\" version=\"1\"> <ep:tuple\n     * xmlns:ep=\"urn:ietf:params:xml:ns:pidf\" id=\"id5\"> <ep:status> <ep:basic>closed</ep:basic>\n     * </ep:status> <op:service-description>\n     * <op:service-id>org.3gpp.cs-videotelephony</op:service-id> <op:version>1.0</op:version>\n     * </op:service-description> <ep:contact>tel:+33960810101</ep:contact>\n     * <ep:timestamp>2009-04-24T16:58:32Z</ep:timestamp> </ep:tuple> <ep:tuple\n     * xmlns:ep=\"urn:ietf:params:xml:ns:pidf\" id=\"id2\"> <ep:status> <ep:basic>open</ep:basic>\n     * </ep:status> <op:service-description> <op:service-id>org.gsma.videoshare</op:service-id>\n     * <op:version>1.0</op:version> </op:service-description>\n     * <ep:contact>sip:+33960810101@domain.com</ep:contact>\n     * <ep:timestamp>2009-04-24T16:58:32Z</ep:timestamp> </ep:tuple> <tuple id=\"geolocid\"> <status>\n     * <basic>automatic</basic> <geopriv> <location-info> <location> <Point srsDimension=\"3\"\\>\n     * <pos>48.73 -3.53 62</pos> </Point> </location> </location-info> <method>GPS</method>\n     * </geopriv> </status> <timestamp>2009-04-24T16:58:32Z</timestamp>\n     * <contact>tel:+33960810101</contact> </tuple> <pdm:person id=\"p1\"> <ci:display-name\n     * xmlns:ci=\"urn:ietf:params:xml:ns:pidf:cipid\">User BRUNE</ci:display-name>\n     * <pdm:timestamp>2009-04-24T16:58:32Z</pdm:timestamp> <rpid:status-icon\n     * opd:etag=\"26362\">http://..../rcs_status_icon</rpid:status-icon> </pdm:person> </presence>\n     */\n\n    private StringBuffer mAccumulator;\n    private PidfDocument mPresence;\n    private Tuple mTuple;\n    private Note mNote;\n    private Contact mContact;\n    private Basic mBasic;\n    private OverridingWillingness mWillingness;\n    private Status mStatus;\n    private Service mService;\n    private StatusIcon mIcon;\n    private Person mPerson;\n    private Geopriv mGeopriv;\n\n    private final InputSource mInputSource;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public PidfParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the PIDF input\n     * \n     * @return PidfParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public PidfParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public PidfDocument getPresence() {\n        return mPresence;\n    }\n\n    public void startDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start document\");\n        }\n        mAccumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n\n        if (localName.equals(\"presence\")) {\n            String entity = attr.getValue(\"entity\").trim();\n            mPresence = new PidfDocument(entity);\n        } else if (localName.equals(\"person\")) {\n            String id = attr.getValue(\"id\").trim();\n            mPerson = new Person(id);\n        } else if (localName.equals(\"tuple\")) {\n            String id = attr.getValue(\"id\").trim();\n            mTuple = new Tuple(id);\n        } else if (localName.equals(\"note\")) {\n            mNote = new Note();\n            String lang = attr.getValue(\"xml:lang\");\n            if (lang != null) {\n                mNote.setLang(lang.trim());\n            }\n        } else if (localName.equals(\"contact\")) {\n            mContact = new Contact();\n            String priority = attr.getValue(\"priority\");\n            if (priority != null) {\n                mContact.setPriority(priority.trim());\n            }\n            String contactType = attr.getValue(\"contactType\");\n\n            if (contactType != null) {\n                mContact.setContactType(contactType.trim());\n            }\n        } else if (localName.equals(\"overriding-willingness\")) {\n            mWillingness = new OverridingWillingness();\n            String until = null;\n            int indexUntilValue = attr.getIndex(\"urn:oma:xml:pde:pidf:ext\", \"until\");\n            if (indexUntilValue != -1) {\n                until = attr.getValue(indexUntilValue);\n            }\n            if (until != null) {\n                mWillingness.setUntilTimestamp(until);\n            }\n        } else if (localName.equals(\"status-icon\")) {\n            mIcon = new StatusIcon();\n            String etag = null;\n            int indexEtagValue = attr.getIndex(\"urn:oma:xml:pde:pidf:ext\", \"etag\");\n            if (indexEtagValue != -1) {\n                etag = attr.getValue(indexEtagValue);\n            }\n            if (etag != null) {\n                mIcon.setEtag(etag);\n            }\n        } else if (localName.equals(\"status\")) {\n            mStatus = new Status();\n        } else if (localName.equals(\"service-description\")) {\n            mService = new Service();\n        } else if (localName.equals(\"geopriv\")) {\n            mGeopriv = new Geopriv();\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (localName.equals(\"tuple\")) {\n            if (mPresence != null) {\n                mPresence.addTuple(mTuple);\n            }\n            mTuple = null;\n        } else if (localName.equals(\"person\")) {\n            if (mPerson != null) {\n                mPresence.setPerson(mPerson);\n                mPerson = null;\n            }\n        } else if (localName.equals(\"note\")) {\n            if ((mNote != null) && (mPerson != null)) {\n                String value = StringUtils.decodeXML(mAccumulator.toString().trim());\n                mNote.setValue(value);\n                mPerson.setNote(mNote);\n                mNote = null;\n            }\n        } else if (localName.equals(\"contact\")) {\n            if ((mContact != null) && (mTuple != null)) {\n                mContact.setUri(mAccumulator.toString().trim());\n                mTuple.addContact(mContact);\n                mContact = null;\n            }\n        } else if (localName.equals(\"basic\")) {\n            mBasic = new Basic(mAccumulator.toString().trim());\n            if (mStatus != null) {\n                mStatus.setBasic(mBasic);\n            } else if (mWillingness != null) {\n                mWillingness.setBasic(mBasic);\n            }\n            mBasic = null;\n        } else if (localName.equals(\"overriding-willingness\")) {\n            if ((mWillingness != null) && (mPerson != null)) {\n                mPerson.setOverridingWillingness(mWillingness);\n                mWillingness = null;\n            }\n        } else if (localName.equals(\"status-icon\")) {\n            String url = mAccumulator.toString();\n            if ((mIcon != null) && (mPerson != null)) {\n                mIcon.setUrl(url.trim());\n                mPerson.setStatusIcon(mIcon);\n                mIcon = null;\n            }\n        } else if (localName.equals(\"status\")) {\n            if ((mStatus != null) && (mTuple != null)) {\n                mTuple.setStatus(mStatus);\n                mStatus = null;\n            }\n        } else if (localName.equals(\"timestamp\")) {\n            String timestamp = mAccumulator.toString();\n            if (timestamp != null) {\n                long ts = DateUtils.decodeDate(timestamp.trim());\n                if (mPerson != null) {\n                    mPerson.setTimestamp(ts);\n                } else if (mTuple != null) {\n                    mTuple.setTimestamp(ts);\n                }\n            }\n        } else if (localName.equals(\"service-description\")) {\n            if ((mService != null) && (mTuple != null)) {\n                mTuple.setService(mService);\n                mService = null;\n            }\n        } else if (localName.equals(\"service-id\")) {\n            if (mService != null) {\n                mService.setId(mAccumulator.toString().trim());\n            }\n        } else if (localName.equals(\"homepage\")) {\n            String homepage = mAccumulator.toString();\n            if ((homepage != null) && (mPerson != null)) {\n                mPerson.setHomePage(homepage.trim());\n                homepage = null;\n            }\n        } else if (localName.equals(\"geopriv\")) {\n            if ((mGeopriv != null) && (mPresence != null)) {\n                mPresence.setGeopriv(mGeopriv);\n                mGeopriv = null;\n            }\n        } else if (localName.equals(\"method\")) {\n            if (mGeopriv != null) {\n                mGeopriv.setMethod(mAccumulator.toString().trim());\n            }\n        } else if (localName.equals(\"pos\")) {\n            if (mGeopriv != null) {\n                StringTokenizer st = new StringTokenizer(mAccumulator.toString().trim());\n                if (st.hasMoreTokens()) {\n                    mGeopriv.setLatitude(Double.parseDouble(st.nextToken()));\n                }\n                if (st.hasMoreTokens()) {\n                    mGeopriv.setLongitude(Double.parseDouble(st.nextToken()));\n                }\n                if (st.hasMoreTokens()) {\n                    mGeopriv.setAltitude(Double.parseDouble(st.nextToken()));\n                }\n            }\n        } else if (localName.equals(\"presence\")) {\n            if (logger.isActivated()) {\n                logger.debug(\"Presence document complete\");\n            }\n        }\n    }\n\n    public void endDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"End document\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Service.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\npublic class Service {\n    private String id = null;\n\n    public Service(String id) {\n        this.id = id;\n    }\n\n    public Service() {\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Status.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\npublic class Status {\n\n    private Basic basic = null;\n\n    public Status(Basic basic) {\n        this.basic = basic;\n    }\n\n    public Status() {\n    }\n\n    public Basic getBasic() {\n        return basic;\n    }\n\n    public void setBasic(Basic basic) {\n        this.basic = basic;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/StatusIcon.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\n/**\n * Status icon\n * \n * @author jexa7410\n */\npublic class StatusIcon {\n    private String url = null;\n    private String etag = null;\n\n    public StatusIcon() {\n\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getEtag() {\n        return etag;\n    }\n\n    public void setEtag(String etag) {\n        this.etag = etag;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/Tuple.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf;\n\nimport java.util.Vector;\n\npublic class Tuple {\n\n    private String id = null;\n    private Status status = null;\n    private Service service = null;\n    private Vector<Contact> contactList = new Vector<Contact>();\n    private long timestamp = -1;\n\n    public Tuple(String id) {\n        this.id = id;\n    }\n\n    public Vector<Contact> getContactList() {\n        return contactList;\n    }\n\n    public void addContact(Contact contact) {\n        contactList.addElement(contact);\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public Status getStatus() {\n        return status;\n    }\n\n    public void setStatus(Status status) {\n        this.status = status;\n    }\n\n    public Service getService() {\n        return service;\n    }\n\n    public void setService(Service service) {\n        this.service = service;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long ts) {\n        this.timestamp = ts;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/pidf/geoloc/Geopriv.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.pidf.geoloc;\n\npublic class Geopriv {\n    private String method = null;\n    private double latitude = 0;\n    private double longitude = 0;\n    private double altitude = 0;\n\n    public Geopriv() {\n    }\n\n    public String getMethod() {\n        return method;\n    }\n\n    public void setMethod(String met) {\n        this.method = met;\n    }\n\n    public double getLatitude() {\n        return latitude;\n    }\n\n    public void setLatitude(double l) {\n        latitude = l;\n    }\n\n    public double getLongitude() {\n        return longitude;\n    }\n\n    public void setLongitude(double l) {\n        longitude = l;\n    }\n\n    public double getAltitude() {\n        return altitude;\n    }\n\n    public void setAltitude(double a) {\n        altitude = a;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/rlmi/ResourceInstance.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.rlmi;\n\npublic class ResourceInstance {\n\n    private String uri;\n    private String state = null;\n    private String reason = null;\n\n    public ResourceInstance(String uri) {\n        this.uri = uri;\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public String getState() {\n        return state;\n    }\n\n    public String getReason() {\n        return reason;\n    }\n\n    public void setState(String state) {\n        this.state = state;\n    }\n\n    public void setReason(String reason) {\n        this.reason = reason;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/rlmi/RlmiDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.rlmi;\n\nimport java.util.Vector;\n\n/**\n * Resource list document\n * \n * @author jexa7410\n */\npublic class RlmiDocument {\n    private String uri = null;\n\n    private Vector<ResourceInstance> resourceList = new Vector<ResourceInstance>();\n\n    public RlmiDocument(String uri) {\n        this.uri = uri;\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void addResource(ResourceInstance res) {\n        resourceList.addElement(res);\n    }\n\n    public Vector<ResourceInstance> getResourceList() {\n        return resourceList;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/rlmi/RlmiParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.rlmi;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * PDIF parser\n * \n * @author jexa7410\n */\npublic class RlmiParser extends DefaultHandler {\n    /*\n     * RLMI SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\"?> <list xmlns=\"urn:ietf:params:xml:ns:rlmi\"\n     * uri=\"sip:+33960810101@domain.com;pres-list=rcs\" version=\"1\" fullState=\"true\"><name>rcs</name>\n     * <resource uri=\"sip:+33960810100@domain.com\"> <instance id=\"001\" state=\"pending\"\n     * reason=\"subscribe\"/> </resource> </list>\n     */\n\n    private StringBuffer accumulator;\n    private ResourceInstance resourceInstance = null;\n    private RlmiDocument resourceInfo = null;\n\n    private final InputSource mInputSource;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     */\n    public RlmiParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the PIDF input\n     * \n     * @return RlmiParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public RlmiParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public RlmiDocument getResourceInfo() {\n        return resourceInfo;\n    }\n\n    public void startDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start document\");\n        }\n        accumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        accumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        accumulator.setLength(0);\n\n        if (localName.equals(\"list\")) {\n            String uri = attr.getValue(\"uri\").trim();\n            resourceInfo = new RlmiDocument(uri);\n        } else if (localName.equals(\"resource\")) {\n            String uri = attr.getValue(\"uri\").trim();\n            resourceInstance = new ResourceInstance(uri);\n        } else if (localName.equals(\"instance\")) {\n            String state = attr.getValue(\"state\");\n            if ((resourceInstance != null) && (state != null)) {\n                resourceInstance.setState(state.trim());\n            }\n            String reason = attr.getValue(\"reason\");\n            if ((resourceInstance != null) && (reason != null)) {\n                resourceInstance.setReason(reason.trim());\n            }\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (localName.equals(\"resource\")) {\n            if (resourceInfo != null) {\n                resourceInfo.addResource(resourceInstance);\n            }\n            resourceInstance = null;\n        } else if (localName.equals(\"list\")) {\n            if (logger.isActivated()) {\n                logger.debug(\"RLMI document is complete\");\n            }\n        }\n    }\n\n    public void endDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"End document\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/watcherinfo/Watcher.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.watcherinfo;\n\npublic class Watcher {\n\n    private String id;\n    private String status;\n    private String event;\n    private String uri;\n    private String displayName;\n\n    public Watcher(String id) {\n        this.id = id;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public void setId(String id) {\n        this.id = id;\n    }\n\n    public String getStatus() {\n        return status;\n    }\n\n    public void setStatus(String status) {\n        this.status = status;\n    }\n\n    public String getEvent() {\n        return event;\n    }\n\n    public void setEvent(String event) {\n        this.event = event;\n    }\n\n    public String getUri() {\n        return uri;\n    }\n\n    public void setUri(String uri) {\n        this.uri = uri;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String name) {\n        this.displayName = name;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/watcherinfo/WatcherInfoDocument.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.watcherinfo;\n\nimport java.util.Vector;\n\n/**\n * Watcher info document\n * \n * @author jexa7410\n */\npublic class WatcherInfoDocument {\n    private String resource;\n\n    private String packageId;\n\n    private Vector<Watcher> watcherList = new Vector<Watcher>();\n\n    public WatcherInfoDocument(String resource, String packageId) {\n        this.resource = resource;\n        this.packageId = packageId;\n    }\n\n    public void addWatcher(Watcher watcher) {\n        watcherList.addElement(watcher);\n    }\n\n    public Vector<Watcher> getWatcherList() {\n        return watcherList;\n    }\n\n    public String getResource() {\n        return resource;\n    }\n\n    public String getPackageId() {\n        return packageId;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/watcherinfo/WatcherInfoParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.watcherinfo;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXParseException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Watcher-info parser\n * \n * @author jexa7410\n */\npublic class WatcherInfoParser extends DefaultHandler {\n    /*\n     * Watcher-Info SAMPLE: <?xml version=\"1.0\" encoding=\"UTF-8\" ?> <watcherinfo\n     * xmlns=\"urn:ietf:params:xml:ns:watcherinfo\" version=\"0\" state=\"full\"> <watcher-list\n     * resource=\"sip:+33960810100@domain.com\" package=\"presence\"> <watcher status=\"active\"\n     * id=\"-838173480\" duration-subscribed=\"3\" event=\"subscribe\">tel:+33960810100</watcher>\n     * </watcher-list> </watcherinfo>\n     */\n    private StringBuffer accumulator;\n    private WatcherInfoDocument watcherInfo = null;\n    private Watcher watcher = null;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     * @throws SAXException\n     * @throws ParserConfigurationException\n     * @throws IOException\n     */\n    public WatcherInfoParser(InputSource inputSource) throws ParserConfigurationException,\n            SAXException, IOException {\n        SAXParserFactory factory = SAXParserFactory.newInstance();\n        SAXParser parser = factory.newSAXParser();\n        parser.parse(inputSource, this);\n    }\n\n    public void startDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start document\");\n        }\n        accumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        accumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        accumulator.setLength(0);\n\n        if (localName.equals(\"watcher-list\")) {\n            String resource = attr.getValue(\"resource\").trim();\n            String packageId = attr.getValue(\"package\").trim();\n            watcherInfo = new WatcherInfoDocument(resource, packageId);\n        } else if (localName.equals(\"watcher\")) {\n            String id = attr.getValue(\"id\");\n            if (id != null) {\n                watcher = new Watcher(id.trim());\n\n                String status = attr.getValue(\"status\");\n                if (status != null) {\n                    watcher.setStatus(status.trim());\n                }\n\n                String event = attr.getValue(\"event\");\n                if (event != null) {\n                    watcher.setEvent(event.trim());\n                }\n\n                String name = attr.getValue(\"display-name\");\n                if (name != null) {\n                    watcher.setDisplayName(name.trim());\n                }\n            }\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (localName.equals(\"watcher\")) {\n            if (watcher != null) {\n                watcher.setUri(accumulator.toString());\n            }\n\n            if (watcherInfo != null) {\n                watcherInfo.addWatcher(watcher);\n            }\n            watcher = null;\n        } else if (localName.equals(\"watcher-list\")) {\n            if (logger.isActivated()) {\n                logger.debug(\"Watcher document is complete\");\n            }\n        }\n    }\n\n    public void endDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"End document\");\n        }\n    }\n\n    public void warning(SAXParseException exception) {\n        if (logger.isActivated()) {\n            logger.error(\"Warning: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n    }\n\n    public void error(SAXParseException exception) {\n        if (logger.isActivated()) {\n            logger.error(\"Error: line \" + exception.getLineNumber() + \": \" + exception.getMessage());\n        }\n    }\n\n    public void fatalError(SAXParseException exception) throws SAXException {\n        if (logger.isActivated()) {\n            logger.error(\"Fatal: line \" + exception.getLineNumber() + \": \" + exception.getMessage());\n        }\n        throw exception;\n    }\n\n    public WatcherInfoDocument getWatcherInfo() {\n        return watcherInfo;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/xdm/HttpAuthenticationAgent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.xdm;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.security.HttpDigestMd5Authentication;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * HTTP Digest MD5 authentication agent\n * \n * @author JM. Auffret\n */\npublic class HttpAuthenticationAgent {\n\n    /**\n     * HTTP Digest MD5 agent\n     */\n    private HttpDigestMd5Authentication digest = new HttpDigestMd5Authentication();\n\n    /**\n     * Constructor\n     */\n    public HttpAuthenticationAgent() {\n    }\n\n    /**\n     * Generate the authorization header\n     * \n     * @param method Method used\n     * @param requestUri Request Uri\n     * @param body Entity body\n     * @return authorizationHeader Authorization header\n     * @throws InvalidArgumentException\n     */\n    private String generateAuthorizationHeader(String method, String requestUri, String body)\n            throws InvalidArgumentException {\n        digest.updateNonceParameters();\n        UserProfile profile = ImsModule.getImsUserProfile();\n        String user = profile.getXdmServerLogin();\n        String password = profile.getXdmServerPassword();\n        String response = digest.calculateResponse(user, password, method, requestUri,\n                digest.buildNonceCounter(), body);\n        StringBuilder auth = new StringBuilder(\"Authorization: Digest username=\\\"\").append(user)\n                .append(\"\\\",realm=\\\"\").append(digest.getRealm()).append(\"\\\",nonce=\\\"\")\n                .append(digest.getNonce()).append(\"\\\",uri=\\\"\").append(requestUri).append(\"\\\"\");\n        String opaque = digest.getOpaque();\n        if (opaque != null) {\n            auth.append(\",opaque=\\\"\").append(opaque).append(\"\\\"\");\n        }\n        String qop = digest.getQop();\n        if ((qop != null) && qop.startsWith(\"auth\")) {\n            auth.append(\",qop=\\\"\").append(qop).append(\"\\\",nc=\").append(digest.buildNonceCounter())\n                    .append(\",cnonce=\\\"\").append(digest.getCnonce()).append(\"\\\",response=\\\"\")\n                    .append(response).append(\"\\\"\");\n        }\n        return auth.toString();\n    }\n\n    /**\n     * Read the WWW-Authenticate header\n     * \n     * @param header WWW-Authenticate header\n     */\n    public void readWwwAuthenticateHeader(String header) {\n        if (header != null) {\n            // Get domain name\n            String value = null;\n            int end = -1;\n            int begin = header.toLowerCase().indexOf(\"realm=\\\"\");\n            if (begin != -1) {\n                begin += 7;\n                end = header.indexOf(\"\\\"\", begin);\n                value = header.substring(begin, end);\n            }\n            digest.setRealm(value);\n\n            // Get opaque parameter\n            value = null;\n            end = -1;\n            begin = header.toLowerCase().indexOf(\"opaque=\\\"\");\n            if (begin != -1) {\n                begin += 8;\n                end = header.indexOf(\"\\\"\", begin);\n                value = header.substring(begin, end);\n            }\n            digest.setOpaque(value);\n\n            // Get qop\n            value = null;\n            end = -1;\n            begin = header.toLowerCase().indexOf(\"qop=\\\"\");\n            if (begin != -1) {\n                begin += 5;\n                end = header.indexOf(\"\\\"\", begin);\n                value = header.substring(begin, end);\n            }\n            digest.setQop(value);\n\n            // Get nonce to be used\n            value = null;\n            end = -1;\n            begin = header.toLowerCase().indexOf(\"nonce=\\\"\");\n            if (begin != -1) {\n                begin += 7;\n                end = header.indexOf(\"\\\"\", begin);\n                value = header.substring(begin, end);\n            }\n            digest.setNextnonce(value);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/xdm/XcapResponseParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.xdm;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.SAXParseException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * XCAP response parser\n * \n * @author jexa7410\n */\npublic class XcapResponseParser extends DefaultHandler {\n\n    private StringBuffer accumulator;\n\n    private List<String> uriList = new ArrayList<String>();\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     * @throws SAXException\n     * @throws ParserConfigurationException\n     * @throws IOException\n     */\n    public XcapResponseParser(InputSource inputSource) throws ParserConfigurationException,\n            SAXException, IOException {\n        SAXParserFactory factory = SAXParserFactory.newInstance();\n        SAXParser parser = factory.newSAXParser();\n        parser.parse(inputSource, this);\n    }\n\n    public void startDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start document\");\n        }\n        accumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        accumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        accumulator.setLength(0);\n\n        if (localName.equals(\"entry\")) {\n            String uri = attr.getValue(\"uri\").trim();\n            uriList.add(uri);\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n    }\n\n    public void endDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"End document\");\n        }\n    }\n\n    public void warning(SAXParseException exception) {\n        if (logger.isActivated()) {\n            logger.error(\"Warning: line \" + exception.getLineNumber() + \": \"\n                    + exception.getMessage());\n        }\n    }\n\n    public void error(SAXParseException exception) {\n        if (logger.isActivated()) {\n            logger.error(\"Error: line \" + exception.getLineNumber() + \": \" + exception.getMessage());\n        }\n    }\n\n    public void fatalError(SAXParseException exception) throws SAXException {\n        if (logger.isActivated()) {\n            logger.error(\"Fatal: line \" + exception.getLineNumber() + \": \" + exception.getMessage());\n        }\n        throw exception;\n    }\n\n    public List<String> getUris() {\n        return uriList;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/presence/xdm/XdmManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.presence.xdm;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\nimport static com.gsma.rcs.utils.StringUtils.UTF8_STR;\n\nimport com.gsma.rcs.core.TerminalInfo;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.http.HttpAuthenticationAgent;\nimport com.gsma.rcs.core.ims.protocol.http.HttpDeleteRequest;\nimport com.gsma.rcs.core.ims.protocol.http.HttpGetRequest;\nimport com.gsma.rcs.core.ims.protocol.http.HttpPutRequest;\nimport com.gsma.rcs.core.ims.protocol.http.HttpRequest;\nimport com.gsma.rcs.core.ims.protocol.http.HttpResponse;\nimport com.gsma.rcs.core.ims.service.presence.PhotoIcon;\nimport com.gsma.rcs.core.ims.service.presence.directory.Folder;\nimport com.gsma.rcs.core.ims.service.presence.directory.XcapDirectoryParser;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.platform.network.SocketConnection;\nimport com.gsma.rcs.utils.Base64;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Set;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport javax2.sip.message.Response;\n\n/**\n * XDM manager\n * \n * @author Jean-Marc AUFFRET\n */\npublic class XdmManager {\n\n    /**\n     * CRLF constant\n     */\n    private static final String CRLF = \"\\r\\n\";\n\n    private static final String XCAP_SCHEME = \"/org.openmobilealliance.xcap-directory/users/\";\n\n    private static final String PRES_RULES_SCHEME = \"/org.openmobilealliance.pres-rules/users/\";\n\n    private static final String RLS_SCHEME = \"/rls-services/users/\";\n\n    private static final String RESOURCE_SCHEME = \"/resource-lists/users/\";\n\n    private static final String XCAP_FRAGMENT = \"/directory.xml\";\n\n    private static final String PRES_RULES_FRAGMENT = \"/pres-rules\";\n\n    private static final String INDEX_FRAGMENT = \"/index\";\n\n    private static final String CONTENT_TYPE_RLS = \"application/rls-services+xml\";\n\n    private static final String CONTENT_TYPE_RESOURCE = \"application/resource-lists+xml\";\n\n    private static final String CONTENT_TYPE_AUTH = \"application/auth-policy+xml\";\n\n    private static final String PROTOCOL_HTTPS = \"https\";\n\n    private static final int DEFAULT_HTTPS_PORT = 443;\n\n    private static final int DEFAULT_HTTP_PORT = 80;\n\n    private Uri xdmServerAddr;\n\n    private String xdmServerLogin;\n\n    private String xdmServerPwd;\n\n    /**\n     * Managed documents\n     */\n    private Hashtable<String, Folder> documents = new Hashtable<String, Folder>();\n\n    private Context mCtx;\n\n    private static final Logger sLogger = Logger.getLogger(XdmManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param ctx Context\n     */\n    public XdmManager(Context ctx) {\n        mCtx = ctx;\n    }\n\n    /**\n     * Send HTTP PUT request\n     * \n     * @param request HTTP request\n     * @return HTTP response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private HttpResponse sendRequestToXDMS(HttpRequest request) throws PayloadException,\n            NetworkException {\n        return sendRequestToXDMS(request, new HttpAuthenticationAgent(xdmServerLogin, xdmServerPwd));\n    }\n\n    /**\n     * Send HTTP PUT request with authentication\n     * \n     * @param request HTTP request\n     * @param authenticationAgent Authentication agent\n     * @return HTTP response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private HttpResponse sendRequestToXDMS(HttpRequest request,\n            HttpAuthenticationAgent authenticationAgent) throws PayloadException, NetworkException {\n        HttpResponse response = sendHttpRequest(request, authenticationAgent);\n        final int responseCode = response.getResponseCode();\n        switch (responseCode) {\n            case Response.UNAUTHORIZED:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"401 Unauthorized response received\");\n                }\n                if (authenticationAgent != null) {\n                    authenticationAgent.readWwwAuthenticateHeader(response\n                            .getHeader(\"www-authenticate\"));\n                }\n                String cookie = response.getHeader(\"set-cookie\");\n                request.setCookie(cookie);\n                return sendRequestToXDMS(request, authenticationAgent);\n\n            case Response.CONDITIONAL_REQUEST_FAILED:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"412 Precondition failed\");\n                }\n                documents.remove(request.getAUID());\n                return sendRequestToXDMS(request);\n\n            default:\n                throw new NetworkException(new StringBuilder(\"Invalid response : \").append(\n                        responseCode).toString());\n        }\n    }\n\n    /**\n     * Send HTTP PUT request\n     * \n     * @param request HTTP request\n     * @param authenticationAgent Authentication agent\n     * @return HTTP response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    // @FIXME: This method needs a complete refactor, However at this moment due to other prior\n    // tasks the refactoring task has been kept in backlog.\n    private HttpResponse sendHttpRequest(HttpRequest request,\n            HttpAuthenticationAgent authenticationAgent) throws PayloadException, NetworkException {\n        SocketConnection conn = null;\n        InputStream is = null;\n        OutputStream os = null;\n        try {\n            URL url = new URL(xdmServerAddr.toString());\n            StringBuilder serviceRoot = new StringBuilder();\n            final String path = url.getPath();\n            if (!TextUtils.isEmpty(path)) {\n                serviceRoot.append(path);\n            }\n            /* Open connection with the XCAP server */\n            conn = NetworkFactory.getFactory().createSocketClientConnection();\n            final String host = url.getHost();\n            int port = url.getPort();\n            if (port == -1) {\n                port = PROTOCOL_HTTPS.equals(url.getProtocol()) ? DEFAULT_HTTPS_PORT\n                        : DEFAULT_HTTP_PORT;\n            }\n            conn.open(host, port);\n            is = conn.getInputStream();\n            os = conn.getOutputStream();\n\n            /* Create the HTTP request */\n            String requestUri = serviceRoot.append(request.getUrl()).toString();\n            StringBuilder httpRequest = new StringBuilder(request.getMethod()).append(\" \")\n                    .append(requestUri).append(\" HTTP/1.1\").append(CRLF).append(\"Host: \")\n                    .append(host).append(\":\").append(port).append(CRLF).append(\"User-Agent: \")\n                    .append(TerminalInfo.getProductName()).append(\" \")\n                    .append(TerminalInfo.getProductVersion(mCtx)).append(CRLF);\n\n            if (authenticationAgent != null) {\n                String authorizationHeader = authenticationAgent.generateAuthorizationHeader(\n                        request.getMethod(), requestUri, request.getContent());\n                httpRequest.append(authorizationHeader).append(CRLF);\n            }\n\n            String cookie = request.getCookie();\n            if (cookie != null) {\n                httpRequest.append(\"Cookie: \").append(cookie).append(CRLF);\n            }\n\n            httpRequest.append(\"X-3GPP-Intended-Identity: \\\"\")\n                    .append(ImsModule.getImsUserProfile().getXdmServerLogin()).append(\"\\\"\")\n                    .append(CRLF);\n\n            /* Set the If-match header */\n            Folder folder = documents.get(request.getAUID());\n            if ((folder != null) && (folder.getEntry() != null)\n                    && (folder.getEntry().getEtag() != null)) {\n                httpRequest.append(\"If-match: \\\"\").append(folder.getEntry().getEtag()).append(\"\\\"\")\n                        .append(CRLF);\n            }\n\n            if (request.getContent() != null) {\n                httpRequest.append(\"Content-type: \").append(request.getContentType()).append(CRLF);\n                httpRequest.append(\"Content-Length:\").append(request.getContentLength())\n                        .append(CRLF).append(CRLF);\n            } else {\n                httpRequest.append(\"Content-Length: 0\").append(CRLF).append(CRLF);\n            }\n\n            /* Write HTTP request headers */\n            os.write(httpRequest.toString().getBytes(UTF8));\n            os.flush();\n\n            /* Write HTTP content */\n            if (request.getContent() != null) {\n                os.write(request.getContent().getBytes(UTF8));\n                os.flush();\n            }\n\n            if (sLogger.isActivated()) {\n                if (request.getContent() != null) {\n                    sLogger.debug(\"Send HTTP request:\\n\" + httpRequest + request.getContent());\n                } else {\n                    sLogger.debug(\"Send HTTP request:\\n\" + httpRequest);\n                }\n            }\n\n            /* Read HTTP headers response */\n            StringBuffer respTrace = new StringBuffer();\n            HttpResponse response = new HttpResponse();\n            int ch = -1;\n            String line = \"\";\n            while ((ch = is.read()) != -1) {\n                line += (char) ch;\n\n                if (line.endsWith(CRLF)) {\n                    if (line.equals(CRLF)) {\n                        /* All headers has been read */\n                        break;\n                    }\n\n                    if (sLogger.isActivated()) {\n                        respTrace.append(line);\n                    }\n\n                    /* Remove CRLF */\n                    line = line.substring(0, line.length() - 2);\n\n                    if (line.startsWith(\"HTTP/\")) {\n                        response.setStatusLine(line);\n                    } else {\n                        int index = line.indexOf(\":\");\n                        String name = line.substring(0, index).trim().toLowerCase();\n                        String value = line.substring(index + 1).trim();\n                        response.addHeader(name, value);\n                    }\n\n                    line = \"\";\n                }\n            }\n\n            int contentLength = -1;\n            try {\n                String value = response.getHeader(\"content-length\");\n                contentLength = Integer.parseInt(value);\n            } catch (NumberFormatException e) {\n                contentLength = -1;\n            }\n\n            if (contentLength > 0) {\n                byte[] content = new byte[contentLength];\n                int nb = -1;\n                int pos = 0;\n                byte[] buffer = new byte[1024];\n                while ((nb = is.read(buffer)) != -1) {\n                    System.arraycopy(buffer, 0, content, pos, nb);\n                    pos += nb;\n\n                    if (pos >= contentLength) {\n                        break;\n                    }\n                }\n                if (sLogger.isActivated()) {\n                    respTrace.append(CRLF).append(new String(content, UTF8));\n                }\n                response.setContent(content);\n            }\n\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Receive HTTP response:\\n\" + respTrace.toString());\n            }\n\n            /* Save the Etag from the received response */\n            String etag = response.getHeader(\"etag\");\n            if ((etag != null) && (folder != null) && (folder.getEntry() != null)) {\n                folder.getEntry().setEtag(etag);\n            }\n            return response;\n\n        } catch (MalformedURLException e) {\n            throw new PayloadException(new StringBuilder(\n                    \"Failed to send http request, malformed uri: \").append(xdmServerAddr)\n                    .toString(), e);\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to send http request!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(conn);\n            CloseableUtils.tryToClose(is);\n            CloseableUtils.tryToClose(os);\n        }\n    }\n\n    /**\n     * Initialize the XDM interface\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void initialize() throws PayloadException, NetworkException {\n        try {\n            UserProfile profile = ImsModule.getImsUserProfile();\n            xdmServerAddr = profile.getXdmServerAddr();\n            xdmServerLogin = profile.getXdmServerLogin();\n            xdmServerPwd = profile.getXdmServerPassword();\n\n            HttpResponse response = getXcapDocuments();\n            if (!response.isSuccessfullResponse()) {\n                throw new NetworkException(\n                        \"Failed to get successfull response from presence server!\");\n            }\n            // Analyze the XCAP directory\n            InputSource input = new InputSource(new ByteArrayInputStream(response.getContent()));\n            XcapDirectoryParser parser = new XcapDirectoryParser(input);\n            documents = parser.getDocuments();\n\n            // Check RCS list document\n            Folder folder = documents.get(\"rls-services\");\n            if ((folder == null) || (folder.getEntry() == null)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The rls-services document does not exist\");\n                }\n\n                // Set RCS list document\n                setRcsList();\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The rls-services document already exists\");\n                }\n            }\n\n            // Check resource list document\n            folder = documents.get(\"resource-lists\");\n            if ((folder == null) || (folder.getEntry() == null)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The resource-lists document does not exist\");\n                }\n\n                // Set resource list document\n                setResourcesList();\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The resource-lists document already exists\");\n                }\n            }\n\n            // Check presence rules document\n            folder = documents.get(\"org.openmobilealliance.pres-rules\");\n            if ((folder == null) || (folder.getEntry() == null)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The org.openmobilealliance.pres-rules document does not exist\");\n                }\n\n                // Set presence rules document\n                setPresenceRules();\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"The org.openmobilealliance.pres-rules document already exists\");\n                }\n            }\n        } catch (ParserConfigurationException e) {\n            throw new PayloadException(\"Can't parse the XCAP directory document!\", e);\n\n        } catch (SAXException e) {\n            throw new PayloadException(\"Can't parse the XCAP directory document!\", e);\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Can't parse the XCAP directory document!\", e);\n        }\n    }\n\n    /**\n     * Get XCAP managed documents\n     * \n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private HttpResponse getXcapDocuments() throws PayloadException, NetworkException {\n        return sendRequestToXDMS(new HttpGetRequest(new StringBuilder(XCAP_SCHEME)\n                .append(ImsModule.getImsUserProfile().getPublicUri()).append(XCAP_FRAGMENT)\n                .toString()));\n    }\n\n    /**\n     * Set RCS list\n     * \n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private HttpResponse setRcsList() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Set RCS list\");\n        }\n        String user = ImsModule.getImsUserProfile().getPublicUri();\n        String resList = xdmServerAddr + \"/resource-lists/users/\" + Uri.encode(user)\n                + \"/index/~~/resource-lists/list%5B@name=%22rcs%22%5D\";\n        String content = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\")\n                .append(UTF8_STR)\n                .append(\"\\\"?>\")\n                .append(CRLF)\n                .append(\"<rls-services xmlns=\\\"urn:ietf:params:xml:ns:rls-services\\\" xmlns:rl=\\\"urn:ietf:params:xml:ns:resource-lists\\\">\")\n                .append(CRLF).append(\"<service uri=\\\"\").append(user).append(\";pres-list=rcs\\\">\")\n                .append(CRLF).append(\"<resource-list>\").append(resList).append(\"</resource-list>\")\n                .append(CRLF).append(\"<packages>\").append(CRLF)\n                .append(\" <package>presence</package>\").append(CRLF).append(\"</packages>\")\n                .append(CRLF).append(\"</service></rls-services>\").toString();\n\n        return sendRequestToXDMS(new HttpPutRequest(Uri.fromParts(RLS_SCHEME, user, INDEX_FRAGMENT)\n                .getEncodedPath(), content, CONTENT_TYPE_RLS));\n\n    }\n\n    /**\n     * Set resources list\n     * \n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private HttpResponse setResourcesList() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Set resources list\");\n        }\n        String user = ImsModule.getImsUserProfile().getPublicUri();\n        String resList = xdmServerAddr + \"/resource-lists/users/\" + Uri.encode(user)\n                + \"/index/~~/resource-lists/list%5B\";\n        String content = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\").append(UTF8_STR)\n                .append(\"\\\"?>\").append(CRLF)\n                .append(\"<resource-lists xmlns=\\\"urn:ietf:params:xml:ns:resource-lists\\\">\")\n                .append(CRLF).append(\"<list name=\\\"oma_buddylist\\\">\").append(CRLF)\n                .append(\" <external anchor=\\\"\").append(resList).append(\"@name=%22rcs%22%5D\\\"/>\")\n                .append(CRLF).append(\"</list>\").append(CRLF)\n                .append(\"<list name=\\\"oma_grantedcontacts\\\">\").append(CRLF)\n                .append(\" <external anchor=\\\"\").append(resList).append(\"@name=%22rcs%22%5D\\\"/>\")\n                .append(CRLF).append(\"</list>\").append(CRLF)\n                .append(\"<list name=\\\"oma_blockedcontacts\\\">\").append(CRLF)\n                .append(\" <external anchor=\\\"\").append(resList)\n                .append(\"@name=%22rcs_blockedcontacts%22%5D\\\"/>\").append(CRLF)\n                .append(\" <external anchor=\\\"\").append(resList)\n                .append(\"@name=%22rcs_revokedcontacts%22%5D\\\"/>\").append(CRLF).append(\"</list>\")\n                .append(CRLF).append(\"<list name=\\\"rcs\\\">\").append(CRLF)\n                .append(\" <display-name>My presence buddies</display-name>\").append(CRLF)\n                .append(\"</list>\").append(CRLF).append(\"<list name=\\\"rcs_blockedcontacts\\\">\")\n                .append(CRLF).append(\" <display-name>My blocked contacts</display-name>\")\n                .append(CRLF).append(\"</list>\").append(CRLF)\n                .append(\"<list name=\\\"rcs_revokedcontacts\\\">\").append(CRLF)\n                .append(\" <display-name>My revoked contacts</display-name>\").append(CRLF)\n                .append(\"</list>\").append(CRLF).append(\"</resource-lists>\").toString();\n\n        return sendRequestToXDMS(new HttpPutRequest(Uri.fromParts(RESOURCE_SCHEME, user,\n                INDEX_FRAGMENT).getEncodedPath(), content, CONTENT_TYPE_RESOURCE));\n\n    }\n\n    /**\n     * Set presence rules\n     * \n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private HttpResponse setPresenceRules() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Set presence rules\");\n        }\n        String user = ImsModule.getImsUserProfile().getPublicUri();\n        String blockedList = xdmServerAddr + \"/resource-lists/users/\" + user\n                + \"/index/~~/resource-lists/list%5B@name=%22oma_blockedcontacts%22%5D\";\n        String grantedList = xdmServerAddr + \"/resource-lists/users/\" + user\n                + \"/index/~~/resource-lists/list%5B@name=%22oma_grantedcontacts%22%5D\";\n        String content = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\")\n                .append(UTF8_STR)\n                .append(\"\\\"?>\")\n                .append(CRLF)\n                .append(\"<cr:ruleset xmlns:ocp=\\\"urn:oma:xml:xdm:common-policy\\\" xmlns:pr=\\\"urn:ietf:params:xml:ns:pres-rules\\\" xmlns:cr=\\\"urn:ietf:params:xml:ns:common-policy\\\">\")\n                .append(CRLF).append(\"<cr:rule id=\\\"wp_prs_allow_own\\\">\").append(CRLF)\n                .append(\" <cr:conditions>\").append(CRLF).append(\"  <cr:identity><cr:one id=\\\"\")\n                .append(user).append(\"\\\"/></cr:identity>\").append(CRLF).append(\" </cr:conditions>\")\n                .append(CRLF)\n                .append(\" <cr:actions><pr:sub-handling>allow</pr:sub-handling></cr:actions>\")\n                .append(CRLF).append(\" <cr:transformations>\").append(CRLF)\n                .append(\"  <pr:provide-services><pr:all-services/></pr:provide-services>\")\n                .append(CRLF)\n                .append(\"  <pr:provide-persons><pr:all-persons/></pr:provide-persons>\")\n                .append(CRLF)\n                .append(\"  <pr:provide-devices><pr:all-devices/></pr:provide-devices>\")\n                .append(CRLF).append(\"  <pr:provide-all-attributes/>\").append(CRLF)\n                .append(\" </cr:transformations>\").append(CRLF).append(\"</cr:rule>\").append(CRLF)\n                .append(\"<cr:rule id=\\\"rcs_allow_services_anonymous\\\">\").append(CRLF)\n                .append(\" <cr:conditions><ocp:anonymous-request/></cr:conditions>\").append(CRLF)\n                .append(\" <cr:actions><pr:sub-handling>allow</pr:sub-handling></cr:actions>\")\n                .append(CRLF).append(\" <cr:transformations>\").append(CRLF)\n                .append(\"  <pr:provide-services><pr:all-services/></pr:provide-services>\")\n                .append(CRLF).append(\"  <pr:provide-all-attributes/>\").append(CRLF)\n                .append(\" </cr:transformations>\").append(CRLF).append(\"</cr:rule>\").append(CRLF)\n                .append(\"<cr:rule id=\\\"wp_prs_unlisted\\\">\").append(CRLF)\n                .append(\" <cr:conditions><ocp:other-identity/></cr:conditions>\").append(CRLF)\n                .append(\" <cr:actions><pr:sub-handling>confirm</pr:sub-handling></cr:actions>\")\n                .append(CRLF).append(\"</cr:rule>\").append(CRLF)\n                .append(\"<cr:rule id=\\\"wp_prs_grantedcontacts\\\">\").append(CRLF)\n                .append(\" <cr:conditions>\").append(CRLF).append(\" <ocp:external-list>\")\n                .append(CRLF).append(\"  <ocp:entry anc=\\\"\").append(grantedList).append(\"\\\"/>\")\n                .append(CRLF).append(\" </ocp:external-list>\").append(CRLF)\n                .append(\" </cr:conditions>\").append(CRLF)\n                .append(\" <cr:actions><pr:sub-handling>allow</pr:sub-handling></cr:actions>\")\n                .append(CRLF).append(\" <cr:transformations>\").append(CRLF)\n                .append(\"   <pr:provide-services><pr:all-services/></pr:provide-services>\")\n                .append(CRLF)\n                .append(\"   <pr:provide-persons><pr:all-persons/></pr:provide-persons>\")\n                .append(CRLF)\n                .append(\"   <pr:provide-devices><pr:all-devices/></pr:provide-devices>\")\n                .append(CRLF).append(\"   <pr:provide-all-attributes/>\").append(CRLF)\n                .append(\" </cr:transformations>\").append(CRLF).append(\"</cr:rule>\").append(CRLF)\n                .append(\"<cr:rule id=\\\"wp_prs_blockedcontacts\\\">\").append(CRLF)\n                .append(\" <cr:conditions>\").append(CRLF).append(\"  <ocp:external-list>\")\n                .append(CRLF).append(\"  <ocp:entry anc=\\\"\").append(blockedList).append(\"\\\"/>\")\n                .append(CRLF).append(\" </ocp:external-list>\").append(CRLF)\n                .append(\" </cr:conditions>\").append(CRLF)\n                .append(\" <cr:actions><pr:sub-handling>block</pr:sub-handling></cr:actions>\")\n                .append(CRLF).append(\"</cr:rule>\").append(CRLF).append(\"</cr:ruleset>\").toString();\n\n        return sendRequestToXDMS(new HttpPutRequest(Uri.fromParts(PRES_RULES_SCHEME, user,\n                PRES_RULES_FRAGMENT).getEncodedPath(), content, CONTENT_TYPE_AUTH));\n    }\n\n    /**\n     * Add a contact to the granted contacts list\n     * \n     * @param contact Contact\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse addContactToGrantedList(ContactId contact) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add \" + contact + \" to granted list\");\n        }\n\n        // URL\n        String url = \"/resource-lists/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/index/~~/resource-lists/list%5B@name=%22rcs%22%5D/entry%5B@uri=%22\"\n                + Uri.encode(PhoneUtils.formatContactIdToUri(contact).toString()) + \"%22%5D\";\n\n        // Content\n        String content = \"<entry uri='\" + contact + \"'></entry>\";\n\n        // Create the request\n        HttpPutRequest request = new HttpPutRequest(url, content, \"application/xcap-el+xml\");\n\n        // Send the request\n        HttpResponse response = sendRequestToXDMS(request);\n        if (response.isSuccessfullResponse()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(contact + \" has been added with success to granted list\");\n            }\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Can't add \" + contact + \" to granted list: \"\n                        + response.getResponseCode() + \" error\");\n            }\n        }\n        return response;\n    }\n\n    /**\n     * Remove a contact from the granted contacts list\n     * \n     * @param contact Contact\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse removeContactFromGrantedList(ContactId contact) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove \" + contact + \" from granted list\");\n        }\n\n        // URL\n        String url = \"/resource-lists/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/index/~~/resource-lists/list%5B@name=%22rcs%22%5D/entry%5B@uri=%22\"\n                + Uri.encode(PhoneUtils.formatContactIdToUri(contact).toString()) + \"%22%5D\";\n\n        // Create the request\n        HttpDeleteRequest request = new HttpDeleteRequest(url);\n\n        // Send the request\n        HttpResponse response = sendRequestToXDMS(request);\n        if (response.isSuccessfullResponse()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(contact + \" has been removed with success from granted list\");\n            }\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Can't remove \" + contact + \" from granted list: \"\n                        + response.getResponseCode() + \" error\");\n            }\n        }\n        return response;\n    }\n\n    private Set<ContactId> convertListOfUrisToSetOfContactId(List<String> uris) {\n        Set<ContactId> result = new HashSet<ContactId>();\n        if (uris != null) {\n            for (String uri : uris) {\n                PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(uri);\n                if (number == null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Cannot parse uri \" + uri);\n                    }\n                    continue;\n                }\n                result.add(ContactUtil.createContactIdFromValidatedData(number));\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Returns the list of granted contacts\n     * \n     * @return List\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public Set<ContactId> getGrantedContacts() throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Get granted contacts list\");\n            }\n            String url = \"/resource-lists/users/\"\n                    + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                    + \"/index/~~/resource-lists/list%5B@name=%22rcs%22%5D\";\n            HttpResponse response = sendRequestToXDMS(new HttpGetRequest(url));\n            if (!response.isSuccessfullResponse()) {\n                throw new PayloadException(new StringBuilder(\n                        \"Can't get granted contacts list, Error Response :  \")\n                        .append(response.getResponseCode()).append(\"!\").toString());\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Granted contacts list has been read with success\");\n            }\n            InputSource input = new InputSource(new ByteArrayInputStream(response.getContent()));\n            XcapResponseParser parser = new XcapResponseParser(input);\n            return convertListOfUrisToSetOfContactId(parser.getUris());\n\n        } catch (ParserConfigurationException e) {\n            throw new PayloadException(\"Unable to get granted contacts list!\", e);\n\n        } catch (SAXException e) {\n            throw new PayloadException(\"Unable to get granted contacts list!\", e);\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Unable to get granted contacts list!\", e);\n        }\n    }\n\n    /**\n     * Remove a contact from the blocked contacts list\n     * \n     * @param contact Contact\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse removeContactFromBlockedList(ContactId contact) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove \" + contact + \" from blocked list\");\n        }\n        String url = \"/resource-lists/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/index/~~/resource-lists/list%5B@name=%22rcs_blockedcontacts%22%5D/entry%5B@uri=%22\"\n                + Uri.encode(PhoneUtils.formatContactIdToUri(contact).toString()) + \"%22%5D\";\n        return sendRequestToXDMS(new HttpDeleteRequest(url));\n    }\n\n    /**\n     * Returns the list of blocked contacts\n     * \n     * @return List\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public Set<ContactId> getBlockedContacts() throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Get blocked contacts list\");\n            }\n            String url = \"/resource-lists/users/\"\n                    + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                    + \"/index/~~/resource-lists/list%5B@name=%22rcs_blockedcontacts%22%5D\";\n            HttpResponse response = sendRequestToXDMS(new HttpGetRequest(url));\n            if (!response.isSuccessfullResponse()) {\n                throw new PayloadException(new StringBuilder(\n                        \"Can't get blocked contacts list, Error Response :  \")\n                        .append(response.getResponseCode()).append(\"!\").toString());\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Blocked contacts list has been read with success\");\n            }\n            InputSource input = new InputSource(new ByteArrayInputStream(response.getContent()));\n            XcapResponseParser parser = new XcapResponseParser(input);\n            return convertListOfUrisToSetOfContactId(parser.getUris());\n\n        } catch (ParserConfigurationException e) {\n            throw new PayloadException(\"Unable to get blocked contacts list!\", e);\n\n        } catch (SAXException e) {\n            throw new PayloadException(\"Unable to get blocked contacts list!\", e);\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Unable to get blocked contacts list!\", e);\n        }\n    }\n\n    /**\n     * Add a contact to the revoked contacts list\n     * \n     * @param contact Contact\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse addContactToRevokedList(ContactId contact) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add \" + contact + \" to revoked list\");\n        }\n        String url = \"/resource-lists/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/index/~~/resource-lists/list%5B@name=%22rcs_revokedcontacts%22%5D/entry%5B@uri=%22\"\n                + Uri.encode(PhoneUtils.formatContactIdToUri(contact).toString()) + \"%22%5D\";\n        String content = \"<entry uri='\" + contact + \"'></entry>\";\n        return sendRequestToXDMS(new HttpPutRequest(url, content, \"application/xcap-el+xml\"));\n    }\n\n    /**\n     * Remove a contact from the revoked contacts list\n     * \n     * @param contact Contact\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse removeContactFromRevokedList(ContactId contact) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove \" + contact + \" from revoked list\");\n        }\n        String url = \"/resource-lists/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/index/~~/resource-lists/list%5B@name=%22rcs_revokedcontacts%22%5D/entry%5B@uri=%22\"\n                + Uri.encode(PhoneUtils.formatContactIdToUri(contact).toString()) + \"%22%5D\";\n        return sendRequestToXDMS(new HttpDeleteRequest(url));\n    }\n\n    /**\n     * Returns the photo icon URL\n     * \n     * @return URL\n     */\n    public String getEndUserPhotoIconUrl() {\n        return xdmServerAddr + \"/org.openmobilealliance.pres-content/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/oma_status-icon/rcs_status_icon\";\n    }\n\n    /**\n     * Upload the end user photo\n     * \n     * @param photo Photo icon\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse uploadEndUserPhoto(PhotoIcon photo) throws PayloadException,\n            NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Upload the end user photo\");\n        }\n        String data = Base64.encodeBase64ToString(photo.getContent());\n        String content = new StringBuilder(\"<?xml version=\\\"1.0\\\" encoding=\\\"\").append(UTF8_STR)\n                .append(\"\\\"?>\").append(CRLF)\n                .append(\"<content xmlns=\\\"urn:oma:xml:prs:pres-content\\\">\").append(CRLF)\n                .append(\"<mime-type>\").append(photo.getType()).append(\"</mime-type>\").append(CRLF)\n                .append(\"<encoding>base64</encoding>\").append(CRLF).append(\"<data>\").append(data)\n                .append(\"</data>\").append(CRLF).append(\"</content>\").toString();\n        String url = \"/org.openmobilealliance.pres-content/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/oma_status-icon/rcs_status_icon\";\n        return sendRequestToXDMS(new HttpPutRequest(url, content,\n                \"application/vnd.oma.pres-content+xml\"));\n    }\n\n    /**\n     * Delete the end user photo\n     * \n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse deleteEndUserPhoto() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Delete the end user photo\");\n        }\n        String url = \"/org.openmobilealliance.pres-content/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri())\n                + \"/oma_status-icon/rcs_status_icon\";\n        return sendRequestToXDMS(new HttpDeleteRequest(url));\n    }\n\n    /**\n     * Set presence info\n     * \n     * @param info Presence info\n     * @return Response\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public HttpResponse setPresenceInfo(String info) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Update presence info\");\n        }\n        String url = \"/pidf-manipulation/users/\"\n                + Uri.encode(ImsModule.getImsUserProfile().getPublicUri()) + \"/perm-presence\";\n        return sendRequestToXDMS(new HttpPutRequest(url, info, \"application/pidf+xml\"));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/ContentSharingError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionBasedServiceError;\n\n/**\n * Content sharing error\n * \n * @author jexa7410\n */\npublic class ContentSharingError extends ImsSessionBasedServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Media player is not initialized\n     */\n    public final static int MEDIA_PLAYER_NOT_INITIALIZED = RICHCALL_ERROR_CODES + 1;\n\n    /**\n     * Media transfer has failed (e.g. MSRP failure)\n     */\n    public final static int MEDIA_TRANSFER_FAILED = RICHCALL_ERROR_CODES + 2;\n\n    /**\n     * Media player has failed (e.g. video player failure)\n     */\n    public final static int MEDIA_STREAMING_FAILED = RICHCALL_ERROR_CODES + 3;\n\n    /**\n     * Unsupported media type (e.g. codec not supported)\n     */\n    public final static int UNSUPPORTED_MEDIA_TYPE = RICHCALL_ERROR_CODES + 4;\n\n    /**\n     * Media saving has failed (e.g. sdcard is not correctly mounted)\n     */\n    public final static int MEDIA_SAVING_FAILED = RICHCALL_ERROR_CODES + 5;\n\n    /**\n     * Media file is too big\n     */\n    public final static int MEDIA_SIZE_TOO_BIG = RICHCALL_ERROR_CODES + 6;\n\n    /**\n     * Not enough storage space\n     */\n    public final static int NOT_ENOUGH_STORAGE_SPACE = RICHCALL_ERROR_CODES + 7;\n\n    /**\n     * Constructor\n     * \n     * @param error Error\n     */\n    public ContentSharingError(ImsServiceError error) {\n        super(error.getErrorCode(), error);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public ContentSharingError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     * @deprecated <p>\n     *             ContentSharingError(int code, Throwable cause)\n     *             </p>\n     */\n    public ContentSharingError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ContentSharingError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/ContentSharingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\n/**\n * Content sharing session\n * \n * @author jexa7410\n */\npublic abstract class ContentSharingSession extends ImsServiceSession {\n    /**\n     * Content to be shared\n     */\n    private MmContent mContent;\n\n    protected final RichcallService mRichcallService;\n\n    protected final CapabilityService mCapabilityService;\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param content Content to be shared\n     * @param contact Remote contactId\n     * @param rcsSettings RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager accessor\n     * @param capabilityService\n     */\n    public ContentSharingSession(RichcallService parent, MmContent content, ContactId contact,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager,\n            CapabilityService capabilityService) {\n        super(parent, contact, PhoneUtils.formatContactIdToUri(contact), rcsSettings, timestamp,\n                contactManager);\n        mRichcallService = parent;\n        mContent = content;\n        mCapabilityService = capabilityService;\n    }\n\n    /**\n     * Returns the content\n     * \n     * @return Content\n     */\n    public MmContent getContent() {\n        return mContent;\n    }\n\n    /**\n     * Set the content\n     * \n     * @param content Content\n     */\n    public void setContent(MmContent content) {\n        mContent = content;\n    }\n\n    /**\n     * Returns the \"file-selector\" attribute\n     * \n     * @return String\n     */\n    public String getFileSelectorAttribute() {\n        return \"name:\\\"\" + mContent.getName() + \"\\\"\" + \" type:\" + mContent.getEncoding() + \" size:\"\n                + mContent.getSize();\n    }\n\n    /**\n     * Returns the \"file-location\" attribute\n     * \n     * @return Uri\n     */\n    public Uri getFileLocationAttribute() {\n        Uri file = mContent.getUri();\n        if ((file != null) && file.getScheme().startsWith(\"http\")) {\n            return file;\n        }\n        return null;\n    }\n\n    /**\n     * Returns the \"file-transfer-id\" attribute\n     * \n     * @return String\n     */\n    public String getFileTransferId() {\n        return \"CSh\" + IdGenerator.generateMessageID();\n    }\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        super.receiveBye(bye);\n        ContactId remote = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionAborted(remote, TerminationReason.TERMINATION_BY_REMOTE);\n        }\n        mCapabilityService.requestContactCapabilities(remote);\n    }\n\n    @Override\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        super.receiveCancel(cancel);\n        mCapabilityService.requestContactCapabilities(getRemoteContact());\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/RichcallService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.CoreException;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.content.VideoContent;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.gsm.CallManager;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.GeolocTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.OriginatingGeolocTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.TerminatingGeolocTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.image.ImageTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.image.OriginatingImageTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.image.TerminatingImageTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.video.OriginatingVideoStreamingSession;\nimport com.gsma.rcs.core.ims.service.richcall.video.TerminatingVideoStreamingSession;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoStreamingSession;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.GeolocSharingDeleteTask;\nimport com.gsma.rcs.provider.sharing.ImageSharingDeleteTask;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.provider.sharing.UpdateGeolocSharingStateAfterUngracefulTerminationTask;\nimport com.gsma.rcs.provider.sharing.UpdateImageSharingStateAfterUngracefulTerminationTask;\nimport com.gsma.rcs.provider.sharing.UpdateVideoSharingStateAfterUngracefulTerminationTask;\nimport com.gsma.rcs.provider.sharing.VideoSharingDeleteTask;\nimport com.gsma.rcs.service.api.GeolocSharingServiceImpl;\nimport com.gsma.rcs.service.api.ImageSharingServiceImpl;\nimport com.gsma.rcs.service.api.VideoSharingServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\n\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax2.sip.message.Response;\n\n/**\n * Rich call service has in charge to monitor the GSM call in order to stop the current content\n * sharing when the call terminates, to process capability request from remote and to request remote\n * capabilities.\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RichcallService extends ImsService {\n\n    private static final String ISH_OPERATION_THREAD_NAME = \"IshOperations\";\n\n    private static final String ISH_DELETE_OPERATION_THREAD_NAME = \"IshDeleteOperations\";\n\n    private static final String VSH_OPERATION_THREAD_NAME = \"VshOperations\";\n\n    private static final String VSH_DELETE_OPERATION_THREAD_NAME = \"VshDeleteOperations\";\n\n    private static final String GSH_OPERATION_THREAD_NAME = \"GshOperations\";\n\n    private static final String GSH_DELETE_OPERATION_THREAD_NAME = \"GshDeleteOperations\";\n\n    /**\n     * Video share features tags\n     */\n    public final static String[] FEATURE_TAGS_VIDEO_SHARE = {\n        FeatureTags.FEATURE_3GPP_VIDEO_SHARE\n    };\n\n    /**\n     * Image share features tags\n     */\n    public final static String[] FEATURE_TAGS_IMAGE_SHARE = {\n            FeatureTags.FEATURE_3GPP_VIDEO_SHARE, FeatureTags.FEATURE_3GPP_IMAGE_SHARE\n    };\n\n    /**\n     * Geoloc share features tags\n     */\n    public final static String[] FEATURE_TAGS_GEOLOC_SHARE = {\n            FeatureTags.FEATURE_3GPP_VIDEO_SHARE, FeatureTags.FEATURE_3GPP_LOCATION_SHARE\n    };\n\n    private final static Logger sLogger = Logger.getLogger(RichcallService.class.getSimpleName());\n\n    /**\n     * ImageTransferSessionCache with Session ID as key\n     */\n    private Map<String, ImageTransferSession> mImageTransferSessionCache = new HashMap<>();\n\n    /**\n     * VideoStreamingSessionCache with Session ID as key\n     */\n    private Map<String, VideoStreamingSession> mVideoStremaingSessionCache = new HashMap<>();\n\n    /**\n     * GeolocTransferSessionCache with Session ID as key\n     */\n    private Map<String, GeolocTransferSession> mGeolocTransferSessionCache = new HashMap<>();\n\n    private final ContactManager mContactManager;\n\n    private final RcsSettings mRcsSettings;\n\n    private final CallManager mCallManager;\n\n    private final RichCallHistory mRichCallHistory;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final Handler mImageSharingOperationHandler;\n\n    private final Handler mImageSharingDeleteOperationHandler;\n\n    private final Handler mVideoSharingOperationHandler;\n\n    private final Handler mVideoSharingDeleteOperationHandler;\n\n    private final Handler mGeolocSharingOperationHandler;\n\n    private final Handler mGeolocSharingDeleteOperationHandler;\n\n    private ImageSharingServiceImpl mImageSharingService;\n\n    private VideoSharingServiceImpl mVideoSharingService;\n\n    private GeolocSharingServiceImpl mGeolocSharingService;\n\n    private final CapabilityService mCapabilityService;\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param richCallHistory RichCallHistory\n     * @param contactsManager ContactManager\n     * @param rcsSettings the RCS settings accessor\n     * @param callManager the call manager\n     * @param localContentResolver the local content resolver\n     * @param capabilityService the capability service\n     */\n    public RichcallService(ImsModule parent, RichCallHistory richCallHistory,\n            ContactManager contactsManager, RcsSettings rcsSettings, CallManager callManager,\n            LocalContentResolver localContentResolver, CapabilityService capabilityService) {\n        super(parent, true);\n        mContactManager = contactsManager;\n        mRcsSettings = rcsSettings;\n        mCallManager = callManager;\n        mRichCallHistory = richCallHistory;\n        mLocalContentResolver = localContentResolver;\n        mCapabilityService = capabilityService;\n        mImageSharingOperationHandler = allocateBgHandler(ISH_OPERATION_THREAD_NAME);\n        mImageSharingDeleteOperationHandler = allocateBgHandler(ISH_DELETE_OPERATION_THREAD_NAME);\n        mVideoSharingOperationHandler = allocateBgHandler(VSH_OPERATION_THREAD_NAME);\n        mVideoSharingDeleteOperationHandler = allocateBgHandler(VSH_DELETE_OPERATION_THREAD_NAME);\n        mGeolocSharingOperationHandler = allocateBgHandler(GSH_OPERATION_THREAD_NAME);\n        mGeolocSharingDeleteOperationHandler = allocateBgHandler(GSH_DELETE_OPERATION_THREAD_NAME);\n    }\n\n    private Handler allocateBgHandler(String threadName) {\n        HandlerThread thread = new HandlerThread(threadName);\n        thread.start();\n        return new Handler(thread.getLooper());\n    }\n\n    public void register(ImageSharingServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mImageSharingService = service;\n    }\n\n    public void register(VideoSharingServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mVideoSharingService = service;\n    }\n\n    public void register(GeolocSharingServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mGeolocSharingService = service;\n    }\n\n    /**\n     * Initializes richcall service\n     */\n    public void initialize() {\n    }\n\n    public void scheduleImageShareOperation(Runnable runnable) {\n        mImageSharingOperationHandler.post(runnable);\n    }\n\n    public void scheduleVideoShareOperation(Runnable runnable) {\n        mVideoSharingOperationHandler.post(runnable);\n    }\n\n    public void scheduleGeolocShareOperation(Runnable runnable) {\n        mGeolocSharingOperationHandler.post(runnable);\n    }\n\n    public void onCoreLayerStarted() {\n        scheduleImageShareOperation(new UpdateImageSharingStateAfterUngracefulTerminationTask(\n                mRichCallHistory, mImageSharingService));\n        scheduleVideoShareOperation(new UpdateVideoSharingStateAfterUngracefulTerminationTask(\n                mRichCallHistory, mVideoSharingService));\n        scheduleGeolocShareOperation(new UpdateGeolocSharingStateAfterUngracefulTerminationTask(\n                mRichCallHistory, mGeolocSharingService));\n    }\n\n    @Override\n    public synchronized void start() {\n        if (isServiceStarted()) {\n            /* Already started */\n            return;\n        }\n        setServiceStarted(true);\n    }\n\n    @Override\n    public synchronized void stop(TerminationReason reasonCode) {\n        if (!isServiceStarted()) {\n            /* Already stopped */\n            return;\n        }\n        setServiceStarted(false);\n        if (TerminationReason.TERMINATION_BY_SYSTEM == reasonCode) {\n            mImageSharingOperationHandler.getLooper().quit();\n            mVideoSharingOperationHandler.getLooper().quit();\n            mGeolocSharingOperationHandler.getLooper().quit();\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n                mImageSharingDeleteOperationHandler.getLooper().quitSafely();\n                mVideoSharingDeleteOperationHandler.getLooper().quitSafely();\n                mGeolocSharingDeleteOperationHandler.getLooper().quitSafely();\n            } else {\n                mImageSharingDeleteOperationHandler.getLooper().quit();\n                mVideoSharingDeleteOperationHandler.getLooper().quit();\n                mGeolocSharingDeleteOperationHandler.getLooper().quit();\n            }\n        }\n    }\n\n    @Override\n    public void check() {\n    }\n\n    private ImageTransferSession getUnidirectionalImageSharingSession() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get Unidirection ImageTransferSession \");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mImageTransferSessionCache.values().iterator().next();\n        }\n    }\n\n    private boolean isCurrentlyImageSharingUniDirectional() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mImageTransferSessionCache.size() >= SharingDirection.UNIDIRECTIONAL;\n        }\n    }\n\n    private boolean isCurrentlyImageSharingBiDirectional() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mImageTransferSessionCache.size() >= SharingDirection.BIDIRECTIONAL;\n        }\n    }\n\n    private void assertMaximumImageTransferSize(long size, String errorMessage)\n            throws CoreException {\n        long maxSize = ImageTransferSession.getMaxImageSharingSize(mRcsSettings);\n        if (maxSize > 0 && size > maxSize) {\n            if (sLogger.isActivated()) {\n                sLogger.error(errorMessage);\n            }\n            throw new CoreException(errorMessage);\n        }\n    }\n\n    private VideoStreamingSession getUnidirectionalVideoSharingSession() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get Unidirection VideoStreamingSession \");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mVideoStremaingSessionCache.values().iterator().next();\n        }\n    }\n\n    private boolean isCurrentlyVideoSharingUniDirectional() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mVideoStremaingSessionCache.size() >= SharingDirection.UNIDIRECTIONAL;\n        }\n    }\n\n    private boolean isCurrentlyVideoSharingBiDirectional() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mVideoStremaingSessionCache.size() >= SharingDirection.BIDIRECTIONAL;\n        }\n    }\n\n    private GeolocTransferSession getUnidirectionalGeolocSharingSession() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get Unidirection GeolocTransferSession \");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGeolocTransferSessionCache.values().iterator().next();\n        }\n    }\n\n    private boolean isCurrentlyGeolocSharingUniDirectional() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGeolocTransferSessionCache.size() >= SharingDirection.UNIDIRECTIONAL;\n        }\n    }\n\n    private boolean isCurrentlyGeolocSharingBiDirectional() {\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGeolocTransferSessionCache.size() >= SharingDirection.BIDIRECTIONAL;\n        }\n    }\n\n    public void addSession(ImageTransferSession session) {\n        String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add ImageTransferSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mImageTransferSessionCache.put(sessionId, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final ImageTransferSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove ImageTransferSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mImageTransferSessionCache.remove(sessionId);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public ImageTransferSession getImageTransferSession(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get ImageTransferSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mImageTransferSessionCache.get(sessionId);\n        }\n    }\n\n    public void addSession(VideoStreamingSession session) {\n        String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add VideoStreamingSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mVideoStremaingSessionCache.put(sessionId, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final VideoStreamingSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove VideoStreamingSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mVideoStremaingSessionCache.remove(sessionId);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public VideoStreamingSession getVideoSharingSession(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get VideoStreamingSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mVideoStremaingSessionCache.get(sessionId);\n        }\n    }\n\n    public void addSession(GeolocTransferSession session) {\n        String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add GeolocTransferSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGeolocTransferSessionCache.put(sessionId, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final GeolocTransferSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove GeolocTransferSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGeolocTransferSessionCache.remove(sessionId);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public GeolocTransferSession getGeolocTransferSession(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get GeolocTransferSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGeolocTransferSessionCache.get(sessionId);\n        }\n    }\n\n    /**\n     * Is call connected with a given contact\n     * \n     * @param contact Contact Id\n     * @return Boolean\n     */\n    public boolean isCallConnectedWith(ContactId contact) {\n        return (mCallManager.isCallConnectedWith(contact));\n    }\n\n    /**\n     * Initiate an image sharing session\n     * \n     * @param contact Remote contact identifier\n     * @param content The file content to share\n     * @param thumbnail The thumbnail content\n     * @param timestamp Local timestamp\n     * @return CSh session\n     * @throws CoreException\n     */\n    public ImageTransferSession createImageSharingSession(ContactId contact, MmContent content,\n            MmContent thumbnail, long timestamp) throws CoreException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate image sharing session with contact \" + contact + \", file \"\n                    + content.toString());\n        }\n        /* Test if call is established */\n        if (!isCallConnectedWith(contact)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Rich call not established: cancel the initiation\");\n            }\n            throw new CoreException(\"Call not established\");\n        }\n\n        assertMaximumImageTransferSize(content.getSize(), \"File exceeds max size.\");\n\n        /* Reject if there are already 2 bidirectional sessions with a given contact */\n        boolean rejectInvitation = false;\n        if (isCurrentlyImageSharingBiDirectional()) {\n            /* Already a bidirectional session */\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Max sessions reached\");\n            }\n            rejectInvitation = true;\n        } else if (isCurrentlyImageSharingUniDirectional()) {\n            ImageTransferSession currentSession = getUnidirectionalImageSharingSession();\n            if (isSessionOriginating(currentSession)) {\n                /* Originating session already used */\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Max originating sessions reached\");\n                }\n                rejectInvitation = true;\n            } else if (contact == null || !contact.equals(currentSession.getRemoteContact())) {\n                /* Not the same contact */\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Only bidirectional session with same contact authorized\");\n                }\n                rejectInvitation = true;\n            }\n        }\n        if (rejectInvitation) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"The max number of sharing sessions is achieved: cancel the initiation\");\n            }\n            throw new CoreException(\"Max content sharing sessions achieved\");\n        }\n        return new OriginatingImageTransferSession(this, content, contact, thumbnail, mRcsSettings,\n                timestamp, mContactManager, mCapabilityService);\n    }\n\n    /**\n     * Receive an image sharing invitation\n     * \n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onImageSharingInvitationReceived(final SipRequest invite, final long timestamp) {\n        final RichcallService richCallService = this;\n        scheduleImageShareOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    if (logActivated) {\n                        sLogger.info(\"Receive an image sharing session invitation\");\n                    }\n\n                    /* Check validity of contact */\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(SipUtils\n                            .getAssertedIdentity(invite));\n                    if (number == null) {\n                        if (logActivated) {\n                            sLogger.debug(\"Rich call not established: cannot parse contact\");\n                        }\n                        sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                        return;\n\n                    }\n                    ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                    mContactManager.setContactDisplayName(contact,\n                            SipUtils.getDisplayNameFromInvite(invite));\n\n                    /* Test if call is established */\n                    if (!isCallConnectedWith(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Rich call not established: reject the invitation\");\n                        }\n                        sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                        return;\n                    }\n\n                    /* Test if the contact is blocked */\n                    if (mContactManager.isBlockedForContact(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + contact\n                                    + \" is blocked: automatically reject the sharing invitation\");\n                        }\n                        MmContent content = ContentManager.createMmContentFromSdp(invite,\n                                mRcsSettings);\n                        addImageSharingInvitationRejected(contact, content,\n                                ImageSharing.ReasonCode.REJECTED_SPAM, timestamp);\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n                    }\n\n                    MmContent content = ContentManager.createMmContentFromSdp(invite, mRcsSettings);\n                    /* Reject if there are already 2 bidirectional sessions with a given contact */\n                    boolean rejectInvitation = false;\n                    if (isCurrentlyImageSharingBiDirectional()) {\n                        /* Already a bidirectional session */\n                        if (logActivated) {\n                            sLogger.debug(\"Max sessions reached\");\n                        }\n                        rejectInvitation = true;\n                        addImageSharingInvitationRejected(contact, content,\n                                ImageSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS, timestamp);\n                    } else if (isCurrentlyImageSharingUniDirectional()) {\n                        ImageTransferSession currentSession = getUnidirectionalImageSharingSession();\n                        if (isSessionTerminating(currentSession)) {\n                            /* Terminating session already used */\n                            if (logActivated) {\n                                sLogger.debug(\"Max terminating sessions reached\");\n                            }\n                            rejectInvitation = true;\n                        } else if (contact == null\n                                || !contact.equals(currentSession.getRemoteContact())) {\n                            /* Not the same contact */\n                            if (logActivated) {\n                                sLogger.debug(\"Only bidirectional session with same contact authorized\");\n                            }\n                            rejectInvitation = true;\n                            addImageSharingInvitationRejected(contact, content,\n                                    ImageSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS,\n                                    timestamp);\n                        }\n                    }\n                    if (rejectInvitation) {\n                        if (logActivated) {\n                            sLogger.debug(\"Reject the invitation\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n\n                    /* Auto reject if file too big or if storage capacity is too small */\n                    ContentSharingError error = ImageTransferSession.isImageCapacityAcceptable(\n                            content.getSize(), mRcsSettings);\n                    if (error != null) {\n                        sendErrorResponse(invite, Response.DECLINE);\n                        int errorCode = error.getErrorCode();\n                        switch (errorCode) {\n                            case ContentSharingError.MEDIA_SIZE_TOO_BIG:\n                                addImageSharingInvitationRejected(contact, content,\n                                        ImageSharing.ReasonCode.REJECTED_MAX_SIZE, timestamp);\n                                break;\n                            case ContentSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                                addImageSharingInvitationRejected(contact, content,\n                                        ImageSharing.ReasonCode.REJECTED_LOW_SPACE, timestamp);\n                                break;\n                            default:\n                                if (sLogger.isActivated()) {\n                                    sLogger.error(\"Unexpected error while receiving image share invitation\"\n                                            .concat(Integer.toString(errorCode)));\n                                }\n                        }\n                        return;\n                    }\n\n                    ImageTransferSession session = new TerminatingImageTransferSession(\n                            richCallService, invite, contact, mRcsSettings, timestamp,\n                            mContactManager, mCapabilityService);\n\n                    mImageSharingService.receiveImageSharingInvitation(session);\n\n                    session.startSession();\n\n                } catch (FileAccessException | RuntimeException | PayloadException e) {\n                    sLogger.error(\"Failed to receive image share invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive image share invitation! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Initiate a live video sharing session\n     * \n     * @param contact Remote contact Id\n     * @param player Media player\n     * @param timestamp Local timestamp\n     * @return CSh session\n     * @throws CoreException\n     */\n    public VideoStreamingSession createLiveVideoSharingSession(ContactId contact,\n            IVideoPlayer player, long timestamp) throws CoreException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a live video sharing session\");\n        }\n\n        /* Test if call is established */\n        if (!isCallConnectedWith(contact)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Rich call not established: cancel the initiation\");\n            }\n            throw new CoreException(\"Call not established\");\n        }\n\n        /* Reject if there are already 2 bidirectional sessions with a given contact */\n        boolean rejectInvitation = false;\n        if (isCurrentlyVideoSharingBiDirectional()) {\n            /* Already a bidirectional session */\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Max sessions reached\");\n            }\n            rejectInvitation = true;\n\n        } else if (isCurrentlyVideoSharingUniDirectional()) {\n            VideoStreamingSession currentSession = getUnidirectionalVideoSharingSession();\n            if (isSessionOriginating(currentSession)) {\n                /* Originating session already used */\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Max originating sessions reached\");\n                }\n                rejectInvitation = true;\n\n            } else if (contact == null || !contact.equals(currentSession.getRemoteContact())) {\n                /* Not the same contact */\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Only bidirectional session with same contact authorized\");\n                }\n                rejectInvitation = true;\n            }\n        }\n        if (rejectInvitation) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"The max number of sharing sessions is achieved: cancel the initiation\");\n            }\n            throw new CoreException(\"Max content sharing sessions achieved\");\n        }\n        return new OriginatingVideoStreamingSession(this, player,\n                ContentManager.createGenericLiveVideoContent(), contact, mRcsSettings, timestamp,\n                mContactManager, mCapabilityService);\n    }\n\n    /**\n     * Receive a video sharing invitation\n     * \n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onVideoSharingInvitationReceived(final SipRequest invite, final long timestamp) {\n        final RichcallService richCallService = this;\n        scheduleVideoShareOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    if (logActivated) {\n                        sLogger.info(\"Receive a video sharing invitation\");\n                    }\n                    /* Check validity of contact */\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(SipUtils\n                            .getAssertedIdentity(invite));\n                    if (number == null) {\n                        if (logActivated) {\n                            sLogger.debug(\"Rich call not established: cannot parse contact\");\n                        }\n                        sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                        return;\n\n                    }\n                    ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                    mContactManager.setContactDisplayName(contact,\n                            SipUtils.getDisplayNameFromInvite(invite));\n\n                    /* Test if call is established */\n                    if (!isCallConnectedWith(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Rich call not established: reject the invitation\");\n                        }\n                        sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                        return;\n                    }\n\n                    String remoteSdp = invite.getSdpContent();\n                    SipUtils.assertContentIsNotNull(remoteSdp, invite);\n                    VideoContent content = ContentManager.createLiveVideoContentFromSdp(remoteSdp\n                            .getBytes(UTF8));\n\n                    /* Test if the contact is blocked */\n                    if (mContactManager.isBlockedForContact(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + contact\n                                    + \" is blocked: automatically reject the sharing invitation\");\n                        }\n                        addVideoSharingInvitationRejected(contact, content,\n                                VideoSharing.ReasonCode.REJECTED_SPAM, timestamp);\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n                    }\n\n                    /* Reject if there are already 2 bidirectional sessions with a given contact */\n                    boolean rejectInvitation = false;\n                    if (isCurrentlyVideoSharingBiDirectional()) {\n                        /* Already a bidirectional session */\n                        if (logActivated) {\n                            sLogger.debug(\"Max sessions reached\");\n                        }\n                        rejectInvitation = true;\n                        addVideoSharingInvitationRejected(contact, content,\n                                VideoSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS, timestamp);\n\n                    } else if (isCurrentlyVideoSharingUniDirectional()) {\n                        VideoStreamingSession currentSession = getUnidirectionalVideoSharingSession();\n                        if (isSessionTerminating(currentSession)) {\n                            // Terminating session already used\n                            if (logActivated) {\n                                sLogger.debug(\"Max terminating sessions reached\");\n                            }\n                            rejectInvitation = true;\n                            addVideoSharingInvitationRejected(contact, content,\n                                    VideoSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS,\n                                    timestamp);\n\n                        } else if (contact == null\n                                || !contact.equals(currentSession.getRemoteContact())) {\n                            // Not the same contact\n                            if (logActivated) {\n                                sLogger.debug(\"Only bidirectional session with same contact authorized\");\n                            }\n                            rejectInvitation = true;\n                            addVideoSharingInvitationRejected(contact, content,\n                                    VideoSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS,\n                                    timestamp);\n                        }\n                    }\n                    if (rejectInvitation) {\n                        if (logActivated) {\n                            sLogger.debug(\"Reject the invitation\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n\n                    /* Create a new session */\n                    VideoStreamingSession session = new TerminatingVideoStreamingSession(\n                            richCallService, invite, contact, mRcsSettings, timestamp,\n                            mContactManager, mCapabilityService);\n\n                    mVideoSharingService.receiveVideoSharingInvitation(session);\n\n                    session.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive video share invitation! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive video share invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * Initiate a geoloc sharing session\n     * \n     * @param contact Remote contact\n     * @param content Content to be shared\n     * @param geoloc Geolocation\n     * @param timestamp Local timesatmp\n     * @return GeolocTransferSession\n     * @throws CoreException\n     */\n    public GeolocTransferSession createGeolocSharingSession(ContactId contact, MmContent content,\n            Geoloc geoloc, long timestamp) throws CoreException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate geoloc sharing session with contact \" + contact + \".\");\n        }\n        if (!isCallConnectedWith(contact)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Rich call not established: cancel the initiation.\");\n            }\n            throw new CoreException(\"Call not established\");\n        }\n        return new OriginatingGeolocTransferSession(this, content, contact, geoloc, mRcsSettings,\n                timestamp, mContactManager, mCapabilityService);\n    }\n\n    /**\n     * Receive a geoloc sharing invitation\n     * \n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onGeolocSharingInvitationReceived(final SipRequest invite, final long timestamp) {\n        final RichcallService richCallService = this;\n        scheduleGeolocShareOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    boolean logActivated = sLogger.isActivated();\n                    if (logActivated) {\n                        sLogger.info(\"Receive a geoloc sharing session invitation\");\n                    }\n\n                    /* Check validity of contact */\n                    PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(SipUtils\n                            .getAssertedIdentity(invite));\n                    if (number == null) {\n                        if (logActivated) {\n                            sLogger.debug(\"Rich call not established: cannot parse contact\");\n                        }\n                        sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                        return;\n\n                    }\n                    ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                    mContactManager.setContactDisplayName(contact,\n                            SipUtils.getDisplayNameFromInvite(invite));\n\n                    /* Test if call is established */\n                    if (!isCallConnectedWith(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Rich call not established: reject the invitation\");\n                        }\n                        sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                        return;\n                    }\n\n                    /* Test if the contact is blocked */\n                    if (mContactManager.isBlockedForContact(contact)) {\n                        if (logActivated) {\n                            sLogger.debug(\"Contact \" + contact\n                                    + \" is blocked: automatically reject the sharing invitation\");\n                        }\n                        addGeolocSharingInvitationRejected(contact,\n                                GeolocSharing.ReasonCode.REJECTED_SPAM, timestamp);\n                        sendErrorResponse(invite, Response.DECLINE);\n                        return;\n                    }\n\n                    /* Reject if there are already 2 bidirectional sessions with a given contact */\n                    boolean rejectInvitation = false;\n                    if (isCurrentlyGeolocSharingBiDirectional()) {\n                        /* Already a bidirectional session */\n                        if (logActivated) {\n                            sLogger.debug(\"Max sessions reached\");\n                        }\n                        addGeolocSharingInvitationRejected(contact,\n                                GeolocSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS, timestamp);\n                        rejectInvitation = true;\n\n                    } else if (isCurrentlyGeolocSharingUniDirectional()) {\n                        GeolocTransferSession currentSession = getUnidirectionalGeolocSharingSession();\n                        if (isSessionTerminating(currentSession)) {\n                            /* Terminating session already used */\n                            if (logActivated) {\n                                sLogger.debug(\"Max terminating sessions reached\");\n                            }\n                            addGeolocSharingInvitationRejected(contact,\n                                    GeolocSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS,\n                                    timestamp);\n                            rejectInvitation = true;\n\n                        } else if (contact == null\n                                || !contact.equals(currentSession.getRemoteContact())) {\n                            /* Not the same contact */\n                            if (logActivated) {\n                                sLogger.debug(\"Only bidirectional session with same contact authorized\");\n                            }\n                            addGeolocSharingInvitationRejected(contact,\n                                    GeolocSharing.ReasonCode.REJECTED_MAX_SHARING_SESSIONS,\n                                    timestamp);\n                            rejectInvitation = true;\n                        }\n                    }\n                    if (rejectInvitation) {\n                        if (logActivated) {\n                            sLogger.debug(\"Reject the invitation\");\n                        }\n                        sendErrorResponse(invite, Response.BUSY_HERE);\n                        return;\n                    }\n\n                    /* Create a new session */\n                    GeolocTransferSession session = new TerminatingGeolocTransferSession(\n                            richCallService, invite, contact, mRcsSettings, timestamp,\n                            mContactManager, mCapabilityService);\n\n                    mGeolocSharingService.receiveGeolocSharingInvitation(session);\n\n                    session.startSession();\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive geoloc share invitation! (\"\n                                + e.getMessage() + \")\");\n                    }\n                    tryToSendErrorResponse(invite, Response.BUSY_HERE);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive geoloc share invitation!\", e);\n                    tryToSendErrorResponse(invite, Response.DECLINE);\n                }\n            }\n        });\n    }\n\n    /**\n     * This function is used when all session needs to terminated in both invitation pending and\n     * started state.\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void terminateAllSessions() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Terminate all sessions\");\n        }\n        terminateAllSessions(TerminationReason.TERMINATION_BY_SYSTEM);\n    }\n\n    /**\n     * Is the current session an originating one\n     * \n     * @param session the session instance\n     * @return true if session is an originating content sharing session (image or video)\n     */\n    private boolean isSessionOriginating(ContentSharingSession session) {\n        return (session instanceof OriginatingImageTransferSession || session instanceof OriginatingVideoStreamingSession);\n    }\n\n    /**\n     * Is the current session a terminating one\n     * \n     * @param session the session instance\n     * @return true if session is an terminating content sharing session (image or video)\n     */\n    private boolean isSessionTerminating(ContentSharingSession session) {\n        return (session instanceof TerminatingImageTransferSession || session instanceof TerminatingVideoStreamingSession);\n    }\n\n    /**\n     * Handles image sharing rejection\n     * \n     * @param remoteContact Remote contact\n     * @param content Multimedia content\n     * @param reasonCode Rejected reason code\n     * @param timestamp Local timestamp when got image sharing invitation\n     */\n    public void addImageSharingInvitationRejected(ContactId remoteContact, MmContent content,\n            ImageSharing.ReasonCode reasonCode, long timestamp) {\n        mImageSharingService.addImageSharingInvitationRejected(remoteContact, content, reasonCode,\n                timestamp);\n    }\n\n    /**\n     * Handle the case of rejected video sharing\n     * \n     * @param remoteContact Remote contact\n     * @param content Video content\n     * @param reasonCode Rejected reason code\n     * @param timestamp Local timestamp when got video sharing invitation\n     */\n    public void addVideoSharingInvitationRejected(ContactId remoteContact, VideoContent content,\n            VideoSharing.ReasonCode reasonCode, long timestamp) {\n        mVideoSharingService.addVideoSharingInvitationRejected(remoteContact, content, reasonCode,\n                timestamp);\n    }\n\n    /**\n     * Handle the case of rejected geoloc sharing\n     * \n     * @param remoteContact Remote contact\n     * @param reasonCode Rejected reason code\n     * @param timestamp Local timestamp when got geoloc sharing invitation\n     */\n    public void addGeolocSharingInvitationRejected(ContactId remoteContact,\n            GeolocSharing.ReasonCode reasonCode, long timestamp) {\n        mGeolocSharingService.addGeolocSharingInvitationRejected(remoteContact, reasonCode,\n                timestamp);\n    }\n\n    /**\n     * Try to delete all image sharing from history and abort/reject any associated ongoing session\n     * if such exists.\n     */\n    public void tryToDeleteImageSharings() {\n        mImageSharingDeleteOperationHandler.post(new ImageSharingDeleteTask(mImageSharingService,\n                this, mLocalContentResolver));\n    }\n\n    /**\n     * Try to delete image sharing with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     */\n    public void tryToDeleteImageSharings(ContactId contact) {\n        mImageSharingDeleteOperationHandler.post(new ImageSharingDeleteTask(mImageSharingService,\n                this, mLocalContentResolver, contact));\n    }\n\n    /**\n     * Try to delete a image sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId the sharing ID\n     */\n    public void tryToDeleteImageSharing(String sharingId) {\n        mImageSharingDeleteOperationHandler.post(new ImageSharingDeleteTask(mImageSharingService,\n                this, mLocalContentResolver, sharingId));\n    }\n\n    /**\n     * Try to delete all video sharing from history and abort/reject any associated ongoing session\n     * if such exists.\n     */\n    public void tryToDeleteVideoSharings() {\n        mVideoSharingDeleteOperationHandler.post(new VideoSharingDeleteTask(mVideoSharingService,\n                this, mLocalContentResolver));\n    }\n\n    /**\n     * Try to delete video sharing with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     */\n    public void tryToDeleteVideoSharings(ContactId contact) {\n        mVideoSharingDeleteOperationHandler.post(new VideoSharingDeleteTask(mVideoSharingService,\n                this, mLocalContentResolver, contact));\n    }\n\n    /**\n     * Try to delete a video sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId the sharing ID\n     */\n    public void tryToDeleteVideoSharing(String sharingId) {\n        mVideoSharingDeleteOperationHandler.post(new VideoSharingDeleteTask(mVideoSharingService,\n                this, mLocalContentResolver, sharingId));\n    }\n\n    /**\n     * Try to delete all geoloc sharing from history and abort/reject any associated ongoing session\n     * if such exists.\n     */\n    public void tryToDeleteGeolocSharings() {\n        mGeolocSharingDeleteOperationHandler.post(new GeolocSharingDeleteTask(\n                mGeolocSharingService, this, mLocalContentResolver));\n    }\n\n    /**\n     * Try to delete geoloc sharing with a given contact from history and abort/reject any\n     * associated ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     */\n    public void tryToDeleteGeolocSharings(ContactId contact) {\n        mGeolocSharingDeleteOperationHandler.post(new GeolocSharingDeleteTask(\n                mGeolocSharingService, this, mLocalContentResolver, contact));\n    }\n\n    /**\n     * Try to delete a geoloc sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId the sharing ID\n     */\n    public void tryToDeleteGeolocSharing(String sharingId) {\n        mGeolocSharingDeleteOperationHandler.post(new GeolocSharingDeleteTask(\n                mGeolocSharingService, this, mLocalContentResolver, sharingId));\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/geoloc/GeolocTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.geoloc;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingSession;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Geoloc sharing transfer session\n * \n * @author jexa7410\n */\npublic abstract class GeolocTransferSession extends ContentSharingSession {\n    /**\n     * Default SO_TIMEOUT value (in milliseconds)\n     */\n    public final static long DEFAULT_SO_TIMEOUT = 30000;\n\n    private boolean mGeolocTransferred = false;\n\n    private Geoloc mGeoloc;\n\n    private static final Logger sLogger = Logger.getLogger(GeolocTransferSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param content Content to be shared\n     * @param contact Remote contact Id\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     * @param capabilityService\n     */\n    public GeolocTransferSession(RichcallService parent, MmContent content, ContactId contact,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager,\n            CapabilityService capabilityService) {\n        super(parent, content, contact, rcsSettings, timestamp, contactManager, capabilityService);\n    }\n\n    /**\n     * Set geoloc\n     * \n     * @param geoloc Geoloc\n     */\n    public void setGeoloc(Geoloc geoloc) {\n        mGeoloc = geoloc;\n    }\n\n    /**\n     * Get geoloc\n     * \n     * @return Geoloc\n     */\n    public Geoloc getGeoloc() {\n        return mGeoloc;\n    }\n\n    /**\n     * Sets Geoloc transferred\n     */\n    public void setGeolocTransferred() {\n        mGeolocTransferred = true;\n    }\n\n    /**\n     * Is geoloc transferred\n     * \n     * @return Boolean\n     */\n    public boolean isGeolocTransferred() {\n        return mGeolocTransferred;\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return the INVITE request\n     * @throws PayloadException\n     */\n    public SipRequest createInvite() throws PayloadException {\n        return SipMessageFactory.createInvite(getDialogPath(),\n                RichcallService.FEATURE_TAGS_GEOLOC_SHARE, getDialogPath().getLocalContent());\n    }\n\n    /**\n     * Session inactivity event\n     */\n    public void handleInactivityEvent() {\n        /* Not need in this class */\n    }\n\n    /**\n     * Handle error\n     * \n     * @param error Error\n     */\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Transfer error: \").append(error.getErrorCode())\n                    .append(\", reason=\").append(error.getMessage()).toString());\n        }\n        closeMediaSession();\n        removeSession();\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((GeolocTransferSessionListener) listener).onSharingError(contact,\n                    new ContentSharingError(error));\n        }\n    }\n\n    @Override\n    public void startSession() {\n        mRichcallService.addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        mRichcallService.removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/geoloc/GeolocTransferSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.geoloc;\n\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Geoloc sharing transfer session listener\n * \n * @author jexa7410\n */\npublic interface GeolocTransferSessionListener extends ImsSessionListener {\n    /**\n     * Content sharing error\n     * \n     * @param contact Remote contact\n     * @param error Error\n     */\n    public void onSharingError(ContactId contact, ContentSharingError error);\n\n    /**\n     * Content has been transfered\n     * \n     * @param contact Remote contact\n     * @param geoloc Geolocation\n     * @param initiatedByRemote\n     */\n    public void onContentTransferred(ContactId contact, Geoloc geoloc, boolean initiatedByRemote);\n\n    /**\n     * Destination user agent received INVITE, and is alerting user of call\n     * \n     * @param contact Remote contact\n     */\n    public void onSessionRinging(ContactId contact);\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void onInvitationReceived(ContactId contact, long timestamp);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/geoloc/OriginatingGeolocTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.geoloc;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.GeolocContent;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStream;\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * Originating geoloc sharing session (transfer)\n * \n * @author jexa7410\n */\npublic class OriginatingGeolocTransferSession extends GeolocTransferSession implements\n        MsrpEventListener {\n\n    private MsrpManager msrpMgr;\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingGeolocTransferSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param content Content to be shared\n     * @param contact Remote contact Id\n     * @param geoloc Geoloc info\n     * @param rcsSettings The RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     * @param capabilityService The capability service\n     */\n    public OriginatingGeolocTransferSession(RichcallService parent, MmContent content,\n            ContactId contact, Geoloc geoloc, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService) {\n        super(parent, content, contact, rcsSettings, timestamp, contactManager, capabilityService);\n        createOriginatingDialogPath();\n        setGeoloc(geoloc);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new sharing session as originating\");\n            }\n\n            // Set setup mode\n            String localSetup = createMobileToMobileSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \" + localSetup);\n            }\n\n            // Set local port\n            int localMsrpPort = 9; // See RFC4145, Page 4\n\n            // Create the MSRP manager\n            String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                    .getNetworkAccess().getIpAddress();\n            msrpMgr = new MsrpManager(localIpAddress, localMsrpPort, mRcsSettings);\n\n            // Build SDP part\n            String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis());\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String sdp = \"v=0\" + SipUtils.CRLF + \"o=- \" + ntpTime + \" \" + ntpTime + \" \"\n                    + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"s=-\" + SipUtils.CRLF\n                    + \"c=\" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"t=0 0\"\n                    + SipUtils.CRLF + \"m=message \" + localMsrpPort + \" TCP/MSRP *\" + SipUtils.CRLF\n                    + \"a=path:\" + msrpMgr.getLocalMsrpPath() + SipUtils.CRLF + \"a=setup:\"\n                    + localSetup + SipUtils.CRLF + \"a=accept-types:\" + getContent().getEncoding()\n                    + SipUtils.CRLF + \"a=file-transfer-id:\" + getFileTransferId() + SipUtils.CRLF\n                    + \"a=file-disposition:render\" + SipUtils.CRLF + \"a=sendonly\" + SipUtils.CRLF;\n\n            // Set File-selector attribute\n            String selector = getFileSelectorAttribute();\n            if (selector != null) {\n                sdp += \"a=file-selector:\" + selector + SipUtils.CRLF;\n            }\n\n            // Set File-location attribute\n            Uri location = getFileLocationAttribute();\n            if (location != null) {\n                sdp += \"a=file-location:\" + location.toString() + SipUtils.CRLF;\n            }\n\n            // Set the local SDP part in the dialog path\n            getDialogPath().setLocalContent(sdp);\n\n            // Create an INVITE request\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInvite();\n\n            // Set the Authorization header\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n\n            // Set initial request in the dialog path\n            getDialogPath().setInvite(invite);\n\n            // Send INVITE request\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException | FileAccessException | PayloadException e) {\n            sLogger.error(\"Failed initiate a new sharing session as originating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /**\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed initiate a new sharing session as originating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"End of thread\");\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        // Changed by Deutsche Telekom\n        // Get the remote SDP part\n        byte[] sdp = getDialogPath().getRemoteContent().getBytes(UTF8);\n\n        // Changed by Deutsche Telekom\n        // Create the MSRP session\n        MsrpSession session = msrpMgr.createMsrpSession(sdp, this);\n        session.setFailureReportOption(true);\n        session.setSuccessReportOption(false);\n    }\n\n    @Override\n    public void openMediaSession() throws NetworkException, PayloadException {\n        msrpMgr.openMsrpSession();\n    }\n\n    @Override\n    public void startMediaTransfer() throws NetworkException {\n        /* Start sending data chunks */\n        byte[] data = ((GeolocContent) getContent()).getData();\n        InputStream stream = new ByteArrayInputStream(data);\n        msrpMgr.sendChunks(stream, getFileTransferId(), getContent().getEncoding(), getContent()\n                .getSize(), TypeMsrpChunk.GeoLocation);\n\n    }\n\n    @Override\n    public void closeMediaSession() {\n        if (msrpMgr != null) {\n            msrpMgr.closeSession();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"MSRP session has been closed\");\n        }\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transferred\");\n            }\n            setGeolocTransferred();\n            closeMediaSession();\n            closeSession(TerminationReason.TERMINATION_BY_USER);\n            removeSession();\n            ContactId contact = getRemoteContact();\n            Geoloc geoloc = getGeoloc();\n            boolean initiatedByRemote = isInitiatedByRemote();\n            for (ImsSessionListener listener : getListeners()) {\n                ((GeolocTransferSessionListener) listener).onContentTransferred(contact, geoloc,\n                        initiatedByRemote);\n            }\n        } catch (PayloadException e) {\n            sLogger.error(new StringBuilder(\"Failed to notify msrp data transfered for msgId : \")\n                    .append(msgId).toString(), e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(new StringBuilder(\"Failed to notify msrp data transfered for msgId : \")\n                    .append(msgId).toString(), e);\n        }\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) {\n        // Not used in originating side\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used for geolocation sharing\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        // Not used in originating side\n        return false;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer aborted\");\n        }\n    }\n\n    @Override\n    public void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk) {\n        try {\n            if (isSessionInterrupted()) {\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transfer error \" + error);\n            }\n            closeMediaSession();\n            closeSession(TerminationReason.TERMINATION_BY_SYSTEM);\n            ContactId contact = getRemoteContact();\n            mCapabilityService.requestContactCapabilities(contact);\n            removeSession();\n            for (ImsSessionListener listener : getListeners()) {\n                ((GeolocTransferSessionListener) listener).onSharingError(contact,\n                        new ContentSharingError(ContentSharingError.MEDIA_TRANSFER_FAILED));\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void handle180Ringing(SipResponse response) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"handle180Ringing\");\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((GeolocTransferSessionListener) listener).onSessionRinging(contact);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/geoloc/TerminatingGeolocTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.geoloc;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Collection;\nimport java.util.Vector;\n\n/**\n * Terminating geoloc sharing session (transfer)\n * \n * @author jexa7410\n */\npublic class TerminatingGeolocTransferSession extends GeolocTransferSession implements\n        MsrpEventListener {\n\n    private MsrpManager msrpMgr;\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingGeolocTransferSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param invite Initial INVITE request\n     * @param contact Contact Id\n     * @param rcsSettings The RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     * @param capabilityService The capability service\n     * @throws PayloadException\n     */\n    public TerminatingGeolocTransferSession(RichcallService parent, SipRequest invite,\n            ContactId contact, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService)\n            throws PayloadException {\n        super(parent, ContentManager.createMmContentFromSdp(invite, rcsSettings), contact,\n                rcsSettings, timestamp, contactManager, capabilityService);\n        createTerminatingDialogPath(invite);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new sharing session as terminating\");\n            }\n            SipDialogPath dialogPath = getDialogPath();\n            send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n            if (getContent() == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"MIME type is not supported\");\n                }\n                send415Error(dialogPath.getInvite());\n                handleError(new ContentSharingError(ContentSharingError.UNSUPPORTED_MEDIA_TYPE));\n                return;\n            }\n\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            long timestamp = getTimestamp();\n            for (ImsSessionListener listener : listeners) {\n                ((GeolocTransferSessionListener) listener).onInvitationReceived(contact, timestamp);\n            }\n\n            InvitationStatus answer = waitInvitationAnswer();\n            switch (answer) {\n                case INVITATION_REJECTED_DECLINE:\n                    /* Intentional fall through */\n                case INVITATION_REJECTED_BUSY_HERE:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected by user\");\n                    }\n                    sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                    removeSession();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_USER);\n                    }\n                    return;\n\n                case INVITATION_TIMEOUT:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected on timeout\");\n                    }\n                    // Ringing period timeout\n                    send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n                    removeSession();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact,\n                                TerminationReason.TERMINATION_BY_TIMEOUT);\n                    }\n                    return;\n\n                case INVITATION_REJECTED_BY_SYSTEM:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been aborted by system\");\n                    }\n                    removeSession();\n                    return;\n\n                case INVITATION_CANCELED:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected by remote\");\n                    }\n                    removeSession();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_REMOTE);\n                    }\n                    return;\n\n                case INVITATION_ACCEPTED:\n                    setSessionAccepted();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionAccepting(contact);\n                    }\n                    break;\n\n                case INVITATION_DELETED:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been deleted\");\n                    }\n                    removeSession();\n                    return;\n\n                default:\n                    throw new IllegalArgumentException(new StringBuilder(\n                            \"Unknown invitation answer in run; answer=\").append(answer).toString());\n            }\n\n            // Parse the remote SDP part\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            MediaAttribute attr1 = mediaDesc.getMediaAttribute(\"file-selector\");\n            String fileSelector = attr1.getName() + \":\" + attr1.getValue();\n            MediaAttribute attr2 = mediaDesc.getMediaAttribute(\"file-transfer-id\");\n            String fileTransferId = attr2.getName() + \":\" + attr2.getValue();\n            MediaAttribute attr3 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr3.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n\n            // Extract the \"setup\" parameter\n            String remoteSetup = \"passive\";\n            MediaAttribute attr4 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr4 != null) {\n                remoteSetup = attr4.getValue();\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \" + localSetup);\n            }\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = 9; // See RFC4145, Page 4\n            } else {\n                localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(mRcsSettings);\n            }\n            String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                    .getNetworkAccess().getIpAddress();\n            msrpMgr = new MsrpManager(localIpAddress, localMsrpPort, mRcsSettings);\n            String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis());\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            String sdp = \"v=0\" + SipUtils.CRLF + \"o=- \" + ntpTime + \" \" + ntpTime + \" \"\n                    + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"s=-\" + SipUtils.CRLF\n                    + \"c=\" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"t=0 0\"\n                    + SipUtils.CRLF + \"m=message \" + localMsrpPort + \" TCP/MSRP *\" + SipUtils.CRLF\n                    + \"a=\" + fileSelector + SipUtils.CRLF + \"a=\" + fileTransferId + SipUtils.CRLF\n                    + \"a=accept-types:\" + getContent().getEncoding() + SipUtils.CRLF + \"a=setup:\"\n                    + localSetup + SipUtils.CRLF + \"a=path:\" + msrpMgr.getLocalMsrpPath()\n                    + SipUtils.CRLF + \"a=recvonly\" + SipUtils.CRLF;\n            dialogPath.setLocalContent(sdp);\n\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    RichcallService.FEATURE_TAGS_GEOLOC_SHARE, sdp);\n            dialogPath.setSigEstablished();\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n\n            if (localSetup.equals(\"passive\")) {\n                // Passive mode: client wait a connection\n                msrpMgr.createMsrpServerSession(remotePath, this);\n                msrpMgr.openMsrpSession(GeolocTransferSession.DEFAULT_SO_TIMEOUT);\n            }\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            if (ctx.isSipAck()) {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"ACK request received\");\n                }\n                if (localSetup.equals(\"active\")) {\n                    String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n                    // Active mode: client should connect\n                    msrpMgr.createMsrpClientSession(remoteHost, remotePort, remotePath, this,\n                            fingerprint);\n                    msrpMgr.openMsrpSession(GeolocTransferSession.DEFAULT_SO_TIMEOUT);\n                    sendEmptyDataChunk();\n                }\n                dialogPath.setSessionEstablished();\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(contact);\n                }\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n                handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED));\n            }\n\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to send 200OK response!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to initiate a new geoloc sharing session as terminating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"End of thread\");\n        }\n    }\n\n    /**\n     * Send an empty data chunk\n     * \n     * @throws NetworkException\n     */\n    public void sendEmptyDataChunk() throws NetworkException {\n        msrpMgr.sendEmptyChunk();\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        // Not used in terminating side\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) throws PayloadException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data received\");\n        }\n        ContactId contact = getRemoteContact();\n        String geolocDoc = new String(data, UTF8);\n        Geoloc geoloc = ChatUtils.parseGeolocDocument(geolocDoc);\n        setGeoloc(geoloc);\n        setGeolocTransferred();\n        boolean initiatedByRemote = isInitiatedByRemote();\n        for (ImsSessionListener listener : getListeners()) {\n            ((GeolocTransferSessionListener) listener).onContentTransferred(contact, geoloc,\n                    initiatedByRemote);\n        }\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        // Not used for geolocation sharing\n        return true;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer aborted\");\n        }\n    }\n\n    @Override\n    public void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk) {\n        try {\n            if (isSessionInterrupted()) {\n                return;\n            }\n            boolean logActivated = sLogger.isActivated();\n\n            if (logActivated) {\n                sLogger.info(\"Data transfer error \".concat(error));\n            }\n            closeMediaSession();\n            closeSession(TerminationReason.TERMINATION_BY_SYSTEM);\n\n            ContactId contact = getRemoteContact();\n            mCapabilityService.requestContactCapabilities(contact);\n            removeSession();\n\n            if (isGeolocTransferred()) {\n                return;\n            }\n            for (ImsSessionListener listener : getListeners()) {\n                ((GeolocTransferSessionListener) listener).onSharingError(contact,\n                        new ContentSharingError(ContentSharingError.MEDIA_TRANSFER_FAILED));\n            }\n\n        } catch (PayloadException e) {\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void closeMediaSession() {\n        // Close the MSRP session\n        if (msrpMgr != null) {\n            msrpMgr.closeSession();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"MSRP session has been closed\");\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/image/ImageTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.image;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingSession;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.StorageUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Image sharing transfer session\n * \n * @author jexa7410\n */\npublic abstract class ImageTransferSession extends ContentSharingSession {\n\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    /**\n     * Default SO_TIMEOUT value (in milliseconds)\n     */\n    public final static long DEFAULT_SO_TIMEOUT = 30000;\n\n    private boolean mImageTransfered = false;\n\n    private MmContent mThumbnail;\n\n    private static final Logger sLogger = Logger.getLogger(ImageTransferSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param content Content to be shared\n     * @param contact Remote contact Id\n     * @param thumbnail The thumbnail content\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     * @param capabilityService\n     */\n    public ImageTransferSession(RichcallService parent, MmContent content, ContactId contact,\n            MmContent thumbnail, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService) {\n        super(parent, content, contact, rcsSettings, timestamp, contactManager, capabilityService);\n        mThumbnail = thumbnail;\n    }\n\n    /**\n     * Sets image transferred\n     */\n    public void setImageTransferred() {\n        mImageTransfered = true;\n    }\n\n    /**\n     * Is image transferred\n     * \n     * @return Boolean\n     */\n    public boolean isImageTransferred() {\n        return mImageTransfered;\n    }\n\n    /**\n     * Returns max image sharing size\n     * \n     * @param rcsSettings\n     * @return Size in bytes\n     */\n    public static long getMaxImageSharingSize(RcsSettings rcsSettings) {\n        return rcsSettings.getMaxImageSharingSize();\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return the INVITE request\n     * @throws PayloadException\n     */\n    public SipRequest createInvite() throws PayloadException {\n        if (mThumbnail != null) {\n            return SipMessageFactory.createMultipartInvite(getDialogPath(),\n                    RichcallService.FEATURE_TAGS_IMAGE_SHARE, getDialogPath().getLocalContent(),\n                    BOUNDARY_TAG);\n        }\n        return SipMessageFactory.createInvite(getDialogPath(),\n                RichcallService.FEATURE_TAGS_IMAGE_SHARE, getDialogPath().getLocalContent());\n    }\n\n    @Override\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Transfer error: \").append(error.getErrorCode())\n                    .append(\", reason=\").append(error.getMessage()).toString());\n        }\n        closeMediaSession();\n        removeSession();\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((ImageTransferSessionListener) listener).onSharingError(contact,\n                    new ContentSharingError(error));\n        }\n    }\n\n    /**\n     * Returns the thumbnail content\n     * \n     * @return Thumbnail\n     */\n    public MmContent getThumbnail() {\n        return mThumbnail;\n    }\n\n    /**\n     * Check if image capacity is acceptable\n     * \n     * @param imageSize Image size in bytes\n     * @param rcsSettings\n     * @return Error or null if image capacity is acceptable\n     */\n    public static ContentSharingError isImageCapacityAcceptable(long imageSize,\n            RcsSettings rcsSettings) {\n        boolean fileIsToBig = (ImageTransferSession.getMaxImageSharingSize(rcsSettings) > 0) ? imageSize > ImageTransferSession\n                .getMaxImageSharingSize(rcsSettings) : false;\n        boolean storageIsTooSmall = (StorageUtils.getExternalStorageFreeSpace() > 0) ? imageSize > StorageUtils\n                .getExternalStorageFreeSpace() : false;\n        if (fileIsToBig) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Image is too big, reject the image sharing\");\n            }\n            return new ContentSharingError(ContentSharingError.MEDIA_SIZE_TOO_BIG);\n        }\n        if (storageIsTooSmall) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Not enough storage capacity, reject the image sharing\");\n            }\n            return new ContentSharingError(ContentSharingError.NOT_ENOUGH_STORAGE_SPACE);\n        }\n        return null;\n    }\n\n    @Override\n    public void handleInactivityEvent() {\n        /* Not need in this class */\n    }\n\n    @Override\n    public void startSession() {\n        mRichcallService.addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        mRichcallService.removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/image/ImageTransferSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.image;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\n/**\n * Image sharing transfer session listener\n * \n * @author jexa7410\n */\npublic interface ImageTransferSessionListener extends ImsSessionListener {\n    /**\n     * Content sharing progress\n     * \n     * @param contact Remote contact\n     * @param currentSize Data size transfered\n     * @param totalSize Total size to be transfered\n     */\n    public void onSharingProgress(ContactId contact, long currentSize, long totalSize);\n\n    /**\n     * Content sharing error\n     * \n     * @param contact Remote contact\n     * @param error Error\n     */\n    public void onSharingError(ContactId contact, ContentSharingError error);\n\n    /**\n     * Content has been transferred\n     * \n     * @param contact Remote contact\n     * @param file Uri of file associated to the received content\n     */\n    public void onContentTransferred(ContactId contact, Uri file);\n\n    /**\n     * Destination user agent received INVITE, and is alerting user of call\n     * \n     * @param contact Remote contact\n     */\n    public void onSessionRinging(ContactId contact);\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     * @param content\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void onInvitationReceived(ContactId contact, MmContent content, long timestamp);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/image/OriginatingImageTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.image;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.Base64;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentLengthHeader;\nimport javax2.sip.header.ContentTypeHeader;\n\n/**\n * Originating content sharing session (transfer)\n * \n * @author jexa7410\n */\npublic class OriginatingImageTransferSession extends ImageTransferSession implements\n        MsrpEventListener {\n\n    private final static String BOUNDARY_TAG = \"boundary1\";\n\n    private MsrpManager msrpMgr;\n\n    private final static Logger sLogger = Logger.getLogger(OriginatingImageTransferSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param content Content to be shared\n     * @param contact Remote contact Id\n     * @param thumbnail Thumbnail content option\n     * @param rcsSettings The RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     * @param capabilityService The capability service\n     */\n    public OriginatingImageTransferSession(RichcallService parent, MmContent content,\n            ContactId contact, MmContent thumbnail, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService) {\n        super(parent, content, contact, thumbnail, rcsSettings, timestamp, contactManager,\n                capabilityService);\n        createOriginatingDialogPath();\n    }\n\n    private byte[] getFileData(Uri file, int size) throws IOException {\n        FileInputStream fileInputStream = null;\n        try {\n            fileInputStream = (FileInputStream) AndroidFactory.getApplicationContext()\n                    .getContentResolver().openInputStream(file);\n            byte[] data = new byte[size];\n            if (size != fileInputStream.read(data, 0, size)) {\n                throw new IOException(\"Unable to retrieve data from \" + file);\n            }\n            return data;\n        } finally {\n            CloseableUtils.tryToClose(fileInputStream);\n        }\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new sharing session as originating\");\n            }\n            // Set setup mode\n            String localSetup = createMobileToMobileSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \" + localSetup);\n            }\n            // Set local port\n            int localMsrpPort;\n            if (\"active\".equals(localSetup)) {\n                localMsrpPort = 9; // See RFC4145, Page 4\n            } else {\n                localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(mRcsSettings);\n            }\n            // Create the MSRP manager\n            String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                    .getNetworkAccess().getIpAddress();\n            msrpMgr = new MsrpManager(localIpAddress, localMsrpPort, getImsService(), mRcsSettings);\n            // Build SDP part\n            String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n            String encoding = getContent().getEncoding();\n            long maxSize = ImageTransferSession.getMaxImageSharingSize(mRcsSettings);\n            // Set File-selector attribute\n            String selector = getFileSelectorAttribute();\n            StringBuilder sdp = new StringBuilder(SdpUtils.buildFileSDP(ipAddress, localMsrpPort,\n                    msrpMgr.getLocalSocketProtocol(), encoding, getFileTransferId(), selector,\n                    \"render\", localSetup, msrpMgr.getLocalMsrpPath(), SdpUtils.DIRECTION_SENDONLY,\n                    maxSize));\n            // Set File-location attribute\n            Uri location = getFileLocationAttribute();\n            if (location != null) {\n                sdp.append(\"a=file-location:\").append(location.toString()).append(SipUtils.CRLF);\n            }\n            MmContent fileIcon = getThumbnail();\n            if (fileIcon == null) {\n                /* Set the local SDP part in the dialog path */\n                getDialogPath().setLocalContent(sdp.toString());\n\n            } else {\n                Capabilities remoteCapabilities = mContactManager\n                        .getContactCapabilities(getRemoteContact());\n                boolean fileIconSupported = remoteCapabilities != null\n                        && remoteCapabilities.isFileTransferThumbnailSupported();\n                if (fileIconSupported) {\n                    sdp.append(\"a=file-icon:cid:image@joyn.com\").append(SipUtils.CRLF);\n                    // Encode the thumbnail file\n                    String imageEncoded = Base64.encodeBase64ToString(getFileData(\n                            fileIcon.getUri(), (int) fileIcon.getSize()));\n                    String sdpContent = sdp.toString();\n                    String multipart = Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                            + ContentTypeHeader.NAME + \": application/sdp\" + SipUtils.CRLF\n                            + ContentLengthHeader.NAME + \": \" + sdpContent.getBytes(UTF8).length\n                            + SipUtils.CRLF + SipUtils.CRLF + sdpContent + SipUtils.CRLF\n                            + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG + SipUtils.CRLF\n                            + ContentTypeHeader.NAME + \": \" + getContent().getEncoding()\n                            + SipUtils.CRLF + SipUtils.HEADER_CONTENT_TRANSFER_ENCODING\n                            + \": base64\" + SipUtils.CRLF + SipUtils.HEADER_CONTENT_ID\n                            + \": <image@joyn.com>\" + SipUtils.CRLF + ContentLengthHeader.NAME\n                            + \": \" + imageEncoded.length() + SipUtils.CRLF\n                            + ContentDispositionHeader.NAME + \": icon\" + SipUtils.CRLF\n                            + SipUtils.CRLF + imageEncoded + SipUtils.CRLF\n                            + Multipart.BOUNDARY_DELIMITER + BOUNDARY_TAG\n                            + Multipart.BOUNDARY_DELIMITER;\n                    // Set the local SDP part in the dialog path\n                    getDialogPath().setLocalContent(multipart);\n\n                } else {\n                    // Set the local SDP part in the dialog path\n                    getDialogPath().setLocalContent(sdp.toString());\n                }\n            }\n            // Create an INVITE request\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInvite();\n            // Set the Authorization header\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n            // Set initial request in the dialog path\n            getDialogPath().setInvite(invite);\n            // Send INVITE request\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | ParseException | FileAccessException | PayloadException e) {\n            sLogger.error(\"Failed to send invite!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (IOException | NetworkException e) {\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /**\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to initiate a new sharing session as originating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"End of thread\");\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Get the remote SDP part */\n        byte[] sdp = getDialogPath().getRemoteContent().getBytes(UTF8);\n        MsrpSession session = msrpMgr.createMsrpSession(sdp, this);\n        session.setFailureReportOption(true);\n        session.setSuccessReportOption(false);\n        /* Do not use right now the mapping to do not increase memory and cpu consumption */\n        session.setMapMsgIdFromTransationId(false);\n    }\n\n    @Override\n    public void openMediaSession() throws NetworkException, PayloadException {\n        msrpMgr.openMsrpSession();\n    }\n\n    @Override\n    public void startMediaTransfer() throws NetworkException, FileAccessException {\n        try {\n            /* Start sending data chunks */\n            InputStream stream = AndroidFactory.getApplicationContext().getContentResolver()\n                    .openInputStream(getContent().getUri());\n            msrpMgr.sendChunks(stream, getFileTransferId(), getContent().getEncoding(),\n                    getContent().getSize(), TypeMsrpChunk.FileSharing);\n\n        } catch (FileNotFoundException e) {\n            throw new FileAccessException(\"Failed to initiate media transfer!\", e);\n        }\n    }\n\n    @Override\n    public void closeMediaSession() {\n        if (msrpMgr != null) {\n            msrpMgr.closeSession();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"MSRP session has been closed\");\n        }\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transferred\");\n            }\n            setImageTransferred();\n            closeMediaSession();\n            closeSession(TerminationReason.TERMINATION_BY_USER);\n            removeSession();\n            ContactId contact = getRemoteContact();\n            Uri image = getContent().getUri();\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onContentTransferred(contact, image);\n            }\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to notify msrp data transfered for msgId : \" + msgId, e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) {\n        // Not used in originating side\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((ImageTransferSessionListener) listener).onSharingProgress(contact, currentSize,\n                    totalSize);\n        }\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        // Not used in originating side\n        return false;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer aborted\");\n        }\n    }\n\n    @Override\n    public void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk) {\n        try {\n            if (isSessionInterrupted() || isInterrupted() || getDialogPath().isSessionTerminated()) {\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transfer error \" + error);\n            }\n            closeSession(TerminationReason.TERMINATION_BY_SYSTEM);\n            closeMediaSession();\n            ContactId contact = getRemoteContact();\n            mCapabilityService.requestContactCapabilities(contact);\n            removeSession();\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onSharingError(contact,\n                        new ContentSharingError(ContentSharingError.MEDIA_TRANSFER_FAILED));\n            }\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to handle msrp error\" + error + \" for message \" + msgId, e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void handle180Ringing(SipResponse response) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"handle180Ringing\");\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((ImageTransferSessionListener) listener).onSessionRinging(contact);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/image/TerminatingImageTransferSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.image;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpConstants;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Vector;\n\n/**\n * Terminating content sharing session (transfer)\n * \n * @author jexa7410\n */\npublic class TerminatingImageTransferSession extends ImageTransferSession implements\n        MsrpEventListener {\n\n    private MsrpManager msrpMgr;\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingImageTransferSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param invite Initial INVITE request\n     * @param contact Contact ID\n     * @param rcsSettings The RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager The contact manager accessor\n     * @param capabilityService The capability service\n     * @throws PayloadException\n     * @throws FileAccessException\n     */\n    public TerminatingImageTransferSession(RichcallService parent, SipRequest invite,\n            ContactId contact, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService)\n            throws PayloadException, FileAccessException {\n        super(parent, ContentManager.createMmContentFromSdp(invite, rcsSettings), contact,\n                FileTransferUtils.extractFileIcon(invite, rcsSettings), rcsSettings, timestamp,\n                contactManager, capabilityService);\n        createTerminatingDialogPath(invite);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new sharing session as terminating\");\n            }\n            SipDialogPath dialogPath = getDialogPath();\n            send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n            if (getContent() == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"MIME type is not supported\");\n                }\n                send415Error(dialogPath.getInvite());\n                handleError(new ContentSharingError(ContentSharingError.UNSUPPORTED_MEDIA_TYPE));\n                return;\n            }\n\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            MmContent content = getContent();\n            long timestamp = getTimestamp();\n            for (ImsSessionListener listener : listeners) {\n                ((ImageTransferSessionListener) listener).onInvitationReceived(contact, content,\n                        timestamp);\n            }\n\n            InvitationStatus answer = waitInvitationAnswer();\n            switch (answer) {\n                case INVITATION_REJECTED_DECLINE:\n                    /* Intentional fall through */\n                case INVITATION_REJECTED_BUSY_HERE:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected by user\");\n                    }\n                    sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_USER);\n                    }\n                    return;\n\n                case INVITATION_TIMEOUT:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected on timeout\");\n                    }\n\n                    // Ringing period timeout\n                    send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact,\n                                TerminationReason.TERMINATION_BY_TIMEOUT);\n                    }\n                    return;\n\n                case INVITATION_REJECTED_BY_SYSTEM:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been aborted by system\");\n                    }\n                    removeSession();\n                    return;\n\n                case INVITATION_CANCELED:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected by remote\");\n                    }\n\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_REMOTE);\n                    }\n                    return;\n\n                case INVITATION_ACCEPTED:\n                    setSessionAccepted();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionAccepting(contact);\n                    }\n                    break;\n\n                case INVITATION_DELETED:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been deleted\");\n                    }\n                    removeSession();\n                    return;\n\n                default:\n                    throw new IllegalArgumentException(new StringBuilder(\n                            \"Unknown invitation answer in run; answer=\").append(answer).toString());\n            }\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            String protocol = mediaDesc.mProtocol;\n            boolean isSecured = false;\n            if (protocol != null) {\n                isSecured = protocol.equalsIgnoreCase(MsrpConstants.SOCKET_MSRP_SECURED_PROTOCOL);\n            }\n            // Changed by Deutsche Telekom\n            String fileSelector = mediaDesc.getMediaAttribute(\"file-selector\").getValue();\n            // Changed by Deutsche Telekom\n            String fileTransferId = mediaDesc.getMediaAttribute(\"file-transfer-id\").getValue();\n            MediaAttribute attr3 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr3.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n\n            // Changed by Deutsche Telekom\n            String fingerprint = SdpUtils.extractFingerprint(parser, mediaDesc);\n            String remoteSetup = \"passive\";\n            MediaAttribute attr4 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr4 != null) {\n                remoteSetup = attr4.getValue();\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n            int localMsrpPort;\n            if (localSetup.equals(\"active\")) {\n                localMsrpPort = 9; // See RFC4145, Page 4\n            } else {\n                localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(mRcsSettings);\n            }\n            String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                    .getNetworkAccess().getIpAddress();\n            msrpMgr = new MsrpManager(localIpAddress, localMsrpPort, getImsService(), mRcsSettings);\n            msrpMgr.setSecured(isSecured);\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            long maxSize = ImageTransferSession.getMaxImageSharingSize(mRcsSettings);\n            String sdp = SdpUtils.buildFileSDP(ipAddress, localMsrpPort,\n                    msrpMgr.getLocalSocketProtocol(), getContent().getEncoding(), fileTransferId,\n                    fileSelector, null, localSetup, msrpMgr.getLocalMsrpPath(),\n                    SdpUtils.DIRECTION_RECVONLY, maxSize);\n            dialogPath.setLocalContent(sdp);\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    RichcallService.FEATURE_TAGS_IMAGE_SHARE, sdp);\n            dialogPath.setSigEstablished();\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessage(resp);\n\n            if (localSetup.equals(\"passive\")) {\n                // Passive mode: client wait a connection\n                // Changed by Deutsche Telekom\n                MsrpSession session = msrpMgr.createMsrpServerSession(remotePath, this);\n                // Do not use right now the mapping to do not increase memory and cpu consumption\n                session.setMapMsgIdFromTransationId(false);\n\n                msrpMgr.openMsrpSession(ImageTransferSession.DEFAULT_SO_TIMEOUT);\n                sendEmptyDataChunk();\n            }\n            getImsService().getImsModule().getSipManager().waitResponse(ctx);\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n            if (ctx.isSipAck()) {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"ACK request received\");\n                }\n                if (localSetup.equals(\"active\")) {\n                    // Active mode: client should connect\n                    // Changed by Deutsche Telekom\n                    MsrpSession session = msrpMgr.createMsrpClientSession(remoteHost, remotePort,\n                            remotePath, this, fingerprint);\n                    session.setMapMsgIdFromTransationId(false);\n                    msrpMgr.openMsrpSession(ImageTransferSession.DEFAULT_SO_TIMEOUT);\n                    sendEmptyDataChunk();\n                }\n                dialogPath.setSessionEstablished();\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(contact);\n                }\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n                handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED));\n            }\n\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to send 200OK response!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to initiate a new sharing session as terminating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"End of thread\");\n        }\n    }\n\n    /**\n     * Send an empty data chunk\n     * \n     * @throws NetworkException\n     */\n    public void sendEmptyDataChunk() throws NetworkException {\n        msrpMgr.sendEmptyChunk();\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        // Not used in terminating side\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data received\");\n        }\n        setImageTransferred();\n        ContactId contact = getRemoteContact();\n        MmContent content = getContent();\n        try {\n            content.writeData2File(data);\n            content.closeFile();\n\n            Uri image = getContent().getUri();\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onContentTransferred(contact, image);\n            }\n\n        } catch (FileAccessException e) {\n            deleteFile();\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onSharingError(contact,\n                        new ContentSharingError(ContentSharingError.MEDIA_SAVING_FAILED));\n            }\n        }\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        ContactId contact = getRemoteContact();\n        try {\n            getContent().writeData2File(data);\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onSharingProgress(contact, currentSize,\n                        totalSize);\n            }\n\n        } catch (FileAccessException e) {\n            deleteFile();\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onSharingError(contact,\n                        new ContentSharingError(ContentSharingError.MEDIA_TRANSFER_FAILED));\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer aborted\");\n        }\n        if (!isImageTransferred()) {\n            deleteFile();\n        }\n    }\n\n    @Override\n    public void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk) {\n        try {\n            if (isSessionInterrupted() || isInterrupted() || getDialogPath().isSessionTerminated()) {\n                return;\n            }\n\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Data transfer error \" + error);\n            }\n\n            closeSession(TerminationReason.TERMINATION_BY_SYSTEM);\n            closeMediaSession();\n\n            ContactId contact = getRemoteContact();\n            mCapabilityService.requestContactCapabilities(contact);\n            removeSession();\n\n            if (isImageTransferred()) {\n                return;\n            }\n            for (ImsSessionListener listener : getListeners()) {\n                ((ImageTransferSessionListener) listener).onSharingError(contact,\n                        new ContentSharingError(ContentSharingError.MEDIA_TRANSFER_FAILED));\n            }\n\n        } catch (PayloadException e) {\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\"Failed to handle msrp error\").append(error)\n                            .append(\" for message \").append(msgId).toString(), e);\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        /* Nothing to do in terminating side */\n    }\n\n    @Override\n    public void closeMediaSession() {\n        if (msrpMgr != null) {\n            msrpMgr.closeSession();\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"MSRP session has been closed\");\n        }\n        if (!isImageTransferred()) {\n            deleteFile();\n        }\n    }\n\n    /**\n     * Delete file\n     */\n    private void deleteFile() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Delete incomplete received image\");\n        }\n        try {\n            getContent().deleteFile();\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.error(\"Can't delete received image\", e);\n            }\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/OriginatingVideoStreamingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\n\nimport android.os.RemoteException;\n\nimport java.text.ParseException;\nimport java.util.Vector;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * Originating video content sharing session (streaming)\n * \n * @author hlxn7157\n */\npublic class OriginatingVideoStreamingSession extends VideoStreamingSession {\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingVideoStreamingSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS service\n     * @param player Media player\n     * @param content Content to be shared\n     * @param contact Remote contact Id\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     * @param capabilityService\n     */\n    public OriginatingVideoStreamingSession(RichcallService parent, IVideoPlayer player,\n            MmContent content, ContactId contact, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService) {\n        super(parent, content, contact, rcsSettings, timestamp, contactManager, capabilityService);\n        createOriginatingDialogPath();\n        setPlayer(player);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new live video sharing session as originating\");\n            }\n\n            SipDialogPath dialogPath = getDialogPath();\n            // Build SDP part\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            IVideoPlayer player = getPlayer();\n            String videoSdp = VideoSdpBuilder.buildSdpOfferWithOrientation(\n                    player.getSupportedCodecs(), player.getLocalRtpPort());\n            String sdp = SdpUtils.buildVideoSDP(ipAddress, videoSdp, SdpUtils.DIRECTION_SENDONLY);\n\n            // Set the local SDP part in the dialog path\n            dialogPath.setLocalContent(sdp);\n\n            // Create an INVITE request\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = SipMessageFactory.createInvite(dialogPath,\n                    RichcallService.FEATURE_TAGS_VIDEO_SHARE, sdp);\n\n            // Set the Authorization header\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n\n            // Set initial request in the dialog path\n            dialogPath.setInvite(invite);\n\n            // Send INVITE request\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException e) {\n            sLogger.error(\"Failed to send invite!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (ParseException e) {\n            sLogger.error(\"Failed to send invite!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RemoteException e) {\n            sLogger.error(\"Failed initiate a new live video sharing session as originating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (FileAccessException e) {\n            sLogger.error(\"Failed to send invite!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to send invite!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /**\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed initiate a new live video sharing session as originating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() throws PayloadException, NetworkException {\n        // Parse the remote SDP part\n        SdpParser parser = new SdpParser(getDialogPath().getRemoteContent().getBytes(UTF8));\n        MediaDescription mediaVideo = parser.getMediaDescription(\"video\");\n        String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaVideo);\n        int remotePort = mediaVideo.mPort;\n\n        // Extract video codecs from SDP\n        Vector<MediaDescription> medias = parser.getMediaDescriptions(\"video\");\n        Vector<VideoCodec> proposedCodecs = VideoCodecManager.extractVideoCodecsFromSdp(medias);\n\n        IVideoPlayer player = getPlayer();\n        try {\n            // Codec negotiation\n            VideoCodec selectedVideoCodec = VideoCodecManager.negociateVideoCodec(\n                    player.getSupportedCodecs(), proposedCodecs);\n\n            if (selectedVideoCodec == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Proposed codecs are not supported\");\n                }\n\n                closeSession(TerminationReason.TERMINATION_BY_SYSTEM);\n\n                // Report error\n                handleError(new ContentSharingError(ContentSharingError.UNSUPPORTED_MEDIA_TYPE));\n                return;\n            }\n            getContent().setEncoding(\"video/\" + selectedVideoCodec.getEncoding());\n\n            // Set the video player orientation\n            SdpOrientationExtension extensionHeader = SdpOrientationExtension.create(mediaVideo);\n            if (extensionHeader != null) {\n                // Update the orientation ID\n                setOrientation(extensionHeader.getExtensionId());\n            }\n            // Set the video player remote info\n            player.setRemoteInfo(selectedVideoCodec, remoteHost, remotePort, getOrientation());\n\n        } catch (RemoteException e) {\n            throw new IllegalArgumentException(\"Error when preparing the media session\", e);\n        }\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public void closeMediaSession() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void handle180Ringing(SipResponse response) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"handle180Ringing\");\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((VideoStreamingSessionListener) listener).onSessionRinging(contact);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/SdpOrientationExtension.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\n\n/**\n * Represents the SDP orientation extension\n * \n * @author Deutsche Telekom\n */\npublic class SdpOrientationExtension {\n\n    /**\n     * Video Orientation extension URI\n     */\n    public static final String VIDEO_ORIENTATION_URI = \"urn:3gpp:video-orientation\";\n\n    /**\n     * Minimum ID value for RTP Extension header. RFC5285\n     */\n    private static final int MIN_ID_VALUE = 1;\n\n    /**\n     * Maximum ID value for RTP Extension header. RFC5285\n     */\n    private static final int MAX_ID_VALUE = 14;\n\n    /**\n     * Extension header ID\n     */\n    private int mExtensionId;\n\n    /**\n     * ExtensionHeader URI\n     */\n    private String mUri;\n\n    /**\n     * Constructor\n     * \n     * @param extensionId Extension header ID\n     * @param uri ExtensionHeader URI\n     */\n    private SdpOrientationExtension(int extensionId, String uri) {\n        mExtensionId = extensionId;\n        mUri = uri;\n    }\n\n    /**\n     * Gets the extension Header id.\n     * \n     * @return Extension header id\n     */\n    public int getExtensionId() {\n        return mExtensionId;\n    }\n\n    /**\n     * Verifies if is a valid SDP Orientation header\n     * \n     * @return <code>True</code> if is a valid header, <code>false</code> otherwise.\n     */\n    public boolean isValid() {\n        return (mExtensionId >= MIN_ID_VALUE && mExtensionId <= MAX_ID_VALUE)\n                && VIDEO_ORIENTATION_URI.equalsIgnoreCase(mUri);\n    }\n\n    /**\n     * Creates a {@link SdpOrientationExtension} from the \"extmap\" media attribute\n     * \n     * @param mediaAttribute Extmap media attribute\n     * @return A SdpOrientationExtension.\n     * @throws RuntimeException if attribute is invalid.\n     */\n    public static SdpOrientationExtension create(MediaAttribute mediaAttribute) {\n        if (mediaAttribute == null || mediaAttribute.getValue() == null) {\n            throw new RuntimeException(\"Invalid media attribute\");\n        }\n        String[] values = mediaAttribute.getValue().split(\" \");\n        return new SdpOrientationExtension(Integer.parseInt(values[0].trim()), values[1].trim());\n    }\n\n    /**\n     * Creates a {@link SdpOrientationExtension} from the Video MediaDescription\n     * \n     * @param videoMediaDescription Video media description\n     * @return A new SdpOrientationExtension or null if invalid media description\n     * @throws RuntimeException if videoMediaDescription is invalid.\n     */\n    public static SdpOrientationExtension create(MediaDescription videoMediaDescription) {\n        return SdpOrientationExtension.create(videoMediaDescription\n                .getMediaAttribute(VideoSdpBuilder.ATTRIBUTE_EXTENSION));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/TerminatingVideoStreamingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\n\nimport android.os.RemoteException;\n\nimport java.util.Collection;\nimport java.util.Vector;\n\n/**\n * Terminating live video content sharing session (streaming)\n * \n * @author Jean-Marc AUFFRET\n */\npublic class TerminatingVideoStreamingSession extends VideoStreamingSession {\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingVideoStreamingSession.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param invite Initial INVITE request\n     * @param contact Contact Id\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     * @param capabilityService\n     */\n    public TerminatingVideoStreamingSession(RichcallService parent, SipRequest invite,\n            ContactId contact, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, CapabilityService capabilityService) {\n        super(parent, ContentManager.createLiveVideoContentFromSdp(invite.getContentBytes()),\n                contact, rcsSettings, timestamp, contactManager, capabilityService);\n        createTerminatingDialogPath(invite);\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new live video sharing session as terminating\");\n            }\n            SipDialogPath dialogPath = getDialogPath();\n            // Send a 180 Ringing response\n            send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n            // Parse the remote SDP part\n            SdpParser parser = new SdpParser(dialogPath.getRemoteContent().getBytes(UTF8));\n            MediaDescription mediaVideo = parser.getMediaDescription(\"video\");\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaVideo);\n            int remotePort = mediaVideo.mPort;\n\n            // Extract video codecs from SDP\n            Vector<MediaDescription> medias = parser.getMediaDescriptions(\"video\");\n            Vector<VideoCodec> proposedCodecs = VideoCodecManager.extractVideoCodecsFromSdp(medias);\n\n            // Notify listener\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            MmContent content = getContent();\n            long timestamp = getTimestamp();\n            for (ImsSessionListener listener : listeners) {\n                ((VideoStreamingSessionListener) listener).onInvitationReceived(contact, content,\n                        timestamp);\n            }\n\n            // Wait invitation answer\n            InvitationStatus answer = waitInvitationAnswer();\n            switch (answer) {\n                case INVITATION_REJECTED_DECLINE:\n                    /* Intentional fall through */\n                case INVITATION_REJECTED_BUSY_HERE:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected by user\");\n                    }\n                    sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_USER);\n                    }\n                    return;\n\n                case INVITATION_TIMEOUT:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected on timeout\");\n                    }\n\n                    // Ringing period timeout\n                    send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact,\n                                TerminationReason.TERMINATION_BY_TIMEOUT);\n                    }\n                    return;\n\n                case INVITATION_REJECTED_BY_SYSTEM:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been aborted by system\");\n                    }\n                    removeSession();\n                    return;\n\n                case INVITATION_CANCELED:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been rejected by remote\");\n                    }\n\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_REMOTE);\n                    }\n                    return;\n\n                case INVITATION_ACCEPTED:\n                    setSessionAccepted();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionAccepting(contact);\n                    }\n                    break;\n\n                case INVITATION_DELETED:\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Session has been deleted\");\n                    }\n                    removeSession();\n                    return;\n\n                default:\n                    throw new IllegalArgumentException(new StringBuilder(\n                            \"Unknown invitation answer in run; answer=\").append(answer).toString());\n            }\n\n            IVideoPlayer player = getPlayer();\n            // Check that a video player has been set\n            if (player == null) {\n                handleError(new ContentSharingError(\n                        ContentSharingError.MEDIA_PLAYER_NOT_INITIALIZED));\n                return;\n            }\n\n            // Codec negotiation\n            VideoCodec selectedVideoCodec = VideoCodecManager.negociateVideoCodec(\n                    player.getSupportedCodecs(), proposedCodecs);\n            if (selectedVideoCodec == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Proposed codecs are not supported\");\n                }\n\n                // Send a 415 Unsupported media type response\n                send415Error(dialogPath.getInvite());\n\n                // Unsupported media type\n                handleError(new ContentSharingError(ContentSharingError.UNSUPPORTED_MEDIA_TYPE));\n                return;\n            }\n\n            // Set the video player orientation\n            SdpOrientationExtension extensionHeader = SdpOrientationExtension.create(mediaVideo);\n            if (extensionHeader != null) {\n                // Update the orientation ID\n                setOrientation(extensionHeader.getExtensionId());\n            }\n\n            // Build SDP part\n            // Note ID_6_5 Extmap: it is recommended not to change the extmap's local\n            // identifier in the SDP answer from the one in the SDP offer because there\n            // are no reasons to do that since there should only be one extension in use.\n            String ipAddress = dialogPath.getSipStack().getLocalIpAddress();\n            String videoSdp = VideoSdpBuilder.buildSdpAnswer(selectedVideoCodec,\n                    player.getLocalRtpPort(), mediaVideo);\n            String sdp = SdpUtils.buildVideoSDP(ipAddress, videoSdp, SdpUtils.DIRECTION_RECVONLY);\n\n            // Set the local SDP part in the dialog path\n            dialogPath.setLocalContent(sdp);\n\n            // Test if the session should be interrupted\n            if (isInterrupted()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n\n            // Create a 200 OK response\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = SipMessageFactory.create200OkInviteResponse(dialogPath,\n                    RichcallService.FEATURE_TAGS_VIDEO_SHARE, sdp);\n\n            // The signalisation is established\n            dialogPath.setSigEstablished();\n\n            // Send response\n            SipTransactionContext ctx = getImsService().getImsModule().getSipManager()\n                    .sendSipMessageAndWait(resp);\n\n            // Analyze the received response\n            if (ctx.isSipAck()) {\n                // ACK received\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"ACK request received\");\n                }\n\n                // The session is established\n                dialogPath.setSessionEstablished();\n\n                // Start session timer\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n\n                // Set the video player remote info\n                player.setRemoteInfo(selectedVideoCodec, remoteHost, remotePort, getOrientation());\n\n                for (ImsSessionListener listener : listeners) {\n                    listener.onSessionStarted(contact);\n                }\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n\n                // No response received: timeout\n                handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED));\n            }\n\n        } catch (RemoteException e) {\n            sLogger.error(\"Failed to set remote info!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to send 200OK response!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new ContentSharingError(ContentSharingError.SEND_RESPONSE_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed initiate a new live video sharing session as terminating!\", e);\n            handleError(new ContentSharingError(ContentSharingError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    /**\n     * Handle error\n     * \n     * @param error Error\n     */\n    public void handleError(ContentSharingError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Session error: \")\n                    .append(String.valueOf(error.getErrorCode())).append(\", reason=\")\n                    .append(error.getMessage()).toString());\n        }\n        closeMediaSession();\n        removeSession();\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((VideoStreamingSessionListener) listener).onSharingError(contact, error);\n        }\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public void closeMediaSession() {\n        /* Nothing to do in case of external codec */\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/VideoCodecManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport java.util.Vector;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\n\n/**\n * Video codec management\n * \n * @author hlxn7157\n */\npublic class VideoCodecManager {\n\n    /**\n     * Video codec negotiation\n     * \n     * @param supportedCodecs List of supported media codecs\n     * @param proposedCodecs List of proposed video codecs\n     * @return Selected codec or null if no codec supported\n     */\n    public static VideoCodec negociateVideoCodec(VideoCodec[] supportedCodecs,\n            Vector<VideoCodec> proposedCodecs) {\n        VideoCodec selectedCodec = null;\n        int pref = -1;\n        for (VideoCodec proposedCodec : proposedCodecs) {\n            for (int j = 0; j < supportedCodecs.length; j++) {\n                VideoCodec videoCodec = supportedCodecs[j];\n                int videoCodecPref = supportedCodecs.length - 1 - j;\n                // Compare codec\n                if (!compareVideoCodec(proposedCodec, videoCodec)) {\n                    continue;\n                }\n                if (videoCodecPref <= pref) {\n                    continue;\n                }\n                pref = videoCodecPref;\n                int proposedCodecWidth = proposedCodec.getWidth();\n                int width = (proposedCodecWidth == 0) ? videoCodec.getWidth() : proposedCodecWidth;\n                int proposedCodectHeight = proposedCodec.getHeight();\n                int height = (proposedCodectHeight == 0) ? videoCodec.getHeight()\n                        : proposedCodectHeight;\n                int proposedCodecPayloadType = proposedCodec.getPayloadType();\n                int payloadType = (proposedCodecPayloadType == 0) ? videoCodec.getPayloadType()\n                        : proposedCodecPayloadType;\n                int proposedCodecClockRate = proposedCodec.getClockRate();\n                int clockRate = (proposedCodecClockRate == 0) ? videoCodec.getClockRate()\n                        : proposedCodecClockRate;\n                int proposedCodecFrameRate = proposedCodec.getFrameRate();\n                int frameRate = (proposedCodecFrameRate == 0) ? videoCodec.getFrameRate()\n                        : proposedCodecFrameRate;\n                int proposedCodecBitRate = proposedCodec.getBitRate();\n                int bitRate = (proposedCodecBitRate == 0) ? videoCodec.getBitRate()\n                        : proposedCodecBitRate;\n                String proposedCodecParameters = proposedCodec.getParameters();\n\n                selectedCodec = new VideoCodec(proposedCodec.getEncoding(), payloadType, clockRate,\n                        frameRate, bitRate, width, height,\n                        (proposedCodecParameters.length() == 0) ? videoCodec.getParameters()\n                                : proposedCodecParameters);\n            }\n        }\n        return selectedCodec;\n    }\n\n    /**\n     * Compare two video codecs\n     * \n     * @param codec1 Video codec 1\n     * @param codec2 Video codec 2\n     * @return boolean\n     */\n    private static boolean compareVideoCodec(VideoCodec codec1, VideoCodec codec2) {\n        if (codec1.getEncoding().equalsIgnoreCase(codec2.getEncoding())\n                && (codec1.getWidth() == codec2.getWidth() || codec1.getWidth() == 0 || codec2\n                        .getWidth() == 0)\n                && (codec1.getHeight() == codec2.getHeight() || codec1.getHeight() == 0 || codec2\n                        .getHeight() == 0)) {\n            if (codec1.getEncoding().equalsIgnoreCase(H264Config.CODEC_NAME)) {\n                if (H264Config.getCodecProfileLevelId(codec1.getParameters()).compareToIgnoreCase(\n                        H264Config.getCodecProfileLevelId(codec2.getParameters())) == 0) {\n                    return true;\n                }\n            } else {\n                if (codec1.getParameters().equalsIgnoreCase(codec2.getParameters())) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Create a video codec from its SDP description\n     * \n     * @param media Media SDP description\n     * @return Video codec\n     */\n    public static VideoCodec createVideoCodecFromSdp(MediaDescription media) {\n        String rtpmap = media.getMediaAttribute(\"rtpmap\").getValue();\n\n        // Extract encoding name\n        String encoding = rtpmap.substring(\n                rtpmap.indexOf(media.mPayload) + media.mPayload.length() + 1).trim();\n        String codecName = encoding;\n\n        // Extract clock rate\n        int clockRate = 0;\n        int index = encoding.indexOf(\"/\");\n        if (index != -1) {\n            codecName = encoding.substring(0, index);\n            clockRate = Integer.parseInt(encoding.substring(index + 1));\n        }\n\n        // Extract video size\n        MediaAttribute frameSize = media.getMediaAttribute(\"framesize\");\n        int videoWidth = 0;\n        int videoHeight = 0;\n        if (frameSize != null) {\n            try {\n                String value = frameSize.getValue();\n                index = value.indexOf(media.mPayload);\n                int separator = value.indexOf('-');\n                if ((index != -1) && (separator != -1)) {\n                    videoWidth = Integer.parseInt(value.substring(index + media.mPayload.length()\n                            + 1, separator));\n                    videoHeight = Integer.parseInt(value.substring(separator + 1));\n                }\n            } catch (NumberFormatException e) {\n                // Use default value\n            }\n        }\n\n        // Extract frame rate\n        MediaAttribute attr = media.getMediaAttribute(\"framerate\");\n        int frameRate = 0;\n        if (attr != null) {\n            try {\n                String value = attr.getValue();\n                index = value.indexOf(media.mPayload);\n                if ((index != -1) && (value.length() > media.mPayload.length())) {\n                    frameRate = Integer.parseInt(value.substring(index + media.mPayload.length()\n                            + 1));\n                } else {\n                    frameRate = Integer.parseInt(value);\n                }\n            } catch (NumberFormatException e) {\n                // Use default value\n                frameRate = H264Config.FRAME_RATE;\n            }\n        }\n\n        // Extract the video codec parameters.\n        MediaAttribute fmtp = media.getMediaAttribute(\"fmtp\");\n        String codecParameters = \"\";\n        if (fmtp != null) {\n            String value = fmtp.getValue();\n            index = 0; // value.indexOf(media.payload);\n            if ((index != -1) && (value.length() > media.mPayload.length())) {\n                codecParameters = value.substring(index + media.mPayload.length() + 1);\n            }\n        }\n\n        // Create a video codec\n        VideoCodec videoCodec = new VideoCodec(codecName, Integer.parseInt(media.mPayload),\n                clockRate, frameRate, 0, videoWidth, videoHeight, codecParameters);\n\n        return videoCodec;\n    }\n\n    /**\n     * Extract list of video codecs from SDP part\n     * \n     * @param medias\n     * @return List of video codecs\n     */\n    public static Vector<VideoCodec> extractVideoCodecsFromSdp(Vector<MediaDescription> medias) {\n        Vector<VideoCodec> codecs = new Vector<>();\n        for (MediaDescription media : medias) {\n            VideoCodec codec = createVideoCodecFromSdp(media);\n            if (codec != null) {\n                codecs.add(codec);\n            }\n        }\n        return codecs;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/VideoSdpBuilder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.rtp.RtpUtils;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\n\n/**\n * Builds the Video SDP\n * \n * @author Deutsche Telekom\n */\npublic class VideoSdpBuilder {\n\n    /**\n     * Extension attribute name, RFC5285\n     */\n    public static final String ATTRIBUTE_EXTENSION = \"extmap\";\n\n    /**\n     * Build SDP offer without the orientation extension ordered by the preferred codec\n     * \n     * @param supportedCodecs Codecs to create SDP\n     * @param localRtpPort Local RTP port\n     * @return SDP offer\n     */\n    public static String buildSdpOfferWithoutOrientation(VideoCodec[] supportedCodecs,\n            int localRtpPort) {\n        // Create video codec list\n        List<VideoCodec> codecs = new ArrayList<VideoCodec>(Arrays.asList(supportedCodecs));\n\n        StringBuilder result = new StringBuilder(\"m=video \").append(localRtpPort)\n                .append(\" RTP/AVP\");\n        for (VideoCodec codec : codecs) {\n            result.append(\" \").append(codec.getPayloadType());\n        }\n        result.append(SipUtils.CRLF);\n        int framerate = 0;\n        for (VideoCodec codec : codecs) {\n            int codeFrameRate = codec.getFrameRate();\n            if (codeFrameRate > framerate) {\n                framerate = codeFrameRate;\n            }\n        }\n        if (framerate > 0) {\n            result.append(\"a=framerate:\").append(framerate).append(SipUtils.CRLF);\n        }\n        for (VideoCodec codec : codecs) {\n            int payloadType = codec.getPayloadType();\n            result.append(\"a=rtpmap:\").append(payloadType).append(\" \").append(codec.getEncoding())\n                    .append(\"/\").append(codec.getClockRate()).append(SipUtils.CRLF);\n            int width = codec.getWidth();\n            int height = codec.getHeight();\n            if (width != 0 && height != 0) {\n                result.append(\"a=framesize:\").append(payloadType).append(\" \").append(width)\n                        .append(\"-\").append(height).append(SipUtils.CRLF);\n            }\n            result.append(\"a=fmtp:\").append(payloadType).append(\" \").append(codec.getParameters())\n                    .append(SipUtils.CRLF);\n        }\n\n        return result.toString();\n    }\n\n    /**\n     * Build SDP offer without the orientation extension ordered by the preferred codec\n     * \n     * @param supportedCodecs Codecs to create SDP\n     * @param localRtpPort Local RTP port\n     * @return SDP offer\n     */\n    public static String buildSdpOfferWithOrientation(VideoCodec[] supportedCodecs, int localRtpPort) {\n        StringBuilder sdp = new StringBuilder(buildSdpOfferWithoutOrientation(supportedCodecs,\n                localRtpPort)).append(\"a=\").append(ATTRIBUTE_EXTENSION).append(':')\n                .append(RtpUtils.RTP_DEFAULT_EXTENSION_ID).append(\" \")\n                .append(SdpOrientationExtension.VIDEO_ORIENTATION_URI).append(SipUtils.CRLF);\n        return sdp.toString();\n    }\n\n    /**\n     * Create the SDP part for a given codec\n     * \n     * @param codec Media codec\n     * @param localRtpPort Local RTP port\n     * @return SDP\n     */\n    private static String buildSdpWithoutOrientation(VideoCodec videoCodec, int localRtpPort) {\n        int payloadType = videoCodec.getPayloadType();\n        StringBuilder sdp = new StringBuilder(\"m=video \").append(localRtpPort).append(\" RTP/AVP \")\n                .append(payloadType).append(SipUtils.CRLF).append(\"a=rtpmap:\").append(payloadType)\n                .append(\" \").append(videoCodec.getEncoding()).append(\"/\")\n                .append(videoCodec.getClockRate()).append(SipUtils.CRLF);\n        int width = videoCodec.getWidth();\n        int height = videoCodec.getHeight();\n        if (width != 0 && height != 0) {\n            sdp.append(\"a=framesize:\").append(payloadType).append(\" \").append(width).append(\"-\")\n                    .append(height).append(SipUtils.CRLF);\n        }\n        int frameRate = videoCodec.getFrameRate();\n        if (frameRate != 0) {\n            sdp.append(\"a=framerate:\").append(frameRate).append(SipUtils.CRLF);\n        }\n        sdp.append(\"a=fmtp:\").append(frameRate).append(\" \").append(videoCodec.getParameters())\n                .append(SipUtils.CRLF);\n        return sdp.toString();\n    }\n\n    /**\n     * Create the SDP part with orientation extension for a given codec\n     * \n     * @param codec Media Codec\n     * @param localRtpPort Local RTP Port\n     * @param extensionId\n     * @return SDP\n     */\n    private static String buildSdpWithOrientationExtension(VideoCodec codec, int localRtpPort,\n            int extensionId) {\n        StringBuilder sdp = new StringBuilder(buildSdpWithoutOrientation(codec, localRtpPort))\n                .append(\"a=\").append(ATTRIBUTE_EXTENSION).append(':').append(extensionId)\n                .append(\" \").append(SdpOrientationExtension.VIDEO_ORIENTATION_URI)\n                .append(SipUtils.CRLF);\n        return sdp.toString();\n    }\n\n    /**\n     * Builds the SDP for a SIP INVITE response. If the SIP INVITE SDP doesn't have the orientation\n     * extension then the response SDP also shouldn't have.\n     * \n     * @param codec Media Codec\n     * @param localRtpPort Local RTP Port\n     * @param inviteVideoMedia\n     * @return SDP answer\n     */\n    public static String buildSdpAnswer(VideoCodec codec, int localRtpPort,\n            MediaDescription inviteVideoMedia) {\n        if (inviteVideoMedia != null) {\n            SdpOrientationExtension extension = SdpOrientationExtension.create(inviteVideoMedia);\n            if (extension != null) {\n                return buildSdpWithOrientationExtension(codec, localRtpPort,\n                        extension.getExtensionId());\n            }\n        }\n\n        return buildSdpWithoutOrientation(codec, localRtpPort);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/VideoStreamingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingSession;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\n\n/**\n * Video sharing streaming session\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class VideoStreamingSession extends ContentSharingSession {\n\n    private int mOrientation;\n\n    private int mWidth;\n\n    private int mHeight;\n\n    private IVideoPlayer mPlayer;\n\n    private final static Logger sLogger = Logger.getLogger(VideoStreamingSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent Richcall service\n     * @param content Content to be shared\n     * @param contact Remote contact Id\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     * @param capabilityService\n     */\n    public VideoStreamingSession(RichcallService parent, MmContent content, ContactId contact,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager,\n            CapabilityService capabilityService) {\n        super(parent, content, contact, rcsSettings, timestamp, contactManager, capabilityService);\n    }\n\n    /**\n     * Get the video orientation ID\n     * \n     * @return Orientation\n     */\n    public int getOrientation() {\n        return mOrientation;\n    }\n\n    /**\n     * Set the video orientation ID\n     * \n     * @param orientation\n     */\n    public void setOrientation(int orientation) {\n        mOrientation = orientation;\n    }\n\n    /**\n     * Get the video width\n     * \n     * @return Width\n     */\n    public int getWidth() {\n        return mWidth;\n    }\n\n    /**\n     * Get the video height\n     * \n     * @return Height\n     */\n    public int getHeight() {\n        return mHeight;\n    }\n\n    /**\n     * Get the video player\n     * \n     * @return Player\n     */\n    public IVideoPlayer getPlayer() {\n        return mPlayer;\n    }\n\n    /**\n     * Set the video player\n     * \n     * @param player\n     */\n    public void setPlayer(IVideoPlayer player) {\n        mPlayer = player;\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return the INVITE request\n     * @throws PayloadException\n     */\n    public SipRequest createInvite() throws PayloadException {\n        return SipMessageFactory.createInvite(getDialogPath(),\n                RichcallService.FEATURE_TAGS_VIDEO_SHARE, getDialogPath().getLocalContent());\n    }\n\n    @Override\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Session error: \").append(error.getErrorCode())\n                    .append(\", reason=\").append(error.getMessage()).toString());\n        }\n        closeMediaSession();\n        removeSession();\n        ContactId contact = getRemoteContact();\n        mCapabilityService.requestContactCapabilities(contact);\n        for (ImsSessionListener imsSessionListener : getListeners()) {\n            ((VideoStreamingSessionListener) imsSessionListener).onSharingError(contact,\n                    new ContentSharingError(error));\n        }\n    }\n\n    @Override\n    public void handleInactivityEvent() {\n        /* Not need in this class */\n    }\n\n    @Override\n    public void startSession() {\n        mRichcallService.addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        mRichcallService.removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/richcall/video/VideoStreamingSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.richcall.video;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Content sharing streaming session listener\n * \n * @author jexa7410\n */\npublic interface VideoStreamingSessionListener extends ImsSessionListener {\n    /**\n     * Content sharing error\n     * \n     * @param contact Remote contact\n     * @param error Error\n     */\n    public void onSharingError(ContactId contact, ContentSharingError error);\n\n    /**\n     * Destination user agent received INVITE, and is alerting user of call\n     * \n     * @param contact Remote contact\n     */\n    public void onSessionRinging(ContactId contact);\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     * @param content\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void onInvitationReceived(ContactId contact, MmContent content, long timestamp);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/EnrichCallingService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip;\n\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\n\n/**\n * Enrich calling service implemented on top of the MM session service\n *\n * @author jmauffret\n */\npublic class EnrichCallingService {\n    /**\n     * Call composer service ID\n     */\n    public final static String CALL_COMPOSER_SERVICE_ID = \"gsma.callcomposer\";\n\n    /**\n     * Shared map service ID\n     */\n    public final static String SHARED_MAP_SERVICE_ID = \"gsma.sharedmap\";\n\n    /**\n     * Shared sketch service ID\n     */\n    public final static String SHARED_SKETCH_SERVICE_ID = \"gsma.sharedsketch\";\n\n    /**\n     * Post call service ID\n     */\n    public final static String POST_CALL_SERVICE_ID = \"gsma.callunanswered\";\n\n    /**\n     * Call composer feature tag\n     */\n    public final static String CALL_COMPOSER_FEATURE_TAG = FeatureTags.FEATURE_RCSE + \"=\\\"\"\n            + FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".\" + CALL_COMPOSER_SERVICE_ID + \"\\\"\";\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/GenericSipSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport gov2.nist.javax2.sip.header.ims.PPreferredServiceHeader;\n\nimport java.text.ParseException;\nimport java.util.Set;\n\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n * Abstract generic SIP session\n * \n * @author jexa7410\n */\npublic abstract class GenericSipSession extends ImsServiceSession {\n\n    private final String mFeatureTag;\n\n    private final SipService mSipService;\n\n    private static final Logger sLogger = Logger.getLogger(GenericSipSession.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent SIP service\n     * @param contact Remote contactId\n     * @param featureTag Feature tag\n     * @param rcsSettings RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager accessor\n     */\n    public GenericSipSession(SipService parent, ContactId contact, String featureTag,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager) {\n        super(parent, contact, PhoneUtils.formatContactIdToUri(contact), rcsSettings, timestamp,\n                contactManager);\n        mSipService = parent;\n        mFeatureTag = featureTag;\n    }\n\n    /**\n     * Returns feature tag of the service\n     * \n     * @return Feature tag\n     */\n    public String getFeatureTag() {\n        return mFeatureTag;\n    }\n\n    /**\n     * Returns the service ID\n     * \n     * @return Service ID\n     */\n    public String getServiceId() {\n        return CapabilityUtils.extractServiceId(mFeatureTag);\n    }\n\n    /**\n     * Create an INVITE request\n     * \n     * @return Request\n     * @throws PayloadException\n     */\n    public SipRequest createInvite() throws PayloadException {\n        String ext = FeatureTags.FEATURE_3GPP + \"=\\\"\" + FeatureTags.FEATURE_3GPP_EXTENSION + \"\\\"\";\n        SipRequest invite = SipMessageFactory.createInvite(getDialogPath(), new String[] {\n                getFeatureTag(), ext\n        }, new String[] {\n                getFeatureTag(), ext, SipUtils.EXPLICIT_REQUIRE\n        }, getDialogPath().getLocalContent());\n\n        try {\n            ExtensionHeader header = (ExtensionHeader) SipUtils.HEADER_FACTORY.createHeader(\n                    PPreferredServiceHeader.NAME, FeatureTags.FEATURE_3GPP_SERVICE_EXTENSION);\n            invite.getStackMessage().addHeader(header);\n\n        } catch (ParseException e) {\n            throw new PayloadException(\n                    \"Can't add SIP headertype \".concat(FeatureTags.FEATURE_3GPP_SERVICE_EXTENSION),\n                    e);\n        }\n\n        return invite;\n    }\n\n    /**\n     * Create 200 OK response\n     * \n     * @return Response\n     * @throws PayloadException\n     */\n    public SipResponse create200OKResponse() throws PayloadException {\n        String ext = FeatureTags.FEATURE_3GPP + \"=\\\"\" + FeatureTags.FEATURE_3GPP_EXTENSION + \"\\\"\";\n        return SipMessageFactory.create200OkInviteResponse(getDialogPath(), new String[] {\n                getFeatureTag(), ext\n        }, new String[] {\n                getFeatureTag(), ext, SipUtils.EXPLICIT_REQUIRE\n        }, getDialogPath().getLocalContent());\n    }\n\n    /**\n     * Prepare media session\n     * \n     * @throws NetworkException\n     */\n    public abstract void prepareMediaSession() throws NetworkException;\n\n    /**\n     * Start media transfer\n     */\n    public abstract void startMediaTransfer();\n\n    /**\n     * Close media session\n     */\n    public abstract void closeMediaSession();\n\n    @Override\n    public void handleError(ImsServiceError error) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        sLogger.error(\"Session error: \" + error.getErrorCode() + \", reason=\" + error.getMessage());\n        closeMediaSession();\n        removeSession();\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onSessionError(contact, new SipSessionError(error));\n        }\n    }\n\n    @Override\n    public void receiveBye(SipRequest bye) throws PayloadException, NetworkException {\n        super.receiveBye(bye);\n        ContactId remote = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            listener.onSessionAborted(remote, TerminationReason.TERMINATION_BY_REMOTE);\n        }\n        getImsService().getImsModule().getCapabilityService().requestContactCapabilities(remote);\n    }\n\n    @Override\n    public void receiveCancel(SipRequest cancel) throws NetworkException, PayloadException {\n        super.receiveCancel(cancel);\n        // Request capabilities to the remote\n        getImsService().getImsModule().getCapabilityService()\n                .requestContactCapabilities(getRemoteContact());\n    }\n\n    /**\n     * Gets the IARI feature tag from the set of feature tags\n     * \n     * @param featureTags The set of feature tags\n     * @return the IARI feature tag or null\n     */\n    public static String getIariFeatureTag(Set<String> featureTags) {\n        for (String tag : featureTags) {\n            if (tag.startsWith(FeatureTags.FEATURE_RCSE)) {\n                return tag;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Gets SIP service\n     * \n     * @return SIP service\n     */\n    public SipService getSipService() {\n        return mSipService;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/ImmManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipManager;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipInterface;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.FifoBuffer;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * Instant Multimedia Message manager\n *\n * @author jexa7410\n */\npublic class ImmManager extends Thread {\n\n    private final SipService mSipService;\n\n    private FifoBuffer mBuffer = new FifoBuffer();\n\n    private final RcsSettings mRcsSettings;\n\n    private final static Logger sLogger = Logger.getLogger(ImmManager.class.getSimpleName());\n\n    /**\n     * Constructor\n     *\n     * @param sipService SIP service\n     * @param rcsSettings RCS settings\n     */\n    public ImmManager(SipService sipService, RcsSettings rcsSettings) {\n        mSipService = sipService;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Terminate manager\n     */\n    public void terminate() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Terminate the IMM manager\");\n        }\n        mBuffer.close();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        InstantMultimediaMessage msg;\n        while ((msg = (InstantMultimediaMessage) mBuffer.getObject()) != null) {\n            try {\n                sendSipMessage(msg, null);// TODO: add sip.instance\n\n            } catch (PayloadException | RuntimeException e) {\n                sLogger.error(\"Failed to send instant multimedia message\", e);\n\n            } catch (NetworkException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n            }\n        }\n    }\n\n    /**\n     * Send a multimedia message\n     *\n     * @param remote Remote contact\n     * @param featureTag Feature tag\n     * @param content Message content\n     * @param contentType Message content type\n     */\n    public void sendMessage(ContactId remote, String featureTag, byte[] content, String contentType) {\n        // Add request in the buffer for background processing\n        InstantMultimediaMessage msg = new InstantMultimediaMessage(remote, featureTag, content,\n                contentType);\n        mBuffer.addObject(msg);\n    }\n\n    private void analyzeSipResponse(SipTransactionContext ctx,\n            SessionAuthenticationAgent authenticationAgent, SipDialogPath dialogPath,\n            InstantMultimediaMessage imm) throws NetworkException, PayloadException,\n            InvalidArgumentException, ParseException {\n        int statusCode = ctx.getStatusCode();\n        switch (statusCode) {\n            case Response.PROXY_AUTHENTICATION_REQUIRED:\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"407 response received\");\n                }\n\n                /* Set the Proxy-Authorization header */\n                authenticationAgent.readProxyAuthenticateHeader(ctx.getSipResponse());\n\n                /* Increment the Cseq number of the dialog path */\n                dialogPath.incrementCseq();\n\n                /* Create a second MESSAGE request with the right token */\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Send second MESSAGE\");\n                }\n                SipRequest msg = SipMessageFactory.createMessage(dialogPath, imm.getFeatureTag(),\n                        imm.getContentType(), imm.getContent());\n\n                /* Set the Authorization header */\n                authenticationAgent.setProxyAuthorizationHeader(msg);\n\n                ctx = mSipService.getImsModule().getSipManager().sendSipMessageAndWait(msg);\n\n                analyzeSipResponse(ctx, authenticationAgent, dialogPath, imm);\n                break;\n\n            case Response.OK:\n            case Response.ACCEPTED:\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"20x OK response received\");\n                }\n                break;\n            default:\n                throw new NetworkException(\"Instant multimedia message has failed: \" + statusCode\n                        + \" response received\");\n        }\n    }\n\n    private void sendSipMessage(InstantMultimediaMessage imm, String remoteInstanceId)\n            throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Send instant multimedia message\");\n            }\n            ImsModule imsModule = mSipService.getImsModule();\n            // Create authentication agent\n            SessionAuthenticationAgent authenticationAgent = new SessionAuthenticationAgent(\n                    imsModule);\n            // @FIXME: This should be an URI instead of String\n            String toUri = PhoneUtils.formatContactIdToUri(imm.getRemote()).toString();\n            SipManager sipManager = imsModule.getSipManager();\n            SipInterface sipInterface = sipManager.getSipStack();\n            // Create a dialog path\n            SipDialogPath dialogPath = new SipDialogPath(sipInterface,\n                    sipInterface.generateCallId(), 1, toUri, ImsModule.getImsUserProfile()\n                            .getPublicUri(), toUri, sipInterface.getServiceRoutePath(),\n                    mRcsSettings);\n            dialogPath.setRemoteSipInstance(remoteInstanceId);\n\n            // Create MESSAGE request\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send first MESSAGE\");\n            }\n            SipRequest msg = SipMessageFactory.createMessage(dialogPath, imm.getFeatureTag(),\n                    imm.getContentType(), imm.getContent());\n            SipTransactionContext ctx = sipManager.sendSipMessageAndWait(msg);\n            analyzeSipResponse(ctx, authenticationAgent, dialogPath, imm);\n\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"Unable to set authorization header for remoteInstanceId: \"\n                    + remoteInstanceId, e);\n        }\n    }\n\n    /**\n     * Instant multimedia message\n     */\n    private static class InstantMultimediaMessage {\n        private final ContactId mRemote;\n        private final String mFeatureTag;\n        private final byte[] mContent;\n        private final String mContentType;\n\n        public InstantMultimediaMessage(ContactId remote, String featureTag, byte[] content,\n                String contentType) {\n            mRemote = remote;\n            mFeatureTag = featureTag;\n            mContent = content;\n            mContentType = contentType;\n        }\n\n        public ContactId getRemote() {\n            return mRemote;\n        }\n\n        public String getFeatureTag() {\n            return mFeatureTag;\n        }\n\n        public byte[] getContent() {\n            return mContent;\n        }\n\n        public String getContentType() {\n            return mContentType;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/SipService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityUtils;\nimport com.gsma.rcs.core.ims.service.sip.messaging.GenericSipMsrpSession;\nimport com.gsma.rcs.core.ims.service.sip.messaging.OriginatingSipMsrpSession;\nimport com.gsma.rcs.core.ims.service.sip.messaging.TerminatingSipMsrpSession;\nimport com.gsma.rcs.core.ims.service.sip.streaming.GenericSipRtpSession;\nimport com.gsma.rcs.core.ims.service.sip.streaming.OriginatingSipRtpSession;\nimport com.gsma.rcs.core.ims.service.sip.streaming.TerminatingSipRtpSession;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.api.MultimediaSessionServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\nimport android.os.Handler;\nimport android.os.HandlerThread;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\nimport javax2.sip.message.Response;\n\n/**\n * SIP service\n * \n * @author Jean-Marc AUFFRET\n */\npublic class SipService extends ImsService {\n\n    private static final String MM_MESSAGING_OPERATION_THREAD_NAME = \"MmmOperations\";\n\n    private static final String MM_STREAMING_OPERATION_THREAD_NAME = \"MmsOperations\";\n\n    private static final String MM_INSTANT_MESSAGE_OPERATION_THREAD_NAME = \"ImmOperations\";\n\n    private final static Logger sLogger = Logger.getLogger(SipService.class.getSimpleName());\n\n    /**\n     * Default MIME-type for multimedia services\n     */\n    public final static String DEFAULT_MIME_TYPE = \"application/*\";\n\n    /**\n     * GenericSipMsrpSessionCache with SessionId as key\n     */\n    private Map<String, GenericSipMsrpSession> mGenericSipMsrpSessionCache = new HashMap<>();\n\n    /**\n     * GenericSipRtpSessionCache with SessionId as key\n     */\n    private Map<String, GenericSipRtpSession> mGenericSipRtpSessionCache = new HashMap<>();\n\n    private final ContactManager mContactManager;\n\n    private final RcsSettings mRcsSettings;\n\n    private ImmManager mImmManager;\n\n    private MultimediaSessionServiceImpl mMmSessionService;\n\n    private final Handler mMultimediaMessagingOperationHandler;\n    private final Handler mMultimediaStreamingOperationHandler;\n    private final Handler mMultimediaMessageOperationHandler;\n\n    /**\n     * Constructor\n     *\n     * @param parent IMS module\n     * @param contactManager ContactManager\n     * @param rcsSettings the RCS settings accessor\n     */\n    public SipService(ImsModule parent, ContactManager contactManager, RcsSettings rcsSettings) {\n        super(parent, true);\n        mContactManager = contactManager;\n        mRcsSettings = rcsSettings;\n        mMultimediaMessagingOperationHandler = allocateBgHandler(MM_MESSAGING_OPERATION_THREAD_NAME);\n        mMultimediaStreamingOperationHandler = allocateBgHandler(MM_STREAMING_OPERATION_THREAD_NAME);\n        mMultimediaMessageOperationHandler = allocateBgHandler(MM_INSTANT_MESSAGE_OPERATION_THREAD_NAME);\n    }\n\n    private Handler allocateBgHandler(String threadName) {\n        HandlerThread thread = new HandlerThread(threadName);\n        thread.start();\n        return new Handler(thread.getLooper());\n    }\n\n    public void register(MultimediaSessionServiceImpl service) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(service.getClass().getName() + \" registered ok.\");\n        }\n        mMmSessionService = service;\n    }\n\n    public void scheduleMultimediaMessagingOperation(Runnable runnable) {\n        mMultimediaMessagingOperationHandler.post(runnable);\n    }\n\n    public void scheduleMultimediaStreamingOperation(Runnable runnable) {\n        mMultimediaStreamingOperationHandler.post(runnable);\n    }\n\n    public void scheduleMultimediaMessageOperation(Runnable runnable) {\n        mMultimediaMessageOperationHandler.post(runnable);\n    }\n\n    @Override\n    public synchronized void start() {\n        if (isServiceStarted()) {\n            // Already started\n            return;\n        }\n        setServiceStarted(true);\n        mImmManager = new ImmManager(this, mRcsSettings);\n        mImmManager.start();\n    }\n\n    @Override\n    public synchronized void stop(ImsServiceSession.TerminationReason reasonCode) {\n        if (!isServiceStarted()) {\n            // Already stopped\n            return;\n        }\n        setServiceStarted(false);\n        mImmManager.terminate();\n        mImmManager = null;\n        if (ImsServiceSession.TerminationReason.TERMINATION_BY_SYSTEM == reasonCode) {\n            mMultimediaMessagingOperationHandler.getLooper().quit();\n            mMultimediaStreamingOperationHandler.getLooper().quit();\n            mMultimediaMessageOperationHandler.getLooper().quit();\n        }\n    }\n\n    @Override\n    public void check() {\n    }\n\n    /**\n     * Initiate a MSRP session\n     *\n     * @param contact Remote contact Id\n     * @param featureTag Feature tag of the service\n     * @param acceptTypes Accept-types related to exchanged messages\n     * @param acceptWrappedTypes Accept-wrapped-types related to exchanged messages\n     * @return SIP session\n     */\n    public GenericSipMsrpSession createMsrpSession(ContactId contact, String featureTag,\n            String[] acceptTypes, String[] acceptWrappedTypes) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a MSRP session with contact \" + contact);\n        }\n        return new OriginatingSipMsrpSession(this, contact, featureTag, mRcsSettings,\n                System.currentTimeMillis(), mContactManager, acceptTypes, acceptWrappedTypes);\n    }\n\n    /**\n     * Receive a session invitation with MSRP media\n     *\n     * @param sessionInvite Resolved intent\n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onMsrpSessionInvitationReceived(final Intent sessionInvite, SipRequest invite,\n            long timestamp) {\n        try {\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(SipUtils\n                    .getAssertedIdentity(invite));\n            if (number == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Cannot process MSRP invitation: invalid SIP header\");\n                }\n                sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                return;\n            }\n            // Test if the contact is blocked\n            ContactId remote = ContactUtil.createContactIdFromValidatedData(number);\n            mContactManager\n                    .setContactDisplayName(remote, SipUtils.getDisplayNameFromInvite(invite));\n            if (mContactManager.isBlockedForContact(remote)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Contact \" + remote\n                            + \" is blocked: automatically reject the session invitation\");\n                }\n                sendErrorResponse(invite, Response.DECLINE);\n                return;\n            }\n            final TerminatingSipMsrpSession session = new TerminatingSipMsrpSession(this, invite,\n                    getImsModule(), remote, sessionInvite, mRcsSettings, timestamp, mContactManager);\n            mMultimediaMessagingOperationHandler.post(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n                        mMmSessionService.receiveSipMsrpSessionInvitation(session);\n                        session.startSession();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed to receive generic MSRP session invitation!\", e);\n                    }\n                }\n            });\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to receive generic MSRP session invitation! (\"\n                        + e.getMessage() + \")\");\n            }\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to receive generic MSRP session invitation!\", e);\n        }\n    }\n\n    /**\n     * Initiate a RTP session\n     *\n     * @param contact Remote contact\n     * @param featureTag Feature tag of the service\n     * @param encoding Encoding\n     * @return SIP session\n     */\n    public GenericSipRtpSession createRtpSession(ContactId contact, String featureTag,\n            String encoding) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a RTP session with contact \" + contact);\n        }\n        return new OriginatingSipRtpSession(this, contact, featureTag, mRcsSettings,\n                System.currentTimeMillis(), mContactManager, encoding);\n    }\n\n    /**\n     * Receive a session invitation with RTP media\n     *\n     * @param sessionInvite Resolved intent\n     * @param invite Initial invite\n     * @param timestamp Local timestamp when got SipRequest\n     */\n    public void onRtpSessionInvitationReceived(final Intent sessionInvite, SipRequest invite,\n            long timestamp) {\n        try {\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(SipUtils\n                    .getAssertedIdentity(invite));\n            if (number == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Cannot process RTP invitation: invalid SIP header\");\n                }\n                sendErrorResponse(invite, Response.SESSION_NOT_ACCEPTABLE);\n                return;\n            }\n            // Test if the contact is blocked\n            ContactId remote = ContactUtil.createContactIdFromValidatedData(number);\n            mContactManager\n                    .setContactDisplayName(remote, SipUtils.getDisplayNameFromInvite(invite));\n            if (mContactManager.isBlockedForContact(remote)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Contact \" + remote\n                            + \" is blocked: automatically reject the session invitation\");\n                }\n                sendErrorResponse(invite, Response.DECLINE);\n                return;\n            }\n            final TerminatingSipRtpSession session = new TerminatingSipRtpSession(this, invite,\n                    getImsModule(), remote, sessionInvite, mRcsSettings, timestamp, mContactManager);\n            mMultimediaStreamingOperationHandler.post(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n                        mMmSessionService.receiveSipRtpSessionInvitation(session);\n                        session.startSession();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed to receive generic RTP session invitation!\", e);\n                    }\n                }\n            });\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to receive generic RTP session invitation! (\"\n                        + e.getMessage() + \")\");\n            }\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to receive generic RTP session invitation!\", e);\n        }\n    }\n\n    public void addSession(GenericSipMsrpSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add GenericSipMsrpSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGenericSipMsrpSessionCache.put(sessionId, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final GenericSipMsrpSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove GenericSipMsrpSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGenericSipMsrpSessionCache.remove(sessionId);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public GenericSipMsrpSession getGenericSipMsrpSession(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get GenericSipMsrpSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGenericSipMsrpSessionCache.get(sessionId);\n        }\n    }\n\n    public void addSession(GenericSipRtpSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add GenericSipRtpSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGenericSipRtpSessionCache.put(sessionId, session);\n            addImsServiceSession(session);\n        }\n    }\n\n    public void removeSession(final GenericSipRtpSession session) {\n        final String sessionId = session.getSessionID();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove GenericSipRtpSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            mGenericSipRtpSessionCache.remove(sessionId);\n            removeImsServiceSession(session);\n        }\n    }\n\n    public GenericSipRtpSession getGenericSipRtpSession(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Get GenericSipRtpSession with sessionId '\" + sessionId + \"'\");\n        }\n        synchronized (getImsServiceSessionOperationLock()) {\n            return mGenericSipRtpSessionCache.get(sessionId);\n        }\n    }\n\n    public void sendInstantMultimediaMessage(ContactId contact, String featureTag, byte[] content,\n            String contentType) throws NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send instant multimedia message to contact \" + contact);\n        }\n        if (mImmManager == null) {\n            throw new NetworkException(\"Cannot send multimedia message: SIP service not started!\");\n        }\n        mImmManager.sendMessage(contact, featureTag, content, contentType);\n    }\n\n    /**\n     * Receive a multimedia instant messsage\n     *\n     * @param intent Resolved intent\n     * @param message Instant message\n     */\n    public void onInstantMessageReceived(final Intent intent, final SipRequest message) {\n        try {\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(SipUtils\n                    .getAssertedIdentity(message));\n            if (number == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Cannot process instant message: invalid SIP header\");\n                }\n                sendErrorResponse(message, Response.SESSION_NOT_ACCEPTABLE);\n                return;\n            }\n            // Test if the contact is blocked\n            final ContactId remote = ContactUtil.createContactIdFromValidatedData(number);\n            mContactManager.setContactDisplayName(remote,\n                    SipUtils.getDisplayNameFromInvite(message));\n            if (mContactManager.isBlockedForContact(remote)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Contact \" + remote\n                            + \" is blocked: automatically reject the message\");\n                }\n                sendErrorResponse(message, Response.DECLINE);\n                return;\n            }\n            /* Send automatically a 200 Ok */\n            getImsModule().getSipManager().sendSipResponse(\n                    SipMessageFactory.createResponse(message, IdGenerator.getIdentifier(),\n                            Response.OK));\n            Set<String> featureTags = message.getFeatureTags();\n            String iariFeatureTag = GenericSipSession.getIariFeatureTag(featureTags);\n            if (iariFeatureTag == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Cannot process instant message: no service ID\");\n                }\n                sendErrorResponse(message, Response.SESSION_NOT_ACCEPTABLE);\n                return;\n            }\n            final String serviceId = CapabilityUtils.extractServiceId(iariFeatureTag);\n            mMultimediaMessageOperationHandler.post(new Runnable() {\n\n                @Override\n                public void run() {\n                    try {\n                        mMmSessionService.receiveSipInstantMessage(intent, remote,\n                                message.getRawContent(), message.getContentType(), serviceId);\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed to receive generic instant message!\", e);\n                    }\n                }\n            });\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to receive generic instant message! (\" + e.getMessage() + \")\");\n            }\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to receive instant message!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/SipSessionError.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip;\n\nimport com.gsma.rcs.core.ims.service.ImsServiceError;\nimport com.gsma.rcs.core.ims.service.ImsSessionBasedServiceError;\n\n/**\n * SIP session error\n * \n * @author jexa7410\n */\npublic class SipSessionError extends ImsSessionBasedServiceError {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Media has failed (e.g. RTP or MSRP failure)\n     */\n    public final static int MEDIA_FAILED = SESSION_ERROR_CODES + 4;\n\n    /**\n     * Constructor\n     * \n     * @param error Error\n     */\n    public SipSessionError(ImsServiceError error) {\n        super(error.getErrorCode(), error.getMessage());\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     */\n    public SipSessionError(int code) {\n        super(code);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param msg Detail message\n     */\n    public SipSessionError(int code, String msg) {\n        super(code, msg);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param code Error code\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public SipSessionError(int code, Throwable cause) {\n        super(code, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/SipSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip;\n\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\n\n/**\n * SIP session listener\n * \n * @author jexa7410\n */\npublic interface SipSessionListener extends ImsSessionListener {\n    /**\n     * SIP session error\n     * \n     * @param contact Remote contact\n     * @param error Error\n     */\n    public void onSessionError(ContactId contact, SipSessionError error);\n\n    /**\n     * Receive data\n     * \n     * @param contact Remote contact\n     * @param data Received data\n     * @param contentType Data content type\n     */\n    public void onDataReceived(ContactId contact, byte[] data, String contentType);\n\n    /**\n     * Destination user agent received INVITE, and is alerting user of call\n     * \n     * @param contact Remote contact\n     */\n    public void onSessionRinging(ContactId contact);\n\n    /**\n     * A session invitation has been received\n     * \n     * @param contact Remote contact\n     * @param sessionInvite\n     */\n    public void onInvitationReceived(ContactId contact, Intent sessionInvite);\n\n    /**\n     * Data has been flushed\n     *\n     * @param contact Remote contact\n     */\n    public void onDataFlushed(ContactId contact);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/messaging/GenericSipMsrpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n *      http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.messaging;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpEventListener;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpManager;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionActivityManager;\nimport com.gsma.rcs.core.ims.service.sip.EnrichCallingService;\nimport com.gsma.rcs.core.ims.service.sip.GenericSipSession;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.Vector;\n\n/**\n * Generic SIP MSRP session\n *\n * @author jexa7410\n */\npublic abstract class GenericSipMsrpSession extends GenericSipSession implements MsrpEventListener {\n\n    private final static String MIME_TYPE = \"text/plain\";\n\n    private MsrpManager mMsrpMgr;\n\n    private int mMaxMsgSize;\n\n    private boolean mFlushRequested = false;\n\n    private final SessionActivityManager mActivityMgr;\n\n    private final Set<String> mTxPendingMessageIds;\n\n    private final static Logger sLogger = Logger.getLogger(GenericSipMsrpSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     *\n     * @param parent SIP service\n     * @param contact Remote contact Id\n     * @param featureTag Feature tag\n     * @param rcsSettings RCS settings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager\n     */\n    public GenericSipMsrpSession(SipService parent, ContactId contact, String featureTag,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager) {\n        super(parent, contact, featureTag, rcsSettings, timestamp, contactManager);\n\n        mMaxMsgSize = rcsSettings.getMaxMsrpLengthForExtensions();\n        mTxPendingMessageIds = new HashSet<>();\n        /* Define the idle timeout depending of the type of service */\n        long timeout;\n        if (EnrichCallingService.CALL_COMPOSER_FEATURE_TAG.equals(featureTag)) {\n            timeout = mRcsSettings.getCallComposerInactivityTimeout();\n        } else {\n            timeout = mRcsSettings.getChatIdleDuration();\n        }\n        mActivityMgr = new SessionActivityManager(this, timeout);\n\n        /* Create the MSRP manager */\n        int localMsrpPort = NetworkRessourceManager.generateLocalMsrpPort(rcsSettings);\n        String localIpAddress = getImsService().getImsModule().getCurrentNetworkInterface()\n                .getNetworkAccess().getIpAddress();\n        mMsrpMgr = new MsrpManager(localIpAddress, localMsrpPort, rcsSettings);\n    }\n\n    /**\n     * Returns the max message size\n     *\n     * @return Max message size\n     */\n    public int getMaxMessageSize() {\n        return mMaxMsgSize;\n    }\n\n    /**\n     * Returns the MSRP manager\n     *\n     * @return MSRP manager\n     */\n    public MsrpManager getMsrpMgr() {\n        return mMsrpMgr;\n    }\n\n    /**\n     * Returns the session activity manager\n     *\n     * @return Activity manager\n     */\n    public SessionActivityManager getActivityManager() {\n        return mActivityMgr;\n    }\n\n    /**\n     * Generate SDP\n     *\n     * @param setup Setup mode\n     * @param acceptTypes Accept-types related to exchanged messages\n     * @param acceptWrappedTypes Accept-wrapped-types related to exchanged messages\n     * @return SDP built\n     */\n    public String generateSdp(String setup, String[] acceptTypes, String[] acceptWrappedTypes) {\n        int msrpPort;\n        if (\"active\".equals(setup)) {\n            msrpPort = 9; /* See RFC4145, Page 4 */\n        } else {\n            msrpPort = getMsrpMgr().getLocalMsrpPort();\n        }\n\n        String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis());\n        String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n\n        String addr = SdpUtils.formatAddressType(ipAddress);\n        StringBuilder sdp = new StringBuilder(\"v=0\").append(SipUtils.CRLF).append(\"o=- \")\n                .append(ntpTime).append(\" \").append(ntpTime).append(\" \").append(addr)\n                .append(SipUtils.CRLF).append(\"s=-\").append(SipUtils.CRLF).append(\"c=\")\n                .append(addr).append(SipUtils.CRLF).append(\"t=0 0\").append(SipUtils.CRLF)\n                .append(\"m=message \").append(msrpPort).append(\" \")\n                .append(getMsrpMgr().getLocalSocketProtocol()).append(\" *\").append(SipUtils.CRLF)\n                .append(\"a=setup:\").append(setup).append(SipUtils.CRLF).append(\"a=path:\")\n                .append(getMsrpMgr().getLocalMsrpPath()).append(SipUtils.CRLF)\n                .append(\"a=max-size:\").append(getMaxMessageSize()).append(SipUtils.CRLF);\n\n        if (acceptTypes != null && acceptTypes.length > 0) {\n            StringBuilder types = new StringBuilder();\n            types.append(acceptTypes[0]);\n            for (int i = 1; i < acceptTypes.length; i++) {\n                types.append(\" \").append(acceptTypes[i]);\n            }\n            sdp.append(\"a=accept-types:\").append(types).append(SipUtils.CRLF);\n        } else {\n            sdp.append(\"a=accept-types:\").append(GenericSipMsrpSession.MIME_TYPE)\n                    .append(SipUtils.CRLF);\n        }\n\n        if (acceptWrappedTypes != null && acceptWrappedTypes.length > 0) {\n            StringBuilder types = new StringBuilder();\n            types.append(acceptWrappedTypes[0]);\n            for (int i = 1; i < acceptWrappedTypes.length; i++) {\n                types.append(\" \").append(acceptWrappedTypes[i]);\n            }\n            sdp.append(\"a=accept-wrapped-types:\").append(types).append(SipUtils.CRLF);\n        }\n\n        sdp.append(\"a=sendrecv\").append(SipUtils.CRLF);\n\n        return sdp.toString();\n    }\n\n    @Override\n    public void prepareMediaSession() {\n        /* Parse the remote SDP part */\n        SdpParser parser = new SdpParser(getDialogPath().getRemoteContent().getBytes(UTF8));\n        Vector<MediaDescription> media = parser.getMediaDescriptions();\n        MediaDescription mediaDesc = media.elementAt(0);\n        MediaAttribute attr = mediaDesc.getMediaAttribute(\"path\");\n        String remoteMsrpPath = attr.getValue();\n        String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n        int remotePort = mediaDesc.mPort;\n\n        /* Create the MSRP session */\n        MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost, remotePort,\n                remoteMsrpPath, this, null);\n        session.setFailureReportOption(true);\n        session.setSuccessReportOption(false);\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        // Not to be used here\n    }\n\n    @Override\n    public void openMediaSession() throws NetworkException, PayloadException {\n        getMsrpMgr().openMsrpSession();\n    }\n\n    @Override\n    public void closeMediaSession() {\n        getActivityManager().stop();\n        if (mMsrpMgr != null) {\n            mMsrpMgr.closeSession();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"MSRP session has been closed\");\n            }\n        }\n    }\n\n    @Override\n    public void handleInactivityEvent() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session inactivity event\");\n        }\n        terminateSession(TerminationReason.TERMINATION_BY_INACTIVITY);\n    }\n\n    @Override\n    public void handle200OK(SipResponse resp) throws PayloadException, NetworkException,\n            FileAccessException {\n        super.handle200OK(resp);\n        getActivityManager().start();\n    }\n\n    /**\n     * Sends a message in real time\n     *\n     * @param content Message content\n     * @param contentType Message content type\n     * @throws NetworkException\n     */\n    public void sendMessage(byte[] content, String contentType) throws NetworkException {\n        ByteArrayInputStream stream = new ByteArrayInputStream(content);\n        String msgId = IdGenerator.getIdentifier().replace('_', '-');\n        mMsrpMgr.sendChunks(stream, msgId, contentType, content.length, TypeMsrpChunk.Unknown);\n        mTxPendingMessageIds.add(msgId);\n    }\n\n    /**\n     * Flush messages\n     */\n    public void flushMessages() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Request messages flush\");\n        }\n        if (mTxPendingMessageIds.isEmpty()) {\n            onMessagesFlushed();\n        } else {\n            mFlushRequested = true;\n        }\n    }\n\n    private void onMessagesFlushed() {\n        mFlushRequested = false;\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onDataFlushed(contact);\n        }\n    }\n\n    @Override\n    public void msrpDataTransferred(String msgId) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transferred\");\n        }\n        mActivityMgr.updateActivity();\n        mTxPendingMessageIds.remove(msgId);\n        if (mFlushRequested && mTxPendingMessageIds.isEmpty()) {\n            onMessagesFlushed();\n        }\n    }\n\n    @Override\n    public void receiveMsrpData(String msgId, byte[] data, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data received (type \" + mimeType + \")\");\n        }\n        mActivityMgr.updateActivity();\n        if (data == null || data.length == 0) {\n            // By-pass empty data\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"By-pass received empty data\");\n            }\n            return;\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onDataReceived(contact, data, mimeType);\n        }\n    }\n\n    @Override\n    public void msrpTransferProgress(long currentSize, long totalSize) {\n        // Not used here\n    }\n\n    @Override\n    public boolean msrpTransferProgress(long currentSize, long totalSize, byte[] data) {\n        // Not used here\n        return false;\n    }\n\n    @Override\n    public void msrpTransferAborted() {\n        // Not used here\n    }\n\n    @Override\n    public void msrpTransferError(String msgId, String error, TypeMsrpChunk typeMsrpChunk) {\n        if (isSessionInterrupted()) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Data transfer error \" + error);\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onSessionError(contact, new SipSessionError(\n                    SipSessionError.MEDIA_FAILED, error));\n        }\n        mTxPendingMessageIds.remove(msgId);\n        if (mFlushRequested && mTxPendingMessageIds.isEmpty()) {\n            onMessagesFlushed();\n        }\n    }\n\n    @Override\n    public void startSession() {\n        getSipService().addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getSipService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/messaging/OriginatingSipMsrpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.messaging;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * Originating SIP MSRP session\n * \n * @author jexa7410\n */\npublic class OriginatingSipMsrpSession extends GenericSipMsrpSession {\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingSipMsrpSession.class\n            .getSimpleName());\n\n    private final String[] mAcceptTypes;\n\n    private final String[] mAcceptWrappedTypes;\n\n    /**\n     * Constructor\n     * \n     * @param parent SIP service\n     * @param contact Remote contact Id\n     * @param featureTag Feature tag\n     * @param rcsSettings the RCS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     * @param acceptTypes Accept-types related to exchanged messages\n     * @param acceptWrappedTypes Accept-wrapped-types related to exchanged messages\n     */\n    public OriginatingSipMsrpSession(SipService parent, ContactId contact, String featureTag,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager,\n            String[] acceptTypes, String[] acceptWrappedTypes) {\n        super(parent, contact, featureTag, rcsSettings, timestamp, contactManager);\n\n        mAcceptTypes = acceptTypes;\n        mAcceptWrappedTypes = acceptWrappedTypes;\n\n        createOriginatingDialogPath();\n    }\n\n    @Override\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new MSRP session as originating\");\n            }\n\n            /* Set setup mode */\n            String localSetup = createMobileToMobileSetupOffer();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n\n            /* Build SDP offer */\n            String sdp = generateSdp(localSetup, mAcceptTypes, mAcceptWrappedTypes);\n\n            /* Set the local SDP part in the dialog path */\n            getDialogPath().setLocalContent(sdp);\n\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInvite();\n\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n\n            /* Set initial request in the dialog path */\n            getDialogPath().setInvite(invite);\n\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException | PayloadException | FileAccessException | ParseException\n                | RuntimeException e) {\n            sLogger.error(\"Session initiation has failed for CallId=\" + getDialogPath().getCallId()\n                    + \" ContactId=\" + getRemoteContact(), e);\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void handle180Ringing(SipResponse response) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"handle180Ringing\");\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onSessionRinging(contact);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/messaging/TerminatingSipMsrpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.messaging;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipManager;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.sip.GenericSipSession;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\n\nimport java.util.Collection;\nimport java.util.StringTokenizer;\nimport java.util.Vector;\n\n/**\n * Terminating SIP MSRP session\n * \n * @author jexa7410\n */\npublic class TerminatingSipMsrpSession extends GenericSipMsrpSession {\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingSipMsrpSession.class\n            .getSimpleName());\n\n    private final Intent mSessionInvite;\n\n    private final ImsModule mImsModule;\n\n    /**\n     * Constructor\n     * \n     * @param parent SIP service\n     * @param invite Initial INVITE request\n     * @param imsModule the IMS module\n     * @param contact the remote contact\n     * @param sessionInvite the session invitate\n     * @param rcsSettings the ECS settings accessor\n     * @param timestamp Local timestamp for the session\n     * @param contactManager the contact manager\n     */\n    public TerminatingSipMsrpSession(SipService parent, SipRequest invite, ImsModule imsModule,\n            ContactId contact, Intent sessionInvite, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager) {\n        super(parent, contact, GenericSipSession.getIariFeatureTag(invite.getFeatureTags()),\n                rcsSettings, timestamp, contactManager);\n        mSessionInvite = sessionInvite;\n        mImsModule = imsModule;\n        createTerminatingDialogPath(invite);\n    }\n\n    @Override\n    public void run() {\n        final boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Initiate a new MSRP session as terminating\");\n        }\n        try {\n            SipDialogPath dialogPath = getDialogPath();\n            send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            for (ImsSessionListener listener : listeners) {\n                ((SipSessionListener) listener).onInvitationReceived(contact, mSessionInvite);\n            }\n\n            InvitationStatus answer = waitInvitationAnswer();\n            switch (answer) {\n                case INVITATION_REJECTED_DECLINE:\n                    /* Intentional fall through */\n                case INVITATION_REJECTED_BUSY_HERE:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been rejected by user\");\n                    }\n                    sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_USER);\n                    }\n                    return;\n\n                case INVITATION_TIMEOUT:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been rejected on timeout\");\n                    }\n                    /* Ringing period timeout */\n                    send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n                    removeSession();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact,\n                                TerminationReason.TERMINATION_BY_TIMEOUT);\n                    }\n                    return;\n\n                case INVITATION_REJECTED_BY_SYSTEM:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been aborted by system\");\n                    }\n                    removeSession();\n                    return;\n\n                case INVITATION_CANCELED:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been rejected by remote\");\n                    }\n                    removeSession();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_REMOTE);\n                    }\n                    return;\n\n                case INVITATION_ACCEPTED:\n                    setSessionAccepted();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionAccepting(contact);\n                    }\n                    break;\n\n                case INVITATION_DELETED:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been deleted\");\n                    }\n                    removeSession();\n                    return;\n\n                default:\n                    throw new IllegalArgumentException(\"Unknown invitation answer in run; answer=\"\n                            + answer);\n            }\n\n            /* Parse the remote SDP part */\n            final SipRequest invite = dialogPath.getInvite();\n            String remoteSdp = invite.getSdpContent();\n            SipUtils.assertContentIsNotNull(remoteSdp, invite);\n            SdpParser parser = new SdpParser(remoteSdp.getBytes(UTF8));\n            Vector<MediaDescription> media = parser.getMediaDescriptions();\n            MediaDescription mediaDesc = media.elementAt(0);\n            MediaAttribute attr1 = mediaDesc.getMediaAttribute(\"path\");\n            String remotePath = attr1.getValue();\n            String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaDesc);\n            int remotePort = mediaDesc.mPort;\n\n            /* Extract the \"setup\" parameter */\n            String remoteSetup = \"passive\";\n            MediaAttribute attr2 = mediaDesc.getMediaAttribute(\"setup\");\n            if (attr2 != null) {\n                remoteSetup = attr2.getValue();\n            }\n            if (logActivated) {\n                sLogger.debug(\"Remote setup attribute is \".concat(remoteSetup));\n            }\n\n            /* Set setup mode */\n            String localSetup = createSetupAnswer(remoteSetup);\n            if (logActivated) {\n                sLogger.debug(\"Local setup attribute is \".concat(localSetup));\n            }\n\n            /* Extract \"accept-type\" */\n            String[] acceptType = new String[0];\n            MediaAttribute attr3 = mediaDesc.getMediaAttribute(\"accept-types\");\n            if (attr3 != null) {\n                StringTokenizer st = new StringTokenizer(attr3.getValue(), \" \");\n                acceptType = new String[st.countTokens()];\n                int i = 0;\n                while (st.hasMoreTokens()) {\n                    acceptType[i] = st.nextToken();\n                    i++;\n                }\n            }\n\n            /* Extract \"accept-wrapped-type\" */\n            String[] acceptWrappedType = new String[0];\n            MediaAttribute attr4 = mediaDesc.getMediaAttribute(\"accept-wrapped-types\");\n            if (attr4 != null) {\n                StringTokenizer st = new StringTokenizer(attr4.getValue(), \" \");\n                acceptWrappedType = new String[st.countTokens()];\n                int i = 0;\n                while (st.hasMoreTokens()) {\n                    acceptWrappedType[i] = st.nextToken();\n                    i++;\n                }\n            }\n\n            /* Build SDP answer */\n            String sdp = generateSdp(localSetup, acceptType, acceptWrappedType);\n\n            /* Set the local SDP part in the dialog path */\n            dialogPath.setLocalContent(sdp);\n\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = create200OKResponse();\n\n            /* The signalisation is established */\n            dialogPath.setSigEstablished();\n            SipManager sipManager = mImsModule.getSipManager();\n            SipTransactionContext ctx = sipManager.sendSipMessage(resp);\n\n            /* Create the MSRP server session */\n            if (localSetup.equals(\"passive\")) {\n                /* Passive mode: client wait a connection */\n                MsrpSession session = getMsrpMgr().createMsrpServerSession(remotePath, this);\n                session.setFailureReportOption(false);\n                session.setSuccessReportOption(false);\n                /* Open the MSRP session */\n                getMsrpMgr().openMsrpSession();\n                getMsrpMgr().sendEmptyChunk();\n            }\n\n            sipManager.waitResponse(ctx);\n\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (logActivated) {\n                    sLogger.info(\"ACK request received\");\n                }\n                /* Create the MSRP client session */\n                if (localSetup.equals(\"active\")) {\n                    /* Active mode: client should connect MSRP session without TLS */\n                    MsrpSession session = getMsrpMgr().createMsrpClientSession(remoteHost,\n                            remotePort, remotePath, this, null);\n                    session.setFailureReportOption(false);\n                    session.setSuccessReportOption(false);\n                    getMsrpMgr().openMsrpSession();\n                    getMsrpMgr().sendEmptyChunk();\n                }\n\n                /* The session is established */\n                dialogPath.setSessionEstablished();\n\n                // Start session timer\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n\n                for (ImsSessionListener listener : getListeners()) {\n                    listener.onSessionStarted(contact);\n                }\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n\n                /* No response received: timeout */\n                handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED));\n            }\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Session initiation has failed for CallId=\" + getDialogPath().getCallId()\n                    + \" ContactId=\" + getRemoteContact(), e);\n            handleError(new SipSessionError(SipSessionError.MEDIA_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new SipSessionError(SipSessionError.MEDIA_FAILED, e));\n\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/streaming/DataReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.streaming;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaSample;\n\n/**\n * Data renderer in charge of receiving data payload and to forward it to the application via the\n * API\n * \n * @author Jean-Marc AUFFRET\n */\npublic class DataReceiver implements MediaOutput {\n    /**\n     * Parent\n     */\n    private GenericSipRtpSession mParent;\n\n    /**\n     * Constructor\n     * @param parent \n     */\n    public DataReceiver(GenericSipRtpSession parent) {\n        mParent = parent;\n    }\n\n    /**\n     * Open the renderer\n     */\n    public void open() {\n        // TODO\n    }\n\n    /**\n     * Close the renderer\n     */\n    public void close() {\n        // TODO\n    }\n\n    /**\n     * Write a media sample\n     * \n     * @param sample Sample\n     */\n    public void writeSample(MediaSample sample) {\n        // Notify API\n        mParent.receiveData(sample.getData(), \"application/*\"); // TODO 1.6: add mime-type\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/streaming/DataSender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.streaming;\n\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.gsma.rcs.core.ims.protocol.rtp.media.MediaSample;\nimport com.gsma.rcs.utils.FifoBuffer;\n\n/**\n * Data player in charge of sending data payload to the network via the RTP protocol\n * \n * @author Jean-Marc AUFFRET\n */\npublic class DataSender implements MediaInput {\n    /**\n     * Received frames\n     */\n    private FifoBuffer mFifo;\n\n    /**\n     * Constructor\n     */\n    public DataSender() {\n    }\n\n    /**\n     * Add a new video frame\n     * \n     * @param data Data\n     * @param timestamp Timestamp\n     */\n    public void addFrame(byte[] data, long timestamp) {\n        if (mFifo != null) {\n            MediaSample sample = new MediaSample(data, timestamp);\n            mFifo.addObject(sample);\n        }\n    }\n\n    /**\n     * Open the player\n     */\n    public void open() {\n        mFifo = new FifoBuffer();\n    }\n\n    /**\n     * Close the player\n     */\n    public void close() {\n        if (mFifo != null) {\n            mFifo.close();\n            mFifo = null;\n        }\n    }\n\n    /**\n     * Read a media sample (blocking method)\n     * \n     * @return Media sample\n     */\n    public MediaSample readSample() {\n        return (MediaSample) mFifo.getObject();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/streaming/GenericSipRtpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.streaming;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.rtp.MediaRtpReceiver;\nimport com.gsma.rcs.core.ims.protocol.rtp.MediaRtpSender;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.Format;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.data.DataFormat;\nimport com.gsma.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionNotEstablishedException;\nimport com.gsma.rcs.core.ims.service.sip.GenericSipSession;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.NetworkRessourceManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Generic SIP RTP session\n * \n * @author jexa7410\n */\npublic abstract class GenericSipRtpSession extends GenericSipSession implements RtpStreamListener {\n    /**\n     * RTP payload format\n     */\n    protected DataFormat mFormat;\n\n    private int mLocalRtpPort = -1;\n\n    private DataSender mDataSender = new DataSender();\n\n    private DataReceiver mDataReceiver = new DataReceiver(this);\n\n    private MediaRtpReceiver mRtpReceiver;\n\n    private MediaRtpSender mRtpSender;\n\n    /**\n     * Media Session started flag\n     */\n    private boolean mMediaSessionStarted;\n\n    private final static Logger sLogger = Logger.getLogger(GenericSipRtpSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS service\n     * @param contact Remote contact Id\n     * @param featureTag Feature tag\n     * @param rcsSettings RCS settings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contact manager\n     * @param encoding Encoding\n     */\n    public GenericSipRtpSession(SipService parent, ContactId contact, String featureTag,\n            RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager, String encoding) {\n        super(parent, contact, featureTag, rcsSettings, timestamp, contactManager);\n\n        /* Get local port */\n        mLocalRtpPort = NetworkRessourceManager.generateLocalRtpPort(rcsSettings);\n\n        /* Create the RTP sender & receiver */\n        mFormat = new DataFormat(encoding);\n        mRtpReceiver = new MediaRtpReceiver(mLocalRtpPort);\n        mRtpSender = new MediaRtpSender(mFormat, mLocalRtpPort);\n    }\n\n    /**\n     * Get local port\n     * \n     * @return RTP port\n     */\n    public int getLocalRtpPort() {\n        return mLocalRtpPort;\n    }\n\n    /**\n     * Returns the RTP receiver\n     * \n     * @return RTP receiver\n     */\n    public MediaRtpReceiver getRtpReceiver() {\n        return mRtpReceiver;\n    }\n\n    /**\n     * Returns the RTP sender\n     * \n     * @return RTP sender\n     */\n    public MediaRtpSender getRtpSender() {\n        return mRtpSender;\n    }\n\n    /**\n     * Returns the RTP format\n     * \n     * @return RTP format\n     */\n    public Format getRtpFormat() {\n        return mFormat;\n    }\n\n    /**\n     * Generate SDP\n     * \n     * @return SDP built\n     */\n    public String generateSdp() {\n        String ntpTime = SipUtils.constructNTPtime(System.currentTimeMillis());\n        String ipAddress = getDialogPath().getSipStack().getLocalIpAddress();\n        return \"v=0\" + SipUtils.CRLF + \"o=- \" + ntpTime + \" \" + ntpTime + \" \"\n                + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"s=-\" + SipUtils.CRLF\n                + \"c=\" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF + \"t=0 0\"\n                + SipUtils.CRLF + \"m=application \" + mLocalRtpPort + \" RTP/AVP \"\n                + getRtpFormat().getPayload() + SipUtils.CRLF + \"a=rtpmap:\"\n                + getRtpFormat().getPayload() + \" \" + getRtpFormat().getCodec()\n                + SipUtils.CRLF +\n                \"a=sendrecv\" + SipUtils.CRLF;\n    }\n\n    @Override\n    public void prepareMediaSession() throws NetworkException {\n        SdpParser parser = new SdpParser(getDialogPath().getRemoteContent().getBytes(UTF8));\n        MediaDescription mediaApp = parser.getMediaDescription(\"application\");\n\n        // Extract session description\n        String remoteHost = SdpUtils.extractRemoteHost(parser.sessionDescription, mediaApp);\n        int remotePort = mediaApp.mPort;\n\n        // Extract encoding name\n        String rtpmap = mediaApp.getMediaAttribute(\"rtpmap\").getValue();\n        String encoding = rtpmap.substring(\n                rtpmap.indexOf(mediaApp.mPayload) + mediaApp.mPayload.length() + 1).trim();\n\n        mFormat = new DataFormat(encoding);\n        mRtpReceiver.prepareSession(remoteHost, remotePort, mDataReceiver, mFormat, this);\n        mRtpSender.prepareSession(mDataSender, remoteHost, remotePort,\n                mRtpReceiver.getInputStream(), this);\n    }\n\n    /**\n     * Gets the encoding payload\n     *\n     * @param content SDP content\n     * @return encoding\n     */\n    public static String getEncoding(String content) {\n        SdpParser parser = new SdpParser(content.getBytes(UTF8));\n        MediaDescription mediaApp = parser.getMediaDescription(\"application\");\n        String rtpmap = mediaApp.getMediaAttribute(\"rtpmap\").getValue();\n        String encoding = rtpmap.substring(\n                rtpmap.indexOf(mediaApp.mPayload) + mediaApp.mPayload.length() + 1).trim();\n        return encoding;\n    }\n\n    @Override\n    public void openMediaSession() {\n        /* Not to be used here */\n    }\n\n    @Override\n    public void startMediaTransfer() {\n        synchronized (this) {\n            mRtpReceiver.startSession();\n            mRtpSender.startSession();\n            mMediaSessionStarted = true;\n        }\n    }\n\n    @Override\n    public void closeMediaSession() {\n        synchronized (this) {\n            mMediaSessionStarted = false;\n            mRtpSender.stopSession();\n            mRtpReceiver.stopSession();\n        }\n    }\n\n    /**\n     * Sends a payload in real time\n     * \n     * @param content Payload content\n     * @throws SessionNotEstablishedException\n     */\n    public void sendPlayload(byte[] content) throws SessionNotEstablishedException {\n        if (!mMediaSessionStarted) {\n            throw new SessionNotEstablishedException(\"Unable to send payload!\");\n        }\n        mDataSender.addFrame(content, System.currentTimeMillis());\n    }\n\n    @Override\n    public void rtpStreamAborted() {\n        try {\n            if (isSessionInterrupted()) {\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.error(\"Media has failed: network failure\");\n            }\n            closeMediaSession();\n            closeSession(TerminationReason.TERMINATION_BY_SYSTEM);\n            removeSession();\n            ContactId contact = getRemoteContact();\n            for (ImsSessionListener listener : getListeners()) {\n                ((SipSessionListener) listener).onSessionError(contact, new SipSessionError(\n                        SipSessionError.MEDIA_FAILED));\n            }\n\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to abort rtp stream!\", e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to abort rtp stream!\", e);\n        }\n    }\n\n    /**\n     * Receive media data\n     *\n     * @param data Data\n     * @param mimeType MIME-type\n     */\n    public void receiveData(byte[] data, String mimeType) {\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onDataReceived(contact, data, mimeType);\n        }\n    }\n\n    @Override\n    public void startSession() {\n        getSipService().addSession(this);\n        start();\n    }\n\n    @Override\n    public void removeSession() {\n        getSipService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/streaming/OriginatingSipRtpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.streaming;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * Originating SIP RTP session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class OriginatingSipRtpSession extends GenericSipRtpSession {\n\n    private static final Logger sLogger = Logger.getLogger(OriginatingSipRtpSession.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param parent SIP service\n     * @param contact Remote contact Id\n     * @param featureTag Feature tag\n     * @param rcsSettings RCS settings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager Contacts\n     * @param encoding Encoding\n     */\n    public OriginatingSipRtpSession(SipService parent, ContactId contact, String featureTag,\n            RcsSettings rcsSettings, long timestamp, ContactManager contactManager, String encoding) {\n        super(parent, contact, featureTag, rcsSettings, timestamp, contactManager, encoding);\n        /* Create dialog path */\n        createOriginatingDialogPath();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new RTP session as originating\");\n            }\n            /* Build SDP part */\n            String sdp = generateSdp();\n            /* Set the local SDP part in the dialog path */\n            getDialogPath().setLocalContent(sdp);\n            /* Create an INVITE request */\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send INVITE\");\n            }\n            SipRequest invite = createInvite();\n            getAuthenticationAgent().setAuthorizationHeader(invite);\n            /* Set initial request in the dialog path */\n            getDialogPath().setInvite(invite);\n            sendInvite(invite);\n\n        } catch (InvalidArgumentException e) {\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        } catch (ParseException e) {\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        } catch (FileAccessException e) {\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        } catch (PayloadException e) {\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /**\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED, e));\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return false;\n    }\n\n    @Override\n    public void handle180Ringing(SipResponse response) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"handle180Ringing\");\n        }\n        ContactId contact = getRemoteContact();\n        for (ImsSessionListener listener : getListeners()) {\n            ((SipSessionListener) listener).onSessionRinging(contact);\n        }\n    }\n\n    @Override\n    public void handleInactivityEvent() {\n        /* Not need in this class */\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/sip/streaming/TerminatingSipRtpSession.java",
    "content": "/*******************************************************************************\n\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.sip.streaming;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsSessionListener;\nimport com.gsma.rcs.core.ims.service.SessionTimerManager;\nimport com.gsma.rcs.core.ims.service.sip.GenericSipSession;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\n\nimport java.util.Collection;\n\n/**\n * Terminating SIP RTP session\n * \n * @author jexa7410\n */\npublic class TerminatingSipRtpSession extends GenericSipRtpSession {\n\n    private static final Logger sLogger = Logger.getLogger(TerminatingSipRtpSession.class\n            .getSimpleName());\n\n    private final Intent mSessionInvite;\n\n    private final ImsModule mImsModule;\n\n    /**\n     * Constructor\n     * \n     * @param parent SIP service\n     * @param invite Initial INVITE request\n     * @param imsModule\n     * @param contact\n     * @param sessionInvite\n     * @param rcsSettings\n     * @param timestamp Local timestamp for the session\n     * @param contactManager\n     */\n    public TerminatingSipRtpSession(SipService parent, SipRequest invite, ImsModule imsModule,\n            ContactId contact, Intent sessionInvite, RcsSettings rcsSettings, long timestamp,\n            ContactManager contactManager) {\n        super(parent, contact, GenericSipSession.getIariFeatureTag(invite.getFeatureTags()),\n                rcsSettings, timestamp, contactManager,\n                GenericSipRtpSession.getEncoding(invite.getContent()));\n\n        mSessionInvite = sessionInvite;\n        mImsModule = imsModule;\n        /* Create dialog path */\n        createTerminatingDialogPath(invite);\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.info(\"Initiate a new RTP session as terminating\");\n        }\n        try {\n            SipDialogPath dialogPath = getDialogPath();\n            send180Ringing(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n            Collection<ImsSessionListener> listeners = getListeners();\n            ContactId contact = getRemoteContact();\n            for (ImsSessionListener listener : listeners) {\n                ((SipSessionListener) listener).onInvitationReceived(contact, mSessionInvite);\n            }\n\n            InvitationStatus answer = waitInvitationAnswer();\n            switch (answer) {\n                case INVITATION_REJECTED_DECLINE:\n                    /* Intentional fall through */\n                case INVITATION_REJECTED_BUSY_HERE:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been rejected by user\");\n                    }\n                    sendErrorResponse(dialogPath.getInvite(), dialogPath.getLocalTag(), answer);\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_USER);\n                    }\n                    return;\n\n                case INVITATION_TIMEOUT:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been rejected on timeout\");\n                    }\n\n                    // Ringing period timeout\n                    send486Busy(dialogPath.getInvite(), dialogPath.getLocalTag());\n\n                    removeSession();\n\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact,\n                                TerminationReason.TERMINATION_BY_TIMEOUT);\n                    }\n                    return;\n\n                case INVITATION_REJECTED_BY_SYSTEM:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been aborted by system\");\n                    }\n                    removeSession();\n                    return;\n\n                case INVITATION_CANCELED:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been canceled\");\n                    }\n                    removeSession();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionRejected(contact, TerminationReason.TERMINATION_BY_REMOTE);\n                    }\n                    return;\n\n                case INVITATION_ACCEPTED:\n                    setSessionAccepted();\n                    for (ImsSessionListener listener : listeners) {\n                        listener.onSessionAccepting(contact);\n                    }\n                    break;\n\n                case INVITATION_DELETED:\n                    if (logActivated) {\n                        sLogger.debug(\"Session has been deleted\");\n                    }\n                    removeSession();\n                    return;\n\n                default:\n                    throw new IllegalArgumentException(new StringBuilder(\n                            \"Unknown invitation answer in run; answer=\").append(answer).toString());\n            }\n\n            String sdp = generateSdp();\n            \n            /* Set the local SDP part in the dialog path */\n            dialogPath.setLocalContent(sdp);\n\n            /* Test if the session should be interrupted */\n            if (isInterrupted()) {\n                if (logActivated) {\n                    sLogger.debug(\"Session has been interrupted: end of processing\");\n                }\n                return;\n            }\n\n            /* Prepare Media Session */\n            prepareMediaSession();\n\n            /* Create a 200 OK response */\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            SipResponse resp = create200OKResponse();\n\n            /* The signalisation is established */\n            dialogPath.setSigEstablished();\n\n            /* Send response */\n            SipTransactionContext ctx = mImsModule.getSipManager().sendSipMessageAndWait(resp);\n\n            /* Analyze the received response */\n            if (ctx.isSipAck()) {\n                if (logActivated) {\n                    sLogger.info(\"ACK request received\");\n                }\n\n                /* The session is established */\n                dialogPath.setSessionEstablished();\n\n                /* Start Media transfer */\n                startMediaTransfer();\n\n                /* Start session timer */\n                SessionTimerManager sessionTimerManager = getSessionTimerManager();\n                if (sessionTimerManager.isSessionTimerActivated(resp)) {\n                    sessionTimerManager.start(SessionTimerManager.UAS_ROLE,\n                            dialogPath.getSessionExpireTime());\n                }\n\n                for (ImsSessionListener listener : getListeners()) {\n                    listener.onSessionStarted(contact);\n                }\n\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"No ACK received for INVITE\");\n                }\n\n                // No response received: timeout\n                handleError(new SipSessionError(SipSessionError.SESSION_INITIATION_FAILED));\n            }\n\n        } catch (PayloadException e) {\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.MEDIA_FAILED, e));\n\n        } catch (NetworkException e) {\n            handleError(new SipSessionError(SipSessionError.MEDIA_FAILED, e));\n\n        } catch (RuntimeException e) {\n            /**\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\"Session initiation has failed for CallId=\")\n                            .append(getDialogPath().getCallId()).append(\" ContactId=\")\n                            .append(getRemoteContact()).toString(), e);\n            handleError(new SipSessionError(SipSessionError.MEDIA_FAILED, e));\n        }\n    }\n\n    @Override\n    public boolean isInitiatedByRemote() {\n        return true;\n    }\n\n    @Override\n    public void handleInactivityEvent() {\n        /* Not need in this class */\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/terms/EndUserNotificationParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.terms;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\nimport java.util.HashMap;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * End user notification request parser. If the message contains the text in different languages\n * it's returns the text in the requested language if present or in the default language (English).\n * \n * @author Deutsche Telekom AG\n */\npublic class EndUserNotificationParser extends DefaultHandler {\n    /*\n     * SAMPLE: <?xml version=\"1.0\" standalone=\"yes\"?> <EndUserNotification id=\"xxxxxxxxx\"> <Subject\n     * xml:lang=\"en\">xxxxxxxxxx</Subject> <Subject xml:lang=\"de\">xxxxxxxxxx</Subject> <Subject\n     * xml:lang=\"es\">xxxxxxxxxx</Subject> <Text xml:lang=\"en\">xxxxxxxxxx</Text> <Text\n     * xml:lang=\"de\">xxxxxxxxxx</Text> <Text xml:lang=\"es\">xxxxxxxxxx</Text> <ButtonOK\n     * xml:lang=\"en\">xxxxxxxxxx</ButtonOK> <ButtonOK xml:lang=\"de\">xxxxxxxxxx</ButtonOK> <ButtonOK\n     * xml:lang=\"es\">xxxxxxxxxx</ButtonOK> </EndUserNotification>\n     */\n\n    /**\n     * Default language is English\n     */\n    private final static String DEFAULT_LANGUAGE = \"en\";\n\n    /**\n     * Char buffer for parsing text from one element\n     */\n    private StringBuffer mAccumulator;\n\n    /**\n     * Value off attribute 'id' off element 'EndUserNotification'\n     */\n    private String mId;\n\n    /**\n     * Requested language (given in constructor)\n     */\n    private String mRequestedLanguage;\n\n    /**\n     * Language from the first 'Subject' element\n     */\n    private String mFirstLanguage;\n\n    /**\n     * Flag if variable 'firstLanguage' is set\n     */\n    private boolean isFirstSubjectParsed;\n\n    /**\n     * Value of language attribute of current xml element during parsing\n     */\n    private String mCurrentLangAttribute;\n\n    /**\n     * HashMap<('ElementName' + 'Language'), text>\n     */\n    private final HashMap<String, String> mElementMap;\n\n    private final InputSource mInputSource;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(EndUserNotificationParser.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     * @param requestedLanguage requested language\n     */\n    public EndUserNotificationParser(InputSource inputSource, String requestedLanguage) {\n        mRequestedLanguage = requestedLanguage;\n        mElementMap = new HashMap<String, String>();\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the end user notification information\n     * \n     * @return EndUserNotificationParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public EndUserNotificationParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public String getId() {\n        return mId;\n    }\n\n    public String getSubject() {\n        return giveTextInBestLanguage(\"Subject\");\n    }\n\n    public String getText() {\n        return giveTextInBestLanguage(\"Text\");\n    }\n\n    public String getButtonOk() {\n        return giveTextInBestLanguage(\"ButtonOK\");\n    }\n\n    public void startDocument() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start document 'EndUserNotification'.\");\n        }\n        mAccumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n\n        if (qname.equals(\"EndUserNotification\")) {\n            mId = attr.getValue(\"id\").trim();\n        } else {\n            mCurrentLangAttribute = attr.getValue(\"xml:lang\");\n            if (mCurrentLangAttribute == null) {\n                // for xml failure tolerance\n                mCurrentLangAttribute = attr.getValue(\"lang\");\n            }\n\n            if (mCurrentLangAttribute == null) {\n                // to avoid null pointer exception\n                mCurrentLangAttribute = \"\";\n            }\n            // put to lower case for xml failure tolerance\n            mCurrentLangAttribute = mCurrentLangAttribute.trim().toLowerCase();\n            if (!isFirstSubjectParsed) {\n                isFirstSubjectParsed = true;\n                mFirstLanguage = mCurrentLangAttribute;\n            }\n        }\n\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (qname.equals(\"EndUserNotification\")) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"EndUserNotification document is complete\");\n            }\n        } else if (mCurrentLangAttribute.equals(mRequestedLanguage)\n                || mCurrentLangAttribute.equals(DEFAULT_LANGUAGE)\n                || mCurrentLangAttribute.equals(mFirstLanguage) || mCurrentLangAttribute.equals(\"\")) {\n            mElementMap.put(qname + mCurrentLangAttribute, mAccumulator.toString().trim());\n        }\n    }\n\n    // Returns text part off xml element,\n    // if found for requested language ('xml:lang' attribute == requestedLanguage)\n    // or with 'xml:lang' is equal \"en\" (english)\n    // or with 'xml:lang' attribute equals to this from the first 'Subject' element\n    // or the text from the element with out any 'xml:lang' attribute\n    // or null if element not found\n    private String giveTextInBestLanguage(String elementName) {\n        if (mElementMap.containsKey(elementName + mRequestedLanguage)) {\n            return mElementMap.get(elementName + mRequestedLanguage);\n\n        } else if (mElementMap.containsKey(elementName + DEFAULT_LANGUAGE)) {\n            return mElementMap.get(elementName + DEFAULT_LANGUAGE);\n\n        } else if (mElementMap.containsKey(elementName + mFirstLanguage)) {\n            return mElementMap.get(elementName + mFirstLanguage);\n\n        } else {\n            return mElementMap.get(elementName);\n        }\n    }\n\n    public void endDocument() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"End document: 'EndUserNotification'\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/terms/TermsAckParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.terms;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Terms & condition request parser\n * \n * @author jexa7410\n */\npublic class TermsAckParser extends DefaultHandler {\n    /*\n     * SAMPLE: <?xml version=\"1.0\" standalone=\"yes\"?> <EndUserConfirmationAck id=\"xxxxxxxxx\"\n     * status=\"xxxxxxxxxxx\"> <Subject>xxxxxxxxxx</Subject> <Text>xxxxxxxxxx</Text>\n     * </EndUserConfirmationAck>\n     */\n\n    private StringBuffer mAccumulator;\n\n    private String mId;\n\n    private String mStatus;\n\n    private String mSubject;\n\n    private String mText;\n\n    private final InputSource mInputSource;\n\n    /**\n     * The logger\n     */\n    private static final Logger sLogger = Logger.getLogger(TermsAckParser.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     * @param requestedLanguage\n     * @param rcsSettings\n     */\n    public TermsAckParser(InputSource inputSource) {\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the terms ack information\n     * \n     * @return TermsAckParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public TermsAckParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public String getId() {\n        return mId;\n    }\n\n    public String getStatus() {\n        return mStatus;\n    }\n\n    public String getSubject() {\n        return mSubject;\n    }\n\n    public String getText() {\n        return mText;\n    }\n\n    public void startDocument() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start document\");\n        }\n        mAccumulator = new StringBuffer();\n    }\n\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n\n        if (localName.equals(\"EndUserConfirmationAck\")) {\n            mId = attr.getValue(\"id\").trim();\n            mStatus = attr.getValue(\"status\").trim();\n        }\n    }\n\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (localName.equals(\"EndUserConfirmationAck\")) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Terms request document is complete\");\n            }\n        } else if (localName.equals(\"Subject\")) {\n            mSubject = mAccumulator.toString().trim();\n        } else if (localName.equals(\"Text\")) {\n            mText = mAccumulator.toString().trim();\n        }\n    }\n\n    public void endDocument() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"End document\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/terms/TermsConditionsService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.terms;\n\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.SipManager;\nimport com.gsma.rcs.core.ims.network.sip.SipMessageFactory;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.protocol.sip.SipInterface;\nimport com.gsma.rcs.core.ims.protocol.sip.SipRequest;\nimport com.gsma.rcs.core.ims.protocol.sip.SipResponse;\nimport com.gsma.rcs.core.ims.protocol.sip.SipTransactionContext;\nimport com.gsma.rcs.core.ims.service.ImsService;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession;\nimport com.gsma.rcs.core.ims.service.SessionAuthenticationAgent;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport org.xml.sax.InputSource;\n\nimport java.io.ByteArrayInputStream;\nimport java.text.ParseException;\nimport java.util.Locale;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.message.Response;\n\n/**\n * Terms & conditions service via SIP\n * \n * @author jexa7410\n */\npublic class TermsConditionsService extends ImsService {\n    /**\n     * Request MIME type\n     */\n    private final static String REQUEST_MIME_TYPE = \"application/end-user-confirmation-request+xml\";\n\n    /**\n     * Ack MIME type\n     */\n    private final static String ACK_MIME_TYPE = \"application/end-user-confirmation-ack+xml\";\n\n    /**\n     * User notification MIME type\n     */\n    private final static String USER_NOTIFICATION_MIME_TYPE = \"application/end-user-notification-request+xml\";\n\n    /**\n     * Response MIME type\n     */\n    private final static String RESPONSE_MIME_TYPE = \"application/end-user-confirmation-response+xml\";\n\n    /**\n     * Accept response\n     */\n    private final static String ACCEPT_RESPONSE = \"accept\";\n\n    /**\n     * Decline response\n     */\n    private final static String DECLINE_RESPONSE = \"decline\";\n\n    private final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(TermsConditionsService.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param parent IMS module\n     * @param rcsSettings RcsSettings\n     */\n    public TermsConditionsService(ImsModule parent, RcsSettings rcsSettings) {\n        super(parent, true);\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public synchronized void start() {\n        if (isServiceStarted()) {\n            return;\n        }\n        setServiceStarted(true);\n    }\n\n    @Override\n    public synchronized void stop(ImsServiceSession.TerminationReason reasonCode) {\n        if (!isServiceStarted()) {\n            return;\n        }\n        setServiceStarted(false);\n    }\n\n    /**\n     * Check the IMS service\n     */\n    public void check() {\n    }\n\n    /**\n     * Receive a SIP message\n     * \n     * @param message Received message\n     */\n    public void onMessageReceived(SipRequest message) {\n        try {\n            boolean logActivated = sLogger.isActivated();\n            if (logActivated) {\n                sLogger.debug(\"Receive terms message\");\n            }\n            if (logActivated) {\n                sLogger.info(\"Send 200 OK\");\n            }\n            final ImsModule imsModule = getImsModule();\n            imsModule.getSipManager().sendSipResponse(\n                    SipMessageFactory.createResponse(message, IdGenerator.getIdentifier(),\n                            Response.OK));\n\n            String lang = Locale.getDefault().getLanguage();\n\n            String remoteId = getRemoteIdentity(message);\n            PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(remoteId);\n            if (number == null) {\n                if (logActivated) {\n                    sLogger.error(\"Can't parse contact : \".concat(remoteId));\n                }\n                return;\n            }\n            ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n            final String contentType = message.getContentType();\n            if (REQUEST_MIME_TYPE.equals(contentType)) {\n                InputSource input = new InputSource(new ByteArrayInputStream(\n                        message.getContentBytes()));\n                TermsRequestParser parser = new TermsRequestParser(input, lang, mRcsSettings);\n                imsModule\n                        .getCore()\n                        .getListener()\n                        .onUserConfirmationRequest(contact, parser.getId(), parser.getType(),\n                                parser.getPin(), parser.getSubject(), parser.getText(),\n                                parser.getButtonAccept(), parser.getButtonReject(),\n                                parser.getTimeout());\n\n            } else if (ACK_MIME_TYPE.equals(contentType)) {\n                InputSource input = new InputSource(new ByteArrayInputStream(\n                        message.getContentBytes()));\n                TermsAckParser parser = new TermsAckParser(input);\n                imsModule\n                        .getCore()\n                        .getListener()\n                        .onUserConfirmationAck(contact, parser.getId(), parser.getStatus(),\n                                parser.getSubject(), parser.getText());\n\n            } else if (USER_NOTIFICATION_MIME_TYPE.equals(contentType)) {\n                InputSource input = new InputSource(new ByteArrayInputStream(\n                        message.getContentBytes()));\n                EndUserNotificationParser parser = new EndUserNotificationParser(input, lang);\n                imsModule\n                        .getCore()\n                        .getListener()\n                        .onUserNotification(contact, parser.getId(), parser.getSubject(),\n                                parser.getText(), parser.getButtonOk());\n            } else {\n                if (logActivated) {\n                    sLogger.warn(\"Unknown terms request \".concat(contentType));\n                }\n            }\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to receive terms request! (\" + e.getMessage() + \")\");\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\"Failed to receive terms request!\", e);\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to receive terms request!\", e);\n        }\n    }\n\n    /**\n     * Accept terms\n     * \n     * @param requestId Request ID\n     * @param pin Response value\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void acceptTerms(String requestId, String pin) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send response for request \".concat(requestId));\n        }\n        if (TextUtils.isEmpty(requestId)) {\n            throw new PayloadException(\"requestId should never be null or empty!\");\n        }\n        sendSipMessage(mRcsSettings.getEndUserConfirmationRequestUri(), requestId, ACCEPT_RESPONSE,\n                pin);\n    }\n\n    /**\n     * Reject terms\n     * \n     * @param requestId Request ID\n     * @param pin Response value\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void rejectTerms(String requestId, String pin) throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send response for request \".concat(requestId));\n        }\n        if (TextUtils.isEmpty(requestId)) {\n            throw new PayloadException(\"requestId should never be null or empty!\");\n        }\n        sendSipMessage(mRcsSettings.getEndUserConfirmationRequestUri(), requestId,\n                DECLINE_RESPONSE, pin);\n    }\n\n    private void sendSipMessage(Uri eucr, String requestId, String responseValue, String pin)\n            throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send SIP response\");\n        }\n        StringBuilder response = new StringBuilder(\n                \"<?xml version=\\\"1.0\\\" standalone=\\\"yes\\\"?><EndUserConfirmationResponse id=\\\"\")\n                .append(requestId).append(\"\\\" value=\\\"\").append(responseValue).append(\"\\\"\");\n\n        if (pin != null) {\n            response.append(\" pin=\\\"\").append(pin).append(\"\\\"\");\n        }\n        response.append(\"/>\");\n\n        final SipManager sipManager = getImsModule().getSipManager();\n        final SipInterface sipStack = sipManager.getSipStack();\n        final String remoteServer = eucr.getPath();\n        SipDialogPath dialogPath = new SipDialogPath(sipStack, sipStack.generateCallId(), 1,\n                remoteServer, ImsModule.getImsUserProfile().getPublicUri(), remoteServer,\n                sipStack.getServiceRoutePath(), mRcsSettings);\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send first MESSAGE\");\n        }\n        SipRequest msg = SipMessageFactory.createMessage(dialogPath, RESPONSE_MIME_TYPE,\n                response.toString());\n        SipTransactionContext ctx = sipManager.sendSipMessageAndWait(msg);\n        final int statusCode = ctx.getStatusCode();\n        switch (statusCode) {\n            case Response.PROXY_AUTHENTICATION_REQUIRED:\n                handle407Authentication(dialogPath, ctx.getSipResponse(), response.toString());\n                break;\n            case Response.OK:\n                /* Intentional fall-through */\n            case Response.ACCEPTED:\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"20x OK response received\");\n                }\n                break;\n            default:\n                throw new IllegalArgumentException(\"Invalid response :  \" + statusCode + \" received!\");\n        }\n    }\n\n    /**\n     * Get remote identity of the incoming request\n     * \n     * @param request Request\n     * @return ID\n     */\n    private String getRemoteIdentity(SipRequest request) {\n        return SipUtils.getAssertedIdentity(request);\n    }\n\n    /**\n     * Is a terms & conditions request\n     * \n     * @param request Request\n     * @return Boolean\n     */\n    public static boolean isTermsRequest(SipRequest request) {\n        String contentType = request.getContentType();\n        return (contentType != null && contentType.startsWith(\"application/end-user\"));\n    }\n\n    private void handle407Authentication(SipDialogPath dialogPath, SipResponse sipResponse,\n            String response) throws PayloadException, NetworkException {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"407 response received\");\n            }\n            final ImsModule imsModule = getImsModule();\n            SessionAuthenticationAgent authenticationAgent = new SessionAuthenticationAgent(\n                    imsModule);\n            authenticationAgent.readProxyAuthenticateHeader(sipResponse);\n            dialogPath.incrementCseq();\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Send second MESSAGE\");\n            }\n            SipRequest msg = SipMessageFactory.createMessage(dialogPath, RESPONSE_MIME_TYPE,\n                    response);\n            authenticationAgent.setProxyAuthorizationHeader(msg);\n            SipTransactionContext ctx = imsModule.getSipManager().sendSipMessageAndWait(msg);\n            final int statusCode = ctx.getStatusCode();\n            switch (statusCode) {\n                case Response.OK:\n                    /* Intentional fall-through */\n                case Response.ACCEPTED:\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"20x OK response received\");\n                    }\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Invalid response :  \" + statusCode + \" received!\");\n            }\n        } catch (InvalidArgumentException | ParseException e) {\n            throw new PayloadException(\"Failed to handle 407 authentication response!\", e);\n\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/terms/TermsRequestParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.terms;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.IOException;\nimport java.util.HashMap;\n\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * End User Confirmation Request request parser. Parse message of type\n * end-user-confirmation-request. If the message contains the text in different languages it's\n * returns the text in the requested language if present or in the default language (English).\n * \n * @author jexa7410\n * @author Deutsche Telekom AG\n */\npublic class TermsRequestParser extends DefaultHandler {\n    /*\n     * SAMPLE: <?xml version=\"1.0\" standalone=\"yes\"?> <EndUserConfirmationRequest id=\"xxxxxxx\"\n     * type=\"xxxxxxx\" pin=\"xxxxxx\" timeout=\"120\"> <Subject xml:lang=\"en\">xxxxxxxxxx</Subject>\n     * <Subject xml:lang=\"de\">xxxxxxxxxx</Subject> <Subject xml:lang=\"es\">xxxxxxxxxx</Subject> <Text\n     * xml:lang=\"en\">xxxxxxxxxx</Text> <Text xml:lang=\"de\">xxxxxxxxxx</Text> <Text\n     * xml:lang=\"es\">xxxxxxxxxx</Text> <ButtonAccept xml:lang=\"en\">xxxxxxxxxx</ButtonAccept>\n     * <ButtonAccept xml:lang=\"de\">xxxxxxxxxx</ButtonAccept> <ButtonAccept\n     * xml:lang=\"es\">xxxxxxxxxx</ButtonAccept> <ButtonReject xml:lang=\"en\">xxxxxxxxxx</ButtonReject>\n     * <ButtonReject xml:lang=\"de\">xxxxxxxxxx</ButtonReject> <ButtonReject\n     * xml:lang=\"es\">xxxxxxxxxx</ButtonReject> </EndUserConfirmationRequest>\n     */\n\n    private static final String END_USER_CONFRIMATION_REQUEST_ELEMENT = \"EndUserConfirmationRequest\";\n\n    private static final String END_USER_NOTIFICATION_TYPE_VOLATILE = \"Volatile\";\n\n    private static final long DEFAULT_T1_TIMER_MULTIPLIER = 64;\n\n    private static final long TIMEOUT_INFINITE = -1;\n\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    /**\n     * Default language is English\n     */\n    private final static String DEFAULT_LANGUAGE = \"en\";\n\n    /**\n     * Char buffer for parsing text from one element\n     */\n    private StringBuffer mAccumulator;\n\n    /**\n     * Value off attribute 'id' off element 'EndUserConfirmationRequest'\n     */\n    private String mId;\n\n    /**\n     * Value off attribute 'type' off element 'EndUserNotification'\n     */\n    private String mType;\n\n    /**\n     * Value off attribute 'timeout' off element 'EndUserNotification'\n     */\n    private long mTimeout;\n\n    /**\n     * Value off attribute 'pin' off element 'EndUserConfirmationRequest'\n     */\n    private boolean mPin;\n\n    /**\n     * Requested language (given in constructor)\n     */\n    private String mRequestedLanguage;\n\n    /**\n     * Language from the first 'Subject' element\n     */\n    private String mFirstLanguage;\n\n    /**\n     * Flag if variable 'firstLanguage' is set\n     */\n    private boolean mIsFirstSubjectParsed = false;\n\n    /**\n     * Value of language attribute of current xml element during parsing\n     */\n    private String mCurrentLangAttribute;\n\n    /**\n     * HashMap<('ElementName' + 'Language'), text>\n     */\n    private HashMap<String, String> mElementMap = new HashMap<String, String>();\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private final RcsSettings mRcsSettings;\n\n    private final InputSource mInputSource;\n\n    /**\n     * Constructor\n     * \n     * @param inputSource Input source\n     * @param requestedLanguage\n     * @param rcsSettings\n     */\n    public TermsRequestParser(InputSource inputSource, String requestedLanguage,\n            RcsSettings rcsSettings) {\n        mRequestedLanguage = requestedLanguage;\n        mRcsSettings = rcsSettings;\n        mInputSource = inputSource;\n    }\n\n    /**\n     * Parse the terms request information\n     * \n     * @return TermsRequestParser\n     * @throws ParserConfigurationException\n     * @throws SAXException\n     * @throws ParseFailureException\n     */\n    public TermsRequestParser parse() throws ParserConfigurationException, SAXException,\n            ParseFailureException {\n        try {\n            SAXParserFactory factory = SAXParserFactory.newInstance();\n            SAXParser parser = factory.newSAXParser();\n            parser.parse(mInputSource, this);\n            return this;\n\n        } catch (IOException e) {\n            throw new ParseFailureException(\"Failed to parse input source!\", e);\n        }\n    }\n\n    public String getId() {\n        return mId;\n    }\n\n    public String getType() {\n        return mType;\n    }\n\n    public long getTimeout() {\n        return mTimeout;\n    }\n\n    public boolean getPin() {\n        return mPin;\n    }\n\n    public String getSubject() {\n        return giveTextInBestLanguage(\"Subject\");\n    }\n\n    public String getText() {\n        return giveTextInBestLanguage(\"Text\");\n    }\n\n    public String getButtonAccept() {\n        return giveTextInBestLanguage(\"ButtonAccept\");\n    }\n\n    public String getButtonReject() {\n        return giveTextInBestLanguage(\"ButtonReject\");\n    }\n\n    public void startDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"Start document 'EndUserConfirmationRequest'\");\n        }\n        mAccumulator = new StringBuffer();\n    }\n\n    @Override\n    public void characters(char buffer[], int start, int length) {\n        mAccumulator.append(buffer, start, length);\n    }\n\n    @Override\n    public void startElement(String namespaceURL, String localName, String qname, Attributes attr) {\n        mAccumulator.setLength(0);\n\n        if (END_USER_CONFRIMATION_REQUEST_ELEMENT.equals(localName)) {\n            mId = attr.getValue(\"id\").trim();\n            mType = attr.getValue(\"type\").trim();\n            if (END_USER_NOTIFICATION_TYPE_VOLATILE.equalsIgnoreCase(mType)) {\n                try {\n                    mTimeout = SECONDS_TO_MILLISECONDS_CONVERSION_RATE\n                            * Integer.parseInt(attr.getValue(\"timeout\").trim());\n                } catch (NumberFormatException e) {\n                    /*\n                     * If the attribute timeout is not present a default value of 64*T1 seconds\n                     * (with T1 as defined in [RFC3261]) shall be used\n                     */\n                    mTimeout = mRcsSettings.getSipTimerT1() * DEFAULT_T1_TIMER_MULTIPLIER;\n                }\n            } else { /* type.equalsIgnoreCase('Persistent') */\n                mTimeout = TIMEOUT_INFINITE;\n            }\n            String pinAttr = attr.getValue(\"pin\");\n            if (pinAttr != null) {\n                mPin = Boolean.parseBoolean(pinAttr.trim());\n            }\n        } else {\n            mCurrentLangAttribute = attr.getValue(\"xml:lang\");\n            if (mCurrentLangAttribute == null) {\n                mCurrentLangAttribute = attr.getValue(\"lang\");\n            }\n            if (mCurrentLangAttribute == null) {\n                mCurrentLangAttribute = \"\";\n            }\n            mCurrentLangAttribute = mCurrentLangAttribute.trim().toLowerCase();\n            if (!mIsFirstSubjectParsed) {\n                mIsFirstSubjectParsed = true;\n                mFirstLanguage = mCurrentLangAttribute;\n            }\n        }\n    }\n\n    @Override\n    public void endElement(String namespaceURL, String localName, String qname) {\n        if (END_USER_CONFRIMATION_REQUEST_ELEMENT.equals(localName)) {\n            if (logger.isActivated()) {\n                logger.debug(\"Terms request document is complete\");\n            }\n        } else if (mCurrentLangAttribute.equals(mRequestedLanguage)\n                || mCurrentLangAttribute.equals(DEFAULT_LANGUAGE)\n                || mCurrentLangAttribute.equals(mFirstLanguage) || mCurrentLangAttribute.equals(\"\")) {\n            mElementMap.put(qname + mCurrentLangAttribute, mAccumulator.toString().trim());\n        }\n    }\n\n    /**\n     * Returns text part off xml element, if found for requested language ('xml:lang' attribute ==\n     * requestedLanguage) or with 'xml:lang' is equal \"en\" (english) or with 'xml:lang' attribute\n     * equals to this from the first 'Subject' element or the text from the element with out any\n     * 'xml:lang' attribute or null if element not found\n     * \n     * @param elementName\n     * @return\n     */\n    private String giveTextInBestLanguage(String elementName) {\n        if (mElementMap.containsKey(elementName + mRequestedLanguage)) {\n            return mElementMap.get(elementName + mRequestedLanguage);\n        } else if (mElementMap.containsKey(elementName + DEFAULT_LANGUAGE)) {\n            return mElementMap.get(elementName + DEFAULT_LANGUAGE);\n        } else if (mElementMap.containsKey(elementName + mFirstLanguage)) {\n            return mElementMap.get(elementName + mFirstLanguage);\n        } else {\n            return mElementMap.get(elementName);\n        }\n    }\n\n    public void endDocument() {\n        if (logger.isActivated()) {\n            logger.debug(\"End document\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/upload/FileUploadSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.upload;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.HttpUploadManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.HttpUploadTransferEventListener;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\nimport java.util.UUID;\n\n/**\n * File upload session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileUploadSession extends Thread implements HttpUploadTransferEventListener {\n\n    private String mUploadId;\n\n    private MmContent mFile;\n\n    private boolean mFileIcon = false;\n\n    protected HttpUploadManager mUploadManager;\n\n    private FileUploadSessionListener mListener;\n\n    private FileTransferHttpInfoDocument mFileInfoDoc;\n\n    private final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(FileUploadSession.class.getName());\n\n    /**\n     * FileUploadSession state\n     */\n    public enum State {\n\n        /**\n         * Session is pending (not yet accepted by a final response to the first POST)\n         */\n        PENDING,\n\n        /**\n         * Session has been established (i.e. response OK to the first POST)\n         */\n        ESTABLISHED;\n    }\n\n    private State mSessionState;\n\n    /**\n     * Constructor\n     * \n     * @param file Content of file to upload\n     * @param fileIcon True if the stack must try to attach file icon\n     * @param rcsSettings\n     */\n    public FileUploadSession(MmContent file, boolean fileIcon, RcsSettings rcsSettings) {\n        super();\n        mSessionState = State.PENDING;\n        mFile = file;\n        mFileIcon = fileIcon;\n        mUploadId = UUID.randomUUID().toString();\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Add a listener event\n     * \n     * @param listener Listener\n     */\n    public void addListener(FileUploadSessionListener listener) {\n        mListener = listener;\n    }\n\n    /**\n     * Returns the unique upload ID\n     * \n     * @return ID\n     */\n    public String getUploadID() {\n        return mUploadId;\n    }\n\n    /**\n     * Gets the session state\n     * \n     * @return the session state\n     */\n    public State getSessionState() {\n        return mSessionState;\n    }\n\n    /**\n     * Returns the content to be uploaded\n     * \n     * @return Content\n     */\n    public MmContent getContent() {\n        return mFile;\n    }\n\n    /**\n     * Returns the file info document of the uploaded file on the content server\n     * \n     * @return XML document\n     */\n    public FileTransferHttpInfoDocument getFileInfoDocument() {\n        return mFileInfoDoc;\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Initiate a new HTTP upload \".concat(mUploadId));\n            }\n            /* Create fileIcon content is requested */\n            MmContent fileIconContent = null;\n            if (mFileIcon) {\n                fileIconContent = FileTransferUtils.createFileicon(mFile.getUri(), mUploadId,\n                        mRcsSettings);\n            }\n            mUploadManager = new HttpUploadManager(mFile, fileIconContent, this, mUploadId,\n                    mRcsSettings);\n            byte[] result = mUploadManager.uploadFile();\n            storeResult(result);\n        } catch (SecurityException e) {\n            sLogger.error(\n                    new StringBuilder(\n                            \"File icon creation has failed as the file is not accessible for HTTP uploadId \")\n                            .append(mUploadId).toString(), e);\n            removeSession();\n            mListener.handleUploadNotAllowedToSend();\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            removeSession();\n            mListener.handleUploadError(FileSharingError.MEDIA_UPLOAD_FAILED);\n        } catch (FileAccessException e) {\n            sLogger.error(new StringBuilder(\"Failed to initiate session for HTTP uploadId \")\n                    .append(mUploadId).toString(), e);\n            removeSession();\n            mListener.handleUploadError(FileSharingError.MEDIA_UPLOAD_FAILED);\n        } catch (PayloadException e) {\n            sLogger.error(new StringBuilder(\"Failed to initiate session for HTTP uploadId \")\n                    .append(mUploadId).toString(), e);\n            removeSession();\n            mListener.handleUploadError(FileSharingError.MEDIA_UPLOAD_FAILED);\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            removeSession();\n            mListener.handleUploadError(FileSharingError.MEDIA_UPLOAD_FAILED);\n        } catch (RuntimeException e) {\n            /*\n             * Intentionally catch runtime exceptions as else it will abruptly end the thread and\n             * eventually bring the whole system down, which is not intended.\n             */\n            sLogger.error(new StringBuilder(\"Failed to initiate session for HTTP uploadId \")\n                    .append(mUploadId).toString(), e);\n            removeSession();\n            mListener.handleUploadError(FileSharingError.MEDIA_UPLOAD_FAILED);\n        }\n    }\n\n    /**\n     * Analyze the result\n     * \n     * @param result Byte array result\n     * @throws PayloadException\n     */\n    private void storeResult(byte[] result) throws PayloadException {\n        // Check if upload has been cancelled\n        if (mUploadManager.isCancelled()) {\n            return;\n        }\n\n        // Parse the result:\n        // <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        // <file>\n        // <file-info type=\"thumbnail\">\n        // <file-size>6208</file-size>\n        // <content-type>image/jpeg</content-type>\n        // <data url = \"https://ftcontentserver.rcs/download?id=001\"\n        // until=\"2014-08-13T17:42:10.000+02:00\"/>\n        // </file-info>\n        //\n        // <file-info type=\"file\">\n        // <file-size>1699846</file-size>\n        // <file-name>IMG_20140805_134311.jpg</file-name>\n        // <content-type>image/jpeg</content-type>\n        // <data url = \"https://ftcontentserver.rcs/download?id=abb\"\n        // until=\"2014-08-13T17:42:10.000+02:00\"/>\n        // </file-info>\n        // </file>\n        if (result != null) {\n            mFileInfoDoc = FileTransferUtils.parseFileTransferHttpDocument(result, mRcsSettings);\n        }\n        if (mFileInfoDoc != null) {\n            // File uploaded with success\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Upload done with success: \".concat(mFileInfoDoc.getUri().toString()));\n            }\n\n            removeSession();\n            mListener.handleUploadTerminated(mFileInfoDoc);\n        } else {\n            // Upload error\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Upload has failed\");\n            }\n            removeSession();\n            // Notify listener\n            mListener.handleUploadError(FileSharingError.MEDIA_UPLOAD_FAILED);\n        }\n    }\n\n    /**\n     * Posts an interrupt request to this Thread\n     */\n    public void interrupt() {\n        super.interrupt();\n\n        // Interrupt the upload\n        mUploadManager.interrupt();\n\n        if (mFileInfoDoc == null) {\n            removeSession();\n            mListener.handleUploadAborted();\n        }\n    }\n\n    /**\n     * Notify the start of the HTTP Upload transfer (once the thumbnail transfer is done). <br>\n     * The upload resume is only possible once thumbnail is transferred\n     */\n    public void uploadStarted() {\n        mSessionState = State.ESTABLISHED;\n    }\n\n    /**\n     * HTTP transfer started\n     */\n    public void onHttpTransferStarted() {\n        // Notify listener\n        mListener.handleUploadStarted();\n    }\n\n    /**\n     * HTTP transfer paused by user\n     */\n    public void onHttpTransferPausedByUser() {\n        // Not used\n    }\n\n    /**\n     * HTTP transfer paused by system\n     */\n    public void onHttpTransferPausedBySystem() {\n        /*\n         * Paused by system will be called for generic exceptions occurring in the lower layers and\n         * in the scope of file upload this corresponds to failure since pause/resume does not exist\n         * for file upload\n         */\n        removeSession();\n    }\n\n    /**\n     * HTTP transfer paused\n     */\n    public void httpTransferPausedByRemote() {\n        // Not used\n    }\n\n    /**\n     * HTTP transfer resumed\n     */\n    public void onHttpTransferResumed() {\n        // Not used\n    }\n\n    /**\n     * HTTP transfer progress\n     * \n     * @param currentSize Current transfered size in bytes\n     * @param totalSize Total size in bytes\n     */\n    public void onHttpTransferProgress(long currentSize, long totalSize) {\n        // Notify listener\n        mListener.handleUploadProgress(currentSize, totalSize);\n    }\n\n    @Override\n    public void onHttpTransferNotAllowedToSend() {\n        removeSession();\n        mListener.handleUploadNotAllowedToSend();\n    }\n\n    /**\n     * Start session\n     */\n    public void startSession() {\n        Core.getInstance().getImService().addSession(this);\n        start();\n    }\n\n    /**\n     * Remove session\n     */\n    public void removeSession() {\n        Core.getInstance().getImService().removeSession(this);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/service/upload/FileUploadSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.service.upload;\n\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\n\n/**\n * File upload session listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface FileUploadSessionListener {\n    /**\n     * Upload started\n     */\n    public void handleUploadStarted();\n\n    /**\n     * Upload progress\n     * \n     * @param currentSize Data size transfered\n     * @param totalSize Total size to be transfered\n     */\n    public void handleUploadProgress(long currentSize, long totalSize);\n\n    /**\n     * Upload terminated with success\n     * \n     * @param info File info document\n     */\n    public void handleUploadTerminated(FileTransferHttpInfoDocument info);\n\n    /**\n     * Upload error\n     * \n     * @param error Error\n     */\n    public void handleUploadError(int error);\n\n    /**\n     * Upload aborted\n     */\n    public void handleUploadAborted();\n\n    /**\n     * Not allowed to send\n     */\n    public void handleUploadNotAllowedToSend();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/userprofile/GibaUserProfileInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.userprofile;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\n/**\n * User profile derived from IMSI\n * \n * @author JM. Auffret\n */\npublic class GibaUserProfileInterface extends UserProfileInterface {\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings\n     */\n    public GibaUserProfileInterface(RcsSettings rcsSettings) {\n        super();\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Read the user profile\n     * \n     * @return User profile\n     */\n    public UserProfile read() {\n        return new UserProfile(null, /* User name derived from GIBA procedure */\n        null, /* Domain derived from GIBA procedure */\n        null, /* No private ID with GIBA procedure */\n        null, /* No password with GIBA procedure */\n        null, /* No realm with GIBA procedure */\n        mRcsSettings.getXdmServer(), null, /* Login derived from GIBA procedure */\n        mRcsSettings.getUserProfileImsPassword(), mRcsSettings.getImConferenceUri(), mRcsSettings);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/userprofile/SettingsUserProfileInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.userprofile;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * User profile read from RCS settings database\n * \n * @author JM. Auffret\n */\npublic class SettingsUserProfileInterface extends UserProfileInterface {\n\n    private static final Logger sLogger = Logger.getLogger(SettingsUserProfileInterface.class\n            .getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings\n     */\n    public SettingsUserProfileInterface(RcsSettings rcsSettings) {\n        super();\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Read the user profile\n     * \n     * @return User profile\n     */\n    public UserProfile read() {\n        ContactId contact = mRcsSettings.getUserProfileImsUserName();\n        if (contact == null) {\n            if (sLogger.isActivated()) {\n                sLogger.error(\"IMS user name not provisioned\");\n            }\n            return null;\n\n        }\n        return new UserProfile(contact, mRcsSettings.getUserProfileImsDomain(),\n                mRcsSettings.getUserProfileImsPrivateId(),\n                mRcsSettings.getUserProfileImsPassword(), mRcsSettings.getUserProfileImsRealm(),\n                mRcsSettings.getXdmServer(), mRcsSettings.getXdmLogin(),\n                mRcsSettings.getXdmPassword(), mRcsSettings.getImConferenceUri(), mRcsSettings);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/userprofile/UserProfile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.userprofile;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.util.ListIterator;\n\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Header;\n\n/**\n * User profile\n * \n * @author JM. Auffret\n */\npublic class UserProfile {\n    /**\n     * User name\n     */\n    private ContactId mContact;\n\n    /**\n     * Private ID for HTTP digest\n     */\n    private String mPrivateID;\n\n    /**\n     * Password for HTTP digest\n     */\n    private String mPassword;\n\n    /**\n     * Realm for HTTP digest\n     */\n    private String mRealm;\n\n    /**\n     * Home domain\n     */\n    private String mHomeDomain;\n\n    /**\n     * XDM server address\n     */\n    private final Uri mXdmServerAddr;\n\n    /**\n     * XDM server login\n     */\n    private String mXdmServerLogin;\n\n    /**\n     * XDM server password\n     */\n    private final String mXdmServerPassword;\n\n    /**\n     * IM conference URI\n     */\n    private Uri mImConference;\n\n    /**\n     * Preferred URI\n     */\n    private Uri mPreferred;\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param contact Username\n     * @param homeDomain Home domain\n     * @param privateID Private id\n     * @param password Password\n     * @param realm Realm\n     * @param xdmServerAddr XDM server address\n     * @param xdmServerLogin Outbound proxy address\n     * @param xdmServerPassword Outbound proxy address\n     * @param rcsSettings the RCS settings accessor\n     */\n    public UserProfile(ContactId contact, String homeDomain, String privateID, String password,\n            String realm, Uri xdmServerAddr, String xdmServerLogin, String xdmServerPassword,\n            Uri imConference, RcsSettings rcsSettings) {\n        mContact = contact;\n        mHomeDomain = homeDomain;\n        mPrivateID = privateID;\n        mPassword = password;\n        mRealm = realm;\n        mXdmServerAddr = xdmServerAddr;\n        mXdmServerLogin = xdmServerLogin;\n        mXdmServerPassword = xdmServerPassword;\n        mImConference = imConference;\n        mRcsSettings = rcsSettings;\n        mPreferred = PhoneUtils.formatContactIdToUri(mContact);\n    }\n\n    /**\n     * Get the user name\n     * \n     * @return Username\n     */\n    public ContactId getUsername() {\n        return mContact;\n    }\n\n    /**\n     * Set the user name\n     * \n     * @param contact Contact Id\n     */\n    public void setUsername(ContactId contact) {\n        mContact = contact;\n    }\n\n    /**\n     * Get the user preferred URI\n     * \n     * @return Preferred URI\n     */\n    public Uri getPreferredUri() {\n        return mPreferred;\n    }\n\n    /**\n     * Get the user public URI\n     * \n     * @return Public URI\n     */\n    // @FIXME: This method should return URI instead of String\n    public String getPublicUri() {\n        if (mPreferred == null) {\n            return PhoneUtils.formatContactIdToUri(mContact).toString();\n        }\n        return mPreferred.toString();\n    }\n\n    private String formatAddressWithDisplayName(String displayName, String address) {\n        return \"\\\"\" + displayName + \"\\\" <\" + address + \">\";\n    }\n\n    private String formatAddressWithDisplayName(String displayName, ContactId contact) {\n        return \"\\\"\" + displayName + \"\\\" <\" + PhoneUtils.formatContactIdToUri(contact) + \">\";\n    }\n\n    /**\n     * Get the user public address\n     * \n     * @return Public address\n     */\n    public String getPublicAddress() {\n        String addr = getPublicUri();\n        String displayName = mRcsSettings.getUserProfileImsDisplayName();\n        if (TextUtils.isEmpty(displayName)) {\n            return addr;\n        }\n        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(addr);\n        if (number == null) {\n            return formatAddressWithDisplayName(displayName, addr);\n        }\n        ContactId me = ContactUtil.createContactIdFromValidatedData(number);\n        if (displayName.equals(me.toString())) {\n            /* Do no insert display name if it is equal to the international number */\n            return addr;\n        }\n        return formatAddressWithDisplayName(displayName, me);\n    }\n\n    /**\n     * Set the user associated URIs\n     * \n     * @param uris List of URIs\n     */\n    public void setAssociatedUri(ListIterator<Header> uris) {\n        if (uris == null) {\n            return;\n        }\n        String sipUri = null;\n        String telUri = null;\n        while (uris.hasNext()) {\n            ExtensionHeader header = (ExtensionHeader) uris.next();\n            String value = header.getValue();\n            value = SipUtils.extractUriFromAddress(value);\n\n            if (value.startsWith(PhoneUtils.SIP_URI_HEADER)) {\n                sipUri = value;\n            } else if (value.startsWith(PhoneUtils.TEL_URI_HEADER)) {\n                telUri = value;\n            }\n        }\n        if ((sipUri != null) && (telUri != null)) {\n            mPreferred = Uri.parse(telUri);\n        } else if (telUri != null) {\n            mPreferred = Uri.parse(telUri);\n        } else if (sipUri != null) {\n            mPreferred = Uri.parse(sipUri);\n        }\n    }\n\n    /**\n     * Get the private ID used for HTTP Digest authentication\n     * \n     * @return Private ID\n     */\n    public String getPrivateID() {\n        return mPrivateID;\n    }\n\n    /**\n     * Returns the password used for HTTP Digest authentication\n     * \n     * @return Password\n     */\n    public String getPassword() {\n        return mPassword;\n    }\n\n    /**\n     * Returns the realm used for HTTP Digest authentication\n     * \n     * @return Realm\n     */\n    public String getRealm() {\n        return mRealm;\n    }\n\n    /**\n     * Returns the home domain\n     * \n     * @return Home domain\n     */\n    public String getHomeDomain() {\n        return mHomeDomain;\n    }\n\n    /**\n     * Set the home domain\n     * \n     * @param domain Home domain\n     */\n    public void setHomeDomain(String domain) {\n        mHomeDomain = domain;\n    }\n\n    /**\n     * Returns the XDM server address\n     * \n     * @return Server address\n     */\n    public Uri getXdmServerAddr() {\n        return mXdmServerAddr;\n    }\n\n    /**\n     * Set the XDM server login\n     * \n     * @param login Login\n     */\n    public void setXdmServerLogin(String login) {\n        mXdmServerLogin = login;\n    }\n\n    /**\n     * Returns the XDM server login\n     * \n     * @return Login\n     */\n    public String getXdmServerLogin() {\n        return mXdmServerLogin;\n    }\n\n    /**\n     * Returns the XDM server password\n     * \n     * @return Password\n     */\n    public String getXdmServerPassword() {\n        return mXdmServerPassword;\n    }\n\n    /**\n     * Returns the IM conference URI\n     * \n     * @return URI\n     */\n    public Uri getImConferenceUri() {\n        return mImConference;\n    }\n\n    /**\n     * Returns the profile value as string\n     * \n     * @return String\n     */\n    public String toString() {\n        return \"IMS username=\" + mContact + \", \" + \"IMS private ID=\" + mPrivateID + \", \"\n                + \"IMS password=\" + mPassword + \", \" + \"IMS home domain=\" + mHomeDomain + \", \"\n                + \"XDM server=\" + mXdmServerAddr + \", \" + \"XDM login=\" + mXdmServerLogin + \", \"\n                + \"XDM password=\" + mXdmServerPassword + \", \" + \"IM Conference URI=\"\n                + mImConference;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/core/ims/userprofile/UserProfileInterface.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.ims.userprofile;\n\n/**\n * User profile interface\n * \n * @author jexa7410\n */\npublic abstract class UserProfileInterface {\n    /**\n     * Constructor\n     */\n    public UserProfileInterface() {\n    }\n\n    /**\n     * Read the user profile\n     * \n     * @return User profile\n     */\n    public abstract UserProfile read();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/AndroidFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform;\n\nimport android.content.Context;\n\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.platform.registry.RegistryFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\n/**\n * Android platform\n * \n * @author jexa7410\n */\npublic class AndroidFactory {\n\n    /**\n     * Android application context\n     */\n    private static Context mContext;\n\n    /**\n     * Returns the application context\n     * \n     * @return Context\n     */\n    public static Context getApplicationContext() {\n        return mContext;\n    }\n\n    /**\n     * Load factory\n     * \n     * @param context Context\n     * @param rcsSettings\n     */\n    public static void setApplicationContext(Context context, RcsSettings rcsSettings) {\n        mContext = context;\n        try {\n            NetworkFactory.loadFactory(\"com.gsma.rcs.platform.network.AndroidNetworkFactory\",\n                    rcsSettings);\n            RegistryFactory.loadFactory(\"com.gsma.rcs.platform.registry.AndroidRegistryFactory\");\n            FileFactory.loadFactory(\"com.gsma.rcs.platform.file.AndroidFileFactory\");\n        } catch (FactoryException e) {\n            throw new IllegalStateException(\"Failed to load factory instance!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/FactoryException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform;\n\n/**\n * Factory exception\n * \n * @author JM. Auffret\n */\npublic class FactoryException extends java.lang.Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message\n     * @param throwable\n     */\n    public FactoryException(String message, Throwable throwable) {\n        super(message, throwable);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/file/AndroidFileFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.file;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.media.MediaScannerConnection;\nimport android.media.MediaScannerConnection.MediaScannerConnectionClient;\nimport android.net.Uri;\n\nimport java.io.File;\n\n/**\n * Android file factory\n * \n * @author jexa7410\n */\npublic class AndroidFileFactory extends FileFactory {\n\n    private static final Logger sLogger = Logger\n            .getLogger(AndroidFileFactory.class.getSimpleName());\n\n    /**\n     * Returns the description of a file\n     * \n     * @param file URI of the file\n     * @return File description\n     */\n    public FileDescription getFileDescription(Uri file) {\n        Context context = AndroidFactory.getApplicationContext();\n        String fileName = FileUtils.getFileName(context, file);\n        long fileSize = FileUtils.getFileSize(context, file);\n        return new FileDescription(fileName, fileSize);\n    }\n\n    /**\n     * Returns whether a file exists or not\n     * \n     * @param url Url of the file to check\n     * @return File existence\n     */\n    public boolean fileExists(String url) {\n        File file = new File(url);\n        return file.exists();\n    }\n\n    /**\n     * Update the media storage\n     * \n     * @param url New URL to be added\n     */\n    public void updateMediaStorage(String url) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Updating media storage with URL \" + url);\n        }\n        MyMediaScannerClient scanner = new MyMediaScannerClient(url);\n        scanner.scan();\n    }\n\n    /**\n     * Media scanner\n     */\n    private class MyMediaScannerClient implements MediaScannerConnectionClient {\n        private String filename;\n\n        private MediaScannerConnection scanner;\n\n        public MyMediaScannerClient(String filename) {\n            this.filename = filename;\n            this.scanner = new MediaScannerConnection(AndroidFactory.getApplicationContext(), this);\n        }\n\n        public void onMediaScannerConnected() {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Scanning file \" + filename);\n            }\n            scanner.scanFile(filename, null);\n        }\n\n        public void onScanCompleted(String path, Uri uri) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Scan completed for uri \" + uri + \" with path \" + path);\n            }\n            if (path.equals(filename)) {\n                scanner.disconnect();\n            }\n        }\n\n        public void scan() {\n            scanner.connect();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/file/FileDescription.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.file;\n\n/**\n * File description\n * \n * @author jexa7410\n */\npublic class FileDescription {\n\n    private String mName;\n\n    private long mSize = -1;\n\n    private boolean mDirectory = false;\n\n    /**\n     * Constructor\n     */\n    public FileDescription(String name, long size) {\n        mName = name;\n        mSize = size;\n    }\n\n    /**\n     * Constructor\n     */\n    public FileDescription(String name, long size, boolean directory) {\n        mName = name;\n        mSize = size;\n        mDirectory = directory;\n    }\n\n    /**\n     * Returns the size of the file\n     * \n     * @return File size\n     */\n    public long getSize() {\n        return mSize;\n    }\n\n    /**\n     * Returns the name of the file\n     * \n     * @return File name\n     */\n    public String getName() {\n        return mName;\n    }\n\n    /**\n     * Returns the size of the file\n     * \n     * @return File size\n     */\n    public boolean isDirectory() {\n        return mDirectory;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/file/FileFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.file;\n\nimport com.gsma.rcs.platform.FactoryException;\n\nimport android.net.Uri;\n\nimport java.io.File;\nimport java.io.IOException;\n\n/**\n * File factory\n * \n * @author jexa7410\n */\npublic abstract class FileFactory {\n\n    private static final String NO_MEDIA = \".nomedia\";\n    /**\n     * Current platform factory\n     */\n    private static FileFactory mFactory;\n\n    public static final String SENT_DIRECTORY = \"sent/\";\n\n    /**\n     * Load the factory\n     * \n     * @param classname Factory classname\n     * @throws FactoryException\n     */\n    public static void loadFactory(String classname) throws FactoryException {\n        if (mFactory != null) {\n            return;\n        }\n        try {\n            mFactory = (FileFactory) Class.forName(classname).newInstance();\n        } catch (InstantiationException e) {\n            throw new FactoryException(\"Can't load the factory \" + classname, e);\n\n        } catch (IllegalAccessException e) {\n            throw new FactoryException(\"Can't load the factory \" + classname, e);\n\n        } catch (ClassNotFoundException e) {\n            throw new FactoryException(\"Can't load the factory \" + classname, e);\n        }\n    }\n\n    /**\n     * Returns the current factory\n     * \n     * @return Factory\n     */\n    public static FileFactory getFactory() {\n        return mFactory;\n    }\n\n    /**\n     * Returns the description of a file\n     * \n     * @param file URI of the file\n     * @return File description\n     */\n    public abstract FileDescription getFileDescription(Uri file);\n\n    /**\n     * Update the media storage\n     * \n     * @param url New URL to be added\n     */\n    public abstract void updateMediaStorage(String url);\n\n    /**\n     * Returns whether a file exists or not\n     * \n     * @param url Url of the file to check\n     * @return File existence\n     */\n    public abstract boolean fileExists(String url);\n\n    /**\n     * Create a directory if not already exist\n     * \n     * @param path Directory path\n     * @return true if the directory exists or is created\n     */\n    public static boolean createDirectory(String path) {\n        File dir = new File(path);\n        if (!dir.exists()) {\n            if (!dir.mkdirs()) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Creates a .nomedia file if not already exist\n     * \n     * @param path Directory path\n     * @throws IOException\n     */\n    public static void setNoMedia(String path) throws IOException {\n        File file = new File(path.concat(NO_MEDIA));\n        file.createNewFile();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/logger/AndroidAppender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.logger;\n\nimport android.util.Log;\n\nimport com.gsma.rcs.utils.logger.Appender;\nimport com.gsma.rcs.utils.logger.Logger;\n\n/**\n * Android appender\n * \n * @author jexa7410\n */\npublic class AndroidAppender extends Appender {\n    /**\n     * Constructor\n     */\n    public AndroidAppender() {\n        super();\n    }\n\n    /**\n     * Print a trace\n     * \n     * @param classname Classname\n     * @param level Trace level\n     * @param trace Trace\n     */\n    public synchronized void printTrace(String classname, int level, String trace) {\n        classname = \"[RCS][\" + classname + \"]\";\n\n        if (level == Logger.INFO_LEVEL) {\n            Log.i(classname, trace);\n        } else if (level == Logger.WARN_LEVEL) {\n            Log.w(classname, trace);\n        } else if (level == Logger.ERROR_LEVEL) {\n            Log.e(classname, trace);\n        } else if (level == Logger.FATAL_LEVEL) {\n            Log.e(classname, trace);\n        } else {\n            Log.v(classname, trace);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/AndroidDatagramConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\n\n/**\n * Android datagram server connection\n * \n * @author jexa7410\n */\npublic class AndroidDatagramConnection implements DatagramConnection {\n    /**\n     * Datagram connection\n     */\n    private DatagramSocket connection = null;\n\n    /**\n     * Datagram Packet\n     */\n    private DatagramPacket packet = null;\n\n    /**\n     * Connection timeout\n     */\n    private int timeout = 0;\n\n    /**\n     * Constructor\n     */\n    public AndroidDatagramConnection() {\n        packet = new DatagramPacket(new byte[DatagramConnection.DEFAULT_DATAGRAM_SIZE],\n                DatagramConnection.DEFAULT_DATAGRAM_SIZE);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param timeout SO Timeout\n     */\n    public AndroidDatagramConnection(int timeout) {\n        this();\n        this.timeout = timeout;\n    }\n\n    /**\n     * Open the datagram connection\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException {\n        connection = new DatagramSocket();\n        connection.setSoTimeout(timeout);\n    }\n\n    /**\n     * Open the datagram connection\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException {\n        connection = new DatagramSocket(port);\n        connection.setSoTimeout(timeout);\n    }\n\n    /**\n     * Close the datagram connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (connection != null) {\n            connection.close();\n            connection = null;\n        }\n    }\n\n    /**\n     * Receive data with a specific buffer size\n     * \n     * @return Byte array\n     * @throws NetworkException\n     */\n    public byte[] receive() throws NetworkException {\n        try {\n            packet.setLength(DatagramConnection.DEFAULT_DATAGRAM_SIZE);\n            connection.receive(packet);\n            int packetLength = packet.getLength();\n            byte[] data = new byte[packetLength];\n            System.arraycopy(packet.getData(), 0, data, 0, packetLength);\n            return data;\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to receive datagram packet!\", e);\n        }\n    }\n\n    /**\n     * Send data\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @param data Data as byte array\n     * @throws NetworkException\n     */\n    public void send(String remoteAddr, int remotePort, byte[] data) throws NetworkException {\n        try {\n            InetAddress address = InetAddress.getByName(remoteAddr);\n            DatagramPacket packet = new DatagramPacket(data, data.length, address, remotePort);\n            connection.send(packet);\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\"Failed to send data to remoteAddr : \")\n                    .append(remoteAddr).toString(), e);\n        }\n\n    }\n\n    /**\n     * Returns the local address\n     * \n     * @return Address\n     * @throws IOException\n     */\n    public String getLocalAddress() throws IOException {\n        if ((connection != null) && (connection.getLocalAddress() != null)) {\n            return connection.getLocalAddress().getHostAddress();\n        }\n        throw new IOException(\"Connection not opened\");\n    }\n\n    /**\n     * Returns the local port\n     * \n     * @return Port\n     * @throws IOException\n     */\n    public int getLocalPort() throws IOException {\n        if (connection != null) {\n            return connection.getLocalPort();\n        }\n        throw new IOException(\"Connection not opened\");\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/AndroidHttpConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\n/**\n * Android HTTP connection\n * \n * @author jexa7410\n */\npublic class AndroidHttpConnection implements HttpConnection {\n    /**\n     * HTTP connection\n     */\n    private HttpURLConnection connection = null;\n\n    /**\n     * Open the HTTP connection\n     * \n     * @param url Remote URL\n     * @throws IOException\n     */\n    public void open(String url) throws IOException {\n        URL urlConn = new URL(url);\n        connection = (HttpURLConnection) urlConn.openConnection();\n        connection.connect();\n    }\n\n    /**\n     * Close the HTTP connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (connection != null) {\n            connection.disconnect();\n        }\n    }\n\n    /**\n     * HTTP GET request\n     * \n     * @return Response\n     * @throws IOException\n     */\n    public ByteArrayOutputStream get() throws IOException {\n        if (connection != null) {\n            return sendHttpRequest(HttpConnection.GET_METHOD);\n        }\n        throw new IOException(\"Connection not opened\");\n    }\n\n    /**\n     * HTTP POST request\n     * \n     * @return Response\n     * @throws IOException\n     */\n    public ByteArrayOutputStream post() throws IOException {\n        if (connection != null) {\n            return sendHttpRequest(HttpConnection.POST_METHOD);\n        }\n        throw new IOException(\"Connection not opened\");\n    }\n\n    /**\n     * Send HTTP request\n     * \n     * @param method HTTP method\n     * @return Response\n     * @throws IOException\n     */\n    private ByteArrayOutputStream sendHttpRequest(String method) throws IOException {\n        connection.setRequestMethod(method);\n        int rc = connection.getResponseCode();\n        if (rc != HttpURLConnection.HTTP_OK) {\n            throw new IOException(\"HTTP error \" + rc);\n        }\n\n        InputStream inputStream = connection.getInputStream();\n        ByteArrayOutputStream result = new ByteArrayOutputStream();\n        int ch;\n        while ((ch = inputStream.read()) != -1) {\n            result.write(ch);\n        }\n        inputStream.close();\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/AndroidNetworkFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface.DnsResolvedFields;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.InetAddressUtils;\nimport com.gsma.rcs.utils.IpAddressUtils;\n\nimport android.net.ConnectivityManager;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.Enumeration;\n\n/**\n * Android network factory\n * \n * @author jexa7410\n */\npublic class AndroidNetworkFactory extends NetworkFactory {\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings\n     */\n    public AndroidNetworkFactory(RcsSettings rcsSettings) {\n        super();\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Returns the local IP address of a given network interface\n     * \n     * @param dnsEntry remote address to find an according local socket address\n     * @param type the type of the network interface, should be either\n     *            {@link android.net.ConnectivityManager#TYPE_WIFI} or\n     *            {@link android.net.ConnectivityManager#TYPE_MOBILE}\n     * @return Address\n     */\n    // Changed by Deutsche Telekom\n    public String getLocalIpAddress(DnsResolvedFields dnsEntry, int type) throws SocketException {\n        /* What kind of remote address (P-CSCF) are we trying to reach? */\n        boolean isIpv4 = dnsEntry != null ? InetAddressUtils.isIPv4Address(dnsEntry.mIpAddress)\n                : true;\n        for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); (en != null)\n                && en.hasMoreElements();) {\n            NetworkInterface netIntf = en.nextElement();\n            for (Enumeration<InetAddress> addr = netIntf.getInetAddresses(); addr.hasMoreElements();) {\n                InetAddress inetAddress = addr.nextElement();\n                String ipAddress = IpAddressUtils.extractHostAddress(inetAddress.getHostAddress());\n                if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()\n                        && (InetAddressUtils.isIPv4Address(ipAddress) == isIpv4)) {\n                    String intfName = netIntf.getDisplayName().toLowerCase();\n                    /* Some devices do list several interfaces though only one is active */\n                    if (((type == ConnectivityManager.TYPE_WIFI) && intfName.startsWith(\"wlan\"))\n                            || ((type == ConnectivityManager.TYPE_MOBILE) && !intfName\n                                    .startsWith(\"wlan\"))) {\n                        return ipAddress;\n                    }\n                }\n            }\n        }\n        throw new SocketException(new StringBuilder(\"Unable to fetch local ip address for type : \")\n                .append(type).append(\"!\").toString());\n    }\n\n    /**\n     * Create a datagram connection\n     * \n     * @return Datagram connection\n     */\n    public DatagramConnection createDatagramConnection() {\n        return new AndroidDatagramConnection();\n    }\n\n    /**\n     * Create a datagram connection with a specific SO timeout\n     * \n     * @param timeout SO timeout\n     * @return Datagram connection\n     */\n    public DatagramConnection createDatagramConnection(int timeout) {\n        return new AndroidDatagramConnection(timeout);\n    }\n\n    /**\n     * Create a socket client connection\n     * \n     * @return Socket connection\n     */\n    public SocketConnection createSocketClientConnection() {\n        return new AndroidSocketConnection();\n    }\n\n    /**\n     * Create a secure socket client connection\n     * \n     * @return Socket connection\n     */\n    public SocketConnection createSecureSocketClientConnection() {\n        return new AndroidSecureSocketConnection(mRcsSettings);\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Create a secure socket client connection w/o checking certificates\n     * \n     * @param fingerprint\n     * @return Socket connection\n     */\n    public SocketConnection createSimpleSecureSocketClientConnection(String fingerprint) {\n        return new AndroidSecureSocketConnection(fingerprint, mRcsSettings);\n    }\n\n    /**\n     * Create a socket server connection\n     * \n     * @return Socket server connection\n     */\n    public SocketServerConnection createSocketServerConnection() {\n        return new AndroidSocketServerConnection();\n    }\n\n    /**\n     * Create an HTTP connection\n     * \n     * @return HTTP connection\n     */\n    public HttpConnection createHttpConnection() {\n        return new AndroidHttpConnection();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/AndroidSecureSocketConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.security.cert.KeyStoreManager;\nimport com.gsma.rcs.core.ims.security.cert.X509KeyManagerWrapper;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provisioning.https.EasyX509TrustManager;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateException;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLPeerUnverifiedException;\nimport javax.net.ssl.SSLSession;\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport javax2.sip.ListeningPoint;\n\n/**\n * Android secure socket connection\n * \n * @author jexa7410\n */\npublic class AndroidSecureSocketConnection extends AndroidSocketConnection {\n    // Changed by Deutsche Telekom\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    /**\n     * SSL factory\n     */\n    // Changed by Deutsche Telekom\n    // TODO: check why this was static before\n    private SSLSocketFactory mSslSocketFactory;\n\n    // Changed by Deutsche Telekom\n    /**\n     * usage of certificate checks\n     */\n    private boolean mCheckCertificate = true;\n\n    // Changed by Deutsche Telekom\n    /**\n     * announced fingerprint\n     */\n    private String mFingerprint;\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings\n     */\n    public AndroidSecureSocketConnection(RcsSettings rcsSettings) {\n        super();\n        mRcsSettings = rcsSettings;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Constructor\n     * \n     * @param fingerprint\n     * @param rcsSettings\n     */\n    public AndroidSecureSocketConnection(String fingerprint, RcsSettings rcsSettings) {\n        super();\n        mCheckCertificate = false;\n        mFingerprint = fingerprint;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param socket SSL socket\n     * @param rcsSettings\n     */\n    public AndroidSecureSocketConnection(SSLSocket socket, RcsSettings rcsSettings) {\n        super(socket);\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Open the socket\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void open(String remoteAddr, int remotePort) throws NetworkException,\n            PayloadException {\n        SSLSocket socket = null;\n        try {\n        // Changed by Deutsche Telekom\n            socket = (SSLSocket) getSslFactory().createSocket(remoteAddr, remotePort);\n        // Changed by Deutsche Telekom\n            socket.startHandshake();\n            if (mFingerprint != null) {\n                // example of a fingerprint:\n                // SHA-1 4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\n                String[] announcedFingerprintElements = mFingerprint.split(\" \");\n                if (announcedFingerprintElements != null && announcedFingerprintElements.length > 1) {\n                    // use the same hashing algorithm as announced\n                    String usedFingerprint = getFingerprint(announcedFingerprintElements[0], socket);\n                    // compare fingerprints and stop if not matching\n                    if (announcedFingerprintElements[1] != null\n                            && !announcedFingerprintElements[1].equals(usedFingerprint)) {\n                        if (logger.isActivated()) {\n                            logger.debug(\"Wrong fingerprint! \" + usedFingerprint\n                                    + \" is used while \" + announcedFingerprintElements[1]\n                                    + \" is expected!\");\n                        }\n                        /* Close the socket as an attack is assumed */\n                        CloseableUtils.tryToClose(socket);\n                        return;\n                    }\n                }\n            }\n            setSocket(socket);\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\n                    \"Failed to open socket connection for address : \").append(remoteAddr)\n                    .append(\"and port : \").append(remotePort).toString(), e);\n        } finally {\n            CloseableUtils.tryToClose(socket);\n        }\n\n    }\n\n    /**\n     * Get the certificate fingerprint\n     * \n     * @param algorithm hash algorithm to be used\n     * @param socket\n     * @return String\n     * @throws SSLPeerUnverifiedException\n     * @throws PayloadException\n     */\n    private String getFingerprint(String algorithm, SSLSocket socket)\n            throws SSLPeerUnverifiedException, PayloadException {\n        try {\n            final SSLSession session = socket.getSession();\n            if (session == null) {\n                throw new SSLPeerUnverifiedException(\"SSL session not available!\");\n            }\n            Certificate[] certs = session.getPeerCertificates();\n            if (logger.isActivated()) {\n                logger.debug(\"Remote certificate chain length: \" + certs.length);\n            }\n            if (certs.length == 0) {\n                throw new SSLPeerUnverifiedException(\n                        \"No remote certificates available for SSL session!\");\n            }\n            return KeyStoreManager.getCertFingerprint(certs[0], algorithm);\n\n        } catch (CertificateEncodingException e) {\n            throw new PayloadException(\"SSL session not available!\", e);\n\n        } catch (NoSuchAlgorithmException e) {\n            throw new PayloadException(\"SSL session not available!\", e);\n        }\n    }\n\n    /**\n     * Returns the SSL factory instance\n     * \n     * @param checkCertificate flag to indicate whether the remote certificate will be checked\n     * @return SSL factory\n     * @throws IOException\n     */\n    // Changed by Deutsche Telekom\n    // TODO: check why this was static before\n    private synchronized SSLSocketFactory getSslFactory() throws IOException {\n        // Changed by Deutsche Telekom\n        FileInputStream ksFileInputStream = null;\n        FileInputStream tsFileInputStream = null;\n        if (mSslSocketFactory == null) {\n            try {\n                // Changed by Deutsche Telekom\n                if (logger.isActivated()) {\n                    logger.debug(\"Create SSLSocketFactory\");\n                }\n                TrustManager[] tms = null;\n                KeyManager[] kms = null;\n\n                String keyStoreType = KeyStoreManager.getKeystoreType();\n                KeyStore keyStore = KeyStore.getInstance(keyStoreType);\n\n                String keyStoreFile = KeyStoreManager.getKeystore().getPath();\n                ksFileInputStream = new FileInputStream(keyStoreFile);\n\n                char[] keyStorePassword = KeyStoreManager.getKeystorePassword().toCharArray();\n                keyStore.load(ksFileInputStream, keyStorePassword);\n\n                String algorithm = KeyManagerFactory.getDefaultAlgorithm();\n\n                if (mCheckCertificate) {\n                    // only use trusted certificates terminating on a well-known root CA\n                    TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(algorithm);\n\n                    if (KeyStoreManager.isOwnCertificateUsed(mRcsSettings)) {\n                        KeyStore trustStore = KeyStore.getInstance(keyStoreType);\n                        // Changed by Deutsche Telekom\n                        tsFileInputStream = new FileInputStream(keyStoreFile);\n                        trustStore.load(tsFileInputStream, keyStorePassword);\n                        tmFactory.init(trustStore);\n\n                        KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(algorithm);\n                        kmFactory.init(keyStore, keyStorePassword);\n                        kms = kmFactory.getKeyManagers();\n                    } else {\n                        tmFactory.init((KeyStore) null);\n                    }\n                    tms = tmFactory.getTrustManagers();\n                } else {\n                    // use an own TrustManager to allow the usage of self-signed certificates\n                    // Changed by Deutsche Telekom\n                    if (logger.isActivated()) {\n                        logger.debug(\"Use self-signed certificates\");\n                    }\n                    KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(algorithm);\n                    kmFactory.init(keyStore, keyStorePassword);\n                    kms = kmFactory.getKeyManagers();\n\n                    // overwrite 1st key manager with own wrapper to work around\n                    // certificate request for unknown issuers\n                    KeyManager km = new X509KeyManagerWrapper(kms);\n                    kms[0] = km;\n\n                    tms = new TrustManager[] {\n                        new EasyX509TrustManager(null)\n                    };\n                }\n                SecureRandom secureRandom = new SecureRandom();\n                secureRandom.nextInt();\n                SSLContext sslContext = SSLContext.getInstance(ListeningPoint.TLS);\n                sslContext.init(kms, tms, secureRandom);\n                mSslSocketFactory = sslContext.getSocketFactory();\n            } catch (NoSuchAlgorithmException e) {\n                throw new IOException(\n                        \"Unable to create SSL instance for service type :  \"\n                                .concat(ListeningPoint.TLS),\n                        e);\n\n            } catch (KeyStoreException e) {\n                throw new IOException(\n                        \"Unable to create SSL instance for service type :  \"\n                                .concat(ListeningPoint.TLS),\n                        e);\n\n            } catch (CertificateException e) {\n                throw new IOException(\n                        \"Unable to create SSL instance for service type :  \"\n                                .concat(ListeningPoint.TLS),\n                        e);\n\n            } catch (UnrecoverableKeyException e) {\n                throw new IOException(\n                        \"Unable to create SSL instance for service type :  \"\n                                .concat(ListeningPoint.TLS),\n                        e);\n\n            } catch (KeyManagementException e) {\n                throw new IOException(\n                        \"Unable to create SSL instance for service type :  \"\n                                .concat(ListeningPoint.TLS),\n                        e);\n\n            } finally {\n                CloseableUtils.tryToClose(ksFileInputStream);\n                CloseableUtils.tryToClose(tsFileInputStream);\n            }\n        }\n        return mSslSocketFactory;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/AndroidSocketConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\n\n/**\n * Android socket connection\n * \n * @author jexa7410\n */\npublic class AndroidSocketConnection implements SocketConnection {\n    /**\n     * Socket connection\n     */\n    private Socket mSocket;\n\n    /**\n     * Constructor\n     */\n    public AndroidSocketConnection() {\n    }\n\n    /**\n     * Constructor\n     * \n     * @param socket Socket\n     */\n    public AndroidSocketConnection(Socket socket) {\n        this.mSocket = socket;\n    }\n\n    /**\n     * Open the socket\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void open(String remoteAddr, int remotePort) throws NetworkException, PayloadException {\n        try {\n            mSocket = new Socket(remoteAddr, remotePort);\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\"Failed to open socket for address : \")\n                    .append(remoteAddr).append(\" and port : \").append(remotePort).toString(), e);\n        }\n    }\n\n    /**\n     * Set the socket\n     * \n     * @param socket Socket\n     */\n    public void setSocket(Socket socket) {\n        this.mSocket = socket;\n    }\n\n    /**\n     * Get the socket\n     * \n     * @return Socket\n     */\n    public Socket getSocket() {\n        return this.mSocket;\n    }\n\n    /**\n     * Close the socket\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (mSocket != null) {\n            mSocket.close();\n            mSocket = null;\n        }\n    }\n\n    /**\n     * Returns the socket input stream\n     * \n     * @return Input stream\n     * @throws NetworkException\n     */\n    public InputStream getInputStream() throws NetworkException {\n        try {\n            return mSocket.getInputStream();\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to get input stream from connection!\", e);\n        }\n    }\n\n    /**\n     * Returns the socket output stream\n     * \n     * @return Output stream\n     * @throws NetworkException\n     */\n    public OutputStream getOutputStream() throws NetworkException {\n        try {\n            return mSocket.getOutputStream();\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to get output stream from connection!\", e);\n        }\n    }\n\n    /**\n     * Returns the remote address of the connection\n     * \n     * @return Address\n     */\n    public String getRemoteAddress() {\n        return mSocket.getInetAddress().getHostAddress();\n    }\n\n    /**\n     * Returns the remote port of the connection\n     * \n     * @return Port\n     */\n    public int getRemotePort() {\n        return mSocket.getPort();\n    }\n\n    /**\n     * Returns the local address of the connection\n     * \n     * @return Address\n     */\n    public String getLocalAddress() {\n        return mSocket.getLocalAddress().getHostAddress();\n    }\n\n    /**\n     * Returns the local port of the connection\n     * \n     * @return Port\n     */\n    public int getLocalPort() {\n        return mSocket.getLocalPort();\n    }\n\n    /**\n     * Get the timeout for this socket during which a reading operation shall block while waiting\n     * for data\n     * \n     * @return Timeout in milliseconds\n     * @throws NetworkException\n     */\n    public int getSoTimeout() throws NetworkException {\n        try {\n            return mSocket.getSoTimeout();\n\n        } catch (IOException e) {\n            throw new NetworkException(\"Failed to get socket timeout!\", e);\n        }\n    }\n\n    /**\n     * Set the timeout for this socket during which a reading operation shall block while waiting\n     * for data\n     * \n     * @param timeout Timeout in milliseconds\n     * @throws NetworkException\n     */\n    public void setSoTimeout(long timeout) throws NetworkException {\n        try {\n            /* NOTE: External API limiting timeout that should be in type 'long' to 'int'. */\n            mSocket.setSoTimeout((int) timeout);\n        } catch (IOException e) {\n            throw new NetworkException(new StringBuilder(\"Failed to set socket timeout : \").append(\n                    timeout).toString(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/AndroidSocketServerConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\n/**\n * Android socket connection\n * \n * @author jexa7410\n */\npublic class AndroidSocketServerConnection implements SocketServerConnection {\n    /**\n     * Socket server connection\n     */\n    private ServerSocket mAcceptSocket;\n\n    private static final Logger sLogger = Logger.getLogger(AndroidSocketServerConnection.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     */\n    public AndroidSocketServerConnection() {\n    }\n\n    /**\n     * Open the socket\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException {\n        mAcceptSocket = new ServerSocket(port);\n    }\n\n    /**\n     * Close the socket\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (mAcceptSocket != null) {\n            mAcceptSocket.close();\n            mAcceptSocket = null;\n        }\n    }\n\n    /**\n     * Accept connection\n     * \n     * @return Socket connection\n     * @throws IOException\n     */\n    public SocketConnection acceptConnection() throws IOException {\n        if (mAcceptSocket != null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Socket serverSocket is waiting for incoming connection\");\n            }\n            Socket socket = mAcceptSocket.accept();\n            return new AndroidSocketConnection(socket);\n        }\n        throw new IOException(\"Connection not opened\");\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/DatagramConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * Datagram connection\n * \n * @author jexa7410\n */\npublic interface DatagramConnection extends Closeable {\n    /**\n     * Default datagram packet size\n     */\n    public static int DEFAULT_DATAGRAM_SIZE = 4096 * 8;\n\n    /**\n     * Open the datagram connection\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException;\n\n    /**\n     * Open the datagram connection\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException;\n\n    /**\n     * Close the datagram connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException;\n\n    /**\n     * Send data\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @param data Data as byte array\n     * @throws NetworkException\n     */\n    public void send(String remoteAddr, int remotePort, byte[] data) throws NetworkException;\n\n    /**\n     * Receive data\n     * \n     * @return Byte array\n     * @throws NetworkException\n     */\n    public byte[] receive() throws NetworkException;\n\n    /**\n     * Returns the local address\n     * \n     * @return Address\n     * @throws IOException\n     */\n    public String getLocalAddress() throws IOException;\n\n    /**\n     * Returns the local port\n     * \n     * @return Port\n     * @throws IOException\n     */\n    public int getLocalPort() throws IOException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/HttpConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * HTTP connection\n * \n * @author jexa7410\n */\npublic interface HttpConnection {\n    /**\n     * GET method\n     */\n    public final static String GET_METHOD = \"GET\";\n\n    /**\n     * POST method\n     */\n    public final static String POST_METHOD = \"POST\";\n\n    /**\n     * Open the HTTP connection\n     * \n     * @param url Remote URL\n     * @throws IOException\n     */\n    public void open(String url) throws IOException;\n\n    /**\n     * Close the HTTP connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException;\n\n    /**\n     * HTTP GET request\n     * \n     * @return Response\n     * @throws IOException\n     */\n    public ByteArrayOutputStream get() throws IOException;\n\n    /**\n     * HTTP POST request\n     * \n     * @return Response\n     * @throws IOException\n     */\n    public ByteArrayOutputStream post() throws IOException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/NetworkFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface.DnsResolvedFields;\nimport com.gsma.rcs.platform.FactoryException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.net.SocketException;\n\n/**\n * Network factory\n * \n * @author jexa7410\n */\npublic abstract class NetworkFactory {\n    /**\n     * Current platform factory\n     */\n    private static NetworkFactory mFactory;\n\n    /**\n     * Load the factory\n     * \n     * @param classname\n     * @param rcsSettings\n     * @throws FactoryException\n     */\n    public static void loadFactory(String classname, RcsSettings rcsSettings)\n            throws FactoryException {\n        if (mFactory != null) {\n            return;\n        }\n        Class<?>[] rcsSettingsArgsClass = new Class[] {\n            RcsSettings.class\n        };\n        Object[] rcsSettingsArgs = new Object[] {\n            rcsSettings\n        };\n        try {\n            mFactory = (NetworkFactory) Class.forName(classname)\n                    .getConstructor(rcsSettingsArgsClass).newInstance(rcsSettingsArgs);\n        } catch (InstantiationException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n\n        } catch (IllegalAccessException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n\n        } catch (InvocationTargetException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n\n        } catch (NoSuchMethodException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n\n        } catch (ClassNotFoundException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n        }\n    }\n\n    /**\n     * Returns the current factory\n     * \n     * @return Factory\n     */\n    public static NetworkFactory getFactory() {\n        return mFactory;\n    }\n\n    /**\n     * Returns the local IP address of a given network interface\n     * \n     * @param dnsEntry address to be connected to\n     * @param type the type of the network interface, should be either\n     *            {@link android.net.ConnectivityManager#TYPE_WIFI} or\n     *            {@link android.net.ConnectivityManager#TYPE_MOBILE}\n     * @return Address\n     * @throws SocketException\n     */\n    // Changed by Deutsche Telekom\n    public abstract String getLocalIpAddress(DnsResolvedFields dnsEntry, int type)\n            throws SocketException;\n\n    /**\n     * Create a datagram connection\n     * \n     * @return Datagram connection\n     */\n    public abstract DatagramConnection createDatagramConnection();\n\n    /**\n     * Create a datagram connection with a specific SO timeout\n     * \n     * @param timeout SO timeout\n     * @return Datagram connection\n     */\n    public abstract DatagramConnection createDatagramConnection(int timeout);\n\n    /**\n     * Create a socket client connection\n     * \n     * @return Socket connection\n     */\n    public abstract SocketConnection createSocketClientConnection();\n\n    /**\n     * Create a secure socket client connection\n     * \n     * @return Socket connection\n     */\n    public abstract SocketConnection createSecureSocketClientConnection();\n\n    // Changed By Deutsche Telekom\n    /**\n     * Create a secure socket client connection w/o checking certificates\n     * \n     * @param fingerprint\n     * @return Socket connection\n     */\n    public abstract SocketConnection createSimpleSecureSocketClientConnection(String fingerprint);\n\n    /**\n     * Create a socket server connection\n     * \n     * @return Socket server connection\n     */\n    public abstract SocketServerConnection createSocketServerConnection();\n\n    /**\n     * Create an HTTP connection\n     * \n     * @return HTTP connection\n     */\n    public abstract HttpConnection createHttpConnection();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/SocketConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Socket client connection\n * \n * @author jexa7410\n */\npublic interface SocketConnection extends Closeable {\n    /**\n     * Open the socket\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void open(String remoteAddr, int remotePort) throws PayloadException, NetworkException;\n\n    /**\n     * Close the socket\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException;\n\n    /**\n     * Returns the socket input stream\n     * \n     * @return Input stream\n     * @throws NetworkException\n     */\n    public InputStream getInputStream() throws NetworkException;\n\n    /**\n     * Returns the socket output stream\n     * \n     * @return Output stream\n     * @throws NetworkException\n     */\n    public OutputStream getOutputStream() throws NetworkException;\n\n    /**\n     * Returns the remote address of the connection\n     * \n     * @return Address\n     */\n    public String getRemoteAddress();\n\n    /**\n     * Returns the remote port of the connection\n     * \n     * @return Port\n     */\n    public int getRemotePort();\n\n    /**\n     * Returns the local address of the connection\n     * \n     * @return Address\n     */\n    public String getLocalAddress();\n\n    /**\n     * Returns the local port of the connection\n     * \n     * @return Port\n     */\n    public int getLocalPort();\n\n    /**\n     * Get the timeout for this socket during which a reading operation shall block while waiting\n     * for data\n     * \n     * @return Milliseconds\n     * @throws NetworkException\n     */\n    public int getSoTimeout() throws NetworkException;\n\n    /**\n     * Set the timeout for this socket during which a reading operation shall block while waiting\n     * for data\n     * \n     * @param timeout Timeout in milliseconds\n     * @throws NetworkException\n     */\n    public void setSoTimeout(long timeout) throws NetworkException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/network/SocketServerConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.network;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\n/**\n * Socket server connection\n * \n * @author jexa7410\n */\npublic interface SocketServerConnection extends Closeable {\n    /**\n     * Open the socket\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException;\n\n    /**\n     * Close the socket\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException;\n\n    /**\n     * Accept connection\n     * \n     * @return Socket connection\n     * @throws IOException\n     */\n    public SocketConnection acceptConnection() throws IOException;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/registry/AndroidRegistryFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.registry;\n\nimport com.gsma.rcs.core.CoreException;\nimport com.gsma.rcs.platform.AndroidFactory;\n\nimport android.app.Activity;\nimport android.content.SharedPreferences;\n\n/**\n * Android registry factory\n * \n * @author jexa7410\n */\npublic class AndroidRegistryFactory extends RegistryFactory {\n    /**\n     * RCS registry name\n     */\n    public static final String RCS_PREFS_NAME = \"RCS\";\n\n    /**\n     * Shared preference\n     */\n    private SharedPreferences preferences;\n\n    /**\n     * Constructor\n     * \n     * @throws CoreException\n     */\n    public AndroidRegistryFactory() throws CoreException {\n        super();\n\n        if (AndroidFactory.getApplicationContext() == null) {\n            throw new CoreException(\"Application context not initialized\");\n        }\n\n        preferences = AndroidFactory.getApplicationContext().getSharedPreferences(RCS_PREFS_NAME,\n                Activity.MODE_PRIVATE);\n    }\n\n    /**\n     * Read a string value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return String\n     */\n    public String readString(String key, String defaultValue) {\n        return preferences.getString(key, defaultValue);\n    }\n\n    /**\n     * Write a string value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public void writeString(String key, String value) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putString(key, value);\n        editor.commit();\n    }\n\n    /**\n     * Read an integer value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Integer\n     */\n    public int readInteger(String key, int defaultValue) {\n        return preferences.getInt(key, defaultValue);\n    }\n\n    /**\n     * Write an integer value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public void writeInteger(String key, int value) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putInt(key, value);\n        editor.commit();\n    }\n\n    /**\n     * Read a long value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Long\n     */\n    public long readLong(String key, long defaultValue) {\n        return preferences.getLong(key, defaultValue);\n    }\n\n    /**\n     * Write a long value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public void writeLong(String key, long value) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putLong(key, value);\n        editor.commit();\n    }\n\n    /**\n     * Read a boolean value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Boolean\n     */\n    public boolean readBoolean(String key, boolean defaultValue) {\n        return preferences.getBoolean(key, defaultValue);\n    }\n\n    /**\n     * Write a boolean value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public void writeBoolean(String key, boolean value) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putBoolean(key, value);\n        editor.commit();\n    }\n\n    /**\n     * Remove a parameter in the registry\n     * \n     * @param key Key name to be removed\n     */\n    public void removeParameter(String key) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.remove(key);\n        editor.commit();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/platform/registry/RegistryFactory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.platform.registry;\n\nimport com.gsma.rcs.platform.FactoryException;\n\n/**\n * Application registry factory\n * \n * @author jexa7410\n */\npublic abstract class RegistryFactory {\n    /**\n     * Current platform factory\n     */\n    private static RegistryFactory mFactory;\n\n    /**\n     * Load the factory\n     * \n     * @param classname Factory classname\n     * @throws FactoryException\n     */\n    public static void loadFactory(String classname) throws FactoryException {\n        if (mFactory != null) {\n            return;\n        }\n        try {\n            mFactory = (RegistryFactory) Class.forName(classname).newInstance();\n        } catch (InstantiationException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n\n        } catch (IllegalAccessException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n\n        } catch (ClassNotFoundException e) {\n            throw new FactoryException(new StringBuilder(\"Can't load the factory \").append(\n                    classname).toString(), e);\n        }\n    }\n\n    /**\n     * Returns the current factory\n     * \n     * @return Factory\n     */\n    public static RegistryFactory getFactory() {\n        return mFactory;\n    }\n\n    /**\n     * Read a string value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return String\n     */\n    public abstract String readString(String key, String defaultValue);\n\n    /**\n     * Write a string value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public abstract void writeString(String key, String value);\n\n    /**\n     * Read an integer value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Integer\n     */\n    public abstract int readInteger(String key, int defaultValue);\n\n    /**\n     * Write an integer value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public abstract void writeInteger(String key, int value);\n\n    /**\n     * Read a long value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Long\n     */\n    public abstract long readLong(String key, long defaultValue);\n\n    /**\n     * Write a long value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public abstract void writeLong(String key, long value);\n\n    /**\n     * Read a boolean value in the registry\n     * \n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Boolean\n     */\n    public abstract boolean readBoolean(String key, boolean defaultValue);\n\n    /**\n     * Write a boolean value in the registry\n     * \n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public abstract void writeBoolean(String key, boolean value);\n\n    /**\n     * Remove a parameter in the registry\n     * \n     * @param key Key name to be removed\n     */\n    public abstract void removeParameter(String key);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/ContentProviderBaseIdCreator.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * As the base column \"_id\" is mandatory and unique in all providers, this class is used to generate\n * the new id as \"_id\" which cannot be primary key and AUTOINCREMENT cannot be used on other\n * columns.\n */\npublic class ContentProviderBaseIdCreator {\n\n    private static final String MAX_PROJECTION = \"MAX(\" + BaseColumns._ID + \")\";\n\n    private static final Map<Uri, AtomicLong> sNextIds = new HashMap<>();\n\n    /**\n     * Creates a unique ID for a specific content provider by incrementing the last generated id,\n     * which is found by reading the base column \"_id\" of that provider, or will return 1 if not\n     * found.\n     * \n     * @param ctx the android context\n     * @param providerUri the caller provider Uri\n     * @return the generated id\n     */\n    public static long createUniqueId(Context ctx, Uri providerUri) {\n\n        AtomicLong nextId = sNextIds.get(providerUri);\n\n        if (nextId != null) {\n            return nextId.incrementAndGet();\n        }\n\n        synchronized (sNextIds) {\n            nextId = sNextIds.get(providerUri);\n\n            if (nextId != null) {\n                return nextId.incrementAndGet();\n            }\n\n            nextId = new AtomicLong();\n\n            Cursor cursor = null;\n            try {\n                cursor = ctx.getContentResolver().query(providerUri, new String[] {\n                    MAX_PROJECTION\n                }, null, null, null);\n                CursorUtil.assertCursorIsNotNull(cursor, providerUri);\n                if (cursor.moveToNext()) {\n                    nextId.set(cursor.getLong(0));\n                }\n\n            } finally {\n                if (cursor != null) {\n                    cursor.close();\n                }\n            }\n\n            sNextIds.put(providerUri, nextId);\n\n            return nextId.incrementAndGet();\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/CursorUtil.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider;\n\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\npublic class CursorUtil {\n\n    public static void assertCursorIsNotNull(Cursor cursor, Uri requestedUri) {\n        if (cursor == null) {\n            throw new ServerApiPersistentStorageException(\"Query failed: \" + requestedUri);\n        }\n    }\n\n    public static void assertCursorIsNotNull(Cursor cursor, String queriedTable) {\n        if (cursor == null) {\n            throw new ServerApiPersistentStorageException(\"Query failed: \" + queriedTable);\n        }\n    }\n\n    public static void close(Cursor cursor) {\n        if (cursor != null) {\n            cursor.close();\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/DeleteTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider;\n\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * A common delete task for service objects stored in the database. By having information about the\n * scope of the deletion, it will retrieve all ids and delete the associated items, one by one or\n * all at once and finally callback on onCompleted. Will retry execution if the last one has\n * results, and if the scope doesnt expect exactly one.\n */\npublic abstract class DeleteTask<T> implements Runnable {\n\n    private final Uri mContentUri;\n\n    private final String mSelection;\n\n    private final String[] mSelectionArgs;\n\n    private final String[] mProjection;\n\n    private static final Logger sLogger = Logger.getLogger(DeleteTask.class.getName());\n\n    private final String mColumnGroupBy;\n\n    private final boolean mPathAppended;\n\n    private boolean mDeleteAllAtOnce;\n\n    protected final LocalContentResolver mLocalContentResolver;\n\n    public abstract static class GroupedByContactId extends DeleteTask<ContactId> {\n\n        private final ContactId mContact;\n\n        /**\n         * Delete a specific item or all\n         *\n         * @param contentResolver the content resolver\n         * @param contentUri the content URI\n         * @param columnPrimaryKey the primary key column\n         * @param columnGroupBy the column to group (either the contact or chat ID)\n         * @param selection the selection scope executed in the database. If null, all are eligible\n         *            for delete or one exactly (in that case selectionArgs must have one value,\n         *            unique id of the item).\n         * @param selectionArgs the selection arguments of the scope\n         */\n        public GroupedByContactId(LocalContentResolver contentResolver, Uri contentUri,\n                String columnPrimaryKey, String columnGroupBy, String selection,\n                String... selectionArgs) {\n            super(contentResolver, contentUri, columnPrimaryKey, columnGroupBy, selection,\n                    selectionArgs);\n            mContact = null;\n        }\n\n        /**\n         * @param contentResolver the content resolver\n         * @param contentUri the content URI\n         * @param columnPrimaryKey the primary key column\n         * @param columnContact the contact column\n         * @param contact the contact\n         */\n        public GroupedByContactId(LocalContentResolver contentResolver, Uri contentUri,\n                String columnPrimaryKey, String columnContact, ContactId contact) {\n            super(contentResolver, contentUri, columnPrimaryKey, columnContact, columnContact\n                    + \"=?\", contact.toString());\n            mContact = contact;\n        }\n\n        /**\n         * Converts the group id as string to ContactId or return the contact if we are in the\n         * unique case.\n         */\n        @Override\n        protected ContactId getGroupAsKey(String groupId) {\n            if (mContact != null) {\n                return mContact;\n            }\n            return ContactUtil.createContactIdFromTrustedData(groupId);\n        }\n\n    }\n\n    public abstract static class GroupedByChatId extends DeleteTask<String> {\n\n        public GroupedByChatId(LocalContentResolver contentResolver, Uri contentUri,\n                String columnPrimaryKey, String columnGroupBy, String selection,\n                String... selectionArgs) {\n            super(contentResolver, contentUri, columnPrimaryKey, columnGroupBy, selection,\n                    selectionArgs);\n        }\n\n        @Override\n        protected String getGroupAsKey(String groupId) {\n            return groupId;\n        }\n\n    }\n\n    public abstract static class NotGrouped extends DeleteTask<String> {\n\n        private static final String DEFAULT_KEY = \"\";\n\n        public NotGrouped(LocalContentResolver contentResolver, Uri contentUri,\n                String columnPrimaryKey, String selection, String... selectionArgs) {\n            super(contentResolver, contentUri, columnPrimaryKey, null, selection, selectionArgs);\n        }\n\n        @Override\n        protected void onRowDelete(String groupId, String itemId) throws PayloadException {\n            onRowDelete(itemId);\n        }\n\n        @Override\n        protected void onCompleted(String groupId, Set<String> deletedIds) {\n            onCompleted(deletedIds);\n        }\n\n        protected abstract void onRowDelete(String itemId) throws PayloadException;\n\n        protected abstract void onCompleted(Set<String> deletedIds);\n\n        @Override\n        protected String getGroupAsKey(String groupIdfromDatabase) {\n            return DEFAULT_KEY;\n        }\n\n    }\n\n    /**\n     * This constructor requires the scope of the deletion as a database query selection, and its\n     * dependencies.\n     * \n     * @param contentResolver the local content resolver\n     * @param contentUri the content uri (not path appended)\n     * @param columnPrimaryKey the primary key of the item to delete\n     * @param columnGroupBy the column by which to group (chat id, contact id) the selection of the\n     *            scope or null if it doesnt apply\n     * @param selection the selection scope executed in the database. If null, all are eligible for\n     *            delete or one exactly (in that case selectionArgs must have one value, unique id\n     *            of the item).\n     * @param selectionArgs the selection arguments of the scope\n     */\n    public DeleteTask(LocalContentResolver contentResolver, Uri contentUri,\n            String columnPrimaryKey, String columnGroupBy, String selection,\n            String... selectionArgs) {\n        mLocalContentResolver = contentResolver;\n        if (selection == null && selectionArgs != null && selectionArgs.length == 1) {\n            mContentUri = contentUri.buildUpon().appendPath(selectionArgs[0]).build();\n            mPathAppended = true;\n            selectionArgs = null;\n        } else {\n            mContentUri = contentUri;\n            mPathAppended = false;\n        }\n        mSelection = selection;\n        if (selectionArgs == null || selectionArgs.length == 0) {\n            mSelectionArgs = null;\n        } else {\n            mSelectionArgs = selectionArgs;\n        }\n        mColumnGroupBy = columnGroupBy;\n        if (mColumnGroupBy == null) {\n            mProjection = new String[] {\n                columnPrimaryKey\n            };\n        } else {\n            mProjection = new String[] {\n                    columnPrimaryKey, mColumnGroupBy\n            };\n        }\n    }\n\n    /**\n     * Queries all the ids of the scope and group them by the \"group\" column.\n     * \n     * @return the map of the ids grouped by the keys returned by the group column\n     */\n    private Map<T, Set<String>> getGroupedItemIds() {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(mContentUri, mProjection, mSelection,\n                    mSelectionArgs, null);\n            CursorUtil.assertCursorIsNotNull(cursor, mContentUri);\n            Map<T, Set<String>> result = null;\n            while (cursor.moveToNext()) {\n                String key = cursor.getString(0);\n                T groupId = null;\n                if (mColumnGroupBy != null) {\n                    groupId = getGroupAsKey(cursor.getString(1));\n                }\n                Set<String> ids = null;\n                if (result != null) {\n                    ids = result.get(groupId);\n                }\n                if (ids == null) {\n                    ids = new HashSet<>();\n                    if (result == null) {\n                        result = new HashMap<>();\n                    }\n                    result.put(groupId, ids);\n                }\n                ids.add(key);\n            }\n            return result;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Execution can be run several times as incoming items can be deleted.\n     * \n     * @return the result of the execution as map (deleted ids mapped by group column)\n     * @throws PayloadException\n     */\n    private Map<T, Set<String>> tryDelete() throws PayloadException {\n        Map<T, Set<String>> items = getGroupedItemIds();\n        if (items == null || items.isEmpty()) {\n            return null;\n        }\n        for (T groupId : items.keySet()) {\n            for (String itemKey : items.get(groupId)) {\n                onRowDelete(groupId, itemKey);\n                if (!mDeleteAllAtOnce) {\n                    mLocalContentResolver.delete(getAppendedPathUri(itemKey), null, null);\n                }\n            }\n            if (mDeleteAllAtOnce) {\n                mLocalContentResolver.delete(mContentUri, mSelection, mSelectionArgs);\n            }\n        }\n        return items;\n    }\n\n    protected boolean isSingleRowDelete() {\n        return mPathAppended;\n    }\n\n    protected Uri getAppendedPathUri(String itemKey) {\n        if (mPathAppended) {\n            return mContentUri;\n        }\n        return mContentUri.buildUpon().appendPath(itemKey).build();\n    }\n\n    protected abstract T getGroupAsKey(String groupIdfromDatabase);\n\n    /**\n     * @param groupId key of the group\n     * @param itemId the item ID\n     * @throws PayloadException\n     */\n    protected abstract void onRowDelete(T groupId, String itemId) throws PayloadException;\n\n    /**\n     * Called after the delete is completed to report the ids deleted per group chatId or contact.\n     * \n     * @param deletedIds as a {@link Set} as required by the listeners.\n     */\n    protected abstract void onCompleted(T groupId, Set<String> deletedIds);\n\n    /**\n     * Set to true if delete on all the scope range at once. False is default. If not set, the task\n     * will delete each row one by one.\n     * \n     * @param deleteAllAtOnce true if delete all at once\n     */\n    public void setAllAtOnce(boolean deleteAllAtOnce) {\n        mDeleteAllAtOnce = deleteAllAtOnce;\n    }\n\n    @Override\n    public void run() {\n        Map<T, Set<String>> deletedIds = null;\n        try {\n            deletedIds = tryDelete();\n            if (deletedIds != null && deletedIds.size() > 0 && !mPathAppended) {\n                Map<T, Set<String>> deletedIds2 = tryDelete();\n                if (deletedIds2 != null) {\n                    for (T groupId : deletedIds.keySet()) {\n                        if (deletedIds.containsKey(groupId)) {\n                            deletedIds.get(groupId).addAll(deletedIds2.get(groupId));\n                        } else {\n                            deletedIds.put(groupId, deletedIds2.get(groupId));\n                        }\n                    }\n                }\n            }\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Exception occurred while deleting!\", e);\n\n        } finally {\n            if (deletedIds != null) {\n                for (Map.Entry<T, Set<String>> entry : deletedIds.entrySet()) {\n                    T groupId = entry.getKey();\n                    Set<String> delIds = entry.getValue();\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"onCompleted groupId=\" + groupId + \" IDs size=\"\n                                + delIds.size());\n                    }\n                    onCompleted(groupId, delIds);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/LocalContentResolver.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentProviderOperation;\nimport android.content.ContentProviderResult;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.OperationApplicationException;\nimport android.database.Cursor;\nimport android.net.Uri;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\n\n/**\n * The purpose of this class is to allow query-/insert-/update-/delete- and stream operations\n * directly on the local providers. The usage of this class allows the local providers to be write\n * protected for external use like from applications accessing the terminal api while still allowing\n * internal write access to the same providers by the service implementations.\n */\n\npublic class LocalContentResolver {\n\n    private final ContentResolver mContentResolver;\n\n    /**\n     * Constructor\n     * \n     * @param contentResolver the content resolver\n     */\n    public LocalContentResolver(ContentResolver contentResolver) {\n        mContentResolver = contentResolver;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param context the context\n     */\n    public LocalContentResolver(Context context) {\n        this(context.getContentResolver());\n    }\n\n    /**\n     * Handles query requests from clients\n     * \n     * @param uri the URI to query\n     * @param projection The list of columns to put into the cursor of null if all\n     * @param selection A selection criteria to apply when filtering rows\n     * @param selectionArgs The array of arguments for the selection or null if no argument.\n     * @param sortOrder the sording order\n     * @return a Cursor or null.\n     */\n    public final Cursor query(Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sortOrder) {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().query(uri, projection,\n                    selection, selectionArgs, sortOrder);\n\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n\n    /**\n     * Handles requests to insert a new row.\n     * \n     * @param uri the URI\n     * @param values A set of column_name/value pairs to add to the database.\n     * @return The URI for the newly inserted item\n     */\n    public final Uri insert(Uri uri, ContentValues values) {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().insert(uri, values);\n\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n\n    /**\n     * Handle requests to update one or more rows.\n     * \n     * @param uri the URI\n     * @param values A set of column_name/value pairs to update\n     * @param selection A selection criteria to apply when filtering rows\n     * @param selectionArgs The array of arguments for the selection or null if no argument.\n     * @return the number of rows affected.\n     */\n    public final int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().update(uri, values, selection,\n                    selectionArgs);\n\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n\n    /**\n     * Handles requests to delete one or more rows.\n     * \n     * @param uri the URI\n     * @param selection A selection criteria to apply when filtering rows\n     * @param selectionArgs The array of arguments for the selection or null if no argument.\n     * @return The number of rows affected.\n     */\n    public final int delete(Uri uri, String selection, String[] selectionArgs) {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().delete(uri, selection,\n                    selectionArgs);\n\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n\n    /**\n     * Create and return a new auto-close input stream for this URI\n     * \n     * @param uri the URI\n     * @return the InputStream\n     * @throws FileNotFoundException\n     */\n    public final InputStream openContentInputStream(Uri uri) throws FileNotFoundException {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().openAssetFile(uri, \"r\")\n                    .createInputStream();\n\n        } catch (IOException e) {\n            throw new FileNotFoundException(\"Unable to create stream\");\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n\n    /**\n     * Create and return a new auto-close output stream for this URI\n     * \n     * @param uri the URI\n     * @return the InputStream\n     * @throws FileNotFoundException\n     */\n    public final OutputStream openContentOutputStream(Uri uri) throws FileNotFoundException {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().openAssetFile(uri, \"w\")\n                    .createOutputStream();\n\n        } catch (IOException e) {\n            throw new FileNotFoundException(\"Unable to create stream\");\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n\n    /**\n     * Handles request to update multiple rows\n     *\n     * @param uri the URI\n     * @param operations the list of the operations to apply\n     * @return the results of the applications\n     * @throws OperationApplicationException\n     */\n    public final ContentProviderResult[] applyBatch(Uri uri,\n            ArrayList<ContentProviderOperation> operations) throws OperationApplicationException {\n        ContentProviderClient contentProviderClient = null;\n        try {\n            contentProviderClient = mContentResolver.acquireContentProviderClient(uri);\n            return contentProviderClient.getLocalContentProvider().applyBatch(operations);\n        } finally {\n            if (contentProviderClient != null) {\n                contentProviderClient.release();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/UserProfilePersistedStorageUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider;\n\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsServiceControl;\n\nimport android.os.Environment;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.io.FileNotFoundException;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.util.regex.Pattern;\n\n/**\n * Backup and restore of user profile information\n * \n * @author YPLO6403\n */\npublic class UserProfilePersistedStorageUtil {\n\n    private static final String DB_FILE_EXTENSION = \".db\";\n\n    /**\n     * Pattern to check if rcs account have atleast 3 characters.\n     */\n    private static final Pattern RCS_ACCOUNT_MATCH_PATTERN = Pattern.compile(\"^\\\\d{3,}$\");\n\n    /**\n     * The location of the database\n     */\n    public static final String DATABASE_LOCATION = \"/data/\"\n            + RcsServiceControl.RCS_STACK_PACKAGENAME + \"/databases/\";\n\n    /**\n     * The maximum number of saved accounts\n     */\n    private static final int MAX_SAVED_ACCOUNT = 3;\n\n    private static final Logger sLogger = Logger.getLogger(UserProfilePersistedStorageUtil.class\n            .getSimpleName());\n\n    /**\n     * Filter to get database files\n     */\n    private static final FilenameFilter sFilenameDbFilter = new FilenameFilter() {\n        @Override\n        public boolean accept(File dir, String filename) {\n            return (filename.endsWith(DB_FILE_EXTENSION));\n        }\n    };\n\n    /**\n     * Get list of RCS accounts saved under the database directory\n     * \n     * @param databasesDir the database directory\n     * @return the array of RCS saved accounts (may be empty) or null\n     */\n    private static File[] listOfSavedAccounts(final File databasesDir) {\n        if (!databasesDir.exists() || !databasesDir.isDirectory()) {\n            /*\n             * As the database itself doesn't exist , So there won't be any accounts related to user\n             * profile saved, So return from here. This is a special case where we don't throw\n             * exception as backup and restore files and not always needed to be present and reading\n             * information from persisted cache is always optional\n             */\n            return null;\n        }\n        FileFilter directoryFilter = new FileFilter() {\n            @Override\n            public boolean accept(File file) {\n                return file.isDirectory()\n                        && RCS_ACCOUNT_MATCH_PATTERN.matcher(file.getName()).matches();\n            }\n        };\n        return databasesDir.listFiles(directoryFilter);\n    }\n\n    /**\n     * Save user account profile\n     * \n     * @param databasesDir the database directory\n     * @param account the account\n     * @throws IOException\n     */\n    private static void saveUserProfile(final File databasesDir, final String account)\n            throws IOException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"saveAccountDatabases account=\".concat(account));\n        }\n        String[] listOfDbFiles = databasesDir.list(sFilenameDbFilter);\n        if (listOfDbFiles == null) {\n            throw new FileNotFoundException(\"Failed to find \" + DB_FILE_EXTENSION + \" files at : \"\n                    + databasesDir.getPath());\n        }\n        File dstDir = new File(databasesDir, account);\n        for (String dbFile : listOfDbFiles) {\n            File srcFile = new File(databasesDir, dbFile);\n            FileUtils.copyFileToDirectory(srcFile, dstDir, true);\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Save file '\" + srcFile + \"' to '\" + dstDir + \"'\");\n            }\n        }\n        // noinspection ResultOfMethodCallIgnored\n        dstDir.setLastModified(System.currentTimeMillis());\n    }\n\n    /**\n     * Restore user account profile\n     * \n     * @param databasesDir the database directory\n     * @param account the account\n     * @throws IOException\n     */\n    private static void restoreUserProfile(final File databasesDir, final String account)\n            throws IOException {\n        File srcDir = new File(databasesDir, account);\n        String[] listOfDbFiles = srcDir.list(sFilenameDbFilter);\n        if (listOfDbFiles == null) {\n            throw new FileNotFoundException(\"Failed to find \" + DB_FILE_EXTENSION + \" files at : \"\n                    + databasesDir.getPath());\n        }\n        for (String dbFile : listOfDbFiles) {\n            File srcFile = new File(srcDir, dbFile);\n            FileUtils.copyFileToDirectory(srcFile, databasesDir, true);\n        }\n    }\n\n    /**\n     * Normalize file backup and manages old user files if not more then MAX_SAVED_ACCOUNT\n     * \n     * @param databasesDir the database directory\n     * @param currentUserAccount the account\n     * @throws IOException\n     */\n    private static void normalizeFileBackup(final File databasesDir, final String currentUserAccount)\n            throws IOException {\n        File[] files = listOfSavedAccounts(databasesDir);\n        if (files == null || files.length <= MAX_SAVED_ACCOUNT) {\n            /* No need to formalize backup files as we havn't reach max saved account limit yet */\n            return;\n        }\n        File file = FileUtils.getOldestFile(files);\n        if (!file.getName().equals(currentUserAccount)) {\n            FileUtils.deleteDirectory(file);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Clean oldest Backup : account=\".concat(file.getName()));\n            }\n            return;\n        }\n        /* Do not clean current account */\n        File[] filesWithoutCurrentAccount = new File[files.length - 1];\n        int i = 0;\n        for (File file2 : files) {\n            if (!file2.getName().equals(currentUserAccount)) {\n                filesWithoutCurrentAccount[i++] = file2;\n            }\n        }\n        file = FileUtils.getOldestFile(filesWithoutCurrentAccount);\n        FileUtils.deleteDirectory(file);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Clean oldest Backup : account=\".concat(file.getName()));\n        }\n    }\n\n    /**\n     * Normalize file backup and manages old user files if not more then MAX_SAVED_ACCOUNT\n     * \n     * @param currentUserAccount the account\n     * @throws IOException\n     */\n    public static void normalizeFileBackup(String currentUserAccount) throws IOException {\n        normalizeFileBackup(\n                new File(Environment.getDataDirectory().toString() + DATABASE_LOCATION),\n                currentUserAccount);\n    }\n\n    /**\n     * Try to backup user account.\n     * <p>\n     * As this method makes an attempt to backup user account any failure that may occur while\n     * backing up will not be propagated to the caller function.\n     * </p>\n     * \n     * @param account the Account to backup\n     */\n    public static void tryToBackupAccount(String account) {\n        File userProfile = new File(Environment.getDataDirectory().toString() + DATABASE_LOCATION);\n        try {\n            saveUserProfile(userProfile, account);\n        } catch (FileNotFoundException e) {\n            /*\n             * If the file that needs to be backed up does not exist then we can't proceed with this\n             * operation, so we log this incident and continue with the rest of the flow as backing\n             * up account is not a mandatory feature that needs full success.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            /*\n             * Since we have failed to do full backup and there is a chance that we might have\n             * partial copy of original files, Hence we should remove those files and also the files\n             * under DATABASE_LOCATION , as anyway we don't have a chance to back those after sim\n             * swap happens.\n             */\n            /* Remove all directories and files those are restored so far */\n            try {\n                FileUtils.deleteDirectory(new File(userProfile, account));\n            } catch (IOException ex) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(ex.getMessage());\n                }\n            }\n            /* Remove directories and files under DATABASE_LOCATION */\n            try {\n                FileUtils.deleteDirectory(userProfile);\n            } catch (IOException ex) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(ex.getMessage());\n                }\n            }\n        }\n    }\n\n    /**\n     * Try to restore user account\n     * <p>\n     * As this method makes an attempt to restore user account any failure that may occur while\n     * restoring will not be propagated to the caller function.\n     * </p>\n     * \n     * @param account Account\n     */\n    public static void tryToRestoreAccount(String account) {\n        File userProfile = new File(Environment.getDataDirectory().toString() + DATABASE_LOCATION);\n        try {\n            restoreUserProfile(userProfile, account);\n        } catch (FileNotFoundException e) {\n            /*\n             * If the file that needs to be backed up does not exist then we can't proceed with this\n             * operation, so we log this incident and continue with the rest of the flow as backing\n             * up account is not a mandatory feature that needs full success.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n            /*\n             * Since we have failed to do full restore and there is a chance that we might have\n             * partial copy of original files, Hence we should remove those files and also the files\n             * under DATABASE_LOCATION , as anyway we don't have a chance to back those after sim\n             * swap happens.\n             */\n            /* Remove all directories and files those are restored so far */\n            try {\n                FileUtils.deleteDirectory(new File(userProfile, account));\n            } catch (IOException ex) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(ex.getMessage());\n                }\n            }\n            /* Remove directories and files under DATABASE_LOCATION */\n            try {\n                FileUtils.deleteDirectory(userProfile);\n            } catch (IOException ex) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(ex.getMessage());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/contact/ContactData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.contact;\n\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\n\nimport android.net.Uri;\n\n/**\n * RCS Contact address book data constants\n * \n * @author Jean-Marc AUFFRET\n */\n/* package private */final class ContactData {\n    /**\n     * Database URI\n     */\n    /* package private */static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.capability/capability\");\n\n    /**\n     * Unique base column id\n     */\n    /* package private */static final String KEY_BASECOLUMN_ID = CapabilitiesLog.BASECOLUMN_ID;\n\n    /**\n     * ContactId formatted number of contact associated to the capabilities.\n     */\n    /* package private */static final String KEY_CONTACT = CapabilitiesLog.CONTACT;\n\n    /**\n     * Image sharing capability. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_CAPABILITY_IMAGE_SHARE = CapabilitiesLog.CAPABILITY_IMAGE_SHARE;\n\n    /**\n     * Video sharing capability. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_CAPABILITY_VIDEO_SHARE = CapabilitiesLog.CAPABILITY_VIDEO_SHARE;\n\n    /**\n     * File transfer capability. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_CAPABILITY_FILE_TRANSFER = CapabilitiesLog.CAPABILITY_FILE_TRANSFER;\n\n    /**\n     * IM/Chat capability. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_CAPABILITY_IM_SESSION = CapabilitiesLog.CAPABILITY_IM_SESSION;\n\n    /**\n     * Geolocation push capability. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_CAPABILITY_GEOLOC_PUSH = CapabilitiesLog.CAPABILITY_GEOLOC_PUSH;\n\n    /**\n     * Supported RCS extensions. List of features tags semicolon separated (e.g. <TAG1>;<TAG2>;\n     * ;TAGn)\n     */\n    /* package private */static final String KEY_CAPABILITY_EXTENSIONS = CapabilitiesLog.CAPABILITY_EXTENSIONS;\n\n    /**\n     * Is an automata. Values: 1 (true), 0 (false).\n     */\n    /* package private */static final String KEY_AUTOMATA = CapabilitiesLog.AUTOMATA;\n\n    /**\n     * Timestamp of the last capability response\n     */\n    /* package private */static final String KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE = CapabilitiesLog.TIMESTAMP;\n\n    /**\n     * Column Name\n     */\n    /* package private */static final String KEY_DISPLAY_NAME = \"display_name\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_SHARING_STATUS = \"presence_sharing_status\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_TIMESTAMP_CONTACT_UPDATED = \"timestamp_contact_updated\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_RCS_STATUS = \"rcs_status\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_REGISTRATION_STATE = \"registration_state\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_RCS_STATUS_TIMESTAMP = \"rcs_status_timestamp\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_FREE_TEXT = \"presence_free_text\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_WEBLINK_NAME = \"presence_weblink_name\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_WEBLINK_URL = \"presence_weblink_url\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_PHOTO_EXIST_FLAG = \"presence_photo_exist_flag\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_PHOTO_ETAG = \"presence_photo_etag\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_PHOTO_DATA = \"presence_photo_data\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_GEOLOC_EXIST_FLAG = \"presence_geoloc_exist_flag\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_GEOLOC_LATITUDE = \"presence_geoloc_latitude\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_GEOLOC_LONGITUDE = \"presence_geoloc_longitude\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_GEOLOC_ALTITUDE = \"presence_geoloc_altitude\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_PRESENCE_TIMESTAMP = \"presence_timestamp\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST = \"capability_time_last_rqst\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_CS_VIDEO = \"capability_cs_video\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_PRESENCE_DISCOVERY = \"capability_presence_discovery\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_SOCIAL_PRESENCE = \"capability_social_presence\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_FILE_TRANSFER_HTTP = \"capability_file_transfer_http\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_FILE_TRANSFER_THUMBNAIL = \"capability_file_transfer_thumbnail\";\n\n    /**\n     * Column name\n     */\n    // TODO: Refer to Ipcall api here in future releases\n    // /* package private */static final String KEY_CAPABILITY_IP_VOICE_CALL =\n    // CapabilitiesLog.CAPABILITY_IP_VOICE_CALL;\n    /* package private */static final String KEY_CAPABILITY_IP_VOICE_CALL = \"capability_ip_voice_call\";\n\n    /**\n     * Column name\n     */\n    // TODO: Refer to Ipcall api here in future releases\n    // /* package private */static final String KEY_CAPABILITY_IP_VIDEO_CALL =\n    // CapabilitiesLog.CAPABILITY_IP_VIDEO_CALL;\n    /* package private */static final String KEY_CAPABILITY_IP_VIDEO_CALL = \"capability_ip_video_call\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_GROUP_CHAT_SF = \"capability_group_chat_sf\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_CAPABILITY_FILE_TRANSFER_SF = \"capability_file_transfer_sf\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_BLOCKING_TIMESTAMP = \"blocking_timestamp\";\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_BLOCKED = \"blocked\";\n\n    /**\n     * TRUE value\n     */\n    /* package private */static final String TRUE_VALUE = Boolean.toString(true);\n\n    /**\n     * FALSE value\n     */\n    /* package private */static final String FALSE_VALUE = Boolean.toString(false);\n\n    /**\n     * BLOCKED value is not set\n     */\n    /* package private */static final int BLOCKED_VALUE_NOT_SET = 0;\n\n    /**\n     * BLOCKED value is set\n     */\n    /* package private */static final int BLOCKED_VALUE_SET = 1;\n\n    /**\n     * Aggregation data constants\n     */\n    /* package private */static final class AggregationData {\n        /**\n         * Database URI\n         */\n        /* package private */static final Uri CONTENT_URI = Uri\n                .parse(\"content://com.gsma.rcs.capability/aggregation\");\n\n        /**\n         * Column name\n         */\n        /* package private */static final String KEY_ID = \"_id\";\n\n        /**\n         * Column name\n         */\n        /* package private */static final String KEY_RCS_NUMBER = \"rcs_number\";\n\n        /**\n         * Column name\n         */\n        /* package private */static final String KEY_RAW_CONTACT_ID = \"raw_contact_id\";\n\n        /**\n         * Column name\n         */\n        /* package private */static final String KEY_RCS_RAW_CONTACT_ID = \"rcs_raw_contact_id\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/contact/ContactManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.contact;\n\nimport static com.gsma.rcs.provider.contact.ContactData.BLOCKED_VALUE_NOT_SET;\nimport static com.gsma.rcs.provider.contact.ContactData.BLOCKED_VALUE_SET;\nimport static com.gsma.rcs.provider.contact.ContactData.CONTENT_URI;\nimport static com.gsma.rcs.provider.contact.ContactData.FALSE_VALUE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_AUTOMATA;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_BLOCKED;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_BLOCKING_TIMESTAMP;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_CS_VIDEO;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_EXTENSIONS;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_FILE_TRANSFER;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_FILE_TRANSFER_HTTP;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_FILE_TRANSFER_SF;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_FILE_TRANSFER_THUMBNAIL;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_GEOLOC_PUSH;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_GROUP_CHAT_SF;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_IMAGE_SHARE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_IM_SESSION;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_IP_VIDEO_CALL;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_IP_VOICE_CALL;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_PRESENCE_DISCOVERY;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_SOCIAL_PRESENCE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CAPABILITY_VIDEO_SHARE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_CONTACT;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_DISPLAY_NAME;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_FREE_TEXT;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_GEOLOC_ALTITUDE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_GEOLOC_EXIST_FLAG;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_GEOLOC_LATITUDE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_GEOLOC_LONGITUDE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_PHOTO_ETAG;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_PHOTO_EXIST_FLAG;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_SHARING_STATUS;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_TIMESTAMP;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_WEBLINK_NAME;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_PRESENCE_WEBLINK_URL;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_RCS_STATUS;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_RCS_STATUS_TIMESTAMP;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_REGISTRATION_STATE;\nimport static com.gsma.rcs.provider.contact.ContactData.KEY_TIMESTAMP_CONTACT_UPDATED;\nimport static com.gsma.rcs.provider.contact.ContactData.TRUE_VALUE;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.addressbook.RcsAccountManager;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.service.ContactInfo;\nimport com.gsma.rcs.core.ims.service.ContactInfo.BlockingState;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.extension.ServiceExtensionManager;\nimport com.gsma.rcs.core.ims.service.presence.FavoriteLink;\nimport com.gsma.rcs.core.ims.service.presence.Geoloc;\nimport com.gsma.rcs.core.ims.service.presence.PhotoIcon;\nimport com.gsma.rcs.core.ims.service.presence.PresenceInfo;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactData.AggregationData;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.StringUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactProvider;\n\nimport android.content.ContentProviderOperation;\nimport android.content.ContentProviderResult;\nimport android.content.ContentResolver;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.OperationApplicationException;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.provider.ContactsContract;\nimport android.provider.ContactsContract.AggregationExceptions;\nimport android.provider.ContactsContract.CommonDataKinds.GroupMembership;\nimport android.provider.ContactsContract.CommonDataKinds.Im;\nimport android.provider.ContactsContract.CommonDataKinds.Phone;\nimport android.provider.ContactsContract.CommonDataKinds.Photo;\nimport android.provider.ContactsContract.CommonDataKinds.StructuredName;\nimport android.provider.ContactsContract.CommonDataKinds.Website;\nimport android.provider.ContactsContract.Data;\nimport android.provider.ContactsContract.Groups;\nimport android.provider.ContactsContract.RawContacts;\nimport android.provider.ContactsContract.StatusUpdates;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\n/**\n * Contains utility methods for interfacing with the Android SDK ContactProvider and the RCS contact\n * provider.\n * \n * @author Jean-Marc AUFFRET\n * @author Deutsche Telekom AG\n * @author Philippe LEMORDANT\n */\npublic final class ContactManager {\n\n    /**\n     * Invalid contact raw ID\n     */\n    public static final long INVALID_ID = -1;\n\n    private static final long INVALID_TIME = -1L;\n\n    /**\n     * MIME type for contact number\n     */\n    private static final String MIMETYPE_NUMBER = ContactProvider.MIME_TYPE_PHONE_NUMBER;\n\n    /**\n     * MIME type for RCS registration state\n     */\n    private static final String MIMETYPE_REGISTRATION_STATE = ContactProvider.MIME_TYPE_REGISTRATION_STATE;\n\n    /**\n     * MIME type for blocking state\n     */\n    private static final String MIMETYPE_BLOCKING_STATE = ContactProvider.MIME_TYPE_BLOCKING_STATE;\n\n    /**\n     * MIME type for blocking timestamp\n     */\n    private static final String MIMETYPE_BLOCKING_TIMESTAMP = ContactProvider.MIME_TYPE_BLOCKING_TIMESTAMP;\n\n    /**\n     * MIME type for GSMA_CS_IMAGE (image sharing) capability\n     */\n    private static final String MIMETYPE_CAPABILITY_IMAGE_SHARE = ContactProvider.MIME_TYPE_IMAGE_SHARE;\n\n    /**\n     * MIME type for 3GPP_CS_VOICE (video sharing) capability\n     */\n    private static final String MIMETYPE_CAPABILITY_VIDEO_SHARE = ContactProvider.MIME_TYPE_VIDEO_SHARE;\n\n    /**\n     * MIME type for RCS_IM (IM session) capability\n     */\n    private static final String MIMETYPE_CAPABILITY_IM_SESSION = ContactProvider.MIME_TYPE_IM_SESSION;\n\n    /**\n     * MIME type for RCS_FT (file transfer) capability\n     */\n    private static final String MIMETYPE_CAPABILITY_FILE_TRANSFER = ContactProvider.MIME_TYPE_FILE_TRANSFER;\n\n    /**\n     * MIME type for geoloc psuh capability\n     */\n    private static final String MIMETYPE_CAPABILITY_GEOLOCATION_PUSH = ContactProvider.MIME_TYPE_GEOLOC_PUSH;\n\n    /**\n     * MIME type for RCS extensions\n     */\n    private static final String MIMETYPE_CAPABILITY_EXTENSIONS = ContactProvider.MIME_TYPE_EXTENSIONS;\n\n    /**\n     * MIME type for RCS IP Voice Call capability\n     */\n    // TODO: Add Ipcall support here in future releases\n    // /*package private */static final String MIMETYPE_CAPABILITY_IP_VOICE_CALL =\n    // ContactProvider.MIME_TYPE_IP_VOICE_CALL;\n    private static final String MIMETYPE_CAPABILITY_IP_VOICE_CALL = \"vnd.android.cursor.item/com.gsma.services.rcs.ip-voice-call\";\n\n    /**\n     * MIME type for RCS IP Video Call capability\n     */\n    // TODO: Add Ipcall support here in future releases\n    // /*package private */static final String MIMETYPE_CAPABILITY_IP_VIDEO_CALL =\n    // ContactProvider.MIME_TYPE_IP_VIDEO_CALL;\n    private static final String MIMETYPE_CAPABILITY_IP_VIDEO_CALL = \"vnd.android.cursor.item/com.gsma.services.rcs.ip-video-call\";\n\n    private enum MimeType {\n\n        // @formatter:off\n        NUMBER(MIMETYPE_NUMBER),\n        REGISTRATION_STATE(MIMETYPE_REGISTRATION_STATE),\n        CAPABILITY_IMAGE_SHARE(MIMETYPE_CAPABILITY_IMAGE_SHARE),\n        CAPABILITY_VIDEO_SHARE(MIMETYPE_CAPABILITY_VIDEO_SHARE),\n        CAPABILITY_IM_SESSION(MIMETYPE_CAPABILITY_IM_SESSION),\n        CAPABILITY_FILE_TRANSFER(MIMETYPE_CAPABILITY_FILE_TRANSFER),\n        CAPABILITY_GEOLOCATION_PUSH(MIMETYPE_CAPABILITY_GEOLOCATION_PUSH),\n        CAPABILITY_EXTENSIONS(MIMETYPE_CAPABILITY_EXTENSIONS),\n        CAPABILITY_IP_VOICE_CALL(MIMETYPE_CAPABILITY_IP_VOICE_CALL),\n        CAPABILITY_IP_VIDEO_CALL(MIMETYPE_CAPABILITY_IP_VIDEO_CALL),\n        BLOCKING_STATE(MIMETYPE_BLOCKING_STATE),\n        BLOCKING_TIMESTAMP(MIMETYPE_BLOCKING_TIMESTAMP);\n        // @formatter:on\n\n        private String mValue;\n\n        MimeType(String value) {\n            mValue = value;\n        }\n\n        private static Map<String, MimeType> mValueToEnum = new HashMap<>();\n        static {\n            for (MimeType entry : MimeType.values()) {\n                mValueToEnum.put(entry.getMimeType(), entry);\n            }\n        }\n\n        /**\n         * Gets string representation\n         * \n         * @return String\n         */\n        public final String getMimeType() {\n            return mValue;\n        }\n\n        /**\n         * Gets the MimeType from its string representation\n         * \n         * @param value the string representation\n         * @return MimeType\n         */\n        public static MimeType getMimeType(String value) {\n            MimeType entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + MimeType.class.getName()\n                    + \".\" + value);\n        }\n    }\n\n    /**\n     * ONLINE available status\n     */\n    private static final int PRESENCE_STATUS_ONLINE = 5; // StatusUpdates.AVAILABLE;\n\n    /**\n     * OFFLINE available status\n     */\n    private static final int PRESENCE_STATUS_OFFLINE = 0; // StatusUpdates.OFFLINE;\n\n    /**\n     * NOT SET available status\n     */\n    private static final int PRESENCE_STATUS_NOT_SET = 1; // StatusUpdates.INVISIBLE;\n\n    /*\n     * For account persisted on SIM card, type may be \"vnd.sec.contact.sim\" (Samsung) or\n     * \"com.android.contacts.sim\" (normal case)\n     */\n    private final static String SIM_ACCOUNT_SELECTION = RawContacts.ACCOUNT_TYPE\n            + \" LIKE '%.sim' AND \" + RawContacts._ID + \"=?\";\n\n    /**\n     * Contact for \"Me\"\n     */\n    private static final String MYSELF = \"myself\";\n\n    private static final String SEL_RAW_CONTACT_MIMETYPE_DATA1 = Data.RAW_CONTACT_ID + \"=? AND \"\n            + Data.MIMETYPE + \"=? AND \" + Data.DATA1 + \"=?\";\n\n    private static final String WHERE_RCS_RAW_CONTACT_ID = AggregationData.KEY_RCS_RAW_CONTACT_ID\n            + \"=?\";\n\n    private static final String[] PROJ_RCS_RAW_CONTACT_ID = new String[] {\n        AggregationData.KEY_RCS_RAW_CONTACT_ID\n    };\n\n    private static final String WHERE_RCS_STATUS_RCS = KEY_RCS_STATUS + \"<>'\"\n            + RcsStatus.NO_INFO.toInt() + \"' AND \" + KEY_RCS_STATUS + \"<>'\"\n            + RcsStatus.NOT_RCS.toInt() + \"'\";\n\n    private static final String WHERE_RCS_STATUS_WITH_SOCIAL_PRESENCE = KEY_RCS_STATUS + \"<>'\"\n            + RcsStatus.NO_INFO.toInt() + \"' AND \" + KEY_RCS_STATUS + \"<>'\"\n            + RcsStatus.NOT_RCS.toInt() + \"' AND \" + KEY_RCS_STATUS + \"<>'\"\n            + RcsStatus.RCS_CAPABLE.toInt() + \"'\";\n\n    private static final String WHERE_RCS_RAW_CONTACT_ID_AND_RCS_NUMBER = AggregationData.KEY_RCS_NUMBER\n            + \"=? AND \" + AggregationData.KEY_RAW_CONTACT_ID + \"=?\";\n\n    /**\n     * Projection to get CONTACT from RCS contact Provider\n     */\n    private static final String[] PROJ_RCSCONTACT_CONTACT = new String[] {\n        KEY_CONTACT\n    };\n\n    private static final String SEL_RAW_CONTACT_FROM_NUMBER = Data.MIMETYPE\n            + \"=? AND PHONE_NUMBERS_EQUAL(\" + Phone.NUMBER + \", ?)\";\n\n    private static final String STRICT_SELECTION_RAW_CONTACT_FROM_NUMBER = Data.MIMETYPE\n            + \"=? AND (NOT PHONE_NUMBERS_EQUAL(\" + Phone.NUMBER + \", ?) AND PHONE_NUMBERS_EQUAL(\"\n            + Phone.NUMBER + \", ?, 1))\";\n\n    private static final String[] PROJ_RAW_CONTACT_ID = {\n        RawContacts._ID\n    };\n\n    private static final String SEL_RAW_CONTACT = RawContacts._ID + \"=?\";\n\n    private static final String SEL_RAW_CONTACT_WITH_WEBLINK = Data.RAW_CONTACT_ID + \"=? AND \"\n            + Website.TYPE + \"=?\";\n\n    private static final String[] PROJ_DATA_ID = new String[] {\n        Data._ID\n    };\n\n    private static final String SEL_DATA_ID = Data._ID + \"=?\";\n\n    private static final String SEL_RAW_CONTACT_WITH_MIMETYPE = Data.RAW_CONTACT_ID + \"=? AND \"\n            + Data.MIMETYPE + \"=?\";\n\n    private static final String SEL_RAW_CONTACT_ME = RawContacts.ACCOUNT_TYPE + \"='\"\n            + RcsAccountManager.ACCOUNT_MANAGER_TYPE + \"' AND \" + RawContacts.SOURCE_ID + \"='\"\n            + MYSELF + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_FILE_TRANSFER = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_FILE_TRANSFER + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_IM_SESSION = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_IM_SESSION + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_IMAGE_SHARING = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_IMAGE_SHARE + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_VIDEO_SHARING = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_VIDEO_SHARE + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_IP_VOICE_CALL = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_IP_VOICE_CALL + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_IP_VIDEO_CALL = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_IP_VIDEO_CALL + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_CAPABILITY_EXTENSIONS = Data.MIMETYPE + \"='\"\n            + MIMETYPE_CAPABILITY_EXTENSIONS + \"'\";\n\n    private static final String SEL_DATA_MIMETYPE_NUMBER = Data.MIMETYPE + \"='\" + MIMETYPE_NUMBER\n            + \"'\";\n\n    private static final String[] PROJ_RAW_CONTACT_DATA1 = {\n            Data.RAW_CONTACT_ID, Data.DATA1\n    };\n\n    private static final String[] PROJ_DATA_RAW_CONTACT = {\n        Data.RAW_CONTACT_ID\n    };\n\n    private final String[] PHONE_PROJ_NUMBER_RAW_CONTACT_ID = {\n            Phone.NUMBER, Phone.RAW_CONTACT_ID\n    };\n\n    private static final String SEL_RAW_CONTACT_ID = Data.RAW_CONTACT_ID + \"=?\";\n\n    private static final String[] PROJ_RAW_CONTACT_DATA_ALL = {\n            Data._ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, Website.URL, Photo.PHOTO\n    };\n\n    private static final String SEL_RAW_CONTACT_MIME_TYPES = Data.RAW_CONTACT_ID + \"=? AND \"\n            + Data.MIMETYPE + \" IN ('\" + MIMETYPE_REGISTRATION_STATE + \"','\"\n            + MIMETYPE_BLOCKING_STATE + \"','\" + MIMETYPE_BLOCKING_TIMESTAMP + \"','\"\n            + MIMETYPE_NUMBER + \"','\" + MIMETYPE_CAPABILITY_IMAGE_SHARE + \"','\"\n            + MIMETYPE_CAPABILITY_VIDEO_SHARE + \"','\" + MIMETYPE_CAPABILITY_IP_VOICE_CALL + \"','\"\n            + MIMETYPE_CAPABILITY_IP_VIDEO_CALL + \"','\" + MIMETYPE_CAPABILITY_IM_SESSION + \"','\"\n            + MIMETYPE_CAPABILITY_FILE_TRANSFER + \"','\" + MIMETYPE_CAPABILITY_GEOLOCATION_PUSH\n            + \"','\" + MIMETYPE_CAPABILITY_EXTENSIONS + \"')\";\n\n    private static final String RCS_CONTACT_GROUP_NAME = RcsAccountManager.ACCOUNT_MANAGER_TYPE;\n\n    private static final String[] PROJ_CONTACT_GROUP_ID = new String[] {\n        Groups._ID\n    };\n\n    private static final String SEL_RCS_CONTACT_GROUP_ACCOUNT_TYPE = Groups.ACCOUNT_TYPE + \"='\"\n            + RCS_CONTACT_GROUP_NAME + \"'\";\n\n    /**\n     * Current instance\n     */\n    private static volatile ContactManager sInstance;\n\n    private final ContentResolver mContentResolver;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final Context mContext;\n\n    private final RcsSettings mRcsSettings;\n\n    private final Map<ContactId, ContactInfo> mContactInfoCache;\n\n    private static final Logger sLogger = Logger.getLogger(ContactManager.class.getSimpleName());\n\n    /**\n     * Get or Create singleton instance of ContactManager\n     * \n     * @param ctx Application context\n     * @param contentResolver Content resolver\n     * @param localContentResolver Local content resolver\n     * @param rcsSettings The accessor to RCS settings\n     * @return singleton instance of ContactManager\n     */\n    public static ContactManager getInstance(Context ctx, ContentResolver contentResolver,\n            LocalContentResolver localContentResolver, RcsSettings rcsSettings) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (ContactManager.class) {\n            if (sInstance == null) {\n                sInstance = new ContactManager(ctx, contentResolver, localContentResolver,\n                        rcsSettings);\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param context Application context\n     * @param contentResolver Content resolver\n     * @param localContentResolver Local content resolver\n     * @param rcsSettings RCS settings accessor\n     */\n    private ContactManager(Context context, ContentResolver contentResolver,\n            LocalContentResolver localContentResolver, RcsSettings rcsSettings) {\n        mContext = context;\n        mContentResolver = contentResolver;\n        mLocalContentResolver = localContentResolver;\n        mContactInfoCache = new HashMap<>();\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Returns my presence info from the RCS contact provider\n     * \n     * @return Presence info or null in case of error\n     */\n    public PresenceInfo getMyPresenceInfo() {\n        if (!mRcsSettings.isSocialPresenceSupported()) {\n            return new PresenceInfo();\n        }\n        Cursor cursor = getRawContactDataCursor(getRawContactIdForMe());\n        CursorUtil.assertCursorIsNotNull(cursor, Data.CONTENT_URI);\n        return getContactInfoFromCursor(cursor).getPresenceInfo();\n    }\n\n    /**\n     * Set the info of a contact. This method is by choice not synchronized here since the methods\n     * invoking this will handle the synchronization and we would like to avoid double locks.\n     * \n     * @param newInfo New contact info\n     * @param oldInfo Old contact info\n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    private void setContactInfoInternal(ContactInfo newInfo, ContactInfo oldInfo)\n            throws ContactManagerException, FileAccessException {\n        ContactId contact = newInfo.getContact();\n        String contactNumber = contact.toString();\n        boolean logActivated = sLogger.isActivated();\n        /* Update contactInfo cache with new contact information */\n        mContactInfoCache.put(contact, newInfo);\n\n        /* Check if we have an entry for the contact */\n        boolean hasEntryInRcsContactAddressBook = isContactIdAssociatedWithRcsContactProvider(contact);\n\n        ContentValues values = new ContentValues();\n        values.put(KEY_CONTACT, contactNumber);\n\n        /* Save RCS status */\n        values.put(KEY_RCS_STATUS, newInfo.getRcsStatus().toInt());\n        values.put(KEY_RCS_STATUS_TIMESTAMP, newInfo.getRcsStatusTimestamp());\n\n        /* Save display name */\n        values.put(KEY_DISPLAY_NAME, newInfo.getDisplayName());\n\n        /* Save capabilities */\n        Capabilities newCapa = newInfo.getCapabilities();\n        values.put(KEY_CAPABILITY_CS_VIDEO, newCapa.isCsVideoSupported());\n        values.put(KEY_CAPABILITY_FILE_TRANSFER, newCapa.isFileTransferMsrpSupported());\n        values.put(KEY_CAPABILITY_IMAGE_SHARE, newCapa.isImageSharingSupported());\n        values.put(KEY_CAPABILITY_IM_SESSION, newCapa.isImSessionSupported());\n        values.put(KEY_CAPABILITY_VIDEO_SHARE, newCapa.isVideoSharingSupported());\n        values.put(KEY_CAPABILITY_GEOLOC_PUSH, newCapa.isGeolocationPushSupported());\n        values.put(KEY_CAPABILITY_FILE_TRANSFER_HTTP, newCapa.isFileTransferHttpSupported());\n        values.put(KEY_CAPABILITY_FILE_TRANSFER_THUMBNAIL,\n                newCapa.isFileTransferThumbnailSupported());\n        values.put(KEY_CAPABILITY_IP_VOICE_CALL, newCapa.isIPVoiceCallSupported());\n        values.put(KEY_CAPABILITY_IP_VIDEO_CALL, newCapa.isIPVideoCallSupported());\n        values.put(KEY_CAPABILITY_FILE_TRANSFER_SF, newCapa.isFileTransferStoreForwardSupported());\n        values.put(KEY_AUTOMATA, newCapa.isSipAutomata());\n        values.put(KEY_CAPABILITY_GROUP_CHAT_SF, newCapa.isGroupChatStoreForwardSupported());\n        values.put(KEY_CAPABILITY_EXTENSIONS,\n                ServiceExtensionManager.getExtensions(newCapa.getSupportedExtensions()));\n        values.put(KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST, newCapa.getTimestampOfLastRequest());\n        values.put(KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE, newCapa.getTimestampOfLastResponse());\n        values.put(KEY_CAPABILITY_PRESENCE_DISCOVERY, newCapa.isPresenceDiscoverySupported());\n        values.put(KEY_CAPABILITY_SOCIAL_PRESENCE, newCapa.isSocialPresenceSupported());\n\n        PhotoIcon photoIcon = null;\n\n        /* Save presence information */\n        PresenceInfo newPresenceInfo = newInfo.getPresenceInfo();\n        if (newPresenceInfo != null) {\n            values.put(KEY_PRESENCE_SHARING_STATUS, newPresenceInfo.getPresenceStatus());\n            values.put(KEY_PRESENCE_FREE_TEXT, newPresenceInfo.getFreetext());\n            FavoriteLink favLink = newPresenceInfo.getFavoriteLink();\n            if (favLink == null) {\n                values.put(KEY_PRESENCE_WEBLINK_NAME, \"\");\n                values.put(KEY_PRESENCE_WEBLINK_URL, \"\");\n            } else {\n                values.put(KEY_PRESENCE_WEBLINK_NAME, favLink.getName());\n                values.put(KEY_PRESENCE_WEBLINK_URL, favLink.getLink());\n            }\n\n            Geoloc geoloc = newPresenceInfo.getGeoloc();\n            if (geoloc == null) {\n                values.put(KEY_PRESENCE_GEOLOC_EXIST_FLAG, FALSE_VALUE);\n                values.put(KEY_PRESENCE_GEOLOC_LATITUDE, 0);\n                values.put(KEY_PRESENCE_GEOLOC_LONGITUDE, 0);\n                values.put(KEY_PRESENCE_GEOLOC_ALTITUDE, 0);\n            } else {\n                values.put(KEY_PRESENCE_GEOLOC_EXIST_FLAG, TRUE_VALUE);\n                values.put(KEY_PRESENCE_GEOLOC_LATITUDE, geoloc.getLatitude());\n                values.put(KEY_PRESENCE_GEOLOC_LONGITUDE, geoloc.getLongitude());\n                values.put(KEY_PRESENCE_GEOLOC_ALTITUDE, geoloc.getAltitude());\n            }\n            values.put(KEY_PRESENCE_TIMESTAMP, newPresenceInfo.getTimestamp());\n\n            photoIcon = newPresenceInfo.getPhotoIcon();\n            if (photoIcon == null) {\n                values.put(KEY_PRESENCE_PHOTO_ETAG, \"\");\n                values.put(KEY_PRESENCE_PHOTO_EXIST_FLAG, FALSE_VALUE);\n            } else {\n                if (photoIcon.getContent() != null) {\n                    values.put(KEY_PRESENCE_PHOTO_EXIST_FLAG, TRUE_VALUE);\n                } else {\n                    values.put(KEY_PRESENCE_PHOTO_EXIST_FLAG, FALSE_VALUE);\n                }\n                values.put(KEY_PRESENCE_PHOTO_ETAG, photoIcon.getEtag());\n            }\n        } else {\n            values.put(KEY_PRESENCE_TIMESTAMP, INVALID_TIME);\n        }\n\n        /* Save blocking state */\n        if (BlockingState.BLOCKED == newInfo.getBlockingState()) {\n            values.put(KEY_BLOCKED, BLOCKED_VALUE_SET);\n            values.put(KEY_BLOCKING_TIMESTAMP, newInfo.getBlockingTimestamp());\n        } else {\n            values.put(KEY_BLOCKED, BLOCKED_VALUE_NOT_SET);\n            values.put(KEY_BLOCKING_TIMESTAMP, INVALID_TIME);\n        }\n\n        values.put(KEY_TIMESTAMP_CONTACT_UPDATED, System.currentTimeMillis());\n\n        /* Save the registration state */\n        values.put(KEY_REGISTRATION_STATE, newInfo.getRegistrationState().toInt());\n\n        if (hasEntryInRcsContactAddressBook) {\n            if (logActivated) {\n                sLogger.info(\"Update RCS contact \".concat(contactNumber));\n            }\n            /* RCS contact already exists in provider: update RABP entry */\n            Uri uri = Uri.withAppendedPath(CONTENT_URI, contactNumber);\n            mLocalContentResolver.update(uri, values, null, null);\n        } else {\n            if (logActivated) {\n                sLogger.info(\"Insert new contact \".concat(contactNumber));\n            }\n            /* RCS contact does not exists in provider: insert entry in RABP */\n            mLocalContentResolver.insert(CONTENT_URI, values);\n        }\n\n        /* Save presence photo content */\n        if (photoIcon != null) {\n            savePhotoIcon(photoIcon, contact);\n        }\n\n        /* Get all the IDs from raw contacts that have this phone number */\n        Set<Long> rawContactIds = getRawContactIdsFromPhoneNumber(contact);\n        if (rawContactIds.isEmpty()) {\n            /*\n             * If the number is not in the native address book, work is done.\n             */\n            return;\n        }\n        boolean isRcsContact = newInfo.isRcsContact();\n        /* For each entries in the native address book, prepare the modifications */\n        ArrayList<ContentProviderOperation> ops = new ArrayList<>();\n        for (Long rawContactId : rawContactIds) {\n            /* Get the associated RCS raw contact ID */\n            long rcsRawContactId = getAssociatedRcsRawContact(rawContactId, contact);\n\n            if (!isRcsContact) {\n                /*\n                 * If the contact is not a RCS contact anymore, we delete the corresponding native\n                 * raw contacts.\n                 */\n                ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)\n                        .withSelection(SEL_RAW_CONTACT, new String[] {\n                            Long.toString(rcsRawContactId)\n                        }).build());\n                /* Also delete the corresponding entries in the RCS aggregation provider. */\n                mLocalContentResolver.delete(AggregationData.CONTENT_URI, WHERE_RCS_RAW_CONTACT_ID,\n                        new String[] {\n                            Long.toString(rcsRawContactId)\n                        });\n            } else {\n                /* If the contact is still a RCS contact, we update the native raw contacts. */\n                if (INVALID_ID == rcsRawContactId) {\n                    /*\n                     * If no RCS raw contact ID is associated to the raw contact, create one with\n                     * the right information.\n                     */\n                    createRcsRawContact(newInfo, rawContactId);\n                    /* Nothing to modify, as the new contact will have taken the new information. */\n                    continue;\n                }\n\n                /* Modify the contact type */\n                if (newInfo.getRcsStatus() != oldInfo.getRcsStatus()) {\n                    /* Update status in RCS contact provider if it has changed */\n                    updateRcsStatusOrCreateNewContact(contact, newInfo.getRcsStatus());\n                }\n\n                /* Modify the capabilities */\n                Capabilities oldCapa = oldInfo.getCapabilities();\n                ContentProviderOperation op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_FILE_TRANSFER, newCapa.isFileTransferMsrpSupported(),\n                        oldCapa.isFileTransferMsrpSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_IMAGE_SHARE, newCapa.isImageSharingSupported(),\n                        oldCapa.isImageSharingSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_IM_SESSION, newCapa.isImSessionSupported(),\n                        oldCapa.isImSessionSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_VIDEO_SHARE, newCapa.isVideoSharingSupported(),\n                        oldCapa.isVideoSharingSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_IP_VOICE_CALL, newCapa.isIPVoiceCallSupported(),\n                        oldCapa.isIPVoiceCallSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_IP_VIDEO_CALL, newCapa.isIPVideoCallSupported(),\n                        oldCapa.isIPVideoCallSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                op = modifyMimeTypeForContact(rcsRawContactId, contact,\n                        MIMETYPE_CAPABILITY_GEOLOCATION_PUSH, newCapa.isGeolocationPushSupported(),\n                        oldCapa.isGeolocationPushSupported());\n                if (op != null) {\n                    ops.add(op);\n                }\n                /* Modify the RCS extensions */\n                op = modifyExtensionsCapabilityForContact(rcsRawContactId, contact,\n                        newCapa.getSupportedExtensions(), oldCapa.getSupportedExtensions());\n                if (op != null) {\n                    ops.add(op);\n                }\n                /* Modify the Blocking state */\n                op = modifyBlockingStateForContact(rcsRawContactId, contact,\n                        newInfo.getBlockingState(), oldInfo.getBlockingState());\n                if (op != null) {\n                    ops.add(op);\n                }\n\n                /* Modify the Blocking timestamp */\n                op = modifyBlockingTimestampForContact(rcsRawContactId, contact,\n                        newInfo.getBlockingTimestamp(), oldInfo.getBlockingTimestamp());\n                if (op != null) {\n                    ops.add(op);\n                }\n\n                /* New contact registration state */\n                String newFreeText = \"\";\n                if (newInfo.getPresenceInfo() != null) {\n                    newFreeText = newInfo.getPresenceInfo().getFreetext();\n                }\n                /* Old contact registration state */\n                String oldFreeText = \"\";\n                if (oldInfo.getPresenceInfo() != null) {\n                    oldFreeText = oldInfo.getPresenceInfo().getFreetext();\n                }\n                List<ContentProviderOperation> registrationOps = modifyContactRegistrationState(\n                        rcsRawContactId, contact, newInfo.getRegistrationState(),\n                        oldInfo.getRegistrationState(), newFreeText, oldFreeText);\n                for (ContentProviderOperation registrationOperation : registrationOps) {\n                    if (registrationOperation != null) {\n                        ops.add(registrationOperation);\n                    }\n                }\n\n                /* Presence fields */\n                List<ContentProviderOperation> presenceOps = modifyPresenceForContact(\n                        rcsRawContactId, contact, newInfo.getPresenceInfo(),\n                        oldInfo.getPresenceInfo());\n                for (ContentProviderOperation presenceOperation : presenceOps) {\n                    if (presenceOperation != null) {\n                        ops.add(presenceOperation);\n                    }\n                }\n            }\n        }\n\n        if (!ops.isEmpty()) {\n            if (logActivated) {\n                sLogger.info(\"Execute \" + ops.size()\n                        + \" operations to update native address book for contact \" + contactNumber\n                        + \" (for raw contact IDs: \" + Arrays.toString(rawContactIds.toArray())\n                        + \")\");\n            }\n            /* Do the actual database modifications */\n            try {\n                mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);\n\n            } catch (RemoteException | OperationApplicationException e) {\n                throw new ContactManagerException(\"Unable to apply batch updates for contact :\"\n                        + newInfo.getContact(), e);\n            }\n        }\n    }\n\n    /**\n     * Get the contact info from the RCS contact provider\n     * \n     * @param contact Contact\n     * @return Contact info\n     */\n    private ContactInfo getContactInfoFromProvider(ContactId contact) {\n        ContactInfo infos = new ContactInfo();\n        infos.setRcsStatus(RcsStatus.NO_INFO);\n        infos.setRcsStatusTimestamp(System.currentTimeMillis());\n        infos.setContact(contact);\n\n        CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder();\n\n        PresenceInfo presenceInfo = new PresenceInfo();\n\n        infos.setRegistrationState(RegistrationState.UNKNOWN);\n\n        infos.setBlockingState(BlockingState.NOT_BLOCKED);\n        infos.setBlockingTimestamp(INVALID_TIME);\n\n        Cursor cursor = null;\n        String contactNumber = contact.toString();\n        Uri uri = Uri.withAppendedPath(CONTENT_URI, contactNumber);\n        try {\n            cursor = mLocalContentResolver.query(uri, null, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, uri);\n            if (cursor.moveToFirst()) {\n                // Get RCS display name\n                infos.setDisplayName(cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_DISPLAY_NAME)));\n\n                // Get RCS Status\n                int rcsStatus = cursor.getInt(cursor.getColumnIndexOrThrow(KEY_RCS_STATUS));\n                infos.setRcsStatus(RcsStatus.valueOf(rcsStatus));\n\n                infos.setRcsStatusTimestamp(cursor.getLong(cursor\n                        .getColumnIndexOrThrow(KEY_RCS_STATUS_TIMESTAMP)));\n\n                int registrationState = cursor.getInt(cursor\n                        .getColumnIndexOrThrow(KEY_REGISTRATION_STATE));\n                infos.setRegistrationState(RegistrationState.valueOf(registrationState));\n\n                int blockingState = cursor.getInt(cursor.getColumnIndexOrThrow(KEY_BLOCKED));\n                infos.setBlockingState(BlockingState.valueOf(blockingState));\n\n                long blockingTimestamp = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(KEY_BLOCKING_TIMESTAMP));\n                infos.setBlockingTimestamp(blockingTimestamp);\n\n                // Get Presence info\n                presenceInfo.setPresenceStatus(cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_SHARING_STATUS)));\n\n                FavoriteLink favLink = new FavoriteLink(cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_WEBLINK_NAME)), cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_WEBLINK_URL)));\n                presenceInfo.setFavoriteLink(favLink);\n                presenceInfo.setFavoriteLinkUrl(favLink.getLink());\n\n                presenceInfo.setFreetext(cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_FREE_TEXT)));\n\n                Geoloc geoloc = null;\n                if (Boolean.parseBoolean(cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_GEOLOC_EXIST_FLAG)))) {\n                    geoloc = new Geoloc(cursor.getDouble(cursor\n                            .getColumnIndexOrThrow(KEY_PRESENCE_GEOLOC_LATITUDE)),\n                            cursor.getDouble(cursor\n                                    .getColumnIndexOrThrow(KEY_PRESENCE_GEOLOC_LONGITUDE)),\n                            cursor.getDouble(cursor\n                                    .getColumnIndexOrThrow(KEY_PRESENCE_GEOLOC_ALTITUDE)));\n                }\n                presenceInfo.setGeoloc(geoloc);\n\n                presenceInfo.setTimestamp(cursor.getLong(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_TIMESTAMP)));\n\n                if (Boolean.parseBoolean(cursor.getString(cursor\n                        .getColumnIndexOrThrow(KEY_PRESENCE_PHOTO_EXIST_FLAG)))) {\n                    try {\n                        presenceInfo.setPhotoIcon(getPhotoIcon(cursor, contact));\n                    } catch (IOException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(e.getMessage());\n                        }\n                    }\n                }\n\n                // Get the capabilities infos\n                capaBuilder.setCsVideo(isCapabilitySupported(cursor, KEY_CAPABILITY_CS_VIDEO));\n                capaBuilder.setFileTransferMsrp(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_FILE_TRANSFER));\n                capaBuilder.setImageSharing(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_IMAGE_SHARE));\n                capaBuilder.setImSession(isCapabilitySupported(cursor, KEY_CAPABILITY_IM_SESSION));\n                capaBuilder.setPresenceDiscovery(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_PRESENCE_DISCOVERY));\n                capaBuilder.setSocialPresence(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_SOCIAL_PRESENCE));\n                capaBuilder.setGeolocationPush(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_GEOLOC_PUSH));\n                capaBuilder.setVideoSharing(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_VIDEO_SHARE));\n                capaBuilder.setFileTransferThumbnail(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_FILE_TRANSFER_THUMBNAIL));\n                capaBuilder.setFileTransferHttp(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_FILE_TRANSFER_HTTP));\n                capaBuilder.setIpVoiceCall(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_IP_VOICE_CALL));\n                capaBuilder.setIpVideoCall(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_IP_VIDEO_CALL));\n                capaBuilder.setFileTransferStoreForward(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_FILE_TRANSFER_SF));\n                capaBuilder.setGroupChatStoreForward(isCapabilitySupported(cursor,\n                        KEY_CAPABILITY_GROUP_CHAT_SF));\n                capaBuilder.setSipAutomata(isCapabilitySupported(cursor, KEY_AUTOMATA));\n                capaBuilder.setExtensions(ServiceExtensionManager.getExtensions(cursor\n                        .getString(cursor.getColumnIndexOrThrow(KEY_CAPABILITY_EXTENSIONS))));\n                capaBuilder.setTimestampOfLastRequest(cursor.getLong(cursor\n                        .getColumnIndexOrThrow(KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST)));\n                capaBuilder.setTimestampOfLastResponse(cursor.getLong(cursor\n                        .getColumnIndexOrThrow(KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE)));\n            }\n            infos.setPresenceInfo(presenceInfo);\n            infos.setCapabilities(capaBuilder.build());\n            return infos;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Get contact info . This method is by choice not synchronized here since the methods invoking\n     * this will handle the synchronization and we would like to avoid double locks.\n     * \n     * @param contact the contact ID\n     * @return ContactInfo\n     */\n    private ContactInfo getContactInfoInternal(ContactId contact) {\n        ContactInfo contactInfo = mContactInfoCache.get(contact);\n        if (contactInfo == null) {\n            contactInfo = getContactInfoFromProvider(contact);\n            mContactInfoCache.put(contact, contactInfo);\n        }\n        return contactInfo;\n    }\n\n    /**\n     * Save photo icon\n     * \n     * @param photoIcon the photo icon\n     * @param contact the contact ID\n     * @throws FileAccessException\n     */\n    private void savePhotoIcon(PhotoIcon photoIcon, ContactId contact) throws FileAccessException {\n        byte photoContent[] = photoIcon.getContent();\n        if (photoContent == null) {\n            return;\n        }\n        Uri photoUri = Uri.withAppendedPath(CONTENT_URI, contact.toString());\n        OutputStream outstream = null;\n        try {\n            outstream = mLocalContentResolver.openContentOutputStream(photoUri);\n            outstream.write(photoContent);\n            outstream.flush();\n        } catch (IOException e) {\n            throw new FileAccessException(\"Failed to save photo icon for contact : \" + contact, e);\n\n        } finally {\n            // noinspection ThrowableResultOfMethodCallIgnored\n            CloseableUtils.tryToClose(outstream);\n        }\n    }\n\n    /**\n     * Get photo icon from RCS contact provider\n     * \n     * @param cursor The cursor\n     * @param contact The contact ID\n     * @return PhotoIcon or null\n     * @throws IOException\n     */\n    private PhotoIcon getPhotoIcon(Cursor cursor, ContactId contact) throws IOException {\n        Uri photoUri = Uri.withAppendedPath(CONTENT_URI, contact.toString());\n        String etag = cursor.getString(cursor.getColumnIndexOrThrow(KEY_PRESENCE_PHOTO_ETAG));\n        InputStream stream = mLocalContentResolver.openContentInputStream(photoUri);\n        byte[] content = new byte[stream.available()];\n        stream.read(content, 0, content.length);\n        Bitmap bmp = BitmapFactory.decodeByteArray(content, 0, content.length);\n        if (bmp == null) {\n            throw new IOException(\"unable to create icon for contact :\" + contact);\n        }\n        return new PhotoIcon(content, bmp.getWidth(), bmp.getHeight(), etag);\n    }\n\n    /**\n     * Get sharing status of a contact\n     * \n     * @param contact Contact\n     * @return sharing status or NO_INFO if cannot be retrieved\n     */\n    private RcsStatus getContactSharingStatus(ContactId contact) {\n        return getContactInfo(contact).getRcsStatus();\n    }\n\n    /**\n     * Block a contact\n     * \n     * @param contact Contact ID\n     * @throws ContactManagerException exception thrown if update operation has failed\n     * @throws FileAccessException\n     */\n    public void blockContact(ContactId contact) throws ContactManagerException, FileAccessException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Block contact \".concat(contact.toString()));\n        }\n        synchronized (mContactInfoCache) {\n            ContactInfo oldInfo = getContactInfoInternal(contact);\n            ContactInfo newInfo = new ContactInfo(oldInfo);\n            newInfo.setRcsStatus(RcsStatus.BLOCKED);\n            setContactInfoInternal(newInfo, oldInfo);\n        }\n    }\n\n    /**\n     * Flush the RCS contact provider\n     */\n    public void flushRcsContactProvider() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"clear ContactInfo cache\");\n        }\n        synchronized (mContactInfoCache) {\n            mContactInfoCache.clear();\n            mLocalContentResolver.delete(CONTENT_URI, null, null);\n        }\n    }\n\n    /**\n     * Update status if contact exists in RCS provider. If it does not already exists, create a new\n     * contact with default attributes.\n     * \n     * @param contact Contact ID\n     * @param rcsStatus RCS status\n     */\n    public void updateRcsStatusOrCreateNewContact(ContactId contact, RcsStatus rcsStatus) {\n        synchronized (mContactInfoCache) {\n            long currentTime = System.currentTimeMillis();\n            ContentValues values = new ContentValues();\n            values.put(KEY_PRESENCE_SHARING_STATUS, rcsStatus.toInt());\n            values.put(KEY_TIMESTAMP_CONTACT_UPDATED, currentTime);\n            if (isContactIdAssociatedWithRcsContactProvider(contact)) {\n                /* Contact already present, update. */\n                Uri uri = Uri.withAppendedPath(CONTENT_URI, contact.toString());\n                mLocalContentResolver.update(uri, values, null, null);\n            } else {\n                /* Contact not present in provider, insert. */\n                values.put(KEY_CONTACT, contact.toString());\n                values.put(KEY_RCS_STATUS, rcsStatus.toInt());\n                values.put(KEY_RCS_STATUS_TIMESTAMP, currentTime);\n                values.put(KEY_REGISTRATION_STATE, RegistrationState.UNKNOWN.toInt());\n                values.put(KEY_PRESENCE_TIMESTAMP, -1);\n                values.put(KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST, Capabilities.INVALID_TIMESTAMP);\n                values.put(KEY_CAPABILITY_CS_VIDEO, 0);\n                values.put(KEY_CAPABILITY_IMAGE_SHARE, 0);\n                values.put(KEY_CAPABILITY_VIDEO_SHARE, 0);\n                values.put(KEY_CAPABILITY_IM_SESSION, 0);\n                values.put(KEY_CAPABILITY_FILE_TRANSFER, 0);\n                values.put(KEY_CAPABILITY_PRESENCE_DISCOVERY, 0);\n                values.put(KEY_CAPABILITY_SOCIAL_PRESENCE, 0);\n                values.put(KEY_CAPABILITY_GEOLOC_PUSH, 0);\n                values.put(KEY_CAPABILITY_FILE_TRANSFER_HTTP, 0);\n                values.put(KEY_CAPABILITY_FILE_TRANSFER_THUMBNAIL, 0);\n                values.put(KEY_CAPABILITY_IP_VOICE_CALL, 0);\n                values.put(KEY_CAPABILITY_IP_VIDEO_CALL, 0);\n                values.put(KEY_CAPABILITY_FILE_TRANSFER_SF, 0);\n                values.put(KEY_CAPABILITY_GROUP_CHAT_SF, 0);\n                values.put(KEY_BLOCKED, BLOCKED_VALUE_NOT_SET);\n                values.put(KEY_BLOCKING_TIMESTAMP, INVALID_TIME);\n                values.put(KEY_AUTOMATA, 0);\n                values.put(KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE, Capabilities.INVALID_TIMESTAMP);\n                mLocalContentResolver.insert(CONTENT_URI, values);\n            }\n            getContactInfoInternal(contact).setRcsStatus(rcsStatus);\n        }\n    }\n\n    /**\n     * Get the RCS contacts in the RCS contact provider which have a presence relationship with the\n     * user\n     * \n     * @return set containing all RCS contacts, \"Me\" item excluded\n     */\n    public Set<ContactId> getRcsContactsWithSocialPresence() {\n        Set<ContactId> rcsNumbers = new HashSet<>();\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(CONTENT_URI, PROJ_RCSCONTACT_CONTACT,\n                    WHERE_RCS_STATUS_WITH_SOCIAL_PRESENCE, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return rcsNumbers;\n            }\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(KEY_CONTACT);\n            do {\n                String contact = cursor.getString(contactColumnIdx);\n                /* Do not check validity of trusted data */\n                rcsNumbers.add(ContactUtil.createContactIdFromTrustedData(contact));\n            } while (cursor.moveToNext());\n            return rcsNumbers;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Gets the RCS contacts from RCS contact provider\n     * \n     * @return set containing all RCS contacts\n     */\n    public Set<ContactId> getRcsContactsFromRcsContactProvider() {\n        Set<ContactId> rcsNumbers = new HashSet<>();\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(CONTENT_URI, PROJ_RCSCONTACT_CONTACT,\n                    WHERE_RCS_STATUS_RCS, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return rcsNumbers;\n            }\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(KEY_CONTACT);\n            do {\n                String contact = cursor.getString(contactColumnIdx);\n                /* Do no check validity of trusted data */\n                rcsNumbers.add(ContactUtil.createContactIdFromTrustedData(contact));\n            } while (cursor.moveToNext());\n            return rcsNumbers;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Get all contacts from RCS contact provider\n     * \n     * @return set containing all contacts that have been at least queried once for capabilities\n     */\n    public Set<ContactId> getAllContactsFromRcsContactProvider() {\n        Set<ContactId> numbers = new HashSet<>();\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(CONTENT_URI, PROJ_RCSCONTACT_CONTACT, null, null,\n                    null);\n            CursorUtil.assertCursorIsNotNull(cursor, CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return numbers;\n            }\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(KEY_CONTACT);\n            do {\n                String contact = cursor.getString(contactColumnIdx);\n                /* Do not check validity of trusted data */\n                numbers.add(ContactUtil.createContactIdFromTrustedData(contact));\n            } while (cursor.moveToNext());\n            return numbers;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Is the number in the RCS blocked list\n     * \n     * @param contact contact to check\n     * @return boolean\n     */\n    public boolean isNumberBlocked(ContactId contact) {\n        return RcsStatus.BLOCKED.equals(getContactSharingStatus(contact));\n    }\n\n    /**\n     * Is the number in the RCS buddy list\n     * \n     * @param contact contact to check\n     * @return boolean\n     */\n    public boolean isNumberShared(ContactId contact) {\n        return RcsStatus.ACTIVE.equals(getContactSharingStatus(contact));\n    }\n\n    /**\n     * Has the number been invited to RCS\n     * \n     * @param contact contact to check\n     * @return boolean\n     */\n    public boolean isNumberInvited(ContactId contact) {\n        return RcsStatus.PENDING.equals(getContactSharingStatus(contact));\n    }\n\n    /**\n     * Has the number invited us to RCS\n     * \n     * @param contact contact to check\n     * @return boolean\n     */\n    public boolean isNumberWilling(ContactId contact) {\n        return RcsStatus.PENDING_OUT.equals(getContactSharingStatus(contact));\n    }\n\n    /**\n     * Has the number invited us to RCS then be cancelled\n     * \n     * @param contact contact to check\n     * @return boolean\n     */\n    public boolean isNumberCancelled(ContactId contact) {\n        return RcsStatus.CANCELLED.equals(getContactSharingStatus(contact));\n    }\n\n    /**\n     * Modify the corresponding mimetype row for the contact\n     *\n     * @param rawContactId Raw contact id of the RCS contact\n     * @param rcsNumber RCS number of the contact\n     * @param mimeType Mime type associated to the capability\n     * @param newState True if the capability must be enabled, else false\n     * @param oldState True if the capability was enabled, else false\n     * @return ContentProviderOperation to be done or null if state is unchanged\n     */\n    private ContentProviderOperation modifyMimeTypeForContact(long rawContactId,\n            ContactId rcsNumber, String mimeType, boolean newState, boolean oldState) {\n        if (newState == oldState) {\n            /* Nothing to do */\n            return null;\n        }\n        if (newState) {\n            /* We have to insert a new data in the raw contact */\n            return insertMimeTypeForContact(rawContactId, rcsNumber, mimeType);\n        }\n        /* We have to remove the data from the raw contact */\n        return deleteMimeTypeForContact(rawContactId, rcsNumber, mimeType);\n    }\n\n    private ContentProviderOperation createMimeTypeForContact(int rawContactId,\n            ContactId rcsNumber, String mimeType) {\n        String mimeTypeDescriptionSummary = getMimeTypeDescriptionSummary(mimeType);\n        /* Check if there is a mimetype description to be added */\n        if (mimeTypeDescriptionSummary != null) {\n            String mimeTypeDescriptionDetails = getMimeTypeDescriptionDetails(mimeType);\n            return ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                    .withValueBackReference(Data.RAW_CONTACT_ID, rawContactId)\n                    .withValue(Data.MIMETYPE, mimeType).withValue(Data.DATA1, rcsNumber.toString())\n                    .withValue(Data.DATA2, mimeTypeDescriptionSummary)\n                    .withValue(Data.DATA3, mimeTypeDescriptionDetails).build();\n        }\n        return ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                .withValueBackReference(Data.RAW_CONTACT_ID, rawContactId)\n                .withValue(Data.MIMETYPE, mimeType).withValue(Data.DATA1, rcsNumber.toString())\n                .build();\n    }\n\n    private ContentProviderOperation insertMimeTypeForContact(long rawContactId,\n            ContactId rcsNumber, String mimeType) {\n        /* Check if there is a mime-type description to be added */\n        String mimeTypeDescriptionSummary = getMimeTypeDescriptionSummary(mimeType);\n        if (mimeTypeDescriptionSummary != null) {\n            String mimeTypeDescriptionDetails = getMimeTypeDescriptionDetails(mimeType);\n            return ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                    .withValue(Data.RAW_CONTACT_ID, rawContactId)\n                    .withValue(Data.MIMETYPE, mimeType).withValue(Data.DATA1, rcsNumber.toString())\n                    .withValue(Data.DATA2, mimeTypeDescriptionSummary)\n                    .withValue(Data.DATA3, mimeTypeDescriptionDetails).build();\n        }\n        return ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                .withValue(Data.RAW_CONTACT_ID, rawContactId).withValue(Data.MIMETYPE, mimeType)\n                .withValue(Data.DATA1, rcsNumber.toString()).build();\n    }\n\n    private ContentProviderOperation deleteMimeTypeForContact(long rawContactId,\n            ContactId rcsNumber, String mimeType) {\n        // We have to remove a data from the raw contact\n        return ContentProviderOperation.newDelete(Data.CONTENT_URI)\n                .withSelection(SEL_RAW_CONTACT_MIMETYPE_DATA1, new String[] {\n                        String.valueOf(rawContactId), mimeType, rcsNumber.toString()\n                }).build();\n    }\n\n    private List<ContentProviderOperation> modifyContactRegistrationState(long rawContactId,\n            ContactId rcsNumber, RegistrationState newRegistrationState,\n            RegistrationState oldRegistrationState, String newFreeText, String oldFreeText) {\n\n        List<ContentProviderOperation> ops = new ArrayList<>();\n        boolean registrationChanged = true;\n        if ((newRegistrationState == oldRegistrationState || RegistrationState.UNKNOWN == newRegistrationState)) {\n            registrationChanged = false;\n        }\n\n        if (registrationChanged) {\n            // Modify registration status\n            ops.add(ContentProviderOperation\n                    .newUpdate(Data.CONTENT_URI)\n                    .withSelection(\n                            SEL_RAW_CONTACT_MIMETYPE_DATA1,\n                            new String[] {\n                                    Long.toString(rawContactId), MIMETYPE_REGISTRATION_STATE,\n                                    rcsNumber.toString()\n                            }).withValue(Data.DATA2, newRegistrationState.toInt()).build());\n        }\n\n        if (StringUtils.equals(newFreeText, oldFreeText) && !registrationChanged) {\n            return ops;\n        }\n\n        int availability = PRESENCE_STATUS_NOT_SET;\n        if (RegistrationState.ONLINE == newRegistrationState) {\n            availability = PRESENCE_STATUS_ONLINE;\n        } else if (RegistrationState.OFFLINE == newRegistrationState) {\n            availability = PRESENCE_STATUS_OFFLINE;\n        }\n\n        // Get the id of the status update data linked to this raw contact id\n        long dataId = INVALID_ID;\n        String[] selectionArgs = {\n            Long.toString(rawContactId)\n        };\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(Data.CONTENT_URI, PROJ_DATA_ID, SEL_RAW_CONTACT_ID,\n                    selectionArgs, null);\n            CursorUtil.assertCursorIsNotNull(cursor, Data.CONTENT_URI);\n            if (cursor.moveToNext()) {\n                dataId = cursor.getLong(cursor.getColumnIndexOrThrow(Data._ID));\n            }\n            ops.add(ContentProviderOperation\n                    .newInsert(StatusUpdates.CONTENT_URI)\n                    .withValue(StatusUpdates.DATA_ID, dataId)\n                    .withValue(StatusUpdates.STATUS, newFreeText)\n                    .withValue(StatusUpdates.STATUS_RES_PACKAGE, mContext.getPackageName())\n                    .withValue(StatusUpdates.STATUS_LABEL, R.string.rcs_core_account_id)\n                    .withValue(StatusUpdates.STATUS_ICON, R.drawable.rcs_icon)\n                    .withValue(StatusUpdates.PRESENCE, availability)\n                    // Needed for inserting PRESENCE\n                    .withValue(StatusUpdates.PROTOCOL, Im.PROTOCOL_CUSTOM)\n                    .withValue(StatusUpdates.CUSTOM_PROTOCOL, \" \" /* Intentional left blank */)\n                    .withValue(StatusUpdates.STATUS_TIMESTAMP, System.currentTimeMillis()).build());\n            return ops;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private List<ContentProviderOperation> modifyContactRegistrationStateForMyself(\n            long rawContactId, RegistrationState newRegistrationState,\n            RegistrationState oldRegistrationState, String newFreeText, String oldFreeText) {\n        List<ContentProviderOperation> ops = new ArrayList<>();\n        boolean registrationChanged = true;\n        if (newRegistrationState == oldRegistrationState\n                || RegistrationState.UNKNOWN.equals(newRegistrationState)) {\n            registrationChanged = false;\n        }\n        if (registrationChanged) {\n            // Modify registration state\n            ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                    .withSelection(SEL_RAW_CONTACT_MIMETYPE_DATA1, new String[] {\n                            Long.toString(rawContactId), MIMETYPE_REGISTRATION_STATE, MYSELF\n                    }).withValue(Data.DATA2, newRegistrationState.toInt()).build());\n        }\n        if (StringUtils.equals(newFreeText, oldFreeText) && !registrationChanged) {\n            return ops;\n        }\n        int availability = PRESENCE_STATUS_NOT_SET;\n        if (RegistrationState.ONLINE.equals(newRegistrationState)) {\n            availability = PRESENCE_STATUS_ONLINE;\n        } else if (RegistrationState.OFFLINE.equals(newRegistrationState)) {\n            availability = PRESENCE_STATUS_OFFLINE;\n        }\n        // Get the id of the status update data linked to this raw contact id\n        long dataId = INVALID_ID;\n        Cursor cur = getRawContactDataCursor(rawContactId);\n        if (cur != null && cur.moveToNext()) {\n            dataId = cur.getLong(cur.getColumnIndex(Data._ID));\n        }\n        ops.add(ContentProviderOperation\n                .newInsert(StatusUpdates.CONTENT_URI)\n                .withValue(StatusUpdates.DATA_ID, dataId)\n                .withValue(StatusUpdates.STATUS, newFreeText)\n                .withValue(StatusUpdates.STATUS_RES_PACKAGE, mContext.getPackageName())\n                .withValue(StatusUpdates.STATUS_LABEL, R.string.rcs_core_account_id)\n                .withValue(StatusUpdates.STATUS_ICON, R.drawable.rcs_icon)\n                .withValue(StatusUpdates.PRESENCE, availability)\n                // Needed for inserting PRESENCE\n                .withValue(StatusUpdates.PROTOCOL, Im.PROTOCOL_CUSTOM)\n                .withValue(StatusUpdates.CUSTOM_PROTOCOL,\n                // Intentional left blank\n                        \" \").withValue(StatusUpdates.STATUS_TIMESTAMP, System.currentTimeMillis())\n                .build());\n        return ops;\n    }\n\n    /**\n     * Modify the RCS extensions capability for the contact\n     * \n     * @param rawContactId Raw contact id of the RCS contact\n     * @param contact RCS number of the contact\n     * @param newExtensions New extensions capabilities\n     * @param oldExtensions Old extensions capabilities\n     * @return contentProviderOperation to be done of null if no update is required\n     */\n    private ContentProviderOperation modifyExtensionsCapabilityForContact(long rawContactId,\n            ContactId contact, Set<String> newExtensions, Set<String> oldExtensions) {\n        /* Compare the two lists of extensions */\n        if (newExtensions.containsAll(oldExtensions) && oldExtensions.containsAll(newExtensions)) {\n            /* Both lists have the same tags, no need to update */\n            return null;\n        }\n        return ContentProviderOperation\n                .newUpdate(Data.CONTENT_URI)\n                .withSelection(\n                        SEL_RAW_CONTACT_MIMETYPE_DATA1,\n                        new String[] {\n                                Long.toString(rawContactId), MIMETYPE_CAPABILITY_EXTENSIONS,\n                                contact.toString()\n                        })\n                .withValue(Data.DATA2, ServiceExtensionManager.getExtensions(newExtensions))\n                .build();\n    }\n\n    /**\n     * Modify blocking state for contact\n     * \n     * @param rawContactId contact id of the RCS contact\n     * @param contact RCS number of the contact\n     * @param newBlockingState new blocking state\n     * @param oldBlockingState old blocking state\n     * @return contentProviderOperation to be done of null if no update is required\n     */\n    private ContentProviderOperation modifyBlockingStateForContact(long rawContactId,\n            ContactId contact, BlockingState newBlockingState, BlockingState oldBlockingState) {\n        if (newBlockingState == oldBlockingState) {\n            return null;\n        }\n        return ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_RAW_CONTACT_MIMETYPE_DATA1, new String[] {\n                        Long.toString(rawContactId), MIMETYPE_BLOCKING_STATE, contact.toString()\n                }).withValue(Data.DATA2, newBlockingState.toInt()).build();\n    }\n\n    /**\n     * Modify blocking timestamp for contact\n     * \n     * @param rawContactId contact id of the RCS contact\n     * @param contact RCS number of the contact\n     * @param newBlockingTimestamp new blocking timestamp\n     * @param oldBlockingTimestamp old blocking timestamp\n     * @return contentProviderOperation to be done of null if no update is required\n     */\n    private ContentProviderOperation modifyBlockingTimestampForContact(long rawContactId,\n            ContactId contact, long newBlockingTimestamp, long oldBlockingTimestamp) {\n        if (newBlockingTimestamp == oldBlockingTimestamp) {\n            return null;\n        }\n        return ContentProviderOperation\n                .newUpdate(Data.CONTENT_URI)\n                .withSelection(\n                        SEL_RAW_CONTACT_MIMETYPE_DATA1,\n                        new String[] {\n                                Long.toString(rawContactId), MIMETYPE_BLOCKING_TIMESTAMP,\n                                contact.toString()\n                        }).withValue(Data.DATA2, newBlockingTimestamp).build();\n    }\n\n    private List<ContentProviderOperation> modifyPresenceForContact(long rawContactId,\n            ContactId contact, PresenceInfo newPresenceInfo, PresenceInfo oldPresenceInfo) {\n        List<ContentProviderOperation> ops = new ArrayList<>();\n        if (newPresenceInfo != null && oldPresenceInfo != null) {\n            if (!StringUtils.equals(newPresenceInfo.getFavoriteLinkUrl(),\n                    oldPresenceInfo.getFavoriteLinkUrl())) {\n\n                // Add the weblink to the native @book\n                ContentValues values = new ContentValues();\n                values.put(Data.RAW_CONTACT_ID, rawContactId);\n                values.put(Website.URL, newPresenceInfo.getFavoriteLinkUrl());\n                values.put(Website.TYPE, Website.TYPE_HOMEPAGE);\n                values.put(Data.IS_PRIMARY, 1);\n                values.put(Data.IS_SUPER_PRIMARY, 1);\n\n                // Get the id of the current weblink mimetype\n                long currentNativeWebLinkDataId = getCurrentNativeWebLinkDataId(rawContactId);\n                if (oldPresenceInfo.getFavoriteLinkUrl() == null) {\n                    // There was no weblink, insert\n                    ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI).withValues(values)\n                            .build());\n                } else if (newPresenceInfo.getFavoriteLinkUrl() != null) {\n                    // Update the existing weblink\n                    ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                            .withSelection(SEL_DATA_ID, new String[] {\n                                String.valueOf(currentNativeWebLinkDataId)\n                            }).withValues(values).build());\n                } else {\n                    // Remove the existing weblink\n                    ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)\n                            .withSelection(SEL_DATA_ID, new String[] {\n                                String.valueOf(currentNativeWebLinkDataId)\n                            }).build());\n                }\n            }\n            // Set the photo-icon\n            PhotoIcon oldPhotoIcon = oldPresenceInfo.getPhotoIcon();\n            PhotoIcon newPhotoIcon = newPresenceInfo.getPhotoIcon();\n            // Check if photo etags are the same between the two presenceInfo\n            boolean haveSameEtags = false;\n            String oldPhotoIconEtag = null;\n            String newPhotoIconEtag = null;\n            if (oldPhotoIcon != null) {\n                oldPhotoIconEtag = oldPhotoIcon.getEtag();\n            }\n            if (newPhotoIcon != null) {\n                newPhotoIconEtag = newPhotoIcon.getEtag();\n            }\n            if (oldPhotoIconEtag == null && newPhotoIconEtag == null) {\n                haveSameEtags = true;\n            } else if (oldPhotoIconEtag != null && newPhotoIconEtag != null) {\n                haveSameEtags = (oldPhotoIconEtag.equalsIgnoreCase(newPhotoIconEtag));\n            }\n            if (!haveSameEtags) {\n                // Not the same etag, so photo changed\n                // Replace photo and etag\n                List<ContentProviderOperation> photoOps = setContactPhoto(rawContactId,\n                        newPhotoIcon, true);\n                for (ContentProviderOperation photoOp : photoOps) {\n                    if (photoOp != null) {\n                        ops.add(photoOp);\n                    }\n                }\n            }\n        } else if (newPresenceInfo != null) {\n            // The new presence info is not null but the old one was, add new fields\n            RegistrationState availability = RegistrationState.UNKNOWN;\n            if (newPresenceInfo.isOnline()) {\n                availability = RegistrationState.ONLINE;\n            } else if (newPresenceInfo.isOffline()) {\n                availability = RegistrationState.OFFLINE;\n            }\n\n            // Add the presence status to native address book\n            List<ContentProviderOperation> registrationStateOps = modifyContactRegistrationState(\n                    rawContactId, contact, availability, RegistrationState.UNKNOWN,\n                    newPresenceInfo.getFreetext(), \"\");\n            for (ContentProviderOperation registrationStateOp : registrationStateOps) {\n                if (registrationStateOp != null) {\n                    ops.add(registrationStateOp);\n                }\n            }\n\n            // Add the weblink to the native @book\n            ContentValues values = new ContentValues();\n            values.put(Data.RAW_CONTACT_ID, rawContactId);\n            values.put(Website.URL, newPresenceInfo.getFavoriteLinkUrl());\n            values.put(Website.TYPE, Website.TYPE_HOMEPAGE);\n            values.put(Data.IS_PRIMARY, 1);\n            values.put(Data.IS_SUPER_PRIMARY, 1);\n\n            // Get the id of the current weblink mimetype\n            long currentNativeWebLinkDataId = getCurrentNativeWebLinkDataId(rawContactId);\n\n            if (newPresenceInfo.getFavoriteLinkUrl() != null) {\n                // Update the existing weblink\n                ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                        .withSelection(SEL_DATA_ID, new String[] {\n                            String.valueOf(currentNativeWebLinkDataId)\n                        }).withValues(values).build());\n            } else {\n                // Remove the existing weblink\n                ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)\n                        .withSelection(SEL_DATA_ID, new String[] {\n                            String.valueOf(currentNativeWebLinkDataId)\n                        }).build());\n            }\n\n            // Set the photo\n            List<ContentProviderOperation> photoOps = setContactPhoto(rawContactId,\n                    newPresenceInfo.getPhotoIcon(), true);\n            for (ContentProviderOperation photoOp : photoOps) {\n                if (photoOp != null) {\n                    ops.add(photoOp);\n                }\n            }\n\n        } else if (oldPresenceInfo != null) {\n            // The new presence info is null but the old one was not, remove fields\n\n            // Remove the presence status to native address book\n            // Force presence status to offline and free text to null\n            List<ContentProviderOperation> registrationStateOps = modifyContactRegistrationState(\n                    rawContactId, contact, RegistrationState.OFFLINE, RegistrationState.UNKNOWN,\n                    \"\", oldPresenceInfo.getFreetext());\n            for (ContentProviderOperation registrationStateOp : registrationStateOps) {\n                if (registrationStateOp != null) {\n                    ops.add(registrationStateOp);\n                }\n            }\n\n            // Remove presence web link in native address book\n            // Add the weblink to the native @book\n            // Get the id of the current weblink mimetype\n            long currentNativeWebLinkDataId = getCurrentNativeWebLinkDataId(rawContactId);\n\n            ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)\n                    .withSelection(SEL_DATA_ID, new String[] {\n                        String.valueOf(currentNativeWebLinkDataId)\n                    }).build());\n\n            // Set the photo\n            List<ContentProviderOperation> photoOps = setContactPhoto(rawContactId, null, true);\n            for (ContentProviderOperation photoOp : photoOps) {\n                if (photoOp != null) {\n                    ops.add(photoOp);\n                }\n            }\n        }\n        return ops;\n    }\n\n    /**\n     * Get the id of the current weblink mimetype\n     * \n     * @param rawContactId The raw contact ID\n     * @return id\n     */\n    private long getCurrentNativeWebLinkDataId(long rawContactId) {\n        Cursor cur = null;\n        try {\n            cur = mContentResolver.query(Data.CONTENT_URI, PROJ_DATA_ID,\n                    SEL_RAW_CONTACT_WITH_WEBLINK, new String[] {\n                            Long.toString(rawContactId), String.valueOf(Website.TYPE_HOMEPAGE)\n                    }, null);\n            CursorUtil.assertCursorIsNotNull(cur, Data.CONTENT_URI);\n\n            if (cur.moveToNext()) {\n                return cur.getLong(cur.getColumnIndexOrThrow(Data._ID));\n            }\n            return INVALID_ID;\n        } finally {\n            CursorUtil.close(cur);\n        }\n    }\n\n    /**\n     * Get description associated to a MIME type. This string will be visible in the contact card\n     * \n     * @param mimeType MIME type\n     * @return String\n     */\n    private String getMimeTypeDescriptionSummary(String mimeType) {\n        if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_FILE_TRANSFER)) {\n            return mContext.getString(R.string.rcs_core_contact_file_transfer_summary);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IM_SESSION)) {\n            return mContext.getString(R.string.rcs_core_contact_im_session_summary);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IP_VOICE_CALL)) {\n            return mContext.getString(R.string.rcs_core_contact_ip_voice_call_summary);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IP_VIDEO_CALL)) {\n            return mContext.getString(R.string.rcs_core_contact_ip_video_call_summary);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IMAGE_SHARE)) {\n            return mContext.getString(R.string.rcs_core_contact_image_share_summary);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_VIDEO_SHARE)) {\n            return mContext.getString(R.string.rcs_core_contact_video_share_summary);\n        } else\n            return null;\n    }\n\n    /**\n     * Get description associated to a MIME type. This string will be visible in the contact card\n     * \n     * @param mimeType MIME type\n     * @return String\n     */\n    private String getMimeTypeDescriptionDetails(String mimeType) {\n        if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_FILE_TRANSFER)) {\n            return mContext.getString(R.string.rcs_core_contact_file_transfer_details);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IM_SESSION)) {\n            return mContext.getString(R.string.rcs_core_contact_im_session_details);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IP_VOICE_CALL)) {\n            return mContext.getString(R.string.rcs_core_contact_ip_voice_call_details);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IP_VIDEO_CALL)) {\n            return mContext.getString(R.string.rcs_core_contact_ip_video_call_details);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_EXTENSIONS)) {\n            return mContext.getString(R.string.rcs_core_contact_extensions_details);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_IMAGE_SHARE)) {\n            return mContext.getString(R.string.rcs_core_contact_image_share_details);\n\n        } else if (mimeType.equalsIgnoreCase(MIMETYPE_CAPABILITY_VIDEO_SHARE)) {\n            return mContext.getString(R.string.rcs_core_contact_video_share_details);\n        } else\n            return null;\n    }\n\n    /**\n     * Get the infos of a contact in the RCS contact provider\n     * \n     * @param contact Contact\n     * @return Contact info\n     */\n    public ContactInfo getContactInfo(ContactId contact) {\n        synchronized (mContactInfoCache) {\n            return getContactInfoInternal(contact);\n        }\n    }\n\n    /**\n     * Sets capabilities for contact\n     * \n     * @param contact Contact Id\n     * @param capabilities Capabilities to set\n     * @throws FileAccessException\n     * @throws ContactManagerException\n     */\n    public void setContactCapabilities(ContactId contact, Capabilities capabilities)\n            throws ContactManagerException, FileAccessException {\n        setContactCapabilities(contact, capabilities, getContactStatus(contact),\n                getRegistrationState(contact));\n    }\n\n    /**\n     * Set contact capabilities\n     * \n     * @param contact Contact Id\n     * @param capabilities Capabilities\n     * @param contactType Contact type\n     * @param registrationState Three possible values : online/offline/unknown\n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    public void setContactCapabilities(ContactId contact, Capabilities capabilities,\n            RcsStatus contactType, RegistrationState registrationState)\n            throws ContactManagerException, FileAccessException {\n        synchronized (mContactInfoCache) {\n            /* Get the current information on this contact */\n            ContactInfo oldInfo = getContactInfoInternal(contact);\n            ContactInfo newInfo = new ContactInfo(oldInfo);\n            /* Set the contact type */\n            newInfo.setRcsStatus(contactType);\n            /* Set the registration state */\n            newInfo.setRegistrationState(registrationState);\n            /* Modify the capabilities regarding the registration state */\n            boolean isRegistered = RegistrationState.ONLINE == registrationState;\n            boolean isRcsContact = newInfo.isRcsContact();\n            CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder(capabilities);\n            capaBuilder.setCsVideo(capaBuilder.isCsVideoSupported() && isRegistered);\n            /*\n             * File transfer. This capability is enabled: - if the capability is present and the\n             * contact is registered - if the FT S&F is enabled and the contact is RCS capable.\n             */\n            capaBuilder.setFileTransferMsrp(capaBuilder.isFileTransferMsrpSupported()\n                    && isRegistered || mRcsSettings.isFileTransferStoreForwardSupported()\n                    && isRcsContact);\n            capaBuilder.setImageSharing(capaBuilder.isImageSharingSupported() && isRegistered);\n            /*\n             * IM session capability is enabled: - if the capability is present and the contact is\n             * registered - if the IM store&forward is enabled and the contact is RCS capable.\n             */\n            capaBuilder.setImSession(capaBuilder.isImSessionSupported() && isRegistered\n                    || mRcsSettings.isImAlwaysOn() && isRcsContact);\n            capaBuilder.setVideoSharing(capaBuilder.isVideoSharingSupported() && isRegistered);\n            capaBuilder\n                    .setGeolocationPush(capaBuilder.isGeolocationPushSupported() && isRegistered);\n            capaBuilder.setFileTransferThumbnail(capaBuilder.isFileTransferThumbnailSupported()\n                    && isRegistered);\n            capaBuilder.setFileTransferHttp(capaBuilder.isFileTransferHttpSupported()\n                    && isRegistered || mRcsSettings.isFtHttpCapAlwaysOn() && isRcsContact);\n            capaBuilder.setFileTransferStoreForward(capaBuilder\n                    .isFileTransferStoreForwardSupported()\n                    && isRegistered\n                    || mRcsSettings.isFtAlwaysOn() && isRcsContact);\n            capaBuilder.setGroupChatStoreForward(capaBuilder.isGroupChatStoreForwardSupported()\n                    && isRegistered);\n            capaBuilder.setIpVoiceCall(capaBuilder.isIPVoiceCallSupported() && isRegistered);\n            capaBuilder.setIpVideoCall(capaBuilder.isIPVideoCallSupported() && isRegistered);\n            capaBuilder.setPresenceDiscovery(capaBuilder.isPresenceDiscovery() && isRegistered);\n            capaBuilder.setSocialPresence(capaBuilder.isSocialPresence() && isRegistered);\n            if (!isRegistered) {\n                /* If contact is not registered, do not put any extensions */\n                capaBuilder.setExtensions(new HashSet<String>());\n            }\n            /* Add the capabilities */\n            newInfo.setCapabilities(capaBuilder.build());\n            /* Do not set contact info if they are unchanged */\n            if (newInfo.getCapabilities().equals(oldInfo.getCapabilities())\n                    && newInfo.getRcsStatus() == oldInfo.getRcsStatus()\n                    && newInfo.getRegistrationState() == oldInfo.getRegistrationState()) {\n                /* Only update time of last response if capabilities are unchanged */\n                updateCapabilitiesTimeLastResponse(contact,\n                        capabilities.getTimestampOfLastResponse());\n                return;\n            }\n            /* Save the modifications */\n            setContactInfoInternal(newInfo, oldInfo);\n        }\n    }\n\n    /**\n     * Merge capabilities with existing capabilities in the cache\n     * \n     * @param contact The contact\n     * @param capabilities The capabilities\n     * @param contactType The contact type\n     * @param registrationState The registration state\n     * @param displayName The display name\n     * @throws ContactManagerException\n     * @throws FileAccessException\n     */\n    public void mergeContactCapabilities(ContactId contact, Capabilities capabilities,\n            RcsStatus contactType, RegistrationState registrationState, String displayName)\n            throws ContactManagerException, FileAccessException {\n        synchronized (mContactInfoCache) {\n            /* Get the current information on this contact */\n            ContactInfo oldInfo = getContactInfoInternal(contact);\n            /* Merge the capabilities */\n            Capabilities contactCapabilities = oldInfo.getCapabilities();\n            CapabilitiesBuilder capBuilder;\n            if (contactCapabilities != null) {\n                capBuilder = new CapabilitiesBuilder(contactCapabilities);\n            } else {\n                capBuilder = new CapabilitiesBuilder();\n            }\n            if (capabilities.isCsVideoSupported()) {\n                capBuilder.setCsVideo(true);\n            }\n            if (capabilities.isFileTransferMsrpSupported()) {\n                capBuilder.setFileTransferMsrp(true);\n            }\n            if (capabilities.isFileTransferHttpSupported()) {\n                capBuilder.setFileTransferHttp(true);\n            }\n            if (capabilities.isFileTransferStoreForwardSupported()) {\n                capBuilder.setFileTransferStoreForward(true);\n            }\n            if (capabilities.isFileTransferThumbnailSupported()) {\n                capBuilder.setFileTransferThumbnail(true);\n            }\n            if (capabilities.isGeolocationPushSupported()) {\n                capBuilder.setGeolocationPush(true);\n            }\n            if (capabilities.isGroupChatStoreForwardSupported()) {\n                capBuilder.setGroupChatStoreForward(true);\n            }\n            if (capabilities.isImSessionSupported()) {\n                capBuilder.setImSession(true);\n            }\n            if (capabilities.isImageSharingSupported()) {\n                capBuilder.setImageSharing(true);\n            }\n            if (capabilities.isIPVideoCallSupported()) {\n                capBuilder.setIpVideoCall(true);\n            }\n            if (capabilities.isIPVoiceCallSupported()) {\n                capBuilder.setIpVoiceCall(true);\n            }\n            if (capabilities.isPresenceDiscoverySupported()) {\n                capBuilder.setPresenceDiscovery(true);\n            }\n            if (capabilities.isSipAutomata()) {\n                capBuilder.setSipAutomata(true);\n            }\n            if (capabilities.isSocialPresenceSupported()) {\n                capBuilder.setSocialPresence(true);\n            }\n            if (capabilities.isVideoSharingSupported()) {\n                capBuilder.setVideoSharing(true);\n            }\n            long timestampOfLastRequest = capabilities.getTimestampOfLastRequest();\n            if (timestampOfLastRequest != Capabilities.INVALID_TIMESTAMP) {\n                capBuilder.setTimestampOfLastRequest(timestampOfLastRequest);\n            }\n            long timestampOfLastResponse = capabilities.getTimestampOfLastResponse();\n            if (timestampOfLastResponse != Capabilities.INVALID_TIMESTAMP) {\n                capBuilder.setTimestampOfLastRequest(timestampOfLastResponse);\n            }\n\n            ContactInfo newInfo = new ContactInfo(oldInfo);\n\n            /* Set the contact type */\n            newInfo.setRcsStatus(contactType);\n            /* Set the registration state */\n            newInfo.setRegistrationState(registrationState);\n            /* Add the capabilities */\n            newInfo.setCapabilities(capBuilder.build());\n            newInfo.setDisplayName(displayName);\n            /* Do not set contact info if they are unchanged */\n            if (newInfo.getCapabilities().equals(oldInfo.getCapabilities())\n                    && newInfo.getRcsStatus() == oldInfo.getRcsStatus()\n                    && newInfo.getRegistrationState() == oldInfo.getRegistrationState()\n                    && (displayName == null ? oldInfo.getDisplayName() == null : displayName\n                            .equals(oldInfo.getDisplayName()))) {\n                return;\n            }\n            /* Save the modifications */\n            setContactInfoInternal(newInfo, oldInfo);\n        }\n    }\n\n    private RcsStatus getContactStatus(ContactId contact) {\n        return getContactInfo(contact).getRcsStatus();\n    }\n\n    private RegistrationState getRegistrationState(ContactId contact) {\n        return getContactInfo(contact).getRegistrationState();\n    }\n\n    /**\n     * Get contact capabilities <br>\n     * If contact has never been enriched with capability, returns null\n     * \n     * @param contact Contact Id\n     * @return capabilities or null if capabilities do not exist\n     */\n    public Capabilities getContactCapabilities(ContactId contact) {\n        if (RcsStatus.NO_INFO.equals(getContactStatus(contact))) {\n            return null;\n        }\n        return getContactInfo(contact).getCapabilities();\n    }\n\n    /**\n     * Update time of last capabilities request for contact\n     * \n     * @param contact Contact Id\n     */\n    public void updateCapabilitiesTimeLastRequest(ContactId contact) {\n        String contactNumber = contact.toString();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Update time of last capabilities request for \".concat(contactNumber));\n        }\n        synchronized (mContactInfoCache) {\n            ContactInfo contactInfo = getContactInfoInternal(contact);\n            Capabilities capabilities = contactInfo.getCapabilities();\n            long now = System.currentTimeMillis();\n            /* Update the cache */\n            CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder(capabilities);\n            capaBuilder.setTimestampOfLastRequest(now);\n            contactInfo.setCapabilities(capaBuilder.build());\n            ContentValues values = new ContentValues();\n            values.put(KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST, now);\n            Uri uri = Uri.withAppendedPath(CONTENT_URI, contactNumber);\n            mLocalContentResolver.update(uri, values, null, null);\n        }\n    }\n\n    /**\n     * Utility method to create new \"RCS\" raw contact, that aggregates with other raw contact\n     * \n     * @param info for the RCS raw contact\n     * @param rawContactId of the raw contact we want to aggregate the RCS infos to\n     * @return the RCS rawContactId concerning this newly created contact\n     * @throws ContactManagerException\n     */\n    private long createRcsRawContact(final ContactInfo info, final long rawContactId)\n            throws ContactManagerException {\n        ContactId contact = info.getContact();\n        try {\n            String contactNumber = contact.toString();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Create RCS rawcontact for '\" + contactNumber\n                        + \"' associated to rawContactId \" + rawContactId);\n            }\n            ArrayList<ContentProviderOperation> ops = new ArrayList<>();\n            /* Create raw contact for RCS */\n            int rawContactRefIms = ops.size();\n            ops.add(ContentProviderOperation\n                    .newInsert(RawContacts.CONTENT_URI)\n                    .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED)\n                    .withValue(RawContacts.ACCOUNT_TYPE, RcsAccountManager.ACCOUNT_MANAGER_TYPE)\n                    .withValue(RawContacts.ACCOUNT_NAME,\n                            mContext.getString(R.string.rcs_core_account_username)).build());\n\n            /* Insert number */\n            ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                    .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                    .withValue(Data.MIMETYPE, MIMETYPE_NUMBER).withValue(Data.DATA1, contactNumber)\n                    .build());\n\n            /* Insert capabilities if supported */\n            Capabilities capabilities = info.getCapabilities();\n            if (capabilities.isFileTransferMsrpSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_FILE_TRANSFER));\n            }\n            if (capabilities.isImageSharingSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_IMAGE_SHARE));\n            }\n            if (capabilities.isImSessionSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_IM_SESSION));\n            }\n            if (capabilities.isVideoSharingSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_VIDEO_SHARE));\n            }\n            if (capabilities.isIPVoiceCallSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_IP_VOICE_CALL));\n            }\n            if (capabilities.isIPVideoCallSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_IP_VIDEO_CALL));\n            }\n            if (capabilities.isGeolocationPushSupported()) {\n                ops.add(createMimeTypeForContact(rawContactRefIms, contact,\n                        MIMETYPE_CAPABILITY_GEOLOCATION_PUSH));\n            }\n            /* Extensions */\n            Set<String> exts = info.getCapabilities().getSupportedExtensions();\n            if (exts.size() > 0) {\n                ops.add(ContentProviderOperation\n                        .newInsert(Data.CONTENT_URI)\n                        .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                        .withValue(Data.MIMETYPE, MIMETYPE_CAPABILITY_EXTENSIONS)\n                        .withValue(Data.DATA1, contactNumber)\n                        .withValue(Data.DATA2, ServiceExtensionManager.getExtensions(exts))\n                        .withValue(Data.DATA3,\n                                getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_EXTENSIONS))\n                        .build());\n            }\n\n            ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                    .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                    .withValue(Data.MIMETYPE, MIMETYPE_REGISTRATION_STATE)\n                    .withValue(Data.DATA1, contactNumber)\n                    .withValue(Data.DATA2, info.getRegistrationState().toInt()).build());\n\n            ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                    .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                    .withValue(Data.MIMETYPE, MIMETYPE_BLOCKING_STATE)\n                    .withValue(Data.DATA1, contactNumber)\n                    .withValue(Data.DATA2, info.getBlockingState().toInt()).build());\n\n            ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                    .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                    .withValue(Data.MIMETYPE, MIMETYPE_BLOCKING_TIMESTAMP)\n                    .withValue(Data.DATA1, contactNumber)\n                    .withValue(Data.DATA2, info.getBlockingTimestamp()).build());\n\n            /* Add raw contact as membership to RCS group */\n            long rcsGroupId = getRcsGroupIdFromContactsContractGroups();\n            if (INVALID_ID != rcsGroupId) {\n                ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                        .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                        .withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE)\n                        .withValue(GroupMembership.GROUP_ROW_ID, rcsGroupId).build());\n            }\n            ContentProviderResult[] results = mContentResolver.applyBatch(\n                    ContactsContract.AUTHORITY, ops);\n            long rcsRawContactId = ContentUris.parseId(results[rawContactRefIms].uri);\n\n            /* Aggregate the newly RCS raw contact and the raw contact that has the phone number */\n            ops.clear();\n            ops.add(ContentProviderOperation\n                    .newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)\n                    .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER)\n                    .withValue(AggregationExceptions.RAW_CONTACT_ID1, rcsRawContactId)\n                    .withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId).build());\n            mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);\n            /* Add to aggregation data provider */\n            ContentValues values = new ContentValues();\n            values.put(AggregationData.KEY_RAW_CONTACT_ID, rawContactId);\n            values.put(AggregationData.KEY_RCS_RAW_CONTACT_ID, rcsRawContactId);\n            values.put(AggregationData.KEY_RCS_NUMBER, contactNumber);\n            mLocalContentResolver.insert(AggregationData.CONTENT_URI, values);\n            return rcsRawContactId;\n\n        } catch (RemoteException | OperationApplicationException e) {\n            throw new ContactManagerException(\"Unable to apply batch updates for contact :\"\n                    + contact, e);\n        }\n    }\n\n    /**\n     * Converts the specified bitmap to a byte array.\n     * \n     * @param bitmap the Bitmap to convert\n     * @return the bitmap as bytes, null if converting fails.\n     */\n    private byte[] convertBitmapToBytes(final Bitmap bitmap) {\n        int size = bitmap.getRowBytes() * bitmap.getHeight();\n        ByteArrayOutputStream out = new ByteArrayOutputStream(size);\n        try {\n            if (bitmap.compress(Bitmap.CompressFormat.PNG, 0 /* quality ignored for PNG */, out)) {\n                return out.toByteArray();\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unable to convert bitmap, compression failed\");\n            }\n            return null;\n\n        } finally {\n            // noinspection ThrowableResultOfMethodCallIgnored\n            CloseableUtils.tryToClose(out);\n        }\n    }\n\n    /**\n     * Utility method to create the \"Me\" raw contact.\n     * \n     * @return the rawContactId of the newly created contact or INVALID_ID is social presence is not\n     *         supported or creation failed\n     * @throws ContactManagerException\n     */\n    public long createMyContact() throws ContactManagerException {\n        try {\n            if (!mRcsSettings.isSocialPresenceSupported()) {\n                return INVALID_ID;\n            }\n            /* Check if RCS raw contact for \"Me\" does not already exist */\n            long imsRawContactId = getRawContactIdForMe();\n\n            if (INVALID_ID != imsRawContactId) {\n                if (sLogger.isActivated()) {\n                    sLogger.error(\"\\\"Me\\\" contact already exists, no need to recreate\");\n                }\n                return imsRawContactId;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.error(\"\\\"Me\\\" contact does not already exists, creating it\");\n            }\n            ArrayList<ContentProviderOperation> ops = new ArrayList<>();\n            /* Create raw contact for RCS */\n            int rawContactRefIms = ops.size();\n            ops.add(ContentProviderOperation\n                    .newInsert(RawContacts.CONTENT_URI)\n                    .withValue(RawContacts.ACCOUNT_TYPE, RcsAccountManager.ACCOUNT_MANAGER_TYPE)\n                    .withValue(RawContacts.ACCOUNT_NAME,\n                            mContext.getString(R.string.rcs_core_account_username))\n                    .withValue(RawContacts.SOURCE_ID, MYSELF)\n                    .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED)\n                    .build());\n            /* Set name */\n            ops.add(ContentProviderOperation\n                    .newInsert(Data.CONTENT_URI)\n                    .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                    .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)\n                    .withValue(StructuredName.DISPLAY_NAME,\n                            mContext.getString(R.string.rcs_core_my_profile)).build());\n            /* Add raw contact as membership to RCS group */\n            long rcsGroupId = getRcsGroupIdFromContactsContractGroups();\n            if (INVALID_ID != rcsGroupId) {\n                ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                        .withValueBackReference(Data.RAW_CONTACT_ID, rawContactRefIms)\n                        .withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE)\n                        .withValue(GroupMembership.GROUP_ROW_ID, rcsGroupId).build());\n            }\n            ContentProviderResult[] results = mContentResolver.applyBatch(\n                    ContactsContract.AUTHORITY, ops);\n            imsRawContactId = ContentUris.parseId(results[rawContactRefIms].uri);\n\n            ops.clear();\n            /* Set default free text to null and availability to online */\n            List<ContentProviderOperation> registrationStateOps = modifyContactRegistrationStateForMyself(\n                    imsRawContactId, RegistrationState.ONLINE, RegistrationState.UNKNOWN, \"\", \"\");\n            for (ContentProviderOperation registrationStateOp : registrationStateOps) {\n                if (registrationStateOp != null) {\n                    ops.add(registrationStateOp);\n                }\n            }\n            mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);\n            return imsRawContactId;\n\n        } catch (RemoteException | OperationApplicationException e) {\n            throw new ContactManagerException(\"Unable to apply batch updates!\", e);\n        }\n    }\n\n    /**\n     * Utility to find the rawContactIds for a specific phone number.\n     * \n     * @param contact the contact ID to search for\n     * @return set of contact Ids\n     */\n    private Set<Long> getRawContactIdsFromPhoneNumber(ContactId contact) {\n        Set<Long> rawContactsIds = new HashSet<>();\n        String[] selectionArgs = {\n                Phone.CONTENT_ITEM_TYPE, contact.toString()\n        };\n        /* Starting LOOSE equal */\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(Data.CONTENT_URI, PROJ_DATA_RAW_CONTACT,\n                    SEL_RAW_CONTACT_FROM_NUMBER, selectionArgs, Data.RAW_CONTACT_ID);\n            CursorUtil.assertCursorIsNotNull(cursor, Data.CONTENT_URI);\n            if (cursor.moveToFirst()) {\n                int contactColumnIdx = cursor.getColumnIndexOrThrow(Data.RAW_CONTACT_ID);\n                do {\n                    long rawContactId = cursor.getLong(contactColumnIdx);\n                    /*\n                     * We exclude the SIM only contacts, as they cannot be aggregated to a RCS raw\n                     * contact (only if OS version if gingerbread or less).\n                     */\n                    if (!isSimAccount(rawContactId)) {\n                        rawContactsIds.add(rawContactId);\n                    }\n                } while (cursor.moveToNext());\n            }\n        } finally {\n            CursorUtil.close(cursor);\n        }\n        /*\n         * No match found using LOOSE equals, starting STRICT equals. This is done because of that\n         * the PHONE_NUMBERS_EQUAL function in Android doesn't always return true when doing loose\n         * lookup of a phone number against itself\n         */\n        String[] selectionArgsStrict = {\n                Phone.CONTENT_ITEM_TYPE, contact.toString(), contact.toString()\n        };\n        cursor = null;\n        try {\n            cursor = mContentResolver.query(Data.CONTENT_URI, PROJ_DATA_RAW_CONTACT,\n                    STRICT_SELECTION_RAW_CONTACT_FROM_NUMBER, selectionArgsStrict,\n                    Data.RAW_CONTACT_ID);\n            CursorUtil.assertCursorIsNotNull(cursor, Data.CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return rawContactsIds;\n            }\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(Data.RAW_CONTACT_ID);\n            do {\n                long rawContactId = cursor.getLong(contactColumnIdx);\n                /*\n                 * We exclude the SIM only contacts, as they cannot be aggregated to a RCS raw\n                 * contact (only if OS version if gingerbread or less).\n                 */\n                if (!isSimAccount(rawContactId)) {\n                    rawContactsIds.add(rawContactId);\n                }\n            } while (cursor.moveToNext());\n            return rawContactsIds;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Utility to get the RCS rawContact associated to a raw contact\n     * \n     * @param rawContactId the id of the rawContact\n     * @param contact The contact ID\n     * @return the id of the associated RCS rawContact\n     */\n    private long getAssociatedRcsRawContact(final long rawContactId, final ContactId contact) {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(AggregationData.CONTENT_URI,\n                    PROJ_RCS_RAW_CONTACT_ID, WHERE_RCS_RAW_CONTACT_ID_AND_RCS_NUMBER, new String[] {\n                            contact.toString(), String.valueOf(rawContactId)\n                    }, null);\n            CursorUtil.assertCursorIsNotNull(cursor, AggregationData.CONTENT_URI);\n            if (cursor.moveToFirst()) {\n                return cursor.getLong(cursor\n                        .getColumnIndexOrThrow(AggregationData.KEY_RCS_RAW_CONTACT_ID));\n\n            }\n            return INVALID_ID;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Utility to check if a phone number is associated to an entry in the RCS contact provider\n     * \n     * @param contact The contact ID\n     * @return true if contact has an entry in the RCS contact provider, else false\n     */\n    public boolean isContactIdAssociatedWithRcsContactProvider(final ContactId contact) {\n        Cursor cursor = null;\n        Uri uri = Uri.withAppendedPath(CONTENT_URI, contact.toString());\n        try {\n            cursor = mLocalContentResolver.query(uri, PROJ_RCSCONTACT_CONTACT, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, uri);\n            return cursor.moveToFirst();\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Utility method to check if a raw contact id is a SIM account\n     * \n     * @param rawContactId raw contact ID\n     * @return True if raw contact id is a SIM account\n     */\n    public boolean isSimAccount(final long rawContactId) {\n        Cursor cursor = null;\n        String[] selectionArgs = new String[] {\n            String.valueOf(rawContactId)\n        };\n        try {\n            cursor = mContentResolver.query(RawContacts.CONTENT_URI, PROJ_RAW_CONTACT_ID,\n                    SIM_ACCOUNT_SELECTION, selectionArgs, null);\n            CursorUtil.assertCursorIsNotNull(cursor, RawContacts.CONTENT_URI);\n            return cursor.moveToFirst();\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Utility to set the photo icon attribute on a RCS contact.\n     * \n     * @param rawContactId RCS raw contact\n     * @param photoIcon The photoIcon\n     * @param makeSuperPrimary whether or not to set the super primary flag\n     * @return list of contentProviderOperation to be done\n     */\n    private List<ContentProviderOperation> setContactPhoto(Long rawContactId, PhotoIcon photoIcon,\n            boolean makeSuperPrimary) {\n        List<ContentProviderOperation> ops = new ArrayList<>();\n        /* Get the photo data id */\n        String[] selectionArgs = {\n                Long.toString(rawContactId), Photo.CONTENT_ITEM_TYPE\n        };\n        String sortOrder = Data._ID + \" DESC\";\n\n        Cursor cursor = mContentResolver.query(Data.CONTENT_URI, PROJ_DATA_ID,\n                SEL_RAW_CONTACT_WITH_MIMETYPE, selectionArgs, sortOrder);\n        if (cursor == null) {\n            return ops;\n        }\n        byte[] iconData = null;\n        if (photoIcon != null) {\n            iconData = photoIcon.getContent();\n        }\n        /* Insert default avatar if icon is null and it is not for myself */\n        if (iconData == null && rawContactId != getRawContactIdForMe()) {\n            Bitmap rcsAvatar = BitmapFactory.decodeResource(mContext.getResources(),\n                    R.drawable.rcs_core_default_portrait_icon);\n            iconData = convertBitmapToBytes(rcsAvatar);\n        }\n        long dataId;\n        try {\n            if (iconData == null) {\n                /*\n                 * May happen only for myself. Remove photoIcon if no data.\n                 */\n                if (cursor.moveToNext()) {\n                    dataId = cursor.getLong(cursor.getColumnIndex(Data._ID));\n                    /* Add delete operation */\n                    ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)\n                            .withSelection(SEL_DATA_ID, new String[] {\n                                String.valueOf(dataId)\n                            }).build());\n                }\n            } else {\n                ContentValues values = new ContentValues();\n                values.put(Data.RAW_CONTACT_ID, rawContactId);\n                values.put(Photo.PHOTO, iconData);\n                values.put(Data.IS_PRIMARY, 1);\n                if (makeSuperPrimary) {\n                    values.put(Data.IS_SUPER_PRIMARY, 1);\n                }\n                if (cursor.moveToNext()) {\n                    /* We already have an icon, update it */\n                    dataId = cursor.getLong(cursor.getColumnIndex(Data._ID));\n                    ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                            .withSelection(SEL_DATA_ID, new String[] {\n                                String.valueOf(dataId)\n                            }).withValues(values).build());\n                } else {\n                    /* We did not have an icon, insert a new one */\n                    ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI).withValues(values)\n                            .build());\n                }\n                values.clear();\n                /* Set etag */\n                values.put(Data.RAW_CONTACT_ID, rawContactId);\n                String etag = null;\n                if (photoIcon != null) {\n                    etag = photoIcon.getEtag();\n                }\n                values.put(Data.DATA2, etag);\n\n                String[] projection2 = {\n                        Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE\n                };\n                String[] selectionArgs2 = {\n                    Long.toString(rawContactId)\n                };\n                Cursor cur2 = null;\n                try {\n                    cur2 = mContentResolver.query(Data.CONTENT_URI, projection2,\n                            SEL_RAW_CONTACT_ID, selectionArgs2, null);\n                    CursorUtil.assertCursorIsNotNull(cur2, Data.CONTENT_URI);\n                    if (cur2.moveToNext()) {\n                        dataId = cur2.getLong(cur2.getColumnIndexOrThrow(Data._ID));\n                        /* We already have an etag, update it */\n                        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                                .withSelection(SEL_DATA_ID, new String[] {\n                                    String.valueOf(dataId)\n                                }).withValues(values).build());\n                    } else {\n                        /* Insert etag */\n                        ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)\n                                .withValues(values).build());\n                    }\n                } finally {\n                    CursorUtil.close(cur2);\n                }\n            }\n            return ops;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Get the raw contact id of the \"Me\" contact.\n     * \n     * @return rawContactId\n     */\n    private long getRawContactIdForMe() {\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(RawContacts.CONTENT_URI, PROJ_RAW_CONTACT_ID,\n                    SEL_RAW_CONTACT_ME, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, RawContacts.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return INVALID_ID;\n            }\n            return cursor.getLong(cursor.getColumnIndexOrThrow(RawContacts._ID));\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Get whether the contact is blocked or not\n     * \n     * @param contact The contact ID\n     * @return flag indicating if IM sessions with the contact are enabled or not\n     */\n    public boolean isBlockedForContact(ContactId contact) {\n        return BlockingState.BLOCKED == getContactInfo(contact).getBlockingState();\n    }\n\n    /**\n     * Utility to create a ContactInfo object from a cursor containing data\n     * \n     * @param cursor The cursor\n     * @return contactInfo\n     */\n    private ContactInfo getContactInfoFromCursor(Cursor cursor) {\n        ContactInfo contactInfo = new ContactInfo();\n        PresenceInfo presenceInfo = new PresenceInfo();\n        Capabilities.CapabilitiesBuilder capaBuilder = new Capabilities.CapabilitiesBuilder();\n        try {\n            int idMimeTypeColumnIdx = cursor.getColumnIndexOrThrow(Data.MIMETYPE);\n            while (cursor.moveToNext()) {\n                String mimeTypeStr = cursor.getString(idMimeTypeColumnIdx);\n                /* Convert mime type string to enumerated */\n                MimeType mimeType = MimeType.getMimeType(mimeTypeStr);\n                switch (mimeType) {\n                    case CAPABILITY_IMAGE_SHARE:\n                        capaBuilder.setImageSharing(true);\n                        break;\n                    case CAPABILITY_VIDEO_SHARE:\n                        capaBuilder.setVideoSharing(true);\n                        break;\n                    case CAPABILITY_IP_VOICE_CALL:\n                        capaBuilder.setIpVoiceCall(true);\n                        break;\n                    case CAPABILITY_IP_VIDEO_CALL:\n                        capaBuilder.setIpVideoCall(true);\n                        break;\n                    case CAPABILITY_IM_SESSION:\n                        capaBuilder.setImSession(true);\n                        break;\n                    case CAPABILITY_FILE_TRANSFER:\n                        capaBuilder.setFileTransferMsrp(true);\n                        break;\n                    case CAPABILITY_GEOLOCATION_PUSH:\n                        capaBuilder.setGeolocationPush(true);\n                        break;\n                    case CAPABILITY_EXTENSIONS: {\n                        /* Set RCS extensions capability */\n                        int columnIndex = cursor.getColumnIndex(Data.DATA2);\n                        if (INVALID_ID != columnIndex) {\n                            capaBuilder.setExtensions(ServiceExtensionManager.getExtensions(cursor\n                                    .getString(columnIndex)));\n                        }\n                    }\n                        break;\n                    case REGISTRATION_STATE: {\n                        /* Set registration state */\n                        int columnIndex = cursor.getColumnIndex(Data.DATA2);\n                        if (columnIndex != -1) {\n                            int registrationState = cursor.getInt(columnIndex);\n                            contactInfo.setRegistrationState(RegistrationState\n                                    .valueOf(registrationState));\n                        }\n                    }\n                        break;\n                    case NUMBER: {\n                        /* Set contact ID */\n                        int columnIndex = cursor.getColumnIndex(Data.DATA1);\n                        if (INVALID_ID != columnIndex) {\n                            String contact = cursor.getString(columnIndex);\n                            /* check validity for contact read from raw contact */\n                            PhoneNumber number = ContactUtil\n                                    .getValidPhoneNumberFromAndroid(contact);\n                            if (number != null) {\n                                contactInfo.setContact(ContactUtil\n                                        .createContactIdFromValidatedData(number));\n                            } else {\n                                if (sLogger.isActivated()) {\n                                    sLogger.warn(\"Cannot parse contact \".concat(contact));\n                                }\n                            }\n                        }\n                    }\n                        break;\n                    case BLOCKING_STATE: {\n                        /* Set blocking state */\n                        int columnIndex = cursor.getColumnIndex(Data.DATA2);\n                        if (columnIndex != -1) {\n                            int state = cursor.getInt(columnIndex);\n                            contactInfo.setBlockingState(BlockingState.valueOf(state));\n                        }\n                    }\n                        break;\n                    case BLOCKING_TIMESTAMP: {\n                        /* Set blocking timestamp */\n                        int columnIndex = cursor.getColumnIndex(Data.DATA2);\n                        if (columnIndex != -1) {\n                            long timestamp = cursor.getLong(columnIndex);\n                            contactInfo.setBlockingTimestamp(timestamp);\n                        }\n                    }\n                        break;\n                    default:\n                        if (sLogger.isActivated()) {\n                            sLogger.warn(\"Unhandled mimetype \".concat(mimeTypeStr));\n                        }\n                        break;\n                }\n            }\n            contactInfo.setPresenceInfo(presenceInfo);\n            contactInfo.setCapabilities(capaBuilder.build());\n            return contactInfo;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Utility to extract data from a raw contact.\n     * \n     * @param rawContactId the rawContactId\n     * @return A cursor containing the requested data.\n     */\n    private Cursor getRawContactDataCursor(final long rawContactId) {\n        String[] selectionArgs = {\n            Long.toString(rawContactId)\n        };\n        return mContentResolver.query(Data.CONTENT_URI, PROJ_RAW_CONTACT_DATA_ALL,\n                SEL_RAW_CONTACT_MIME_TYPES, selectionArgs, null);\n    }\n\n    /**\n     * Update UI strings when device's locale has changed\n     * \n     * @throws ContactManagerException\n     */\n    public void updateStrings() throws ContactManagerException {\n        ArrayList<ContentProviderOperation> ops = new ArrayList<>();\n        /* Update My profile display name */\n        ContentValues values = new ContentValues();\n        values.put(StructuredName.DISPLAY_NAME, mContext.getString(R.string.rcs_core_my_profile));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_RAW_CONTACT_WITH_MIMETYPE, new String[] {\n                        Long.toString(getRawContactIdForMe()), StructuredName.DISPLAY_NAME\n                }).withValues(values).build());\n\n        /* Update file transfer menu */\n        values.clear();\n        values.put(Data.DATA2, getMimeTypeDescriptionSummary(MIMETYPE_CAPABILITY_FILE_TRANSFER));\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_FILE_TRANSFER));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_FILE_TRANSFER, null).withValues(values)\n                .build());\n\n        /* Update chat menu */\n        values.clear();\n        values.put(Data.DATA2, getMimeTypeDescriptionSummary(MIMETYPE_CAPABILITY_IM_SESSION));\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_IM_SESSION));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_IM_SESSION, null).withValues(values)\n                .build());\n\n        /* Update image sharing menu */\n        values.clear();\n        values.put(Data.DATA2, getMimeTypeDescriptionSummary(MIMETYPE_CAPABILITY_IMAGE_SHARE));\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_IMAGE_SHARE));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_IMAGE_SHARING, null).withValues(values)\n                .build());\n\n        /* Update video sharing menu */\n        values.clear();\n        values.put(Data.DATA2, getMimeTypeDescriptionSummary(MIMETYPE_CAPABILITY_VIDEO_SHARE));\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_VIDEO_SHARE));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_VIDEO_SHARING, null).withValues(values)\n                .build());\n\n        /* Update IP voice call menu */\n        values.clear();\n        values.put(Data.DATA2, getMimeTypeDescriptionSummary(MIMETYPE_CAPABILITY_IP_VOICE_CALL));\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_IP_VOICE_CALL));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_IP_VOICE_CALL, null).withValues(values)\n                .build());\n\n        /* Update IP video call menu */\n        values.clear();\n        values.put(Data.DATA2, getMimeTypeDescriptionSummary(MIMETYPE_CAPABILITY_IP_VIDEO_CALL));\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_IP_VIDEO_CALL));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_IP_VIDEO_CALL, null).withValues(values)\n                .build());\n\n        /*\n         * Update extensions menu: do not update summary which contains the list of supported\n         * extensions.\n         */\n        values.clear();\n        values.put(Data.DATA3, getMimeTypeDescriptionDetails(MIMETYPE_CAPABILITY_EXTENSIONS));\n        ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)\n                .withSelection(SEL_DATA_MIMETYPE_CAPABILITY_EXTENSIONS, null).withValues(values)\n                .build());\n\n        if (!ops.isEmpty()) {\n            /* Do the actual database modifications */\n            try {\n                mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);\n            } catch (RemoteException | OperationApplicationException e) {\n                throw new ContactManagerException(\"Unable to apply batch updates !\", e);\n\n            }\n        }\n    }\n\n    /**\n     * Clean the RCS entries <br>\n     * This removes the RCS entries that are associated to numbers not present in the address book\n     * anymore <br>\n     * This also creates a RCS raw contact for numbers that are present, have RCS raw contact but\n     * not on all raw contacts (typical example: a RCS number is present in the address book and\n     * another contact is created using the same number)\n     * \n     * @throws ContactManagerException\n     */\n    public void cleanRCSEntries() throws ContactManagerException {\n        synchronized (mContactInfoCache) {\n            cleanRCSRawContactsInAB();\n            cleanEntriesInRcsContactProvider();\n        }\n    }\n\n    /**\n     * Clean Address Book\n     * \n     * @throws ContactManagerException\n     */\n    private void cleanRCSRawContactsInAB() throws ContactManagerException {\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(Data.CONTENT_URI, PROJ_RAW_CONTACT_DATA1,\n                    SEL_DATA_MIMETYPE_NUMBER, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, Data.CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return;\n            }\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(Data.RAW_CONTACT_ID);\n            int data1ColumnIdx = cursor.getColumnIndexOrThrow(Data.DATA1);\n            /*\n             * Get all RCS raw contacts id Delete RCS Entry where number is not in the address book\n             * anymore.\n             */\n            ArrayList<ContentProviderOperation> ops = new ArrayList<>();\n            do {\n                String phoneNumber = cursor.getString(data1ColumnIdx);\n                PhoneNumber number = ContactUtil.getValidPhoneNumberFromAndroid(phoneNumber);\n                if (number == null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Cannot parse contact \" + phoneNumber);\n                    }\n                    continue;\n                }\n                ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                long rawContactId = cursor.getLong(contactColumnIdx);\n                if (getRawContactIdsFromPhoneNumber(contact).isEmpty()) {\n                    ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)\n                            .withSelection(SEL_RAW_CONTACT, new String[] {\n                                Long.toString(rawContactId)\n                            }).build());\n                    /* Also delete the corresponding entries in the aggregation provider */\n                    mLocalContentResolver.delete(AggregationData.CONTENT_URI,\n                            WHERE_RCS_RAW_CONTACT_ID, new String[] {\n                                Long.toString(rawContactId)\n                            });\n                }\n            } while (cursor.moveToNext());\n            if (!ops.isEmpty()) {\n                /* Do the actual database modifications */\n                mContentResolver.applyBatch(ContactsContract.AUTHORITY, ops);\n            }\n        } catch (RemoteException | OperationApplicationException e) {\n            throw new ContactManagerException(\"Unable to apply batch updates !\", e);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Clean all in RCS contact provider\n     */\n    private void cleanEntriesInRcsContactProvider() {\n        /* Get All contacts in RCS contact provider */\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(CONTENT_URI, PROJ_RCSCONTACT_CONTACT, null, null,\n                    null);\n            CursorUtil.assertCursorIsNotNull(cursor, CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return;\n            }\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(KEY_CONTACT);\n            /* Delete RCS contact Entry where number is not in the address book anymore */\n            do {\n                String phoneNumber = cursor.getString(contactColumnIdx);\n                /* Do not check validity for trusted data */\n                PhoneNumber number = ContactUtil.getValidPhoneNumberFromAndroid(phoneNumber);\n                ContactId contact = ContactUtil.createContactIdFromValidatedData(number);\n                if (getRawContactIdsFromPhoneNumber(contact).isEmpty()) {\n                    Uri uri = Uri.withAppendedPath(ContactData.CONTENT_URI, phoneNumber);\n                    mLocalContentResolver.delete(uri, null, null);\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"cleanEntriesInRcsContactProvider clear for contact=\"\n                                .concat(phoneNumber));\n                    }\n                    mContactInfoCache.remove(contact);\n                }\n            } while (cursor.moveToNext());\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Delete all RCS entries in databases\n     */\n    public void deleteRCSEntries() {\n        /* Delete Aggregation data */\n        mLocalContentResolver.delete(AggregationData.CONTENT_URI, null, null);\n        synchronized (mContactInfoCache) {\n            /* Empty the cache */\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"deleteRCSEntries\");\n            }\n            mContactInfoCache.clear();\n            /* Delete presence data */\n            mLocalContentResolver.delete(CONTENT_URI, null, null);\n        }\n    }\n\n    /**\n     * Is capability supported\n     * \n     * @param cursor Cursor\n     * @param column Column name\n     * @return True if capability is supported\n     */\n    private boolean isCapabilitySupported(Cursor cursor, String column) {\n        return cursor.getInt(cursor.getColumnIndexOrThrow(column)) == CapabilitiesLog.SUPPORTED;\n    }\n\n    /**\n     * Sets the display name into the RCS contact provider\n     * \n     * @param contact Contact ID\n     * @param displayName the display name\n     */\n    public void setContactDisplayName(ContactId contact, String displayName) {\n        synchronized (mContactInfoCache) {\n            ContentValues values = new ContentValues();\n            values.put(KEY_DISPLAY_NAME, displayName);\n            /* Check if record exists and if so then update is required */\n            String oldDisplayName = getContactDisplayName(contact);\n            boolean updateRequired = !StringUtils.equals(oldDisplayName, displayName);\n            if (updateRequired) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Update display name '\" + displayName + \"' for contact:\"\n                            + contact);\n                }\n                Uri uri = Uri.withAppendedPath(ContactData.CONTENT_URI, contact.toString());\n                /* Contact already present and display name is new, update */\n                mLocalContentResolver.update(uri, values, null, null);\n\n                getContactInfoInternal(contact).setDisplayName(displayName);\n            }\n        }\n    }\n\n    /**\n     * Get RCS display name for contact\n     * \n     * @param contact ID\n     * @return the display name or null\n     */\n    public String getContactDisplayName(ContactId contact) {\n        return getContactInfo(contact).getDisplayName();\n    }\n\n    /**\n     * Update the time of last capabilities refresh\n     *\n     * @param contact ID\n     * @param timestampOfLastResponse the time when capabilities are refreshed\n     */\n    public void updateCapabilitiesTimeLastResponse(ContactId contact, long timestampOfLastResponse) {\n        String contactNumber = contact.toString();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Update the time of last capabilities response for \"\n                    .concat(contactNumber));\n        }\n        synchronized (mContactInfoCache) {\n            ContactInfo contactInfo = getContactInfoInternal(contact);\n            Capabilities capabilities = contactInfo.getCapabilities();\n            /* Update the cache */\n            CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder(capabilities);\n            capaBuilder.setTimestampOfLastResponse(timestampOfLastResponse);\n            contactInfo.setCapabilities(capaBuilder.build());\n            ContentValues values = new ContentValues();\n            values.put(KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE, timestampOfLastResponse);\n            Uri uri = Uri.withAppendedPath(CONTENT_URI, contactNumber);\n            mLocalContentResolver.update(uri, values, null, null);\n        }\n    }\n\n    /**\n     * Set the blocking state for a given contact\n     * \n     * @param contact Contact ID\n     * @param state Blocking state\n     * @throws ContactManagerException exception thrown if update operation has failed\n     * @throws FileAccessException\n     */\n    public void setBlockingState(ContactId contact, BlockingState state)\n            throws ContactManagerException, FileAccessException {\n        synchronized (mContactInfoCache) {\n            /* Get the current information on this contact */\n            ContactInfo oldInfo = getContactInfoInternal(contact);\n            ContactInfo newInfo = new ContactInfo(oldInfo);\n            /* Update the state */\n            newInfo.setBlockingState(state);\n            newInfo.setBlockingTimestamp(System.currentTimeMillis());\n            /* Save the modifications */\n            setContactInfoInternal(newInfo, oldInfo);\n        }\n    }\n\n    /**\n     * Gets the raw IDs for all contacts of the native address book\n     * \n     * @return map of contact IDs associated with their raw contact IDs\n     */\n    public Map<ContactId, Set<Long>> getAllRawIdsInPhoneAddressBook() {\n        Map<ContactId, Set<Long>> result = new HashMap<>();\n        Cursor cursor = null;\n        try {\n            /* Query all phone numbers of the native address book */\n            cursor = mContentResolver.query(Phone.CONTENT_URI, PHONE_PROJ_NUMBER_RAW_CONTACT_ID,\n                    null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, Phone.CONTENT_URI);\n            if (!cursor.moveToFirst()) {\n                return result;\n            }\n            int columnIndexPhoneNumber = cursor.getColumnIndexOrThrow(Phone.NUMBER);\n            int columnIndexRawContactId = cursor.getColumnIndexOrThrow(Phone.RAW_CONTACT_ID);\n            do {\n                String phoneNumber = cursor.getString(columnIndexPhoneNumber);\n                PhoneNumber validatedNumber = ContactUtil\n                        .getValidPhoneNumberFromAndroid(phoneNumber);\n                if (validatedNumber == null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Cannot parse phone number '\" + phoneNumber + \"'\");\n                    }\n                    continue;\n                }\n                Long rawContactId = cursor.getLong(columnIndexRawContactId);\n                if (ContactManager.INVALID_ID == rawContactId) {\n                    if (sLogger.isActivated()) {\n                        sLogger.warn(\"Phone number '\" + phoneNumber + \"' has no raw contact ID\");\n                    }\n                    continue;\n                }\n                ContactId contact = ContactUtil.createContactIdFromValidatedData(validatedNumber);\n                if (result.containsKey(contact)) {\n                    Set<Long> rawIds = result.get(contact);\n                    rawIds.add(rawContactId);\n                    result.put(contact, rawIds);\n                } else {\n                    Set<Long> rawIds = new HashSet<>();\n                    rawIds.add(rawContactId);\n                    result.put(contact, rawIds);\n                }\n            } while (cursor.moveToNext());\n            return result;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Checks if a RCS raw contact exists for the raw contact of the native address book\n     * \n     * @param rawContactId the raw contact ID of the native address book\n     * @param contact contactId\n     * @return true if a RCS raw contact exists for the raw contact of the native address book\n     */\n    public boolean isAssociatedRcsRawContact(long rawContactId, final ContactId contact) {\n        long rcsRawContactId = getAssociatedRcsRawContact(rawContactId, contact);\n        return (ContactManager.INVALID_ID != rcsRawContactId);\n    }\n\n    /**\n     * Aggregate contact with RCS raw contact\n     * \n     * @param contactInfo contact to aggregate with RCS raw contact. The contact must be RCS.\n     * @throws ContactManagerException thrown is contact information setting fails\n     * @throws FileAccessException\n     */\n    public void aggregateContactWithRcsRawContact(ContactInfo contactInfo)\n            throws ContactManagerException, FileAccessException {\n        synchronized (mContactInfoCache) {\n            /*\n             * if RCS contact does not exist, it will be created and RCS raw contact also. if RCS\n             * contact already exists, it will enforce creation and association of RCS raw contact.\n             */\n            setContactInfoInternal(contactInfo, contactInfo);\n        }\n    }\n\n    /**\n     * Gets the RCS group ID or INVALID_ID if it does not exist\n     * \n     * @return the RCS group ID or INVALID_ID if it does not exist\n     */\n    public long getRcsGroupIdFromContactsContractGroups() {\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(Groups.CONTENT_URI, PROJ_CONTACT_GROUP_ID,\n                    SEL_RCS_CONTACT_GROUP_ACCOUNT_TYPE, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, Groups.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return ContactManager.INVALID_ID;\n            }\n            return cursor.getLong(cursor.getColumnIndexOrThrow(Groups._ID));\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Checks if a set of raw contact IDs is only associated to a SIM account\n     * \n     * @param rawContactIds the set of raw contact Identifiers\n     * @return true if the raw contact identifiers are only associated to a SIM account, else false\n     */\n    private boolean isOnlySimAssociated(Set<Long> rawContactIds) {\n        for (Long rawContactId : rawContactIds) {\n            if (isSimAccount(rawContactId)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Gets the set of contacts only SIM associated\n     * \n     * @param contacts the map of contacts with their raw contact IDs\n     * @return the set of contacts only SIM associated\n     */\n    public Set<ContactId> getContactsOnlySimAssociated(Map<ContactId, Set<Long>> contacts) {\n        Set<ContactId> result = new HashSet<>();\n        for (Entry<ContactId, Set<Long>> contactEntry : contacts.entrySet()) {\n            Set<Long> nativeRawContactIds = contactEntry.getValue();\n            if (isOnlySimAssociated(nativeRawContactIds)) {\n                result.add(contactEntry.getKey());\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/contact/ContactManagerException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.contact;\n\n/**\n * ContactManager exception\n * \n * @author jexa7410\n */\npublic class ContactManagerException extends Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ContactManagerException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ContactManagerException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/contact/ContactProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.contact;\n\nimport com.gsma.rcs.provider.ContentProviderBaseIdCreator;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.contact.ContactData.AggregationData;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentUris;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.os.ParcelFileDescriptor;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * RCS Contact provider <br>\n * This provider contains the list of the RCS contacts and their status <br>\n * It is used by the AddressBookManager to keep the synchronization between the native address book\n * and the RCS contacts. <br>\n * It also contains the list of aggregations between native raw contacts and RCS raw contacts\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class ContactProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String CAPABILITY_TABLE = \"capability\";\n\n    private static final String AGGREGATION_TABLE = \"aggregation\";\n\n    /**\n     * Database filename\n     */\n    public static final String DATABASE_NAME = \"capability.db\";\n\n    private static final String RCS_CONTACT_SELECTION_WITH_CONTACT_ONLY = ContactData.KEY_CONTACT\n            .concat(\"=?\");\n\n    private static final String AGGREGATION_DATA_SELECTION_WITH_ID_ONLY = AggregationData.KEY_ID\n            .concat(\"=?\");\n\n    private final static String[] PHOTO_DATA_PROJECTION = new String[] {\n        ContactData.KEY_PRESENCE_PHOTO_DATA\n    };\n\n    private static final String FILENAME_PREFIX = \"photoData\";\n\n    private static final UriMatcher sUriMatcher;\n    static {\n        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n\n        sUriMatcher.addURI(ContactData.CONTENT_URI.getAuthority(), ContactData.CONTENT_URI\n                .getPath().substring(1), UriType.InternalContacts.INTERNAL_CONTACTS);\n        sUriMatcher.addURI(ContactData.CONTENT_URI.getAuthority(), ContactData.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"),\n                UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID);\n        sUriMatcher.addURI(AggregationData.CONTENT_URI.getAuthority(), AggregationData.CONTENT_URI\n                .getPath().substring(1), UriType.Aggregation.AGGREGATION);\n        sUriMatcher.addURI(AggregationData.CONTENT_URI.getAuthority(), AggregationData.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.Aggregation.AGGREGATION_WITH_ID);\n        sUriMatcher.addURI(CapabilitiesLog.CONTENT_URI.getAuthority(), CapabilitiesLog.CONTENT_URI\n                .getPath().substring(1), UriType.Contacts.CONTACTS);\n        sUriMatcher.addURI(CapabilitiesLog.CONTENT_URI.getAuthority(), CapabilitiesLog.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.Contacts.CONTACTS_WITH_ID);\n    }\n\n    /**\n     * String to allow projection for exposed URI to a set of columns\n     */\n    private static final String[] COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS = new String[] {\n            ContactData.KEY_BASECOLUMN_ID, ContactData.KEY_CONTACT,\n            ContactData.KEY_CAPABILITY_IMAGE_SHARE, ContactData.KEY_CAPABILITY_VIDEO_SHARE,\n            ContactData.KEY_CAPABILITY_IM_SESSION, ContactData.KEY_CAPABILITY_FILE_TRANSFER,\n            ContactData.KEY_CAPABILITY_GEOLOC_PUSH, ContactData.KEY_CAPABILITY_EXTENSIONS,\n            ContactData.KEY_AUTOMATA, ContactData.KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE\n    };\n\n    private static final Set<String> COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS = new HashSet<>(\n            Arrays.asList(COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS));\n\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private static final class UriType {\n\n        private static final class Contacts {\n\n            private static final int CONTACTS = 1;\n\n            private static final int CONTACTS_WITH_ID = 2;\n        }\n\n        private static final class Aggregation {\n\n            private static final int AGGREGATION = 3;\n\n            private static final int AGGREGATION_WITH_ID = 4;\n        }\n\n        private static final class InternalContacts {\n\n            private static final int INTERNAL_CONTACTS = 5;\n\n            private static final int INTERNAL_CONTACTS_WITH_ID = 6;\n        }\n    }\n\n    private static final class CursorType {\n\n        private static final class Contacts {\n\n            private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/eab\";\n\n            private static final String TYPE_ITEM = \"vnd.android.cursor.item/eab\";\n        }\n\n        private static final class Aggregation {\n\n            private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/aggregation\";\n\n            private static final String TYPE_ITEM = \"vnd.android.cursor.item/aggregation\";\n        }\n    }\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n\n        private static final int DATABASE_VERSION = 28;\n\n        private void createDb(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + CAPABILITY_TABLE + '('\n                    + ContactData.KEY_CONTACT + \" TEXT NOT NULL PRIMARY KEY,\"\n                    + ContactData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_DISPLAY_NAME + \" TEXT,\"\n                    + ContactData.KEY_RCS_STATUS + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_RCS_STATUS_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_REGISTRATION_STATE + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_PRESENCE_SHARING_STATUS + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_FREE_TEXT + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_WEBLINK_NAME + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_WEBLINK_URL + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_PHOTO_EXIST_FLAG + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_PHOTO_ETAG + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_PHOTO_DATA + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_GEOLOC_EXIST_FLAG + \" TEXT,\"\n                    + ContactData.KEY_PRESENCE_GEOLOC_LATITUDE + \" REAL,\"\n                    + ContactData.KEY_PRESENCE_GEOLOC_LONGITUDE + \" REAL,\"\n                    + ContactData.KEY_PRESENCE_GEOLOC_ALTITUDE + \" REAL,\"\n                    + ContactData.KEY_PRESENCE_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_TIMESTAMP_LAST_REQUEST + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_CS_VIDEO + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_IMAGE_SHARE + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_VIDEO_SHARE + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_IM_SESSION + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_FILE_TRANSFER + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_PRESENCE_DISCOVERY + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_SOCIAL_PRESENCE + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_GEOLOC_PUSH + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_FILE_TRANSFER_HTTP + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_FILE_TRANSFER_THUMBNAIL + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_IP_VOICE_CALL + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_IP_VIDEO_CALL + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_FILE_TRANSFER_SF + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_GROUP_CHAT_SF + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_EXTENSIONS + \" TEXT,\"\n                    + ContactData.KEY_BLOCKED + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_BLOCKING_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_TIMESTAMP_CONTACT_UPDATED + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_AUTOMATA + \" INTEGER NOT NULL,\"\n                    + ContactData.KEY_CAPABILITY_TIMESTAMP_LAST_RESPONSE + \" INTEGER NOT NULL)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + ContactData.KEY_BASECOLUMN_ID + \"_idx\" + \" ON \"\n                    + CAPABILITY_TABLE + '(' + ContactData.KEY_BASECOLUMN_ID + ')');\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + AGGREGATION_TABLE + '('\n                    + AggregationData.KEY_ID + \" INTEGER PRIMARY KEY AUTOINCREMENT,\"\n                    + AggregationData.KEY_RCS_NUMBER + \" TEXT NOT NULL,\"\n                    + AggregationData.KEY_RAW_CONTACT_ID + \" INTEGER NOT NULL,\"\n                    + AggregationData.KEY_RCS_RAW_CONTACT_ID + \" INTEGER NOT NULL)\");\n        }\n\n        public DatabaseHelper(Context context) {\n            super(context, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            createDb(db);\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(CAPABILITY_TABLE));\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(AGGREGATION_TABLE));\n            onCreate(db);\n        }\n    }\n\n    private DatabaseHelper mOpenHelper;\n\n    private String getSelectionWithContact(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return RCS_CONTACT_SELECTION_WITH_CONTACT_ONLY;\n        }\n        return \"(\" + RCS_CONTACT_SELECTION_WITH_CONTACT_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithContact(String[] selectionArgs, String contact) {\n        return DatabaseUtils.appendIdWithSelectionArgs(contact, selectionArgs);\n    }\n\n    private String getSelectionWithAggregationDataId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return AGGREGATION_DATA_SELECTION_WITH_ID_ONLY;\n        }\n        return \"(\" + AGGREGATION_DATA_SELECTION_WITH_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithAggregationId(String[] selectionArgs,\n            String aggregationDataId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(aggregationDataId, selectionArgs);\n    }\n\n    private String[] restrictProjectionToExternallyDefinedColumns(String[] projection)\n            throws UnsupportedOperationException {\n        if (projection == null || projection.length == 0) {\n            return COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS;\n        }\n        for (String projectedColumn : projection) {\n            if (!COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS.contains(projectedColumn)) {\n                throw new UnsupportedOperationException(\"No visibility to the accessed column \"\n                        + projectedColumn + \"!\");\n            }\n        }\n        return projection;\n    }\n\n    private ParcelFileDescriptor openPhotoDataFile(Uri uri, String mode)\n            throws FileNotFoundException {\n        Cursor cursor = null;\n        try {\n            cursor = query(uri, PHOTO_DATA_PROJECTION, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, uri);\n            if (!cursor.moveToFirst()) {\n                throw new FileNotFoundException(\"No item found for URI \" + uri + \"!\");\n            }\n            String path = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ContactData.KEY_PRESENCE_PHOTO_DATA));\n            if (path == null) {\n                throw new FileNotFoundException(\"No photo is defined for URI \" + uri + \"!\");\n            }\n            return ParcelFileDescriptor.open(new File(path), DatabaseUtils.parseMode(mode));\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalContacts.INTERNAL_CONTACTS:\n                /* Intentional fall through */\n            case UriType.Contacts.CONTACTS:\n                return CursorType.Contacts.TYPE_DIRECTORY;\n\n            case UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Contacts.CONTACTS_WITH_ID:\n                return CursorType.Contacts.TYPE_ITEM;\n\n            case UriType.Aggregation.AGGREGATION:\n                return CursorType.Aggregation.TYPE_DIRECTORY;\n\n            case UriType.Aggregation.AGGREGATION_WITH_ID:\n                return CursorType.Aggregation.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalContacts.INTERNAL_CONTACTS:\n                /* Intentional fall through */\n            case UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID:\n                Context context = getContext();\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String contact = initialValues.getAsString(ContactData.KEY_CONTACT);\n                initialValues.put(ContactData.KEY_BASECOLUMN_ID, ContentProviderBaseIdCreator\n                        .createUniqueId(getContext(), ContactData.CONTENT_URI));\n                if (db.insert(CAPABILITY_TABLE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri.toString() + '!');\n                }\n                if (!initialValues.containsKey(ContactData.KEY_PRESENCE_PHOTO_DATA)) {\n                    try {\n                        String filename = FILENAME_PREFIX.concat(contact);\n                        /*\n                         * Creating a empty file to get the path for the photo data\n                         */\n                        context.openFileOutput(filename, Context.MODE_PRIVATE).close();\n                        String path = context.getFileStreamPath(filename).getAbsolutePath();\n                        initialValues.put(ContactData.KEY_PRESENCE_PHOTO_DATA, path);\n                        initialValues.put(ContactData.KEY_PRESENCE_PHOTO_EXIST_FLAG,\n                                ContactData.FALSE_VALUE);\n                    } catch (IOException e) {\n                        /*\n                         * As Social Presence Profile Picture is optional for a RCS user, So if\n                         * there is an issue with creating an empty file for same, We should still\n                         * proceed with updating user capability information.\n                         */\n                        if (logger.isActivated()) {\n                            logger.debug(e.getMessage());\n                        }\n                    }\n                }\n                db.update(CAPABILITY_TABLE, initialValues, RCS_CONTACT_SELECTION_WITH_CONTACT_ONLY,\n                        getSelectionArgsWithContact(null, contact));\n                Uri notificationUri = Uri.withAppendedPath(CapabilitiesLog.CONTENT_URI, contact);\n                context.getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.Contacts.CONTACTS_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Contacts.CONTACTS:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            case UriType.Aggregation.AGGREGATION:\n                /* Intentional fall through */\n            case UriType.Aggregation.AGGREGATION_WITH_ID:\n                db = mOpenHelper.getWritableDatabase();\n                long rowID = db.insert(AGGREGATION_TABLE, null, initialValues);\n                notificationUri = ContentUris.withAppendedId(AggregationData.CONTENT_URI, rowID);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID:\n                    String contact = uri.getLastPathSegment();\n                    selection = getSelectionWithContact(selection);\n                    selectionArgs = getSelectionArgsWithContact(selectionArgs, contact);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(CAPABILITY_TABLE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(CapabilitiesLog.CONTENT_URI, contact));\n                    return cursor;\n\n                case UriType.InternalContacts.INTERNAL_CONTACTS:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(CAPABILITY_TABLE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            CapabilitiesLog.CONTENT_URI);\n                    return cursor;\n\n                case UriType.Contacts.CONTACTS_WITH_ID:\n                    contact = uri.getLastPathSegment();\n                    selection = getSelectionWithContact(selection);\n                    selectionArgs = getSelectionArgsWithContact(selectionArgs, contact);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.Contacts.CONTACTS:\n                    /* Limited access with exposed URI */\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(CAPABILITY_TABLE,\n                            restrictProjectionToExternallyDefinedColumns(projection), selection,\n                            selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                case UriType.Aggregation.AGGREGATION_WITH_ID:\n                    String aggregationDataid = uri.getLastPathSegment();\n                    selection = getSelectionWithAggregationDataId(selection);\n                    selectionArgs = getSelectionArgsWithAggregationId(selectionArgs,\n                            aggregationDataid);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.Aggregation.AGGREGATION:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(AGGREGATION_TABLE, projection, selection, selectionArgs,\n                            null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n        } /*\n           * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n           * exception.\n           */catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID:\n                String contact = uri.getLastPathSegment();\n                selection = getSelectionWithContact(selection);\n                selectionArgs = getSelectionArgsWithContact(selectionArgs, contact);\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(CAPABILITY_TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(\n                            Uri.withAppendedPath(CapabilitiesLog.CONTENT_URI, contact), null);\n                }\n                return count;\n\n            case UriType.InternalContacts.INTERNAL_CONTACTS:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.update(CAPABILITY_TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(CapabilitiesLog.CONTENT_URI,\n                            null);\n                }\n                return count;\n\n            case UriType.Contacts.CONTACTS_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Contacts.CONTACTS:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            case UriType.Aggregation.AGGREGATION_WITH_ID:\n                String aggregationDataid = uri.getLastPathSegment();\n                selection = getSelectionWithAggregationDataId(selection);\n                selectionArgs = getSelectionArgsWithAggregationId(selectionArgs, aggregationDataid);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.Aggregation.AGGREGATION:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.update(AGGREGATION_TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(uri, null);\n                }\n                return count;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID:\n                String contact = uri.getLastPathSegment();\n                selection = getSelectionWithContact(selection);\n                selectionArgs = getSelectionArgsWithContact(selectionArgs, contact);\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(CAPABILITY_TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(\n                            Uri.withAppendedPath(CapabilitiesLog.CONTENT_URI, contact), null);\n                }\n                return count;\n\n            case UriType.InternalContacts.INTERNAL_CONTACTS:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.delete(CAPABILITY_TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(CapabilitiesLog.CONTENT_URI,\n                            null);\n                }\n                return count;\n\n            case UriType.Contacts.CONTACTS_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Contacts.CONTACTS:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            case UriType.Aggregation.AGGREGATION_WITH_ID:\n                String aggregationDataId = uri.getLastPathSegment();\n                selection = getSelectionWithAggregationDataId(selection);\n                selectionArgs = getSelectionArgsWithAggregationId(selectionArgs, aggregationDataId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.Aggregation.AGGREGATION:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.delete(AGGREGATION_TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(uri, null);\n                }\n                return count;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)\n            throws FileNotFoundException {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.Contacts.CONTACTS_WITH_ID:\n                /* Intentional fall through */\n            case UriType.InternalContacts.INTERNAL_CONTACTS_WITH_ID:\n                return openPhotoDataFile(uri, mode);\n\n            case UriType.InternalContacts.INTERNAL_CONTACTS:\n                /* Intentional fall through */\n            case UriType.Contacts.CONTACTS:\n                /* Intentional fall through */\n            case UriType.Aggregation.AGGREGATION:\n                /* Intentional fall through */\n            case UriType.Aggregation.AGGREGATION_WITH_ID:\n                throw new UnsupportedOperationException(\n                        \"Opening file stream is not supported for URI \" + uri + \"!\");\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/fthttp/FtHttpResume.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.fthttp;\n\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\n/**\n * @author YPLO6403 FtHttpResume is the abstract base class for all FT HTTP resume classes\n */\npublic abstract class FtHttpResume {\n\n    /**\n     * The direction of transfer\n     */\n    final private Direction mDirection;\n\n    /**\n     * Uri of file\n     */\n    final private Uri mFile;\n\n    /**\n     * The file name\n     */\n    final private String mFileName;\n\n    /**\n     * The file mime type\n     */\n    final private String mMimeType;\n\n    /**\n     * The size of the file to download\n     */\n    final private long mSize;\n\n    /**\n     * The fileIcon URI\n     */\n    final private Uri mFileIcon;\n\n    /**\n     * The remote contact identifier\n     */\n    final private ContactId mContact;\n\n    /**\n     * The Chat Id\n     */\n    final private String mChatId;\n\n    /**\n     * The file transfer Id\n     */\n    final private String mFileTransferId;\n\n    /**\n     * Is FT initiated from Group Chat\n     */\n    final private boolean mGroupTransfer;\n\n    /**\n     * The local timestamp\n     */\n    final private long mTimestamp;\n\n    /**\n     * The timestamp sent in payload\n     */\n    final private long mTimestampSent;\n\n    /**\n     * Creates an instance of FtHttpResume Data Object\n     * \n     * @param direction the {@code direction} value.\n     * @param file the {@code Uri of file} value.\n     * @param fileName the {@code fileName} value.\n     * @param mimeType the {@code mimeType} value.\n     * @param size the {@code size} value.\n     * @param fileIcon the {@code fileIcon} value.\n     * @param contact the {@code contactId} value.\n     * @param chatId the {@code chatId} value.\n     * @param fileTransferId the {@code fileTransferId} value.\n     * @param groupTransfer the {@code groupTransfer} value.\n     * @param timestamp the {@code timestamp} value\n     * @param timestampSent the {@code timestampSent} value\n     */\n    public FtHttpResume(Direction direction, Uri file, String fileName, String mimeType, long size,\n            Uri fileIcon, ContactId contact, String chatId, String fileTransferId,\n            boolean groupTransfer, long timestamp, long timestampSent) {\n        if (size <= 0 || file == null || fileName == null)\n            throw new IllegalArgumentException(\"size invalid arguments (size=\" + size + \") (file=\"\n                    + file + \") (fileName=\" + fileName + \")\");\n        mDirection = direction;\n        mFile = file;\n        mFileName = fileName;\n        mSize = size;\n        mFileIcon = fileIcon;\n        mContact = contact;\n        mChatId = chatId;\n        mFileTransferId = fileTransferId;\n        mGroupTransfer = groupTransfer;\n        mTimestamp = timestamp;\n        mTimestampSent = timestampSent;\n        mMimeType = mimeType;\n    }\n\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    public long getTimestampSent() {\n        return mTimestampSent;\n    }\n\n    /**\n     * Gets direction\n     * \n     * @return direction\n     */\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    /**\n     * Gets file URI\n     * \n     * @return file URI\n     */\n    public Uri getFile() {\n        return mFile;\n    }\n\n    /**\n     * Get file name\n     * \n     * @return file name\n     */\n    public String getFileName() {\n        return mFileName;\n    }\n\n    /**\n     * Gets file size\n     * \n     * @return file size\n     */\n    public long getSize() {\n        return mSize;\n    }\n\n    /**\n     * Gets file icon URI\n     * \n     * @return file icon URI\n     */\n    public Uri getFileicon() {\n        return mFileIcon;\n    }\n\n    /**\n     * Gets remote contact\n     * \n     * @return remote contact\n     */\n    public ContactId getContact() {\n        return mContact;\n    }\n\n    /**\n     * Gets chat ID\n     * \n     * @return chat ID\n     */\n    public String getChatId() {\n        return mChatId;\n    }\n\n    /**\n     * Gets file transfer ID\n     * \n     * @return file transfer ID\n     */\n    public String getFileTransferId() {\n        return mFileTransferId;\n    }\n\n    /**\n     * Checks if group transfer\n     * \n     * @return True if group transfer\n     */\n    public boolean isGroupTransfer() {\n        return mGroupTransfer;\n    }\n\n    /**\n     * Gets the file mime type\n     * \n     * @return the file mime type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    @Override\n    public String toString() {\n        return \"FtHttpResume [timestamp=\" + mTimestamp + \", timestampSent=\" + mTimestampSent\n                + \", dir=\" + mDirection + \", file=\" + mFile + \", fileName=\" + mFileName\n                + \",fileIcon=\" + mFileIcon + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/fthttp/FtHttpResumeDownload.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.fthttp;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\n/**\n * @author YPLO6403 Class to handle FtHttpResumeDownload data objects\n */\npublic final class FtHttpResumeDownload extends FtHttpResume {\n\n    /**\n     * The URI to download file from\n     */\n    private final Uri mServerAddress;\n\n    private final long mFileExpiration;\n\n    private final long mIconExpiration;\n\n    private final boolean mAccepted;\n\n    private final String mRemoteSipInstance;\n\n    /**\n     * Creates a FT HTTP resume download data object\n     * \n     * @param downloadServerAddress the {@code downloadServerAddress} instance.\n     * @param file the {@code file} value.\n     * @param fileIcon the {@code fileIcon} value.\n     * @param content the {@code content} content.\n     * @param contact the {@code contactId} value.\n     * @param chatId the {@code chatId} value.\n     * @param filetransferId the {@code filetransferId} value.\n     * @param isGroup the {@code isGroup} value.\n     * @param timestamp the {@code timestamp} value.\n     * @param timestampSent the {@code timestampSent} value.\n     * @param fileExpiration the {@code fileExpiration} value.\n     * @param iconExpiration the {@code iconExpiration} value.\n     * @param accepted the {@code accepted} value.\n     * @param remoteSipInstance the {@code remoteSipInstance} value.\n     */\n    public FtHttpResumeDownload(Uri downloadServerAddress, Uri file, Uri fileIcon,\n            MmContent content, ContactId contact, String chatId, String filetransferId,\n            boolean isGroup, long timestamp, long timestampSent, long fileExpiration,\n            long iconExpiration, boolean accepted, String remoteSipInstance) {\n        super(Direction.INCOMING, file, content.getName(), content.getEncoding(),\n                content.getSize(), fileIcon, contact, chatId, filetransferId, isGroup, timestamp,\n                timestampSent);\n        mServerAddress = downloadServerAddress;\n        mFileExpiration = fileExpiration;\n        mIconExpiration = iconExpiration;\n        mAccepted = accepted;\n        mRemoteSipInstance = remoteSipInstance;\n        if (downloadServerAddress == null || filetransferId == null)\n            throw new IllegalArgumentException(\"Invalid argument\");\n    }\n\n    /**\n     * Returns the download server URI\n     * \n     * @return the download server URI\n     */\n    public Uri getServerAddress() {\n        return mServerAddress;\n    }\n\n    /**\n     * Returns the time when the file on the content server is no longer valid to download.\n     * \n     * @return time\n     */\n    public long getFileExpiration() {\n        return mFileExpiration;\n    }\n\n    /**\n     * Returns the time when the file icon on the content server is no longer valid to download.\n     * \n     * @return time\n     */\n    public long getIconExpiration() {\n        return mIconExpiration;\n    }\n\n    /**\n     * Checks if download is accepted\n     * \n     * @return True if accepted\n     */\n    public boolean isAccepted() {\n        return mAccepted;\n    }\n\n    /**\n     * Gets remote SIP instance\n     * \n     * @return remote SIP instance\n     */\n    public String getRemoteSipInstance() {\n        return mRemoteSipInstance;\n    }\n\n    @Override\n    public String toString() {\n        return \"FtHttpResumeDownload [serverAddress=\" + mServerAddress + \", file=\" + getFile()\n                + \",fileName=\" + getFileName() + \", size=\" + getSize() + \", fileicon=\"\n                + getFileicon() + \", contact=\" + getContact() + \", chatId=\" + getChatId()\n                + \", fileTransferId=\" + getFileTransferId() + \", isGroup=\" + isGroupTransfer()\n                + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/fthttp/FtHttpResumeUpload.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.fthttp;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\n/**\n * @author YPLO6403 Class to handle FtHttpResumeUpload data objects\n */\npublic class FtHttpResumeUpload extends FtHttpResume {\n\n    /**\n     * The FT HTTP Transfer Id\n     */\n    final private String mTId;\n\n    /**\n     * Creates a FT HTTP resume upload data object\n     * \n     * @param file the {@code file} value.\n     * @param fileIcon the {@code fileIcon} value.\n     * @param tId the {@code tId} value.\n     * @param contact the {@code contactId} value.\n     * @param chatId the {@code chatId} value.\n     * @param fileTransferId the {@code fileTransferId} value.\n     * @param isGroup the {@code isGroup} value.\n     * @param timestamp the {@code timestamp} value.\n     * @param timestampSent the {@code timestampSent} value.\n     */\n    public FtHttpResumeUpload(MmContent file, Uri fileIcon, String tId, ContactId contact,\n            String chatId, String fileTransferId, boolean isGroup, long timestamp,\n            long timestampSent) {\n        super(Direction.OUTGOING, file.getUri(), file.getName(), file.getEncoding(),\n                file.getSize(), fileIcon, contact, chatId, fileTransferId, isGroup, timestamp,\n                timestampSent);\n        mTId = tId;\n    }\n\n    /**\n     * Gets the HTTP File Transfer ID\n     * \n     * @return the HTTP File Transfer ID\n     */\n    public String getTId() {\n        return mTId;\n    }\n\n    @Override\n    public String toString() {\n        return \"FtHttpResumeUpload [tId=\" + mTId + \", file=\" + getFile() + \",getFileName()=\"\n                + getFileName() + \", getSize()=\" + getSize() + \", getFileicon()=\" + getFileicon()\n                + \", getContact()=\" + getContact() + \", getChatId()=\" + getChatId()\n                + \", getFileTransferId()=\" + getFileTransferId() + \", isGroup()=\"\n                + isGroupTransfer() + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/GroupChatDequeueTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.SessionNotEstablishedException;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.DequeueTask;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.GroupChatImpl;\nimport com.gsma.rcs.service.api.GroupFileTransferImpl;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * GroupChatDequeueTask tries to dequeue all group chat messages that are QUEUED and all file\n * transfers that are either QUEUED or UPLOADED but not transferred for a specific group chat.\n */\npublic class GroupChatDequeueTask extends DequeueTask {\n\n    private final String mChatId;\n\n    private final HistoryLog mHistoryLog;\n\n    public GroupChatDequeueTask(Context ctx, Core core, MessagingLog messagingLog,\n            ChatServiceImpl chatService, FileTransferServiceImpl fileTransferService,\n            RcsSettings rcsSettings, ContactManager contactManager, HistoryLog historyLog,\n            String chatId) {\n        super(ctx, core, contactManager, messagingLog, rcsSettings, chatService,\n                fileTransferService);\n        mChatId = chatId;\n        mHistoryLog = historyLog;\n    }\n\n    private void setGroupChatEntryAsFailedDequeue(int providerId, String chatId, String id,\n            String mimeType) {\n        switch (providerId) {\n            case MessageData.HISTORYLOG_MEMBER_ID:\n                setGroupChatMessageAsFailedDequeue(chatId, id, mimeType);\n                break;\n            case FileTransferData.HISTORYLOG_MEMBER_ID:\n                setGroupFileTransferAsFailedDequeue(chatId, id);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Provider id \" + providerId\n                        + \" not supported in this context!\");\n        }\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = mLogger.isActivated();\n        if (logActivated) {\n            mLogger.debug(\"Execute task to dequeue group chat messages and group file transfers for chatId \"\n                    .concat(mChatId));\n        }\n        ImdnManager imdnManager = mImService.getImdnManager();\n        boolean displayedReportEnabled = imdnManager\n                .isRequestGroupDeliveryDisplayedReportsEnabled();\n        boolean deliveryReportEnabled = imdnManager.isDeliveryDeliveredReportsEnabled();\n        int providerId = -1;\n        String id = null;\n        Disposition disposition;\n        String mimeType = null;\n        Cursor cursor = null;\n        try {\n            if (!isImsConnected()) {\n                if (logActivated) {\n                    mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue group chat messages and group file transfers for chatId \"\n                            .concat(mChatId));\n                }\n                return;\n            }\n            if (isShuttingDownOrStopped()) {\n                if (logActivated) {\n                    mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue group chat messages and group file transfers for chatId \"\n                            .concat(mChatId));\n                }\n                return;\n            }\n            cursor = mHistoryLog.getQueuedGroupChatMessagesAndGroupFileTransfers(mChatId);\n            int providerIdIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_PROVIDER_ID);\n            int idIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_ID);\n            int contentIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_CONTENT);\n            int mimeTypeIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_MIME_TYPE);\n            int fileIconIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_FILEICON);\n            int statusIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_STATUS);\n            int fileSizeIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_FILESIZE);\n            int dispositionIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_DISPOSITION);\n            GroupChatImpl groupChat = mChatService.getOrCreateGroupChat(mChatId);\n            while (cursor.moveToNext()) {\n                try {\n                    if (!isImsConnected()) {\n                        if (logActivated) {\n                            mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue group chat messages and group file transfers for chatId \"\n                                    .concat(mChatId));\n                        }\n                        return;\n                    }\n                    if (isShuttingDownOrStopped()) {\n                        if (logActivated) {\n                            mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue group chat messages and group file transfers for chatId \"\n                                    .concat(mChatId));\n                        }\n                        return;\n                    }\n                    providerId = cursor.getInt(providerIdIdx);\n                    id = cursor.getString(idIdx);\n                    mimeType = cursor.getString(mimeTypeIdx);\n                    disposition = Disposition.valueOf(cursor.getInt(dispositionIdx));\n                    switch (providerId) {\n                        case MessageData.HISTORYLOG_MEMBER_ID:\n                            if (!isPossibleToDequeueGroupChatMessagesAndGroupFileTransfers(mChatId)) {\n                                setGroupChatMessageAsFailedDequeue(mChatId, id, mimeType);\n                                continue;\n                            }\n                            long timestamp = System.currentTimeMillis();\n                            String content = cursor.getString(contentIdx);\n                            /* For outgoing message, timestampSent = timestamp */\n                            ChatMessage message = ChatUtils.createChatMessage(id, mimeType,\n                                    content, null, null, timestamp, timestamp);\n                            groupChat.dequeueGroupChatMessage(message);\n                            break;\n\n                        case FileTransferData.HISTORYLOG_MEMBER_ID:\n                            Uri file = Uri.parse(cursor.getString(contentIdx));\n                            if (!isPossibleToDequeueGroupFileTransfer(mChatId, file,\n                                    cursor.getLong(fileSizeIdx))) {\n                                setGroupFileTransferAsFailedDequeue(mChatId, id);\n                                continue;\n                            }\n                            State state = State.valueOf(cursor.getInt(statusIdx));\n                            if (logActivated) {\n                                mLogger.debug(\"Dequeue chatId=\" + mChatId + \" in state=\" + state\n                                        + \" file=\" + file);\n                            }\n                            GroupFileTransferImpl groupFileTransfer;\n                            switch (state) {\n                                case QUEUED:\n                                    if (!isAllowedToDequeueGroupFileTransfer()) {\n                                        continue;\n                                    }\n                                    MmContent fileContent = FileTransferUtils.createMmContent(file,\n                                            mimeType, disposition);\n                                    MmContent fileIconContent = null;\n                                    String fileIcon = cursor.getString(fileIconIdx);\n                                    if (fileIcon != null) {\n                                        Uri fileIconUri = Uri.parse(fileIcon);\n                                        fileIconContent = FileTransferUtils\n                                                .createIconContent(fileIconUri);\n                                    }\n                                    mFileTransferService.dequeueGroupFileTransfer(mChatId, id,\n                                            fileContent, fileIconContent);\n                                    break;\n\n                                case STARTED:\n                                    if (!isPossibleToDequeueGroupChatMessagesAndGroupFileTransfers(mChatId)) {\n                                        setGroupFileTransferAsFailedDequeue(mChatId, id);\n                                        continue;\n                                    }\n                                    groupFileTransfer = mFileTransferService\n                                            .getOrCreateGroupFileTransfer(mChatId, id);\n                                    String fileInfo = FileTransferUtils\n                                            .createHttpFileTransferXml(mMessagingLog\n                                                    .getFileDownloadInfo(id));\n                                    groupChat.dequeueGroupFileInfo(id, fileInfo,\n                                            displayedReportEnabled, deliveryReportEnabled,\n                                            groupFileTransfer);\n                                    break;\n\n                                default:\n                                    break;\n                            }\n                            break;\n                        default:\n                            break;\n                    }\n\n                } catch (SessionNotEstablishedException | FileAccessException | NetworkException e) {\n                    if (logActivated) {\n                        mLogger.debug(\"Failed to dequeue group chat entry with id '\" + id\n                                + \"' on group chat '\" + mChatId + \"' due to: \" + e.getMessage());\n                    }\n\n                } catch (PayloadException e) {\n                    mLogger.error(\"Failed to dequeue group chat entry with id '\" + id\n                            + \"' on group chat '\" + mChatId, e);\n                    setGroupChatEntryAsFailedDequeue(providerId, mChatId, id, mimeType);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally all the terminal and non-terminal cases should be handled above so\n                     * if we come here that means that there is a bug and so we output a stack trace\n                     * so the bug can then be properly tracked down and fixed. We also mark the\n                     * respective entry that failed to dequeue as FAILED.\n                     */\n                    mLogger.error(\"Failed to dequeue group chat entry with id '\" + id\n                            + \"' and chatId '\" + mChatId + \"'\", e);\n                    setGroupChatEntryAsFailedDequeue(providerId, mChatId, id, mimeType);\n                }\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally all the terminal and non-terminal cases should be handled above so if we\n             * come here that means that there is a bug and so we output a stack trace so the bug\n             * can then be properly tracked down and fixed. We also mark the respective entry that\n             * failed to dequeue as FAILED.\n             */\n            mLogger.error(\n                    \"Exception occurred while dequeueing group chat message and group file transfer with id '\"\n                            + id + \"' and chatId '\" + mChatId + \"'\", e);\n            if (id == null) {\n                return;\n            }\n            setGroupChatEntryAsFailedDequeue(providerId, mChatId, id, mimeType);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/GroupChatTerminalExceptionTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.database.Cursor;\n\npublic class GroupChatTerminalExceptionTask implements Runnable {\n\n    private final String mChatId;\n\n    private final ChatServiceImpl mChatService;\n\n    private final FileTransferServiceImpl mFileTransferService;\n\n    private final HistoryLog mHistoryLog;\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatTerminalExceptionTask.class\n            .getName());\n\n    /* package private */public GroupChatTerminalExceptionTask(String chatId,\n            ChatServiceImpl chatService, FileTransferServiceImpl fileTransferService,\n            HistoryLog historyLog) {\n        mChatId = chatId;\n        mChatService = chatService;\n        mFileTransferService = fileTransferService;\n        mHistoryLog = historyLog;\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Execute task to mark all queued group chat messages and group file transfers as failed with chatId \"\n                    .concat(mChatId));\n        }\n        Cursor cursor = null;\n        try {\n            cursor = mHistoryLog.getQueuedGroupChatMessagesAndGroupFileTransfers(mChatId);\n            int providerIdIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_PROVIDER_ID);\n            int idIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_ID);\n            int mimeTypeIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_MIME_TYPE);\n            while (cursor.moveToNext()) {\n                int providerId = cursor.getInt(providerIdIdx);\n                String id = cursor.getString(idIdx);\n                String mimeType = cursor.getString(mimeTypeIdx);\n                switch (providerId) {\n                    case MessageData.HISTORYLOG_MEMBER_ID:\n                        mChatService.setGroupChatMessageStatusAndReasonCode(id, mimeType, mChatId,\n                                Status.FAILED, Content.ReasonCode.FAILED_SEND);\n                        break;\n                    case FileTransferData.HISTORYLOG_MEMBER_ID:\n                        mFileTransferService.setGroupFileTransferStateAndReasonCode(id, mChatId,\n                                State.FAILED, FileTransfer.ReasonCode.FAILED_NOT_ALLOWED_TO_SEND);\n                        break;\n                    default:\n                        throw new IllegalArgumentException(\"Not expecting to handle provider id '\"\n                                + providerId + \"'!\");\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    \"Exception occurred while trying to mark queued group chat messages and group file transfers as failed with chatId \"\n                            + mChatId, e);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/HistoryConstants.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.rcs.provider.contact.ContactProvider;\nimport com.gsma.rcs.provider.messaging.ChatProvider;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.FileTransferProvider;\nimport com.gsma.rcs.provider.messaging.GroupChatData;\nimport com.gsma.rcs.provider.messaging.GroupDeliveryInfoProvider;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.settings.RcsSettingsProvider;\nimport com.gsma.rcs.provider.sharing.GeolocSharingData;\nimport com.gsma.rcs.provider.sharing.GeolocSharingProvider;\nimport com.gsma.rcs.provider.sharing.ImageSharingData;\nimport com.gsma.rcs.provider.sharing.ImageSharingProvider;\nimport com.gsma.rcs.provider.sharing.VideoSharingData;\nimport com.gsma.rcs.provider.sharing.VideoSharingProvider;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/* package private */final class HistoryConstants {\n\n    /* package private */static final String[] FULL_PROJECTION = {\n            HistoryLogData.KEY_BASECOLUMN_ID, HistoryLogData.KEY_PROVIDER_ID,\n            HistoryLogData.KEY_ID, HistoryLogData.KEY_MIME_TYPE, HistoryLogData.KEY_DIRECTION,\n            HistoryLogData.KEY_CONTACT, HistoryLogData.KEY_TIMESTAMP,\n            HistoryLogData.KEY_TIMESTAMP_SENT, HistoryLogData.KEY_TIMESTAMP_DELIVERED,\n            HistoryLogData.KEY_TIMESTAMP_DISPLAYED, HistoryLogData.KEY_EXPIRED_DELIVERY,\n            HistoryLogData.KEY_STATUS, HistoryLogData.KEY_REASON_CODE,\n            HistoryLogData.KEY_READ_STATUS, HistoryLogData.KEY_CHAT_ID, HistoryLogData.KEY_CONTENT,\n            HistoryLogData.KEY_FILEICON, HistoryLogData.KEY_FILEICON_MIME_TYPE,\n            HistoryLogData.KEY_FILENAME, HistoryLogData.KEY_FILESIZE,\n            HistoryLogData.KEY_TRANSFERRED, HistoryLogData.KEY_DURATION,\n            HistoryLogData.KEY_DISPOSITION\n    };\n\n    /* package private */static final Set<String> PROTECTED_INTERNAL_DATABASES = getProtectedInternalDatabases();\n\n    /* package private */static final Set<Integer> INTERNAL_MEMBER_IDS = getInternalMemberIds();\n\n    /* package private */static final Set<HistoryMemberDatabase> INTERNAL_MEMBERS = getInternalMembers();\n\n    private static Set<String> getProtectedInternalDatabases() {\n        Set<String> protectedInternalDatabases = new HashSet<>();\n        protectedInternalDatabases.add(RcsSettingsProvider.DATABASE_NAME);\n        protectedInternalDatabases.add(ContactProvider.DATABASE_NAME);\n        protectedInternalDatabases.add(GroupDeliveryInfoProvider.DATABASE_NAME);\n        return protectedInternalDatabases;\n    }\n\n    private static Set<Integer> getInternalMemberIds() {\n        Set<Integer> internalMemberIds = new HashSet<>();\n        internalMemberIds.add(GroupChatData.HISTORYLOG_MEMBER_ID);\n        internalMemberIds.add(MessageData.HISTORYLOG_MEMBER_ID);\n        internalMemberIds.add(FileTransferData.HISTORYLOG_MEMBER_ID);\n        internalMemberIds.add(ImageSharingData.HISTORYLOG_MEMBER_ID);\n        internalMemberIds.add(VideoSharingData.HISTORYLOG_MEMBER_ID);\n        internalMemberIds.add(GeolocSharingData.HISTORYLOG_MEMBER_ID);\n        return internalMemberIds;\n    }\n\n    private static Set<HistoryMemberDatabase> getInternalMembers() {\n        Set<HistoryMemberDatabase> internalMembers = new HashSet<>();\n        internalMembers.add(new HistoryMemberDatabase(GroupChatData.HISTORYLOG_MEMBER_ID,\n                GroupChatData.CONTENT_URI, ChatProvider.DATABASE_NAME, null,\n                ChatProvider.TABLE_GROUP_CHAT, getGroupChatProviderColumnMapping()));\n        internalMembers.add(new HistoryMemberDatabase(MessageData.HISTORYLOG_MEMBER_ID,\n                MessageData.CONTENT_URI, ChatProvider.DATABASE_NAME, null,\n                ChatProvider.TABLE_MESSAGE, getChatMessageProviderColumnMapping()));\n        internalMembers.add(new HistoryMemberDatabase(FileTransferData.HISTORYLOG_MEMBER_ID,\n                FileTransferData.CONTENT_URI, FileTransferProvider.DATABASE_NAME, null,\n                FileTransferProvider.TABLE, getFileTransferProviderColumnMapping()));\n        internalMembers.add(new HistoryMemberDatabase(ImageSharingData.HISTORYLOG_MEMBER_ID,\n                ImageSharingData.CONTENT_URI, ImageSharingProvider.DATABASE_NAME, null,\n                ImageSharingProvider.TABLE, getImageSharingProviderColumnMapping()));\n        internalMembers.add(new HistoryMemberDatabase(VideoSharingData.HISTORYLOG_MEMBER_ID,\n                VideoSharingData.CONTENT_URI, VideoSharingProvider.DATABASE_NAME, null,\n                VideoSharingProvider.TABLE, getVideoSharingProviderColumnMapping()));\n        internalMembers.add(new HistoryMemberDatabase(GeolocSharingData.HISTORYLOG_MEMBER_ID,\n                GeolocSharingData.CONTENT_URI, GeolocSharingProvider.DATABASE_NAME, null,\n                GeolocSharingProvider.TABLE, getGeolocSharingProviderColumnMapping()));\n        return internalMembers;\n    }\n\n    private static Map<String, String> getGroupChatProviderColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLogData.KEY_PROVIDER_ID,\n                String.valueOf(GroupChatData.HISTORYLOG_MEMBER_ID));\n        columnMapping.put(HistoryLogData.KEY_BASECOLUMN_ID, ChatLog.GroupChat.BASECOLUMN_ID);\n        columnMapping.put(HistoryLogData.KEY_DIRECTION, ChatLog.GroupChat.DIRECTION);\n        columnMapping.put(HistoryLogData.KEY_CONTACT, ChatLog.GroupChat.CONTACT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP, ChatLog.GroupChat.TIMESTAMP);\n        columnMapping.put(HistoryLogData.KEY_STATUS, ChatLog.GroupChat.STATE);\n        columnMapping.put(HistoryLogData.KEY_REASON_CODE, ChatLog.GroupChat.REASON_CODE);\n        columnMapping.put(HistoryLogData.KEY_CHAT_ID, ChatLog.GroupChat.CHAT_ID);\n        columnMapping.put(HistoryLogData.KEY_CONTENT, ChatLog.GroupChat.SUBJECT);\n        return columnMapping;\n    }\n\n    private static Map<String, String> getChatMessageProviderColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLogData.KEY_PROVIDER_ID,\n                String.valueOf(MessageData.HISTORYLOG_MEMBER_ID));\n        columnMapping.put(HistoryLogData.KEY_BASECOLUMN_ID, ChatLog.Message.BASECOLUMN_ID);\n        columnMapping.put(HistoryLogData.KEY_ID, ChatLog.Message.MESSAGE_ID);\n        columnMapping.put(HistoryLogData.KEY_MIME_TYPE, ChatLog.Message.MIME_TYPE);\n        columnMapping.put(HistoryLogData.KEY_DIRECTION, ChatLog.Message.DIRECTION);\n        columnMapping.put(HistoryLogData.KEY_CONTACT, ChatLog.Message.CONTACT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP, ChatLog.Message.TIMESTAMP);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP_SENT, ChatLog.Message.TIMESTAMP_SENT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP_DELIVERED,\n                ChatLog.Message.TIMESTAMP_DELIVERED);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP_DISPLAYED,\n                ChatLog.Message.TIMESTAMP_DISPLAYED);\n        columnMapping.put(HistoryLogData.KEY_EXPIRED_DELIVERY, ChatLog.Message.EXPIRED_DELIVERY);\n        columnMapping.put(HistoryLogData.KEY_STATUS, ChatLog.Message.STATUS);\n        columnMapping.put(HistoryLogData.KEY_REASON_CODE, ChatLog.Message.REASON_CODE);\n        columnMapping.put(HistoryLogData.KEY_READ_STATUS, ChatLog.Message.READ_STATUS);\n        columnMapping.put(HistoryLogData.KEY_CHAT_ID, ChatLog.Message.CHAT_ID);\n        columnMapping.put(HistoryLogData.KEY_CONTENT, ChatLog.Message.CONTENT);\n        return columnMapping;\n    }\n\n    private static Map<String, String> getFileTransferProviderColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLogData.KEY_PROVIDER_ID,\n                String.valueOf(FileTransferData.HISTORYLOG_MEMBER_ID));\n        columnMapping.put(HistoryLogData.KEY_BASECOLUMN_ID, FileTransferLog.BASECOLUMN_ID);\n        columnMapping.put(HistoryLogData.KEY_ID, FileTransferLog.FT_ID);\n        columnMapping.put(HistoryLogData.KEY_MIME_TYPE, FileTransferLog.MIME_TYPE);\n        columnMapping.put(HistoryLogData.KEY_DIRECTION, FileTransferLog.DIRECTION);\n        columnMapping.put(HistoryLogData.KEY_CONTACT, FileTransferLog.CONTACT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP, FileTransferLog.TIMESTAMP);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP_SENT, FileTransferLog.TIMESTAMP_SENT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP_DELIVERED,\n                FileTransferLog.TIMESTAMP_DELIVERED);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP_DISPLAYED,\n                FileTransferLog.TIMESTAMP_DISPLAYED);\n        columnMapping.put(HistoryLogData.KEY_EXPIRED_DELIVERY, FileTransferLog.EXPIRED_DELIVERY);\n        columnMapping.put(HistoryLogData.KEY_STATUS, FileTransferLog.STATE);\n        columnMapping.put(HistoryLogData.KEY_REASON_CODE, FileTransferLog.REASON_CODE);\n        columnMapping.put(HistoryLogData.KEY_READ_STATUS, FileTransferLog.READ_STATUS);\n        columnMapping.put(HistoryLogData.KEY_CHAT_ID, FileTransferLog.CHAT_ID);\n        columnMapping.put(HistoryLogData.KEY_CONTENT, FileTransferLog.FILE);\n        columnMapping.put(HistoryLogData.KEY_FILEICON, FileTransferLog.FILEICON);\n        columnMapping.put(HistoryLogData.KEY_FILENAME, FileTransferLog.FILENAME);\n        columnMapping.put(HistoryLogData.KEY_FILESIZE, FileTransferLog.FILESIZE);\n        columnMapping.put(HistoryLogData.KEY_TRANSFERRED, FileTransferLog.TRANSFERRED);\n        columnMapping.put(HistoryLogData.KEY_DISPOSITION, FileTransferLog.DISPOSITION);\n        return columnMapping;\n    }\n\n    private static Map<String, String> getImageSharingProviderColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLogData.KEY_PROVIDER_ID,\n                String.valueOf(ImageSharingData.HISTORYLOG_MEMBER_ID));\n        columnMapping.put(HistoryLogData.KEY_BASECOLUMN_ID, ImageSharingLog.BASECOLUMN_ID);\n        columnMapping.put(HistoryLogData.KEY_ID, ImageSharingLog.SHARING_ID);\n        columnMapping.put(HistoryLogData.KEY_MIME_TYPE, ImageSharingLog.MIME_TYPE);\n        columnMapping.put(HistoryLogData.KEY_DIRECTION, ImageSharingLog.DIRECTION);\n        columnMapping.put(HistoryLogData.KEY_CONTACT, ImageSharingLog.CONTACT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP, ImageSharingLog.TIMESTAMP);\n        columnMapping.put(HistoryLogData.KEY_STATUS, ImageSharingLog.STATE);\n        columnMapping.put(HistoryLogData.KEY_REASON_CODE, ImageSharingLog.REASON_CODE);\n        columnMapping.put(HistoryLogData.KEY_CONTENT, ImageSharingLog.FILE);\n        columnMapping.put(HistoryLogData.KEY_FILENAME, ImageSharingLog.FILENAME);\n        columnMapping.put(HistoryLogData.KEY_FILESIZE, ImageSharingLog.FILESIZE);\n        columnMapping.put(HistoryLogData.KEY_TRANSFERRED, ImageSharingLog.TRANSFERRED);\n        return columnMapping;\n    }\n\n    private static Map<String, String> getVideoSharingProviderColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLogData.KEY_PROVIDER_ID,\n                String.valueOf(VideoSharingData.HISTORYLOG_MEMBER_ID));\n        columnMapping.put(HistoryLogData.KEY_BASECOLUMN_ID, VideoSharingLog.BASECOLUMN_ID);\n        columnMapping.put(HistoryLogData.KEY_ID, VideoSharingLog.SHARING_ID);\n        columnMapping.put(HistoryLogData.KEY_DIRECTION, VideoSharingLog.DIRECTION);\n        columnMapping.put(HistoryLogData.KEY_CONTACT, VideoSharingLog.CONTACT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP, VideoSharingLog.TIMESTAMP);\n        columnMapping.put(HistoryLogData.KEY_STATUS, VideoSharingLog.STATE);\n        columnMapping.put(HistoryLogData.KEY_REASON_CODE, VideoSharingLog.REASON_CODE);\n        columnMapping.put(HistoryLogData.KEY_DURATION, VideoSharingLog.DURATION);\n        return columnMapping;\n    }\n\n    private static Map<String, String> getGeolocSharingProviderColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLogData.KEY_PROVIDER_ID,\n                String.valueOf(GeolocSharingData.HISTORYLOG_MEMBER_ID));\n        columnMapping.put(HistoryLogData.KEY_BASECOLUMN_ID, GeolocSharingLog.BASECOLUMN_ID);\n        columnMapping.put(HistoryLogData.KEY_ID, GeolocSharingLog.SHARING_ID);\n        columnMapping.put(HistoryLogData.KEY_DIRECTION, GeolocSharingLog.DIRECTION);\n        columnMapping.put(HistoryLogData.KEY_CONTACT, GeolocSharingLog.CONTACT);\n        columnMapping.put(HistoryLogData.KEY_TIMESTAMP, GeolocSharingLog.TIMESTAMP);\n        columnMapping.put(HistoryLogData.KEY_STATUS, GeolocSharingLog.STATE);\n        columnMapping.put(HistoryLogData.KEY_REASON_CODE, GeolocSharingLog.REASON_CODE);\n        columnMapping.put(HistoryLogData.KEY_MIME_TYPE, GeolocSharingLog.MIME_TYPE);\n        columnMapping.put(HistoryLogData.KEY_CONTENT, GeolocSharingLog.CONTENT);\n        return columnMapping;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/HistoryLog.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\npublic class HistoryLog {\n\n    private static volatile HistoryLog sInstance;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private static final Uri CHATMESSAGE_AND_FILETRANSFER_CONTENT_URI = new HistoryUriBuilder(\n            HistoryLogData.CONTENT_URI).appendProvider(MessageData.HISTORYLOG_MEMBER_ID)\n            .appendProvider(FileTransferData.HISTORYLOG_MEMBER_ID).build();\n\n    private static final String SELECTION_QUEUED_CHATMESSAGES_AND_FILETRANSFERS = \"(\"\n            + HistoryLogData.KEY_STATUS + \"=\" + Status.QUEUED.toInt() + \" AND \"\n            + HistoryLogData.KEY_MIME_TYPE + \"<>'\" + MimeType.GROUPCHAT_EVENT + \"' AND \"\n            + HistoryLogData.KEY_PROVIDER_ID + \"=\" + MessageData.HISTORYLOG_MEMBER_ID + \") OR (\"\n            + HistoryLogData.KEY_STATUS + \"=\" + FileTransfer.State.QUEUED.toInt() + \" AND \"\n            + HistoryLogData.KEY_PROVIDER_ID + \"=\" + FileTransferData.HISTORYLOG_MEMBER_ID + ')';\n\n    private static final String SELECTION_UPLOADED_BUT_NOT_TRANSFERRED_FILETRANSFERS = \"(\"\n            + HistoryLogData.KEY_PROVIDER_ID + \"=\" + FileTransferData.HISTORYLOG_MEMBER_ID\n            + \" AND \" + HistoryLogData.KEY_STATUS + \"=\" + FileTransfer.State.STARTED.toInt()\n            + \" AND \" + HistoryLogData.KEY_DIRECTION + \"=\" + Direction.OUTGOING.toInt() + \" AND \"\n            + HistoryLogData.KEY_FILESIZE + \"=\" + HistoryLogData.KEY_TRANSFERRED + \")\";\n\n    private static final String SELECTION_QUEUED_GROUPCHATMESSAGES_AND_GROUPFILETRANSFERS = HistoryLogData.KEY_CHAT_ID\n            + \"=? AND (\"\n            + SELECTION_QUEUED_CHATMESSAGES_AND_FILETRANSFERS\n            + \" OR \"\n            + SELECTION_UPLOADED_BUT_NOT_TRANSFERRED_FILETRANSFERS + ')';\n\n    private static final String SELECTION_QUEUED_ONETOONECHATMESSAGES_AND_ONETOONE_FILETRANSFERS = HistoryLogData.KEY_CHAT_ID\n            + \"=\"\n            + HistoryLogData.KEY_CONTACT\n            + \" AND (\"\n            + SELECTION_QUEUED_CHATMESSAGES_AND_FILETRANSFERS\n            + \" OR \"\n            + SELECTION_UPLOADED_BUT_NOT_TRANSFERRED_FILETRANSFERS + ')';\n\n    private static final String SELECTION_ID = HistoryLogData.KEY_ID + \"=?\";\n\n    private static final String[] PROJECTION_REMOTE_CONTACT = new String[] {\n        HistoryLogData.KEY_CONTACT\n    };\n\n    private static final int FIRST_COLUMN_IDX = 0;\n\n    private static final String ORDER_BY_TIMESTAMP_ASC = HistoryLogData.KEY_TIMESTAMP\n            .concat(\" ASC\");\n\n    private HistoryLog(LocalContentResolver localContentResolver) {\n        mLocalContentResolver = localContentResolver;\n    }\n\n    /**\n     * Get or Create Singleton instance of HistoryLog\n     * \n     * @param localContentResolver Local content resolver\n     * @return HistoryLog instance\n     */\n    public static HistoryLog getInstance(LocalContentResolver localContentResolver) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (HistoryLog.class) {\n            if (sInstance == null) {\n                sInstance = new HistoryLog(localContentResolver);\n            }\n            return sInstance;\n        }\n    }\n\n    public Cursor getQueuedGroupChatMessagesAndGroupFileTransfers(String chatId) {\n        String[] selectionArgs = new String[] {\n            chatId\n        };\n        Cursor cursor = mLocalContentResolver.query(CHATMESSAGE_AND_FILETRANSFER_CONTENT_URI, null,\n                SELECTION_QUEUED_GROUPCHATMESSAGES_AND_GROUPFILETRANSFERS, selectionArgs,\n                ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, CHATMESSAGE_AND_FILETRANSFER_CONTENT_URI);\n        return cursor;\n    }\n\n    public Cursor getQueuedOneToOneChatMessagesAndOneToOneFileTransfers() {\n        Cursor cursor = mLocalContentResolver.query(CHATMESSAGE_AND_FILETRANSFER_CONTENT_URI, null,\n                SELECTION_QUEUED_ONETOONECHATMESSAGES_AND_ONETOONE_FILETRANSFERS, null,\n                ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, CHATMESSAGE_AND_FILETRANSFER_CONTENT_URI);\n        return cursor;\n    }\n\n    /**\n     * Get remote contact corresponding to the unique ID of message/ FT entry\n     * \n     * @param id Unique ID of message/ FT entry\n     * @return ContactId\n     */\n    public ContactId getRemoteContact(String id) {\n        String[] selectionArgs = new String[] {\n            id\n        };\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(CHATMESSAGE_AND_FILETRANSFER_CONTENT_URI,\n                    PROJECTION_REMOTE_CONTACT, SELECTION_ID, selectionArgs, null);\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return ContactUtil.createContactIdFromTrustedData(cursor.getString(FIRST_COLUMN_IDX));\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/HistoryLogData.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.net.Uri;\n\npublic class HistoryLogData {\n\n    /**\n     * Database URI\n     */\n    public static final Uri CONTENT_URI = Uri.parse(\"content://com.gsma.rcs.history/history\");\n\n    /* package private */static final String KEY_BASECOLUMN_ID = HistoryLog.BASECOLUMN_ID;\n\n    /* package private */static final String KEY_PROVIDER_ID = HistoryLog.PROVIDER_ID;\n\n    /* package private */static final String KEY_ID = HistoryLog.ID;\n\n    /* package private */static final String KEY_MIME_TYPE = HistoryLog.MIME_TYPE;\n\n    /* package private */static final String KEY_DISPOSITION = HistoryLog.DISPOSITION;\n\n    /* package private */static final String KEY_DIRECTION = HistoryLog.DIRECTION;\n\n    /* package private */static final String KEY_CONTACT = HistoryLog.CONTACT;\n\n    /* package private */static final String KEY_TIMESTAMP = HistoryLog.TIMESTAMP;\n\n    /* package private */static final String KEY_TIMESTAMP_SENT = HistoryLog.TIMESTAMP_SENT;\n\n    /* package private */static final String KEY_TIMESTAMP_DELIVERED = HistoryLog.TIMESTAMP_DELIVERED;\n\n    /* package private */static final String KEY_TIMESTAMP_DISPLAYED = HistoryLog.TIMESTAMP_DISPLAYED;\n\n    /* package private */static final String KEY_EXPIRED_DELIVERY = HistoryLog.EXPIRED_DELIVERY;\n\n    /* package private */static final String KEY_STATUS = HistoryLog.STATUS;\n\n    /* package private */static final String KEY_REASON_CODE = HistoryLog.REASON_CODE;\n\n    /* package private */static final String KEY_READ_STATUS = HistoryLog.READ_STATUS;\n\n    /* package private */static final String KEY_CHAT_ID = HistoryLog.CHAT_ID;\n\n    /* package private */static final String KEY_CONTENT = HistoryLog.CONTENT;\n\n    /* package private */static final String KEY_FILEICON = HistoryLog.FILEICON;\n\n    /* package private */static final String KEY_FILEICON_MIME_TYPE = HistoryLog.FILEICON_MIME_TYPE;\n\n    /* package private */static final String KEY_FILENAME = HistoryLog.FILENAME;\n\n    /* package private */static final String KEY_FILESIZE = HistoryLog.FILESIZE;\n\n    /* package private */static final String KEY_TRANSFERRED = HistoryLog.TRANSFERRED;\n\n    /* package private */static final String KEY_DURATION = HistoryLog.DURATION;\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/HistoryMemberBaseIdCreator.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport android.content.ContentProviderClient;\nimport android.content.Context;\nimport android.util.SparseArray;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * As the base column \"_id\" is unique across all content providers that are history members, this\n * class is used to generate this id.\n */\npublic class HistoryMemberBaseIdCreator {\n\n    private static final long RANGE_SIZE = Long.MAX_VALUE / HistoryProvider.MAX_ATTACHED_PROVIDERS;\n\n    private static SparseArray<AtomicLong> sNextIds = new SparseArray<>();\n\n    /**\n     * Creates a unique ID for a specific content provider by incrementing the last generated id and\n     * by assigning a range big enough to avoid any overlap. The last generated id is found by\n     * reading the base column \"_id\" of that provider, or will return 1 if not found.\n     * \n     * @param ctx the android context\n     * @return the generated id\n     */\n    public static long createUniqueId(Context ctx, int memberId) {\n        AtomicLong nextId = sNextIds.get(memberId);\n        if (nextId != null) {\n            return nextId.incrementAndGet();\n        }\n        synchronized (sNextIds) {\n            nextId = sNextIds.get(memberId);\n            if (nextId != null) {\n                return nextId.incrementAndGet();\n            }\n            String historyLogAuthority = HistoryLogData.CONTENT_URI.getAuthority();\n            ContentProviderClient contentProviderClient = ctx.getContentResolver()\n                    .acquireContentProviderClient(historyLogAuthority);\n            try {\n                HistoryProvider provider = (HistoryProvider) contentProviderClient\n                        .getLocalContentProvider();\n                long maxId = provider.getMaxId(memberId);\n                if (maxId == 0) {\n                    maxId = (memberId - 1) * RANGE_SIZE;\n                }\n                nextId = new AtomicLong(maxId);\n                sNextIds.put(memberId, nextId);\n                nextId.set(maxId);\n                return nextId.incrementAndGet();\n\n            } finally {\n                if (contentProviderClient != null) {\n                    contentProviderClient.release();\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/HistoryMemberDatabase.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport android.net.Uri;\n\nimport java.util.Map;\n\n/* package private */class HistoryMemberDatabase {\n\n    private final int mProviderId;\n\n    private final Uri mContentProviderUri;\n\n    private Uri mDatabaseUri;\n\n    private String mDatabaseName;\n\n    private final String mTableName;\n\n    private final Map<String, String> mColumnMapping;\n\n    private long mMaxId = 0;\n\n    private boolean mAttached;\n\n    public HistoryMemberDatabase(int memberId, Uri contentProviderUri, String databaseName,\n            Uri databaseUri, String tableName, Map<String, String> columnMapping) {\n        super();\n        mProviderId = memberId;\n        mContentProviderUri = contentProviderUri;\n        mDatabaseName = databaseName;\n        mDatabaseUri = databaseUri;\n        mTableName = tableName;\n        mColumnMapping = columnMapping;\n    }\n\n    public String getDatabaseName() {\n        return mDatabaseName;\n    }\n\n    public int getProviderId() {\n        return mProviderId;\n    }\n\n    public Uri getContentProviderUri() {\n        return mContentProviderUri;\n    }\n\n    void setDatabaseUri(Uri databaseUri) {\n        mDatabaseUri = databaseUri;\n    }\n\n    public Uri getDatabaseUri() {\n        return mDatabaseUri;\n    }\n\n    public String getTableName() {\n        return mTableName;\n    }\n\n    public Map<String, String> getColumnMapping() {\n        return mColumnMapping;\n    }\n\n    public void setAttached(boolean attached) {\n        mAttached = attached;\n    }\n\n    public boolean isAttached() {\n        return mAttached;\n    }\n\n    public long getMaxId() {\n        return mMaxId;\n    }\n\n    public void setMaxId(long maxId) {\n        mMaxId = maxId;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/HistoryProvider.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.services.rcs.history.HistoryLog;\n\nimport android.content.ContentValues;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteQueryBuilder;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\nimport java.security.ProviderException;\nimport java.util.List;\n\npublic class HistoryProvider extends MultiDbProvider {\n\n    /**\n     * The number of databases will not exceed 20 as SQlite cannot attach more.\n     */\n    public static final int MAX_ATTACHED_PROVIDERS = 20;\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/history\";\n\n    }\n\n    private static final class UriType {\n\n        private static final class History {\n\n            private static final int HISTORY = 1;\n\n        }\n\n        private static final class InternalHistory {\n\n            private static final int HISTORY = 2;\n\n        }\n\n    }\n\n    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n    static {\n        sUriMatcher.addURI(HistoryLog.CONTENT_URI.getAuthority(), HistoryLog.CONTENT_URI.getPath()\n                .substring(1), UriType.History.HISTORY);\n        sUriMatcher.addURI(HistoryLogData.CONTENT_URI.getAuthority(), HistoryLogData.CONTENT_URI\n                .getPath().substring(1), UriType.InternalHistory.HISTORY);\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.History.HISTORY:\n            case UriType.InternalHistory.HISTORY:\n                return CursorType.TYPE_DIRECTORY;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        List<String> historyLogMembers = uri.getQueryParameters(HistoryLogData.KEY_PROVIDER_ID);\n        ensureDatabasesAttached(historyLogMembers);\n        StringBuilder query = new StringBuilder(\"SELECT \");\n        if (projection == null) {\n            SQLiteQueryBuilder.appendColumns(query, HistoryConstants.FULL_PROJECTION);\n        } else {\n            SQLiteQueryBuilder.appendColumns(query, projection);\n        }\n        String unionQuery = mQueryHelper.generateUnionQuery(historyLogMembers, selectionArgs,\n                selection);\n        query.append(\" FROM (\").append(unionQuery).append(')');\n        if (!TextUtils.isEmpty(selection)) {\n            query.append(\" WHERE \").append(selection);\n        }\n        if (sort != null) {\n            query.append(\" ORDER BY \").append(sort);\n        }\n        return executeReadQuery(query.toString(), selectionArgs);\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String where, String[] whereArgs) {\n        throw new ProviderException(\"Operation not supported!\");\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        throw new ProviderException(\"Operation not supported!\");\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String where, String[] whereArgs) {\n        throw new ProviderException(\"Operation not supported!\");\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/MultiDbProvider.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport static com.gsma.rcs.provider.history.HistoryConstants.INTERNAL_MEMBERS;\nimport static com.gsma.rcs.provider.history.HistoryConstants.INTERNAL_MEMBER_IDS;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ServerApiIllegalArgumentException;\n\nimport android.content.ContentProvider;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.provider.BaseColumns;\nimport android.util.SparseArray;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Mother class for the History Provider that embeds generic functions for the\n * registration/unregistration of external providers and its related database operations.\n */\n/* package private */\n@SuppressWarnings(\"ConstantConditions\")\nabstract class MultiDbProvider extends ContentProvider {\n\n    private static final String MAX_PROJECTION = \"MAX(\" + BaseColumns._ID + \")\";\n\n    private final SparseArray<HistoryMemberDatabase> mHistoryMemberDatabases = new SparseArray<>();\n\n    private final Set<String> mForbiddenCanonicalPaths = new HashSet<>();\n\n    /**\n     * This is a flag put to true each time a member is registered so to execute refresh on query.\n     */\n    private boolean mAllDatabasesAttached = false;\n\n    private DatabaseHelper mOpenHelper;\n\n    protected final QueryHelper mQueryHelper = new QueryHelper();\n\n    private final class DatabaseHelper extends SQLiteOpenHelper {\n\n        private static final int DATABASE_VERSION = 1;\n\n        private DatabaseHelper(Context context) {\n            super(context, null, null, DATABASE_VERSION);\n        }\n\n        private String getDatabaseAlias(int providerId) {\n            return \"db\".concat(String.valueOf(providerId));\n        }\n\n        private void detach(int providerId) {\n            getWritableDatabase().execSQL(\"DETACH DATABASE \" + getDatabaseAlias(providerId));\n            mHistoryMemberDatabases.get(providerId).setAttached(false);\n        }\n\n        private void detachAll() {\n            for (int i = 0; i < mHistoryMemberDatabases.size(); i++) {\n                int providerId = mHistoryMemberDatabases.keyAt(i);\n                if (mHistoryMemberDatabases.get(providerId).isAttached()) {\n                    detach(providerId);\n                }\n            }\n        }\n\n        private void attach(int providerId) {\n            HistoryMemberDatabase memberDatabase = mHistoryMemberDatabases.get(providerId);\n            Uri database = memberDatabase.getDatabaseUri();\n            String attachCommand = \"ATTACH DATABASE '\" + database.getPath() + \"' AS \"\n                    + getDatabaseAlias(providerId);\n            SQLiteDatabase db = getWritableDatabase();\n            db.execSQL(attachCommand);\n            mHistoryMemberDatabases.get(providerId).setAttached(true);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n        }\n    }\n\n    private void registerDatabase(HistoryMemberDatabase memberDatabase) throws IOException {\n        mHistoryMemberDatabases.put(memberDatabase.getProviderId(), memberDatabase);\n\n        String canonicalPath = new File(memberDatabase.getDatabaseUri().getPath())\n                .getCanonicalPath();\n        mForbiddenCanonicalPaths.add(canonicalPath);\n\n        mQueryHelper.generateSubQuery(memberDatabase.getProviderId(),\n                memberDatabase.getColumnMapping(), memberDatabase.getTableName());\n    }\n\n    protected void ensureDatabaseAttached(int providerId) {\n        HistoryMemberDatabase memberDatabase = mHistoryMemberDatabases.get(providerId);\n        synchronized (memberDatabase) {\n            if (memberDatabase.isAttached()) {\n                return;\n            }\n            Uri requestedUri = memberDatabase.getContentProviderUri();\n            Cursor cursor = null;\n            try {\n                cursor = getContext().getContentResolver().query(requestedUri, new String[] {\n                    MAX_PROJECTION\n                }, null, null, null);\n                CursorUtil.assertCursorIsNotNull(cursor, requestedUri);\n                if (cursor.moveToNext()) {\n                    memberDatabase.setMaxId(cursor.getLong(0));\n                }\n\n            } finally {\n                if (cursor != null) {\n                    cursor.close();\n                }\n            }\n            mOpenHelper.attach(providerId);\n        }\n    }\n\n    /* package private */void ensureDatabasesAttached(List<String> providerIds) {\n        if (mAllDatabasesAttached) {\n            return;\n        }\n        for (String providerId : providerIds) {\n            ensureDatabaseAttached(Integer.parseInt(providerId));\n        }\n        mAllDatabasesAttached = true;\n        for (int i = 0; i < mHistoryMemberDatabases.size(); i++) {\n            HistoryMemberDatabase member = mHistoryMemberDatabases.valueAt(i);\n            if (!member.isAttached()) {\n                mAllDatabasesAttached = false;\n                break;\n            }\n        }\n    }\n\n    /* package private */long getMaxId(int providerId) {\n        ensureDatabaseAttached(providerId);\n        return mHistoryMemberDatabases.get(providerId).getMaxId();\n    }\n\n    /**\n     * Initializes the internal providers.\n     * \n     * @throws IOException\n     */\n    public void registerInternalProviders() throws IOException {\n        if (mHistoryMemberDatabases.size() > 0) {\n            return;\n        }\n\n        if (mOpenHelper == null) {\n            return;\n        }\n\n        mOpenHelper.detachAll();\n        mAllDatabasesAttached = false;\n        mQueryHelper.clear();\n        mForbiddenCanonicalPaths.clear();\n        mHistoryMemberDatabases.clear();\n\n        for (String databaseName : HistoryConstants.PROTECTED_INTERNAL_DATABASES) {\n            Uri databaseUri = Uri.fromFile(getContext().getDatabasePath(databaseName));\n            String canonicalPath = new File(databaseUri.getPath()).getCanonicalPath();\n            mForbiddenCanonicalPaths.add(canonicalPath);\n        }\n\n        for (HistoryMemberDatabase internalMember : INTERNAL_MEMBERS) {\n            Uri databaseUri = Uri.fromFile(getContext().getDatabasePath(\n                    internalMember.getDatabaseName()));\n            internalMember.setDatabaseUri(databaseUri);\n            registerDatabase(internalMember);\n        }\n\n    }\n\n    protected Cursor executeReadQuery(String sql, String[] selectionArgs) {\n        return mOpenHelper.getReadableDatabase().rawQuery(sql, selectionArgs);\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        try {\n            registerInternalProviders();\n        } catch (IOException e) {\n            throw new IllegalStateException(\"Problem registering internal history providers!\", e);\n        }\n        return true;\n    }\n\n    public void registerDatabase(int providerId, Uri contentProviderUri, Uri databaseUri,\n            String tableName, Map<String, String> columnMapping) throws IOException {\n        if (mHistoryMemberDatabases.get(providerId) != null) {\n            throw new IllegalArgumentException(\n                    \"Cannot register external database for already registered provider id \"\n                            + providerId + \"!\");\n        }\n\n        String canonicalPath = new File(databaseUri.getPath()).getCanonicalPath();\n        if (mForbiddenCanonicalPaths.contains(canonicalPath)) {\n            throw new IllegalArgumentException(\"Forbidden to add '\" + databaseUri + \"'\"\n                    + \" as a history log member!\");\n        }\n        registerDatabase(new HistoryMemberDatabase(providerId, contentProviderUri, null,\n                databaseUri, tableName, columnMapping));\n    }\n\n    public void unregisterDatabaseByProviderId(int providerId) {\n        if (INTERNAL_MEMBER_IDS.contains(providerId)) {\n            throw new ServerApiIllegalArgumentException(\n                    \"Trying to access history log member with invalid external id:\" + providerId\n                            + \"!\");\n        }\n\n        HistoryMemberDatabase memberDatabase = mHistoryMemberDatabases.get(providerId);\n        synchronized (memberDatabase) {\n            mQueryHelper.clearProvider(providerId);\n            if (memberDatabase.isAttached()) {\n                mOpenHelper.detach(providerId);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/OneToOneChatDequeueTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.SessionUnavailableException;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.DequeueTask;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.OneToOneChatImpl;\nimport com.gsma.rcs.service.api.OneToOneFileTransferImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * OneToOneChatDequeueTask tries to dequeue and send all QUEUED one-one chat messages and QUEUED or\n * UPLOADED but not transferred one-one file transfers.\n */\npublic class OneToOneChatDequeueTask extends DequeueTask {\n\n    private final HistoryLog mHistoryLog;\n\n    public OneToOneChatDequeueTask(Context ctx, Core core, MessagingLog messagingLog,\n            RcsSettings rcsSettings, ChatServiceImpl chatService,\n            FileTransferServiceImpl fileTransferService, ContactManager contactManager,\n            HistoryLog historyLog) {\n        super(ctx, core, contactManager, messagingLog, rcsSettings, chatService,\n                fileTransferService);\n        mHistoryLog = historyLog;\n    }\n\n    private void setOneToOneChatEntryAsFailedDequeue(int providerId, ContactId contact, String id,\n            String mimeType) {\n        switch (providerId) {\n            case MessageData.HISTORYLOG_MEMBER_ID:\n                setOneToOneChatMessageAsFailedDequeue(contact, id, mimeType);\n                break;\n            case FileTransferData.HISTORYLOG_MEMBER_ID:\n                setOneToOneFileTransferAsFailedDequeue(contact, id);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Provider id \" + providerId\n                        + \" not supported in this context!\");\n        }\n    }\n\n    public void run() {\n        boolean logActivated = mLogger.isActivated();\n        if (logActivated) {\n            mLogger.debug(\"Execute task to dequeue all one-to-one chat messages and one-to-one file transfers.\");\n        }\n        int providerId = -1;\n        String id = null;\n        Disposition disposition;\n        ContactId contact = null;\n        String mimeType = null;\n        Cursor cursor = null;\n        ImdnManager imdnManager = mImService.getImdnManager();\n        boolean displayedReportEnabled = imdnManager\n                .isRequestGroupDeliveryDisplayedReportsEnabled();\n        boolean deliveryReportEnabled = imdnManager.isDeliveryDeliveredReportsEnabled();\n        try {\n            if (!isImsConnected()) {\n                if (logActivated) {\n                    mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue all one-to-one chat messages and one-to-one file transfers.\");\n                }\n                return;\n            }\n            if (isShuttingDownOrStopped()) {\n                if (logActivated) {\n                    mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue all one-to-one chat messages and one-to-one file transfers.\");\n                }\n                return;\n            }\n            cursor = mHistoryLog.getQueuedOneToOneChatMessagesAndOneToOneFileTransfers();\n            int providerIdIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_PROVIDER_ID);\n            int idIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_ID);\n            int contactIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_CONTACT);\n            int contentIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_CONTENT);\n            int mimeTypeIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_MIME_TYPE);\n            int fileIconIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_FILEICON);\n            int statusIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_STATUS);\n            int fileSizeIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_FILESIZE);\n            int dispositionIdx = cursor.getColumnIndexOrThrow(HistoryLogData.KEY_DISPOSITION);\n            while (cursor.moveToNext()) {\n                try {\n                    if (!isImsConnected()) {\n                        if (logActivated) {\n                            mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue all one-to-one chat messages and one-to-one file transfers.\");\n                        }\n                        return;\n                    }\n                    if (isShuttingDownOrStopped()) {\n                        if (logActivated) {\n                            mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue all one-to-one chat messages and one-to-one file transfers.\");\n                        }\n                        return;\n                    }\n                    providerId = cursor.getInt(providerIdIdx);\n                    id = cursor.getString(idIdx);\n                    String phoneNumber = cursor.getString(contactIdx);\n                    contact = ContactUtil.createContactIdFromTrustedData(phoneNumber);\n                    OneToOneChatImpl oneToOneChat = mChatService.getOrCreateOneToOneChat(contact);\n                    mimeType = cursor.getString(mimeTypeIdx);\n                    disposition = Disposition.valueOf(cursor.getInt(dispositionIdx));\n                    switch (providerId) {\n                        case MessageData.HISTORYLOG_MEMBER_ID:\n                            if (!isPossibleToDequeueOneToOneChatMessage(contact)) {\n                                setOneToOneChatMessageAsFailedDequeue(contact, id, mimeType);\n                                continue;\n                            }\n                            if (!isAllowedToDequeueOneToOneChatMessage(contact)) {\n                                continue;\n                            }\n                            String content = cursor.getString(contentIdx);\n                            long timestamp = System.currentTimeMillis();\n                            /* For outgoing message, timestampSent = timestamp */\n                            ChatMessage msg = ChatUtils.createChatMessage(id, mimeType, content,\n                                    contact, null, timestamp, timestamp);\n                            oneToOneChat.dequeueOneToOneChatMessage(msg);\n                            break;\n                        case FileTransferData.HISTORYLOG_MEMBER_ID:\n                            Uri file = Uri.parse(cursor.getString(contentIdx));\n                            if (!isPossibleToDequeueOneToOneFileTransfer(contact, file,\n                                    cursor.getLong(fileSizeIdx))) {\n                                setOneToOneFileTransferAsFailedDequeue(contact, id);\n                                continue;\n                            }\n                            State state = State.valueOf(cursor.getInt(statusIdx));\n                            switch (state) {\n                                case QUEUED:\n                                    if (!isAllowedToDequeueOneToOneFileTransfer(contact,\n                                            mFileTransferService)) {\n                                        continue;\n                                    }\n                                    MmContent fileContent = FileTransferUtils.createMmContent(file,\n                                            mimeType, disposition);\n                                    MmContent fileIconContent = null;\n                                    String fileIcon = cursor.getString(fileIconIdx);\n                                    if (fileIcon != null) {\n                                        Uri fileIconUri = Uri.parse(fileIcon);\n                                        fileIconContent = FileTransferUtils\n                                                .createIconContent(fileIconUri);\n                                    }\n                                    mFileTransferService.dequeueOneToOneFileTransfer(id, contact,\n                                            fileContent, fileIconContent);\n                                    break;\n                                case STARTED:\n                                    if (!isPossibleToDequeueOneToOneChatMessage(contact)) {\n                                        setOneToOneFileTransferAsFailedDequeue(contact, id);\n                                        continue;\n                                    }\n                                    if (!isAllowedToDequeueOneToOneChatMessage(contact)) {\n                                        continue;\n                                    }\n                                    String fileInfo = FileTransferUtils\n                                            .createHttpFileTransferXml(mMessagingLog\n                                                    .getFileDownloadInfo(id));\n                                    OneToOneFileTransferImpl oneToOneFileTransfer = mFileTransferService\n                                            .getOrCreateOneToOneFileTransfer(id);\n                                    oneToOneChat.dequeueOneToOneFileInfo(id, fileInfo,\n                                            displayedReportEnabled, deliveryReportEnabled,\n                                            oneToOneFileTransfer);\n                                    break;\n                                default:\n                                    break;\n                            }\n                            break;\n                        default:\n                            break;\n                    }\n                } catch (SessionUnavailableException | FileAccessException | NetworkException e) {\n                    if (logActivated) {\n                        mLogger.debug(\"Failed to dequeue one-one entry with id '\" + id\n                                + \"' for contact '\" + contact + \"' due to: \" + e.getMessage());\n                    }\n\n                } catch (PayloadException e) {\n                    mLogger.error(\"Failed to dequeue one-one entry with id '\" + id\n                            + \"' for contact '\" + contact, e);\n                    setOneToOneChatEntryAsFailedDequeue(providerId, contact, id, mimeType);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally all the terminal and non-terminal cases should be handled above so\n                     * if we come here that means that there is a bug and so we output a stack trace\n                     * so the bug can then be properly tracked down and fixed. We also mark the\n                     * respective entry that failed to dequeue as FAILED.\n                     */\n                    mLogger.error(\"Failed to dequeue one-one entry with id '\" + id\n                            + \"' for contact '\" + contact + \"'!\", e);\n                    setOneToOneChatEntryAsFailedDequeue(providerId, contact, id, mimeType);\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally all the terminal and non-terminal cases should be handled above so if we\n             * come here that means that there is a bug and so we output a stack trace so the bug\n             * can then be properly tracked down and fixed. We also mark the respective entry that\n             * failed to dequeue as FAILED.\n             */\n            mLogger.error(\n                    \"Exception occurred while dequeueing one-to-one chat message and one-to-one file transfer with id '\"\n                            + id + \"' for contact '\" + contact + \"'!\", e);\n            if (id == null) {\n                return;\n            }\n            setOneToOneChatEntryAsFailedDequeue(providerId, contact, id, mimeType);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/history/QueryHelper.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.history;\n\nimport static com.gsma.rcs.provider.history.HistoryConstants.FULL_PROJECTION;\n\nimport android.database.sqlite.SQLiteQueryBuilder;\nimport android.text.TextUtils;\nimport android.util.SparseArray;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/* package private */class QueryHelper {\n\n    private final Map<String[], String> mUriQueryCache = new HashMap<>();\n\n    private final SparseArray<String> mSubQueries = new SparseArray<>();\n\n    /* package private */String generateSubQuery(int providerId, Map<String, String> columnMapper,\n            String tablename) {\n        StringBuilder query = null;\n        for (String providerField : FULL_PROJECTION) {\n            if (query == null) {\n                query = new StringBuilder(\"SELECT \");\n            } else {\n                query.append(\",\");\n            }\n            String databaseField = columnMapper.get(providerField);\n            if (HistoryLogData.KEY_PROVIDER_ID.equals(providerField)) {\n                databaseField = Integer.toString(providerId);\n            }\n            query.append(databaseField).append(\" AS \").append(providerField);\n        }\n        query.append(\" FROM \").append(tablename);\n        String subQuery = query.toString();\n        mSubQueries.put(providerId, subQuery);\n        return subQuery;\n    }\n\n    private StringBuilder generateParamlessSubQuery(int providerId, String selection) {\n        StringBuilder query = new StringBuilder(mSubQueries.get(providerId));\n        if (!TextUtils.isEmpty(selection)) {\n            query.append(\" WHERE \").append(selection);\n        }\n        return query;\n    }\n\n    private String generateParamlessUnionQuery(List<String> historyLogMembers, String selection) {\n        String subQueries[] = new String[historyLogMembers.size()];\n        int i = 0;\n        for (String historyLogMember : historyLogMembers) {\n            int providerId = Integer.valueOf(historyLogMember);\n            subQueries[i++] = generateParamlessSubQuery(providerId, selection).toString();\n        }\n        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();\n        return queryBuilder.buildUnionQuery(subQueries, null, null);\n    }\n\n    private String generateUnionQuery(List<String> historyLogMembers) {\n        String[] keyQueryCache = getKey(historyLogMembers);\n        String unionQuery = mUriQueryCache.get(keyQueryCache);\n        if (unionQuery != null) {\n            return unionQuery;\n        }\n        String subQueries[] = new String[historyLogMembers.size()];\n        int i = 0;\n        for (String historyLogMember : historyLogMembers) {\n            int providerId = Integer.valueOf(historyLogMember);\n            subQueries[i++] = mSubQueries.get(providerId);\n        }\n        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();\n        unionQuery = queryBuilder.buildUnionQuery(subQueries, null, null);\n        mUriQueryCache.put(keyQueryCache, unionQuery);\n        return unionQuery;\n    }\n\n    /**\n     * Will return a unique key for a specific set of strings\n     * \n     * @param providerIds the list of provider IDs\n     * @return the generated key\n     */\n    private static String[] getKey(List<String> providerIds) {\n        String[] key = new String[providerIds.size()];\n        providerIds.toArray(key);\n        Arrays.sort(key);\n        return key;\n    }\n\n    private static boolean contains(String[] key, int providerId) {\n        return Arrays.binarySearch(key, Integer.toString(providerId)) >= 0;\n    }\n\n    /**\n     * When no selection arguments are given there is no need to bind selection parameters. Since\n     * the history provider uses a union query with a surrounding selection clause the query can in\n     * such case be optimized so that the selection is done on the internal level, which is a major\n     * speed up in common use cases.\n     */\n    /* package private */String generateUnionQuery(List<String> historyLogMembers,\n            String[] selectionArgs, String selection) {\n        if (selectionArgs == null) {\n            return generateParamlessUnionQuery(historyLogMembers, selection);\n        }\n        return generateUnionQuery(historyLogMembers);\n    }\n\n    /* package private */void clearProvider(int providerId) {\n\n        synchronized (mUriQueryCache) {\n            for (String[] uriQueryCacheKey : mUriQueryCache.keySet()) {\n                if (contains(uriQueryCacheKey, providerId)) {\n                    mUriQueryCache.remove(uriQueryCacheKey);\n                }\n            }\n            mSubQueries.remove(providerId);\n        }\n\n    }\n\n    /* package private */void clear() {\n        mSubQueries.clear();\n        mUriQueryCache.clear();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/ChatMessagePersistedStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.database.Cursor;\n\n/**\n * ChatMessagePersistedStorageAccessor helps in retrieving persisted data related to a chat message\n * from the persisted storage. It can utilize caching for such data that will not be changed after\n * creation of the group chat to speed up consecutive access.\n */\npublic class ChatMessagePersistedStorageAccessor {\n\n    private final MessagingLog mMessagingLog;\n\n    private final String mId;\n\n    private ContactId mRemoteContact;\n\n    private String mContent;\n\n    private String mMimeType;\n\n    private String mChatId;\n\n    private Boolean mRead;\n\n    private Direction mDirection;\n\n    private Long mTimestampDelivered;\n\n    private Long mTimestampDisplayed;\n\n    /**\n     * Constructor for outgoing message\n     * \n     * @param messagingLog MessagingLog\n     * @param id Message Id\n     */\n    public ChatMessagePersistedStorageAccessor(MessagingLog messagingLog, String id) {\n        mMessagingLog = messagingLog;\n        mId = id;\n    }\n\n    /**\n     * Constructor for outgoing message\n     * \n     * @param messagingLog MessagingLog\n     * @param id Message Id\n     * @param remoteContact Contact Id\n     * @param content Message content\n     * @param mimeType Mime type\n     * @param chatId Chat ID\n     * @param direction Direction\n     */\n    public ChatMessagePersistedStorageAccessor(MessagingLog messagingLog, String id,\n            ContactId remoteContact, String content, String mimeType, String chatId,\n            Direction direction) {\n        mMessagingLog = messagingLog;\n        mId = id;\n        mRemoteContact = remoteContact;\n        mContent = content;\n        mChatId = chatId;\n        mMimeType = mimeType;\n        mDirection = direction;\n    }\n\n    private void cacheData() {\n        Cursor cursor = null;\n        try {\n            cursor = mMessagingLog.getChatMessageData(mId);\n            if (!cursor.moveToNext()) {\n                throw new ServerApiPersistentStorageException(\"Data not found for message \" + mId);\n            }\n            String contact = cursor\n                    .getString(cursor.getColumnIndexOrThrow(MessageData.KEY_CONTACT));\n            if (contact != null) {\n                /* Do not check validity for trusted data */\n                mRemoteContact = ContactUtil.createContactIdFromTrustedData(contact);\n            }\n            mDirection = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(MessageData.KEY_DIRECTION)));\n            mContent = cursor.getString(cursor.getColumnIndexOrThrow(MessageData.KEY_CONTENT));\n            mChatId = cursor.getString(cursor.getColumnIndexOrThrow(MessageData.KEY_CHAT_ID));\n            mMimeType = cursor.getString(cursor.getColumnIndexOrThrow(MessageData.KEY_MIME_TYPE));\n            if (!Boolean.TRUE.equals(mRead)) {\n                mRead = ReadStatus.READ.toInt() == cursor.getInt(cursor\n                        .getColumnIndexOrThrow(MessageData.KEY_READ_STATUS));\n            }\n            if (mTimestampDelivered == null || mTimestampDelivered == 0) {\n                mTimestampDelivered = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(MessageData.KEY_TIMESTAMP_DELIVERED));\n            }\n            if (mTimestampDisplayed == null || mTimestampDisplayed == 0) {\n                mTimestampDisplayed = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(MessageData.KEY_TIMESTAMP_DISPLAYED));\n            }\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    public String getId() {\n        return mId;\n    }\n\n    public ContactId getRemoteContact() {\n        if (mRemoteContact == null) {\n            cacheData();\n        }\n        return mRemoteContact;\n    }\n\n    public String getContent() {\n        if (mContent == null) {\n            cacheData();\n        }\n        return mContent;\n    }\n\n    public String getMimeType() {\n        if (mMimeType == null) {\n            cacheData();\n        }\n        return mMimeType;\n    }\n\n    public Direction getDirection() {\n        if (mDirection == null) {\n            cacheData();\n        }\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        Long timestamp = mMessagingLog.getMessageTimestamp(mId);\n        if (timestamp == null) {\n            throw new ServerApiPersistentStorageException(\"Timestamp not found for message \" + mId);\n        }\n        return timestamp;\n    }\n\n    public long getTimestampSent() {\n        Long timestamp = mMessagingLog.getMessageSentTimestamp(mId);\n        if (timestamp == null) {\n            throw new ServerApiPersistentStorageException(\"TimestampSent not found for message \"\n                    + mId);\n        }\n        return timestamp;\n    }\n\n    public long getTimestampDelivered() {\n        /*\n         * Utilizing cache here as Timestamp delivered can't be changed in persistent storage after\n         * it has been set to some value bigger than zero, so no need to query for it multiple\n         * times.\n         */\n        if (mTimestampDelivered == null || mTimestampDelivered == 0) {\n            cacheData();\n        }\n        return mTimestampDelivered;\n    }\n\n    public long getTimestampDisplayed() {\n        /*\n         * Utilizing cache here as Timestamp displayed can't be changed in persistent storage after\n         * it has been set to some value bigger than zero, so no need to query for it multiple\n         * times.\n         */\n        if (mTimestampDisplayed == null || mTimestampDisplayed == 0) {\n            cacheData();\n        }\n        return mTimestampDisplayed;\n    }\n\n    public Status getStatus() {\n        Status status = mMessagingLog.getMessageStatus(mId);\n        if (status == null) {\n            throw new ServerApiPersistentStorageException(\"Status not found for message \" + mId);\n        }\n        return status;\n    }\n\n    public ReasonCode getReasonCode() {\n        ReasonCode reasonCode = mMessagingLog.getMessageReasonCode(mId);\n        if (reasonCode == null) {\n            throw new ServerApiPersistentStorageException(\"Reason code not found for message \"\n                    + mId);\n        }\n        return reasonCode;\n    }\n\n    public String getChatId() {\n        if (mChatId == null) {\n            cacheData();\n        }\n        return mChatId;\n    }\n\n    public boolean isRead() {\n        /*\n         * No need to read from provider unless incoming and not already marked as read.\n         */\n        if (Direction.INCOMING == getDirection() && !Boolean.TRUE.equals(mRead)) {\n            cacheData();\n        }\n        return mRead;\n    }\n\n    public boolean isExpiredDelivery() {\n        Boolean expiredDelivery = mMessagingLog.isChatMessageExpiredDelivery(mId);\n        if (expiredDelivery == null) {\n            throw new ServerApiPersistentStorageException(\"Expired Delivery not found for message \"\n                    + mId);\n        }\n        return expiredDelivery;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/ChatProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.history.HistoryMemberBaseIdCreator;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.services.rcs.chat.ChatLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Chat provider\n * \n * @author Jean-Marc AUFFRET\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class ChatProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String SELECTION_WITH_CHAT_ID_ONLY = GroupChatData.KEY_CHAT_ID\n            .concat(\"=?\");\n\n    private static final String SELECTION_WITH_MSG_ID_ONLY = MessageData.KEY_MESSAGE_ID\n            .concat(\"=?\");\n\n    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n    static {\n        sUriMatcher.addURI(GroupChatData.CONTENT_URI.getAuthority(), GroupChatData.CONTENT_URI\n                .getPath().substring(1), UriType.InternalChat.CHAT);\n        sUriMatcher.addURI(GroupChatData.CONTENT_URI.getAuthority(), GroupChatData.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.InternalChat.CHAT_WITH_ID);\n        sUriMatcher.addURI(ChatLog.GroupChat.CONTENT_URI.getAuthority(),\n                ChatLog.GroupChat.CONTENT_URI.getPath().substring(1), UriType.Chat.CHAT);\n        sUriMatcher.addURI(ChatLog.GroupChat.CONTENT_URI.getAuthority(),\n                ChatLog.GroupChat.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.Chat.CHAT_WITH_ID);\n        sUriMatcher.addURI(MessageData.CONTENT_URI.getAuthority(), MessageData.CONTENT_URI\n                .getPath().substring(1), UriType.InternalMessage.MESSAGE);\n        sUriMatcher.addURI(MessageData.CONTENT_URI.getAuthority(), MessageData.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.InternalMessage.MESSAGE_WITH_ID);\n        sUriMatcher.addURI(ChatLog.Message.CONTENT_URI.getAuthority(), ChatLog.Message.CONTENT_URI\n                .getPath().substring(1), UriType.Message.MESSAGE);\n        sUriMatcher.addURI(ChatLog.Message.CONTENT_URI.getAuthority(), ChatLog.Message.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.Message.MESSAGE_WITH_ID);\n\n    }\n\n    /**\n     * Messages table name\n     */\n    public static final String TABLE_MESSAGE = \"message\";\n\n    /**\n     * Group chats table name\n     */\n    public static final String TABLE_GROUP_CHAT = \"groupchat\";\n\n    /**\n     * Database name\n     */\n    public static final String DATABASE_NAME = \"chat.db\";\n\n    /**\n     * String to allow projection for exposed group chat URI to a set of columns.\n     */\n    private static final String[] GROUP_CHAT_COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS = new String[] {\n            GroupChatData.KEY_BASECOLUMN_ID, GroupChatData.KEY_CHAT_ID, GroupChatData.KEY_CONTACT,\n            GroupChatData.KEY_STATE, GroupChatData.KEY_SUBJECT, GroupChatData.KEY_DIRECTION,\n            GroupChatData.KEY_TIMESTAMP, GroupChatData.KEY_REASON_CODE,\n            GroupChatData.KEY_PARTICIPANTS\n    };\n\n    private static final Set<String> GROUP_CHAT_COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS = new HashSet<>(\n            Arrays.asList(GROUP_CHAT_COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS));\n\n    /**\n     * String to allow projection for exposed message URI to a set of columns.\n     */\n    private static final String[] MESSAGE_COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS = new String[] {\n            MessageData.KEY_BASECOLUMN_ID, MessageData.KEY_CHAT_ID, MessageData.KEY_CONTACT,\n            MessageData.KEY_CONTENT, MessageData.KEY_DIRECTION, MessageData.KEY_EXPIRED_DELIVERY,\n            MessageData.KEY_MESSAGE_ID, MessageData.KEY_MIME_TYPE, MessageData.KEY_READ_STATUS,\n            MessageData.KEY_REASON_CODE, MessageData.KEY_STATUS, MessageData.KEY_TIMESTAMP,\n            MessageData.KEY_TIMESTAMP_DELIVERED, MessageData.KEY_TIMESTAMP_DISPLAYED,\n            MessageData.KEY_TIMESTAMP_SENT\n    };\n\n    private static final Set<String> MESSAGE_COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS = new HashSet<>(\n            Arrays.asList(MESSAGE_COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS));\n\n    private static final class UriType {\n\n        private static final class Chat {\n\n            private static final int CHAT = 1;\n\n            private static final int CHAT_WITH_ID = 2;\n        }\n\n        private static final class Message {\n\n            private static final int MESSAGE = 3;\n\n            private static final int MESSAGE_WITH_ID = 4;\n        }\n\n        private static final class InternalChat {\n\n            private static final int CHAT = 5;\n\n            private static final int CHAT_WITH_ID = 6;\n        }\n\n        private static final class InternalMessage {\n\n            private static final int MESSAGE = 7;\n\n            private static final int MESSAGE_WITH_ID = 8;\n        }\n\n    }\n\n    private static final class CursorType {\n\n        private static final class Chat {\n\n            private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/groupchat\";\n\n            private static final String TYPE_ITEM = \"vnd.android.cursor.item/groupchat\";\n        }\n\n        private static final class Message {\n\n            private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/chatmessage\";\n\n            private static final String TYPE_ITEM = \"vnd.android.cursor.item/chatmessage\";\n        }\n    }\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 17;\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE_GROUP_CHAT + '('\n                    + GroupChatData.KEY_CHAT_ID + \" TEXT NOT NULL PRIMARY KEY,\"\n                    + GroupChatData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + GroupChatData.KEY_REJOIN_ID + \" TEXT,\"\n                    + GroupChatData.KEY_SUBJECT + \" TEXT,\"\n                    + GroupChatData.KEY_PARTICIPANTS + \" TEXT NOT NULL,\"\n                    + GroupChatData.KEY_STATE + \" INTEGER NOT NULL,\"\n                    + GroupChatData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + GroupChatData.KEY_DIRECTION + \" INTEGER NOT NULL,\"\n                    + GroupChatData.KEY_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + GroupChatData.KEY_USER_ABORTION + \" INTEGER NOT NULL,\"\n                    + GroupChatData.KEY_CONTACT + \" TEXT)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + TABLE_GROUP_CHAT + '_' + GroupChatData.KEY_BASECOLUMN_ID\n                    + \"_idx\" + \" ON \" + TABLE_GROUP_CHAT + '(' + GroupChatData.KEY_BASECOLUMN_ID\n                    + ')');\n            db.execSQL(\"CREATE INDEX \" + TABLE_GROUP_CHAT + '_' + GroupChatData.KEY_TIMESTAMP\n                    + \"_idx\" + \" ON \" + TABLE_GROUP_CHAT + '(' + GroupChatData.KEY_TIMESTAMP + ')');\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE_MESSAGE + '('\n                    + MessageData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_CHAT_ID + \" TEXT NOT NULL,\"\n                    + MessageData.KEY_CONTACT + \" TEXT,\"\n                    + MessageData.KEY_MESSAGE_ID + \" TEXT NOT NULL PRIMARY KEY,\"\n                    + MessageData.KEY_CONTENT + \" TEXT,\"\n                    + MessageData.KEY_MIME_TYPE + \" TEXT NOT NULL,\"\n                    + MessageData.KEY_DIRECTION + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_STATUS + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_READ_STATUS + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_TIMESTAMP_SENT + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_TIMESTAMP_DELIVERED + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_TIMESTAMP_DISPLAYED + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_DELIVERY_EXPIRATION + \" INTEGER NOT NULL,\"\n                    + MessageData.KEY_EXPIRED_DELIVERY + \" INTEGER NOT NULL)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + TABLE_MESSAGE + '_' + MessageData.KEY_BASECOLUMN_ID\n                    + \"_idx\" + \" ON \" + TABLE_MESSAGE + '(' + MessageData.KEY_BASECOLUMN_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + TABLE_MESSAGE + '_' + MessageData.KEY_CHAT_ID + \"_idx\"\n                    + \" ON \" + TABLE_MESSAGE + '(' + MessageData.KEY_CHAT_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + MessageData.KEY_TIMESTAMP + \"_idx\" + \" ON \"\n                    + TABLE_MESSAGE + '(' + MessageData.KEY_TIMESTAMP + ')');\n            db.execSQL(\"CREATE INDEX \" + MessageData.KEY_TIMESTAMP_SENT + \"_idx\" + \" ON \"\n                    + TABLE_MESSAGE + '(' + MessageData.KEY_TIMESTAMP_SENT + ')');\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE_GROUP_CHAT));\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE_MESSAGE));\n            onCreate(db);\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithChatId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_CHAT_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_CHAT_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithChatId(String[] selectionArgs, String chatId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(chatId, selectionArgs);\n    }\n\n    private String getSelectionWithMessageId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_MSG_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_MSG_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithMessageId(String[] selectionArgs, String messageId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(messageId, selectionArgs);\n    }\n\n    private String[] restrictGroupChatProjectionToExternallyDefinedColumns(String[] projection)\n            throws UnsupportedOperationException {\n        if (projection == null || projection.length == 0) {\n            return GROUP_CHAT_COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS;\n        }\n        for (String projectedColumn : projection) {\n            if (!GROUP_CHAT_COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS.contains(projectedColumn)) {\n                throw new UnsupportedOperationException(\"No visibility to the accessed column \"\n                        + projectedColumn + \"!\");\n            }\n        }\n        return projection;\n    }\n\n    private String[] restrictMessageProjectionToExternallyDefinedColumns(String[] projection)\n            throws UnsupportedOperationException {\n        if (projection == null || projection.length == 0) {\n            return MESSAGE_COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS;\n        }\n        for (String projectedColumn : projection) {\n            if (!MESSAGE_COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS.contains(projectedColumn)) {\n                throw new UnsupportedOperationException(\"No visibility to the accessed column \"\n                        + projectedColumn + \"!\");\n            }\n        }\n        return projection;\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalChat.CHAT:\n                /* Intentional fall through */\n            case UriType.Chat.CHAT:\n                return CursorType.Chat.TYPE_DIRECTORY;\n\n            case UriType.InternalChat.CHAT_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Chat.CHAT_WITH_ID:\n                return CursorType.Chat.TYPE_ITEM;\n\n            case UriType.InternalMessage.MESSAGE:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE:\n                return CursorType.Message.TYPE_DIRECTORY;\n\n            case UriType.InternalMessage.MESSAGE_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE_WITH_ID:\n                return CursorType.Message.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalChat.CHAT_WITH_ID:\n                    String chatId = uri.getLastPathSegment();\n                    selection = getSelectionWithChatId(selection);\n                    selectionArgs = getSelectionArgsWithChatId(selectionArgs, chatId);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE_GROUP_CHAT, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(ChatLog.GroupChat.CONTENT_URI, chatId));\n                    return cursor;\n\n                case UriType.InternalChat.CHAT:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE_GROUP_CHAT, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            ChatLog.GroupChat.CONTENT_URI);\n                    return cursor;\n\n                case UriType.Chat.CHAT_WITH_ID:\n                    chatId = uri.getLastPathSegment();\n                    selection = getSelectionWithChatId(selection);\n                    selectionArgs = getSelectionArgsWithChatId(selectionArgs, chatId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.Chat.CHAT:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE_GROUP_CHAT,\n                            restrictGroupChatProjectionToExternallyDefinedColumns(projection),\n                            selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                case UriType.InternalMessage.MESSAGE_WITH_ID:\n                    String msgId = uri.getLastPathSegment();\n                    selection = getSelectionWithMessageId(selection);\n                    selectionArgs = getSelectionArgsWithMessageId(selectionArgs, msgId);\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE_MESSAGE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, msgId));\n                    return cursor;\n\n                case UriType.InternalMessage.MESSAGE:\n                    /* Intentional fall through */\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE_MESSAGE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            ChatLog.Message.CONTENT_URI);\n                    return cursor;\n\n                case UriType.Message.MESSAGE_WITH_ID:\n                    msgId = uri.getLastPathSegment();\n                    selection = getSelectionWithMessageId(selection);\n                    selectionArgs = getSelectionArgsWithMessageId(selectionArgs, msgId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.Message.MESSAGE:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE_MESSAGE,\n                            restrictMessageProjectionToExternallyDefinedColumns(projection),\n                            selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n\n        } /*\n           * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n           * exception.\n           */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalChat.CHAT_WITH_ID:\n                String chatId = uri.getLastPathSegment();\n                selection = getSelectionWithChatId(selection);\n                selectionArgs = getSelectionArgsWithChatId(selectionArgs, chatId);\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(TABLE_GROUP_CHAT, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(\n                            Uri.withAppendedPath(ChatLog.GroupChat.CONTENT_URI, chatId), null);\n                }\n                return count;\n\n            case UriType.InternalChat.CHAT:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.update(TABLE_GROUP_CHAT, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(ChatLog.GroupChat.CONTENT_URI,\n                            null);\n                }\n                return count;\n\n            case UriType.InternalMessage.MESSAGE_WITH_ID:\n                String msgId = uri.getLastPathSegment();\n                selection = getSelectionWithMessageId(selection);\n                selectionArgs = getSelectionArgsWithMessageId(selectionArgs, msgId);\n                db = mOpenHelper.getWritableDatabase();\n                count = db.update(TABLE_MESSAGE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(\n                            Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, msgId), null);\n                }\n                return count;\n\n            case UriType.InternalMessage.MESSAGE:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.update(TABLE_MESSAGE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(ChatLog.Message.CONTENT_URI,\n                            null);\n                }\n                return count;\n\n            case UriType.Chat.CHAT_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Chat.CHAT:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalChat.CHAT:\n                /* Intentional fall through */\n            case UriType.InternalChat.CHAT_WITH_ID:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String chatId = initialValues.getAsString(GroupChatData.KEY_CHAT_ID);\n                initialValues.put(GroupChatData.KEY_BASECOLUMN_ID, HistoryMemberBaseIdCreator\n                        .createUniqueId(getContext(), ChatLog.GroupChat.HISTORYLOG_MEMBER_ID));\n\n                if (db.insert(TABLE_GROUP_CHAT, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri + '!');\n                }\n                Uri notificationUri = Uri.withAppendedPath(ChatLog.GroupChat.CONTENT_URI, chatId);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.InternalMessage.MESSAGE:\n                /* Intentional fall through */\n            case UriType.InternalMessage.MESSAGE_WITH_ID:\n                db = mOpenHelper.getWritableDatabase();\n                String messageId = initialValues.getAsString(MessageData.KEY_MESSAGE_ID);\n                initialValues.put(MessageData.KEY_BASECOLUMN_ID, HistoryMemberBaseIdCreator\n                        .createUniqueId(getContext(), MessageData.HISTORYLOG_MEMBER_ID));\n\n                if (db.insert(TABLE_MESSAGE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri + '!');\n                }\n                notificationUri = Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, messageId);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.Chat.CHAT:\n                /* Intentional fall through */\n            case UriType.Chat.CHAT_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE_WITH_ID:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalChat.CHAT_WITH_ID:\n                String chatId = uri.getLastPathSegment();\n                selection = getSelectionWithChatId(selection);\n                selectionArgs = getSelectionArgsWithChatId(selectionArgs, chatId);\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(TABLE_GROUP_CHAT, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(\n                            Uri.withAppendedPath(ChatLog.GroupChat.CONTENT_URI, chatId), null);\n                }\n                return count;\n\n            case UriType.InternalChat.CHAT:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.delete(TABLE_GROUP_CHAT, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(ChatLog.GroupChat.CONTENT_URI,\n                            null);\n                }\n                return count;\n\n            case UriType.InternalMessage.MESSAGE_WITH_ID:\n                String msgId = uri.getLastPathSegment();\n                selection = getSelectionWithMessageId(selection);\n                selectionArgs = getSelectionArgsWithMessageId(selectionArgs, msgId);\n                db = mOpenHelper.getWritableDatabase();\n                count = db.delete(TABLE_MESSAGE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(\n                            Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, msgId), null);\n                }\n                return count;\n\n            case UriType.InternalMessage.MESSAGE:\n                db = mOpenHelper.getWritableDatabase();\n                count = db.delete(TABLE_MESSAGE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(ChatLog.Message.CONTENT_URI,\n                            null);\n                }\n                return count;\n\n            case UriType.Chat.CHAT_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Chat.CHAT:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE_WITH_ID:\n                /* Intentional fall through */\n            case UriType.Message.MESSAGE:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/DelayedDisplayNotificationDispatcher.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.database.Cursor;\n\n/**\n * Delayed Display Notification Dispatcher retrieves those text messages for which requested display\n * reports have not yet been successfully sent.\n */\npublic class DelayedDisplayNotificationDispatcher implements Runnable {\n\n    private static final Logger sLogger = Logger\n            .getLogger(DelayedDisplayNotificationDispatcher.class.getName());\n\n    private static final String[] PROJECTION_CHAT_MESSAGE = new String[] {\n            MessageData.KEY_MESSAGE_ID, MessageData.KEY_CHAT_ID, MessageData.KEY_CONTACT,\n            MessageData.KEY_TIMESTAMP_DISPLAYED\n    };\n\n    private final static String SELECTION_READ_CHAT_MESSAGES_WITH_DISPLAY_REPORT_REQUESTED = MessageData.KEY_MIME_TYPE\n            + \" IN('\"\n            + MimeType.TEXT_MESSAGE\n            + \"','\"\n            + MimeType.GEOLOC_MESSAGE\n            + \"') AND \"\n            + MessageData.KEY_READ_STATUS\n            + \"=\"\n            + ReadStatus.READ.toInt()\n            + \" AND \"\n            + MessageData.KEY_STATUS + \"=\" + Status.DISPLAY_REPORT_REQUESTED.toInt();\n\n    private static final String ORDER_BY_TIMESTAMP_ASC = MessageData.KEY_TIMESTAMP.concat(\" ASC\");\n\n    private LocalContentResolver mLocalContentResolver;\n\n    private ChatServiceImpl mChatApi;\n\n    public DelayedDisplayNotificationDispatcher(LocalContentResolver localContentResolver,\n            ChatServiceImpl chatApi) {\n        mLocalContentResolver = localContentResolver;\n        mChatApi = chatApi;\n    }\n\n    @Override\n    public void run() {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(MessageData.CONTENT_URI, PROJECTION_CHAT_MESSAGE,\n                    SELECTION_READ_CHAT_MESSAGES_WITH_DISPLAY_REPORT_REQUESTED, null,\n                    ORDER_BY_TIMESTAMP_ASC);\n            CursorUtil.assertCursorIsNotNull(cursor, MessageData.CONTENT_URI);\n            int columIdxMessageId = cursor.getColumnIndexOrThrow(MessageData.KEY_MESSAGE_ID);\n            int columnIdxContact = cursor.getColumnIndexOrThrow(MessageData.KEY_CONTACT);\n            int columnIdxTimestampDisplayed = cursor\n                    .getColumnIndexOrThrow(MessageData.KEY_TIMESTAMP_DISPLAYED);\n            int columnIdxChatId = cursor.getColumnIndexOrThrow(MessageData.KEY_CHAT_ID);\n            while (cursor.moveToNext()) {\n                String contactNumber = cursor.getString(columnIdxContact);\n                String chatId = cursor.getString(columnIdxChatId);\n                String msgId = cursor.getString(columIdxMessageId);\n                long timestampDisplayed = cursor.getLong(columnIdxTimestampDisplayed);\n                /* Do no check validity for trusted data */\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(contactNumber);\n\n                if (chatId.equals(contactNumber)) {\n                    mChatApi.sendOne2OneDisplayedDeliveryReport(msgId, contact, timestampDisplayed);\n                } else {\n                    mChatApi.sendGroupChatDisplayedDeliveryReport(msgId, contact,\n                            timestampDisplayed, chatId);\n                }\n            }\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\"Failed to dispatch display notifications!\", e);\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/FileTransferData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.net.Uri;\n\n/**\n * File transfer data constants\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileTransferData {\n\n    /**\n     * Database URI\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.filetransfer/filetransfer\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = FileTransferLog.HISTORYLOG_MEMBER_ID;\n\n    /**\n     * Unique history log id\n     */\n    /* package private */static final String KEY_BASECOLUMN_ID = FileTransferLog.BASECOLUMN_ID;\n\n    /**\n     * Unique file transfer identifier\n     */\n    /* package private */static final String KEY_FT_ID = FileTransferLog.FT_ID;\n\n    /**\n     * Id of chat\n     */\n    /* package private */static final String KEY_CHAT_ID = FileTransferLog.CHAT_ID;\n\n    /**\n     * Date of the transfer\n     */\n    /* package private */static final String KEY_TIMESTAMP = FileTransferLog.TIMESTAMP;\n\n    /**\n     * Time when file is sent. If 0 means not sent.\n     */\n    /* package private */static final String KEY_TIMESTAMP_SENT = FileTransferLog.TIMESTAMP_SENT;\n\n    /**\n     * Time when file is delivered. If 0 means not delivered.\n     */\n    /* package private */static final String KEY_TIMESTAMP_DELIVERED = FileTransferLog.TIMESTAMP_DELIVERED;\n\n    /**\n     * Time when file is displayed.\n     */\n    /* package private */static final String KEY_TIMESTAMP_DISPLAYED = FileTransferLog.TIMESTAMP_DISPLAYED;\n\n    /**\n     * If delivery has expired for this file. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_EXPIRED_DELIVERY = FileTransferLog.EXPIRED_DELIVERY;\n\n    /**\n     * ContactId formatted number of remote contact or null if the filetransfer is an outgoing group\n     * file transfer.\n     */\n    /* package private */static final String KEY_CONTACT = FileTransferLog.CONTACT;\n\n    /**\n     * @see FileTransfer.State for possible states.\n     */\n    /* package private */static final String KEY_STATE = FileTransferLog.STATE;\n\n    /**\n     * Reason code associated with the file transfer state.\n     * \n     * @see FileTransfer.ReasonCode for possible reason codes.\n     */\n    /* package private */static final String KEY_REASON_CODE = FileTransferLog.REASON_CODE;\n\n    /**\n     * @see ReadStatus\n     */\n    /* package private */static final String KEY_READ_STATUS = FileTransferLog.READ_STATUS;\n\n    /**\n     * Multipurpose Internet Mail Extensions (MIME) type of message\n     */\n    /* package private */static final String KEY_MIME_TYPE = FileTransferLog.MIME_TYPE;\n\n    /**\n     * URI of the file\n     */\n    /* package private */static final String KEY_FILE = FileTransferLog.FILE;\n\n    /**\n     * Filename\n     */\n    /* package private */static final String KEY_FILENAME = FileTransferLog.FILENAME;\n\n    /**\n     * Size transferred in bytes\n     */\n    /* package private */static final String KEY_TRANSFERRED = FileTransferLog.TRANSFERRED;\n\n    /**\n     * File size in bytes\n     */\n    /* package private */static final String KEY_FILESIZE = FileTransferLog.FILESIZE;\n\n    /**\n     * File transfer disposition\n     *\n     * @see Disposition\n     */\n    /* package private */static final String KEY_DISPOSITION = FileTransferLog.DISPOSITION;\n\n    /**\n     * Incoming transfer or outgoing transfer\n     * \n     * @see Direction\n     */\n    /* package private */static final String KEY_DIRECTION = FileTransferLog.DIRECTION;\n\n    /**\n     * Column name KEY_FILEICON : the URI of the file icon\n     */\n    /* package private */static final String KEY_FILEICON = FileTransferLog.FILEICON;\n\n    /**\n     * URI of the file icon\n     */\n    /* package private */static final String KEY_FILEICON_MIME_TYPE = FileTransferLog.FILEICON_MIME_TYPE;\n\n    /**\n     * The time for when file on the content server is no longer valid to download.\n     */\n    /* package private */static final String KEY_FILE_EXPIRATION = FileTransferLog.FILE_EXPIRATION;\n\n    /**\n     * The time for when file icon on the content server is no longer valid to download.\n     */\n    /* package private */static final String KEY_FILEICON_EXPIRATION = FileTransferLog.FILEICON_EXPIRATION;\n\n    /**\n     * The upload transaction ID (hidden field from client applications)\n     */\n    /* package private */static final String KEY_UPLOAD_TID = \"upload_tid\";\n\n    /**\n     * The download server address (hidden field from client applications)\n     */\n    /* package private */static final String KEY_DOWNLOAD_URI = \"download_uri\";\n\n    /**\n     * The remote SIP instance ID to fill the accept contact header of the SIP delivery notification\n     * (hidden field from client applications).<br>\n     * Only application for incoming HTTP file transfers.\n     */\n    /* package private */static final String KEY_REMOTE_SIP_ID = \"remote_sip_id\";\n\n    /**\n     * Time when file delivery time out will expire or 0 if this file is not eligible for delivery\n     * expiration (hidden field from client applications).\n     */\n    /* package private */static final String KEY_DELIVERY_EXPIRATION = \"delivery_expiration\";\n\n    /**\n     * The download server address for fileicon (hidden field from client applications)\n     */\n    /* package private */static final String KEY_FILEICON_DOWNLOAD_URI = \"fileicon_download_uri\";\n\n    /**\n     * The fileicon size (hidden field from client applications)\n     */\n    /* package private */static final String KEY_FILEICON_SIZE = \"fileicon_size\";\n\n    /**\n     * @see FileTransferLog#UNKNOWN_EXPIRATION\n     */\n    public static final long UNKNOWN_EXPIRATION = FileTransferLog.UNKNOWN_EXPIRATION;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/FileTransferDequeueTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.SessionNotEstablishedException;\nimport com.gsma.rcs.core.ims.service.im.chat.SessionUnavailableException;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.DequeueTask;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.GroupChatImpl;\nimport com.gsma.rcs.service.api.GroupFileTransferImpl;\nimport com.gsma.rcs.service.api.OneToOneChatImpl;\nimport com.gsma.rcs.service.api.OneToOneFileTransferImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * FileTransferDequeueTask tries to dequeue all one-to-one and group file transfers that are either\n * QUEUED or UPLOADED but not transferred\n */\npublic class FileTransferDequeueTask extends DequeueTask {\n\n    public FileTransferDequeueTask(Context ctx, Core core, MessagingLog messagingLog,\n            ChatServiceImpl chatService, FileTransferServiceImpl fileTransferService,\n            ContactManager contactManager, RcsSettings rcsSettings) {\n        super(ctx, core, contactManager, messagingLog, rcsSettings, chatService,\n                fileTransferService);\n    }\n\n    private void setGroupFileTransferAsFailedDequeue(String id, boolean groupFile,\n            ContactId contact, String chatId) {\n        if (groupFile) {\n            setGroupFileTransferAsFailedDequeue(chatId, id);\n        } else {\n            setOneToOneFileTransferAsFailedDequeue(contact, id);\n        }\n    }\n\n    public void run() {\n        boolean logActivated = mLogger.isActivated();\n        if (logActivated) {\n            mLogger.debug(\"Execute task to dequeue one-to-one and group file transfers\");\n        }\n        String id = null;\n        ContactId contact = null;\n        String chatId = null;\n        boolean groupFile = false;\n        Cursor cursor = null;\n        ImdnManager imdnManager = mImService.getImdnManager();\n        boolean displayedReportEnabled = imdnManager\n                .isRequestGroupDeliveryDisplayedReportsEnabled();\n        boolean deliveryReportEnabled = imdnManager.isDeliveryDeliveredReportsEnabled();\n        try {\n            if (!isImsConnected()) {\n                if (logActivated) {\n                    mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue one-to-one and group file transfers\");\n                }\n                return;\n            }\n            if (isShuttingDownOrStopped()) {\n                if (logActivated) {\n                    mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue one-to-one and group file transfers\");\n                }\n                return;\n            }\n            cursor = mMessagingLog.getQueuedAndUploadedButNotTransferredFileTransfers();\n            int fileTransferIdIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FT_ID);\n            int fileIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILE);\n            int fileIconIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILEICON);\n            int contactIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_CONTACT);\n            int chatIdIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_CHAT_ID);\n            int stateIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_STATE);\n            int fileSizeIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILESIZE);\n            int dispositionIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_DISPOSITION);\n            int mimeIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_MIME_TYPE);\n            while (cursor.moveToNext()) {\n                try {\n                    if (!isImsConnected()) {\n                        if (logActivated) {\n                            mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue one-to-one and group file transfers\");\n                        }\n                        return;\n                    }\n                    if (isShuttingDownOrStopped()) {\n                        if (logActivated) {\n                            mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue one-to-one and group file transfers\");\n                        }\n                        return;\n                    }\n                    id = cursor.getString(fileTransferIdIdx);\n                    String contactNumber = cursor.getString(contactIdx);\n                    contact = contactNumber != null ? ContactUtil\n                            .createContactIdFromTrustedData(contactNumber) : null;\n                    chatId = cursor.getString(chatIdIdx);\n                    Disposition disposition = Disposition.valueOf(cursor.getInt(dispositionIdx));\n                    String mimeType = cursor.getString(mimeIdx);\n                    groupFile = !chatId.equals(contactNumber);\n                    State state = State.valueOf(cursor.getInt(stateIdx));\n                    Uri file = Uri.parse(cursor.getString(fileIdx));\n                    long size = cursor.getLong(fileSizeIdx);\n                    if (groupFile) {\n                        if (!isPossibleToDequeueGroupFileTransfer(chatId, file, size)) {\n                            setGroupFileTransferAsFailedDequeue(chatId, id);\n                            continue;\n                        }\n                    } else {\n                        if (!isPossibleToDequeueOneToOneFileTransfer(contact, file, size)) {\n                            setOneToOneFileTransferAsFailedDequeue(contact, id);\n                            continue;\n                        }\n                    }\n                    switch (state) {\n                        case QUEUED:\n                            if (groupFile) {\n                                if (!isAllowedToDequeueGroupFileTransfer()) {\n                                    continue;\n                                }\n                            } else {\n                                if (!isAllowedToDequeueOneToOneFileTransfer(contact,\n                                        mFileTransferService)) {\n                                    continue;\n                                }\n                            }\n                            MmContent content = FileTransferUtils.createMmContent(file, mimeType,\n                                    disposition);\n                            MmContent fileIconContent = null;\n                            String fileIcon = cursor.getString(fileIconIdx);\n                            if (fileIcon != null) {\n                                Uri fileIconUri = Uri.parse(fileIcon);\n                                fileIconContent = FileTransferUtils.createIconContent(fileIconUri);\n                            }\n                            if (groupFile) {\n                                mFileTransferService.dequeueGroupFileTransfer(chatId, id, content,\n                                        fileIconContent);\n                            } else {\n                                mFileTransferService.dequeueOneToOneFileTransfer(id, contact,\n                                        content, fileIconContent);\n                            }\n                            break;\n\n                        case STARTED:\n                            if (groupFile) {\n                                if (!isPossibleToDequeueGroupChatMessagesAndGroupFileTransfers(chatId)) {\n                                    setGroupFileTransferAsFailedDequeue(chatId, id);\n                                    continue;\n                                }\n                            } else {\n                                if (!isPossibleToDequeueOneToOneChatMessage(contact)) {\n                                    setOneToOneFileTransferAsFailedDequeue(contact, id);\n                                    continue;\n                                }\n                                if (!isAllowedToDequeueOneToOneChatMessage(contact)) {\n                                    continue;\n                                }\n                            }\n                            String fileInfo = FileTransferUtils\n                                    .createHttpFileTransferXml(mMessagingLog\n                                            .getFileDownloadInfo(cursor));\n                            if (groupFile) {\n                                GroupChatImpl groupChat = mChatService.getOrCreateGroupChat(chatId);\n                                GroupFileTransferImpl groupFileTransfer = mFileTransferService\n                                        .getOrCreateGroupFileTransfer(chatId, id);\n                                groupChat.dequeueGroupFileInfo(id, fileInfo,\n                                        displayedReportEnabled, deliveryReportEnabled,\n                                        groupFileTransfer);\n                            } else {\n                                OneToOneChatImpl oneToOneChat = mChatService\n                                        .getOrCreateOneToOneChat(contact);\n                                OneToOneFileTransferImpl oneToOneFileTransfer = mFileTransferService\n                                        .getOrCreateOneToOneFileTransfer(id);\n                                oneToOneChat.dequeueOneToOneFileInfo(id, fileInfo,\n                                        displayedReportEnabled, deliveryReportEnabled,\n                                        oneToOneFileTransfer);\n                            }\n                            break;\n\n                        default:\n                            break;\n                    }\n\n                } catch (SessionUnavailableException | SessionNotEstablishedException\n                        | FileAccessException | NetworkException e) {\n                    if (logActivated) {\n                        mLogger.debug(\"Failed to dequeue file transfer with fileTransferId '\" + id\n                                + \"' on chat '\" + chatId + \"' due to: \" + e.getMessage());\n                    }\n\n                } catch (PayloadException e) {\n                    mLogger.error(\"Failed to dequeue file transfer with fileTransferId '\" + id\n                            + \"' on chat '\" + chatId, e);\n                    setGroupFileTransferAsFailedDequeue(id, groupFile, contact, chatId);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally all the terminal and non-terminal cases should be handled above so\n                     * if we come here that means that there is a bug and so we output a stack trace\n                     * so the bug can then be properly tracked down and fixed. We also mark the\n                     * respective entry that failed to dequeue as FAILED.\n                     */\n                    mLogger.error(\"Failed to dequeue file transfer with fileTransferId '\" + id\n                            + \"' and chatId '\" + chatId + \"'!\", e);\n                    setGroupFileTransferAsFailedDequeue(id, groupFile, contact, chatId);\n                }\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally all the terminal and non-terminal cases should be handled above so if we\n             * come here that means that there is a bug and so we output a stack trace so the bug\n             * can then be properly tracked down and fixed. We also mark the respective entry that\n             * failed to dequeue as FAILED.\n             */\n            mLogger.error(\"Exception occurred while dequeueing file transfer with transferId '\"\n                    + id + \"' and chatId '\" + chatId + \"'!\", e);\n            if (id == null) {\n                return;\n            }\n            setGroupFileTransferAsFailedDequeue(id, groupFile, contact, chatId);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/FileTransferLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpThumbnail;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeDownload;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.MimeManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Class to interface the 'filetransfer' table\n */\npublic class FileTransferLog implements IFileTransferLog {\n    private static final String SELECTION_FILE_BY_T_ID = FileTransferData.KEY_UPLOAD_TID + \"=?\";\n\n    private static final String SELECTION_BY_PAUSED_BY_SYSTEM = FileTransferData.KEY_STATE + \"=\"\n            + State.PAUSED.toInt() + \" AND \" + FileTransferData.KEY_REASON_CODE + \"=\"\n            + ReasonCode.PAUSED_BY_SYSTEM.toInt();\n\n    private static final String SELECTION_BY_EQUAL_CHAT_ID_AND_CONTACT = FileTransferData.KEY_CHAT_ID\n            + \"=\" + FileTransferData.KEY_CONTACT;\n\n    private static final String SELECTION_BY_QUEUED_AND_UPLOADED_BUT_NOT_TRANSFERRED_FILE_TRANSFERS = FileTransferData.KEY_STATE\n            + \"=\"\n            + State.QUEUED.toInt()\n            + \" OR (\"\n            + FileTransferData.KEY_STATE\n            + \"=\"\n            + State.STARTED.toInt()\n            + \" AND \"\n            + FileTransferData.KEY_DIRECTION\n            + \"=\"\n            + Direction.OUTGOING.toInt()\n            + \" AND \"\n            + FileTransferData.KEY_DOWNLOAD_URI\n            + \" IS NOT NULL)\";\n\n    private static final String SELECTION_BY_INTERRUPTED_FILE_TRANSFERS = FileTransferData.KEY_STATE\n            + \" IN ('\"\n            + State.STARTED.toInt()\n            + \"','\"\n            + State.INVITED.toInt()\n            + \"','\"\n            + State.ACCEPTING.toInt() + \"','\" + State.INITIATING.toInt() + \"')\";\n\n    private static final String SELECTION_BY_NOT_DISPLAYED = FileTransferData.KEY_STATE + \"<>\"\n            + State.DISPLAYED.toInt();\n\n    private static final int FILE_TRANSFER_DELIVERY_EXPIRED = 1;\n\n    private static final int FILE_TRANSFER_DELIVERY_EXPIRATION_NOT_APPLICABLE = 0;\n\n    private static final String SELECTION_BY_UNDELIVERED_ONETOONE_FILE_TRANSFERS = FileTransferData.KEY_EXPIRED_DELIVERY\n            + \"<>\"\n            + FILE_TRANSFER_DELIVERY_EXPIRED\n            + \" AND \"\n            + FileTransferData.KEY_DELIVERY_EXPIRATION\n            + \"<>\"\n            + FILE_TRANSFER_DELIVERY_EXPIRATION_NOT_APPLICABLE\n            + \" AND \"\n            + FileTransferData.KEY_STATE\n            + \" NOT IN(\"\n            + State.DELIVERED.toInt()\n            + \",\"\n            + State.DISPLAYED.toInt() + \")\";\n\n    private static final String SELECTION_BY_UNDELIVERED_STATUS = FileTransferData.KEY_STATE\n            + \" NOT IN(\" + State.DELIVERED.toInt() + \",\" + State.DISPLAYED.toInt() + \")\";\n\n    private static final String ORDER_BY_TIMESTAMP_ASC = FileTransferData.KEY_TIMESTAMP\n            .concat(\" ASC\");\n\n    private final static String[] PROJECTION_FILE_TRANSFER_ID = new String[] {\n        FileTransferData.KEY_FT_ID\n    };\n\n    private static final String SELECTION_BY_NOT_READ = FileTransferData.KEY_READ_STATUS + \"=\"\n            + ReadStatus.UNREAD.toInt();\n\n    private static final int FIRST_COLUMN_IDX = 0;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final GroupDeliveryInfoLog mGroupChatDeliveryInfoLog;\n\n    private final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(FileTransferLog.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param localContentResolver Local content resolver\n     * @param groupChatDeliveryInfoLog Group chat delivery info log\n     * @param rcsSettings RcsSettings\n     */\n    /* package private */FileTransferLog(LocalContentResolver localContentResolver,\n            GroupDeliveryInfoLog groupChatDeliveryInfoLog, RcsSettings rcsSettings) {\n        mLocalContentResolver = localContentResolver;\n        mGroupChatDeliveryInfoLog = groupChatDeliveryInfoLog;\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public void addOneToOneFileTransfer(String fileTransferId, ContactId contact,\n            Direction direction, MmContent content, MmContent fileIcon, State state,\n            ReasonCode reasonCode, long timestamp, long timestampSent, long fileExpiration,\n            long fileIconExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add file transfer entry Id=\" + fileTransferId + \", contact=\" + contact\n                    + \", filename=\" + content.getName() + \", size=\" + content.getSize() + \", MIME=\"\n                    + content.getEncoding() + \", state=\" + state + \", reasonCode=\" + reasonCode\n                    + \", timestamp=\" + timestamp + \", timestampSent=\" + timestampSent);\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_FT_ID, fileTransferId);\n        values.put(FileTransferData.KEY_CHAT_ID, contact.toString());\n        values.put(FileTransferData.KEY_CONTACT, contact.toString());\n        values.put(FileTransferData.KEY_FILE, content.getUri().toString());\n        values.put(FileTransferData.KEY_FILENAME, content.getName());\n        values.put(FileTransferData.KEY_MIME_TYPE, content.getEncoding());\n        values.put(FileTransferData.KEY_DIRECTION, direction.toInt());\n        if (content.isPlayable()) {\n            values.put(FileTransferData.KEY_DISPOSITION, FileTransfer.Disposition.RENDER.toInt());\n        } else {\n            values.put(FileTransferData.KEY_DISPOSITION, FileTransfer.Disposition.ATTACH.toInt());\n        }\n        values.put(FileTransferData.KEY_TRANSFERRED, 0);\n        values.put(FileTransferData.KEY_FILESIZE, content.getSize());\n        if (fileIcon != null) {\n            values.put(FileTransferData.KEY_FILEICON, fileIcon.getUri().toString());\n            values.put(FileTransferData.KEY_FILEICON_MIME_TYPE, fileIcon.getEncoding());\n            values.put(FileTransferData.KEY_FILEICON_EXPIRATION, fileIconExpiration);\n        } else {\n            values.put(FileTransferData.KEY_FILEICON_EXPIRATION,\n                    FileTransferData.UNKNOWN_EXPIRATION);\n        }\n        values.put(FileTransferData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(FileTransferData.KEY_STATE, state.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP, timestamp);\n        values.put(FileTransferData.KEY_TIMESTAMP_SENT, timestampSent);\n        values.put(FileTransferData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(FileTransferData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(FileTransferData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 0);\n        values.put(FileTransferData.KEY_FILE_EXPIRATION, fileExpiration);\n        mLocalContentResolver.insert(FileTransferData.CONTENT_URI, values);\n    }\n\n    @Override\n    public void addOutgoingGroupFileTransfer(String fileTransferId, String chatId,\n            MmContent content, MmContent thumbnail, Set<ContactId> recipients, State state,\n            ReasonCode reasonCode, long timestamp, long timestampSent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"addOutgoingGroupFileTransfer: Id=\" + fileTransferId + \", chatId=\"\n                    + chatId + \" filename=\" + content.getName() + \", size=\" + content.getSize()\n                    + \", MIME=\" + content.getEncoding());\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_FT_ID, fileTransferId);\n        values.put(FileTransferData.KEY_CHAT_ID, chatId);\n        values.put(FileTransferData.KEY_FILE, content.getUri().toString());\n        values.put(FileTransferData.KEY_FILENAME, content.getName());\n        values.put(FileTransferData.KEY_MIME_TYPE, content.getEncoding());\n        values.put(FileTransferData.KEY_DIRECTION, Direction.OUTGOING.toInt());\n        values.put(FileTransferData.KEY_TRANSFERRED, 0);\n        values.put(FileTransferData.KEY_FILESIZE, content.getSize());\n        values.put(MessageData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP, timestamp);\n        values.put(FileTransferData.KEY_TIMESTAMP_SENT, timestampSent);\n        values.put(FileTransferData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(FileTransferData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(FileTransferData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 0);\n        values.put(FileTransferData.KEY_STATE, state.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, reasonCode.toInt());\n        if (thumbnail != null) {\n            values.put(FileTransferData.KEY_FILEICON, thumbnail.getUri().toString());\n            values.put(FileTransferData.KEY_FILEICON_MIME_TYPE, thumbnail.getEncoding());\n        }\n        values.put(FileTransferData.KEY_FILEICON_EXPIRATION, FileTransferData.UNKNOWN_EXPIRATION);\n        values.put(FileTransferData.KEY_FILE_EXPIRATION, FileTransferData.UNKNOWN_EXPIRATION);\n        if (content.isPlayable()) {\n            values.put(FileTransferData.KEY_DISPOSITION, FileTransfer.Disposition.RENDER.toInt());\n        } else {\n            values.put(FileTransferData.KEY_DISPOSITION, FileTransfer.Disposition.ATTACH.toInt());\n        }\n        mLocalContentResolver.insert(FileTransferData.CONTENT_URI, values);\n\n        try {\n            for (ContactId contact : recipients) {\n                /* Add entry with delivered and displayed timestamps set to 0. */\n                mGroupChatDeliveryInfoLog.addGroupChatDeliveryInfoEntry(chatId, contact,\n                        fileTransferId, GroupDeliveryInfo.Status.NOT_DELIVERED,\n                        GroupDeliveryInfo.ReasonCode.UNSPECIFIED, 0, 0);\n            }\n        } catch (Exception e) {\n            if (sLogger.isActivated()) {\n                sLogger.error(\"Group file transfer with fileTransferId '\" + fileTransferId\n                        + \"' could not be added to database!\", e);\n            }\n            mLocalContentResolver.delete(\n                    Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), null, null);\n            mLocalContentResolver.delete(\n                    Uri.withAppendedPath(GroupDeliveryInfoData.CONTENT_URI, fileTransferId), null,\n                    null);\n            /* TODO: Throw exception */\n        }\n    }\n\n    @Override\n    public void addIncomingGroupFileTransfer(String fileTransferId, String chatId,\n            ContactId contact, MmContent content, MmContent fileIcon, State state,\n            ReasonCode reasonCode, long timestamp, long timestampSent, long fileExpiration,\n            long fileIconExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add incoming file transfer entry: fileTransferId=\" + fileTransferId\n                    + \", chatId=\" + chatId + \", contact=\" + contact + \", filename=\"\n                    + content.getName() + \", size=\" + content.getSize() + \", MIME=\"\n                    + content.getEncoding() + \", state=\" + state + \", reasonCode=\" + reasonCode\n                    + \", timestamp=\" + timestamp + \", timestampSent=\" + timestampSent\n                    + \", expiration=\" + fileExpiration);\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_FT_ID, fileTransferId);\n        values.put(FileTransferData.KEY_CHAT_ID, chatId);\n        values.put(FileTransferData.KEY_FILE, content.getUri().toString());\n        values.put(FileTransferData.KEY_CONTACT, contact.toString());\n        values.put(FileTransferData.KEY_FILENAME, content.getName());\n        values.put(FileTransferData.KEY_MIME_TYPE, content.getEncoding());\n        values.put(FileTransferData.KEY_DIRECTION, Direction.INCOMING.toInt());\n        values.put(FileTransferData.KEY_TRANSFERRED, 0);\n        values.put(FileTransferData.KEY_FILESIZE, content.getSize());\n        values.put(FileTransferData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(FileTransferData.KEY_STATE, state.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP, timestamp);\n        values.put(FileTransferData.KEY_TIMESTAMP_SENT, timestampSent);\n        values.put(FileTransferData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(FileTransferData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(FileTransferData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 0);\n        if (fileIcon != null) {\n            values.put(FileTransferData.KEY_FILEICON, fileIcon.getUri().toString());\n            values.put(FileTransferData.KEY_FILEICON_MIME_TYPE, fileIcon.getEncoding());\n            values.put(FileTransferData.KEY_FILEICON_EXPIRATION, fileIconExpiration);\n        } else {\n            values.put(FileTransferData.KEY_FILEICON_EXPIRATION,\n                    FileTransferData.UNKNOWN_EXPIRATION);\n        }\n        values.put(FileTransferData.KEY_FILE_EXPIRATION, fileExpiration);\n        if (content.isPlayable()) {\n            values.put(FileTransferData.KEY_DISPOSITION, FileTransfer.Disposition.RENDER.toInt());\n        } else {\n            values.put(FileTransferData.KEY_DISPOSITION, FileTransfer.Disposition.ATTACH.toInt());\n        }\n        mLocalContentResolver.insert(FileTransferData.CONTENT_URI, values);\n    }\n\n    /**\n     * Set file transfer state and reason code. Note that this method should not be used for\n     * State.DELIVERED and State.DISPLAYED. These states require timestamps and should be set\n     * through setFileTransferDelivered and setFileTransferDisplayed respectively.\n     * \n     * @param fileTransferId File transfer ID\n     * @param state File transfer state (see restriction above)\n     * @param reasonCode File transfer state reason code\n     */\n    @Override\n    public boolean setFileTransferStateAndReasonCode(String fileTransferId, State state,\n            ReasonCode reasonCode) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferStateAndReasonCode: fileTransferId=\" + fileTransferId\n                    + \", state=\" + state + \", reasonCode=\" + reasonCode);\n        }\n\n        switch (state) {\n            case DELIVERED:\n            case DISPLAYED:\n                throw new IllegalArgumentException(\"State that requires \"\n                        + \"timestamp passed, use specific method taking timestamp\"\n                        + \" to set state \" + state.toString());\n            default:\n        }\n\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_STATE, state.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, reasonCode.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values,\n                SELECTION_BY_UNDELIVERED_STATUS, null) > 0;\n    }\n\n    @Override\n    public int markFileTransferAsRead(String fileTransferId, long timestampDisplayed) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Mark file transfer as read ID=\" + fileTransferId);\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_READ_STATUS, ReadStatus.READ.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values,\n                SELECTION_BY_NOT_READ, null);\n    }\n\n    @Override\n    public boolean setFileTransferProgress(String fileTransferId, long currentSize) {\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_TRANSFERRED, currentSize);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public Long getFileTransferProgress(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_TRANSFERRED, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    @Override\n    public boolean setFileTransferred(String fileTransferId, MmContent content,\n            long fileExpiration, long fileIconExpiration, long deliveryExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferred (Id=\" + fileTransferId + \") (uri=\" + content.getUri()\n                    + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_STATE, State.TRANSFERRED.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, ReasonCode.UNSPECIFIED.toInt());\n        values.put(FileTransferData.KEY_TRANSFERRED, content.getSize());\n        values.put(FileTransferData.KEY_FILE_EXPIRATION, fileExpiration);\n        values.put(FileTransferData.KEY_FILEICON_EXPIRATION, fileIconExpiration);\n        values.put(FileTransferData.KEY_DELIVERY_EXPIRATION, deliveryExpiration);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public boolean isFileTransfer(String fileTransferId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId);\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_FILE_TRANSFER_ID, null,\n                    null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            return cursor.moveToNext();\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public boolean setFileUploadTId(String fileTransferId, String tId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileUploadTId (tId=\" + tId + \") (fileTransferId=\" + fileTransferId\n                    + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_UPLOAD_TID, tId);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public boolean setFileDownloadAddress(String fileTransferId, Uri downloadAddress) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileDownloadAddress (address=\" + downloadAddress\n                    + \") (fileTransferId=\" + fileTransferId + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_DOWNLOAD_URI, downloadAddress.toString());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public boolean setRemoteSipId(String fileTransferId, String sipInstanceId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setRemoteSipId (sip ID=\" + sipInstanceId + \") (fileTransferId=\"\n                    + fileTransferId + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_REMOTE_SIP_ID, sipInstanceId);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public List<FtHttpResume> retrieveFileTransfersPausedBySystem() {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(FileTransferData.CONTENT_URI, null,\n                    SELECTION_BY_PAUSED_BY_SYSTEM, null, ORDER_BY_TIMESTAMP_ASC);\n            CursorUtil.assertCursorIsNotNull(cursor, FileTransferData.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return Collections.emptyList();\n            }\n\n            int sizeColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILESIZE);\n            int mimeTypeColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_MIME_TYPE);\n            int contactColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_CONTACT);\n            int chatIdColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_CHAT_ID);\n            int fileColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILE);\n            int fileNameColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILENAME);\n            int directionColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_DIRECTION);\n            int fileTransferIdColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FT_ID);\n            int fileIconColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILEICON);\n            int timestampColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP);\n            int timestampSentColumnIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP_SENT);\n\n            int downloadUriColumnIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_DOWNLOAD_URI);\n            int tIdColumnIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_UPLOAD_TID);\n            int fileExpirationColumnIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILE_EXPIRATION);\n            int iconExpirationColumnIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_EXPIRATION);\n            int remoteSipIdColumnIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_REMOTE_SIP_ID);\n\n            List<FtHttpResume> fileTransfers = new ArrayList<>();\n            do {\n                long size = cursor.getLong(sizeColumnIdx);\n                String mimeType = cursor.getString(mimeTypeColumnIdx);\n                String fileTransferId = cursor.getString(fileTransferIdColumnIdx);\n                String phoneNumber = cursor.getString(contactColumnIdx);\n                ContactId contact = phoneNumber == null ? null : ContactUtil\n                        .createContactIdFromTrustedData(phoneNumber);\n                String chatId = cursor.getString(chatIdColumnIdx);\n                String file = cursor.getString(fileColumnIdx);\n                String fileName = cursor.getString(fileNameColumnIdx);\n                Direction direction = Direction.valueOf(cursor.getInt(directionColumnIdx));\n                String fileIcon = cursor.getString(fileIconColumnIdx);\n                long timestamp = cursor.getLong(timestampColumnIdx);\n                long timestampSent = cursor.getLong(timestampSentColumnIdx);\n                boolean isGroup = !chatId.equals(phoneNumber);\n                MmContent content = ContentManager.createMmContent(Uri.parse(file), mimeType, size,\n                        fileName);\n                Uri fileIconUri = fileIcon != null ? Uri.parse(fileIcon) : null;\n                if (direction == Direction.INCOMING) {\n\n                    String downloadUri = cursor.getString(downloadUriColumnIdx);\n                    long fileExpiration = cursor.getLong(fileExpirationColumnIdx);\n                    long iconExpiration = cursor.getLong(iconExpirationColumnIdx);\n                    String remoteSipId = cursor.getString(remoteSipIdColumnIdx);\n                    /*\n                     * File transfer is paused by system only if already accepted\n                     */\n                    fileTransfers.add(new FtHttpResumeDownload(Uri.parse(downloadUri), Uri\n                            .parse(file), fileIconUri, content, contact, chatId, fileTransferId,\n                            isGroup, timestamp, timestampSent, fileExpiration, iconExpiration,\n                            true, remoteSipId));\n                } else {\n                    String tId = cursor.getString(tIdColumnIdx);\n                    fileTransfers.add(new FtHttpResumeUpload(content, fileIconUri, tId, contact,\n                            chatId, fileTransferId, isGroup, timestamp, timestampSent));\n                }\n            } while (cursor.moveToNext());\n            return fileTransfers;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public FtHttpResumeUpload retrieveFtHttpResumeUpload(String tId) {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(FileTransferData.CONTENT_URI, null,\n                    SELECTION_FILE_BY_T_ID, new String[] {\n                        tId\n                    }, null);\n            CursorUtil.assertCursorIsNotNull(cursor, FileTransferData.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            String fileName = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILENAME));\n            long size = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_TRANSFERRED));\n            String mimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_MIME_TYPE));\n            String fileTransferId = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FT_ID));\n            String phoneNumber = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_CONTACT));\n            ContactId contact = phoneNumber == null ? null : ContactUtil\n                    .createContactIdFromTrustedData(phoneNumber);\n            long timestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP));\n            long timestampSent = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP_SENT));\n            String chatId = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_CHAT_ID));\n            String file = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILE));\n            String fileIcon = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON));\n            boolean isGroup = !chatId.equals(phoneNumber);\n            MmContent content = ContentManager.createMmContent(Uri.parse(file), mimeType, size,\n                    fileName);\n            Uri fileIconUri = fileIcon != null ? Uri.parse(fileIcon) : null;\n            return new FtHttpResumeUpload(content, fileIconUri, tId, contact, chatId,\n                    fileTransferId, isGroup, timestamp, timestampSent);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Cursor getFileTransferData(String columnName, String fileTransferId) {\n        String[] projection = {\n            columnName\n        };\n        Uri contentUri = Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, projection, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        if (!cursor.moveToNext()) {\n            CursorUtil.close(cursor);\n            return null;\n        }\n        return cursor;\n    }\n\n    private Integer getDataAsInteger(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getInt(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Long getDataAsLong(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getLong(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private String getDataAsString(Cursor cursor) {\n        try {\n            return cursor.getString(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Boolean getDataAsBoolean(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getInt(FIRST_COLUMN_IDX) == 1;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public Cursor getFileTransferData(String fileTransferId) {\n        Uri contentUri = Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        return cursor;\n    }\n\n    @Override\n    public Uri getFileTransferIcon(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_FILEICON, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        String uriString = getDataAsString(cursor);\n        if (uriString == null) {\n            return null;\n        }\n        return Uri.parse(uriString);\n    }\n\n    @Override\n    public State getFileTransferState(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_STATE, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return State.valueOf(getDataAsInteger(cursor));\n    }\n\n    @Override\n    public ReasonCode getFileTransferReasonCode(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_REASON_CODE, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return ReasonCode.valueOf(getDataAsInteger(cursor));\n    }\n\n    @Override\n    public Long getFileTransferTimestamp(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_TIMESTAMP, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    @Override\n    public Long getFileTransferSentTimestamp(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_TIMESTAMP_SENT, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    @Override\n    public String getFileTransferChatId(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_CHAT_ID, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsString(cursor);\n    }\n\n    @Override\n    public Boolean isFileTransferExpiredDelivery(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_EXPIRED_DELIVERY, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsBoolean(cursor);\n    }\n\n    @Override\n    public boolean isGroupFileTransfer(String fileTransferId) {\n        /*\n         * Warning: return true if record does not exist.\n         */\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId);\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_FILE_TRANSFER_ID,\n                    SELECTION_BY_EQUAL_CHAT_ID_AND_CONTACT, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            /*\n             * For a one-to-one file transfer, value of chatID is equal to the value of contact\n             */\n            return !cursor.moveToNext();\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public FtHttpResume getFileTransferResumeInfo(String fileTransferId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId);\n            cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            String phoneNumber = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_CONTACT));\n            ContactId contact = phoneNumber != null ? ContactUtil\n                    .createContactIdFromTrustedData(phoneNumber) : null;\n            String chatId = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_CHAT_ID));\n            String fileUri = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILE));\n            Direction direction = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_DIRECTION)));\n            String fileIcon = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON));\n            long timestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP));\n            long timestampSent = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP_SENT));\n            long fileSize = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILESIZE));\n            String fileName = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILENAME));\n            String fileMimetype = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_MIME_TYPE));\n            boolean isGroup = !chatId.equals(phoneNumber);\n            Uri file = Uri.parse(fileUri);\n            MmContent content = ContentManager.createMmContent(file, fileMimetype, fileSize,\n                    fileName);\n            Uri fileIconUri = fileIcon != null ? Uri.parse(fileIcon) : null;\n            if (Direction.INCOMING == direction) {\n                String downloadUri = cursor.getString(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_DOWNLOAD_URI));\n                long fileExpiration = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_FILE_EXPIRATION));\n                long iconExpiration = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_EXPIRATION));\n                FileTransfer.State state = FileTransfer.State.valueOf(cursor.getInt(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_STATE)));\n                String remoteSipId = cursor.getString(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_REMOTE_SIP_ID));\n                /*\n                 * If state is INVITED then file transfer is not accepted\n                 */\n                boolean accepted = !(FileTransfer.State.INVITED == state);\n                return new FtHttpResumeDownload(Uri.parse(downloadUri), file, fileIconUri, content,\n                        contact, chatId, fileTransferId, isGroup, timestamp, timestampSent,\n                        fileExpiration, iconExpiration, accepted, remoteSipId);\n            }\n            String tId = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_UPLOAD_TID));\n            return new FtHttpResumeUpload(content, fileIconUri, tId, contact, chatId,\n                    fileTransferId, isGroup, timestamp, timestampSent);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public Cursor getQueuedAndUploadedButNotTransferredFileTransfers() {\n        Cursor cursor = mLocalContentResolver.query(FileTransferData.CONTENT_URI, null,\n                SELECTION_BY_QUEUED_AND_UPLOADED_BUT_NOT_TRANSFERRED_FILE_TRANSFERS, null,\n                ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, FileTransferData.CONTENT_URI);\n        return cursor;\n    }\n\n    @Override\n    public Cursor getInterruptedFileTransfers() {\n        Cursor cursor = mLocalContentResolver.query(FileTransferData.CONTENT_URI, null,\n                SELECTION_BY_INTERRUPTED_FILE_TRANSFERS, null, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, FileTransferData.CONTENT_URI);\n        return cursor;\n    }\n\n    @Override\n    public boolean setFileTransferStateAndTimestamp(String fileTransferId, State state,\n            ReasonCode reasonCode, long timestamp, long timestampSent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferStateAndTimestamp: fileTransferId=\" + fileTransferId\n                    + \", state=\" + state + \", reasonCode=\" + reasonCode + \", timestamp=\"\n                    + timestamp + \", timestampSent=\" + timestampSent);\n        }\n\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_STATE, state.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP, timestamp);\n        values.put(FileTransferData.KEY_TIMESTAMP_SENT, timestampSent);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public boolean setFileTransferDelivered(String fileTransferId, long timestampDelivered) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferDelivered fileTransferId=\" + fileTransferId\n                    + \", timestampDelivered=\" + timestampDelivered);\n        }\n\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_STATE, FileTransfer.State.DELIVERED.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, FileTransfer.ReasonCode.UNSPECIFIED.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP_DELIVERED, timestampDelivered);\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 0);\n\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values,\n                SELECTION_BY_NOT_DISPLAYED, null) > 0;\n    }\n\n    @Override\n    public boolean setFileTransferDisplayed(String fileTransferId, long timestampDisplayed) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferDisplayed fileTransferId=\" + fileTransferId\n                    + \", timestampDisplayed=\" + timestampDisplayed);\n        }\n\n        ContentValues values = new ContentValues();\n\n        values.put(FileTransferData.KEY_STATE, FileTransfer.State.DISPLAYED.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, FileTransfer.ReasonCode.UNSPECIFIED.toInt());\n        values.put(FileTransferData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 0);\n\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public void clearFileTransferDeliveryExpiration(List<String> fileTransferIds) {\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 0);\n        values.put(FileTransferData.KEY_DELIVERY_EXPIRATION, 0);\n        List<String> parameters = new ArrayList<>();\n        for (int i = 0; i < fileTransferIds.size(); i++) {\n            parameters.add(\"?\");\n        }\n        String selection = FileTransferData.KEY_FT_ID + \" IN (\" + TextUtils.join(\",\", parameters)\n                + \")\";\n        mLocalContentResolver.update(FileTransferData.CONTENT_URI, values, selection,\n                fileTransferIds.toArray(new String[fileTransferIds.size()]));\n    }\n\n    @Override\n    public boolean setFileTransferDeliveryExpired(String fileTransferId) {\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_EXPIRED_DELIVERY, 1);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public Cursor getUnDeliveredOneToOneFileTransfers() {\n        Cursor cursor = mLocalContentResolver.query(FileTransferData.CONTENT_URI, null,\n                SELECTION_BY_UNDELIVERED_ONETOONE_FILE_TRANSFERS, null, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, FileTransferData.CONTENT_URI);\n        return cursor;\n    }\n\n    @Override\n    public void setFileTransferDownloadInfo(String fileTransferId,\n            FileTransferHttpInfoDocument ftHttpInfo) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferDownloadInfo fileTransferId=\".concat(fileTransferId));\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_DOWNLOAD_URI, ftHttpInfo.getUri().toString());\n        values.put(FileTransferData.KEY_TRANSFERRED, ftHttpInfo.getSize());\n        values.put(FileTransferData.KEY_FILE_EXPIRATION, ftHttpInfo.getExpiration());\n        FileTransferHttpThumbnail fileIcon = ftHttpInfo.getFileThumbnail();\n        if (fileIcon != null) {\n            values.put(FileTransferData.KEY_FILEICON_DOWNLOAD_URI, fileIcon.getUri().toString());\n            values.put(FileTransferData.KEY_FILEICON_SIZE, fileIcon.getSize());\n            values.put(FileTransferData.KEY_FILEICON_MIME_TYPE, fileIcon.getMimeType());\n            values.put(FileTransferData.KEY_FILEICON_EXPIRATION, fileIcon.getExpiration());\n        }\n        mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null);\n    }\n\n    @Override\n    public FileTransferHttpInfoDocument getFileDownloadInfo(Cursor cursor)\n            throws FileAccessException {\n        String fileTransferId = cursor.getString(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FT_ID));\n        String file = cursor.getString(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_DOWNLOAD_URI));\n        if (file == null) {\n            throw new FileAccessException(\n                    \"File download URI not available for file transfer ID=\".concat(fileTransferId));\n        }\n        String fileName = cursor.getString(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FILENAME));\n        int size = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferData.KEY_TRANSFERRED));\n        String mimeType = cursor.getString(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_MIME_TYPE));\n        long fileExpiration = cursor.getLong(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FILE_EXPIRATION));\n        long fileIconExpiration = cursor.getLong(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_EXPIRATION));\n        String fileIcon = cursor.getString(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_DOWNLOAD_URI));\n        int fileIconSize = cursor.getInt(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_SIZE));\n        String fileIconMimeType = cursor.getString(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_MIME_TYPE));\n        FileTransferHttpThumbnail fileIconData = fileIcon != null ? new FileTransferHttpThumbnail(\n                mRcsSettings, Uri.parse(fileIcon), fileIconMimeType, fileIconSize,\n                fileIconExpiration) : null;\n        FileTransferHttpInfoDocument infoDoc = new FileTransferHttpInfoDocument(mRcsSettings,\n                Uri.parse(file), fileName, size, mimeType, fileExpiration, fileIconData);\n        Disposition disposition = Disposition.valueOf(cursor.getInt(cursor\n                .getColumnIndexOrThrow(FileTransferData.KEY_DISPOSITION)));\n        infoDoc.setFileDisposition(disposition);\n        if (MimeManager.isAudioType(mimeType)) {\n            file = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILE));\n            long duration = FileUtils.getDurationFromFile(AndroidFactory.getApplicationContext(),\n                    Uri.parse(file));\n            infoDoc.setPlayingLength((int) (duration / 1000L) + 1);\n        }\n        return infoDoc;\n    }\n\n    @Override\n    public FileTransferHttpInfoDocument getFileDownloadInfo(String fileTransferId)\n            throws FileAccessException {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId);\n            cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, FileTransferData.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            return getFileDownloadInfo(cursor);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public void setFileTransferTimestamps(String fileTransferId, long timestamp, long timestampSent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileTransferTimestamps: fileTransferId=\" + fileTransferId\n                    + \", timestamp=\" + timestamp + \", timestampSent=\" + timestampSent);\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_TIMESTAMP, timestamp);\n        values.put(FileTransferData.KEY_TIMESTAMP_SENT, timestampSent);\n        mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null);\n    }\n\n    @Override\n    public boolean setFileInfoDequeued(String fileTransferId, long deliveryExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setFileInfoDequeued (Id=\" + fileTransferId + \") (deliveryExpiration=\"\n                    + deliveryExpiration + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(FileTransferData.KEY_STATE, State.TRANSFERRED.toInt());\n        values.put(FileTransferData.KEY_REASON_CODE, ReasonCode.UNSPECIFIED.toInt());\n        values.put(FileTransferData.KEY_DELIVERY_EXPIRATION, deliveryExpiration);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, fileTransferId), values, null,\n                null) > 0;\n    }\n\n    @Override\n    public Uri getFile(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_FILE, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return Uri.parse(getDataAsString(cursor));\n    }\n\n    @Override\n    public Direction getFileTransferDirection(String fileTransferId) {\n        Cursor cursor = getFileTransferData(FileTransferData.KEY_DIRECTION, fileTransferId);\n        if (cursor == null) {\n            return null;\n        }\n        return Direction.valueOf(getDataAsInteger(cursor));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/FileTransferPersistedStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * FileTransferPersistedStorageAccessor helps in retrieving persisted data related to a file\n * transfer from the persisted storage. It can utilize caching for such data that will not be\n * changed after creation of the File transfer to speed up consecutive access.\n */\npublic class FileTransferPersistedStorageAccessor {\n\n    private final String mFileTransferId;\n\n    private final MessagingLog mMessagingLog;\n\n    private ContactId mContact;\n\n    private Boolean mRead;\n\n    private Disposition mDisposition;\n\n    private Direction mDirection;\n\n    private String mChatId;\n\n    private String mFileName;\n\n    private Long mFileSize;\n\n    private String mMimeType;\n\n    private Uri mFile;\n\n    private Uri mFileIcon;\n\n    private String mFileIconMimeType;\n\n    private Long mTimestampDelivered;\n\n    private Long mTimestampDisplayed;\n\n    private Long mFileExpiration = FileTransferData.UNKNOWN_EXPIRATION;\n\n    private Long mFileIconExpiration = FileTransferData.UNKNOWN_EXPIRATION;\n\n    /**\n     * Constructor\n     * \n     * @param fileTransferId the file transfer ID\n     * @param messagingLog the messaging log accessor\n     */\n    public FileTransferPersistedStorageAccessor(String fileTransferId, MessagingLog messagingLog) {\n        mFileTransferId = fileTransferId;\n        mMessagingLog = messagingLog;\n    }\n\n    private void cacheData() {\n        Cursor cursor = null;\n        try {\n            cursor = mMessagingLog.getFileTransferData(mFileTransferId);\n            if (!cursor.moveToNext()) {\n                throw new ServerApiPersistentStorageException(\"Data not found for file transfer \"\n                        + mFileTransferId);\n            }\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_CONTACT));\n            if (contact != null) {\n                mContact = ContactUtil.createContactIdFromTrustedData(contact);\n            }\n            mDirection = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_DIRECTION)));\n            mDisposition = Disposition.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_DISPOSITION)));\n            mChatId = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferData.KEY_CHAT_ID));\n            mFileName = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILENAME));\n            mMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_MIME_TYPE));\n            mFile = Uri.parse(cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILE)));\n            String fileIcon = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON));\n            if (fileIcon != null) {\n                mFileIcon = Uri.parse(fileIcon);\n            }\n            if (!Boolean.TRUE.equals(mRead)) {\n                mRead = ReadStatus.READ.toInt() == cursor.getInt(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_READ_STATUS));\n            }\n            mFileSize = cursor.getLong(cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILESIZE));\n            mFileIconMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_MIME_TYPE));\n            if (mTimestampDelivered == null || mTimestampDelivered == 0) {\n                mTimestampDelivered = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP_DELIVERED));\n            }\n            if (mTimestampDisplayed == null || mTimestampDisplayed == 0) {\n                mTimestampDisplayed = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_TIMESTAMP_DISPLAYED));\n            }\n            if (mFileExpiration == FileTransferData.UNKNOWN_EXPIRATION) {\n                mFileExpiration = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_FILE_EXPIRATION));\n            }\n            if (mFileIconExpiration == FileTransferData.UNKNOWN_EXPIRATION) {\n                mFileIconExpiration = cursor.getLong(cursor\n                        .getColumnIndexOrThrow(FileTransferData.KEY_FILEICON_EXPIRATION));\n            }\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    public String getChatId() {\n        /*\n         * Utilizing cache here as chatId can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mChatId == null) {\n            cacheData();\n        }\n        return mChatId;\n    }\n\n    public ContactId getRemoteContact() {\n        /*\n         * Utilizing cache here as contact can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mContact == null) {\n            cacheData();\n        }\n        return mContact;\n    }\n\n    public Uri getFile() {\n        /*\n         * Utilizing cache here as file can't be changed in persistent storage after entry insertion\n         * anyway so no need to query for it multiple times.\n         */\n        if (mFile == null) {\n            cacheData();\n        }\n        return mFile;\n    }\n\n    public String getFileName() {\n        /*\n         * Utilizing cache here as file name can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mFileName == null) {\n            cacheData();\n        }\n        return mFileName;\n    }\n\n    public Long getFileSize() {\n        /*\n         * Utilizing cache here as file size can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mFileSize == null) {\n            cacheData();\n        }\n        return mFileSize;\n    }\n\n    public String getMimeType() {\n        /*\n         * Utilizing cache here as mime type can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mMimeType == null) {\n            cacheData();\n        }\n        return mMimeType;\n    }\n\n    public Uri getFileIcon() {\n        /*\n         * Utilizing cache here as file icon can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mFileIcon == null) {\n            cacheData();\n        }\n        return mFileIcon;\n    }\n\n    public String getFileIconMimeType() {\n        /*\n         * Utilizing cache here as file icon mime type can't be changed in persistent storage after\n         * entry insertion anyway so no need to query for it multiple times.\n         */\n        if (mFileIconMimeType == null) {\n            cacheData();\n        }\n        return mFileIconMimeType;\n    }\n\n    public long getTimestamp() {\n        Long timestamp = mMessagingLog.getFileTransferTimestamp(mFileTransferId);\n        if (timestamp == null) {\n            throw new ServerApiPersistentStorageException(\"Timestamp not found for file transfer \"\n                    + mFileTransferId);\n        }\n        return timestamp;\n    }\n\n    public long getTimestampSent() {\n        Long timestamp = mMessagingLog.getFileTransferSentTimestamp(mFileTransferId);\n        if (timestamp == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"TimestampSent not found for file transfer \" + mFileTransferId);\n        }\n        return timestamp;\n    }\n\n    public long getTimestampDelivered() {\n        /*\n         * Utilizing cache here as Timestamp delivered can't be changed in persistent storage after\n         * it has been set to some value bigger than zero, so no need to query for it multiple\n         * times.\n         */\n        if (mTimestampDelivered == null || mTimestampDelivered == 0) {\n            cacheData();\n        }\n        return mTimestampDelivered;\n    }\n\n    public Long getTimestampDisplayed() {\n        /*\n         * Utilizing cache here as Timestamp displayed can't be changed in persistent storage after\n         * it has been set to some value bigger than zero, so no need to query for it multiple\n         * times.\n         */\n        if (mTimestampDisplayed == null || mTimestampDisplayed == 0) {\n            cacheData();\n        }\n        return mTimestampDisplayed;\n    }\n\n    public State getState() {\n        State state = mMessagingLog.getFileTransferState(mFileTransferId);\n        if (state == null) {\n            throw new ServerApiPersistentStorageException(\"State not found for file transfer \"\n                    + mFileTransferId);\n        }\n        return state;\n    }\n\n    public ReasonCode getReasonCode() {\n        ReasonCode reasonCode = mMessagingLog.getFileTransferReasonCode(mFileTransferId);\n        if (reasonCode == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Reason code not found for file transfer \" + mFileTransferId);\n        }\n        return reasonCode;\n    }\n\n    public Disposition getDisposition() {\n        /*\n         * Utilizing cache here as disposition can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mDisposition == null) {\n            cacheData();\n        }\n        return mDisposition;\n    }\n\n    public Direction getDirection() {\n        /*\n         * Utilizing cache here as direction can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mDirection == null) {\n            cacheData();\n        }\n        return mDirection;\n    }\n\n    public Boolean isRead() {\n        /*\n         * No need to read from provider unless incoming and not already marked as read.\n         */\n        if (Direction.INCOMING == getDirection() && !Boolean.TRUE.equals(mRead)) {\n            cacheData();\n        }\n        return mRead;\n    }\n\n    public boolean setStateAndReasonCode(State state, ReasonCode reasonCode) {\n        return mMessagingLog.setFileTransferStateAndReasonCode(mFileTransferId, state, reasonCode);\n    }\n\n    public boolean setProgress(long currentSize) {\n        return mMessagingLog.setFileTransferProgress(mFileTransferId, currentSize);\n    }\n\n    public boolean setTransferred(MmContent content, long fileExpiration, long fileIconExpiration,\n            long deliveryExpiration) {\n        return mMessagingLog.setFileTransferred(mFileTransferId, content, fileExpiration,\n                fileIconExpiration, deliveryExpiration);\n    }\n\n    public void addOneToOneFileTransfer(ContactId contact, Direction direction, MmContent content,\n            MmContent fileIcon, State status, ReasonCode reasonCode, long timestamp,\n            long timestampSent, long fileExpiration, long fileIconExpiration) {\n        mContact = contact;\n        mDirection = direction;\n        mMessagingLog.addOneToOneFileTransfer(mFileTransferId, contact, direction, content,\n                fileIcon, status, reasonCode, timestamp, timestampSent, fileExpiration,\n                fileIconExpiration);\n    }\n\n    public void addIncomingGroupFileTransfer(String chatId, ContactId contact, MmContent content,\n            MmContent fileicon, State state, ReasonCode reasonCode, long timestamp,\n            long timestampSent, long fileExpiration, long fileIconExpiration) {\n        mChatId = chatId;\n        mContact = contact;\n        mMessagingLog.addIncomingGroupFileTransfer(mFileTransferId, chatId, contact, content,\n                fileicon, state, reasonCode, timestamp, timestampSent, fileExpiration,\n                fileIconExpiration);\n    }\n\n    public FtHttpResume getFileTransferResumeInfo() {\n        return mMessagingLog.getFileTransferResumeInfo(mFileTransferId);\n    }\n\n    /**\n     * Returns the time for when file on the content server is no longer valid to download.\n     * \n     * @return time\n     */\n    public long getFileExpiration() {\n        /* No need to read from provider unless outgoing and expiration is unknown. */\n        if (Direction.OUTGOING == getDirection()\n                && FileTransferData.UNKNOWN_EXPIRATION == mFileExpiration) {\n            cacheData();\n        }\n        return mFileExpiration;\n    }\n\n    /**\n     * Returns the time for when file icon on the content server is no longer valid to download.\n     * \n     * @return time\n     */\n    public long getFileIconExpiration() {\n        /* No need to read from provider unless outgoing and expiration is unknown. */\n        if (Direction.OUTGOING == getDirection()\n                && FileTransferData.UNKNOWN_EXPIRATION == mFileIconExpiration) {\n            cacheData();\n        }\n        return mFileIconExpiration;\n    }\n\n    /**\n     * Returns true if delivery for this file has expired or false otherwise. Note: false means\n     * either that delivery for this file has not yet expired, delivery has been successful,\n     * delivery expiration has been cleared (see clearFileTransferDeliveryExpiration) or that this\n     * particular file is not eligible for delivery expiration in the first place.\n     * \n     * @return deliveryExpiration\n     */\n    public boolean isExpiredDelivery() {\n        Boolean expiredDelivery = mMessagingLog.isFileTransferExpiredDelivery(mFileTransferId);\n        if (expiredDelivery == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Expired Delivery not found for file transfer \" + mFileTransferId);\n        }\n        return expiredDelivery;\n    }\n\n    public boolean setStateAndTimestamp(State state, ReasonCode reasonCode, long timestamp,\n            long timestampSent) {\n        return mMessagingLog.setFileTransferStateAndTimestamp(mFileTransferId, state, reasonCode,\n                timestamp, timestampSent);\n    }\n\n    public boolean setFileInfoDequeued(long deliveryExpiration) {\n        return mMessagingLog.setFileInfoDequeued(mFileTransferId, deliveryExpiration);\n    }\n\n    /**\n     * Returns the number of transferred bytes.\n     * \n     * @return the number of transferred bytes.\n     */\n    public long getFileTransferProgress() {\n        Long transferred = mMessagingLog.getFileTransferProgress(mFileTransferId);\n        if (transferred == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Transferred not found for file transfer \" + mFileTransferId);\n        }\n        return transferred;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/FileTransferProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.history.HistoryMemberBaseIdCreator;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * File transfer content provider\n * \n * @author Jean-Marc AUFFRET\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class FileTransferProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String SELECTION_WITH_FT_ID_ONLY = FileTransferData.KEY_FT_ID.concat(\"=?\");\n\n    private static final class UriType {\n\n        private static final class FileTransfer {\n\n            private static final int FILE_TRANSFER = 1;\n\n            private static final int FILE_TRANSFER_WITH_ID = 2;\n        }\n\n        private static final class InternalFileTransfer {\n\n            private static final int FILE_TRANSFER = 3;\n\n            private static final int FILE_TRANSFER_WITH_ID = 4;\n        }\n    }\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/filetransfer\";\n\n        private static final String TYPE_ITEM = \"vnd.android.cursor.item/filetransfer\";\n    }\n\n    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n    static {\n        sUriMatcher.addURI(FileTransferLog.CONTENT_URI.getAuthority(), FileTransferLog.CONTENT_URI\n                .getPath().substring(1), UriType.FileTransfer.FILE_TRANSFER);\n        sUriMatcher.addURI(FileTransferLog.CONTENT_URI.getAuthority(), FileTransferLog.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.FileTransfer.FILE_TRANSFER_WITH_ID);\n        sUriMatcher.addURI(FileTransferData.CONTENT_URI.getAuthority(),\n                FileTransferData.CONTENT_URI.getPath().substring(1),\n                UriType.InternalFileTransfer.FILE_TRANSFER);\n        sUriMatcher.addURI(FileTransferData.CONTENT_URI.getAuthority(),\n                FileTransferData.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.InternalFileTransfer.FILE_TRANSFER_WITH_ID);\n    }\n\n    /**\n     * Strings to allow projection for exposed URI to a set of columns.\n     */\n    private static final String[] COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS = new String[] {\n            FileTransferData.KEY_BASECOLUMN_ID, FileTransferData.KEY_FT_ID,\n            FileTransferData.KEY_CHAT_ID, FileTransferData.KEY_CONTACT, FileTransferData.KEY_FILE,\n            FileTransferData.KEY_FILENAME, FileTransferData.KEY_MIME_TYPE,\n            FileTransferData.KEY_FILEICON, FileTransferData.KEY_FILEICON_MIME_TYPE,\n            FileTransferData.KEY_DIRECTION, FileTransferData.KEY_FILESIZE,\n            FileTransferData.KEY_TRANSFERRED, FileTransferData.KEY_TIMESTAMP,\n            FileTransferData.KEY_TIMESTAMP_SENT, FileTransferData.KEY_TIMESTAMP_DELIVERED,\n            FileTransferData.KEY_TIMESTAMP_DISPLAYED, FileTransferData.KEY_STATE,\n            FileTransferData.KEY_REASON_CODE, FileTransferData.KEY_READ_STATUS,\n            FileTransferData.KEY_FILE_EXPIRATION, FileTransferData.KEY_FILEICON_EXPIRATION,\n            FileTransferData.KEY_EXPIRED_DELIVERY, FileTransferData.KEY_DISPOSITION\n    };\n\n    private static final Set<String> COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS = new HashSet<>(\n            Arrays.asList(COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS));\n\n    /**\n     * Table name\n     */\n    public static final String TABLE = \"filetransfer\";\n\n    /**\n     * Database name\n     */\n    public static final String DATABASE_NAME = \"filetransfer.db\";\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 17;\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE + '(' + FileTransferData.KEY_FT_ID\n                    + \" TEXT NOT NULL PRIMARY KEY,\" \n                    + FileTransferData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_CONTACT + \" TEXT,\"\n                    + FileTransferData.KEY_FILE + \" TEXT NOT NULL,\" \n                    + FileTransferData.KEY_FILENAME + \" TEXT NOT NULL,\" \n                    + FileTransferData.KEY_CHAT_ID + \" TEXT NOT NULL,\"\n                    + FileTransferData.KEY_MIME_TYPE + \" TEXT NOT NULL,\"\n                    + FileTransferData.KEY_STATE + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_READ_STATUS + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_DISPOSITION + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_DIRECTION + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_TIMESTAMP_SENT + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_TIMESTAMP_DELIVERED + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_TIMESTAMP_DISPLAYED + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_DELIVERY_EXPIRATION + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_EXPIRED_DELIVERY + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_TRANSFERRED + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_FILESIZE + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_FILEICON + \" TEXT,\"\n                    + FileTransferData.KEY_UPLOAD_TID + \" TEXT,\"\n                    + FileTransferData.KEY_DOWNLOAD_URI + \" TEXT,\"\n                    + FileTransferData.KEY_FILEICON_MIME_TYPE + \" TEXT,\"\n                    + FileTransferData.KEY_FILEICON_EXPIRATION + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_FILE_EXPIRATION + \" INTEGER NOT NULL,\"\n                    + FileTransferData.KEY_REMOTE_SIP_ID + \" TEXT,\"\n                    + FileTransferData.KEY_FILEICON_DOWNLOAD_URI + \" TEXT,\"\n                    + FileTransferData.KEY_FILEICON_SIZE + \" INTEGER)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + FileTransferData.KEY_BASECOLUMN_ID + \"_idx\" + \" ON \"\n                    + TABLE + '(' + FileTransferData.KEY_BASECOLUMN_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + FileTransferData.KEY_CHAT_ID + \"_idx\" + \" ON \" + TABLE\n                    + '(' + FileTransferData.KEY_CHAT_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + FileTransferData.KEY_TIMESTAMP + \"_idx\" + \" ON \" + TABLE\n                    + '(' + FileTransferData.KEY_TIMESTAMP + ')');\n            db.execSQL(\"CREATE INDEX \" + FileTransferData.KEY_TIMESTAMP_SENT + \"_idx\" + \" ON \"\n                    + TABLE + '(' + FileTransferData.KEY_TIMESTAMP_SENT + ')');\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE));\n            onCreate(db);\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithFtId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_FT_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_FT_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithFtId(String[] selectionArgs, String ftId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(ftId, selectionArgs);\n    }\n\n    private String[] restrictProjectionToExternallyDefinedColumns(String[] projection)\n            throws UnsupportedOperationException {\n        if (projection == null || projection.length == 0) {\n            return COLUMNS_ALLOWED_FOR_EXTERNAL_ACCESS;\n        }\n        for (String projectedColumn : projection) {\n            if (!COLUMNS_SET_ALLOWED_FOR_EXTERNAL_ACCESS.contains(projectedColumn)) {\n                throw new UnsupportedOperationException(\"No visibility to the accessed column \"\n                        + projectedColumn + \"!\");\n            }\n        }\n        return projection;\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalFileTransfer.FILE_TRANSFER:\n                /* Intentional fall through */\n            case UriType.FileTransfer.FILE_TRANSFER:\n                return CursorType.TYPE_DIRECTORY;\n\n            case UriType.InternalFileTransfer.FILE_TRANSFER_WITH_ID:\n                /* Intentional fall through */\n            case UriType.FileTransfer.FILE_TRANSFER_WITH_ID:\n                return CursorType.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalFileTransfer.FILE_TRANSFER_WITH_ID:\n                    String ftId = uri.getLastPathSegment();\n                    selection = getSelectionWithFtId(selection);\n                    selectionArgs = getSelectionArgsWithFtId(selectionArgs, ftId);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(FileTransferLog.CONTENT_URI, ftId));\n                    return cursor;\n\n                case UriType.InternalFileTransfer.FILE_TRANSFER:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            FileTransferLog.CONTENT_URI);\n                    return cursor;\n\n                case UriType.FileTransfer.FILE_TRANSFER_WITH_ID:\n                    ftId = uri.getLastPathSegment();\n                    selection = getSelectionWithFtId(selection);\n                    selectionArgs = getSelectionArgsWithFtId(selectionArgs, ftId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.FileTransfer.FILE_TRANSFER:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(TABLE,\n                            restrictProjectionToExternallyDefinedColumns(projection), selection,\n                            selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n\n            }\n        } /*\n           * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n           * exception.\n           */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        Uri notificationUri = FileTransferLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalFileTransfer.FILE_TRANSFER_WITH_ID:\n                String ftId = uri.getLastPathSegment();\n                selection = getSelectionWithFtId(selection);\n                selectionArgs = getSelectionArgsWithFtId(selectionArgs, ftId);\n                notificationUri = Uri.withAppendedPath(notificationUri, ftId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalFileTransfer.FILE_TRANSFER:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.FileTransfer.FILE_TRANSFER_WITH_ID:\n                /* Intentional fall through */\n            case UriType.FileTransfer.FILE_TRANSFER:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalFileTransfer.FILE_TRANSFER:\n                /* Intentional fall through */\n            case UriType.InternalFileTransfer.FILE_TRANSFER_WITH_ID:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String ftId = initialValues.getAsString(FileTransferData.KEY_FT_ID);\n                initialValues.put(FileTransferData.KEY_BASECOLUMN_ID, HistoryMemberBaseIdCreator\n                        .createUniqueId(getContext(), FileTransferData.HISTORYLOG_MEMBER_ID));\n                if (db.insert(TABLE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri.toString() + '!');\n                }\n                Uri notificationUri = Uri.withAppendedPath(FileTransferLog.CONTENT_URI, ftId);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.FileTransfer.FILE_TRANSFER_WITH_ID:\n                /* Intentional fall through */\n            case UriType.FileTransfer.FILE_TRANSFER:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        Uri notificationUri = FileTransferLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalFileTransfer.FILE_TRANSFER_WITH_ID:\n                String ftId = uri.getLastPathSegment();\n                selection = getSelectionWithFtId(selection);\n                selectionArgs = getSelectionArgsWithFtId(selectionArgs, ftId);\n                notificationUri = Uri.withAppendedPath(notificationUri, ftId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalFileTransfer.FILE_TRANSFER:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.FileTransfer.FILE_TRANSFER_WITH_ID:\n                /* Intentional fall through */\n            case UriType.FileTransfer.FILE_TRANSFER:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/FileTransferStateAndReasonCode.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\npublic class FileTransferStateAndReasonCode {\n\n    private final State mState;\n\n    private final ReasonCode mReasonCode;\n\n    public FileTransferStateAndReasonCode(State state, ReasonCode reasonCode) {\n        mState = state;\n        mReasonCode = reasonCode;\n    }\n\n    public State getState() {\n        return mState;\n    }\n\n    public ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupChatData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.GroupChat;\n\nimport android.net.Uri;\n\n/**\n * Chat data constants\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GroupChatData {\n    /**\n     * Database URIs\n     */\n    public static final Uri CONTENT_URI = Uri.parse(\"content://com.gsma.rcs.chat/groupchat\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = ChatLog.GroupChat.HISTORYLOG_MEMBER_ID;\n\n    /**\n     * Base column unique id\n     */\n    /* package private */static final String KEY_BASECOLUMN_ID = ChatLog.GroupChat.BASECOLUMN_ID;\n\n    /**\n     * Id for chat room\n     */\n    /* package private */static final String KEY_CHAT_ID = ChatLog.GroupChat.CHAT_ID;\n\n    /**\n     * State of chat room.\n     * \n     * @see GroupChat.State\n     */\n    /* package private */static final String KEY_STATE = ChatLog.GroupChat.STATE;\n\n    /**\n     * Reason code associated with the group chat state.\n     * \n     * @see GroupChat.ReasonCode\n     */\n    /* package private */static final String KEY_REASON_CODE = ChatLog.GroupChat.REASON_CODE;\n\n    /**\n     * Subject of the group chat room\n     */\n    /* package private */static final String KEY_SUBJECT = ChatLog.GroupChat.SUBJECT;\n\n    /**\n     * List of participants and associated status stored as a String parseable with the\n     * ChatLog.GroupChat.getParticipantInfos() method.\n     */\n    /* package private */static final String KEY_PARTICIPANTS = ChatLog.GroupChat.PARTICIPANTS;\n\n    /**\n     * Status direction of group chat\n     * \n     * @see RcsService.Direction\n     */\n    /* package private */static final String KEY_DIRECTION = ChatLog.GroupChat.DIRECTION;\n\n    /**\n     * Timestamp of the invitation\n     */\n    /* package private */static final String KEY_TIMESTAMP = ChatLog.GroupChat.TIMESTAMP;\n\n    /**\n     * ContactId formatted number of the inviter of the group chat or null if this is a group chat\n     * initiated by the local user (ie outgoing group chat).\n     */\n    /* package private */static final String KEY_CONTACT = ChatLog.GroupChat.CONTACT;\n\n    /**\n     * Column name\n     */\n    /* package private */static final String KEY_REJOIN_ID = \"rejoin_id\";\n\n    /**\n     * Column name : Departed by user\n     */\n    /* package private */static final String KEY_USER_ABORTION = \"user_abortion\";\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupChatDeleteTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.util.Set;\n\n/**\n * Deletion task for group chats.\n */\npublic class GroupChatDeleteTask extends DeleteTask.NotGrouped {\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatDeleteTask.class.getName());\n\n    private static final String SELECTION_GROUPDELIVERY_BY_CHATID = GroupDeliveryInfoData.KEY_CHAT_ID\n            + \"=?\";\n\n    private final ChatServiceImpl mChatService;\n\n    private final InstantMessagingService mImService;\n\n    /**\n     * Deletion of all group chats.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     */\n    public GroupChatDeleteTask(ChatServiceImpl chatService, InstantMessagingService imService,\n            LocalContentResolver contentResolver) {\n        super(contentResolver, GroupChatData.CONTENT_URI, GroupChatData.KEY_CHAT_ID, null);\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of a specific group chat.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param chatId the group chat id\n     */\n    public GroupChatDeleteTask(ChatServiceImpl chatService, InstantMessagingService imService,\n            LocalContentResolver contentResolver, String chatId) {\n        super(contentResolver, GroupChatData.CONTENT_URI, GroupChatData.KEY_CHAT_ID, null, chatId);\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    @Override\n    protected void onRowDelete(String chatId) throws PayloadException {\n        GroupChatSession session = mImService.getGroupChatSession(chatId);\n        if (session == null) {\n            mLocalContentResolver.delete(GroupDeliveryInfoData.CONTENT_URI,\n                    SELECTION_GROUPDELIVERY_BY_CHATID, new String[] {\n                        chatId\n                    });\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mLocalContentResolver.delete(GroupDeliveryInfoData.CONTENT_URI,\n                SELECTION_GROUPDELIVERY_BY_CHATID, new String[] {\n                    chatId\n                });\n    }\n\n    @Override\n    protected void onCompleted(Set<String> deletedIds) {\n        mChatService.broadcastGroupChatsDeleted(deletedIds);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupChatLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.util.SparseArray;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * This class interfaces the chat table\n */\npublic class GroupChatLog implements IGroupChatLog {\n\n    private static final String PARTICIPANT_INFO_PARTICIPANT_SEPARATOR = \",\";\n\n    private static final String PARTICIPANT_INFO_STATUS_SEPARATOR = \"=\";\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final static String SELECT_CHAT_ID_STATUS_REJECTED = GroupChatData.KEY_STATE + \"=\"\n            + State.ABORTED.toInt() + \" AND \" + GroupChatData.KEY_REASON_CODE + \"=\"\n            + ReasonCode.ABORTED_BY_USER.toInt() + \" AND \" + GroupChatData.KEY_USER_ABORTION + \"=\"\n            + UserAbortion.SERVER_NOT_NOTIFIED.toInt();\n\n    private static final String SELECT_ACTIVE_GROUP_CHATS = GroupChatData.KEY_STATE + \"=\"\n            + State.STARTED.toInt();\n\n    // @formatter:off\n    private static final String[] PROJECTION_GC_INFO = new String[] {\n        GroupChatData.KEY_CHAT_ID,\n        GroupChatData.KEY_REJOIN_ID,\n        GroupChatData.KEY_PARTICIPANTS,\n        GroupChatData.KEY_SUBJECT,\n        GroupChatData.KEY_TIMESTAMP\n    };\n    // @formatter:on\n\n    private static final String[] PROJECTION_GC_CHAT_ID = new String[] {\n        GroupChatData.KEY_CHAT_ID\n    };\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatLog.class.getSimpleName());\n\n    private static final int FIRST_COLUMN_IDX = 0;\n\n    private enum UserAbortion {\n\n        SERVER_NOTIFIED(0), SERVER_NOT_NOTIFIED(1);\n\n        private final int mValue;\n\n        private static SparseArray<UserAbortion> mValueToEnum = new SparseArray<>();\n        static {\n            for (UserAbortion entry : UserAbortion.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        UserAbortion(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param localContentResolver Local content resolver\n     */\n    /* package private */GroupChatLog(LocalContentResolver localContentResolver) {\n        mLocalContentResolver = localContentResolver;\n    }\n\n    /**\n     * Convert participants to string representation\n     * \n     * @param participants the participants\n     * @return the string with comma separated values of key pairs formatted as follows: \"key=value\"\n     */\n    private String generateEncodedParticipantInfos(Map<ContactId, ParticipantStatus> participants) {\n        StringBuilder builder = new StringBuilder();\n        int size = participants.size();\n        for (Map.Entry<ContactId, ParticipantStatus> participant : participants.entrySet()) {\n            builder.append(participant.getKey());\n            builder.append(PARTICIPANT_INFO_STATUS_SEPARATOR);\n            builder.append(participant.getValue().toInt());\n            if (--size != 0) {\n                builder.append(PARTICIPANT_INFO_PARTICIPANT_SEPARATOR);\n            }\n        }\n        return builder.toString();\n    }\n\n    /**\n     * Convert string representation of participants into participants\n     * \n     * @param participants the participants\n     * @return the participants and their individual status\n     */\n    private Map<ContactId, ParticipantStatus> parseEncodedParticipantInfos(String participants) {\n        String[] encodedParticipantInfos = participants\n                .split(PARTICIPANT_INFO_PARTICIPANT_SEPARATOR);\n        Map<ContactId, ParticipantStatus> participantInfos = new HashMap<>();\n        for (String encodedParticipantInfo : encodedParticipantInfos) {\n            String[] participantInfo = encodedParticipantInfo\n                    .split(PARTICIPANT_INFO_STATUS_SEPARATOR);\n            ContactId participant = ContactUtil.createContactIdFromTrustedData(participantInfo[0]);\n            ParticipantStatus status = ParticipantStatus.valueOf(Integer\n                    .parseInt(participantInfo[1]));\n            participantInfos.put(participant, status);\n        }\n        return participantInfos;\n    }\n\n    @Override\n    public void addGroupChat(String chatId, ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode,\n            Direction direction, long timestamp) {\n        String encodedParticipants = generateEncodedParticipantInfos(participants);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"addGroupChat; chatID=\" + chatId + \", subject=\" + subject + \", state=\"\n                    + state + \" reasonCode=\" + reasonCode + \", direction=\" + direction\n                    + \", timestamp=\" + timestamp + \", participants=\" + encodedParticipants);\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_CHAT_ID, chatId);\n        if (contact != null) {\n            values.put(GroupChatData.KEY_CONTACT, contact.toString());\n        }\n        values.put(GroupChatData.KEY_STATE, state.toInt());\n        values.put(GroupChatData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(GroupChatData.KEY_SUBJECT, subject);\n\n        values.put(GroupChatData.KEY_PARTICIPANTS, encodedParticipants);\n        values.put(GroupChatData.KEY_DIRECTION, direction.toInt());\n        values.put(GroupChatData.KEY_TIMESTAMP, timestamp);\n        values.put(GroupChatData.KEY_USER_ABORTION, UserAbortion.SERVER_NOTIFIED.toInt());\n        mLocalContentResolver.insert(GroupChatData.CONTENT_URI, values);\n    }\n\n    @Override\n    public void acceptGroupChatNextInvitation(String chatId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"acceptGroupChatNextInvitation (chatId=\" + chatId + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_USER_ABORTION, UserAbortion.SERVER_NOTIFIED.toInt());\n        mLocalContentResolver.update(Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId),\n                values, SELECT_CHAT_ID_STATUS_REJECTED, null);\n    }\n\n    @Override\n    public boolean setGroupChatParticipantsStateAndReasonCode(String chatId,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode) {\n        String encodedParticipants = generateEncodedParticipantInfos(participants);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setGCParticipantsStateAndReasonCode (chatId=\" + chatId\n                    + \") (participants=\" + encodedParticipants + \") (state=\" + state\n                    + \") (reasonCode=\" + reasonCode + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_PARTICIPANTS, encodedParticipants);\n        values.put(GroupChatData.KEY_STATE, state.toInt());\n        values.put(GroupChatData.KEY_REASON_CODE, reasonCode.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId), values, null, null) > 0;\n    }\n\n    @Override\n    public boolean setGroupChatStateAndReasonCode(String chatId, State state, ReasonCode reasonCode) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setGroupChatStateAndReasonCode (chatId=\" + chatId + \") (state=\" + state\n                    + \") (reasonCode=\" + reasonCode + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_STATE, state.toInt());\n        values.put(GroupChatData.KEY_REASON_CODE, reasonCode.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId), values, null, null) > 0;\n    }\n\n    @Override\n    public boolean setGroupChatParticipants(String chatId,\n            Map<ContactId, ParticipantStatus> participants) {\n        String encodedParticipants = generateEncodedParticipantInfos(participants);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"updateGroupChatParticipant (chatId=\" + chatId + \") (participants=\"\n                    + encodedParticipants + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_PARTICIPANTS, encodedParticipants);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId), values, null, null) > 0;\n    }\n\n    @Override\n    public boolean setGroupChatRejoinId(String chatId, String rejoinId, boolean updateStateToStarted) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Update group chat rejoin ID to \".concat(rejoinId));\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_REJOIN_ID, rejoinId);\n        if (updateStateToStarted) {\n            values.put(GroupChatData.KEY_STATE, State.STARTED.toInt());\n            values.put(GroupChatData.KEY_REASON_CODE, ReasonCode.UNSPECIFIED.toInt());\n        }\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId), values, null, null) > 0;\n    }\n\n    @Override\n    public GroupChatInfo getGroupChatInfo(String chatId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId);\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_GC_INFO, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            if (!cursor.moveToNext()) {\n                return null;\n            }\n            long timestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(GroupChatData.KEY_TIMESTAMP));\n            String subject = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GroupChatData.KEY_SUBJECT));\n            String rejoinId = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GroupChatData.KEY_REJOIN_ID));\n            Uri rejoinUri = rejoinId != null ? Uri.parse(rejoinId) : null;\n            Map<ContactId, ParticipantStatus> participants = parseEncodedParticipantInfos(cursor\n                    .getString(cursor.getColumnIndexOrThrow(GroupChatData.KEY_PARTICIPANTS)));\n            return new GroupChatInfo(rejoinUri, chatId, participants, subject, timestamp);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public Map<ContactId, ParticipantStatus> getParticipants(String chatId) {\n        Cursor cursor = getGroupChatData(GroupChatData.KEY_PARTICIPANTS, chatId);\n        if (cursor == null) {\n            return null;\n        }\n        return parseEncodedParticipantInfos(getDataAsString(cursor));\n    }\n\n    @Override\n    public Map<ContactId, ParticipantStatus> getParticipants(String chatId,\n            Set<ParticipantStatus> statuses) {\n        Map<ContactId, ParticipantStatus> participants = getParticipants(chatId);\n        if (participants == null) {\n            return null;\n        }\n        Map<ContactId, ParticipantStatus> matchingParticipants = new HashMap<>();\n        for (Map.Entry<ContactId, ParticipantStatus> participant : participants.entrySet()) {\n            ParticipantStatus status = participant.getValue();\n            if (statuses.contains(status)) {\n                matchingParticipants.put(participant.getKey(), status);\n            }\n        }\n        return matchingParticipants;\n    }\n\n    @Override\n    public boolean isGroupChatNextInviteRejected(String chatId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId);\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_GC_CHAT_ID,\n                    SELECT_CHAT_ID_STATUS_REJECTED, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            return cursor.moveToNext();\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Cursor getGroupChatData(String columnName, String chatId) {\n        String[] projection = new String[] {\n            columnName\n        };\n        Uri contentUri = Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, projection, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        if (!cursor.moveToNext()) {\n            CursorUtil.close(cursor);\n            return null;\n        }\n        return cursor;\n    }\n\n    private String getDataAsString(Cursor cursor) {\n        try {\n            return cursor.getString(FIRST_COLUMN_IDX);\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Integer getDataAsInteger(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getInt(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    public State getGroupChatState(String chatId) {\n        Cursor cursor = getGroupChatData(GroupChatData.KEY_STATE, chatId);\n        if (cursor == null) {\n            return null;\n        }\n        return State.valueOf(getDataAsInteger(cursor));\n    }\n\n    public ReasonCode getGroupChatReasonCode(String chatId) {\n        Cursor cursor = getGroupChatData(GroupChatData.KEY_REASON_CODE, chatId);\n        if (cursor == null) {\n            return null;\n        }\n        return ReasonCode.valueOf(getDataAsInteger(cursor));\n    }\n\n    @Override\n    public boolean setRejectNextGroupChatNextInvitation(String chatId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setRejectNextGroupChatNextInvitation (chatId=\" + chatId + \")\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(GroupChatData.KEY_USER_ABORTION, UserAbortion.SERVER_NOT_NOTIFIED.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId), values, null, null) > 0;\n    }\n\n    @Override\n    public Set<String> getChatIdsOfActiveGroupChatsForAutoRejoin() {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(GroupChatData.CONTENT_URI, PROJECTION_GC_CHAT_ID,\n                    SELECT_ACTIVE_GROUP_CHATS, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, GroupChatData.CONTENT_URI);\n            Set<String> activeGroupChats = new HashSet<>();\n            while (cursor.moveToNext()) {\n                String chatId = cursor.getString(FIRST_COLUMN_IDX);\n                activeGroupChats.add(chatId);\n            }\n            return activeGroupChats;\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public Cursor getGroupChatData(String chatId) {\n        Uri contentUri = Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        return cursor;\n    }\n\n    @Override\n    public boolean isGroupChatPersisted(String chatId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(GroupChatData.CONTENT_URI, chatId);\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_GC_CHAT_ID, null, null,\n                    null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            return cursor.moveToNext();\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupChatMessageDeleteTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.util.Set;\n\npublic class GroupChatMessageDeleteTask extends DeleteTask.GroupedByChatId {\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatMessageDeleteTask.class\n            .getName());\n\n    private static final String SELECTION_GROUP_CHATMESSAGES = MessageData.KEY_CHAT_ID + \"<>\"\n            + MessageData.KEY_CONTACT + \" OR \" + MessageData.KEY_CONTACT + \" IS NULL\";\n\n    private static final String SELECTION_CHATMESSAGES_BY_CHATID = MessageData.KEY_CHAT_ID + \"=?\";\n\n    private final ChatServiceImpl mChatService;\n\n    private final InstantMessagingService mImService;\n\n    /**\n     * Deletion of all group chat messages.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     */\n    public GroupChatMessageDeleteTask(ChatServiceImpl chatService,\n            InstantMessagingService imService, LocalContentResolver contentResolver) {\n        super(contentResolver, MessageData.CONTENT_URI, MessageData.KEY_MESSAGE_ID,\n                MessageData.KEY_CHAT_ID, SELECTION_GROUP_CHATMESSAGES);\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of all chat messages from the specified group chat id.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param chatId the chat id\n     */\n    public GroupChatMessageDeleteTask(ChatServiceImpl chatService,\n            InstantMessagingService imService, LocalContentResolver contentResolver, String chatId) {\n        super(contentResolver, MessageData.CONTENT_URI, MessageData.KEY_MESSAGE_ID,\n                MessageData.KEY_CHAT_ID, SELECTION_CHATMESSAGES_BY_CHATID, chatId);\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of a specific message.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param chatId the chat id (optional, can be null)\n     * @param messageId the message id\n     */\n    public GroupChatMessageDeleteTask(ChatServiceImpl chatService,\n            InstantMessagingService imService, LocalContentResolver contentResolver, String chatId,\n            String messageId) {\n        super(contentResolver, MessageData.CONTENT_URI, MessageData.KEY_MESSAGE_ID,\n                MessageData.KEY_CHAT_ID, null, messageId);\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    @Override\n    protected void onRowDelete(String chatId, String msgId) throws PayloadException {\n        if (isSingleRowDelete()) {\n            return;\n\n        }\n        ChatSession session = mImService.getGroupChatSession(chatId);\n        if (session == null) {\n            mChatService.removeGroupChat(chatId);\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mChatService.removeGroupChat(chatId);\n    }\n\n    @Override\n    protected void onCompleted(String chatId, Set<String> msgIds) {\n        mChatService.broadcastGroupChatMessagesDeleted(chatId, msgIds);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupChatPersistedStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.database.Cursor;\n\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * GroupChatPersistedStorageAccessor helps in retrieving persisted data related to a group chat from\n * the persisted storage. It can utilize caching for such data that will not be changed after\n * creation of the group chat to speed up consecutive access.\n */\npublic class GroupChatPersistedStorageAccessor {\n\n    private final String mChatId;\n\n    private final MessagingLog mMessagingLog;\n\n    private String mSubject;\n\n    private Direction mDirection;\n\n    private ContactId mContact;\n\n    private long mTimestamp;\n\n    private final RcsSettings mRcsSettings;\n\n    public GroupChatPersistedStorageAccessor(String chatId, MessagingLog messagingLog,\n            RcsSettings rcsSettings) {\n        mChatId = chatId;\n        mMessagingLog = messagingLog;\n        mRcsSettings = rcsSettings;\n    }\n\n    private void cacheData() {\n        Cursor cursor = null;\n        try {\n            cursor = mMessagingLog.getGroupChatData(mChatId);\n            if (!cursor.moveToNext()) {\n                throw new ServerApiPersistentStorageException(\"Data not found for group chat \"\n                        + mChatId);\n            }\n            mSubject = cursor.getString(cursor.getColumnIndexOrThrow(GroupChatData.KEY_SUBJECT));\n            mDirection = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(GroupChatData.KEY_DIRECTION)));\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GroupChatData.KEY_CONTACT));\n            if (contact != null) {\n                mContact = ContactUtil.createContactIdFromTrustedData(contact);\n            }\n            mTimestamp = cursor.getLong(cursor.getColumnIndexOrThrow(GroupChatData.KEY_TIMESTAMP));\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public Direction getDirection() {\n        /*\n         * Utilizing cache here as direction can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mDirection == null) {\n            cacheData();\n        }\n        return mDirection;\n    }\n\n    public State getState() {\n        State state = mMessagingLog.getGroupChatState(mChatId);\n        if (state == null) {\n            throw new ServerApiPersistentStorageException(\"State not found for group chat \"\n                    + mChatId);\n        }\n        return state;\n    }\n\n    public ReasonCode getReasonCode() {\n        ReasonCode reasonCode = mMessagingLog.getGroupChatReasonCode(mChatId);\n        if (reasonCode == null) {\n            throw new ServerApiPersistentStorageException(\"Reason code not found for group chat \"\n                    + mChatId);\n        }\n        return reasonCode;\n    }\n\n    public String getSubject() {\n        /*\n         * Utilizing cache here as subject can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mSubject == null) {\n            cacheData();\n        }\n        return mSubject;\n    }\n\n    public long getTimestamp() {\n        /*\n         * Utilizing cache here as timestamp can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mTimestamp == 0) {\n            cacheData();\n        }\n        return mTimestamp;\n    }\n\n    public ContactId getRemoteContact() {\n        /* Remote contact is null for outgoing group chat */\n        if (Direction.OUTGOING == getDirection()) {\n            return null;\n        }\n        /*\n         * Utilizing cache here as remote contact can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mContact == null) {\n            cacheData();\n        }\n        return mContact;\n    }\n\n    public Map<ContactId, ParticipantStatus> getParticipants() {\n        return mMessagingLog.getParticipants(mChatId);\n    }\n\n    public Map<ContactId, ParticipantStatus> getParticipants(Set<ParticipantStatus> statuses) {\n        return mMessagingLog.getParticipants(mChatId, statuses);\n    }\n\n    public int getMaxParticipants() {\n        return mRcsSettings.getMaxChatParticipants();\n    }\n\n    public boolean setStateAndReasonCode(State state, ReasonCode reasonCode) {\n        return mMessagingLog.setGroupChatStateAndReasonCode(mChatId, state, reasonCode);\n    }\n\n    public boolean setMessageStatusAndReasonCode(String msgId, Status status,\n            Content.ReasonCode reasonCode) {\n        return mMessagingLog.setChatMessageStatusAndReasonCode(msgId, status, reasonCode);\n    }\n\n    public boolean setMessageStatusDelivered(String msgId, long timestampDelivered) {\n        return mMessagingLog.setChatMessageStatusDelivered(msgId, timestampDelivered);\n    }\n\n    public boolean setMessageStatusDisplayed(String msgId, long timestampDisplayed) {\n        return mMessagingLog.setChatMessageStatusDisplayed(msgId, timestampDisplayed);\n    }\n\n    public boolean setGroupDeliveryInfoStatusAndReasonCode(String chatId, ContactId contact,\n            String msgId, GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n        return mMessagingLog.setGroupChatDeliveryInfoStatusAndReasonCode(chatId, contact, msgId,\n                status, reasonCode);\n    }\n\n    public boolean isDeliveredToAllRecipients(String msgId) {\n        return mMessagingLog.isDeliveredToAllRecipients(msgId);\n    }\n\n    public boolean isDisplayedByAllRecipients(String msgId) {\n        return mMessagingLog.isDisplayedByAllRecipients(msgId);\n    }\n\n    public boolean setRejoinId(String rejoinId, boolean updateStateToStarted) {\n        return mMessagingLog.setGroupChatRejoinId(mChatId, rejoinId, updateStateToStarted);\n    }\n\n    public void addGroupChat(ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode,\n            Direction direction, long timestamp) {\n        mContact = contact;\n        mSubject = subject;\n        mDirection = direction;\n        mTimestamp = timestamp;\n        mMessagingLog.addGroupChat(mChatId, contact, subject, participants, state, reasonCode,\n                direction, timestamp);\n    }\n\n    public void addGroupChatEvent(ContactId contact, GroupChatEvent.Status status, long timestamp) {\n        mContact = contact;\n        mTimestamp = timestamp;\n        mMessagingLog.addGroupChatEvent(mChatId, contact, status, timestamp);\n    }\n\n    public void addIncomingGroupChatMessage(ChatMessage msg, boolean imdnDisplayedRequested) {\n        mMessagingLog.addIncomingGroupChatMessage(mChatId, msg, imdnDisplayedRequested);\n    }\n\n    public void addOutgoingGroupChatMessage(ChatMessage msg, Set<ContactId> recipients,\n            Status status, Content.ReasonCode reasonCode) {\n        mMessagingLog.addOutgoingGroupChatMessage(mChatId, msg, recipients, status, reasonCode);\n    }\n\n    public boolean setRejectNextGroupChatNextInvitation() {\n        return mMessagingLog.setRejectNextGroupChatNextInvitation(mChatId);\n    }\n\n    public boolean setParticipantsStateAndReasonCode(\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode) {\n        return mMessagingLog.setGroupChatParticipantsStateAndReasonCode(mChatId, participants,\n                state, reasonCode);\n    }\n\n    public boolean setGroupChatDeliveryInfoDelivered(String chatId, ContactId contact,\n            String msgId, long timestampDelivered) {\n        return mMessagingLog.setGroupChatDeliveryInfoDelivered(chatId, contact, msgId,\n                timestampDelivered);\n    }\n\n    public boolean setDeliveryInfoDisplayed(String chatId, ContactId contact, String msgId,\n            long timestampDisplayed) {\n        return mMessagingLog.setGroupChatDeliveryInfoDisplayed(chatId, contact, msgId,\n                timestampDisplayed);\n    }\n\n    public void addGroupChatFailedDeliveryMessage(ChatMessage msg) {\n        mMessagingLog.addGroupChatFailedDeliveryMessage(mChatId, msg);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupDeliveryInfoData.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfoLog;\n\nimport android.net.Uri;\n\n/**\n * Delivery info data constants\n */\n/* package private */class GroupDeliveryInfoData {\n\n    /* package private */static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.groupdeliveryinfo/groupdeliveryinfo\");\n\n    /* package private */static final String KEY_STATUS = GroupDeliveryInfoLog.STATUS;\n\n    /* package private */static final String KEY_BASECOLUMN_ID = GroupDeliveryInfoLog.BASECOLUMN_ID;\n\n    /* package private */static final String KEY_REASON_CODE = GroupDeliveryInfoLog.REASON_CODE;\n\n    /* package private */static final String KEY_ID = GroupDeliveryInfoLog.ID;\n\n    /* package private */static final String KEY_CHAT_ID = GroupDeliveryInfoLog.CHAT_ID;\n\n    /* package private */static final String KEY_CONTACT = GroupDeliveryInfoLog.CONTACT;\n\n    /* package private */static final String KEY_TIMESTAMP_DELIVERED = GroupDeliveryInfoLog.TIMESTAMP_DELIVERED;\n\n    /* package private */static final String KEY_TIMESTAMP_DISPLAYED = GroupDeliveryInfoLog.TIMESTAMP_DISPLAYED;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupDeliveryInfoLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * Class to interface the deliveryinfo table\n */\npublic class GroupDeliveryInfoLog implements IGroupDeliveryInfoLog {\n\n    private static final String SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT = GroupDeliveryInfoData.KEY_ID\n            + \"=? AND \" + GroupDeliveryInfoData.KEY_CONTACT + \"=?\";\n\n    private static final String SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT_EXCLUDE_DISPLAYED = GroupDeliveryInfoData.KEY_ID\n            + \"=? AND \"\n            + GroupDeliveryInfoData.KEY_CONTACT\n            + \"=?\"\n            + \" AND \"\n            + GroupDeliveryInfoData.KEY_STATUS + \"<>\" + Status.DISPLAYED.toInt();\n\n    private static final String SELECTION_CONTACTS_NOT_RECEIVED_MESSAGE = GroupDeliveryInfoData.KEY_STATUS\n            + \"=\"\n            + Status.NOT_DELIVERED.toInt()\n            + \" OR (\"\n            + GroupDeliveryInfoData.KEY_STATUS\n            + \"=\"\n            + Status.FAILED.toInt()\n            + \" AND \"\n            + GroupDeliveryInfoData.KEY_REASON_CODE\n            + \" IN (\"\n            + ReasonCode.FAILED_DELIVERY.toInt() + \",\" + ReasonCode.FAILED_DISPLAY.toInt() + \"))\";\n\n    private static final String SELECTION_DELIVERY_INFO_NOT_DISPLAYED = GroupDeliveryInfoData.KEY_STATUS\n            + \"<>\" + Status.DISPLAYED.toInt();\n\n    private static final String[] PROJECTION_MESSAGE_ID = new String[] {\n        GroupDeliveryInfoData.KEY_ID\n    };\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    /**\n     * Constructor\n     * \n     * @param localContentResolver Local content resolver\n     */\n    /* package private */GroupDeliveryInfoLog(LocalContentResolver localContentResolver) {\n        mLocalContentResolver = localContentResolver;\n    }\n\n    @Override\n    public Uri addGroupChatDeliveryInfoEntry(String chatId, ContactId contact, String msgId,\n            Status status, ReasonCode reasonCode, long timestampDelivered, long timestampDisplayed) {\n        ContentValues values = new ContentValues();\n        values.put(GroupDeliveryInfoData.KEY_CHAT_ID, chatId);\n        values.put(GroupDeliveryInfoData.KEY_ID, msgId);\n        values.put(GroupDeliveryInfoData.KEY_CONTACT, contact.toString());\n        values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());\n        values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DELIVERED, timestampDelivered);\n        values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);\n        return mLocalContentResolver.insert(GroupDeliveryInfoData.CONTENT_URI, values);\n    }\n\n    /**\n     * Set delivery status for outgoing group chat messages and files. Note that this method should\n     * not be used for Status.DELIVERED and Status.DISPLAYED. These states require timestamps and\n     * should be set through setGroupChatDeliveryInfoDisplayed and setGroupChatDeliveryInfoDisplayed\n     * respectively.\n     * \n     * @param chatId Group chat ID\n     * @param contact The contact ID for which the entry is to be updated\n     * @param msgId Message ID\n     * @param status Status\n     * @param reasonCode Reason code\n     * @return true if an entry was updated, otherwise false\n     */\n    public boolean setGroupChatDeliveryInfoStatusAndReasonCode(String chatId, ContactId contact,\n            String msgId, Status status, ReasonCode reasonCode) {\n        ContentValues values = new ContentValues();\n        values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());\n        values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reasonCode.toInt());\n        String[] selectionArgs = new String[] {\n                msgId, contact.toString()\n        };\n\n        switch (status) {\n            case DELIVERED:\n            case DISPLAYED:\n                throw new IllegalArgumentException(\"Status that requires \"\n                        + \"timestamp passed, use specific method taking timestamp\"\n                        + \" to set status \" + status.toString());\n            default:\n        }\n\n        return (mLocalContentResolver.update(GroupDeliveryInfoData.CONTENT_URI, values,\n                SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT, selectionArgs) >= 1);\n    }\n\n    @Override\n    public boolean isDeliveredToAllRecipients(String msgId) {\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(\n                    Uri.withAppendedPath(GroupDeliveryInfoData.CONTENT_URI, msgId), null,\n                    SELECTION_CONTACTS_NOT_RECEIVED_MESSAGE, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, GroupDeliveryInfoData.CONTENT_URI);\n            return !cursor.moveToFirst();\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public boolean isDisplayedByAllRecipients(String msgId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(GroupDeliveryInfoData.CONTENT_URI, msgId);\n            cursor = mLocalContentResolver.query(contentUri, null,\n                    SELECTION_DELIVERY_INFO_NOT_DISPLAYED, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            return !cursor.moveToFirst();\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Set outgoing group chat message or file to delivered\n     * \n     * @param chatId Group chat ID\n     * @param contact The contact ID for which the entry is to be updated\n     * @param msgId Message ID\n     * @param timestampDelivered Time for delivery\n     */\n    public boolean setGroupChatDeliveryInfoDelivered(String chatId, ContactId contact,\n            String msgId, long timestampDelivered) {\n        GroupDeliveryInfo.Status status = GroupDeliveryInfo.Status.DELIVERED;\n        GroupDeliveryInfo.ReasonCode reason = GroupDeliveryInfo.ReasonCode.UNSPECIFIED;\n\n        ContentValues values = new ContentValues();\n        values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());\n        values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DELIVERED, timestampDelivered);\n        values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reason.toInt());\n        String[] selectionArgs = new String[] {\n                msgId, contact.toString()\n        };\n\n        if (mLocalContentResolver.update(GroupDeliveryInfoData.CONTENT_URI, values,\n                SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT_EXCLUDE_DISPLAYED, selectionArgs) > 0) {\n            /* A matching GDI row was found and updated. */\n            return true;\n        }\n\n        Cursor cursor = null;\n        try {\n            Uri contentUri = GroupDeliveryInfoData.CONTENT_URI;\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_MESSAGE_ID,\n                    SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT, selectionArgs, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            if (cursor.getCount() < 1) {\n                /*\n                 * No entry updated means that there was no matching row. Adding row and setting\n                 * displayed timestamp to 0.\n                 */\n                addGroupChatDeliveryInfoEntry(chatId, contact, msgId, status, reason,\n                        timestampDelivered, 0);\n                return true;\n            }\n            /*\n             * A matching row was found but since it was not already updated above we can assume it\n             * shouldn't be updated.\n             */\n            return false;\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public boolean setGroupChatDeliveryInfoDisplayed(String chatId, ContactId contact,\n            String msgId, long timestampDisplayed) {\n        ContentValues values = new ContentValues();\n        GroupDeliveryInfo.Status status = GroupDeliveryInfo.Status.DISPLAYED;\n        GroupDeliveryInfo.ReasonCode reason = GroupDeliveryInfo.ReasonCode.UNSPECIFIED;\n\n        values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());\n        values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);\n        values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reason.toInt());\n        String[] selectionArgs = new String[] {\n                msgId, contact.toString()\n        };\n\n        if (mLocalContentResolver.update(GroupDeliveryInfoData.CONTENT_URI, values,\n                SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT, selectionArgs) < 1) {\n            /*\n             * No entry updated means that there was no matching row. Adding row and setting\n             * delivered timestamp to same as displayed timestamp. This is the most reasonable value\n             * we can set at this point.\n             */\n            addGroupChatDeliveryInfoEntry(chatId, contact, msgId, status, reason,\n                    timestampDisplayed, timestampDisplayed);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupDeliveryInfoProvider.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * All rights, including trade secret rights, reserved.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.provider.ContentProviderBaseIdCreator;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfoLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\n/**\n * Group Delivery info provider of chat and file messages\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class GroupDeliveryInfoProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String DATABASE_TABLE = \"groupdeliveryinfo\";\n\n    private static final String SELECTION_WITH_ID_ONLY = GroupDeliveryInfoData.KEY_ID.concat(\"=?\");\n\n    public static final String DATABASE_NAME = \"groupdeliveryinfo.db\";\n\n    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n    static {\n        sUriMatcher.addURI(GroupDeliveryInfoData.CONTENT_URI.getAuthority(),\n                GroupDeliveryInfoData.CONTENT_URI.getPath().substring(1),\n                UriType.InternalGroupDeliveryInfo.DELIVERY);\n        sUriMatcher.addURI(GroupDeliveryInfoData.CONTENT_URI.getAuthority(),\n                GroupDeliveryInfoData.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.InternalGroupDeliveryInfo.DELIVERY_WITH_ID);\n        sUriMatcher.addURI(GroupDeliveryInfoLog.CONTENT_URI.getAuthority(),\n                GroupDeliveryInfoLog.CONTENT_URI.getPath().substring(1),\n                UriType.GroupDeliveryInfo.DELIVERY);\n        sUriMatcher.addURI(GroupDeliveryInfoLog.CONTENT_URI.getAuthority(),\n                GroupDeliveryInfoLog.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.GroupDeliveryInfo.DELIVERY_WITH_ID);\n    }\n\n    private static final class UriType {\n\n        private static final class GroupDeliveryInfo {\n            private static final int DELIVERY = 1;\n\n            private static final int DELIVERY_WITH_ID = 2;\n        }\n\n        private static final class InternalGroupDeliveryInfo {\n            private static final int DELIVERY = 3;\n\n            private static final int DELIVERY_WITH_ID = 4;\n        }\n    }\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/com.gsma.services.rcs.provider.groupdeliveryinfo\";\n\n        private static final String TYPE_ITEM = \"vnd.android.cursor.item/com.gsma.services.rcs.provider.groupdeliveryinfo\";\n    }\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n\n        private static final int DATABASE_VERSION = 4;\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + DATABASE_TABLE + '('\n                    + GroupDeliveryInfoData.KEY_CHAT_ID + \" TEXT NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_ID + \" TEXT NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_CONTACT + \" TEXT NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_STATUS + \" INTEGER NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_TIMESTAMP_DELIVERED + \" INTEGER NOT NULL,\"\n                    + GroupDeliveryInfoData.KEY_TIMESTAMP_DISPLAYED + \" INTEGER NOT NULL, \"\n                    + \"PRIMARY KEY(\" + GroupDeliveryInfoData.KEY_ID + ',' + GroupDeliveryInfoData.KEY_CONTACT + \"))\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + GroupDeliveryInfoData.KEY_BASECOLUMN_ID + \"_idx\" + \" ON \"\n                    + DATABASE_TABLE + '(' + GroupDeliveryInfoData.KEY_BASECOLUMN_ID + ')');\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(DATABASE_TABLE));\n            onCreate(db);\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithAppendedId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithAppendedId(String[] selectionArgs, String appendedId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(appendedId, selectionArgs);\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGroupDeliveryInfo.DELIVERY:\n                /* Intentional fall through */\n            case UriType.GroupDeliveryInfo.DELIVERY:\n                return CursorType.TYPE_ITEM;\n\n            case UriType.InternalGroupDeliveryInfo.DELIVERY_WITH_ID:\n                /* Intentional fall through */\n            case UriType.GroupDeliveryInfo.DELIVERY_WITH_ID:\n                return CursorType.TYPE_DIRECTORY;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalGroupDeliveryInfo.DELIVERY_WITH_ID:\n                    String appendedId = uri.getLastPathSegment();\n                    selection = getSelectionWithAppendedId(selection);\n                    selectionArgs = getSelectionArgsWithAppendedId(selectionArgs, appendedId);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(DATABASE_TABLE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(GroupDeliveryInfoLog.CONTENT_URI, appendedId));\n                    return cursor;\n\n                case UriType.InternalGroupDeliveryInfo.DELIVERY:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(DATABASE_TABLE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            GroupDeliveryInfoLog.CONTENT_URI);\n                    return cursor;\n\n                case UriType.GroupDeliveryInfo.DELIVERY_WITH_ID:\n                    appendedId = uri.getLastPathSegment();\n                    selection = getSelectionWithAppendedId(selection);\n                    selectionArgs = getSelectionArgsWithAppendedId(selectionArgs, appendedId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.GroupDeliveryInfo.DELIVERY:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db.query(DATABASE_TABLE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n        }\n        /*\n         * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n         * exception.\n         */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGroupDeliveryInfo.DELIVERY:\n                /* Intentional fall through */\n            case UriType.InternalGroupDeliveryInfo.DELIVERY_WITH_ID:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String appendedId = initialValues.getAsString(GroupDeliveryInfoData.KEY_ID);\n                initialValues.put(GroupDeliveryInfoData.KEY_BASECOLUMN_ID,\n                        ContentProviderBaseIdCreator.createUniqueId(getContext(),\n                                GroupDeliveryInfoData.CONTENT_URI));\n                if (db.insert(DATABASE_TABLE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri.toString() + '!');\n                }\n                Uri notificationUri = Uri.withAppendedPath(GroupDeliveryInfoLog.CONTENT_URI,\n                        appendedId);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.GroupDeliveryInfo.DELIVERY:\n                /* Intentional fall through */\n            case UriType.GroupDeliveryInfo.DELIVERY_WITH_ID:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        Uri notificationUri = GroupDeliveryInfoLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGroupDeliveryInfo.DELIVERY_WITH_ID:\n                String appendedId = uri.getLastPathSegment();\n                selection = getSelectionWithAppendedId(selection);\n                selectionArgs = getSelectionArgsWithAppendedId(selectionArgs, appendedId);\n                notificationUri = Uri.withAppendedPath(notificationUri, appendedId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalGroupDeliveryInfo.DELIVERY:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(DATABASE_TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.GroupDeliveryInfo.DELIVERY_WITH_ID:\n                /* Intentional fall through */\n            case UriType.GroupDeliveryInfo.DELIVERY:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        Uri notificationUri = GroupDeliveryInfoLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGroupDeliveryInfo.DELIVERY_WITH_ID:\n                String appendedId = uri.getLastPathSegment();\n                selection = getSelectionWithAppendedId(selection);\n                selectionArgs = getSelectionArgsWithAppendedId(selectionArgs, appendedId);\n                notificationUri = Uri.withAppendedPath(notificationUri, appendedId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalGroupDeliveryInfo.DELIVERY:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(DATABASE_TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.GroupDeliveryInfo.DELIVERY_WITH_ID:\n                /* Intentional fall through */\n            case UriType.GroupDeliveryInfo.DELIVERY:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/GroupFileTransferDeleteTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.util.Set;\n\npublic class GroupFileTransferDeleteTask extends DeleteTask.GroupedByChatId {\n\n    private static final Logger sLogger = Logger.getLogger(GroupFileTransferDeleteTask.class\n            .getName());\n\n    private static final String SELECTION_ALL_GROUP_FILETRANSFERS = FileTransferData.KEY_CHAT_ID\n            + \"<>\" + FileTransferData.KEY_CONTACT + \" OR \" + FileTransferData.KEY_CONTACT\n            + \" IS NULL\";\n\n    private static final String SELECTION_FILETRANSFER_BY_CHATID = FileTransferData.KEY_CHAT_ID\n            + \"=?\";\n\n    private final FileTransferServiceImpl mFileTransferService;\n\n    private final InstantMessagingService mImService;\n\n    /**\n     * Deletion of all group file transfers.\n     * \n     * @param fileTransferService the file transfer service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     */\n    public GroupFileTransferDeleteTask(FileTransferServiceImpl fileTransferService,\n            InstantMessagingService imService, LocalContentResolver contentResolver) {\n        super(contentResolver, FileTransferData.CONTENT_URI, FileTransferData.KEY_FT_ID,\n                FileTransferData.KEY_CHAT_ID, SELECTION_ALL_GROUP_FILETRANSFERS);\n        mFileTransferService = fileTransferService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of all file transfers that belong to the specified group chat.\n     * \n     * @param fileTransferService the file transfer service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param chatId the chat id\n     */\n    public GroupFileTransferDeleteTask(FileTransferServiceImpl fileTransferService,\n            InstantMessagingService imService, LocalContentResolver contentResolver, String chatId) {\n        super(contentResolver, FileTransferData.CONTENT_URI, FileTransferData.KEY_FT_ID,\n                FileTransferData.KEY_CHAT_ID, SELECTION_FILETRANSFER_BY_CHATID, chatId);\n        mFileTransferService = fileTransferService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of a specific file transfer.\n     * \n     * @param fileTransferService the file transfer service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param chatId the chat id\n     * @param transferId the transfer id\n     */\n    public GroupFileTransferDeleteTask(FileTransferServiceImpl fileTransferService,\n            InstantMessagingService imService, LocalContentResolver contentResolver, String chatId,\n            String transferId) {\n        super(contentResolver, FileTransferData.CONTENT_URI, FileTransferData.KEY_FT_ID,\n                FileTransferData.KEY_CHAT_ID, null, transferId);\n        mFileTransferService = fileTransferService;\n        mImService = imService;\n    }\n\n    @Override\n    protected void onRowDelete(String chatId, String transferId) throws PayloadException {\n        FileSharingSession session = mImService.getFileSharingSession(transferId);\n        if (session == null) {\n            mFileTransferService.ensureThumbnailIsDeleted(transferId);\n            mFileTransferService.ensureFileCopyIsDeletedIfExisting(transferId);\n            mFileTransferService.removeGroupFileTransfer(transferId);\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mFileTransferService.ensureThumbnailIsDeleted(transferId);\n        mFileTransferService.ensureFileCopyIsDeletedIfExisting(transferId);\n        mFileTransferService.removeGroupFileTransfer(transferId);\n    }\n\n    @Override\n    protected void onCompleted(String chatId, Set<String> transferIds) {\n        mFileTransferService.broadcastGroupFileTransfersDeleted(chatId, transferIds);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/IFileTransferLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Interface for the ft table\n * \n * @author LEMORDANT Philippe\n */\npublic interface IFileTransferLog {\n\n    /**\n     * Add one to one file transfer\n     * \n     * @param fileTransferId File Transfer ID\n     * @param contact Contact ID\n     * @param direction Direction\n     * @param content File content\n     * @param fileIcon File icon content\n     * @param state File transfer state\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp for both incoming and outgoing file transfer for one-one\n     *            chat\n     * @param timestampSent Timestamp sent in payload for both incoming and outgoing file transfer\n     *            for one-one chat\n     * @param fileExpiration the time when file on the content server is no longer valid to\n     *            download.\n     * @param fileIconExpiration the time when file icon on the content server is no longer valid to\n     *            download.\n     */\n    void addOneToOneFileTransfer(String fileTransferId, ContactId contact, Direction direction,\n            MmContent content, MmContent fileIcon, State state, ReasonCode reasonCode,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration);\n\n    /**\n     * Add an outgoing File Transfer supported by Group Chat\n     * \n     * @param fileTransferId the identity of the file transfer\n     * @param chatId the identity of the group chat\n     * @param content the File content\n     * @param fileIcon the fileIcon content\n     * @param recipients the recipients\n     * @param state File transfer state\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp for outgoing file transfer for a group chat\n     * @param timestampSent Timestamp sent in payload for outgoing file transfer for a group chat\n     */\n    void addOutgoingGroupFileTransfer(String fileTransferId, String chatId, MmContent content,\n            MmContent fileIcon, Set<ContactId> recipients, State state, ReasonCode reasonCode,\n            long timestamp, long timestampSent);\n\n    /**\n     * Add incoming group file transfer\n     * \n     * @param fileTransferId File transfer ID\n     * @param chatId Chat ID\n     * @param contact Contact ID\n     * @param content File content\n     * @param fileIcon File icon contentID\n     * @param state File transfer state\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp for incoming file transfer for a group chat\n     * @param timestampSent Timestamp sent in payload for incoming file transfer for a group chat\n     * @param fileExpiration the time when file on the content server is no longer valid to\n     *            download.\n     * @param fileIconExpiration the time when file icon on the content server is no longer valid to\n     *            download.\n     */\n    void addIncomingGroupFileTransfer(String fileTransferId, String chatId, ContactId contact,\n            MmContent content, MmContent fileIcon, State state, ReasonCode reasonCode,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration);\n\n    /**\n     * Set file transfer state and reason code. Note that this method should not be used for\n     * State.DELIVERED and State.DISPLAYED. These states require timestamps and should be set\n     * through setFileTransferDelivered and setFileTransferDisplayed respectively.\n     * \n     * @param fileTransferId File transfer ID\n     * @param state File transfer state (see restriction above)\n     * @param reasonCode File transfer state reason code\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferStateAndReasonCode(String fileTransferId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Set file transfer state, reason code, timestamp and timestampSent\n     * \n     * @param fileTransferId File transfer ID\n     * @param state New file transfer state\n     * @param reasonCode New file transfer reason code\n     * @param timestamp New local timestamp for the file transfer\n     * @param timestampSent New timestamp sent in payload for the file transfer\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferStateAndTimestamp(String fileTransferId, State state,\n            ReasonCode reasonCode, long timestamp, long timestampSent);\n\n    /**\n     * Update file transfer read status\n     * \n     * @param fileTransferId File transfer ID\n     * @param timestampDisplayed Time displayed\n     * @return the number of rows affected\n     */\n    int markFileTransferAsRead(String fileTransferId, long timestampDisplayed);\n\n    /**\n     * Update file transfer download progress\n     * \n     * @param fileTransferId File transfer ID\n     * @param currentSize Current size\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferProgress(String fileTransferId, long currentSize);\n\n    /**\n     * Set file transfer URI\n     * \n     * @param fileTransferId File transfer ID\n     * @param content the MmContent of received file\n     * @param fileExpiration the time when file on the content server is no longer valid to download\n     * @param fileIconExpiration the time when file icon on the content server is no longer valid to\n     *            download\n     * @param deliveryExpiration delivery expiration\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferred(String fileTransferId, MmContent content, long fileExpiration,\n            long fileIconExpiration, long deliveryExpiration);\n\n    /**\n     * Tells if the MessageID corresponds to that of a file transfer\n     * \n     * @param fileTransferId File Transfer Id\n     * @return boolean If there is File Transfer corresponding to msgId\n     */\n    boolean isFileTransfer(String fileTransferId);\n\n    /**\n     * Returns the icon for a file transfer\n     * \n     * @param fileTransferId the file transfer ID\n     * @return the icon or null if there s none\n     */\n    Uri getFileTransferIcon(String fileTransferId);\n\n    /**\n     * Set file upload TID\n     * \n     * @param fileTransferId File transfer ID\n     * @param tId TID\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileUploadTId(String fileTransferId, String tId);\n\n    /**\n     * Set file download server uri\n     * \n     * @param fileTransferId File transfer ID\n     * @param downloadAddress Download Address\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileDownloadAddress(String fileTransferId, Uri downloadAddress);\n\n    /**\n     * Retrieve file transfers paused by SYSTEM on connection loss\n     * \n     * @return list of FtHttpResume\n     */\n    List<FtHttpResume> retrieveFileTransfersPausedBySystem();\n\n    /**\n     * Retrieve resumable file upload\n     * \n     * @param tId Unique Id used while uploading\n     * @return instance of FtHttpResumeUpload\n     */\n    FtHttpResumeUpload retrieveFtHttpResumeUpload(String tId);\n\n    /**\n     * Get the Uri for a file transfer with specific id\n     * \n     * @param fileTransferId specific id\n     * @return Uri Uri of the file\n     */\n    Uri getFile(String fileTransferId);\n\n    /**\n     * Get DIrection of file transfer with specific id\n     * \n     * @param fileTransferId specific id\n     * @return Direction Direction of file transfer\n     */\n    Direction getFileTransferDirection(String fileTransferId);\n\n    /**\n     * Get the chat id for a file transfer with specific id\n     * \n     * @param fileTransferId specific id\n     * @return chat id\n     */\n    String getFileTransferChatId(String fileTransferId);\n\n    /**\n     * Get file transfer state from its unique ID\n     * \n     * @param fileTransferId Unique ID of file transfer\n     * @return State\n     */\n    State getFileTransferState(String fileTransferId);\n\n    /**\n     * Get file transfer reason code from its unique ID\n     * \n     * @param fileTransferId Unique ID of file transfer\n     * @return reason code on the file transfer\n     */\n    ReasonCode getFileTransferReasonCode(String fileTransferId);\n\n    /**\n     * Get file transfer data from its unique ID\n     * \n     * @param fileTransferId the file transfer ID\n     * @return Cursor or null if no data exists\n     */\n    Cursor getFileTransferData(String fileTransferId);\n\n    /**\n     * Is group file transfer\n     * \n     * @param fileTransferId the file transfer ID\n     * @return true if it is group file transfer\n     */\n    boolean isGroupFileTransfer(String fileTransferId);\n\n    /**\n     * Get file transfer timestamp from file transfer Id\n     * \n     * @param fileTransferId the file transfer ID\n     * @return timestamp\n     */\n    Long getFileTransferTimestamp(String fileTransferId);\n\n    /**\n     * Get file transfer sent timestamp from file transfer Id\n     * \n     * @param fileTransferId the file transfer ID\n     * @return sent timestamp\n     */\n    Long getFileTransferSentTimestamp(String fileTransferId);\n\n    /**\n     * Get file transfer resume info from its corresponding filetransferId\n     * \n     * @param fileTransferId the file transfer ID\n     * @return FtHttpResume\n     */\n    FtHttpResume getFileTransferResumeInfo(String fileTransferId);\n\n    /**\n     * Get all one-to-one and group file transfers that are queued and uploaded but not transferred\n     * in ascending order of timestamp\n     * \n     * @return Cursor\n     */\n    Cursor getQueuedAndUploadedButNotTransferredFileTransfers();\n\n    /**\n     * Get interrupted file transfers\n     * \n     * @return Cursor\n     */\n    Cursor getInterruptedFileTransfers();\n\n    /**\n     * Sets remote SIP Instance identifier for download HTTP file transfer\n     * \n     * @param fileTransferId the file transfer ID\n     * @param remoteInstanceId the remote instance ID\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setRemoteSipId(String fileTransferId, String remoteInstanceId);\n\n    /**\n     * Set file transfer delivered\n     * \n     * @param fileTransferId File transfer ID\n     * @param timestampDelivered Time delivered\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferDelivered(String fileTransferId, long timestampDelivered);\n\n    /**\n     * Set file transfer displayed\n     * \n     * @param fileTransferId File transfer ID\n     * @param timestampDisplayed Time displayed\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferDisplayed(String fileTransferId, long timestampDisplayed);\n\n    /**\n     * Marks undelivered file transfers to indicate that transfers have been processed.\n     * \n     * @param fileTransferIds the file transfer IDs\n     */\n    void clearFileTransferDeliveryExpiration(List<String> fileTransferIds);\n\n    /**\n     * Set file transfer delivery expired for specified file transfer id.\n     * \n     * @param fileTransferId the file transfer ID\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileTransferDeliveryExpired(String fileTransferId);\n\n    /**\n     * Get one-one file transfers with unexpired delivery\n     * \n     * @return Cursor\n     */\n    Cursor getUnDeliveredOneToOneFileTransfers();\n\n    /**\n     * Returns true if delivery for this file has expired or false otherwise. Note: false means\n     * either that delivery for this file has not yet expired, delivery has been successful,\n     * delivery expiration has been cleared (see clearFileTransferDeliveryExpiration) or that this\n     * particular file is not eligible for delivery expiration in the first place.\n     * \n     * @param fileTransferId the file transfer ID\n     * @return boolean\n     */\n    Boolean isFileTransferExpiredDelivery(String fileTransferId);\n\n    /**\n     * Set file transfer download info in DB\n     * \n     * @param fileTransferId the file transfer ID\n     * @param ftHttpInfo the file transfer HTTP information\n     */\n    void setFileTransferDownloadInfo(String fileTransferId, FileTransferHttpInfoDocument ftHttpInfo);\n\n    /**\n     * Get file download info\n     * \n     * @param fileTransferId the file transfer ID\n     * @return FileTransferHttpInfoDocument\n     * @throws FileAccessException\n     */\n    FileTransferHttpInfoDocument getFileDownloadInfo(String fileTransferId)\n            throws FileAccessException;\n\n    /**\n     * Get file download info\n     * \n     * @param cursor the cursor\n     * @return FileTransferHttpInfoDocument\n     * @throws FileAccessException\n     */\n    FileTransferHttpInfoDocument getFileDownloadInfo(Cursor cursor) throws FileAccessException;\n\n    /**\n     * Set file transfer timestamp and timestampSent\n     * \n     * @param fileTransferId File transfer ID\n     * @param timestamp New local timestamp for the file transfer\n     * @param timestampSent New timestamp sent in payload for the file transfer\n     */\n    void setFileTransferTimestamps(String fileTransferId, long timestamp, long timestampSent);\n\n    /**\n     * Set file info dequeued successfully.\n     * \n     * @param fileTransferId the file transfer ID\n     * @param deliveryExpiration the delivery expiration\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setFileInfoDequeued(String fileTransferId, long deliveryExpiration);\n\n    /**\n     * Gets the number of transferred bytes\n     * \n     * @param fileTransferId the file transfer ID\n     * @return the number of transferred bytes\n     */\n    Long getFileTransferProgress(String fileTransferId);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/IGroupChatLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.database.Cursor;\n\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Interface for the chat table\n * \n * @author LEMORDANT Philippe\n */\npublic interface IGroupChatLog {\n\n    /**\n     * Add group chat session\n     * \n     * @param chatId Chat ID\n     * @param contact Contact ID\n     * @param subject Subject\n     * @param participants map of participants and associated status\n     * @param state State\n     * @param reasonCode ReasonCode\n     * @param direction Direction\n     * @param timestamp Timestamp\n     */\n    void addGroupChat(String chatId, ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode,\n            Direction direction, long timestamp);\n\n    /**\n     * Accept next Group Chat invitation\n     * \n     * @param chatId Chat ID of the group chat\n     */\n    void acceptGroupChatNextInvitation(String chatId);\n\n    /**\n     * Set group chat state and reason code\n     * \n     * @param chatId Chat ID\n     * @param state Group chat state\n     * @param reasonCode Group chat state reason code\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatStateAndReasonCode(String chatId, State state, ReasonCode reasonCode);\n\n    /**\n     * Set group chat participants, state and reason code\n     * \n     * @param chatId Chat ID\n     * @param participants map of participants and associated status\n     * @param state Group chat state\n     * @param reasonCode Group chat state reason code\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatParticipantsStateAndReasonCode(String chatId,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode);\n\n    /**\n     * Set group chat participants\n     * \n     * @param chatId Chat ID\n     * @param participants map of participants and associated status\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatParticipants(String chatId, Map<ContactId, ParticipantStatus> participants);\n\n    /**\n     * Set group chat rejoin ID\n     * \n     * @param chatId Chat ID\n     * @param rejoinId Rejoin ID\n     * @param updateStateToStarted True if session state must be updated to started\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatRejoinId(String chatId, String rejoinId, boolean updateStateToStarted);\n\n    /**\n     * Get the group chat info\n     * \n     * @param chatId Chat ID\n     * @return Group chat info\n     */\n    GroupChatInfo getGroupChatInfo(String chatId);\n\n    /**\n     * Is next group chat Invitation rejected\n     * \n     * @param chatId Chat ID\n     * @return true if next GC invitation should be rejected\n     */\n    boolean isGroupChatNextInviteRejected(String chatId);\n\n    /**\n     * Set reject the next group chat invitation\n     * \n     * @param chatId Chat ID\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setRejectNextGroupChatNextInvitation(String chatId);\n\n    /**\n     * Get group chat state from its chat ID\n     * \n     * @param chatId Chat ID of the group chat\n     * @return State\n     */\n    State getGroupChatState(String chatId);\n\n    /**\n     * Get group chat state reason code from its chat ID\n     * \n     * @param chatId Chat ID of the group chat\n     * @return Reason code of the state\n     */\n    ReasonCode getGroupChatReasonCode(String chatId);\n\n    /**\n     * Get group chat participants from its chat ID\n     * \n     * @param chatId Chat ID of the group chat\n     * @return all group chat participants\n     */\n    Map<ContactId, ParticipantStatus> getParticipants(String chatId);\n\n    /**\n     * Get group chat participants from its chat ID\n     * \n     * @param chatId Chat ID of the group chat\n     * @param statuses participant status to match\n     * @return all group chat participants matching any of the specified participant statuses\n     */\n    Map<ContactId, ParticipantStatus> getParticipants(String chatId, Set<ParticipantStatus> statuses);\n\n    /**\n     * Get group chat data from its chat ID\n     * \n     * @param chatId Chat ID of the group chat\n     * @return Cursor or null if no data exists\n     */\n    Cursor getGroupChatData(String chatId);\n\n    /**\n     * Retrieve all active group chats for auto-rejoin\n     * \n     * @return Set of chat IDs of those group chats that has to be auto-rejoined\n     */\n    Set<String> getChatIdsOfActiveGroupChatsForAutoRejoin();\n\n    /**\n     * Checks if group chat is persisted\n     * \n     * @param chatId Chat ID of the group chat\n     * @return true if group chat is persisted\n     */\n    boolean isGroupChatPersisted(String chatId);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/IGroupDeliveryInfoLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status;\n\nimport android.net.Uri;\n\n/**\n * Interface for the deliveryinfo table\n * \n * @author LEMORDANT Philippe\n */\npublic interface IGroupDeliveryInfoLog {\n\n    /**\n     * Add a new entry (chat message or file transfer)\n     * \n     * @param chatId Chat ID of a chat session\n     * @param contact Contact phone identifier\n     * @param msgId Message ID of a chat message\n     * @param status Delivery info status\n     * @param reasonCode Delivery info status reason code\n     * @param timestampDisplayed Timestamp for display\n     * @param timestampDelivered Timestamp for delivery\n     */\n    Uri addGroupChatDeliveryInfoEntry(String chatId, ContactId contact, String msgId,\n            Status status, ReasonCode reasonCode, long timestampDisplayed, long timestampDelivered);\n\n    /**\n     * Set delivery status for outgoing group chat messages and files\n     * \n     * @param chatId Group chat ID\n     * @param contact The contact ID for which the entry is to be updated\n     * @param msgId Message ID\n     * @param status Delivery info status\n     * @param reasonCode Delivery info status reason code\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatDeliveryInfoStatusAndReasonCode(String chatId, ContactId contact,\n            String msgId, Status status, ReasonCode reasonCode);\n\n    /**\n     * Check if all recipients have received message\n     * \n     * @param msgId Message ID\n     * @return true If it is last contact to receive message\n     */\n    boolean isDeliveredToAllRecipients(String msgId);\n\n    /**\n     * Check if all recipients have displayed message\n     * \n     * @param msgId Message ID\n     * @return true If it is last contact to display message\n     */\n    boolean isDisplayedByAllRecipients(String msgId);\n\n    /**\n     * Set delivery info status to delivered for outgoing group chat message or file\n     * \n     * @param chatId Group chat ID\n     * @param contact The contact ID for which the entry is to be updated\n     * @param msgId Message ID\n     * @param timestampDelivered Timestamp for message delivery\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatDeliveryInfoDelivered(String chatId, ContactId contact, String msgId,\n            long timestampDelivered);\n\n    /**\n     * Set delivery info status to displayed for outgoing group chat message or file\n     * \n     * @param chatId Group chat ID\n     * @param contact The contact ID for which the entry is to be updated\n     * @param msgId Message ID\n     * @param timestampDisplayed Timestamp for message display\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setGroupChatDeliveryInfoDisplayed(String chatId, ContactId contact, String msgId,\n            long timestampDisplayed);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/IMessageLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.database.Cursor;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Interface for the message table\n * \n * @author LEMORDANT Philippe\n */\npublic interface IMessageLog {\n\n    /**\n     * Add a spam message\n     * \n     * @param msg Chat message\n     */\n    void addOneToOneSpamMessage(ChatMessage msg);\n\n    /**\n     * Add a chat message\n     * \n     * @param msg Chat message\n     * @param imdnDisplayedRequested IMDN display report requested\n     */\n    void addIncomingOneToOneChatMessage(ChatMessage msg, boolean imdnDisplayedRequested);\n\n    /**\n     * Add a chat message\n     * \n     * @param msg Chat message\n     * @param status Message status\n     * @param reasonCode Status reason code\n     * @param deliveryExpiration TODO\n     */\n    void addOutgoingOneToOneChatMessage(ChatMessage msg, Status status, ReasonCode reasonCode,\n            long deliveryExpiration);\n\n    /**\n     * Add an incoming group chat message\n     * \n     * @param chatId Chat ID\n     * @param msg Chat message\n     * @param imdnDisplayedRequested IMDN display report requested\n     */\n    void addIncomingGroupChatMessage(String chatId, ChatMessage msg, boolean imdnDisplayedRequested);\n\n    /**\n     * Add an outgoing group chat message\n     * \n     * @param chatId Chat ID\n     * @param msg Chat message\n     * @param recipients the set of recipients\n     * @param status Message status\n     * @param reasonCode Status reason code\n     */\n    void addOutgoingGroupChatMessage(String chatId, ChatMessage msg, Set<ContactId> recipients,\n            Status status, ReasonCode reasonCode);\n\n    /**\n     * Add group chat system message\n     * \n     * @param chatId Chat ID\n     * @param contact Contact ID\n     * @param status Status\n     * @param timestamp Local timestamp when got group chat notification\n     * @return the message ID created for the group chat system event\n     */\n    String addGroupChatEvent(String chatId, ContactId contact, GroupChatEvent.Status status,\n            long timestamp);\n\n    /**\n     * Update chat message read status\n     * \n     * @param msgId message ID\n     * @param timestampDisplayed Displayed time\n     * @return the number of rows affected.\n     */\n    int markMessageAsRead(String msgId, long timestampDisplayed);\n\n    /**\n     * Set chat message status and reason code. Note that this method should not be used for\n     * Status.DELIVERED and Status.DISPLAYED. These states require timestamps and should be set\n     * through setChatMessageStatusDelivered and setChatMessageStatusDisplayed respectively.\n     * \n     * @param msgId message ID\n     * @param status Message status (See restriction above)\n     * @param reasonCode Message status reason code\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setChatMessageStatusAndReasonCode(String msgId, Status status, ReasonCode reasonCode);\n\n    /**\n     * Check if the message is already persisted in db\n     * \n     * @param msgId message ID\n     * @return true if the message already exists in db\n     */\n    boolean isMessagePersisted(String msgId);\n\n    /**\n     * Check if the message is read by remote contact\n     * \n     * @param msgId message ID\n     * @return true if read, false if unread and null if record is not found\n     */\n    Boolean isMessageRead(String msgId);\n\n    /**\n     * Returns the timestamp_sent of a message\n     * \n     * @param msgId message ID\n     * @return timestamp_sent\n     */\n    Long getMessageSentTimestamp(String msgId);\n\n    /**\n     * Returns the timestamp of a message\n     * \n     * @param msgId message ID\n     * @return timestamp\n     */\n    Long getMessageTimestamp(String msgId);\n\n    /**\n     * Get message state from its unique ID\n     * \n     * @param msgId message ID\n     * @return State\n     */\n    Status getMessageStatus(String msgId);\n\n    /**\n     * Get message reason code from its unique ID\n     * \n     * @param msgId message ID\n     * @return reason code of the state\n     */\n    ReasonCode getMessageReasonCode(String msgId);\n\n    /**\n     * Get message MIME-type from its unique ID\n     * \n     * @param msgId message ID\n     * @return MIME-type\n     */\n    String getMessageMimeType(String msgId);\n\n    /**\n     * Get message data from its unique ID\n     * \n     * @param msgId message ID\n     * @return Cursor or null if no data exists\n     */\n    Cursor getChatMessageData(String msgId);\n\n    /**\n     * Get all one-to-one chat messages for specific contact that are in queued state in ascending\n     * order of timestamp\n     * \n     * @param contact Contact ID\n     * @return Cursor\n     */\n    Cursor getQueuedOneToOneChatMessages(ContactId contact);\n\n    /**\n     * Gets group chat events per contacts for chat ID\n     * \n     * @param chatId Chat ID\n     * @return group chat events for contacts or null if there is no group chat events\n     */\n    Map<ContactId, GroupChatEvent.Status> getGroupChatEvents(String chatId);\n\n    /**\n     * Returns true if the chat id and contact are same for this message id.\n     * \n     * @param messageId the message id\n     * @return true if the message belongs to one to one conversation\n     */\n    boolean isOneToOneChatMessage(String messageId);\n\n    /**\n     * Set chat message delivered\n     * \n     * @param msgId message ID\n     * @param timestampDelivered Delivered time\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setChatMessageStatusDelivered(String msgId, long timestampDelivered);\n\n    /**\n     * Set chat message displayed\n     * \n     * @param msgId message ID\n     * @param timestampDisplayed Displayed time\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setChatMessageStatusDisplayed(String msgId, long timestampDisplayed);\n\n    /**\n     * Marks undelivered chat messages to indicate that messages have been processed.\n     * \n     * @param msgIds List of message IDs\n     */\n    void clearMessageDeliveryExpiration(List<String> msgIds);\n\n    /**\n     * Set message delivery expired for specified message id.\n     * \n     * @param msgId message ID\n     * @return True if an entry was updated, otherwise false\n     */\n    boolean setChatMessageDeliveryExpired(String msgId);\n\n    /**\n     * Get one-one chat messages with unexpired delivery\n     * \n     * @return Cursor\n     */\n    Cursor getUndeliveredOneToOneChatMessages();\n\n    /**\n     * Returns true if delivery for this chat message has expired or false otherwise. Note: false\n     * means either that delivery for this chat message has not yet expired, delivery has been\n     * successful, delivery expiration has been cleared (see clearMessageDeliveryExpiration) or that\n     * this particular chat message is not eligible for delivery expiration in the first place.\n     * \n     * @param msgId message ID\n     * @return boolean\n     */\n    Boolean isChatMessageExpiredDelivery(String msgId);\n\n    /**\n     * Get chat id for chat message\n     * \n     * @param msgId message ID\n     * @return ChatId\n     */\n    String getMessageChatId(String msgId);\n\n    /**\n     * Set chat message status and sent timestamp for outgoing messages\n     * \n     * @param msgId message ID\n     * @param status Message status\n     * @param reasonCode Message status reason code\n     * @param timestamp New local timestamp\n     * @param timestampSent New timestamp sent in payload\n     * @return boolean\n     */\n    boolean setChatMessageStatusAndTimestamp(String msgId, Status status, ReasonCode reasonCode,\n            long timestamp, long timestampSent);\n\n    /**\n     * Add a one to one chat message for which delivery report has failed\n     * \n     * @param msg Chat message\n     */\n    void addOneToOneFailedDeliveryMessage(ChatMessage msg);\n\n    /**\n     * Add a group chat message for which delivery report has failed\n     * \n     * @param chatId the chat ID\n     * @param msg Chat message\n     */\n    void addGroupChatFailedDeliveryMessage(String chatId, ChatMessage msg);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/MessageData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\n\nimport android.net.Uri;\n\n/**\n * Message data constants\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MessageData {\n    /**\n     * Database URIs\n     */\n    public static final Uri CONTENT_URI = Uri.parse(\"content://com.gsma.rcs.chat/chatmessage\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = ChatLog.Message.HISTORYLOG_MEMBER_ID;\n\n    /**\n     * Unique history ID\n     */\n    /* package private */static final String KEY_BASECOLUMN_ID = ChatLog.Message.BASECOLUMN_ID;\n\n    /**\n     * Id of chat room\n     */\n    /* package private */static final String KEY_CHAT_ID = ChatLog.Message.CHAT_ID;\n\n    /**\n     * ContactId formatted number of remote contact or null if the message is an outgoing group chat\n     * message.\n     */\n    /* package private */static final String KEY_CONTACT = ChatLog.Message.CONTACT;\n\n    /**\n     * Id of the message\n     */\n    /* package private */static final String KEY_MESSAGE_ID = ChatLog.Message.MESSAGE_ID;\n\n    /**\n     * Content of the message (as defined by one of the mimetypes in ChatLog.Message.Mimetype)\n     */\n    /* package private */static final String KEY_CONTENT = ChatLog.Message.CONTENT;\n\n    /**\n     * Multipurpose Internet Mail Extensions (MIME) type of message\n     */\n    /* package private */static final String KEY_MIME_TYPE = ChatLog.Message.MIME_TYPE;\n\n    /**\n     * Status direction of message.\n     * \n     * @see Direction\n     */\n    /* package private */static final String KEY_DIRECTION = ChatLog.Message.DIRECTION;\n\n    /**\n     * @see Status\n     */\n    /* package private */static final String KEY_STATUS = ChatLog.Message.STATUS;\n\n    /**\n     * Reason code associated with the message status.\n     * \n     * @see ReasonCode\n     */\n    /* package private */static final String KEY_REASON_CODE = ChatLog.Message.REASON_CODE;\n\n    /**\n     * This is set on the receiver side when the message has been displayed.\n     * \n     * @see RcsService.ReadStatus for the list of status.\n     */\n    /* package private */static final String KEY_READ_STATUS = ChatLog.Message.READ_STATUS;\n\n    /**\n     * Time when message inserted\n     */\n    /* package private */static final String KEY_TIMESTAMP = ChatLog.Message.TIMESTAMP;\n\n    /**\n     * Time when message sent. If 0 means not sent.\n     */\n    /* package private */static final String KEY_TIMESTAMP_SENT = ChatLog.Message.TIMESTAMP_SENT;\n\n    /**\n     * Time when message delivered. If 0 means not delivered\n     */\n    /* package private */static final String KEY_TIMESTAMP_DELIVERED = ChatLog.Message.TIMESTAMP_DELIVERED;\n\n    /**\n     * Time when message displayed. If 0 means not displayed.\n     */\n    /* package private */static final String KEY_TIMESTAMP_DISPLAYED = ChatLog.Message.TIMESTAMP_DISPLAYED;\n\n    /**\n     * If delivery has expired for this message. Values: 1 (true), 0 (false)\n     */\n    /* package private */static final String KEY_EXPIRED_DELIVERY = ChatLog.Message.EXPIRED_DELIVERY;\n\n    /**\n     * Time when message delivery time-out will expire or 0 if this message is not eligible for\n     * delivery expiration.\n     */\n    /* package private */static final String KEY_DELIVERY_EXPIRATION = \"delivery_expiration\";\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/MessageLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Class to interface the message table\n */\npublic class MessageLog implements IMessageLog {\n\n    private LocalContentResolver mLocalContentResolver;\n\n    private GroupDeliveryInfoLog mGroupChatDeliveryInfoLog;\n\n    private final RcsSettings mRcsSettings;\n\n    private static final Logger sLogger = Logger.getLogger(MessageLog.class.getSimpleName());\n\n    private static final String[] PROJECTION_MESSAGE_ID = new String[] {\n        MessageData.KEY_MESSAGE_ID\n    };\n\n    private static final String[] PROJECTION_GROUP_CHAT_EVENTS = new String[] {\n            MessageData.KEY_STATUS, MessageData.KEY_CONTACT\n    };\n\n    private static final String SELECTION_GROUP_CHAT_EVENTS = MessageData.KEY_CHAT_ID + \"=? AND \"\n            + MessageData.KEY_MIME_TYPE + \"='\" + MimeType.GROUPCHAT_EVENT + \"' GROUP BY \"\n            + MessageData.KEY_CONTACT;\n\n    private static final int FIRST_COLUMN_IDX = 0;\n\n    private static final String SELECTION_QUEUED_ONETOONE_CHAT_MESSAGES = MessageData.KEY_CHAT_ID\n            + \"=? AND \" + MessageData.KEY_STATUS + \"=\" + Status.QUEUED.toInt();\n\n    private static final int CHAT_MESSAGE_DELIVERY_EXPIRED = 1;\n\n    private static final int CHAT_MESSAGE_DELIVERY_EXPIRATION_NOT_APPLICABLE = 0;\n\n    private static final String SELECTION_BY_UNDELIVERED_ONETOONE_CHAT_MESSAGES = MessageData.KEY_EXPIRED_DELIVERY\n            + \"<>\"\n            + CHAT_MESSAGE_DELIVERY_EXPIRED\n            + \" AND \"\n            + MessageData.KEY_DELIVERY_EXPIRATION\n            + \"<>\"\n            + CHAT_MESSAGE_DELIVERY_EXPIRATION_NOT_APPLICABLE\n            + \" AND \"\n            + MessageData.KEY_STATUS\n            + \" NOT IN(\"\n            + Status.DELIVERED.toInt()\n            + \",\"\n            + Status.DISPLAYED.toInt() + \")\";\n    private static final String SELECTION_BY_UNDELIVERED_STATUS = MessageData.KEY_STATUS\n            + \" NOT IN(\" + Status.DELIVERED.toInt() + \",\" + Status.DISPLAYED.toInt() + \")\";\n\n    private static final String ORDER_BY_TIMESTAMP_ASC = MessageData.KEY_TIMESTAMP.concat(\" ASC\");\n\n    private static final String SELECTION_BY_NOT_DISPLAYED = MessageData.KEY_STATUS + \"<>\"\n            + Status.DISPLAYED.toInt();\n\n    private static final String SELECTION_BY_NOT_READ = MessageData.KEY_READ_STATUS + \"=\"\n            + ReadStatus.UNREAD.toInt();\n\n    /**\n     * Constructor\n     * \n     * @param localContentResolver Local content resolver\n     * @param groupChatDeliveryInfoLog the GC delivery information\n     * @param rcsSettings the RCS settings accessor\n     */\n    /* package private */MessageLog(LocalContentResolver localContentResolver,\n            GroupDeliveryInfoLog groupChatDeliveryInfoLog, RcsSettings rcsSettings) {\n        mLocalContentResolver = localContentResolver;\n        mGroupChatDeliveryInfoLog = groupChatDeliveryInfoLog;\n        mRcsSettings = rcsSettings;\n    }\n\n    private void addIncomingOneToOneMessage(ChatMessage msg, Status status, ReasonCode reasonCode) {\n        ContactId contact = msg.getRemoteContact();\n        String msgId = msg.getMessageId();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add incoming chat message: contact=\" + contact + \", msg=\" + msgId\n                    + \", status=\" + status + \", reasonCode=\" + reasonCode + \".\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_CHAT_ID, contact.toString());\n        values.put(MessageData.KEY_MESSAGE_ID, msgId);\n        values.put(MessageData.KEY_CONTACT, contact.toString());\n        values.put(MessageData.KEY_DIRECTION, Direction.INCOMING.toInt());\n        values.put(MessageData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(MessageData.KEY_MIME_TYPE, msg.getMimeType());\n        values.put(MessageData.KEY_CONTENT, msg.getContent());\n        values.put(MessageData.KEY_TIMESTAMP, msg.getTimestamp());\n        values.put(MessageData.KEY_TIMESTAMP_SENT, msg.getTimestampSent());\n        values.put(MessageData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(MessageData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(MessageData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        values.put(MessageData.KEY_STATUS, status.toInt());\n        values.put(MessageData.KEY_REASON_CODE, reasonCode.toInt());\n        mLocalContentResolver.insert(MessageData.CONTENT_URI, values);\n    }\n\n    @Override\n    public void addOutgoingOneToOneChatMessage(ChatMessage msg, Status status,\n            ReasonCode reasonCode, long deliveryExpiration) {\n        ContactId contact = msg.getRemoteContact();\n        String msgId = msg.getMessageId();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add outgoing chat message: contact=\" + contact + \", msg=\" + msgId\n                    + \", status=\" + status + \", reasonCode=\" + reasonCode + \".\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_CHAT_ID, contact.toString());\n        values.put(MessageData.KEY_MESSAGE_ID, msgId);\n        values.put(MessageData.KEY_CONTACT, contact.toString());\n        values.put(MessageData.KEY_DIRECTION, Direction.OUTGOING.toInt());\n        values.put(MessageData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(MessageData.KEY_MIME_TYPE, msg.getMimeType());\n        values.put(MessageData.KEY_CONTENT, msg.getContent());\n        values.put(MessageData.KEY_TIMESTAMP, msg.getTimestamp());\n        values.put(MessageData.KEY_TIMESTAMP_SENT, msg.getTimestampSent());\n        values.put(MessageData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(MessageData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(MessageData.KEY_DELIVERY_EXPIRATION, deliveryExpiration);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        values.put(MessageData.KEY_STATUS, status.toInt());\n        values.put(MessageData.KEY_REASON_CODE, reasonCode.toInt());\n        mLocalContentResolver.insert(MessageData.CONTENT_URI, values);\n    }\n\n    @Override\n    public void addOneToOneSpamMessage(ChatMessage msg) {\n        addIncomingOneToOneMessage(msg, Status.REJECTED, ReasonCode.REJECTED_SPAM);\n    }\n\n    @Override\n    public void addOneToOneFailedDeliveryMessage(ChatMessage msg) {\n        addIncomingOneToOneMessage(msg, Status.FAILED, ReasonCode.FAILED_DELIVERY);\n    }\n\n    @Override\n    public void addIncomingOneToOneChatMessage(ChatMessage msg, boolean imdnDisplayedRequested) {\n        if (imdnDisplayedRequested) {\n            addIncomingOneToOneMessage(msg, Status.DISPLAY_REPORT_REQUESTED, ReasonCode.UNSPECIFIED);\n        } else {\n            addIncomingOneToOneMessage(msg, Status.RECEIVED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void addIncomingGroupChatMessage(String chatId, ChatMessage msg,\n            boolean imdnDisplayedRequested) {\n        Status chatMessageStatus = imdnDisplayedRequested ? Status.DISPLAY_REPORT_REQUESTED\n                : Status.RECEIVED;\n        addGroupChatMessage(chatId, msg, Direction.INCOMING, null, chatMessageStatus,\n                ReasonCode.UNSPECIFIED);\n    }\n\n    @Override\n    public void addOutgoingGroupChatMessage(String chatId, ChatMessage msg,\n            Set<ContactId> recipients, Status status, ReasonCode reasonCode) {\n        addGroupChatMessage(chatId, msg, Direction.OUTGOING, recipients, status, reasonCode);\n    }\n\n    /**\n     * Add group chat message\n     * \n     * @param chatId Chat ID\n     * @param msg Chat message\n     * @param direction Direction\n     * @param status Status\n     * @param reasonCode Reason code\n     */\n    private void addGroupChatMessage(String chatId, ChatMessage msg, Direction direction,\n            Set<ContactId> recipients, Status status, ReasonCode reasonCode) {\n        String msgId = msg.getMessageId();\n        ContactId contact = msg.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add group chat message; chatId=\" + chatId + \", msg=\" + msgId + \", dir=\"\n                    + direction + \", contact=\" + contact + \".\");\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_CHAT_ID, chatId);\n        values.put(MessageData.KEY_MESSAGE_ID, msgId);\n        if (contact != null) {\n            values.put(MessageData.KEY_CONTACT, contact.toString());\n        }\n        values.put(MessageData.KEY_DIRECTION, direction.toInt());\n        values.put(MessageData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(MessageData.KEY_STATUS, status.toInt());\n        values.put(MessageData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(MessageData.KEY_MIME_TYPE, msg.getMimeType());\n        values.put(MessageData.KEY_CONTENT, msg.getContent());\n        values.put(MessageData.KEY_TIMESTAMP, msg.getTimestamp());\n        values.put(MessageData.KEY_TIMESTAMP_SENT, msg.getTimestampSent());\n        values.put(MessageData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(MessageData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(MessageData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        mLocalContentResolver.insert(MessageData.CONTENT_URI, values);\n        if (Direction.OUTGOING == direction) {\n            try {\n                GroupDeliveryInfo.Status deliveryStatus = GroupDeliveryInfo.Status.NOT_DELIVERED;\n                if (mRcsSettings.isAlbatrosRelease()) {\n                    deliveryStatus = GroupDeliveryInfo.Status.UNSUPPORTED;\n                }\n                for (ContactId recipient : recipients) {\n                    /* Add entry with delivered and displayed timestamps set to 0. */\n                    mGroupChatDeliveryInfoLog.addGroupChatDeliveryInfoEntry(chatId, recipient,\n                            msgId, deliveryStatus, GroupDeliveryInfo.ReasonCode.UNSPECIFIED, 0, 0);\n                }\n            } catch (Exception e) {\n                mLocalContentResolver.delete(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                        null, null);\n                mLocalContentResolver.delete(\n                        Uri.withAppendedPath(GroupDeliveryInfoData.CONTENT_URI, msgId), null, null);\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Group chat message with msgId '\" + msgId\n                            + \"' could not be added to database!\");\n                }\n            }\n        }\n    }\n\n    @Override\n    public String addGroupChatEvent(String chatId, ContactId contact, GroupChatEvent.Status status,\n            long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add group chat system message: chatID=\" + chatId + \", contact=\"\n                    + contact + \", status=\" + status);\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_CHAT_ID, chatId);\n        if (contact != null) {\n            values.put(MessageData.KEY_CONTACT, contact.toString());\n        }\n        String msgId = IdGenerator.generateMessageID();\n        values.put(MessageData.KEY_MESSAGE_ID, msgId);\n        values.put(MessageData.KEY_MIME_TYPE, MimeType.GROUPCHAT_EVENT);\n        values.put(MessageData.KEY_STATUS, status.toInt());\n        values.put(MessageData.KEY_REASON_CODE, ReasonCode.UNSPECIFIED.toInt());\n        values.put(MessageData.KEY_DIRECTION, Direction.IRRELEVANT.toInt());\n        values.put(MessageData.KEY_READ_STATUS, ReadStatus.UNREAD.toInt());\n        values.put(MessageData.KEY_TIMESTAMP, timestamp);\n        values.put(MessageData.KEY_TIMESTAMP_SENT, timestamp);\n        values.put(MessageData.KEY_TIMESTAMP_DELIVERED, 0);\n        values.put(MessageData.KEY_TIMESTAMP_DISPLAYED, 0);\n        values.put(MessageData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        mLocalContentResolver.insert(MessageData.CONTENT_URI, values);\n        return msgId;\n    }\n\n    @Override\n    public int markMessageAsRead(String msgId, long timestampDisplayed) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Mark chat message as read ID=\" + msgId);\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_READ_STATUS, ReadStatus.READ.toInt());\n        values.put(MessageData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);\n        return mLocalContentResolver.update(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                values, SELECTION_BY_NOT_READ, null);\n    }\n\n    @Override\n    public boolean setChatMessageStatusAndReasonCode(String msgId, Status status,\n            ReasonCode reasonCode) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Update chat message: msgId=\" + msgId + \", status=\" + status\n                    + \", reasonCode=\" + reasonCode);\n        }\n        switch (status) {\n            case DELIVERED:\n            case DISPLAYED:\n                throw new IllegalArgumentException(\"Status that requires \"\n                        + \"timestamp passed, use specific method taking timestamp\"\n                        + \" to set status \" + status.toString());\n            default:\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_STATUS, status.toInt());\n        values.put(MessageData.KEY_REASON_CODE, reasonCode.toInt());\n        return mLocalContentResolver.update(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                values, SELECTION_BY_UNDELIVERED_STATUS, null) > 0;\n    }\n\n    @Override\n    public boolean isMessagePersisted(String msgId) {\n        Cursor cursor = null;\n        Uri contentUri = Uri.withAppendedPath(MessageData.CONTENT_URI, msgId);\n        try {\n            cursor = mLocalContentResolver.query(contentUri, PROJECTION_MESSAGE_ID, null, null,\n                    null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            return cursor.moveToNext();\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Cursor getMessageData(String columnName, String msgId) {\n        String[] projection = new String[] {\n            columnName\n        };\n        Uri contentUri = Uri.withAppendedPath(MessageData.CONTENT_URI, msgId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, projection, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        if (!cursor.moveToNext()) {\n            CursorUtil.close(cursor);\n            return null;\n        }\n        return cursor;\n    }\n\n    private Integer getDataAsInteger(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getInt(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Long getDataAsLong(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getLong(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private String getDataAsString(Cursor cursor) {\n        try {\n            return cursor.getString(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Boolean getDataAsBoolean(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getInt(FIRST_COLUMN_IDX) == 1;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public Boolean isMessageRead(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_READ_STATUS, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return (getDataAsInteger(cursor) == ReadStatus.READ.toInt());\n    }\n\n    @Override\n    public Long getMessageSentTimestamp(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_TIMESTAMP_SENT, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    @Override\n    public Long getMessageTimestamp(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_TIMESTAMP, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    @Override\n    public Status getMessageStatus(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_STATUS, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return Status.valueOf(getDataAsInteger(cursor));\n    }\n\n    @Override\n    public ReasonCode getMessageReasonCode(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_REASON_CODE, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return ReasonCode.valueOf(getDataAsInteger(cursor));\n    }\n\n    @Override\n    public String getMessageMimeType(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_MIME_TYPE, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsString(cursor);\n    }\n\n    @Override\n    public String getMessageChatId(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_CHAT_ID, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsString(cursor);\n    }\n\n    @Override\n    public Boolean isChatMessageExpiredDelivery(String msgId) {\n        Cursor cursor = getMessageData(MessageData.KEY_EXPIRED_DELIVERY, msgId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsBoolean(cursor);\n    }\n\n    @Override\n    public Cursor getChatMessageData(String msgId) {\n        Uri contentUri = Uri.withAppendedPath(MessageData.CONTENT_URI, msgId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        return cursor;\n    }\n\n    @Override\n    public Cursor getQueuedOneToOneChatMessages(ContactId contact) {\n        String[] selectionArgs = new String[] {\n            contact.toString()\n        };\n        Cursor cursor = mLocalContentResolver.query(MessageData.CONTENT_URI, null,\n                SELECTION_QUEUED_ONETOONE_CHAT_MESSAGES, selectionArgs, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, MessageData.CONTENT_URI);\n        return cursor;\n    }\n\n    @Override\n    public Map<ContactId, GroupChatEvent.Status> getGroupChatEvents(String chatId) {\n        String[] selectionArgs = new String[] {\n            chatId\n        };\n        Cursor cursor = null;\n        try {\n            cursor = mLocalContentResolver.query(MessageData.CONTENT_URI,\n                    PROJECTION_GROUP_CHAT_EVENTS, SELECTION_GROUP_CHAT_EVENTS, selectionArgs,\n                    ORDER_BY_TIMESTAMP_ASC);\n            CursorUtil.assertCursorIsNotNull(cursor, MessageData.CONTENT_URI);\n            if (!cursor.moveToNext()) {\n                return Collections.emptyMap();\n            }\n            Map<ContactId, GroupChatEvent.Status> groupChatEvents = new HashMap<>();\n            int columnIdxStatus = cursor.getColumnIndexOrThrow(MessageData.KEY_STATUS);\n            int columnIdxContact = cursor.getColumnIndexOrThrow(MessageData.KEY_CONTACT);\n            do {\n                GroupChatEvent.Status status = GroupChatEvent.Status.valueOf(cursor\n                        .getInt(columnIdxStatus));\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(cursor\n                        .getString(columnIdxContact));\n                groupChatEvents.put(contact, status);\n            } while (cursor.moveToNext());\n            return groupChatEvents;\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public boolean isOneToOneChatMessage(String msgId) {\n        Cursor cursor = null;\n        try {\n            Uri contentUri = Uri.withAppendedPath(MessageData.CONTENT_URI, msgId);\n            cursor = mLocalContentResolver.query(contentUri, new String[] {\n                    MessageData.KEY_CONTACT, MessageData.KEY_CHAT_ID\n            }, null, null, null);\n            CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n            if (!cursor.moveToNext()) {\n                return false;\n            }\n            String contactId = cursor.getString(cursor\n                    .getColumnIndexOrThrow(MessageData.KEY_CONTACT));\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(MessageData.KEY_CHAT_ID));\n            return chatId.equals(contactId);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    @Override\n    public boolean setChatMessageStatusDelivered(String msgId, long timestampDelivered) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setChatMessageStatusDelivered msgId=\" + msgId + \", timestampDelivered=\"\n                    + timestampDelivered);\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_STATUS, Status.DELIVERED.toInt());\n        values.put(MessageData.KEY_REASON_CODE, ReasonCode.UNSPECIFIED.toInt());\n        values.put(MessageData.KEY_TIMESTAMP_DELIVERED, timestampDelivered);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        return mLocalContentResolver.update(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                values, SELECTION_BY_NOT_DISPLAYED, null) > 0;\n    }\n\n    @Override\n    public boolean setChatMessageStatusDisplayed(String msgId, long timestampDisplayed) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setChatMessageStatusDisplayed msgId=\" + msgId + \", timestampDisplayed=\"\n                    + timestampDisplayed);\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_STATUS, Status.DISPLAYED.toInt());\n        values.put(MessageData.KEY_REASON_CODE, ReasonCode.UNSPECIFIED.toInt());\n        values.put(MessageData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        return mLocalContentResolver.update(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                values, null, null) > 0;\n    }\n\n    @Override\n    public void clearMessageDeliveryExpiration(List<String> msgIds) {\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_DELIVERY_EXPIRATION, 0);\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 0);\n        List<String> parameters = new ArrayList<>();\n        for (int i = 0; i < msgIds.size(); i++) {\n            parameters.add(\"?\");\n        }\n        String selection = MessageData.KEY_MESSAGE_ID + \" IN (\" + TextUtils.join(\",\", parameters)\n                + \")\";\n        mLocalContentResolver.update(MessageData.CONTENT_URI, values, selection,\n                msgIds.toArray(new String[msgIds.size()]));\n    }\n\n    @Override\n    public boolean setChatMessageDeliveryExpired(String msgId) {\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_EXPIRED_DELIVERY, 1);\n        return mLocalContentResolver.update(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                values, null, null) > 0;\n    }\n\n    @Override\n    public Cursor getUndeliveredOneToOneChatMessages() {\n        Cursor cursor = mLocalContentResolver.query(MessageData.CONTENT_URI, null,\n                SELECTION_BY_UNDELIVERED_ONETOONE_CHAT_MESSAGES, null, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, MessageData.CONTENT_URI);\n        return cursor;\n    }\n\n    @Override\n    public boolean setChatMessageStatusAndTimestamp(String msgId, Status status,\n            ReasonCode reasonCode, long timestamp, long timestampSent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Update chat message: msgId=\" + msgId + \", status=\" + status\n                    + \", reasonCode=\" + reasonCode + \", timestamp=\" + timestamp\n                    + \", timestampSent=\" + timestampSent);\n        }\n        ContentValues values = new ContentValues();\n        values.put(MessageData.KEY_STATUS, status.toInt());\n        values.put(MessageData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(MessageData.KEY_TIMESTAMP, timestamp);\n        values.put(MessageData.KEY_TIMESTAMP_SENT, timestampSent);\n        return mLocalContentResolver.update(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                values, null, null) > 0;\n    }\n\n    @Override\n    public void addGroupChatFailedDeliveryMessage(String chatId, ChatMessage msg) {\n        addGroupChatMessage(chatId, msg, Direction.INCOMING, null, Status.FAILED,\n                ReasonCode.FAILED_DELIVERY);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/MessagingLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Class to interface the Instant Messaging tables\n * \n * @author LEMORDANT Philippe\n */\npublic class MessagingLog implements IGroupChatLog, IMessageLog, IFileTransferLog,\n        IGroupDeliveryInfoLog {\n    /**\n     * Current instance\n     */\n    private static volatile MessagingLog sInstance;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final GroupChatLog mGroupChatLog;\n\n    private final MessageLog mMessageLog;\n\n    private final FileTransferLog mFileTransferLog;\n\n    private final GroupDeliveryInfoLog mGroupChatDeliveryInfoLog;\n\n    /**\n     * Get or Create Singleton instance of MessagingLog\n     * \n     * @param localContentResolver Local content resolver\n     * @param rcsSettings the RCS settings accessor\n     * @return singleton instance\n     */\n    public static MessagingLog getInstance(LocalContentResolver localContentResolver,\n            RcsSettings rcsSettings) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (MessagingLog.class) {\n            if (sInstance == null) {\n                sInstance = new MessagingLog(localContentResolver, rcsSettings);\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param localContentResolver Local content provider\n     * @param rcsSettings the RCS settings accessor\n     */\n    private MessagingLog(LocalContentResolver localContentResolver, RcsSettings rcsSettings) {\n        mLocalContentResolver = localContentResolver;\n        mGroupChatLog = new GroupChatLog(localContentResolver);\n        mGroupChatDeliveryInfoLog = new GroupDeliveryInfoLog(localContentResolver);\n        mMessageLog = new MessageLog(mLocalContentResolver, mGroupChatDeliveryInfoLog, rcsSettings);\n        mFileTransferLog = new FileTransferLog(localContentResolver, mGroupChatDeliveryInfoLog,\n                rcsSettings);\n    }\n\n    @Override\n    public void addGroupChat(String chatId, ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode,\n            Direction direction, long timestamp) {\n        mGroupChatLog.addGroupChat(chatId, contact, subject, participants, state, reasonCode,\n                direction, timestamp);\n    }\n\n    @Override\n    public void acceptGroupChatNextInvitation(String chatId) {\n        mGroupChatLog.acceptGroupChatNextInvitation(chatId);\n    }\n\n    @Override\n    public boolean setGroupChatStateAndReasonCode(String chatId, State state, ReasonCode reasonCode) {\n        return mGroupChatLog.setGroupChatStateAndReasonCode(chatId, state, reasonCode);\n    }\n\n    @Override\n    public boolean setGroupChatParticipants(String chatId,\n            Map<ContactId, ParticipantStatus> participants) {\n        return mGroupChatLog.setGroupChatParticipants(chatId, participants);\n    }\n\n    @Override\n    public boolean setGroupChatRejoinId(String chatId, String rejoinId, boolean updateStateToStarted) {\n        return mGroupChatLog.setGroupChatRejoinId(chatId, rejoinId, updateStateToStarted);\n    }\n\n    @Override\n    public GroupChatInfo getGroupChatInfo(String chatId) {\n        return mGroupChatLog.getGroupChatInfo(chatId);\n    }\n\n    @Override\n    public void addOneToOneSpamMessage(ChatMessage msg) {\n        mMessageLog.addOneToOneSpamMessage(msg);\n    }\n\n    @Override\n    public void addIncomingOneToOneChatMessage(ChatMessage msg, boolean imdnDisplayedRequested) {\n        mMessageLog.addIncomingOneToOneChatMessage(msg, imdnDisplayedRequested);\n    }\n\n    @Override\n    public void addOutgoingOneToOneChatMessage(ChatMessage msg, Status status,\n            Content.ReasonCode reasonCode, long deliveryExpiration) {\n        mMessageLog.addOutgoingOneToOneChatMessage(msg, status, reasonCode, deliveryExpiration);\n    }\n\n    @Override\n    public void addIncomingGroupChatMessage(String chatId, ChatMessage msg,\n            boolean imdnDisplayedRequested) {\n        mMessageLog.addIncomingGroupChatMessage(chatId, msg, imdnDisplayedRequested);\n    }\n\n    @Override\n    public void addOutgoingGroupChatMessage(String chatId, ChatMessage msg,\n            Set<ContactId> recipients, Status status, Content.ReasonCode reasonCode) {\n        mMessageLog.addOutgoingGroupChatMessage(chatId, msg, recipients, status, reasonCode);\n    }\n\n    @Override\n    public String addGroupChatEvent(String chatId, ContactId contact, GroupChatEvent.Status status,\n            long timestamp) {\n        return mMessageLog.addGroupChatEvent(chatId, contact, status, timestamp);\n    }\n\n    @Override\n    public int markMessageAsRead(String msgId, long timestampDisplayed) {\n        return mMessageLog.markMessageAsRead(msgId, timestampDisplayed);\n    }\n\n    @Override\n    public boolean setChatMessageStatusAndReasonCode(String msgId, Status status,\n            Content.ReasonCode reasonCode) {\n        return mMessageLog.setChatMessageStatusAndReasonCode(msgId, status, reasonCode);\n    }\n\n    @Override\n    public boolean isMessagePersisted(String msgId) {\n        return mMessageLog.isMessagePersisted(msgId);\n    }\n\n    @Override\n    public void addOneToOneFileTransfer(String fileTransferId, ContactId contact,\n            Direction direction, MmContent content, MmContent fileIcon, FileTransfer.State state,\n            FileTransfer.ReasonCode reasonCode, long timestamp, long timestampSent,\n            long fileExpiration, long fileIconExpiration) {\n        mFileTransferLog.addOneToOneFileTransfer(fileTransferId, contact, direction, content,\n                fileIcon, state, reasonCode, timestamp, timestampSent, fileExpiration,\n                fileIconExpiration);\n    }\n\n    @Override\n    public void addOutgoingGroupFileTransfer(String fileTransferId, String chatId,\n            MmContent content, MmContent thumbnail, Set<ContactId> recipients,\n            FileTransfer.State state, FileTransfer.ReasonCode reasonCode, long timestamp,\n            long timestampSent) {\n        mFileTransferLog.addOutgoingGroupFileTransfer(fileTransferId, chatId, content, thumbnail,\n                recipients, state, reasonCode, timestamp, timestampSent);\n    }\n\n    @Override\n    public void addIncomingGroupFileTransfer(String fileTransferId, String chatId,\n            ContactId contact, MmContent content, MmContent fileIcon, FileTransfer.State state,\n            FileTransfer.ReasonCode reasonCode, long timestamp, long timestampSent,\n            long fileExpiration, long fileIconExpiration) {\n        mFileTransferLog.addIncomingGroupFileTransfer(fileTransferId, chatId, contact, content,\n                fileIcon, state, reasonCode, timestamp, timestampSent, fileExpiration,\n                fileIconExpiration);\n    }\n\n    @Override\n    public boolean setFileTransferStateAndReasonCode(String fileTransferId,\n            FileTransfer.State state, FileTransfer.ReasonCode reasonCode) {\n        return mFileTransferLog\n                .setFileTransferStateAndReasonCode(fileTransferId, state, reasonCode);\n    }\n\n    @Override\n    public boolean setFileTransferDelivered(String fileTransferId, long timestampDelivered) {\n        return mFileTransferLog.setFileTransferDelivered(fileTransferId, timestampDelivered);\n    }\n\n    @Override\n    public boolean setFileTransferDisplayed(String fileTransferId, long timestampDisplayed) {\n        return mFileTransferLog.setFileTransferDisplayed(fileTransferId, timestampDisplayed);\n    }\n\n    @Override\n    public boolean setFileTransferStateAndTimestamp(String fileTransferId,\n            FileTransfer.State state, FileTransfer.ReasonCode reasonCode, long timestamp,\n            long timestampSent) {\n        return mFileTransferLog.setFileTransferStateAndTimestamp(fileTransferId, state, reasonCode,\n                timestamp, timestampSent);\n    }\n\n    @Override\n    public int markFileTransferAsRead(String fileTransferId, long timestampDisplayed) {\n        return mFileTransferLog.markFileTransferAsRead(fileTransferId, timestampDisplayed);\n    }\n\n    @Override\n    public boolean setFileTransferProgress(String fileTransferId, long currentSize) {\n        return mFileTransferLog.setFileTransferProgress(fileTransferId, currentSize);\n    }\n\n    @Override\n    public boolean setFileTransferred(String fileTransferId, MmContent content,\n            long fileExpiration, long fileIconExpiration, long deliveryExpiration) {\n        return mFileTransferLog.setFileTransferred(fileTransferId, content, fileExpiration,\n                fileIconExpiration, deliveryExpiration);\n    }\n\n    @Override\n    public Uri getFileTransferIcon(String fileTransferId) {\n        return mFileTransferLog.getFileTransferIcon(fileTransferId);\n    }\n\n    @Override\n    public boolean isFileTransfer(String fileTransferId) {\n        return mFileTransferLog.isFileTransfer(fileTransferId);\n    }\n\n    @Override\n    public boolean isGroupChatNextInviteRejected(String chatId) {\n        return mGroupChatLog.isGroupChatNextInviteRejected(chatId);\n    }\n\n    /**\n     * Delete all entries in Chat, Message and FileTransfer Logs\n     */\n    public void deleteAllEntries() {\n        mLocalContentResolver.delete(GroupChatData.CONTENT_URI, null, null);\n        mLocalContentResolver.delete(MessageData.CONTENT_URI, null, null);\n        mLocalContentResolver.delete(FileTransferData.CONTENT_URI, null, null);\n        mLocalContentResolver.delete(GroupDeliveryInfoData.CONTENT_URI, null, null);\n    }\n\n    @Override\n    public Uri addGroupChatDeliveryInfoEntry(String chatId, ContactId contact, String msgId,\n            GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode,\n            long timestampDelivered, long timestampDisplayed) {\n        return mGroupChatDeliveryInfoLog.addGroupChatDeliveryInfoEntry(chatId, contact, msgId,\n                status, reasonCode, timestampDelivered, timestampDisplayed);\n    }\n\n    @Override\n    public boolean setGroupChatDeliveryInfoStatusAndReasonCode(String chatId, ContactId contact,\n            String msgId, GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n        return mGroupChatDeliveryInfoLog.setGroupChatDeliveryInfoStatusAndReasonCode(chatId,\n                contact, msgId, status, reasonCode);\n    }\n\n    @Override\n    public boolean isDeliveredToAllRecipients(String msgId) {\n        return mGroupChatDeliveryInfoLog.isDeliveredToAllRecipients(msgId);\n    }\n\n    @Override\n    public boolean isDisplayedByAllRecipients(String msgId) {\n        return mGroupChatDeliveryInfoLog.isDisplayedByAllRecipients(msgId);\n    }\n\n    @Override\n    public boolean setFileUploadTId(String fileTransferId, String tId) {\n        return mFileTransferLog.setFileUploadTId(fileTransferId, tId);\n    }\n\n    @Override\n    public boolean setFileDownloadAddress(String fileTransferId, Uri downloadAddress) {\n        return mFileTransferLog.setFileDownloadAddress(fileTransferId, downloadAddress);\n    }\n\n    @Override\n    public List<FtHttpResume> retrieveFileTransfersPausedBySystem() {\n        return mFileTransferLog.retrieveFileTransfersPausedBySystem();\n    }\n\n    @Override\n    public FtHttpResumeUpload retrieveFtHttpResumeUpload(String tId) {\n        return mFileTransferLog.retrieveFtHttpResumeUpload(tId);\n    }\n\n    @Override\n    public GroupChat.State getGroupChatState(String chatId) {\n        return mGroupChatLog.getGroupChatState(chatId);\n    }\n\n    @Override\n    public GroupChat.ReasonCode getGroupChatReasonCode(String chatId) {\n        return mGroupChatLog.getGroupChatReasonCode(chatId);\n    }\n\n    @Override\n    public String getFileTransferChatId(String fileTransferId) {\n        return mFileTransferLog.getFileTransferChatId(fileTransferId);\n    }\n\n    @Override\n    public FileTransfer.State getFileTransferState(String fileTransferId) {\n        return mFileTransferLog.getFileTransferState(fileTransferId);\n    }\n\n    @Override\n    public FileTransfer.ReasonCode getFileTransferReasonCode(String fileTransferId) {\n        return mFileTransferLog.getFileTransferReasonCode(fileTransferId);\n    }\n\n    @Override\n    public Long getFileTransferSentTimestamp(String fileTransferId) {\n        return mFileTransferLog.getFileTransferSentTimestamp(fileTransferId);\n    }\n\n    @Override\n    public Long getFileTransferTimestamp(String fileTransferId) {\n        return mFileTransferLog.getFileTransferTimestamp(fileTransferId);\n    }\n\n    @Override\n    public Map<ContactId, ParticipantStatus> getParticipants(String chatId) {\n        return mGroupChatLog.getParticipants(chatId);\n    }\n\n    @Override\n    public Map<ContactId, ParticipantStatus> getParticipants(String chatId,\n            Set<ParticipantStatus> statuses) {\n        return mGroupChatLog.getParticipants(chatId, statuses);\n    }\n\n    @Override\n    public boolean isGroupFileTransfer(String fileTransferId) {\n        return mFileTransferLog.isGroupFileTransfer(fileTransferId);\n    }\n\n    @Override\n    public boolean setRejectNextGroupChatNextInvitation(String chatId) {\n        return mGroupChatLog.setRejectNextGroupChatNextInvitation(chatId);\n    }\n\n    @Override\n    public Long getMessageSentTimestamp(String msgId) {\n        return mMessageLog.getMessageSentTimestamp(msgId);\n    }\n\n    @Override\n    public Boolean isMessageRead(String msgId) {\n        return mMessageLog.isMessageRead(msgId);\n    }\n\n    @Override\n    public Long getMessageTimestamp(String msgId) {\n        return mMessageLog.getMessageTimestamp(msgId);\n    }\n\n    @Override\n    public Status getMessageStatus(String msgId) {\n        return mMessageLog.getMessageStatus(msgId);\n    }\n\n    @Override\n    public Content.ReasonCode getMessageReasonCode(String msgId) {\n        return mMessageLog.getMessageReasonCode(msgId);\n    }\n\n    @Override\n    public String getMessageMimeType(String msgId) {\n        return mMessageLog.getMessageMimeType(msgId);\n    }\n\n    @Override\n    public Set<String> getChatIdsOfActiveGroupChatsForAutoRejoin() {\n        return mGroupChatLog.getChatIdsOfActiveGroupChatsForAutoRejoin();\n    }\n\n    @Override\n    public Cursor getFileTransferData(String fileTransferId) {\n        return mFileTransferLog.getFileTransferData(fileTransferId);\n    }\n\n    @Override\n    public Cursor getGroupChatData(String chatId) {\n        return mGroupChatLog.getGroupChatData(chatId);\n    }\n\n    @Override\n    public Cursor getChatMessageData(String msgId) {\n        return mMessageLog.getChatMessageData(msgId);\n    }\n\n    @Override\n    public FtHttpResume getFileTransferResumeInfo(String fileTransferId) {\n        return mFileTransferLog.getFileTransferResumeInfo(fileTransferId);\n    }\n\n    @Override\n    public Cursor getQueuedOneToOneChatMessages(ContactId contact) {\n        return mMessageLog.getQueuedOneToOneChatMessages(contact);\n    }\n\n    @Override\n    public Cursor getQueuedAndUploadedButNotTransferredFileTransfers() {\n        return mFileTransferLog.getQueuedAndUploadedButNotTransferredFileTransfers();\n    }\n\n    @Override\n    public Cursor getInterruptedFileTransfers() {\n        return mFileTransferLog.getInterruptedFileTransfers();\n    }\n\n    @Override\n    public boolean setRemoteSipId(String fileTransferId, String remoteInstanceId) {\n        return mFileTransferLog.setRemoteSipId(fileTransferId, remoteInstanceId);\n    }\n\n    @Override\n    public boolean isGroupChatPersisted(String chatId) {\n        return mGroupChatLog.isGroupChatPersisted(chatId);\n    }\n\n    @Override\n    public Map<ContactId, GroupChatEvent.Status> getGroupChatEvents(String chatId) {\n        return mMessageLog.getGroupChatEvents(chatId);\n    }\n\n    @Override\n    public boolean setGroupChatParticipantsStateAndReasonCode(String chatId,\n            Map<ContactId, ParticipantStatus> participants, State state, ReasonCode reasonCode) {\n        return mGroupChatLog.setGroupChatParticipantsStateAndReasonCode(chatId, participants,\n                state, reasonCode);\n    }\n\n    @Override\n    public boolean isOneToOneChatMessage(String msgId) {\n        return mMessageLog.isOneToOneChatMessage(msgId);\n    }\n\n    @Override\n    public boolean setGroupChatDeliveryInfoDelivered(String chatId, ContactId contact,\n            String fileTransferId, long timestampDelivered) {\n        return mGroupChatDeliveryInfoLog.setGroupChatDeliveryInfoDelivered(chatId, contact,\n                fileTransferId, timestampDelivered);\n    }\n\n    @Override\n    public boolean setGroupChatDeliveryInfoDisplayed(String chatId, ContactId contact,\n            String fileTransferId, long timestampDisplayed) {\n        return mGroupChatDeliveryInfoLog.setGroupChatDeliveryInfoDisplayed(chatId, contact,\n                fileTransferId, timestampDisplayed);\n    }\n\n    @Override\n    public boolean setChatMessageStatusDelivered(String msgId, long timestampDelivered) {\n        return mMessageLog.setChatMessageStatusDelivered(msgId, timestampDelivered);\n    }\n\n    @Override\n    public boolean setChatMessageStatusDisplayed(String msgId, long timestampDisplayed) {\n        return mMessageLog.setChatMessageStatusDisplayed(msgId, timestampDisplayed);\n    }\n\n    @Override\n    public void clearMessageDeliveryExpiration(List<String> msgIds) {\n        mMessageLog.clearMessageDeliveryExpiration(msgIds);\n    }\n\n    @Override\n    public void clearFileTransferDeliveryExpiration(List<String> fileTransferIds) {\n        mFileTransferLog.clearFileTransferDeliveryExpiration(fileTransferIds);\n    }\n\n    @Override\n    public boolean setFileTransferDeliveryExpired(String fileTransferId) {\n        return mFileTransferLog.setFileTransferDeliveryExpired(fileTransferId);\n    }\n\n    @Override\n    public boolean setChatMessageDeliveryExpired(String msgId) {\n        return mMessageLog.setChatMessageDeliveryExpired(msgId);\n    }\n\n    @Override\n    public Cursor getUndeliveredOneToOneChatMessages() {\n        return mMessageLog.getUndeliveredOneToOneChatMessages();\n    }\n\n    @Override\n    public Cursor getUnDeliveredOneToOneFileTransfers() {\n        return mFileTransferLog.getUnDeliveredOneToOneFileTransfers();\n    }\n\n    @Override\n    public Boolean isChatMessageExpiredDelivery(String msgId) {\n        return mMessageLog.isChatMessageExpiredDelivery(msgId);\n    }\n\n    @Override\n    public Boolean isFileTransferExpiredDelivery(String fileTransferId) {\n        return mFileTransferLog.isFileTransferExpiredDelivery(fileTransferId);\n    }\n\n    @Override\n    public String getMessageChatId(String msgId) {\n        return mMessageLog.getMessageChatId(msgId);\n    }\n\n    @Override\n    public void setFileTransferDownloadInfo(String fileTransferId,\n            FileTransferHttpInfoDocument ftHttpInfo) {\n        mFileTransferLog.setFileTransferDownloadInfo(fileTransferId, ftHttpInfo);\n    }\n\n    @Override\n    public FileTransferHttpInfoDocument getFileDownloadInfo(String fileTransferId)\n            throws FileAccessException {\n        return mFileTransferLog.getFileDownloadInfo(fileTransferId);\n    }\n\n    @Override\n    public FileTransferHttpInfoDocument getFileDownloadInfo(Cursor cursor)\n            throws FileAccessException {\n        return mFileTransferLog.getFileDownloadInfo(cursor);\n    }\n\n    @Override\n    public void setFileTransferTimestamps(String fileTransferId, long timestamp, long timestampSent) {\n        mFileTransferLog.setFileTransferTimestamps(fileTransferId, timestamp, timestampSent);\n    }\n\n    @Override\n    public boolean setFileInfoDequeued(String fileTransferId, long deliveryExpiration) {\n        return mFileTransferLog.setFileInfoDequeued(fileTransferId, deliveryExpiration);\n    }\n\n    @Override\n    public boolean setChatMessageStatusAndTimestamp(String msgId, Status status,\n            Content.ReasonCode reasonCode, long timestamp, long timestampSent) {\n        return mMessageLog.setChatMessageStatusAndTimestamp(msgId, status, reasonCode, timestamp,\n                timestampSent);\n    }\n\n    @Override\n    public Long getFileTransferProgress(String fileTransferId) {\n        return mFileTransferLog.getFileTransferProgress(fileTransferId);\n    }\n\n    @Override\n    public void addOneToOneFailedDeliveryMessage(ChatMessage msg) {\n        mMessageLog.addOneToOneFailedDeliveryMessage(msg);\n    }\n\n    @Override\n    public void addGroupChatFailedDeliveryMessage(String chatId, ChatMessage msg) {\n        mMessageLog.addGroupChatFailedDeliveryMessage(chatId, msg);\n    }\n\n    @Override\n    public Uri getFile(String fileTransferId) {\n        return mFileTransferLog.getFile(fileTransferId);\n    }\n\n    @Override\n    public Direction getFileTransferDirection(String fileTransferId) {\n        return mFileTransferLog.getFileTransferDirection(fileTransferId);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/OneToOneChatMessageDeleteTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.DeliveryExpirationManager;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\npublic class OneToOneChatMessageDeleteTask extends DeleteTask.GroupedByContactId {\n\n    private static final Logger sLogger = Logger.getLogger(OneToOneChatMessageDeleteTask.class\n            .getName());\n\n    private static final String SELECTION_ONETOONE_CHATMESSAGES = MessageData.KEY_CHAT_ID + \"=\"\n            + MessageData.KEY_CONTACT;\n\n    private static final String SELECTION_ONETOONE_CHATMESSAGES_BY_CHATID = MessageData.KEY_CHAT_ID\n            + \"=?\";\n\n    private final ChatServiceImpl mChatService;\n\n    private final InstantMessagingService mImService;\n\n    /**\n     * Deletion of all one to one chat messages.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     */\n    public OneToOneChatMessageDeleteTask(ChatServiceImpl chatService,\n            InstantMessagingService imService, LocalContentResolver contentResolver) {\n        super(contentResolver, MessageData.CONTENT_URI, MessageData.KEY_MESSAGE_ID,\n                MessageData.KEY_CONTACT, SELECTION_ONETOONE_CHATMESSAGES);\n        mChatService = chatService;\n        mImService = imService;\n        setAllAtOnce(true);\n    }\n\n    /**\n     * Deletion of a specific chat message.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param messageId the message id\n     */\n    public OneToOneChatMessageDeleteTask(ChatServiceImpl chatService,\n            InstantMessagingService imService, LocalContentResolver contentResolver,\n            String messageId) {\n        super(contentResolver, MessageData.CONTENT_URI, MessageData.KEY_MESSAGE_ID,\n                MessageData.KEY_CONTACT, null, messageId);\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of a specific one to one conversation.\n     * \n     * @param chatService the chat service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param contact the contact\n     */\n    public OneToOneChatMessageDeleteTask(ChatServiceImpl chatService,\n            InstantMessagingService imService, LocalContentResolver contentResolver,\n            ContactId contact) {\n        super(contentResolver, MessageData.CONTENT_URI, MessageData.KEY_MESSAGE_ID,\n                MessageData.KEY_CONTACT, SELECTION_ONETOONE_CHATMESSAGES_BY_CHATID, contact\n                        .toString());\n        mChatService = chatService;\n        mImService = imService;\n        setAllAtOnce(true);\n    }\n\n    @Override\n    protected void onRowDelete(ContactId contact, String msgId) throws PayloadException {\n        if (isSingleRowDelete()) {\n            return;\n\n        }\n        ChatSession session = mImService.getOneToOneChatSession(contact);\n        if (session == null) {\n            mChatService.removeOneToOneChat(contact);\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mChatService.removeOneToOneChat(contact);\n    }\n\n    @Override\n    protected void onCompleted(ContactId contact, Set<String> msgIds) {\n        DeliveryExpirationManager expirationManager = mImService.getDeliveryExpirationManager();\n        for (String messageId : msgIds) {\n            expirationManager.cancelDeliveryTimeoutAlarm(messageId);\n        }\n        mChatService.broadcastOneToOneMessagesDeleted(contact, msgIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/OneToOneChatMessageDequeueTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.SessionUnavailableException;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.DequeueTask;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.OneToOneChatImpl;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\nimport android.database.Cursor;\n\n/**\n * OneToOneChatMessageDequeueTask tries to dequeues and sends the queued one-one chat messages of a\n * specific contact.\n */\npublic class OneToOneChatMessageDequeueTask extends DequeueTask {\n\n    private final ContactId mContact;\n\n    public OneToOneChatMessageDequeueTask(Context ctx, Core core, ContactId contact,\n            MessagingLog messagingLog, ChatServiceImpl chatService, RcsSettings rcsSettings,\n            ContactManager contactManager, FileTransferServiceImpl fileTransferService) {\n        super(ctx, core, contactManager, messagingLog, rcsSettings, chatService,\n                fileTransferService);\n        mContact = contact;\n    }\n\n    @Override\n    public void run() {\n        boolean logActivated = mLogger.isActivated();\n        if (logActivated) {\n            mLogger.debug(\"Execute task to dequeue one-to-one chat messages for contact \"\n                    .concat(mContact.toString()));\n        }\n        String id = null;\n        String mimeType = null;\n        Cursor cursor = null;\n        try {\n            if (!isImsConnected()) {\n                if (logActivated) {\n                    mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue one-to-one chat messages for contact \"\n                            .concat(mContact.toString()));\n                }\n                return;\n            }\n            if (isShuttingDownOrStopped()) {\n                if (logActivated) {\n                    mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue one-to-one chat messages for contact \"\n                            .concat(mContact.toString()));\n                }\n                return;\n            }\n            cursor = mMessagingLog.getQueuedOneToOneChatMessages(mContact);\n            int msgIdIdx = cursor.getColumnIndexOrThrow(MessageData.KEY_MESSAGE_ID);\n            int contentIdx = cursor.getColumnIndexOrThrow(MessageData.KEY_CONTENT);\n            int mimeTypeIdx = cursor.getColumnIndexOrThrow(MessageData.KEY_MIME_TYPE);\n            OneToOneChatImpl oneToOneChat = mChatService.getOrCreateOneToOneChat(mContact);\n            while (cursor.moveToNext()) {\n                try {\n                    if (!isImsConnected()) {\n                        if (logActivated) {\n                            mLogger.debug(\"IMS not connected, exiting dequeue task to dequeue one-to-one chat messages for contact \"\n                                    .concat(mContact.toString()));\n                        }\n                        return;\n                    }\n                    if (isShuttingDownOrStopped()) {\n                        if (logActivated) {\n                            mLogger.debug(\"Core service is shutting down/stopped, exiting dequeue task to dequeue one-to-one chat messages for contact \"\n                                    .concat(mContact.toString()));\n                        }\n                        return;\n                    }\n                    id = cursor.getString(msgIdIdx);\n                    mimeType = cursor.getString(mimeTypeIdx);\n                    if (!isPossibleToDequeueOneToOneChatMessage(mContact)) {\n                        setOneToOneChatMessageAsFailedDequeue(mContact, id, mimeType);\n                        continue;\n                    }\n                    if (!isAllowedToDequeueOneToOneChatMessage(mContact)) {\n                        continue;\n                    }\n                    String content = cursor.getString(contentIdx);\n                    long timestamp = System.currentTimeMillis();\n\n                    /* For outgoing message, timestampSent = timestamp */\n                    ChatMessage msg = ChatUtils.createChatMessage(id, mimeType, content, mContact,\n                            null, timestamp, timestamp);\n                    oneToOneChat.dequeueOneToOneChatMessage(msg);\n\n                } catch (SessionUnavailableException | NetworkException e) {\n                    if (logActivated) {\n                        mLogger.debug(\"Failed to dequeue one-one chat message '\" + id\n                                + \"' message for contact '\" + mContact + \"' due to: \"\n                                + e.getMessage());\n                    }\n                } catch (PayloadException e) {\n                    mLogger.error(\"Failed to dequeue one-one chat message '\" + id\n                            + \"' message for contact '\" + mContact, e);\n                    setOneToOneChatMessageAsFailedDequeue(mContact, id, mimeType);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally all the terminal and non-terminal cases should be handled above so\n                     * if we come here that means that there is a bug and so we output a stack trace\n                     * so the bug can then be properly tracked down and fixed. We also mark the\n                     * respective entry that failed to dequeue as FAILED.\n                     */\n                    mLogger.error(\"Failed to dequeue one-one chat message '\" + id\n                            + \"'for contact '\" + mContact + \"' \", e);\n                    setOneToOneChatMessageAsFailedDequeue(mContact, id, mimeType);\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally all the terminal and non-terminal cases should be handled above so if we\n             * come here that means that there is a bug and so we output a stack trace so the bug\n             * can then be properly tracked down and fixed. We also mark the respective entry that\n             * failed to dequeue as FAILED.\n             */\n            mLogger.error(\"Exception occured while dequeueing one-to-one chat message with msgId '\"\n                    + id + \"'for contact '\" + mContact + \"' \", e);\n            if (id == null) {\n                return;\n            }\n            setOneToOneChatMessageAsFailedDequeue(mContact, id, mimeType);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/OneToOneFileTransferDeleteTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.DeliveryExpirationManager;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\npublic class OneToOneFileTransferDeleteTask extends DeleteTask.GroupedByContactId {\n\n    private static final Logger sLogger = Logger.getLogger(OneToOneFileTransferDeleteTask.class\n            .getName());\n\n    private static final String SELECTION_ALL_ONETOONE_FILETRANSFERS = FileTransferData.KEY_CHAT_ID\n            + \"=\" + FileTransferData.KEY_CONTACT;\n\n    private static final String SELECTION_ONETOONE_FILETRANSFER_BY_CHATID = FileTransferData.KEY_CHAT_ID\n            + \"=?\";\n\n    private final FileTransferServiceImpl mFileTransferService;\n\n    private final InstantMessagingService mImService;\n\n    /**\n     * Deletion of all one to one file transfers.\n     * \n     * @param fileTransferService the file transfer service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     */\n    public OneToOneFileTransferDeleteTask(FileTransferServiceImpl fileTransferService,\n            InstantMessagingService imService, LocalContentResolver contentResolver) {\n        super(contentResolver, FileTransferData.CONTENT_URI, FileTransferData.KEY_FT_ID,\n                FileTransferData.KEY_CONTACT, SELECTION_ALL_ONETOONE_FILETRANSFERS);\n        mFileTransferService = fileTransferService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of a specific file transfer.\n     * \n     * @param fileTransferService the file transfer service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param transferId the transfer id\n     */\n    public OneToOneFileTransferDeleteTask(FileTransferServiceImpl fileTransferService,\n            InstantMessagingService imService, LocalContentResolver contentResolver,\n            String transferId) {\n        super(contentResolver, FileTransferData.CONTENT_URI, FileTransferData.KEY_FT_ID,\n                FileTransferData.KEY_CONTACT, null, transferId);\n        mFileTransferService = fileTransferService;\n        mImService = imService;\n    }\n\n    /**\n     * Deletion of all file transfers from a specific one to one conversation.\n     * \n     * @param fileTransferService the file transfer service impl\n     * @param imService the IM service\n     * @param contentResolver the content resolver\n     * @param contact the contact id\n     */\n    public OneToOneFileTransferDeleteTask(FileTransferServiceImpl fileTransferService,\n            InstantMessagingService imService, LocalContentResolver contentResolver,\n            ContactId contact) {\n        super(contentResolver, FileTransferData.CONTENT_URI, FileTransferData.KEY_FT_ID,\n                FileTransferData.KEY_CONTACT, SELECTION_ONETOONE_FILETRANSFER_BY_CHATID, contact\n                        .toString());\n        mFileTransferService = fileTransferService;\n        mImService = imService;\n    }\n\n    @Override\n    protected void onRowDelete(ContactId contact, String transferId) throws PayloadException {\n        FileSharingSession session = mImService.getFileSharingSession(transferId);\n        if (session == null) {\n            mFileTransferService.ensureThumbnailIsDeleted(transferId);\n            mFileTransferService.ensureFileCopyIsDeletedIfExisting(transferId);\n            mFileTransferService.removeOneToOneFileTransfer(transferId);\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mFileTransferService.ensureThumbnailIsDeleted(transferId);\n        mFileTransferService.ensureFileCopyIsDeletedIfExisting(transferId);\n        mFileTransferService.removeOneToOneFileTransfer(transferId);\n    }\n\n    @Override\n    protected void onCompleted(ContactId contact, Set<String> transferIds) {\n        DeliveryExpirationManager expirationManager = mImService.getDeliveryExpirationManager();\n        for (String transferId : transferIds) {\n            expirationManager.cancelDeliveryTimeoutAlarm(transferId);\n        }\n        mFileTransferService.broadcastOneToOneFileTransferDeleted(contact, transferIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/RecreateDeliveryExpirationAlarms.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.DeliveryExpirationManager;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.database.Cursor;\n\npublic class RecreateDeliveryExpirationAlarms implements Runnable {\n\n    private final DeliveryExpirationManager mOneToOneUndeliveredImManager;\n\n    private final MessagingLog mMessagingLog;\n\n    private static final Logger sLogger = Logger.getLogger(RecreateDeliveryExpirationAlarms.class\n            .getName());\n\n    public RecreateDeliveryExpirationAlarms(MessagingLog messagingLog,\n            DeliveryExpirationManager oneToOneUndeliveredImManager) {\n        mMessagingLog = messagingLog;\n        mOneToOneUndeliveredImManager = oneToOneUndeliveredImManager;\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"initiating.\");\n        }\n        Cursor cursor = null;\n        try {\n            long currentTime = System.currentTimeMillis();\n            cursor = mMessagingLog.getUndeliveredOneToOneChatMessages();\n            int msgIdIdx = cursor.getColumnIndexOrThrow(MessageData.KEY_MESSAGE_ID);\n            int chatMessageContactIdx = cursor.getColumnIndexOrThrow(MessageData.KEY_CONTACT);\n            int chatMessageDeliveryExpirationIdx = cursor\n                    .getColumnIndexOrThrow(MessageData.KEY_DELIVERY_EXPIRATION);\n            while (cursor.moveToNext()) {\n                String msgId = cursor.getString(msgIdIdx);\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(cursor\n                        .getString(chatMessageContactIdx));\n                long deliveryExpiration = cursor.getLong(chatMessageDeliveryExpirationIdx);\n                if (deliveryExpiration > currentTime) {\n                    mOneToOneUndeliveredImManager.scheduleOneToOneChatMessageDeliveryTimeoutAlarm(\n                            contact, msgId, deliveryExpiration);\n                } else {\n                    mOneToOneUndeliveredImManager.onChatMessageDeliveryExpirationReceived(contact,\n                            msgId);\n                }\n            }\n            CursorUtil.close(cursor);\n\n            cursor = mMessagingLog.getUnDeliveredOneToOneFileTransfers();\n\n            int fileTransferIdIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FT_ID);\n            int fileTransferContactIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_CONTACT);\n            int fileTransferDeliveryExpirationIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_DELIVERY_EXPIRATION);\n            while (cursor.moveToNext()) {\n                String fileTransferId = cursor.getString(fileTransferIdIdx);\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(cursor\n                        .getString(fileTransferContactIdx));\n                long deliveryExpiration = cursor.getLong(fileTransferDeliveryExpirationIdx);\n                if (deliveryExpiration > currentTime) {\n                    mOneToOneUndeliveredImManager.scheduleOneToOneFileTransferDeliveryTimeoutAlarm(\n                            contact, fileTransferId, deliveryExpiration);\n                } else {\n                    mOneToOneUndeliveredImManager.onFileTransferDeliveryExpirationReceived(contact,\n                            fileTransferId);\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    \"Exception occured while recreating delivery expiration alarms for one-to-one chat message and one-to-one file transfer \",\n                    e);\n        } finally {\n            CursorUtil.close(cursor);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"done.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/messaging/UpdateFileTransferStateAfterUngracefulTerminationTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.messaging;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.database.Cursor;\n\npublic class UpdateFileTransferStateAfterUngracefulTerminationTask implements Runnable {\n\n    private final MessagingLog mMessagingLog;\n\n    private final FileTransferServiceImpl mFileTransferService;\n\n    private static final Logger sLogger = Logger\n            .getLogger(UpdateFileTransferStateAfterUngracefulTerminationTask.class.getName());\n\n    public UpdateFileTransferStateAfterUngracefulTerminationTask(MessagingLog messagingLog,\n            FileTransferServiceImpl fileTransferService) {\n        mMessagingLog = messagingLog;\n        mFileTransferService = fileTransferService;\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"initiating.\");\n        }\n        Cursor cursor = null;\n        try {\n            cursor = mMessagingLog.getInterruptedFileTransfers();\n            int chatIdIdx = cursor.getColumnIndex(FileTransferData.KEY_CHAT_ID);\n            int contactIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_CONTACT);\n            int fileTransferIdIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FT_ID);\n            int uploadIdIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_UPLOAD_TID);\n            int downloadUriIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_DOWNLOAD_URI);\n            int stateIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_STATE);\n            int fileExpirationIdx = cursor\n                    .getColumnIndexOrThrow(FileTransferData.KEY_FILE_EXPIRATION);\n            int fileSizeIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_FILESIZE);\n            int transferredIdx = cursor.getColumnIndexOrThrow(FileTransferData.KEY_TRANSFERRED);\n            while (cursor.moveToNext()) {\n                String fileTransferId = cursor.getString(fileTransferIdIdx);\n                String contactNumber = cursor.getString(contactIdx);\n                String chatId = cursor.getString(chatIdIdx);\n                ContactId contact = contactNumber != null ? ContactUtil\n                        .createContactIdFromTrustedData(contactNumber) : null;\n                State state = State.valueOf(cursor.getInt(stateIdx));\n                boolean groupFileTransfer = !chatId.equals(contactNumber);\n                if (cursor.getString(downloadUriIdx) == null\n                        && cursor.getString(uploadIdIdx) == null) {\n                    /* MSRP file transfer */\n                    switch (state) {\n                        case INITIATING:\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.FAILED,\n                                        ReasonCode.FAILED_INITIATION);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.FAILED,\n                                    ReasonCode.FAILED_INITIATION);\n                            break;\n                        case ACCEPTING:\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.ABORTED,\n                                        ReasonCode.ABORTED_BY_SYSTEM);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.ABORTED,\n                                    ReasonCode.ABORTED_BY_SYSTEM);\n                            break;\n                        case STARTED:\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.FAILED,\n                                        ReasonCode.FAILED_DATA_TRANSFER);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.FAILED,\n                                    ReasonCode.FAILED_DATA_TRANSFER);\n                            break;\n                        case INVITED:\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.REJECTED,\n                                        ReasonCode.REJECTED_BY_SYSTEM);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.REJECTED,\n                                    ReasonCode.REJECTED_BY_SYSTEM);\n                            break;\n                        default:\n                            sLogger.error(getClass().getName() + \" unexpected state (\" + state\n                                    + \") detected! Error in SQL statement?\");\n                            break;\n                    }\n                } else {\n                    /* HTTP file transfer */\n                    switch (state) {\n                        case INITIATING:\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.FAILED,\n                                        ReasonCode.FAILED_INITIATION);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.FAILED,\n                                    ReasonCode.FAILED_INITIATION);\n                            break;\n                        case ACCEPTING:\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.ABORTED,\n                                        ReasonCode.ABORTED_BY_SYSTEM);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.ABORTED,\n                                    ReasonCode.ABORTED_BY_SYSTEM);\n                            break;\n                        case STARTED:\n                            if (cursor.getLong(fileSizeIdx) == cursor.getLong(transferredIdx)) {\n                                break;\n                            }\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.PAUSED,\n                                        ReasonCode.PAUSED_BY_SYSTEM);\n                            } else {\n                                mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                        fileTransferId, contact, State.PAUSED,\n                                        ReasonCode.PAUSED_BY_SYSTEM);\n                            }\n                            break;\n                        case INVITED:\n                            if (cursor.getLong(fileExpirationIdx) > System.currentTimeMillis()) {\n                                /* File is not yet expired on the server */\n                                break;\n                            }\n                            if (groupFileTransfer) {\n                                mFileTransferService.setGroupFileTransferStateAndReasonCode(\n                                        fileTransferId, chatId, State.REJECTED,\n                                        ReasonCode.REJECTED_BY_TIMEOUT);\n                                break;\n                            }\n                            mFileTransferService.setOneToOneFileTransferStateAndReasonCode(\n                                    fileTransferId, contact, State.REJECTED,\n                                    ReasonCode.REJECTED_BY_TIMEOUT);\n                            break;\n                        default:\n                            sLogger.error(getClass().getName() + \" unexpected state (\" + state\n                                    + \") detected! Error in SQL statement?\");\n                            break;\n                    }\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    \"Exception occured while trying to update file transfer state for interrupted file transfers\",\n                    e);\n        } finally {\n            CursorUtil.close(cursor);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"done.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/settings/RcsSettings.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.settings;\n\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.extension.ServiceExtensionManager;\nimport com.gsma.rcs.core.ims.service.sip.EnrichCallingService;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.AuthenticationProcedure;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ConfigurationMode;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.EnableRcseSwitch;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.GsmaRelease;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImMsgTech;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImSessionStartMode;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.NetworkAccessType;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption;\n\nimport android.content.ContentProviderOperation;\nimport android.content.ContentValues;\nimport android.content.OperationApplicationException;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * RCS settings\n *\n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic class RcsSettings {\n\n    private final static Logger sLogger = Logger.getLogger(RcsSettings.class.getName());\n\n    /**\n     * Minimum number of participants in a group chat\n     */\n    private static final int MINIMUM_GC_PARTICIPANTS = 2;\n\n    /**\n     * The maximum length of the Group Chat subject\n     */\n    private static final int GROUP_CHAT_SUBJECT_MAX_LENGTH = 50;\n\n    private static final String WHERE_CLAUSE = RcsSettingsData.KEY_KEY + \"=?\";\n\n    /**\n     * Current instance\n     */\n    private static volatile RcsSettings sInstance;\n\n    /**\n     * Local Content resolver\n     */\n    final private LocalContentResolver mLocalContentResolver;\n\n    /**\n     * A cache for storing settings in order to increase performance\n     */\n    final private Map<String, Object> mCache;\n\n    /**\n     * Get or Create Singleton instance of RcsSettings.\n     *\n     * @param localContentResolver Local content resolver\n     * @return RcsSettings instance\n     */\n    public static RcsSettings getInstance(LocalContentResolver localContentResolver) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (RcsSettings.class) {\n            if (sInstance == null) {\n                sInstance = new RcsSettings(localContentResolver);\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Constructor\n     *\n     * @param localContentResolver Local content resolver\n     */\n    private RcsSettings(LocalContentResolver localContentResolver) {\n        super();\n        mLocalContentResolver = localContentResolver;\n        mCache = new HashMap<>();\n    }\n\n    private ContentProviderOperation buildContentProviderOp(String key, String value) {\n        return ContentProviderOperation.newUpdate(RcsSettingsData.CONTENT_URI)\n                .withValue(RcsSettingsData.KEY_VALUE, value)\n                .withSelection(WHERE_CLAUSE, new String[] {\n                    key\n                }).build();\n    }\n\n    private ContentProviderOperation buildContentProviderOp(String key, Object value) {\n        return buildContentProviderOp(key, value == null ? null : value.toString());\n    }\n\n    /**\n     * Read boolean parameter\n     * <p/>\n     * If parsing of the value fails, method return false.\n     *\n     * @param key the key field\n     * @return the value field\n     */\n    public boolean readBoolean(String key) {\n        Boolean value = (Boolean) mCache.get(key);\n        if (value == null) {\n            value = Boolean.parseBoolean(readParameter(key));\n            mCache.put(key, value);\n        }\n        return value;\n    }\n\n    /**\n     * Write boolean parameter\n     *\n     * @param key the key field\n     * @param value the boolean value\n     */\n    public void writeBoolean(String key, Boolean value) {\n        if (writeParameter(key, value.toString()) != 0) {\n            mCache.put(key, value);\n        }\n    }\n\n    /**\n     * Read int parameter\n     * <p/>\n     * If parsing of the value fails, method return default value.\n     *\n     * @param key the key field\n     * @return the value field\n     */\n    public int readInteger(String key) {\n        Integer value = (Integer) mCache.get(key);\n        if (value == null) {\n            value = Integer.parseInt(readParameter(key));\n            mCache.put(key, value);\n        }\n        return value;\n    }\n\n    /**\n     * Read long parameter\n     * <p/>\n     * If parsing of the value fails, method return default value.\n     *\n     * @param key the key field\n     * @return the value field\n     */\n    public long readLong(String key) {\n        Long value = (Long) mCache.get(key);\n        if (value == null) {\n            value = Long.parseLong(readParameter(key));\n            mCache.put(key, value);\n        }\n        return value;\n    }\n\n    /**\n     * Read String parameter\n     *\n     * @param key the key field\n     * @return the value field or defaultValue (if read fails)\n     */\n    public String readString(String key) {\n        String value = (String) mCache.get(key);\n        if (value == null && !mCache.containsKey(key)) {\n            value = readParameter(key);\n            mCache.put(key, value);\n        }\n        return value;\n    }\n\n    /**\n     * Write integer parameter\n     *\n     * @param key the key field\n     * @param value the integer value\n     */\n    public void writeInteger(String key, Integer value) {\n        if (writeParameter(key, value.toString()) != 0) {\n            mCache.put(key, value);\n        }\n    }\n\n    /**\n     * Write long parameter\n     *\n     * @param key the key field\n     * @param value the long value\n     */\n    public void writeLong(String key, Long value) {\n        if (writeParameter(key, value.toString()) != 0) {\n            mCache.put(key, value);\n        }\n    }\n\n    /**\n     * Write String parameter\n     *\n     * @param key the key field\n     * @param value the long value\n     */\n    public void writeString(String key, String value) {\n        if (writeParameter(key, value) != 0) {\n            mCache.put(key, value);\n        }\n    }\n\n    /**\n     * Read Uri parameter\n     *\n     * @param key the key field\n     * @return the value field or defaultValue (if read fails)\n     */\n    public Uri readUri(String key) {\n        Uri value = (Uri) mCache.get(key);\n        if (value == null && !mCache.containsKey(key)) {\n            String dbValue = readParameter(key);\n            if (dbValue != null) {\n                value = Uri.parse(dbValue);\n            }\n            mCache.put(key, value);\n        }\n        return value;\n    }\n\n    /**\n     * Write uri parameter\n     *\n     * @param key the key field\n     * @param value the long value\n     */\n    public void writeUri(String key, Uri value) {\n        if (writeParameter(key, value == null ? null : value.toString()) != 0) {\n            mCache.put(key, value);\n        }\n    }\n\n    /**\n     * Read ContactId parameter\n     *\n     * @param key the key field\n     * @return the value field or defaultValue (if read fails)\n     */\n    public ContactId readContactId(String key) {\n        ContactId value = (ContactId) mCache.get(key);\n        if (value == null && !mCache.containsKey(key)) {\n            String dbValue = readParameter(key);\n            if (dbValue != null) {\n                value = ContactUtil.createContactIdFromTrustedData(dbValue);\n            }\n            mCache.put(key, value);\n        }\n        return value;\n    }\n\n    /**\n     * Write ContactId parameter\n     *\n     * @param key the key field\n     * @param value the long value\n     */\n    public void writeContactId(String key, ContactId value) {\n        if (writeParameter(key, value == null ? null : value.toString()) != 0) {\n            mCache.put(key, value);\n        }\n    }\n\n    /**\n     * Read a parameter from database\n     *\n     * @param key Key\n     * @return Value\n     */\n    private String readParameter(String key) {\n        Cursor c = null;\n        try {\n            String[] whereArg = new String[] {\n                key\n            };\n            c = mLocalContentResolver.query(RcsSettingsData.CONTENT_URI, null, WHERE_CLAUSE,\n                    whereArg, null);\n            CursorUtil.assertCursorIsNotNull(c, RcsSettingsData.CONTENT_URI);\n            if (!c.moveToFirst()) {\n                throw new IllegalArgumentException(\"Illegal setting key:\" + key);\n            }\n            return c.getString(c.getColumnIndexOrThrow(RcsSettingsData.KEY_VALUE));\n\n        } finally {\n            if (c != null) {\n                c.close();\n            }\n        }\n    }\n\n    /**\n     * Write a string setting parameter to Database\n     *\n     * @param key the key setting\n     * @param value the value setting\n     * @return the number of rows updated\n     */\n    private int writeParameter(String key, String value) {\n        ContentValues values = new ContentValues();\n        values.put(RcsSettingsData.KEY_VALUE, value);\n        String[] whereArgs = new String[] {\n            key\n        };\n        return mLocalContentResolver.update(RcsSettingsData.CONTENT_URI, values, WHERE_CLAUSE,\n                whereArgs);\n    }\n\n    /**\n     * Is RCS service activated\n     *\n     * @return Boolean\n     */\n    public boolean isServiceActivated() {\n        return readBoolean(RcsSettingsData.SERVICE_ACTIVATED);\n    }\n\n    /**\n     * Set the RCS service activation state\n     *\n     * @param state State\n     */\n    public void setServiceActivationState(boolean state) {\n        writeBoolean(RcsSettingsData.SERVICE_ACTIVATED, state);\n    }\n\n    /**\n     * Is send displayed notification activated\n     *\n     * @return Boolean\n     */\n    public boolean isRespondToDisplayReports() {\n        return readBoolean(RcsSettingsData.CHAT_RESPOND_TO_DISPLAY_REPORTS);\n    }\n\n    /**\n     * Set send displayed notification\n     *\n     * @param state True if respond to display reports\n     */\n    public void setRespondToDisplayReports(boolean state) {\n        writeBoolean(RcsSettingsData.CHAT_RESPOND_TO_DISPLAY_REPORTS, state);\n    }\n\n    /**\n     * Get the min battery level\n     *\n     * @return Battery level in percentage\n     */\n    public MinimumBatteryLevel getMinBatteryLevel() {\n        return MinimumBatteryLevel.valueOf(readInteger(RcsSettingsData.MIN_BATTERY_LEVEL));\n    }\n\n    /**\n     * Set the min battery level\n     *\n     * @param level Battery level in percentage\n     */\n    public void setMinBatteryLevel(MinimumBatteryLevel level) {\n        writeInteger(RcsSettingsData.MIN_BATTERY_LEVEL, level.toInt());\n    }\n\n    /**\n     * Get user profile username (i.e. username part of the IMPU)\n     *\n     * @return Username part of SIP-URI or null if not provisioned\n     */\n    public ContactId getUserProfileImsUserName() {\n        return readContactId(RcsSettingsData.USERPROFILE_IMS_USERNAME);\n    }\n\n    /**\n     * Set user profile IMS username (i.e. username part of the IMPU)\n     *\n     * @param contact the contact ID\n     */\n    public void setUserProfileImsUserName(ContactId contact) {\n        writeContactId(RcsSettingsData.USERPROFILE_IMS_USERNAME, contact);\n    }\n\n    /**\n     * Get UUID(Universally Unique Identifier) format: 8-4-4-4-12 hex digits\n     *\n     * @return uuid value\n     */\n    public String getUUID() {\n        return readString(RcsSettingsData.UUID);\n    }\n\n    /**\n     * Get user profile IMS display name associated to IMPU\n     *\n     * @return String\n     */\n    public String getUserProfileImsDisplayName() {\n        return readString(RcsSettingsData.USERPROFILE_IMS_DISPLAY_NAME);\n    }\n\n    /**\n     * Set user profile IMS display name associated to IMPU\n     *\n     * @param value Value\n     */\n    public void setUserProfileImsDisplayName(String value) {\n        writeString(RcsSettingsData.USERPROFILE_IMS_DISPLAY_NAME, value);\n    }\n\n    /**\n     * Get user profile IMS private Id (i.e. IMPI)\n     *\n     * @return SIP-URI\n     */\n    public String getUserProfileImsPrivateId() {\n        return readString(RcsSettingsData.USERPROFILE_IMS_PRIVATE_ID);\n    }\n\n    /**\n     * Set user profile IMS private Id (i.e. IMPI)\n     *\n     * @param uri SIP-URI\n     */\n    public void setUserProfileImsPrivateId(String uri) {\n        writeString(RcsSettingsData.USERPROFILE_IMS_PRIVATE_ID, uri);\n    }\n\n    /**\n     * Get user profile IMS password\n     *\n     * @return String\n     */\n    public String getUserProfileImsPassword() {\n        return readString(RcsSettingsData.USERPROFILE_IMS_PASSWORD);\n    }\n\n    /**\n     * Set user profile IMS password\n     *\n     * @param pwd Password\n     */\n    public void setUserProfileImsPassword(String pwd) {\n        writeString(RcsSettingsData.USERPROFILE_IMS_PASSWORD, pwd);\n    }\n\n    /**\n     * Get user profile IMS realm\n     *\n     * @return String\n     */\n    public String getUserProfileImsRealm() {\n        return readString(RcsSettingsData.USERPROFILE_IMS_REALM);\n    }\n\n    /**\n     * Set user profile IMS realm\n     *\n     * @param realm Realm\n     */\n    public void setUserProfileImsRealm(String realm) {\n        writeString(RcsSettingsData.USERPROFILE_IMS_REALM, realm);\n    }\n\n    /**\n     * Get user profile IMS home domain\n     *\n     * @return Domain\n     */\n    public String getUserProfileImsDomain() {\n        return readString(RcsSettingsData.USERPROFILE_IMS_HOME_DOMAIN);\n    }\n\n    /**\n     * Set user profile IMS home domain\n     *\n     * @param domain Domain\n     */\n    public void setUserProfileImsDomain(String domain) {\n        writeString(RcsSettingsData.USERPROFILE_IMS_HOME_DOMAIN, domain);\n    }\n\n    /**\n     * Get IMS proxy address for mobile access\n     *\n     * @return Address\n     */\n    public String getImsProxyAddrForMobile() {\n        return readString(RcsSettingsData.IMS_PROXY_ADDR_MOBILE);\n    }\n\n    /**\n     * Set IMS proxy address for mobile access\n     *\n     * @param addr Address\n     */\n    public void setImsProxyAddrForMobile(String addr) {\n        writeString(RcsSettingsData.IMS_PROXY_ADDR_MOBILE, addr);\n    }\n\n    /**\n     * Get IMS proxy port for mobile access\n     *\n     * @return Port\n     */\n    public int getImsProxyPortForMobile() {\n        return readInteger(RcsSettingsData.IMS_PROXY_PORT_MOBILE);\n    }\n\n    /**\n     * Set IMS proxy port for mobile access\n     *\n     * @param port Port number\n     */\n    public void setImsProxyPortForMobile(int port) {\n        writeInteger(RcsSettingsData.IMS_PROXY_PORT_MOBILE, port);\n    }\n\n    /**\n     * Get IMS proxy address for Wi-Fi access\n     *\n     * @return Address\n     */\n    public String getImsProxyAddrForWifi() {\n        return readString(RcsSettingsData.IMS_PROXY_ADDR_WIFI);\n    }\n\n    /**\n     * Set IMS proxy address for Wi-Fi access\n     *\n     * @param addr Address\n     */\n    public void setImsProxyAddrForWifi(String addr) {\n        writeString(RcsSettingsData.IMS_PROXY_ADDR_WIFI, addr);\n    }\n\n    /**\n     * Get IMS proxy port for Wi-Fi access\n     *\n     * @return Port\n     */\n    public int getImsProxyPortForWifi() {\n        return readInteger(RcsSettingsData.IMS_PROXY_PORT_WIFI);\n    }\n\n    /**\n     * Set IMS proxy port for Wi-Fi access\n     *\n     * @param port Port number\n     */\n    public void setImsProxyPortForWifi(int port) {\n        writeInteger(RcsSettingsData.IMS_PROXY_PORT_WIFI, port);\n    }\n\n    /**\n     * Get XDM server address\n     *\n     * @return Address as <host>:<port>/<root>\n     */\n    public Uri getXdmServer() {\n        return readUri(RcsSettingsData.XDM_SERVER);\n    }\n\n    /**\n     * Set XDM server address\n     *\n     * @param addr Address as <host>:<port>/<root>\n     */\n    public void setXdmServer(Uri addr) {\n        writeUri(RcsSettingsData.XDM_SERVER, addr);\n    }\n\n    /**\n     * Get XDM server login\n     *\n     * @return String value\n     */\n    public String getXdmLogin() {\n        return readString(RcsSettingsData.XDM_LOGIN);\n    }\n\n    /**\n     * Set XDM server login\n     *\n     * @param value Value\n     */\n    public void setXdmLogin(String value) {\n        writeString(RcsSettingsData.XDM_LOGIN, value);\n    }\n\n    /**\n     * Get XDM server password\n     *\n     * @return String value\n     */\n    public String getXdmPassword() {\n        return readString(RcsSettingsData.XDM_PASSWORD);\n    }\n\n    /**\n     * Set XDM server password\n     *\n     * @param value Value\n     */\n    public void setXdmPassword(String value) {\n        writeString(RcsSettingsData.XDM_PASSWORD, value);\n    }\n\n    /**\n     * Get file transfer HTTP server address\n     *\n     * @return Address\n     */\n    public Uri getFtHttpServer() {\n        return readUri(RcsSettingsData.FT_HTTP_SERVER);\n    }\n\n    /**\n     * Set file transfer HTTP server address\n     *\n     * @param addr Address\n     */\n    public void setFtHttpServer(Uri addr) {\n        writeUri(RcsSettingsData.FT_HTTP_SERVER, addr);\n    }\n\n    /**\n     * Get file transfer HTTP server login\n     *\n     * @return String value\n     */\n    public String getFtHttpLogin() {\n        return readString(RcsSettingsData.FT_HTTP_LOGIN);\n    }\n\n    /**\n     * Set file transfer HTTP server login\n     *\n     * @param value Value\n     */\n    public void setFtHttpLogin(String value) {\n        writeString(RcsSettingsData.FT_HTTP_LOGIN, value);\n    }\n\n    /**\n     * Get file transfer HTTP server password\n     *\n     * @return String value\n     */\n    public String getFtHttpPassword() {\n        return readString(RcsSettingsData.FT_HTTP_PASSWORD);\n    }\n\n    /**\n     * Set file transfer HTTP server password\n     *\n     * @param value Value\n     */\n    public void setFtHttpPassword(String value) {\n        writeString(RcsSettingsData.FT_HTTP_PASSWORD, value);\n    }\n\n    /**\n     * Get file transfer protocol\n     *\n     * @return FileTransferProtocol\n     */\n    public FileTransferProtocol getFtProtocol() {\n        String protocol = readString(RcsSettingsData.FT_PROTOCOL);\n        return FileTransferProtocol.valueOf(protocol);\n    }\n\n    /**\n     * Set file transfer protocol\n     *\n     * @param protocol the protocol\n     */\n    public void setFtProtocol(FileTransferProtocol protocol) {\n        writeString(RcsSettingsData.FT_PROTOCOL, protocol.name());\n    }\n\n    /**\n     * Get IM conference URI\n     *\n     * @return SIP-URI\n     */\n    public Uri getImConferenceUri() {\n        return readUri(RcsSettingsData.IM_CONF_URI);\n    }\n\n    /**\n     * Set IM conference URI\n     *\n     * @param uri SIP-URI\n     */\n    public void setImConferenceUri(Uri uri) {\n        writeUri(RcsSettingsData.IM_CONF_URI, uri);\n    }\n\n    /**\n     * Get end user confirmation request URI\n     *\n     * @return SIP-URI\n     */\n    public Uri getEndUserConfirmationRequestUri() {\n        return readUri(RcsSettingsData.ENDUSER_CONFIRMATION_URI);\n    }\n\n    /**\n     * Set end user confirmation request\n     *\n     * @param uri SIP-URI\n     */\n    public void setEndUserConfirmationRequestUri(Uri uri) {\n        writeUri(RcsSettingsData.ENDUSER_CONFIRMATION_URI, uri);\n    }\n\n    /**\n     * Get my capabilities\n     *\n     * @return capability\n     */\n    public Capabilities getMyCapabilities() {\n        /* Initialize with default capabilities */\n        CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder();\n        /* Add my own capabilities */\n        capaBuilder.setCsVideo(isCsVideoSupported());\n        capaBuilder.setFileTransferMsrp(isFileTransferSupported());\n        capaBuilder.setFileTransferHttp(isFileTransferHttpSupported());\n        capaBuilder.setImageSharing(isImageSharingSupported());\n        capaBuilder.setImSession(isImSessionSupported());\n        capaBuilder.setPresenceDiscovery(isPresenceDiscoverySupported());\n        capaBuilder.setSocialPresence(isSocialPresenceSupported());\n        capaBuilder.setVideoSharing(isVideoSharingSupported());\n        capaBuilder.setGeolocationPush(isGeoLocationPushSupported());\n        capaBuilder.setFileTransferThumbnail(isFileTransferThumbnailSupported());\n        capaBuilder.setFileTransferStoreForward(isFileTransferStoreForwardSupported());\n        capaBuilder.setIpVoiceCall(isIPVoiceCallSupported());\n        capaBuilder.setIpVideoCall(isIPVideoCallSupported());\n        capaBuilder.setGroupChatStoreForward(isGroupChatStoreForwardSupported());\n        capaBuilder.setSipAutomata(isSipAutomata());\n        capaBuilder.setTimestampOfLastRequest(Capabilities.INVALID_TIMESTAMP);\n        capaBuilder.setTimestampOfLastResponse(Capabilities.INVALID_TIMESTAMP);\n        /* Add extensions */\n        capaBuilder.setExtensions(getSupportedRcsExtensions());\n        return capaBuilder.build();\n    }\n\n    /**\n     * Get max photo-icon size\n     *\n     * @return Size in bytes\n     */\n    public long getMaxPhotoIconSize() {\n        return readLong(RcsSettingsData.MAX_PHOTO_ICON_SIZE);\n    }\n\n    /**\n     * Sets max photo-icon size\n     *\n     * @param size the maximum photo icon size\n     */\n    public void setMaxPhotoIconSize(long size) {\n        writeLong(RcsSettingsData.MAX_PHOTO_ICON_SIZE, size);\n    }\n\n    /**\n     * Get max number of participants in a group chat\n     *\n     * @return Number of participants\n     */\n    public int getMaxChatParticipants() {\n        return readInteger(RcsSettingsData.MAX_CHAT_PARTICIPANTS);\n    }\n\n    /**\n     * @return minimum number of participants in a Group Chat\n     */\n    public int getMinGroupChatParticipants() {\n        return MINIMUM_GC_PARTICIPANTS;\n    }\n\n    /**\n     * Get max length of a chat message\n     *\n     * @return Number of char\n     */\n    public int getMaxChatMessageLength() {\n        return readInteger(RcsSettingsData.MAX_CHAT_MSG_LENGTH);\n    }\n\n    /**\n     * Get max length of a group chat message\n     *\n     * @return Number of char\n     */\n    public int getMaxGroupChatMessageLength() {\n        return readInteger(RcsSettingsData.MAX_GROUPCHAT_MSG_LENGTH);\n    }\n\n    /**\n     * Get idle duration of a chat session\n     *\n     * @return Duration in milliseconds\n     */\n    public long getChatIdleDuration() {\n        return readLong(RcsSettingsData.CHAT_IDLE_DURATION);\n    }\n\n    /**\n     * Get max file transfer size\n     *\n     * @return Size in bytes\n     */\n    public long getMaxFileTransferSize() {\n        return readLong(RcsSettingsData.MAX_FILE_TRANSFER_SIZE);\n    }\n\n    /**\n     * Sets warning threshold for max file transfer size\n     *\n     * @param size the maximum file transfer size\n     */\n    public void setMaxFileTransferSize(long size) {\n        writeLong(RcsSettingsData.MAX_FILE_TRANSFER_SIZE, size);\n    }\n\n    /**\n     * Get warning threshold for max file transfer size\n     *\n     * @return Size in bytes\n     */\n    public long getWarningMaxFileTransferSize() {\n        return readLong(RcsSettingsData.WARN_FILE_TRANSFER_SIZE);\n    }\n\n    /**\n     * Sets warning threshold for max file transfer size\n     *\n     * @param size the warning threshold for file transfer size\n     */\n    public void setWarningMaxFileTransferSize(long size) {\n        writeLong(RcsSettingsData.WARN_FILE_TRANSFER_SIZE, size);\n    }\n\n    /**\n     * Gets the max image share size\n     *\n     * @return Size in bytes\n     */\n    public long getMaxImageSharingSize() {\n        return readLong(RcsSettingsData.MAX_IMAGE_SHARE_SIZE);\n    }\n\n    /**\n     * Sets the max image share size\n     *\n     * @param size the maximum image sharing size\n     */\n    public void setMaxImageSharingSize(long size) {\n        writeLong(RcsSettingsData.MAX_IMAGE_SHARE_SIZE, size);\n    }\n\n    /**\n     * Get max duration of a video share\n     *\n     * @return Duration in milliseconds\n     */\n    public long getMaxVideoShareDuration() {\n        return readLong(RcsSettingsData.MAX_VIDEO_SHARE_DURATION);\n    }\n\n    /**\n     * Get max audio message duration of a video share\n     *\n     * @return Duration in milliseconds\n     */\n    public long getMaxAudioMessageDuration() {\n        return readLong(RcsSettingsData.MAX_AUDIO_MESSAGE_DURATION);\n    }\n\n    /**\n     * Get max number of simultaneous chat sessions\n     *\n     * @return Number of sessions\n     */\n    public int getMaxChatSessions() {\n        return readInteger(RcsSettingsData.MAX_CHAT_SESSIONS);\n    }\n\n    /**\n     * Get max number of simultaneous file transfer sessions\n     *\n     * @return Number of sessions\n     */\n    public int getMaxFileTransferSessions() {\n        return readInteger(RcsSettingsData.MAX_FILE_TRANSFER_SESSIONS);\n    }\n\n    /**\n     * Get max number of simultaneous outgoing file transfer sessions\n     *\n     * @return Number of sessions\n     */\n    public int getMaxConcurrentOutgoingFileTransferSessions() {\n        return readInteger(RcsSettingsData.MAX_CONCURRENT_OUTGOING_FILE_TRANSFERS);\n    }\n\n    /**\n     * Is SMS fallback service activated\n     *\n     * @return Boolean\n     */\n    public boolean isSmsFallbackServiceActivated() {\n        return readBoolean(RcsSettingsData.SMS_FALLBACK_SERVICE);\n    }\n\n    /**\n     * Is chat invitation auto accepted\n     *\n     * @return Boolean\n     */\n    public boolean isChatAutoAccepted() {\n        return readBoolean(RcsSettingsData.AUTO_ACCEPT_CHAT);\n    }\n\n    /**\n     * Is group chat invitation auto accepted\n     *\n     * @return Boolean\n     */\n    public boolean isGroupChatAutoAccepted() {\n        return readBoolean(RcsSettingsData.AUTO_ACCEPT_GROUP_CHAT);\n    }\n\n    /**\n     * Is file transfer invitation auto accepted\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferAutoAccepted() {\n        return readBoolean(RcsSettingsData.AUTO_ACCEPT_FILE_TRANSFER);\n    }\n\n    /**\n     * Is Store & Forward service warning activated\n     *\n     * @return Boolean\n     */\n    public boolean isStoreForwardWarningActivated() {\n        return readBoolean(RcsSettingsData.WARN_SF_SERVICE);\n    }\n\n    /**\n     * Get IM session start mode\n     *\n     * @return the IM session start mode\n     *         <p/>\n     *         <ul>\n     *         <li>0 (RCS-e default): The 200 OK is sent when the receiver consumes the notification\n     *         opening the chat window.\n     *         <li>1 (RCS default): The 200 OK is sent when the receiver starts to type a message\n     *         back in the chat window.\n     *         <li>2: The 200 OK is sent when the receiver presses the button to send a message\n     *         (that is the message will be buffered in the client until the MSRP session is\n     *         established). Note: as described in section 3.2, the parameter only affects the\n     *         behavior for 1-to-1 sessions in case no session between the parties has been\n     *         established yet.\n     *         </ul>\n     */\n    public ImSessionStartMode getImSessionStartMode() {\n        return ImSessionStartMode.valueOf(readInteger(RcsSettingsData.IM_SESSION_START));\n    }\n\n    /**\n     * Set IM session start mode\n     *\n     * @param mode IM session start mode\n     */\n    public void setImSessionStartMode(ImSessionStartMode mode) {\n        writeInteger(RcsSettingsData.IM_SESSION_START, mode.toInt());\n    }\n\n    /**\n     * Get polling period used before each IMS service check (e.g. test subscription state for\n     * presence service)\n     *\n     * @return Period in milliseconds\n     */\n    public long getImsServicePollingPeriod() {\n        return readLong(RcsSettingsData.IMS_SERVICE_POLLING_PERIOD);\n    }\n\n    /**\n     * Get default SIP listening port\n     *\n     * @return Port\n     */\n    public int getSipListeningPort() {\n        return readInteger(RcsSettingsData.SIP_DEFAULT_PORT);\n    }\n\n    /**\n     * Get default SIP protocol for mobile\n     *\n     * @return Protocol (udp | tcp | tls)\n     */\n    public String getSipDefaultProtocolForMobile() {\n        return readString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_MOBILE);\n    }\n\n    /**\n     * Get default SIP protocol for wifi\n     *\n     * @return Protocol (udp | tcp | tls)\n     */\n    public String getSipDefaultProtocolForWifi() {\n        return readString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_WIFI);\n    }\n\n    /**\n     * Get TLS Certificate root\n     *\n     * @return Path of the certificate\n     */\n    public String getTlsCertificateRoot() {\n        return readString(RcsSettingsData.TLS_CERTIFICATE_ROOT);\n    }\n\n    /**\n     * Get TLS Certificate intermediate\n     *\n     * @return Path of the certificate\n     */\n    public String getTlsCertificateIntermediate() {\n        return readString(RcsSettingsData.TLS_CERTIFICATE_INTERMEDIATE);\n    }\n\n    /**\n     * Get SIP transaction timeout used to wait SIP response\n     *\n     * @return Timeout in milliseconds\n     */\n    public long getSipTransactionTimeout() {\n        return readLong(RcsSettingsData.SIP_TRANSACTION_TIMEOUT);\n    }\n\n    /**\n     * Get default MSRP port\n     *\n     * @return Port\n     */\n    public int getDefaultMsrpPort() {\n        return readInteger(RcsSettingsData.MSRP_DEFAULT_PORT);\n    }\n\n    /**\n     * Get default RTP port\n     *\n     * @return Port\n     */\n    public int getDefaultRtpPort() {\n        return readInteger(RcsSettingsData.RTP_DEFAULT_PORT);\n    }\n\n    /**\n     * Get MSRP transaction timeout used to wait MSRP response\n     *\n     * @return Timeout in milliseconds\n     */\n    public long getMsrpTransactionTimeout() {\n        return readLong(RcsSettingsData.MSRP_TRANSACTION_TIMEOUT);\n    }\n\n    /**\n     * Get default expire period for REGISTER\n     *\n     * @return Period in milliseconds\n     */\n    public long getRegisterExpirePeriod() {\n        return readLong(RcsSettingsData.REGISTER_EXPIRE_PERIOD);\n    }\n\n    /**\n     * Get registration retry base time\n     *\n     * @return Time in milliseconds\n     */\n    public long getRegisterRetryBaseTime() {\n        return readLong(RcsSettingsData.REGISTER_RETRY_BASE_TIME);\n    }\n\n    /**\n     * Get registration retry max time\n     *\n     * @return Time in milliseconds\n     */\n    public long getRegisterRetryMaxTime() {\n        return readLong(RcsSettingsData.REGISTER_RETRY_MAX_TIME);\n    }\n\n    /**\n     * Get default expire period for PUBLISH\n     *\n     * @return Period in milliseconds\n     */\n    public long getPublishExpirePeriod() {\n        return readLong(RcsSettingsData.PUBLISH_EXPIRE_PERIOD);\n    }\n\n    /**\n     * Get IMS authentication procedure for mobile access\n     *\n     * @return Authentication procedure\n     */\n    public AuthenticationProcedure getImsAuthenticationProcedureForMobile() {\n        return AuthenticationProcedure\n                .valueOf(readString(RcsSettingsData.IMS_AUTHENT_PROCEDURE_MOBILE));\n    }\n\n    /**\n     * Set the authentication procedure for mobile\n     *\n     * @param procedure the procedure\n     */\n    public void setImsAuthenticationProcedureForMobile(AuthenticationProcedure procedure) {\n        writeString(RcsSettingsData.IMS_AUTHENT_PROCEDURE_MOBILE, procedure.name());\n    }\n\n    /**\n     * Get IMS authentication procedure for Wi-Fi access\n     *\n     * @return Authentication procedure\n     */\n    public AuthenticationProcedure getImsAuthenticationProcedureForWifi() {\n        return AuthenticationProcedure\n                .valueOf(readString(RcsSettingsData.IMS_AUTHENT_PROCEDURE_WIFI));\n    }\n\n    /**\n     * Set the authentication procedure for Wi-Fi\n     *\n     * @param procedure the procedure\n     */\n    public void setImsAuhtenticationProcedureForWifi(AuthenticationProcedure procedure) {\n        writeString(RcsSettingsData.IMS_AUTHENT_PROCEDURE_WIFI, procedure.name());\n    }\n\n    /**\n     * Is Tel-URI format used\n     *\n     * @return Boolean\n     */\n    public boolean isTelUriFormatUsed() {\n        return readBoolean(RcsSettingsData.TEL_URI_FORMAT);\n    }\n\n    /**\n     * Get ringing period\n     *\n     * @return Period in milliseconds\n     */\n    public long getRingingPeriod() {\n        return readLong(RcsSettingsData.RINGING_SESSION_PERIOD);\n    }\n\n    /**\n     * Get default expire period for SUBSCRIBE\n     *\n     * @return Period in milliseconds\n     */\n    public long getSubscribeExpirePeriod() {\n        return readLong(RcsSettingsData.SUBSCRIBE_EXPIRE_PERIOD);\n    }\n\n    /**\n     * Get \"Is-composing\" timeout for chat service\n     *\n     * @return Timer in milliseconds\n     */\n    public long getIsComposingTimeout() {\n        return readLong(RcsSettingsData.IS_COMPOSING_TIMEOUT);\n    }\n\n    /**\n     * Get default expire period for INVITE (session refresh)\n     *\n     * @return Period in milliseconds\n     */\n    public long getSessionRefreshExpirePeriod() {\n        return readLong(RcsSettingsData.SESSION_REFRESH_EXPIRE_PERIOD);\n    }\n\n    /**\n     * Is permanente state mode activated\n     *\n     * @return Boolean\n     */\n    public boolean isPermanentStateModeActivated() {\n        return readBoolean(RcsSettingsData.PERMANENT_STATE_MODE);\n    }\n\n    /**\n     * Is trace activated\n     *\n     * @return Boolean\n     */\n    public boolean isTraceActivated() {\n        return readBoolean(RcsSettingsData.TRACE_ACTIVATED);\n    }\n\n    /**\n     * Get trace level\n     *\n     * @return trace level\n     */\n    public int getTraceLevel() {\n        return readInteger(RcsSettingsData.TRACE_LEVEL);\n    }\n\n    /**\n     * Is media trace activated\n     *\n     * @return Boolean\n     */\n    public boolean isSipTraceActivated() {\n        return readBoolean(RcsSettingsData.SIP_TRACE_ACTIVATED);\n    }\n\n    /**\n     * Get SIP trace file\n     *\n     * @return SIP trace file\n     */\n    public String getSipTraceFile() {\n        return readString(RcsSettingsData.SIP_TRACE_FILE);\n    }\n\n    /**\n     * Is media trace activated\n     *\n     * @return Boolean\n     */\n    public boolean isMediaTraceActivated() {\n        return readBoolean(RcsSettingsData.MEDIA_TRACE_ACTIVATED);\n    }\n\n    /**\n     * Get capability refresh timeout used to avoid too many requests in a short time\n     *\n     * @return Timeout in milliseconds\n     */\n    public long getCapabilityRefreshTimeout() {\n        return readLong(RcsSettingsData.CAPABILITY_REFRESH_TIMEOUT);\n    }\n\n    /**\n     * Get capability expiry timeout used to decide when to refresh contact capabilities\n     *\n     * @return Timeout in milliseconds\n     */\n    public long getCapabilityExpiryTimeout() {\n        return readLong(RcsSettingsData.CAPABILITY_EXPIRY_TIMEOUT);\n    }\n\n    /**\n     * Get capability polling period used to refresh contacts capabilities\n     *\n     * @return Timeout in milliseconds\n     */\n    public long getCapabilityPollingPeriod() {\n        return readLong(RcsSettingsData.CAPABILITY_POLLING_PERIOD);\n    }\n\n    /**\n     * Is CS video supported\n     *\n     * @return Boolean\n     */\n    public boolean isCsVideoSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_CS_VIDEO);\n    }\n\n    /**\n     * Is file transfer supported\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_FILE_TRANSFER);\n    }\n\n    /**\n     * Set HTTP file transfer support\n     *\n     * @param supported true if HTTP file transfer is supported\n     */\n    public void setFileTransferHttpSupported(boolean supported) {\n        writeBoolean(RcsSettingsData.CAPABILITY_FILE_TRANSFER_HTTP, supported);\n    }\n\n    /**\n     * Is file transfer via HTTP supported\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferHttpSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_FILE_TRANSFER_HTTP);\n    }\n\n    /**\n     * Is IM session supported\n     *\n     * @return Boolean\n     */\n    public boolean isImSessionSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_IM_SESSION);\n    }\n\n    /**\n     * Is image sharing supported\n     *\n     * @return Boolean\n     */\n    public boolean isImageSharingSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_IMAGE_SHARING);\n    }\n\n    /**\n     * Is video sharing supported\n     *\n     * @return Boolean\n     */\n    public boolean isVideoSharingSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_VIDEO_SHARING);\n    }\n\n    /**\n     * Is presence discovery supported\n     *\n     * @return Boolean\n     */\n    public boolean isPresenceDiscoverySupported() {\n        return getXdmServer() != null && readBoolean(RcsSettingsData.CAPABILITY_PRESENCE_DISCOVERY);\n    }\n\n    /**\n     * Is social presence supported\n     *\n     * @return Boolean\n     */\n    public boolean isSocialPresenceSupported() {\n        return getXdmServer() != null && readBoolean(RcsSettingsData.CAPABILITY_SOCIAL_PRESENCE);\n    }\n\n    /**\n     * Is geolocation push supported\n     *\n     * @return Boolean\n     */\n    public boolean isGeoLocationPushSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH);\n    }\n\n    /**\n     * Is file transfer thumbnail supported\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferThumbnailSupported() {\n        // Thumbnail is only supported in HTPP.\n        // The thThumbnail configuration settings is fixed 0 for MSRP per specification.\n        // Refer to PDD v3 page 106.\n        return isFileTransferHttpSupported();\n    }\n\n    /**\n     * Is file transfer Store & Forward supported\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferStoreForwardSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_FILE_TRANSFER_SF);\n    }\n\n    /**\n     * Is IP voice call supported\n     *\n     * @return Boolean\n     */\n    public boolean isIPVoiceCallSupported() {\n        // TODO: Add Ipcall support here in future releases\n        // return readBoolean(RcsSettingsData.CAPABILITY_IP_VOICE_CALL);\n        return false;\n    }\n\n    /**\n     * Is IP video call supported\n     *\n     * @return Boolean\n     */\n    public boolean isIPVideoCallSupported() {\n        // TODO: Add Ipcall support here in future releases\n        // return readBoolean(RcsSettingsData.CAPABILITY_IP_VIDEO_CALL);\n        return false;\n    }\n\n    /**\n     * Is group chat Store & Forward supported\n     *\n     * @return Boolean\n     */\n    public boolean isGroupChatStoreForwardSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_GROUP_CHAT_SF);\n    }\n\n    /**\n     * Is invite only if group chat Store & Forward supported\n     *\n     * @return Boolean\n     */\n    public boolean isGroupChatInviteIfFullStoreForwardSupported() {\n        return readBoolean(RcsSettingsData.GROUP_CHAT_INVITE_ONLY_FULL_SF);\n    }\n\n    /**\n     * Get set of supported RCS extensions\n     *\n     * @return the set of extensions\n     */\n    public Set<String> getSupportedRcsExtensions() {\n        return ServiceExtensionManager\n                .getExtensions(readString(RcsSettingsData.CAPABILITY_RCS_EXTENSIONS));\n    }\n\n    /**\n     * Set the set of supported RCS extensions\n     *\n     * @param extensions Set of extensions\n     */\n    public void setSupportedRcsExtensions(Set<String> extensions) {\n        writeString(RcsSettingsData.CAPABILITY_RCS_EXTENSIONS,\n                ServiceExtensionManager.getExtensions(extensions));\n    }\n\n    /**\n     * Is call composer supported\n     *\n     * @return Boolean\n     */\n    public boolean isCallComposerSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_CALL_COMPOSER);\n    }\n\n    /**\n     * Is shared map supported\n     *\n     * @return Boolean\n     */\n    public boolean isSharedMapSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_SHARED_MAP);\n    }\n\n    /**\n     * Is shared sketch supported\n     *\n     * @return Boolean\n     */\n    public boolean isSharedSketchSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_SHARED_SKETCH);\n    }\n\n    /**\n     * Is post call supported\n     *\n     * @return Boolean\n     */\n    public boolean isPostCallSupported() {\n        return readBoolean(RcsSettingsData.CAPABILITY_POST_CALL);\n    }\n\n    /**\n     * Is IM always-on thanks to the Store & Forward functionality\n     *\n     * @return Boolean\n     */\n    public boolean isImAlwaysOn() {\n        return readBoolean(RcsSettingsData.IM_CAPABILITY_ALWAYS_ON);\n    }\n\n    /**\n     * Is File Transfer always-on thanks to the Store & Forward functionality\n     *\n     * @return Boolean\n     */\n    public boolean isFtAlwaysOn() {\n        return readBoolean(RcsSettingsData.FT_CAPABILITY_ALWAYS_ON);\n    }\n\n    /**\n     * Get FT Http cap always on option\n     *\n     * @return result ( Default = false = OFF and true = ON )\n     */\n    public boolean isFtHttpCapAlwaysOn() {\n        return readBoolean(RcsSettingsData.FT_HTTP_CAP_ALWAYS_ON);\n    }\n\n    /**\n     * Is IM reports activated\n     *\n     * @return Boolean\n     */\n    public boolean isImReportsActivated() {\n        return readBoolean(RcsSettingsData.IM_USE_REPORTS);\n    }\n\n    /**\n     * Get network access\n     *\n     * @return Network type\n     */\n    public NetworkAccessType getNetworkAccess() {\n        return NetworkAccessType.valueOf(readInteger(RcsSettingsData.NETWORK_ACCESS));\n    }\n\n    /**\n     * Set network access type\n     *\n     * @param networkAccess the network access\n     */\n    public void setNetworkAccess(NetworkAccessType networkAccess) {\n        writeInteger(RcsSettingsData.NETWORK_ACCESS, networkAccess.toInt());\n    }\n\n    /**\n     * Get SIP timer T1\n     *\n     * @return Timer in milliseconds\n     */\n    public long getSipTimerT1() {\n        return readLong(RcsSettingsData.SIP_TIMER_T1);\n    }\n\n    /**\n     * Get SIP timer T2\n     *\n     * @return Timer in milliseconds\n     */\n    public long getSipTimerT2() {\n        return readLong(RcsSettingsData.SIP_TIMER_T2);\n    }\n\n    /**\n     * Get SIP timer T4\n     *\n     * @return Timer in milliseconds\n     */\n    public long getSipTimerT4() {\n        return readLong(RcsSettingsData.SIP_TIMER_T4);\n    }\n\n    /**\n     * Is SIP keep-alive enabled\n     *\n     * @return Boolean\n     */\n    public boolean isSipKeepAliveEnabled() {\n        return readBoolean(RcsSettingsData.SIP_KEEP_ALIVE);\n    }\n\n    /**\n     * Get SIP keep-alive period\n     *\n     * @return Period in milliseconds\n     */\n    public long getSipKeepAlivePeriod() {\n        return readLong(RcsSettingsData.SIP_KEEP_ALIVE_PERIOD);\n    }\n\n    /**\n     * Get operator authorized to connect to RCS platform\n     *\n     * @return SIM operator name (null means any SIM operator is authorized to connect to RCS)\n     */\n    public String getNetworkOperator() {\n        return readString(RcsSettingsData.RCS_OPERATOR);\n    }\n\n    /**\n     * Is GRUU supported\n     *\n     * @return Boolean\n     */\n    public boolean isGruuSupported() {\n        return readBoolean(RcsSettingsData.GRUU);\n    }\n\n    /**\n     * Is CPU Always_on activated\n     *\n     * @return Boolean\n     */\n    public boolean isCpuAlwaysOn() {\n        return readBoolean(RcsSettingsData.CPU_ALWAYS_ON);\n    }\n\n    /**\n     * Get configuration mode\n     *\n     * @return Mode MANUAL | AUTO\n     */\n    public ConfigurationMode getConfigurationMode() {\n        return ConfigurationMode.valueOf(readInteger(RcsSettingsData.CONFIG_MODE));\n    }\n\n    /**\n     * Set configuration mode\n     *\n     * @param mode MANUAL | AUTO\n     */\n    public void setConfigurationMode(ConfigurationMode mode) {\n        writeInteger(RcsSettingsData.CONFIG_MODE, mode.toInt());\n    }\n\n    /**\n     * Get terms and conditions via provisioning response\n     *\n     * @return TermsAndConditionsResponse\n     */\n    public TermsAndConditionsResponse getTermsAndConditionsResponse() {\n        return TermsAndConditionsResponse.valueOf(readInteger(RcsSettingsData.TC_RESPONSE));\n    }\n\n    /**\n     * Get provisioning version\n     *\n     * @return Version\n     */\n    public int getProvisioningVersion() {\n        return readInteger(RcsSettingsData.PROVISIONING_VERSION);\n    }\n\n    /**\n     * Set provisioning version\n     *\n     * @param version Version\n     */\n    public void setProvisioningVersion(int version) {\n        writeInteger(RcsSettingsData.PROVISIONING_VERSION, version);\n    }\n\n    /**\n     * Set terms and conditions response\n     *\n     * @param resp The terms and conditions response\n     */\n    public void setTermsAndConditionsResponse(TermsAndConditionsResponse resp) {\n        writeInteger(RcsSettingsData.TC_RESPONSE, resp.toInt());\n    }\n\n    /**\n     * Get secondary provisioning address\n     *\n     * @return Address\n     */\n    public String getSecondaryProvisioningAddress() {\n        return readString(RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS);\n    }\n\n    /**\n     * Is secondary provisioning address only used\n     *\n     * @return Boolean\n     */\n    public boolean isSecondaryProvisioningAddressOnly() {\n        return readBoolean(RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS_ONLY);\n    }\n\n    /**\n     * Reset configuration parameters to default values\n     */\n    public void resetConfigParameters() {\n        ArrayList<ContentProviderOperation> operations = new ArrayList<>();\n        for (Map.Entry<String, Object> entry : RcsSettingsData.sSettingsKeyDefaultValue.entrySet()) {\n            operations.add(buildContentProviderOp(entry.getKey(), entry.getValue()));\n        }\n        try {\n            mCache.clear();\n            mLocalContentResolver.applyBatch(RcsSettingsData.CONTENT_URI, operations);\n\n        } catch (OperationApplicationException e) {\n            sLogger.error(\"Reset existing configuration failed\", e);\n        }\n    }\n\n    /**\n     * Is user profile configured\n     *\n     * @return Returns true if the configuration is valid\n     */\n    public boolean isUserProfileConfigured() {\n        // Check platform settings\n        if (TextUtils.isEmpty(getImsProxyAddrForMobile())) {\n            return false;\n        }\n\n        // Check user profile settings\n        if (TextUtils.isEmpty(getUserProfileImsDomain())) {\n            return false;\n        }\n        AuthenticationProcedure mode = getImsAuthenticationProcedureForMobile();\n        switch (mode) {\n            case DIGEST:\n                if (getUserProfileImsUserName() == null) {\n                    return false;\n                }\n                if (TextUtils.isEmpty(getUserProfileImsPassword())) {\n                    return false;\n                }\n                if (TextUtils.isEmpty(getUserProfileImsPrivateId())) {\n                    return false;\n                }\n                break;\n            default:\n                break;\n        }\n        return true;\n    }\n\n    /**\n     * Is group chat activated\n     *\n     * @return Boolean\n     */\n    public boolean isGroupChatActivated() {\n        return !RcsSettingsData.DEFAULT_GROUP_CHAT_URI.equals(getImConferenceUri());\n    }\n\n    /**\n     * Get the root directory for photos\n     *\n     * @return Directory path\n     */\n    public String getPhotoRootDirectory() {\n        return readString(RcsSettingsData.DIRECTORY_PATH_PHOTOS);\n    }\n\n    /**\n     * Get the root directory for videos\n     *\n     * @return Directory path\n     */\n    public String getVideoRootDirectory() {\n        return readString(RcsSettingsData.DIRECTORY_PATH_VIDEOS);\n    }\n\n    public String getAudioRootDirectory() {\n        return readString(RcsSettingsData.DIRECTORY_PATH_AUDIOS);\n    }\n\n    /**\n     * Get the root directory for files\n     *\n     * @return Directory path\n     */\n    public String getFileRootDirectory() {\n        return readString(RcsSettingsData.DIRECTORY_PATH_FILES);\n    }\n\n    /**\n     * Is secure MSRP media over Mobile access\n     *\n     * @return Boolean\n     */\n    public boolean isSecureMsrpOverMobile() {\n        return readBoolean(RcsSettingsData.SECURE_MSRP_OVER_MOBILE);\n    }\n\n    /**\n     * Is secure MSRP media over Wi-Fi\n     *\n     * @return Boolean\n     */\n    public boolean isSecureMsrpOverWifi() {\n        return readBoolean(RcsSettingsData.SECURE_MSRP_OVER_WIFI);\n    }\n\n    /**\n     * Get the root directory for file icons\n     *\n     * @return Directory path\n     */\n    public String getFileIconRootDirectory() {\n        return readString(RcsSettingsData.DIRECTORY_PATH_FILEICONS);\n    }\n\n    public ImMsgTech getImMsgTech() {\n        return ImMsgTech.valueOf(readInteger(RcsSettingsData.IM_MSG_TECH));\n    }\n\n    public void setImMsgTech(ImMsgTech mode) {\n        writeInteger(RcsSettingsData.IM_MSG_TECH, mode.toInt());\n    }\n\n    public boolean isFirstMessageInInvite() {\n        return readBoolean(RcsSettingsData.FIRST_MESSAGE_INVITE);\n    }\n\n    public void setFirstMessageInInvite(boolean inInvite) {\n        writeBoolean(RcsSettingsData.FIRST_MESSAGE_INVITE, inInvite);\n    }\n\n    /**\n     * Is secure RTP media over Mobile access\n     *\n     * @return Boolean\n     */\n    public boolean isSecureRtpOverMobile() {\n        return readBoolean(RcsSettingsData.SECURE_RTP_OVER_MOBILE);\n    }\n\n    /**\n     * Is secure RTP media over Wi-Fi\n     *\n     * @return Boolean\n     */\n    public boolean isSecureRtpOverWifi() {\n        return readBoolean(RcsSettingsData.SECURE_RTP_OVER_WIFI);\n    }\n\n    /**\n     * Get max geolocation label length\n     *\n     * @return Number of char\n     */\n    public int getMaxGeolocLabelLength() {\n        return readInteger(RcsSettingsData.MAX_GEOLOC_LABEL_LENGTH);\n    }\n\n    /**\n     * Get geolocation expiration time\n     *\n     * @return Time in milliseconds\n     */\n    public long getGeolocExpirationTime() {\n        return readLong(RcsSettingsData.GEOLOC_EXPIRATION_TIME);\n    }\n\n    /**\n     * Set provisioning token\n     *\n     * @param token the token\n     */\n    public void setProvisioningToken(String token) {\n        writeString(RcsSettingsData.PROVISIONING_TOKEN, token);\n    }\n\n    /**\n     * @return provisioning token\n     */\n    public String getProvisioningToken() {\n        return readString(RcsSettingsData.PROVISIONING_TOKEN);\n    }\n\n    /**\n     * Is SIP device an automata ?\n     *\n     * @return Boolean\n     */\n    public boolean isSipAutomata() {\n        return readBoolean(RcsSettingsData.CAPABILITY_SIP_AUTOMATA);\n    }\n\n    /**\n     * Get max file-icon size\n     *\n     * @return Size in bytes\n     */\n    public long getMaxFileIconSize() {\n        return readLong(RcsSettingsData.MAX_FILE_ICON_SIZE);\n    }\n\n    /**\n     * Get the GSMA release\n     *\n     * @return the GSMA release\n     */\n    public GsmaRelease getGsmaRelease() {\n        return GsmaRelease.valueOf(readInteger(RcsSettingsData.KEY_GSMA_RELEASE));\n    }\n\n    /**\n     * Set the GSMA release\n     *\n     * @param release Release\n     */\n    public void setGsmaRelease(GsmaRelease release) {\n        writeInteger(RcsSettingsData.KEY_GSMA_RELEASE, release.toInt());\n    }\n\n    /**\n     * Is Albatros GSMA release\n     *\n     * @return Boolean\n     */\n    public boolean isAlbatrosRelease() {\n        return (GsmaRelease.ALBATROS.equals(getGsmaRelease()));\n    }\n\n    /**\n     * Is TCP fallback enabled according to RFC3261 chapter 18.1.1\n     *\n     * @return Boolean\n     */\n    public boolean isTcpFallback() {\n        return readBoolean(RcsSettingsData.TCP_FALLBACK);\n    }\n\n    /**\n     * Is RCS extensions allowed\n     *\n     * @return Boolean\n     */\n    public boolean isExtensionsAllowed() {\n        return readBoolean(RcsSettingsData.ALLOW_EXTENSIONS);\n    }\n\n    /**\n     * Is RCS extension authorized\n     *\n     * @return Boolean\n     */\n    public boolean isExtensionAuthorized(String ext) {\n        return ext != null\n                && !(EnrichCallingService.CALL_COMPOSER_FEATURE_TAG.equals(ext) && !isCallComposerSupported())\n                && !(EnrichCallingService.SHARED_MAP_SERVICE_ID.equals(ext) && !isSharedMapSupported())\n                && !(EnrichCallingService.SHARED_SKETCH_SERVICE_ID.equals(ext) && !isSharedSketchSupported())\n                && !(EnrichCallingService.POST_CALL_SERVICE_ID.equals(ext) && !isPostCallSupported());\n    }\n\n    /**\n     * Get max lenght for extensions using real time messaging (MSRP)\n     *\n     * @return Max length\n     */\n    public int getMaxMsrpLengthForExtensions() {\n        return readInteger(RcsSettingsData.MAX_MSRP_SIZE_EXTENSIONS);\n    }\n\n    /**\n     * Get call composer inactivity timeout\n     *\n     * @return Timeout in milliseconds\n     */\n    public long getCallComposerInactivityTimeout() {\n        return readLong(RcsSettingsData.CALL_COMPOSER_INACTIVITY_TIMEOUT);\n    }\n\n    /**\n     * Set the client messaging mode\n     *\n     * @param mode the client messaging mode (0: CONVERGED, 1: INTEGRATED, 2: SEAMLESS, 3: NONE)\n     */\n    public void setMessagingMode(MessagingMode mode) {\n        writeInteger(RcsSettingsData.MESSAGING_MODE, mode.toInt());\n    }\n\n    /**\n     * Get the client messaging mode\n     *\n     * @return the client messaging mode (0: CONVERGED, 1: INTEGRATED, 2: SEAMLESS, 3: NONE)\n     */\n    public MessagingMode getMessagingMode() {\n        return MessagingMode.valueOf(readInteger(RcsSettingsData.MESSAGING_MODE));\n    }\n\n    /**\n     * Is file transfer invitation auto accepted in roaming\n     *\n     * @return Boolean\n     */\n    public boolean isFileTransferAutoAcceptedInRoaming() {\n        return readBoolean(RcsSettingsData.AUTO_ACCEPT_FT_IN_ROAMING);\n    }\n\n    /**\n     * Set File Transfer Auto Accepted in roaming\n     *\n     * @param option Option\n     */\n    public void setFileTransferAutoAcceptedInRoaming(boolean option) {\n        writeBoolean(RcsSettingsData.AUTO_ACCEPT_FT_IN_ROAMING, option);\n    }\n\n    /**\n     * Set File Transfer Auto Accepted in normal conditions\n     *\n     * @param option Option\n     */\n    public void setFileTransferAutoAccepted(boolean option) {\n        writeBoolean(RcsSettingsData.AUTO_ACCEPT_FILE_TRANSFER, option);\n    }\n\n    /**\n     * Is file transfer invitation auto accepted enabled (by the network)\n     *\n     * @return Boolean\n     */\n    public boolean isFtAutoAcceptedModeChangeable() {\n        return readBoolean(RcsSettingsData.AUTO_ACCEPT_FT_CHANGEABLE);\n    }\n\n    /**\n     * Set File Transfer Auto Accepted Mode changeable option\n     *\n     * @param option Option\n     */\n    public void setFtAutoAcceptedModeChangeable(boolean option) {\n        writeBoolean(RcsSettingsData.AUTO_ACCEPT_FT_CHANGEABLE, option);\n    }\n\n    /**\n     * returns the image resize option for file transfer in the range [ALWAYS_PERFORM,\n     * ONLY_ABOVE_MAX_SIZE, ASK]\n     *\n     * @return image resize option (0: ALWAYS_PERFORM, 1: ONLY_ABOVE_MAX_SIZE, 2: ASK)\n     */\n    public ImageResizeOption getImageResizeOption() {\n        return ImageResizeOption.valueOf(readInteger(RcsSettingsData.KEY_IMAGE_RESIZE_OPTION));\n    }\n\n    /**\n     * Set the image resize option\n     *\n     * @param option the image resize option (0: ALWAYS_PERFORM, 1: ONLY_ABOVE_MAX_SIZE, 2: ASK)\n     */\n    public void setImageResizeOption(ImageResizeOption option) {\n        writeInteger(RcsSettingsData.KEY_IMAGE_RESIZE_OPTION, option.toInt());\n    }\n\n    /**\n     * Get the default messaging method\n     *\n     * @return the default messaging method (0: AUTOMATIC, 1: RCS, 2: NON_RCS)\n     */\n    public MessagingMethod getDefaultMessagingMethod() {\n        return MessagingMethod.valueOf(readInteger(RcsSettingsData.DEFAULT_MESSAGING_METHOD));\n    }\n\n    /**\n     * Set default messaging method\n     *\n     * @param method the default messaging method (0: AUTOMATIC, 1: RCS, 2: NON_RCS)\n     */\n    public void setDefaultMessagingMethod(MessagingMethod method) {\n        writeInteger(RcsSettingsData.DEFAULT_MESSAGING_METHOD, method.toInt());\n    }\n\n    /**\n     * Is configuration valid\n     *\n     * @return Boolean\n     */\n    public boolean isConfigurationValid() {\n        return readBoolean(RcsSettingsData.CONFIGURATION_VALID);\n    }\n\n    /**\n     * Set configuration valid\n     *\n     * @param valid true if configuration is valid\n     */\n    public void setConfigurationValid(boolean valid) {\n        writeBoolean(RcsSettingsData.CONFIGURATION_VALID, valid);\n    }\n\n    /**\n     * @return the maximum length of subject in Group Chat\n     */\n    public int getGroupChatSubjectMaxLength() {\n        return GROUP_CHAT_SUBJECT_MAX_LENGTH;\n    }\n\n    /**\n     * Sets RCS activation changeable by the client applications\n     *\n     * @param enableSwitch the enable switch\n     */\n    public void setEnableRcseSwitch(EnableRcseSwitch enableSwitch) {\n        writeInteger(RcsSettingsData.ENABLE_RCS_SWITCH, enableSwitch.toInt());\n    }\n\n    /**\n     * Returns how to show the RCS enabled/disabled switch\n     *\n     * @return EnableRcseSwitch\n     */\n    public EnableRcseSwitch getEnableRcseSwitch() {\n        return EnableRcseSwitch.valueOf(readInteger(RcsSettingsData.ENABLE_RCS_SWITCH));\n    }\n\n    /**\n     * Get contact cap validity period in one-one messaging\n     *\n     * @return Period in milliseconds\n     */\n    public long getMsgCapValidityPeriod() {\n        return readLong(RcsSettingsData.MSG_CAP_VALIDITY_PERIOD);\n    }\n\n    /**\n     * Get group imdn display reports option\n     *\n     * @return True if group display reports are to be requested and responded to\n     */\n    public boolean isRequestAndRespondToGroupDisplayReportsEnabled() {\n        return readBoolean(RcsSettingsData.REQUEST_AND_RESPOND_TO_GROUP_DISPLAY_REPORTS);\n    }\n\n    /**\n     * Get message delivery timeout in one-one messaging\n     *\n     * @return Period in milliseconds\n     */\n    public long getMsgDeliveryTimeoutPeriod() {\n        return readLong(RcsSettingsData.MSG_DELIVERY_TIMEOUT);\n    }\n\n    /**\n     * Restrict display name length to 256 characters, as allowing infinite length string as display\n     * name will eventually crash the stack.\n     *\n     * @return the maximum characters allowed for display name\n     */\n    public int getMaxAllowedDisplayNameChars() {\n        return readInteger(RcsSettingsData.MAX_ALLOWED_DISPLAY_NAME_CHARS);\n    }\n\n    /**\n     * Sets the user message content\n     *\n     * @param message the user message content\n     */\n    public void setProvisioningUserMessageContent(String message) {\n        writeString(RcsSettingsData.PROV_USER_MSG_CONTENT, message);\n    }\n\n    /**\n     * Gets the user message content\n     *\n     * @return the user message content\n     */\n    public String getProvisioningUserMessageContent() {\n        return readString(RcsSettingsData.PROV_USER_MSG_CONTENT);\n    }\n\n    /**\n     * Sets the user message title\n     *\n     * @param title the user message title\n     */\n    public void setProvisioningUserMessageTitle(String title) {\n        writeString(RcsSettingsData.PROV_USER_MSG_TITLE, title);\n    }\n\n    /**\n     * Gets the user message title\n     *\n     * @return the user message title\n     */\n    public String getProvisioningUserMessageTitle() {\n        return readString(RcsSettingsData.PROV_USER_MSG_TITLE);\n    }\n\n    /**\n     * Get mobile country code\n     *\n     * @return mobile country code or 0 if undefined\n     */\n    public int getMobileCountryCode() {\n        return readInteger(RcsSettingsData.MOBILE_COUNTRY_CODE);\n    }\n\n    /**\n     * Set the mobile country code\n     *\n     * @param mcc the mobile country code\n     */\n    public void setMobileCountryCode(int mcc) {\n        writeInteger(RcsSettingsData.MOBILE_COUNTRY_CODE, mcc);\n    }\n\n    /**\n     * Get mobile network code\n     *\n     * @return mobile network code or 0 if undefined\n     */\n    public int getMobileNetworkCode() {\n        return readInteger(RcsSettingsData.MOBILE_NETWORK_CODE);\n    }\n\n    /**\n     * Set the mobile network code\n     *\n     * @param mnc the mobile network code\n     */\n    public void setMobileNetworkCode(int mnc) {\n        writeInteger(RcsSettingsData.MOBILE_NETWORK_CODE, mnc);\n    }\n\n    /**\n     * Sets whether an Accept button is shown with the message in the terms and conditions pop-up\n     *\n     * @param accept True if an Accept button is shown with the message in the terms and conditions\n     *            pop-up\n     */\n    public void setProvisioningAcceptButton(boolean accept) {\n        writeBoolean(RcsSettingsData.PROV_ACCEPT_BUTTON, accept);\n    }\n\n    /**\n     * Is Accept button shown with the message in the terms and conditions pop-up\n     *\n     * @return Boolean True if Accept button shown with the message in the terms and conditions\n     *         pop-up\n     */\n    public boolean isProvisioningAcceptButton() {\n        return readBoolean(RcsSettingsData.PROV_ACCEPT_BUTTON);\n    }\n\n    /**\n     * Sets whether a Decline button is shown with the message in the terms and conditions pop-up\n     *\n     * @param reject True if a Decline button is shown with the message in the terms and conditions\n     *            pop-up\n     */\n    public void setProvisioningRejectButton(boolean reject) {\n        writeBoolean(RcsSettingsData.PROV_REJECT_BUTTON, reject);\n    }\n\n    /**\n     * Is Decline button shown with the message in the terms and conditions pop-up\n     *\n     * @return Boolean True if a Decline button is shown with the message in the terms and\n     *         conditions pop-up\n     */\n    public boolean isProvisioningRejectButton() {\n        return readBoolean(RcsSettingsData.PROV_REJECT_BUTTON);\n    }\n\n    /**\n     * Sets the display language\n     *\n     * @param language the display language\n     */\n    public void setDisplayLanguage(String language) {\n        writeString(RcsSettingsData.LOCAL_DISPLAY_LANGUAGE, language);\n    }\n\n    /**\n     * Gets the display language\n     *\n     * @return the display language\n     */\n    public String getDisplayLanguage() {\n        return readString(RcsSettingsData.LOCAL_DISPLAY_LANGUAGE);\n    }\n\n    /**\n     * Is enrich calling service supported\n     *\n     * @return Boolean True if supported\n     */\n    public boolean isEnrichCallingServiceSupported() {\n        return readBoolean(RcsSettingsData.ENRICH_CALLING_SERVICE);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/settings/RcsSettingsData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.settings;\n\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption;\n\nimport android.net.ConnectivityManager;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.util.SparseArray;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax2.sip.ListeningPoint;\n\n/**\n * RCS settings data constants\n *\n * @author jexa7410\n * @author yplo6403\n */\npublic class RcsSettingsData {\n    /**\n     * Content provider URI\n     */\n    /* package private */static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.setting/setting\");\n\n    /**\n     * Key of the Rcs configuration parameter\n     */\n    /* package private */static final String KEY_KEY = \"key\";\n\n    /**\n     * Value of the Rcs configuration parameter\n     */\n    /* package private */static final String KEY_VALUE = \"value\";\n\n    /**\n     * Default group chat conference URI\n     */\n    public static final Uri DEFAULT_GROUP_CHAT_URI = Uri.parse(\"sip:foo@bar\");\n\n    /**\n     * File type for certificate\n     */\n    public static final String CERTIFICATE_FILE_TYPE = \".crt\";\n\n    // ---------------------------------------------------------------------------\n    // Enumerated\n    // ---------------------------------------------------------------------------\n\n    /**\n     * The authentication procedure enumerated type.\n     */\n    public enum AuthenticationProcedure {\n        /**\n         * GIBA authentication\n         */\n        GIBA(0),\n        /**\n         * Digest authentication\n         */\n        DIGEST(1);\n\n        private final int mValue;\n\n        private static SparseArray<AuthenticationProcedure> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (AuthenticationProcedure entry : AuthenticationProcedure.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        AuthenticationProcedure(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the authentication procedure\n         * @return AuthenticationProcedure\n         */\n        public static AuthenticationProcedure valueOf(int value) {\n            AuthenticationProcedure entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + AuthenticationProcedure.class.getName() + \".\" + value);\n        }\n\n    }\n\n    /**\n     * Option for what ux-operation to react on when handling manual acceptance of one2one and group\n     * chat invitations.\n     */\n    public enum ImSessionStartMode {\n\n        /**\n         * Group chat session is accepted when opening conversation\n         */\n        ON_OPENING(0),\n        /**\n         * Group chat session is accepted when composing first message\n         */\n        ON_COMPOSING(1),\n        /**\n         * Group chat session is accepted when sending first message\n         */\n        ON_SENDING(2);\n\n        private final int mValue;\n\n        private static SparseArray<ImSessionStartMode> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (ImSessionStartMode entry : ImSessionStartMode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ImSessionStartMode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the IM session start mode\n         * @return ImSessionStartMode\n         */\n        public static ImSessionStartMode valueOf(int value) {\n            ImSessionStartMode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + ImSessionStartMode.class.getName() + \".\" + value);\n        }\n\n    }\n\n    public enum TermsAndConditionsResponse {\n\n        NO_ANSWER(0), DECLINED(1), ACCEPTED(2);\n\n        private final int mValue;\n\n        private static SparseArray<TermsAndConditionsResponse> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (TermsAndConditionsResponse entry : TermsAndConditionsResponse.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        TermsAndConditionsResponse(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the Terms and Condition response\n         * @return TermAndConditionsResponse\n         */\n        public static TermsAndConditionsResponse valueOf(int value) {\n            TermsAndConditionsResponse entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + TermsAndConditionsResponse.class.getName() + \".\" + value);\n        }\n\n    }\n\n    public enum ImMsgTech {\n\n        SIMPLE_IM(0),\n\n        CPM(1);\n\n        private final int mValue;\n\n        private static SparseArray<ImMsgTech> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (ImMsgTech entry : ImMsgTech.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ImMsgTech(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the IM message tech\n         * @return ImMsgTech\n         */\n        public static ImMsgTech valueOf(int value) {\n            ImMsgTech entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ImMsgTech.class.getName()\n                    + \".\" + value);\n        }\n\n    }\n\n    /**\n     * Network access type\n     */\n    public enum NetworkAccessType {\n        /**\n         * Mobile access type\n         */\n        MOBILE(ConnectivityManager.TYPE_MOBILE),\n        /**\n         * Wifi access type\n         */\n        WIFI(ConnectivityManager.TYPE_WIFI),\n        /**\n         * All access types\n         */\n        ANY(-1);\n\n        private int mValue;\n\n        private static SparseArray<NetworkAccessType> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (NetworkAccessType entry : NetworkAccessType.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        NetworkAccessType(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the network access type.\n         * @return NetworkAccessType\n         */\n        public static NetworkAccessType valueOf(int value) {\n            NetworkAccessType entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + NetworkAccessType.class.getName() + \".\" + value);\n        }\n\n    }\n\n    /**\n     * EnableRcseSwitch describes whether or not to show the RCS enabled/disabled switch permanently\n     */\n    public enum EnableRcseSwitch {\n        /**\n         * the switch is shown permanently\n         */\n        ALWAYS_SHOW(1),\n        /**\n         * the switch is only shown during roaming\n         */\n        ONLY_SHOW_IN_ROAMING(0),\n        /**\n         * the switch is never shown\n         */\n        NEVER_SHOW(-1);\n\n        private int mValue;\n\n        private static SparseArray<EnableRcseSwitch> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (EnableRcseSwitch entry : EnableRcseSwitch.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        EnableRcseSwitch(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the enable RCSe switch\n         * @return EnableRcseSwitch\n         */\n        public static EnableRcseSwitch valueOf(int value) {\n            EnableRcseSwitch entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + EnableRcseSwitch.class.getName() + \".\" + value);\n        }\n\n    }\n\n    /**\n     * The configuration mode enumerated type.\n     */\n    public enum ConfigurationMode {\n        /**\n         * Manual configuration\n         */\n        MANUAL(0),\n        /**\n         * Automatic configuration\n         */\n        AUTO(1);\n\n        private int mValue;\n\n        private static SparseArray<ConfigurationMode> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (ConfigurationMode entry : ConfigurationMode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ConfigurationMode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the configuration mode\n         * @return ConfigurationMode\n         */\n        public static ConfigurationMode valueOf(int value) {\n            ConfigurationMode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + ConfigurationMode.class.getName() + \".\" + value);\n        }\n    }\n\n    /**\n     * The File Transfer protocol enumerated type.\n     */\n    public enum FileTransferProtocol {\n        /**\n         * MSRP protocol\n         */\n        MSRP,\n        /**\n         * HTTP protocol\n         */\n        HTTP\n    }\n\n    /**\n     * The GSMA release enumerated type.\n     */\n    public enum GsmaRelease {\n        /**\n         * Albatros release\n         */\n        ALBATROS(0),\n        /**\n         * Blackbird release\n         */\n        BLACKBIRD(1),\n        /**\n         * Crane release\n         */\n        CRANE(2);\n\n        private int mValue;\n\n        private static SparseArray<GsmaRelease> mValueToEnum = new SparseArray<>();\n\n        static {\n            for (GsmaRelease entry : GsmaRelease.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        GsmaRelease(int value) {\n            mValue = value;\n        }\n\n        /**\n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * @param value the value representing the GSMA release\n         * @return GsmaRelease\n         */\n        public static GsmaRelease valueOf(int value) {\n            GsmaRelease entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + GsmaRelease.class.getName()\n                    + \".\" + value);\n        }\n\n    }\n\n    // ---------------------------------------------------------------------------\n    // UI settings\n    // ---------------------------------------------------------------------------\n\n    /**\n     * Activate or not the RCS service\n     */\n    public static final String SERVICE_ACTIVATED = \"ServiceActivated\";\n    /* package private */static final Boolean DEFAULT_SERVICE_ACTIVATED = true;\n\n    /**\n     * Send or not the displayed notification\n     */\n    public static final String CHAT_RESPOND_TO_DISPLAY_REPORTS = \"ChatRespondToDisplayReports\";\n    /* package private */static final Boolean DEFAULT_CHAT_RESPOND_TO_DISPLAY_REPORTS = true;\n\n    /**\n     * Battery level minimum\n     */\n    /* package private */static final String MIN_BATTERY_LEVEL = \"MinBatteryLevel\";\n    /* package private */static final Integer DEFAULT_MIN_BATTERY_LEVEL = 0;\n\n    // ---------------------------------------------------------------------------\n    // Service settings\n    // ---------------------------------------------------------------------------\n    /**\n     * Max file-icon size\n     */\n    public static final String MAX_FILE_ICON_SIZE = \"FileIconSize\";\n    /* package private */static final Long DEFAULT_MAX_FILE_ICON_SIZE = 50L * 1024L;\n\n    /**\n     * Max photo-icon size\n     */\n    public static final String MAX_PHOTO_ICON_SIZE = \"MaxPhotoIconSize\";\n    /* package private */static final Long DEFAULT_MAX_PHOTO_ICON_SIZE = 100L * 1024L;\n\n    /**\n     * Max length of the freetext\n     */\n    public static final String MAX_FREETXT_LENGTH = \"MaxFreetextLength\";\n    /* package private */static final Integer DEFAULT_MAX_FREETXT_LENGTH = 100;\n\n    /**\n     * Max number of participants in a group chat\n     */\n    public static final String MAX_CHAT_PARTICIPANTS = \"MaxChatParticipants\";\n    /* package private */static final Integer DEFAULT_MAX_CHAT_PARTICIPANTS = 10;\n\n    /**\n     * Max length of a chat message\n     */\n    public static final String MAX_CHAT_MSG_LENGTH = \"MaxChatMessageLength\";\n    /* package private */static final Integer DEFAULT_MAX_CHAT_MSG_LENGTH = 100;\n\n    /**\n     * Max length of a group chat message\n     */\n    public static final String MAX_GROUPCHAT_MSG_LENGTH = \"MaxGroupChatMessageLength\";\n    /* package private */static final Integer DEFAULT_MAX_GC_MSG_LENGTH = 100;\n\n    /**\n     * Idle duration of a chat session in milliseconds\n     */\n    public static final String CHAT_IDLE_DURATION = \"ChatIdleDuration\";\n    /* package private */static final Long DEFAULT_CHAT_IDLE_DURATION = 300000L;\n\n    /**\n     * Max size of a file transfer\n     */\n    public static final String MAX_FILE_TRANSFER_SIZE = \"MaxFileTransferSize\";\n    /* package private */static final Long DEFAULT_MAX_FT_SIZE = 3072L * 1024L;\n\n    /**\n     * Warning threshold for file transfer size\n     */\n    public static final String WARN_FILE_TRANSFER_SIZE = \"WarnFileTransferSize\";\n    /* package private */static final Long DEFAULT_WARN_FT_SIZE = 2048L * 1024L;\n\n    /**\n     * Max size of an image share\n     */\n    public static final String MAX_IMAGE_SHARE_SIZE = \"MaxImageShareSize\";\n    /* package private */static final Long DEFAULT_MAX_ISH_SIZE = 3072L * 1024L;\n\n    /**\n     * Max duration of a video share in milliseconds\n     */\n    public static final String MAX_VIDEO_SHARE_DURATION = \"MaxVideoShareDuration\";\n    /* package private */static final Long DEFAULT_MAX_VSH_DURATION = 54000000L;\n\n    /**\n     * Max Audio Message Duration in millisecond\n     */\n    public static final String MAX_AUDIO_MESSAGE_DURATION = \"MaxAudioMessageDuration\";\n    /* package private */static final Long DEFAULT_MAX_AUDIO_DURATION = 600000L;\n\n    /**\n     * Max number of simultaneous chat sessions\n     */\n    public static final String MAX_CHAT_SESSIONS = \"MaxChatSessions\";\n    /* package private */static final Integer DEFAULT_MAX_CHAT_SESSIONS = 20;\n\n    /**\n     * Max number of simultaneous file transfer sessions\n     */\n    public static final String MAX_FILE_TRANSFER_SESSIONS = \"MaxFileTransferSessions\";\n    /* package private */static final Integer DEFAULT_MAX_FT_SESSIONS = 10;\n\n    /**\n     * Max number of simultaneous outgoing file transfer sessions allowed\n     */\n    public static final String MAX_CONCURRENT_OUTGOING_FILE_TRANSFERS = \"MaxConcurrentOutgoingFileTransferSessions\";\n    /* package private */static final Integer DEFAULT_MAX_CONCURRENT_OUTGOING_FT_SESSIONS = 1;\n\n    /**\n     * Max number of simultaneous IP call sessions\n     */\n    public static final String MAX_IP_CALL_SESSIONS = \"MaxIpCallSessions\";\n    /* package private */static final Integer DEFAULT_MAX_IP_CALL_SESSIONS = 5;\n\n    /**\n     * Activate or not SMS fallback service\n     */\n    public static final String SMS_FALLBACK_SERVICE = \"SmsFallbackService\";\n    /* package private */static final Boolean DEFAULT_SMS_FALLBACK_SERVICE = true;\n\n    /**\n     * Auto accept file transfer invitation\n     */\n    public static final String AUTO_ACCEPT_FILE_TRANSFER = \"AutoAcceptFileTransfer\";\n    /* package private */static final Boolean DEFAULT_AUTO_ACCEPT_FT = false;\n\n    /**\n     * Auto accept chat invitation\n     */\n    public static final String AUTO_ACCEPT_CHAT = \"AutoAcceptChat\";\n    /* package private */static final Boolean DEFAULT_AUTO_ACCEPT_CHAT = false;\n\n    /**\n     * Auto accept group chat invitation\n     */\n    public static final String AUTO_ACCEPT_GROUP_CHAT = \"AutoAcceptGroupChat\";\n    /* package private */static final Boolean DEFAULT_AUTO_ACCEPT_GC = false;\n\n    /**\n     * Display a warning if Store & Forward service is activated\n     */\n    public static final String WARN_SF_SERVICE = \"StoreForwardServiceWarning\";\n    /* package private */static final Boolean DEFAULT_WARN_SF_SERVICE = false;\n\n    /**\n     * Define when the chat receiver sends the 200 OK back to the sender\n     */\n    public static final String IM_SESSION_START = \"ImSessionStart\";\n    /* package private */static final Integer DEFAULT_IM_SESSION_START = 1;\n\n    /**\n     * Max entries for chat log\n     */\n    public static final String MAX_CHAT_LOG_ENTRIES = \"MaxChatLogEntries\";\n    /* package private */static final Integer DEFAULT_MAX_CHAT_LOG_ENTRIES = 500;\n\n    /**\n     * Max entries for richcall log\n     */\n    public static final String MAX_RICHCALL_LOG_ENTRIES = \"MaxRichcallLogEntries\";\n    /* package private */static final Integer DEFAULT_MAX_RICHCALL_LOG_ENTRIES = 200;\n\n    /**\n     * Max entries for IP call log\n     */\n    public static final String MAX_IPCALL_LOG_ENTRIES = \"MaxIpcallLogEntries\";\n    /* package private */static final Integer DEFAULT_MAX_IPCALL_LOG_ENTRIES = 200;\n\n    /**\n     * Max length of a geolocation label\n     */\n    public static final String MAX_GEOLOC_LABEL_LENGTH = \"MaxGeolocLabelLength\";\n    /* package private */static final Integer DEFAULT_MAX_GEOLOC_LABEL_LENGTH = 100;\n\n    /**\n     * Geolocation expiration time\n     */\n    public static final String GEOLOC_EXPIRATION_TIME = \"GeolocExpirationTime\";\n    /* package private */static final Long DEFAULT_GEOLOC_EXPIRATION_TIME = 3600000L;\n\n    /**\n     * Convergent messaging UX option\n     */\n    public static final String MESSAGING_MODE = \"MessagingMode\";\n    /* package private */static final Integer DEFAULT_KEY_MESSAGING_MODE = MessagingMode.NONE\n            .toInt();\n\n    /**\n     * Default messaging method\n     */\n    public static final String DEFAULT_MESSAGING_METHOD = \"DefaultMessagingMethod\";\n    /* package private */static final Integer DEFAULT_KEY_DEFAULT_MESSAGING_METHOD = MessagingMethod.AUTOMATIC\n            .toInt();\n\n    /**\n     * Enrich calling service support\n     */\n    public static final String ENRICH_CALLING_SERVICE = \"EnrichCallingSupport\";\n    /* package private */static final Boolean DEFAULT_ENRICH_CALLING_SERVICE = true;\n\n    // ---------------------------------------------------------------------------\n    // User profile settings\n    // ---------------------------------------------------------------------------\n\n    /**\n     * IMS username or username part of the IMPU (for HTTP Digest only)\n     */\n    public static final String USERPROFILE_IMS_USERNAME = \"MyContactId\";\n    /* package private */static final ContactId DEFAULT_USERPROFILE_IMS_USERNAME = null;\n\n    /**\n     * IMS display name\n     */\n    public static final String USERPROFILE_IMS_DISPLAY_NAME = \"MyDisplayName\";\n    /* package private */static final String DEFAULT_USERPROFILE_IMS_DISPLAY_NAME = null;\n\n    /**\n     * IMS home domain\n     */\n    public static final String USERPROFILE_IMS_HOME_DOMAIN = \"ImsHomeDomain\";\n    /* package private */static final String DEFAULT_USERPROFILE_IMS_HOME_DOMAIN = null;\n\n    /**\n     * IMS private URI or IMPI (for HTTP Digest only)\n     */\n    public static final String USERPROFILE_IMS_PRIVATE_ID = \"ImsPrivateId\";\n    /* package private */static final String DEFAULT_USERPROFILE_IMS_PRIVATE_ID = null;\n\n    /**\n     * IMS password (for HTTP Digest only)\n     */\n    public static final String USERPROFILE_IMS_PASSWORD = \"ImsPassword\";\n    /* package private */static final String DEFAULT_USERPROFILE_IMS_PASSWORD = null;\n\n    /**\n     * IMS realm (for HTTP Digest only)\n     */\n    public static final String USERPROFILE_IMS_REALM = \"ImsRealm\";\n    /* package private */static final String DEFAULT_USERPROFILE_IMS_REALM = null;\n\n    /**\n     * P-CSCF or outbound proxy address for mobile access\n     */\n    public static final String IMS_PROXY_ADDR_MOBILE = \"ImsOutboundProxyAddrForMobile\";\n    /* package private */static final String DEFAULT_IMS_PROXY_ADDR_MOBILE = null;\n\n    /**\n     * P-CSCF or outbound proxy port for mobile access\n     */\n    public static final String IMS_PROXY_PORT_MOBILE = \"ImsOutboundProxyPortForMobile\";\n    /* package private */static final Integer DEFAULT_IMS_PROXY_PORT_MOBILE = 5060;\n\n    /**\n     * P-CSCF or outbound proxy address for Wi-Fi access\n     */\n    public static final String IMS_PROXY_ADDR_WIFI = \"ImsOutboundProxyAddrForWifi\";\n    /* package private */static final String DEFAULT_IMS_PROXY_ADDR_WIFI = null;\n\n    /**\n     * P-CSCF or outbound proxy port for Wi-Fi access\n     */\n    public static final String IMS_PROXY_PORT_WIFI = \"ImsOutboundProxyPortForWifi\";\n    /* package private */static final Integer DEFAULT_IMS_PROXY_PORT_WIFI = 5060;\n\n    /**\n     * XDM server address & port\n     */\n    public static final String XDM_SERVER = \"XdmServerAddr\";\n    /* package private */static final Uri DEFAULT_XDM_SERVER = null;\n\n    /**\n     * XDM server login (for HTTP Digest only)\n     */\n    public static final String XDM_LOGIN = \"XdmServerLogin\";\n    /* package private */static final String DEFAULT_XDM_LOGIN = null;\n\n    /**\n     * XDM server password (for HTTP Digest only)\n     */\n    public static final String XDM_PASSWORD = \"XdmServerPassword\";\n    /* package private */static final String DEFAULT_XDM_PASSWORD = null;\n\n    /**\n     * File transfer HTTP server address & port\n     */\n    public static final String FT_HTTP_SERVER = \"FtHttpServerAddr\";\n    /* package private */static final Uri DEFAULT_FT_HTTP_SERVER = null;\n\n    /**\n     * File transfer HTTP server login\n     */\n    public static final String FT_HTTP_LOGIN = \"FtHttpServerLogin\";\n    /* package private */static final String DEFAULT_FT_HTTP_LOGIN = null;\n\n    /**\n     * File transfer HTTP server password\n     */\n    public static final String FT_HTTP_PASSWORD = \"FtHttpServerPassword\";\n    /* package private */static final String DEFAULT_FT_HTTP_PASSWORD = null;\n\n    /**\n     * File transfer default protocol\n     */\n    public static final String FT_PROTOCOL = \"FtProtocol\";\n    /* package private */static final String DEFAULT_FT_PROTOCOL = FileTransferProtocol.MSRP.name();\n\n    /**\n     * IM conference URI for group chat session\n     */\n    public static final String IM_CONF_URI = \"ImConferenceUri\";\n    /* package private */static final Uri DEFAULT_IM_CONF_URI = RcsSettingsData.DEFAULT_GROUP_CHAT_URI;\n\n    /**\n     * End user confirmation request URI for terms and conditions\n     */\n    public static final String ENDUSER_CONFIRMATION_URI = \"EndUserConfReqUri\";\n    /* package private */static final String DEFAULT_ENDUSER_CONFIRMATION_URI = null;\n\n    /**\n     * UUID value for populating SIP instance\n     */\n    public static final String UUID = \"UUID\";\n    /* package private */static final String DEFAULT_UUID = null;\n\n    // ---------------------------------------------------------------------------\n    // Stack settings\n    // ---------------------------------------------------------------------------\n\n    /**\n     * Polling period used before each IMS service check (e.g. test subscription state for presence\n     * service)\n     */\n    public static final String IMS_SERVICE_POLLING_PERIOD = \"ImsServicePollingPeriod\";\n    /* package private */static final Long DEFAULT_IMS_SERVICE_POLLING_PERIOD = 30000L;\n\n    /**\n     * Default SIP port\n     */\n    public static final String SIP_DEFAULT_PORT = \"SipListeningPort\";\n    /* package private */static final Integer DEFAULT_SIP_DEFAULT_PORT = 5062;\n\n    /**\n     * Default SIP protocol for mobile\n     */\n    public static final String SIP_DEFAULT_PROTOCOL_FOR_MOBILE = \"SipDefaultProtocolForMobile\";\n    /* package private */static final String DEFAULT_SIP_DEFAULT_PROTOCOL_FOR_MOBILE = ListeningPoint.UDP;\n\n    /**\n     * Default SIP protocol for Wi-Fi\n     */\n    public static final String SIP_DEFAULT_PROTOCOL_FOR_WIFI = \"SipDefaultProtocolForWifi\";\n    /* package private */static final String DEFAULT_SIP_DEFAULT_PROTOCOL_FOR_WIFI = ListeningPoint.TCP;\n\n    /**\n     * TLS Certificate root\n     */\n    public static final String TLS_CERTIFICATE_ROOT = \"TlsCertificateRoot\";\n    /* package private */static final String DEFAULT_TLS_CERTIFICATE_ROOT = null;\n\n    /**\n     * TLS Certificate intermediate\n     */\n    public static final String TLS_CERTIFICATE_INTERMEDIATE = \"TlsCertificateIntermediate\";\n    /* package private */static final String DEFAULT_TLS_CERTIFICATE_INTERMEDIATE = null;\n\n    /**\n     * SIP transaction timeout used to wait a SIP response in milliseconds\n     */\n    public static final String SIP_TRANSACTION_TIMEOUT = \"SipTransactionTimeout\";\n    /* package private */static final Long DEFAULT_SIP_TRANSACTION_TIMEOUT = 120000L;\n\n    /**\n     * Default TCP port for MSRP session\n     */\n    public static final String MSRP_DEFAULT_PORT = \"DefaultMsrpPort\";\n    /* package private */static final Integer DEFAULT_MSRP_DEFAULT_PORT = 20000;\n\n    /**\n     * Default UDP port for RTP session\n     */\n    public static final String RTP_DEFAULT_PORT = \"DefaultRtpPort\";\n    /* package private */static final Integer DEFAULT_RTP_DEFAULT_PORT = 10000;\n\n    /**\n     * MSRP transaction timeout used to wait MSRP response in milliseconds\n     */\n    public static final String MSRP_TRANSACTION_TIMEOUT = \"MsrpTransactionTimeout\";\n    /* package private */static final Long DEFAULT_MSRP_TRANSACTION_TIMEOUT = 5000L;\n\n    /**\n     * Registration expire period\n     */\n    public static final String REGISTER_EXPIRE_PERIOD = \"RegisterExpirePeriod\";\n    /* package private */static final Long DEFAULT_REGISTER_EXPIRE_PERIOD = 600000000L;\n\n    /**\n     * Registration retry base time\n     */\n    public static final String REGISTER_RETRY_BASE_TIME = \"RegisterRetryBaseTime\";\n    /* package private */static final Long DEFAULT_REGISTER_RETRY_BASE_TIME = 30000L;\n\n    /**\n     * Registration retry max time\n     */\n    public static final String REGISTER_RETRY_MAX_TIME = \"RegisterRetryMaxTime\";\n    /* package private */static final Long DEFAULT_REGISTER_RETRY_MAX_TIME = 1800000L;\n\n    /**\n     * Publish expire period\n     */\n    public static final String PUBLISH_EXPIRE_PERIOD = \"PublishExpirePeriod\";\n    /* package private */static final Long DEFAULT_PUBLISH_EXPIRE_PERIOD = 3600000L;\n\n    /**\n     * Revoke timeout in milliseconds\n     */\n    public static final String REVOKE_TIMEOUT = \"RevokeTimeout\";\n    /* package private */static final Long DEFAULT_REVOKE_TIMEOUT = 300000L;\n\n    /**\n     * IMS authentication procedure for mobile access\n     */\n    public static final String IMS_AUTHENT_PROCEDURE_MOBILE = \"ImsAuthenticationProcedureForMobile\";\n    /* package private */static final String DEFAULT_IMS_AUTHENT_PROCEDURE_MOBILE = AuthenticationProcedure.DIGEST\n            .name();\n\n    /**\n     * IMS authentication procedure for Wi-Fi access\n     */\n    public static final String IMS_AUTHENT_PROCEDURE_WIFI = \"ImsAuthenticationProcedureForWifi\";\n    /* package private */static final String DEFAULT_IMS_AUTHENT_PROCEDURE_WIFI = AuthenticationProcedure.DIGEST\n            .name();\n\n    /**\n     * Activate or not Tel-URI format\n     */\n    public static final String TEL_URI_FORMAT = \"TelUriFormat\";\n    /* package private */static final Boolean DEFAULT_TEL_URI_FORMAT = true;\n\n    /**\n     * Ringing session period in milliseconds. At the end of the period the session is cancelled\n     */\n    public static final String RINGING_SESSION_PERIOD = \"RingingPeriod\";\n    /* package private */static final Long DEFAULT_RINGING_SESSION_PERIOD = 60000L;\n\n    /**\n     * Subscribe expiration period\n     */\n    public static final String SUBSCRIBE_EXPIRE_PERIOD = \"SubscribeExpirePeriod\";\n    /* package private */static final Long DEFAULT_SUBSCRIBE_EXPIRE_PERIOD = 3600000L;\n\n    /**\n     * \"Is-composing\" timeout milliseconds for chat service\n     */\n    public static final String IS_COMPOSING_TIMEOUT = \"IsComposingTimeout\";\n    /* package private */static final Long DEFAULT_IS_COMPOSING_TIMEOUT = 15000L;\n\n    /**\n     * SIP session refresh expire period\n     */\n    public static final String SESSION_REFRESH_EXPIRE_PERIOD = \"SessionRefreshExpirePeriod\";\n    /* package private */static final Long DEFAULT_SESSION_REFRESH_EXPIRE_PERIOD = 0L;\n\n    /**\n     * Activate or not permanent state mode\n     */\n    public static final String PERMANENT_STATE_MODE = \"PermanentState\";\n    /* package private */static final Boolean DEFAULT_PERMANENT_STATE_MODE = true;\n\n    /**\n     * Activate or not the traces\n     */\n    public static final String TRACE_ACTIVATED = \"TraceActivated\";\n    /* package private */static final Boolean DEFAULT_TRACE_ACTIVATED = true;\n\n    /**\n     * Logger trace level\n     */\n    public static final String TRACE_LEVEL = \"TraceLevel\";\n    /* package private */static final Integer DEFAULT_TRACE_LEVEL = Logger.DEBUG_LEVEL;\n\n    /**\n     * Activate or not the SIP trace\n     */\n    public static final String SIP_TRACE_ACTIVATED = \"SipTraceActivated\";\n    /* package private */static final Boolean DEFAULT_SIP_TRACE_ACTIVATED = false;\n\n    /**\n     * SIP trace file\n     */\n    public static final String SIP_TRACE_FILE = \"SipTraceFile\";\n    /* package private */static final String DEFAULT_SIP_TRACE_FILE = Environment\n            .getExternalStorageDirectory() + \"/sip.txt\";\n\n    /**\n     * Activate or not the media trace\n     */\n    public static final String MEDIA_TRACE_ACTIVATED = \"MediaTraceActivated\";\n    /* package private */static final Boolean DEFAULT_MEDIA_TRACE_ACTIVATED = false;\n\n    /**\n     * Capability refresh timeout used to avoid too many requests in a short time\n     */\n    public static final String CAPABILITY_REFRESH_TIMEOUT = \"CapabilityRefreshTimeout\";\n    /* package private */static final Long DEFAULT_CAPABILITY_REFRESH_TIMEOUT = 1000L;\n\n    /**\n     * Capability refresh timeout used to decide when to refresh contact capabilities\n     */\n    public static final String CAPABILITY_EXPIRY_TIMEOUT = \"CapabilityExpiryTimeout\";\n    /* package private */static final Long DEFAULT_CAPABILITY_EXPIRY_TIMEOUT = 86400000L;\n\n    /**\n     * Polling period used to decide when to refresh contacts capabilities\n     */\n    public static final String CAPABILITY_POLLING_PERIOD = \"CapabilityPollingPeriod\";\n    /* package private */static final Long DEFAULT_CAPABILITY_POLLING_PERIOD = 3600000L;\n\n    /**\n     * CS video capability\n     */\n    public static final String CAPABILITY_CS_VIDEO = \"CapabilityCsVideo\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_CS_VIDEO = false;\n\n    /**\n     * Image sharing capability\n     */\n    public static final String CAPABILITY_IMAGE_SHARING = \"CapabilityImageShare\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_ISH = false;\n\n    /**\n     * Video sharing capability\n     */\n    public static final String CAPABILITY_VIDEO_SHARING = \"CapabilityVideoShare\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_VSH = false;\n\n    /**\n     * IP voice call capability\n     */\n    public static final String CAPABILITY_IP_VOICE_CALL = \"CapabilityIPVoiceCall\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_IP_VOICE_CALL = false;\n\n    /**\n     * IP video call capability\n     */\n    public static final String CAPABILITY_IP_VIDEO_CALL = \"CapabilityIPVideoCall\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_IP_VIDEO_CALL = false;\n\n    /**\n     * Instant Messaging session capability\n     */\n    public static final String CAPABILITY_IM_SESSION = \"CapabilityImSession\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_IM_SESSION = false;\n\n    /**\n     * Group Instant Messaging session capability\n     */\n    public static final String CAPABILITY_IM_GROUP_SESSION = \"CapabilityImGroupSession\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_IM_GROUP_SESSION = true;\n\n    /**\n     * File transfer capability\n     */\n    public static final String CAPABILITY_FILE_TRANSFER = \"CapabilityFileTransfer\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_FT = false;\n\n    /**\n     * File transfer via HTTP capability\n     */\n    public static final String CAPABILITY_FILE_TRANSFER_HTTP = \"CapabilityFileTransferHttp\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_FT_HTTP = false;\n\n    /**\n     * Presence discovery capability\n     */\n    public static final String CAPABILITY_PRESENCE_DISCOVERY = \"CapabilityPresenceDiscovery\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_PRESENCE_DISCOVERY = false;\n\n    /**\n     * Social presence capability\n     */\n    public static final String CAPABILITY_SOCIAL_PRESENCE = \"CapabilitySocialPresence\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_SOCIAL_PRESENCE = false;\n\n    /**\n     * Geolocation push capability\n     */\n    public static final String CAPABILITY_GEOLOCATION_PUSH = \"CapabilityGeoLocationPush\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_GEOLOCATION_PUSH = false;\n\n    /**\n     * File transfer thumbnail capability\n     */\n    public static final String CAPABILITY_FILE_TRANSFER_THUMBNAIL = \"CapabilityFileTransferThumbnail\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_FT_THUMBNAIL = false;\n\n    /**\n     * File transfer Store & Forward\n     */\n    public static final String CAPABILITY_FILE_TRANSFER_SF = \"CapabilityFileTransferSF\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_FT_SF = false;\n\n    /**\n     * Group chat Store & Forward\n     */\n    public static final String CAPABILITY_GROUP_CHAT_SF = \"CapabilityGroupChatSF\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_GC_SF = false;\n\n    /**\n     * RCS extensions capability\n     */\n    public static final String CAPABILITY_RCS_EXTENSIONS = \"CapabilityRcsExtensions\";\n    /* package private */static final String DEFAULT_CAPABILITY_RCS_EXTENSIONS = null;\n\n    /**\n     * Call composer\n     */\n    public static final String CAPABILITY_CALL_COMPOSER = \"CapabilityCallComposer\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_CALL_COMPOSER = true;\n\n    /**\n     * Shared map\n     */\n    public static final String CAPABILITY_SHARED_MAP = \"CapabilitySharedMap\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_SHARED_MAP = true;\n\n    /**\n     * Shared sketch\n     */\n    public static final String CAPABILITY_SHARED_SKETCH = \"CapabilitySharedSketch\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_SHARED_SKETCH = true;\n\n    /**\n     * Post call\n     */\n    public static final String CAPABILITY_POST_CALL = \"CapabilityPostCall\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_POST_CALL = true;\n\n    /**\n     * Instant messaging is always on (Store & Forward server)\n     */\n    public static final String IM_CAPABILITY_ALWAYS_ON = \"ImAlwaysOn\";\n    /* package private */static final Boolean DEFAULT_IM_CAPABILITY_ALWAYS_ON = true;\n\n    /**\n     * Group chat Store & Forward to invite participants\n     */\n    public static final String GROUP_CHAT_INVITE_ONLY_FULL_SF = \"GroupChatInviteOnlyFSF\";\n\n    /* package private */static final Boolean DEFAULT_GC_INVITE_ONLY_FULL_SF = false;\n\n    /**\n     * SIP Automata capability (@see RFC3840)\n     */\n    public static final String CAPABILITY_SIP_AUTOMATA = \"CapabilitySipAutomata\";\n    /* package private */static final Boolean DEFAULT_CAPABILITY_SIP_AUTOMATA = false;\n\n    /**\n     * File transfer always on (Store & Forward server)\n     */\n    public static final String FT_CAPABILITY_ALWAYS_ON = \"FtAlwaysOn\";\n    /* package private */static final Boolean DEFAULT_FT_CAPABILITY_ALWAYS_ON = false;\n\n    /**\n     * File transfer over HTTP always on\n     */\n    public static final String FT_HTTP_CAP_ALWAYS_ON = \"ftHTTPCapAlwaysOn\";\n\n    /* package private */static final Boolean DEFAULT_FT_HTTP_CAP_ALWAYS_ON = false;\n\n    public static final String MSG_DELIVERY_TIMEOUT = \"msgDeliveryTimeout\";\n\n    /*\n     * According to joyn Blackbird Product Definition Document Delivery Timeout - \"This parameter\n     * controls the timeout for the reception of Optional delivery reports for joyn messages after\n     * which a capability Parameter check is done to verify whether the contact is offline. When set\n     * to 0 the timeout shall not be used as a trigger for the capability exchange. A default value\n     * of 300 seconds is used in case the parameter is not provided.\"\n     */\n    /* package private */static final Long DEFAULT_MSG_DELIVERY_TIMEOUT = 300000L;\n\n    /**\n     * Contacts validity period in one-one messaging\n     */\n    public static final String MSG_CAP_VALIDITY_PERIOD = \"msgCapValidity\";\n\n    /* package private */static final Long DEFAULT_MSG_CAP_VALIDITY_PERIOD = 0L;\n\n    /**\n     * Instant messaging use report\n     */\n    public static final String IM_USE_REPORTS = \"ImUseReports\";\n    /* package private */static final Boolean DEFAULT_IM_USE_REPORTS = true;\n\n    /**\n     * Network access authorized\n     */\n    public static final String NETWORK_ACCESS = \"NetworkAccess\";\n    /* package private */static final Integer DEFAULT_NETWORK_ACCESS = NetworkAccessType.ANY\n            .toInt();\n\n    /**\n     * SIP stack timer T1 in milliseconds\n     */\n    public static final String SIP_TIMER_T1 = \"SipTimerT1\";\n    /* package private */static final Long DEFAULT_SIP_TIMER_T1 = 2000L;\n\n    /**\n     * SIP stack timer T2 in milliseconds\n     */\n    public static final String SIP_TIMER_T2 = \"SipTimerT2\";\n    /* package private */static final Long DEFAULT_SIP_TIMER_T2 = 16000L;\n\n    /**\n     * SIP stack timer T4 in milliseconds\n     */\n    public static final String SIP_TIMER_T4 = \"SipTimerT4\";\n    /* package private */static final Long DEFAULT_SIP_TIMER_T4 = 17000L;\n\n    /**\n     * Enable SIP keep alive\n     */\n    public static final String SIP_KEEP_ALIVE = \"SipKeepAlive\";\n    /* package private */static final Boolean DEFAULT_SIP_KEEP_ALIVE = true;\n\n    /**\n     * SIP keep alive period\n     */\n    public static final String SIP_KEEP_ALIVE_PERIOD = \"SipKeepAlivePeriod\";\n    /* package private */static final Long DEFAULT_SIP_KEEP_ALIVE_PERIOD = 60000L;\n\n    /**\n     * RCS APN\n     */\n    public static final String RCS_APN = \"RcsApn\";\n    /* package private */static final String DEFAULT_RCS_APN = null;\n\n    /**\n     * RCS operator\n     */\n    public static final String RCS_OPERATOR = \"RcsOperator\";\n    /* package private */static final String DEFAULT_RCS_OPERATOR = null;\n\n    /**\n     * GRUU support\n     */\n    public static final String GRUU = \"GRUU\";\n    /* package private */static final Boolean DEFAULT_GRUU = true;\n\n    /**\n     * IMEI used as device ID\n     */\n    public static final String USE_IMEI_AS_DEVICE_ID = \"ImeiDeviceId\";\n    /* package private */static final Boolean DEFAULT_USE_IMEI_AS_DEVICE_ID = true;\n\n    /**\n     * CPU always_on support\n     */\n    public static final String CPU_ALWAYS_ON = \"CpuAlwaysOn\";\n    /* package private */static final Boolean DEFAULT_CPU_ALWAYS_ON = false;\n\n    /**\n     * Configuration mode\n     */\n    public static final String CONFIG_MODE = \"ConfigMode\";\n    /* package private */static final Integer DEFAULT_CONFIG_MODE = ConfigurationMode.AUTO.toInt();\n\n    /**\n     * Terms and conditions response\n     */\n    /* package private */static final String TC_RESPONSE = \"TCResp\";\n    /* package private */static final Integer DEFAULT_TC_RESPONSE = TermsAndConditionsResponse.NO_ANSWER\n            .toInt();\n\n    /**\n     * Provisioning version\n     */\n    public static final String PROVISIONING_VERSION = \"ProvisioningVersion\";\n    /* package private */static final String DEFAULT_PROVISIONING_VERSION = \"0\";\n\n    /**\n     * Provisioning version\n     */\n    public static final String PROVISIONING_TOKEN = \"ProvisioningToken\";\n    /* package private */static final String DEFAULT_PROVISIONING_TOKEN = null;\n\n    /**\n     * Secondary provisioning address\n     */\n    public static final String SECONDARY_PROVISIONING_ADDRESS = \"SecondaryProvisioningAddress\";\n    /* package private */static final String DEFAULT_SECONDARY_PROV_ADDR = null;\n\n    /**\n     * Use only the secondary provisioning address\n     */\n    public static final String SECONDARY_PROVISIONING_ADDRESS_ONLY = \"SecondaryProvisioningAddressOnly\";\n    /* package private */static final Boolean DEFAULT_SECONDARY_PROV_ADDR_ONLY = false;\n\n    /**\n     * Directory path for photos\n     */\n    public static final String DIRECTORY_PATH_PHOTOS = \"DirectoryPathPhotos\";\n    /* package private */static final String DEFAULT_DIRECTORY_PATH_PHOTOS = Environment\n            .getExternalStorageDirectory() + \"/rcs/photos/\";\n\n    /**\n     * Directory path for videos\n     */\n    public static final String DIRECTORY_PATH_VIDEOS = \"DirectoryPathVideos\";\n    /* package private */static final String DEFAULT_DIRECTORY_PATH_VIDEOS = Environment\n            .getExternalStorageDirectory() + \"/rcs/videos/\";\n\n    /**\n     * Directory path for audios\n     */\n    public static final String DIRECTORY_PATH_AUDIOS = \"DirectoryPathAudios\";\n    /* package private */static final String DEFAULT_DIRECTORY_PATH_AUDIOS = Environment\n            .getExternalStorageDirectory() + \"/rcs/audios/\";\n\n    /**\n     * Directory path for files\n     */\n    public static final String DIRECTORY_PATH_FILES = \"DirectoryPathFiles\";\n    /* package private */static final String DEFAULT_DIRECTORY_PATH_FILES = Environment\n            .getExternalStorageDirectory() + \"/rcs/files/\";\n\n    /**\n     * Directory path for file icons\n     */\n    public static final String DIRECTORY_PATH_FILEICONS = \"DirectoryPathFileIcons\";\n    /* package private */static final String DEFAULT_DIRECTORY_PATH_FILEICONS = Environment\n            .getExternalStorageDirectory() + \"/rcs/fileicons/\";\n\n    /**\n     * Secure MSRP over Mobile access\n     */\n    public static final String SECURE_MSRP_OVER_MOBILE = \"SecureMsrpOverMobile\";\n    /* package private */static final Boolean DEFAULT_SECURE_MSRP_OVER_MOBILE = false;\n\n    /**\n     * Secure RTP over Mobile access\n     */\n    public static final String SECURE_RTP_OVER_MOBILE = \"SecureRtpOverMobile\";\n    /* package private */static final Boolean DEFAULT_SECURE_RTP_OVER_MOBILE = false;\n\n    /**\n     * Secure MSRP over Wi-Fi\n     */\n    public static final String SECURE_MSRP_OVER_WIFI = \"SecureMsrpOverWifi\";\n    /* package private */static final Boolean DEFAULT_SECURE_MSRP_OVER_WIFI = false;\n\n    /**\n     * Secured RTP over Wi-Fi\n     */\n    public static final String SECURE_RTP_OVER_WIFI = \"SecureRtpOverWifi\";\n    /* package private */static final Boolean DEFAULT_SECURE_RTP_OVER_WIFI = false;\n\n    /**\n     * Key and associated values for GSMA release of the device as provisioned by the network\n     */\n    public static final String KEY_GSMA_RELEASE = \"GsmaRelease\";\n    /* package private */static final Integer DEFAULT_KEY_GSMA_RELEASE = GsmaRelease.BLACKBIRD\n            .toInt();\n\n    /**\n     * IP voice call breakout capabilities in RCS-AA mode\n     */\n    public static final String IPVOICECALL_BREAKOUT_AA = \"IPCallBreakOutAA\";\n    /* package private */static final Boolean DEFAULT_IPVOICECALL_BREAKOUT_AA = false;\n\n    /**\n     * IP voice call breakout capabilities in RCS-CS mode\n     */\n    public static final String IPVOICECALL_BREAKOUT_CS = \"IPCallBreakOutCS\";\n    /* package private */static final Boolean DEFAULT_IPVOICECALL_BREAKOUT_CS = false;\n\n    /**\n     * CS call upgrade to IP Video Call in RCS-CS mode\n     */\n    public static final String IPVIDEOCALL_UPGRADE_FROM_CS = \"rcsIPVideoCallUpgradeFromCS\";\n    /* package private */static final Boolean DEFAULT_IPVIDEOCALL_UPGRADE_FROM_CS = false;\n\n    /**\n     * CS call upgrade to IP Video Call in case of capability error\n     */\n    public static final String IPVIDEOCALL_UPGRADE_ON_CAPERROR = \"rcsIPVideoCallUpgradeOnCapError\";\n    /* package private */static final Boolean DEFAULT_IPVIDEOCALL_UPGRADE_ON_CAPERROR = false;\n\n    /**\n     * Leaf node that tells an RCS-CS device whether it can initiate an RCS IP Video Call upgrade\n     * without first tearing down the CS voice call\n     */\n    public static final String IPVIDEOCALL_UPGRADE_ATTEMPT_EARLY = \"rcsIPVideoCallUpgradeAttemptEarly\";\n    /* package private */static final Boolean DEFAULT_IPVIDEOCALL_UPGRADE_ATTEMPT_EARLY = false;\n\n    /**\n     * TCP fallback option\n     */\n    public static final String TCP_FALLBACK = \"TcpFallback\";\n    /* package private */static final Boolean DEFAULT_TCP_FALLBACK = false;\n\n    /**\n     * Control RCS extensions\n     */\n    public static final String CONTROL_EXTENSIONS = \"ControlRcsExtensions\";\n    /* package private */static final Boolean DEFAULT_CONTROL_EXTENSIONS = false;\n\n    /**\n     * Allow RCS extensions\n     */\n    public static final String ALLOW_EXTENSIONS = \"AllowRcsExtensions\";\n    /* package private */static final Boolean DEFAULT_ALLOW_EXTENSIONS = true;\n\n    /**\n     * Max length for extensions using real time messaging (MSRP)\n     */\n    public static final String MAX_MSRP_SIZE_EXTENSIONS = \"ExtensionsMaxMsrpSize\";\n    /* package private */static final Integer DEFAULT_MAX_MSRP_SIZE_EXTENSIONS = 0;\n\n    /**\n     * Call composer inactivity timeout before session is closed\n     */\n    public static final String CALL_COMPOSER_INACTIVITY_TIMEOUT = \"CallComposerInactivityTimeout\";\n    /* package private */static final Long DEFAULT_CALL_COMPOSER_INACTIVITY_TIMEOUT = 180000L;\n\n    /**\n     * Validity of the RCS configuration.\n     */\n    public static final String CONFIGURATION_VALID = \"ConfigurationValidity\";\n    /* package private */static final Boolean DEFAULT_CONFIGURATION_VALID = false;\n\n    /**\n     * Auto accept file transfer invitation in roaming\n     */\n    public static final String AUTO_ACCEPT_FT_IN_ROAMING = \"AutoAcceptFtInRoaming\";\n    /* package private */static final Boolean DEFAULT_AUTO_ACCEPT_FT_IN_ROAMING = false;\n\n    /**\n     * Auto accept file transfer enabled\n     */\n    public static final String AUTO_ACCEPT_FT_CHANGEABLE = \"AutoAcceptFtChangeable\";\n    /* package private */static final Boolean DEFAULT_AUTO_ACCEPT_FT_CHANGEABLE = false;\n\n    /**\n     * Image resize option\n     */\n    public static final String KEY_IMAGE_RESIZE_OPTION = \"ImageResizeOption\";\n    /* package private */static final Integer DEFAULT_KEY_IMAGE_RESIZE_OPTION = ImageResizeOption.ALWAYS_ASK\n            .toInt();\n\n    /**\n     * RCS stack can be activated/deactivated by client applications\n     */\n    public static final String ENABLE_RCS_SWITCH = \"enableRcseSwitch\";\n    /* package private */static final Integer DEFAULT_ENABLE_RCS_SWITCH = EnableRcseSwitch.ALWAYS_SHOW\n            .toInt();\n\n    public static final String IM_MSG_TECH = \"ImMsgTech\";\n    /* package private */static final Integer DEFAULT_IM_MSG_TECH = ImMsgTech.SIMPLE_IM.toInt();\n\n    public static final String FIRST_MESSAGE_INVITE = \"FirstMessageInvite\";\n    /* package private */static final Boolean DEFAULT_FIRST_MESSAGE_INVITE = true;\n\n    public static final String REQUEST_AND_RESPOND_TO_GROUP_DISPLAY_REPORTS = \"RequestAndRespondToGroupDisplayReports\";\n    /* package private */static final Boolean DEFAULT_REQUEST_AND_RESPOND_TO_GROUP_DISPLAY_REPORTS = false;\n\n    public static final String MAX_ALLOWED_DISPLAY_NAME_CHARS = \"MaxAllowedDisplayNameChars\";\n    /* package private */static final Integer DEFAULT_MAX_ALLOWED_DISPLAY_NAME_CHARS = 256;\n\n    /**\n     * Provisioning optional user message content associated with the result of the configuration\n     * server response\n     */\n    /* package private */static final String PROV_USER_MSG_CONTENT = \"message\";\n    /* package private */static final String DEFAULT_PROV_USER_MSG_CONTENT = null;\n\n    /**\n     * Provisioning optional user message title associated with the result of the configuration\n     * server response\n     */\n    /* package private */static final String PROV_USER_MSG_TITLE = \"title\";\n    /* package private */static final String DEFAULT_PROV_USER_MSG_TITLE = null;\n\n    /**\n     * Mobile Country Code (0 if undefined)\n     */\n    /* package private */static final String MOBILE_COUNTRY_CODE = \"mcc\";\n    /* package private */static final Integer DEFAULT_MOBILE_COUNTRY_CODE = 0;\n\n    /**\n     * Mobile Network Code (0 if undefined)\n     */\n    /* package private */static final String MOBILE_NETWORK_CODE = \"mnc\";\n    /* package private */static final Integer DEFAULT_MOBILE_NETWORK_CODE = 0;\n\n    /* package private */static final String PROV_ACCEPT_BUTTON = \"Accept_btn\";\n    /* package private */static final Boolean DEFAULT_PROV_ACCEPT_BUTTON = false;\n\n    /* package private */static final String PROV_REJECT_BUTTON = \"Reject_btn\";\n    /* package private */static final Boolean DEFAULT_PROV_REJECT_BUTTON = false;\n\n    /* package private */static final String LOCAL_DISPLAY_LANGUAGE = \"language\";\n    /* package private */static final String DEFAULT_LOCAL_DISPLAY_LANGUAGE = null;\n\n    /* package private */final static Map<String, Object> sSettingsKeyDefaultValue;\n    static {\n        sSettingsKeyDefaultValue = new HashMap<>();\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SERVICE_ACTIVATED,\n                RcsSettingsData.DEFAULT_SERVICE_ACTIVATED);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CHAT_RESPOND_TO_DISPLAY_REPORTS,\n                RcsSettingsData.DEFAULT_CHAT_RESPOND_TO_DISPLAY_REPORTS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MIN_BATTERY_LEVEL,\n                RcsSettingsData.DEFAULT_MIN_BATTERY_LEVEL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_FILE_ICON_SIZE,\n                RcsSettingsData.DEFAULT_MAX_FILE_ICON_SIZE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_PHOTO_ICON_SIZE,\n                RcsSettingsData.DEFAULT_MAX_PHOTO_ICON_SIZE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_FREETXT_LENGTH,\n                RcsSettingsData.DEFAULT_MAX_FREETXT_LENGTH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_GEOLOC_LABEL_LENGTH,\n                RcsSettingsData.DEFAULT_MAX_GEOLOC_LABEL_LENGTH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.GEOLOC_EXPIRATION_TIME,\n                RcsSettingsData.DEFAULT_GEOLOC_EXPIRATION_TIME);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_CHAT_PARTICIPANTS,\n                RcsSettingsData.DEFAULT_MAX_CHAT_PARTICIPANTS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_CHAT_MSG_LENGTH,\n                RcsSettingsData.DEFAULT_MAX_CHAT_MSG_LENGTH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_GROUPCHAT_MSG_LENGTH,\n                RcsSettingsData.DEFAULT_MAX_GC_MSG_LENGTH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CHAT_IDLE_DURATION,\n                RcsSettingsData.DEFAULT_CHAT_IDLE_DURATION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_FILE_TRANSFER_SIZE,\n                RcsSettingsData.DEFAULT_MAX_FT_SIZE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.WARN_FILE_TRANSFER_SIZE,\n                RcsSettingsData.DEFAULT_WARN_FT_SIZE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_IMAGE_SHARE_SIZE,\n                RcsSettingsData.DEFAULT_MAX_ISH_SIZE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_VIDEO_SHARE_DURATION,\n                RcsSettingsData.DEFAULT_MAX_VSH_DURATION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_AUDIO_MESSAGE_DURATION,\n                RcsSettingsData.DEFAULT_MAX_AUDIO_DURATION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_CHAT_SESSIONS,\n                RcsSettingsData.DEFAULT_MAX_CHAT_SESSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_FILE_TRANSFER_SESSIONS,\n                RcsSettingsData.DEFAULT_MAX_FT_SESSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_CONCURRENT_OUTGOING_FILE_TRANSFERS,\n                RcsSettingsData.DEFAULT_MAX_CONCURRENT_OUTGOING_FT_SESSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_IP_CALL_SESSIONS,\n                RcsSettingsData.DEFAULT_MAX_IP_CALL_SESSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SMS_FALLBACK_SERVICE,\n                RcsSettingsData.DEFAULT_SMS_FALLBACK_SERVICE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.WARN_SF_SERVICE,\n                RcsSettingsData.DEFAULT_WARN_SF_SERVICE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.AUTO_ACCEPT_CHAT,\n                RcsSettingsData.DEFAULT_AUTO_ACCEPT_CHAT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.AUTO_ACCEPT_GROUP_CHAT,\n                RcsSettingsData.DEFAULT_AUTO_ACCEPT_GC);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.AUTO_ACCEPT_FILE_TRANSFER,\n                RcsSettingsData.DEFAULT_AUTO_ACCEPT_FT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IM_SESSION_START,\n                RcsSettingsData.DEFAULT_IM_SESSION_START);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USERPROFILE_IMS_USERNAME,\n                RcsSettingsData.DEFAULT_USERPROFILE_IMS_USERNAME);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USERPROFILE_IMS_DISPLAY_NAME,\n                RcsSettingsData.DEFAULT_USERPROFILE_IMS_DISPLAY_NAME);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USERPROFILE_IMS_HOME_DOMAIN,\n                RcsSettingsData.DEFAULT_USERPROFILE_IMS_HOME_DOMAIN);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USERPROFILE_IMS_PRIVATE_ID,\n                RcsSettingsData.DEFAULT_USERPROFILE_IMS_PRIVATE_ID);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USERPROFILE_IMS_PASSWORD,\n                RcsSettingsData.DEFAULT_USERPROFILE_IMS_PASSWORD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USERPROFILE_IMS_REALM,\n                RcsSettingsData.DEFAULT_USERPROFILE_IMS_REALM);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_PROXY_ADDR_MOBILE,\n                RcsSettingsData.DEFAULT_IMS_PROXY_ADDR_MOBILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_PROXY_PORT_MOBILE,\n                RcsSettingsData.DEFAULT_IMS_PROXY_PORT_MOBILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_PROXY_ADDR_WIFI,\n                RcsSettingsData.DEFAULT_IMS_PROXY_ADDR_WIFI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_PROXY_PORT_WIFI,\n                RcsSettingsData.DEFAULT_IMS_PROXY_PORT_WIFI);\n        sSettingsKeyDefaultValue\n                .put(RcsSettingsData.XDM_SERVER, RcsSettingsData.DEFAULT_XDM_SERVER);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.XDM_LOGIN, RcsSettingsData.DEFAULT_XDM_LOGIN);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.XDM_PASSWORD,\n                RcsSettingsData.DEFAULT_XDM_PASSWORD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FT_HTTP_SERVER,\n                RcsSettingsData.DEFAULT_FT_HTTP_SERVER);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FT_HTTP_LOGIN,\n                RcsSettingsData.DEFAULT_FT_HTTP_LOGIN);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FT_HTTP_PASSWORD,\n                RcsSettingsData.DEFAULT_FT_HTTP_PASSWORD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FT_PROTOCOL,\n                RcsSettingsData.DEFAULT_FT_PROTOCOL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IM_CONF_URI,\n                RcsSettingsData.DEFAULT_IM_CONF_URI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.ENDUSER_CONFIRMATION_URI,\n                RcsSettingsData.DEFAULT_ENDUSER_CONFIRMATION_URI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.UUID, RcsSettingsData.DEFAULT_UUID);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_CS_VIDEO,\n                RcsSettingsData.DEFAULT_CAPABILITY_CS_VIDEO);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_IMAGE_SHARING,\n                RcsSettingsData.DEFAULT_CAPABILITY_ISH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_VIDEO_SHARING,\n                RcsSettingsData.DEFAULT_CAPABILITY_VSH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_IP_VOICE_CALL,\n                RcsSettingsData.DEFAULT_CAPABILITY_IP_VOICE_CALL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_IP_VIDEO_CALL,\n                RcsSettingsData.DEFAULT_CAPABILITY_IP_VIDEO_CALL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_IM_SESSION,\n                RcsSettingsData.DEFAULT_CAPABILITY_IM_SESSION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_IM_GROUP_SESSION,\n                RcsSettingsData.DEFAULT_CAPABILITY_IM_GROUP_SESSION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_FILE_TRANSFER,\n                RcsSettingsData.DEFAULT_CAPABILITY_FT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_FILE_TRANSFER_HTTP,\n                RcsSettingsData.DEFAULT_CAPABILITY_FT_HTTP);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_PRESENCE_DISCOVERY,\n                RcsSettingsData.DEFAULT_CAPABILITY_PRESENCE_DISCOVERY);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_SOCIAL_PRESENCE,\n                RcsSettingsData.DEFAULT_CAPABILITY_SOCIAL_PRESENCE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH,\n                RcsSettingsData.DEFAULT_CAPABILITY_GEOLOCATION_PUSH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_FILE_TRANSFER_THUMBNAIL,\n                RcsSettingsData.DEFAULT_CAPABILITY_FT_THUMBNAIL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_GROUP_CHAT_SF,\n                RcsSettingsData.DEFAULT_CAPABILITY_GC_SF);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_FILE_TRANSFER_SF,\n                RcsSettingsData.DEFAULT_CAPABILITY_FT_SF);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_RCS_EXTENSIONS,\n                RcsSettingsData.DEFAULT_CAPABILITY_RCS_EXTENSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_CALL_COMPOSER,\n                RcsSettingsData.DEFAULT_CAPABILITY_CALL_COMPOSER);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_SHARED_MAP,\n                RcsSettingsData.DEFAULT_CAPABILITY_SHARED_MAP);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_SHARED_SKETCH,\n                RcsSettingsData.DEFAULT_CAPABILITY_SHARED_SKETCH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_POST_CALL,\n                RcsSettingsData.DEFAULT_CAPABILITY_POST_CALL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_SERVICE_POLLING_PERIOD,\n                RcsSettingsData.DEFAULT_IMS_SERVICE_POLLING_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_DEFAULT_PORT,\n                RcsSettingsData.DEFAULT_SIP_DEFAULT_PORT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_MOBILE,\n                RcsSettingsData.DEFAULT_SIP_DEFAULT_PROTOCOL_FOR_MOBILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_WIFI,\n                RcsSettingsData.DEFAULT_SIP_DEFAULT_PROTOCOL_FOR_WIFI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TLS_CERTIFICATE_ROOT,\n                RcsSettingsData.DEFAULT_TLS_CERTIFICATE_ROOT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TLS_CERTIFICATE_INTERMEDIATE,\n                RcsSettingsData.DEFAULT_TLS_CERTIFICATE_INTERMEDIATE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_TRANSACTION_TIMEOUT,\n                RcsSettingsData.DEFAULT_SIP_TRANSACTION_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MSRP_DEFAULT_PORT,\n                RcsSettingsData.DEFAULT_MSRP_DEFAULT_PORT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.RTP_DEFAULT_PORT,\n                RcsSettingsData.DEFAULT_RTP_DEFAULT_PORT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MSRP_TRANSACTION_TIMEOUT,\n                RcsSettingsData.DEFAULT_MSRP_TRANSACTION_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.REGISTER_EXPIRE_PERIOD,\n                RcsSettingsData.DEFAULT_REGISTER_EXPIRE_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.REGISTER_RETRY_BASE_TIME,\n                RcsSettingsData.DEFAULT_REGISTER_RETRY_BASE_TIME);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.REGISTER_RETRY_MAX_TIME,\n                RcsSettingsData.DEFAULT_REGISTER_RETRY_MAX_TIME);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PUBLISH_EXPIRE_PERIOD,\n                RcsSettingsData.DEFAULT_PUBLISH_EXPIRE_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.REVOKE_TIMEOUT,\n                RcsSettingsData.DEFAULT_REVOKE_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_AUTHENT_PROCEDURE_MOBILE,\n                RcsSettingsData.DEFAULT_IMS_AUTHENT_PROCEDURE_MOBILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IMS_AUTHENT_PROCEDURE_WIFI,\n                RcsSettingsData.DEFAULT_IMS_AUTHENT_PROCEDURE_WIFI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TEL_URI_FORMAT,\n                RcsSettingsData.DEFAULT_TEL_URI_FORMAT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.RINGING_SESSION_PERIOD,\n                RcsSettingsData.DEFAULT_RINGING_SESSION_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SUBSCRIBE_EXPIRE_PERIOD,\n                RcsSettingsData.DEFAULT_SUBSCRIBE_EXPIRE_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IS_COMPOSING_TIMEOUT,\n                RcsSettingsData.DEFAULT_IS_COMPOSING_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SESSION_REFRESH_EXPIRE_PERIOD,\n                RcsSettingsData.DEFAULT_SESSION_REFRESH_EXPIRE_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PERMANENT_STATE_MODE,\n                RcsSettingsData.DEFAULT_PERMANENT_STATE_MODE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TRACE_ACTIVATED,\n                RcsSettingsData.DEFAULT_TRACE_ACTIVATED);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TRACE_LEVEL,\n                RcsSettingsData.DEFAULT_TRACE_LEVEL);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_TRACE_ACTIVATED,\n                RcsSettingsData.DEFAULT_SIP_TRACE_ACTIVATED);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_TRACE_FILE,\n                RcsSettingsData.DEFAULT_SIP_TRACE_FILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MEDIA_TRACE_ACTIVATED,\n                RcsSettingsData.DEFAULT_MEDIA_TRACE_ACTIVATED);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_REFRESH_TIMEOUT,\n                RcsSettingsData.DEFAULT_CAPABILITY_REFRESH_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_EXPIRY_TIMEOUT,\n                RcsSettingsData.DEFAULT_CAPABILITY_EXPIRY_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_POLLING_PERIOD,\n                RcsSettingsData.DEFAULT_CAPABILITY_POLLING_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IM_CAPABILITY_ALWAYS_ON,\n                RcsSettingsData.DEFAULT_IM_CAPABILITY_ALWAYS_ON);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.GROUP_CHAT_INVITE_ONLY_FULL_SF,\n                RcsSettingsData.DEFAULT_GC_INVITE_ONLY_FULL_SF);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FT_CAPABILITY_ALWAYS_ON,\n                RcsSettingsData.DEFAULT_FT_CAPABILITY_ALWAYS_ON);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FT_HTTP_CAP_ALWAYS_ON,\n                RcsSettingsData.DEFAULT_FT_HTTP_CAP_ALWAYS_ON);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MSG_DELIVERY_TIMEOUT,\n                RcsSettingsData.DEFAULT_MSG_DELIVERY_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MSG_CAP_VALIDITY_PERIOD,\n                RcsSettingsData.DEFAULT_MSG_CAP_VALIDITY_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IM_USE_REPORTS,\n                RcsSettingsData.DEFAULT_IM_USE_REPORTS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.NETWORK_ACCESS,\n                RcsSettingsData.DEFAULT_NETWORK_ACCESS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_TIMER_T1,\n                RcsSettingsData.DEFAULT_SIP_TIMER_T1);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_TIMER_T2,\n                RcsSettingsData.DEFAULT_SIP_TIMER_T2);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_TIMER_T4,\n                RcsSettingsData.DEFAULT_SIP_TIMER_T4);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_KEEP_ALIVE,\n                RcsSettingsData.DEFAULT_SIP_KEEP_ALIVE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SIP_KEEP_ALIVE_PERIOD,\n                RcsSettingsData.DEFAULT_SIP_KEEP_ALIVE_PERIOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.RCS_APN, RcsSettingsData.DEFAULT_RCS_APN);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.RCS_OPERATOR,\n                RcsSettingsData.DEFAULT_RCS_OPERATOR);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_CHAT_LOG_ENTRIES,\n                RcsSettingsData.DEFAULT_MAX_CHAT_LOG_ENTRIES);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_RICHCALL_LOG_ENTRIES,\n                RcsSettingsData.DEFAULT_MAX_RICHCALL_LOG_ENTRIES);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_IPCALL_LOG_ENTRIES,\n                RcsSettingsData.DEFAULT_MAX_IPCALL_LOG_ENTRIES);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.GRUU, RcsSettingsData.DEFAULT_GRUU);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.USE_IMEI_AS_DEVICE_ID,\n                RcsSettingsData.DEFAULT_USE_IMEI_AS_DEVICE_ID);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CPU_ALWAYS_ON,\n                RcsSettingsData.DEFAULT_CPU_ALWAYS_ON);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CONFIG_MODE,\n                RcsSettingsData.DEFAULT_CONFIG_MODE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TC_RESPONSE,\n                RcsSettingsData.DEFAULT_TC_RESPONSE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PROVISIONING_VERSION,\n                RcsSettingsData.DEFAULT_PROVISIONING_VERSION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PROVISIONING_TOKEN,\n                RcsSettingsData.DEFAULT_PROVISIONING_TOKEN);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS,\n                RcsSettingsData.DEFAULT_SECONDARY_PROV_ADDR);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS_ONLY,\n                RcsSettingsData.DEFAULT_SECONDARY_PROV_ADDR_ONLY);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.DIRECTORY_PATH_PHOTOS,\n                RcsSettingsData.DEFAULT_DIRECTORY_PATH_PHOTOS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.DIRECTORY_PATH_VIDEOS,\n                RcsSettingsData.DEFAULT_DIRECTORY_PATH_VIDEOS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.DIRECTORY_PATH_AUDIOS,\n                RcsSettingsData.DEFAULT_DIRECTORY_PATH_AUDIOS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.DIRECTORY_PATH_FILES,\n                RcsSettingsData.DEFAULT_DIRECTORY_PATH_FILES);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.DIRECTORY_PATH_FILEICONS,\n                RcsSettingsData.DEFAULT_DIRECTORY_PATH_FILEICONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SECURE_MSRP_OVER_MOBILE,\n                RcsSettingsData.DEFAULT_SECURE_MSRP_OVER_MOBILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SECURE_RTP_OVER_MOBILE,\n                RcsSettingsData.DEFAULT_SECURE_RTP_OVER_MOBILE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SECURE_MSRP_OVER_WIFI,\n                RcsSettingsData.DEFAULT_SECURE_MSRP_OVER_WIFI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.SECURE_RTP_OVER_WIFI,\n                RcsSettingsData.DEFAULT_SECURE_RTP_OVER_WIFI);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MESSAGING_MODE,\n                RcsSettingsData.DEFAULT_KEY_MESSAGING_MODE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CAPABILITY_SIP_AUTOMATA,\n                RcsSettingsData.DEFAULT_CAPABILITY_SIP_AUTOMATA);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.KEY_GSMA_RELEASE,\n                RcsSettingsData.DEFAULT_KEY_GSMA_RELEASE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IPVOICECALL_BREAKOUT_AA,\n                RcsSettingsData.DEFAULT_IPVOICECALL_BREAKOUT_AA);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IPVOICECALL_BREAKOUT_CS,\n                RcsSettingsData.DEFAULT_IPVOICECALL_BREAKOUT_CS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IPVIDEOCALL_UPGRADE_FROM_CS,\n                RcsSettingsData.DEFAULT_IPVIDEOCALL_UPGRADE_FROM_CS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IPVIDEOCALL_UPGRADE_ON_CAPERROR,\n                RcsSettingsData.DEFAULT_IPVIDEOCALL_UPGRADE_ON_CAPERROR);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IPVIDEOCALL_UPGRADE_ATTEMPT_EARLY,\n                RcsSettingsData.DEFAULT_IPVIDEOCALL_UPGRADE_ATTEMPT_EARLY);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.TCP_FALLBACK,\n                RcsSettingsData.DEFAULT_TCP_FALLBACK);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CONTROL_EXTENSIONS,\n                RcsSettingsData.DEFAULT_CONTROL_EXTENSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.ALLOW_EXTENSIONS,\n                RcsSettingsData.DEFAULT_ALLOW_EXTENSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_MSRP_SIZE_EXTENSIONS,\n                RcsSettingsData.DEFAULT_MAX_MSRP_SIZE_EXTENSIONS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CALL_COMPOSER_INACTIVITY_TIMEOUT,\n                RcsSettingsData.DEFAULT_CALL_COMPOSER_INACTIVITY_TIMEOUT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.CONFIGURATION_VALID,\n                RcsSettingsData.DEFAULT_CONFIGURATION_VALID);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.AUTO_ACCEPT_FT_IN_ROAMING,\n                RcsSettingsData.DEFAULT_AUTO_ACCEPT_FT_IN_ROAMING);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.AUTO_ACCEPT_FT_CHANGEABLE,\n                RcsSettingsData.DEFAULT_AUTO_ACCEPT_FT_CHANGEABLE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.DEFAULT_MESSAGING_METHOD,\n                RcsSettingsData.DEFAULT_KEY_DEFAULT_MESSAGING_METHOD);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.KEY_IMAGE_RESIZE_OPTION,\n                RcsSettingsData.DEFAULT_KEY_IMAGE_RESIZE_OPTION);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.ENABLE_RCS_SWITCH,\n                RcsSettingsData.DEFAULT_ENABLE_RCS_SWITCH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.IM_MSG_TECH,\n                RcsSettingsData.DEFAULT_IM_MSG_TECH);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.FIRST_MESSAGE_INVITE,\n                RcsSettingsData.DEFAULT_FIRST_MESSAGE_INVITE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.REQUEST_AND_RESPOND_TO_GROUP_DISPLAY_REPORTS,\n                RcsSettingsData.DEFAULT_REQUEST_AND_RESPOND_TO_GROUP_DISPLAY_REPORTS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MAX_ALLOWED_DISPLAY_NAME_CHARS,\n                RcsSettingsData.DEFAULT_MAX_ALLOWED_DISPLAY_NAME_CHARS);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PROV_USER_MSG_CONTENT,\n                RcsSettingsData.DEFAULT_PROV_USER_MSG_CONTENT);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PROV_USER_MSG_TITLE,\n                RcsSettingsData.DEFAULT_PROV_USER_MSG_TITLE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MOBILE_COUNTRY_CODE,\n                RcsSettingsData.DEFAULT_MOBILE_COUNTRY_CODE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.MOBILE_NETWORK_CODE,\n                RcsSettingsData.DEFAULT_MOBILE_NETWORK_CODE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PROV_ACCEPT_BUTTON,\n                RcsSettingsData.DEFAULT_PROV_ACCEPT_BUTTON);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.PROV_REJECT_BUTTON,\n                RcsSettingsData.DEFAULT_PROV_REJECT_BUTTON);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.LOCAL_DISPLAY_LANGUAGE,\n                RcsSettingsData.DEFAULT_LOCAL_DISPLAY_LANGUAGE);\n        sSettingsKeyDefaultValue.put(RcsSettingsData.ENRICH_CALLING_SERVICE,\n                RcsSettingsData.DEFAULT_ENRICH_CALLING_SERVICE);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/settings/RcsSettingsProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.settings;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.utils.DatabaseUtils;\n\nimport android.content.ContentProvider;\nimport android.content.ContentProviderOperation;\nimport android.content.ContentProviderResult;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.OperationApplicationException;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.Map;\n\n/**\n * RCS settings provider\n *\n * @author jexa7410\n * @author yplo6403\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class RcsSettingsProvider extends ContentProvider {\n\n    private static final String TABLE = \"setting\";\n\n    private static final String SELECTION_WITH_KEY_ONLY = RcsSettingsData.KEY_KEY.concat(\"=?\");\n\n    /**\n     * Database filename\n     */\n    public static final String DATABASE_NAME = \"rcs_settings.db\";\n\n    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n\n    static {\n        sUriMatcher.addURI(RcsSettingsData.CONTENT_URI.getAuthority(), RcsSettingsData.CONTENT_URI\n                .getPath().substring(1), UriType.SETTINGS);\n        sUriMatcher.addURI(RcsSettingsData.CONTENT_URI.getAuthority(), RcsSettingsData.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.SETTINGS_WITH_KEY);\n    }\n\n    private static final class UriType {\n\n        private static final int SETTINGS = 1;\n\n        private static final int SETTINGS_WITH_KEY = 2;\n    }\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/com.gsma.rcs.setting\";\n\n        private static final String TYPE_ITEM = \"vnd.android.cursor.item/com.gsma.rcs.setting\";\n    }\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 121;\n\n        /**\n         * Add a parameter in the db\n         *\n         * @param db Database\n         * @param key Key\n         * @param value Value\n         */\n        private void addParameter(SQLiteDatabase db, String key, String value) {\n            ContentValues values = new ContentValues();\n            values.put(RcsSettingsData.KEY_KEY, key);\n            values.put(RcsSettingsData.KEY_VALUE, value);\n            db.insertOrThrow(TABLE, null, values);\n        }\n\n        private void addParameter(SQLiteDatabase db, String key, Object value) {\n            addParameter(db, key, value == null ? null : value.toString());\n        }\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE + '(' + RcsSettingsData.KEY_KEY\n                    + \" TEXT NOT NULL PRIMARY KEY,\" + RcsSettingsData.KEY_VALUE + \" TEXT)\");\n            /* Insert default values for parameters */\n            for (Map.Entry<String, Object> entry : RcsSettingsData.sSettingsKeyDefaultValue\n                    .entrySet()) {\n                addParameter(db, entry.getKey(), entry.getValue());\n            }\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            /* Get old data before deleting the table */\n            Cursor oldDataCursor = db.query(TABLE, null, null, null, null, null, null);\n            CursorUtil.assertCursorIsNotNull(oldDataCursor, TABLE);\n\n            /*\n             * Get all the pairs key/value of the old table to insert them back after update\n             */\n            ArrayList<ContentValues> valuesList = new ArrayList<>();\n            while (oldDataCursor.moveToNext()) {\n                String key = null;\n                String value = null;\n                int index = oldDataCursor.getColumnIndex(RcsSettingsData.KEY_KEY);\n                if (index != -1) {\n                    key = oldDataCursor.getString(index);\n                }\n                index = oldDataCursor.getColumnIndex(RcsSettingsData.KEY_VALUE);\n                if (index != -1) {\n                    value = oldDataCursor.getString(index);\n                }\n                if (key != null && value != null) {\n                    ContentValues values = new ContentValues();\n                    values.put(RcsSettingsData.KEY_KEY, key);\n                    values.put(RcsSettingsData.KEY_VALUE, value);\n                    valuesList.add(values);\n                }\n            }\n            oldDataCursor.close();\n\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE));\n\n            onCreate(db);\n\n            /* Put the old values back when possible */\n            for (ContentValues values : valuesList) {\n                String[] selectionArgs = new String[] {\n                    values.getAsString(RcsSettingsData.KEY_KEY)\n                };\n                db.update(TABLE, values, SELECTION_WITH_KEY_ONLY, selectionArgs);\n            }\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithKey(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_KEY_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_KEY_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithKey(String[] selectionArgs, String key) {\n        return DatabaseUtils.appendIdWithSelectionArgs(key, selectionArgs);\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.SETTINGS:\n                return CursorType.TYPE_DIRECTORY;\n\n            case UriType.SETTINGS_WITH_KEY:\n                return CursorType.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.SETTINGS_WITH_KEY:\n                    String key = uri.getLastPathSegment();\n                    selection = getSelectionWithKey(selection);\n                    selectionArgs = getSelectionArgsWithKey(selectionArgs, key);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.SETTINGS:\n                    SQLiteDatabase database = mOpenHelper.getReadableDatabase();\n                    cursor = database.query(TABLE, projection, selection, selectionArgs, null,\n                            null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n        }\n        /*\n         * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n         * exception.\n         */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.SETTINGS_WITH_KEY:\n                String key = uri.getLastPathSegment();\n                selection = getSelectionWithKey(selection);\n                selectionArgs = getSelectionArgsWithKey(selectionArgs, key);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.SETTINGS:\n                SQLiteDatabase database = mOpenHelper.getWritableDatabase();\n                int count = database.update(TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(uri, null);\n                }\n                return count;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        throw new UnsupportedOperationException(\"Cannot insert URI \" + uri + \"!\");\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String where, String[] whereArgs) {\n        throw new UnsupportedOperationException(\"Cannot delete URI \" + uri + \"!\");\n    }\n\n    @Override\n    public ContentProviderResult[] applyBatch(\n            @NonNull ArrayList<ContentProviderOperation> operations)\n            throws OperationApplicationException {\n        SQLiteDatabase database = mOpenHelper.getWritableDatabase();\n        database.beginTransaction();\n        try {\n            ContentProviderResult[] results = new ContentProviderResult[operations.size()];\n            int index = 0;\n            for (ContentProviderOperation operation : operations) {\n                results[index] = operation.apply(this, results, index);\n                index++;\n            }\n            database.setTransactionSuccessful();\n            return results;\n        } finally {\n            database.endTransaction();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/GeolocSharingData.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\n\nimport android.net.Uri;\n\n/**\n * Geoloc sharing data constants\n */\npublic class GeolocSharingData {\n\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.geolocshare/geolocshare\");\n\n    public static final int HISTORYLOG_MEMBER_ID = GeolocSharingLog.HISTORYLOG_MEMBER_ID;\n\n    /* package private */static final String KEY_BASECOLUMN_ID = GeolocSharingLog.BASECOLUMN_ID;\n\n    /* package private */static final String KEY_SHARING_ID = GeolocSharingLog.SHARING_ID;\n\n    /* package private */static final String KEY_CONTACT = GeolocSharingLog.CONTACT;\n\n    /* package private */static final String KEY_CONTENT = GeolocSharingLog.CONTENT;\n\n    /* package private */static final String KEY_MIME_TYPE = GeolocSharingLog.MIME_TYPE;\n\n    /* package private */static final String KEY_DIRECTION = GeolocSharingLog.DIRECTION;\n\n    /* package private */static final String KEY_STATE = GeolocSharingLog.STATE;\n\n    /* package private */static final String KEY_REASON_CODE = GeolocSharingLog.REASON_CODE;\n\n    /* package private */static final String KEY_TIMESTAMP = GeolocSharingLog.TIMESTAMP;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/GeolocSharingDeleteTask.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.GeolocTransferSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.GeolocSharingServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\npublic class GeolocSharingDeleteTask extends DeleteTask.GroupedByContactId {\n\n    private static final Logger sLogger = Logger.getLogger(GeolocSharingDeleteTask.class.getName());\n\n    private final GeolocSharingServiceImpl mGeolocSharingService;\n\n    private final RichcallService mRichcallService;\n\n    /**\n     * Deletion of all Geoloc sharing.\n     * \n     * @param geolocSharingService the geoloc service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     */\n    public GeolocSharingDeleteTask(GeolocSharingServiceImpl geolocSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver) {\n        super(contentResolver, GeolocSharingData.CONTENT_URI, GeolocSharingData.KEY_SHARING_ID,\n                GeolocSharingData.KEY_CONTACT, (String) null);\n        mGeolocSharingService = geolocSharingService;\n        mRichcallService = richcallService;\n    }\n\n    /**\n     * Deletion of all geoloc sharing with a specific contact.\n     * \n     * @param geolocSharingService the geoloc service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     * @param contact the contact id\n     */\n    public GeolocSharingDeleteTask(GeolocSharingServiceImpl geolocSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver, ContactId contact) {\n        super(contentResolver, GeolocSharingData.CONTENT_URI, GeolocSharingData.KEY_SHARING_ID,\n                GeolocSharingData.KEY_CONTACT, contact);\n        mGeolocSharingService = geolocSharingService;\n        mRichcallService = richcallService;\n    }\n\n    /**\n     * Deletion of a specific geoloc sharing.\n     * \n     * @param geolocSharingService the geoloc service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     * @param transferId the transfer id\n     */\n    public GeolocSharingDeleteTask(GeolocSharingServiceImpl geolocSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver, String transferId) {\n        super(contentResolver, GeolocSharingData.CONTENT_URI, GeolocSharingData.KEY_SHARING_ID,\n                GeolocSharingData.KEY_CONTACT, null, transferId);\n        mGeolocSharingService = geolocSharingService;\n        mRichcallService = richcallService;\n    }\n\n    @Override\n    protected void onRowDelete(ContactId contact, String sharingId) throws PayloadException {\n        GeolocTransferSession session = mRichcallService.getGeolocTransferSession(sharingId);\n        if (session == null) {\n            mGeolocSharingService.removeGeolocSharing(sharingId);\n            return;\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mGeolocSharingService.removeGeolocSharing(sharingId);\n    }\n\n    @Override\n    protected void onCompleted(ContactId contact, Set<String> deletedIds) {\n        mGeolocSharingService.broadcastDeleted(contact, deletedIds);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/GeolocSharingPersistedStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\n\nimport android.database.Cursor;\n\n/**\n * GeolocSharingPersistedStorageAccessor helps in retrieving persisted data related to a geoloc\n * sharing from the persisted storage. It can utilize caching for such data that will not be changed\n * after creation of the geoloc sharing to speed up consecutive access.\n */\npublic class GeolocSharingPersistedStorageAccessor {\n\n    private final String mSharingId;\n\n    private final RichCallHistory mRichCallLog;\n\n    private ContactId mContact;\n\n    private Geoloc mGeoloc;\n\n    private Direction mDirection;\n\n    private long mTimestamp;\n\n    public GeolocSharingPersistedStorageAccessor(String sharingId, RichCallHistory richCallHistory) {\n        mSharingId = sharingId;\n        mRichCallLog = richCallHistory;\n    }\n\n    public GeolocSharingPersistedStorageAccessor(String sharingId, ContactId contact,\n            Geoloc geoloc, Direction direction, RichCallHistory richCallHistory, long timestamp) {\n        mSharingId = sharingId;\n        mContact = contact;\n        mGeoloc = geoloc;\n        mDirection = direction;\n        mRichCallLog = richCallHistory;\n        mTimestamp = timestamp;\n    }\n\n    private void cacheData() {\n        Cursor cursor = null;\n        try {\n            cursor = mRichCallLog.getGeolocSharingData(mSharingId);\n            if (!cursor.moveToNext()) {\n                throw new ServerApiPersistentStorageException(\"Data not found for video sharing \"\n                        + mSharingId);\n            }\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GeolocSharingData.KEY_CONTACT));\n            if (contact != null) {\n                mContact = ContactUtil.createContactIdFromTrustedData(contact);\n            }\n            mDirection = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(GeolocSharingData.KEY_DIRECTION)));\n            String geoloc = cursor.getString(cursor\n                    .getColumnIndexOrThrow(GeolocSharingData.KEY_CONTENT));\n            if (geoloc != null) {\n                mGeoloc = new Geoloc(geoloc);\n            }\n            mTimestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(GeolocSharingData.KEY_TIMESTAMP));\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    public ContactId getRemoteContact() {\n        /*\n         * Utilizing cache here as contact can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mContact == null) {\n            cacheData();\n        }\n        return mContact;\n    }\n\n    public Geoloc getGeoloc() {\n        /*\n         * Utilizing cache here as geoloc can't be changed in persistent storage after geoloc has\n         * been set anyway so no need to query for it multiple times.\n         */\n        if (mGeoloc == null) {\n            cacheData();\n        }\n        return mGeoloc;\n    }\n\n    public String getMimeType() {\n        return MimeType.GEOLOC_MESSAGE;\n    }\n\n    public State getState() {\n        State state = mRichCallLog.getGeolocSharingState(mSharingId);\n        if (state == null) {\n            throw new ServerApiPersistentStorageException(\"State not found for geoloc sharing \"\n                    + mSharingId);\n        }\n        return state;\n    }\n\n    public ReasonCode getReasonCode() {\n        ReasonCode reasonCode = mRichCallLog.getGeolocSharingReasonCode(mSharingId);\n        if (reasonCode == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Reason code not found for geoloc sharing \" + mSharingId);\n        }\n        return reasonCode;\n    }\n\n    public Direction getDirection() {\n        /*\n         * Utilizing cache here as direction can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mDirection == null) {\n            cacheData();\n        }\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        /*\n         * Utilizing cache here as timestamp can't be changed in persistent storage after it has\n         * been set to some value bigger than zero, so no need to query for it multiple times.\n         */\n        if (mTimestamp == 0) {\n            cacheData();\n        }\n        return mTimestamp;\n    }\n\n    public boolean setStateAndReasonCode(State state, ReasonCode reasonCode) {\n        return mRichCallLog.setGeolocSharingStateAndReasonCode(mSharingId, state, reasonCode);\n    }\n\n    public void addIncomingGeolocSharing(ContactId contact, State state, ReasonCode reasonCode,\n            long timestamp) {\n        mContact = contact;\n        mTimestamp = timestamp;\n        mRichCallLog.addIncomingGeolocSharing(mContact, mSharingId, state, reasonCode, timestamp);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/GeolocSharingProvider.java",
    "content": "/*\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.history.HistoryMemberBaseIdCreator;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\n@SuppressWarnings(\"ConstantConditions\")\npublic class GeolocSharingProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String SELECTION_WITH_SHARING_ID_ONLY = GeolocSharingData.KEY_SHARING_ID\n            .concat(\"=?\");\n\n    private static final class UriType {\n\n        private static final class GeolocSharing {\n            private static final int BASE = 1;\n\n            private static final int WITH_SHARING_ID = 2;\n        }\n\n        private static final class InternalGeolocSharing {\n            private static final int BASE = 3;\n\n            private static final int WITH_SHARING_ID = 4;\n        }\n    }\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/geolocshare\";\n\n        private static final String TYPE_ITEM = \"vnd.android.cursor.item/geolocshare\";\n    }\n\n    private static final UriMatcher sUriMatcher;\n    static {\n        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n        sUriMatcher.addURI(GeolocSharingData.CONTENT_URI.getAuthority(),\n                GeolocSharingData.CONTENT_URI.getPath().substring(1),\n                UriType.InternalGeolocSharing.BASE);\n        sUriMatcher.addURI(GeolocSharingData.CONTENT_URI.getAuthority(),\n                GeolocSharingData.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.InternalGeolocSharing.WITH_SHARING_ID);\n        sUriMatcher.addURI(GeolocSharingLog.CONTENT_URI.getAuthority(),\n                GeolocSharingLog.CONTENT_URI.getPath().substring(1), UriType.GeolocSharing.BASE);\n        sUriMatcher.addURI(GeolocSharingLog.CONTENT_URI.getAuthority(),\n                GeolocSharingLog.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.GeolocSharing.WITH_SHARING_ID);\n    }\n\n    /**\n     * Table name\n     */\n    public static final String TABLE = \"geolocshare\";\n\n    /**\n     * Database name\n     */\n    public static final String DATABASE_NAME = \"geolocshare.db\";\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 3;\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE + \" (\"\n                    + GeolocSharingData.KEY_SHARING_ID + \" TEXT NOT NULL PRIMARY KEY,\"\n                    + GeolocSharingData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + GeolocSharingData.KEY_CONTACT + \" TEXT NOT NULL,\"\n                    + GeolocSharingData.KEY_CONTENT + \" TEXT,\" \n                    + GeolocSharingData.KEY_MIME_TYPE + \" TEXT NOT NULL,\" \n                    + GeolocSharingData.KEY_DIRECTION + \" INTEGER NOT NULL,\"\n                    + GeolocSharingData.KEY_STATE + \" INTEGER NOT NULL,\"\n                    + GeolocSharingData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + GeolocSharingData.KEY_TIMESTAMP + \" INTEGER NOT NULL)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + GeolocSharingData.KEY_BASECOLUMN_ID + \"_idx ON \" + TABLE\n                    + '(' + GeolocSharingData.KEY_BASECOLUMN_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + GeolocSharingData.KEY_CONTACT + \"_idx ON \" + TABLE + '('\n                    + GeolocSharingData.KEY_CONTACT + ')');\n            db.execSQL(\"CREATE INDEX \" + GeolocSharingData.KEY_TIMESTAMP + \"_idx ON \" + TABLE + '('\n                    + GeolocSharingData.KEY_TIMESTAMP + ')');\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE));\n            onCreate(db);\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithSharingId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_SHARING_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_SHARING_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithSharingId(String[] selectionArgs, String sharingId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(sharingId, selectionArgs);\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGeolocSharing.BASE:\n                /* Intentional fall through */\n            case UriType.GeolocSharing.BASE:\n                return CursorType.TYPE_DIRECTORY;\n\n            case UriType.InternalGeolocSharing.WITH_SHARING_ID:\n                /* Intentional fall through */\n            case UriType.GeolocSharing.WITH_SHARING_ID:\n                return CursorType.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalGeolocSharing.WITH_SHARING_ID:\n                    String sharingId = uri.getLastPathSegment();\n                    selection = getSelectionWithSharingId(selection);\n                    selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(GeolocSharingLog.CONTENT_URI, sharingId));\n                    return cursor;\n\n                case UriType.InternalGeolocSharing.BASE:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            GeolocSharingLog.CONTENT_URI);\n                    return cursor;\n\n                case UriType.GeolocSharing.WITH_SHARING_ID:\n                    sharingId = uri.getLastPathSegment();\n                    selection = getSelectionWithSharingId(selection);\n                    selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.GeolocSharing.BASE:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n        }\n        /*\n         * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n         * exception.\n         */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        Uri notificationUri = GeolocSharingLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGeolocSharing.WITH_SHARING_ID:\n                String sharingId = uri.getLastPathSegment();\n                selection = getSelectionWithSharingId(selection);\n                selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                notificationUri = Uri.withAppendedPath(notificationUri, sharingId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalGeolocSharing.BASE:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    ContentResolver resolver = getContext().getContentResolver();\n                    resolver.notifyChange(notificationUri, null);\n                    resolver.notifyChange(HistoryLog.CONTENT_URI, null);\n                }\n                return count;\n\n            case UriType.GeolocSharing.WITH_SHARING_ID:\n                /* Intentional fall through */\n            case UriType.GeolocSharing.BASE:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGeolocSharing.WITH_SHARING_ID:\n                /* Intentional fall through */\n            case UriType.InternalGeolocSharing.BASE:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String sharingId = initialValues.getAsString(GeolocSharingData.KEY_SHARING_ID);\n                initialValues.put(GeolocSharingData.KEY_BASECOLUMN_ID, HistoryMemberBaseIdCreator\n                        .createUniqueId(getContext(), GeolocSharingData.HISTORYLOG_MEMBER_ID));\n                if (db.insert(TABLE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri.toString() + '!');\n                }\n                Uri notificationUri = GeolocSharingLog.CONTENT_URI.buildUpon()\n                        .appendPath(sharingId).build();\n                ContentResolver resolver = getContext().getContentResolver();\n                resolver.notifyChange(notificationUri, null);\n                resolver.notifyChange(HistoryLog.CONTENT_URI, null);\n                return notificationUri;\n\n            case UriType.GeolocSharing.WITH_SHARING_ID:\n                /* Intentional fall through */\n            case UriType.GeolocSharing.BASE:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        Uri notificationUri = GeolocSharingLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalGeolocSharing.WITH_SHARING_ID:\n                String sharingId = uri.getLastPathSegment();\n                selection = getSelectionWithSharingId(selection);\n                selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                notificationUri = Uri.withAppendedPath(notificationUri, sharingId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalGeolocSharing.BASE:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    ContentResolver resolver = getContext().getContentResolver();\n                    resolver.notifyChange(notificationUri, null);\n                    resolver.notifyChange(HistoryLog.CONTENT_URI, null);\n                }\n                return count;\n\n            case UriType.GeolocSharing.WITH_SHARING_ID:\n                /* Intentional fall through */\n            case UriType.GeolocSharing.BASE:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/GeolocSharingStateAndReasonCode.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\n\npublic class GeolocSharingStateAndReasonCode {\n\n    private final State mState;\n\n    private final ReasonCode mReasonCode;\n\n    public GeolocSharingStateAndReasonCode(State state, ReasonCode reasonCode) {\n        mState = state;\n        mReasonCode = reasonCode;\n    }\n\n    public State getState() {\n        return mState;\n    }\n\n    public ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/ImageSharingData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\n\nimport android.net.Uri;\n\n/**\n * Image sharing data constants\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ImageSharingData {\n\n    /**\n     * Content provider URI\n     */\n    /* package private */public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.imageshare/imageshare\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = ImageSharingLog.HISTORYLOG_MEMBER_ID;\n\n    /**\n     * Unique history log id\n     */\n    /* package private */static final String KEY_BASECOLUMN_ID = ImageSharingLog.BASECOLUMN_ID;\n\n    /**\n     * Unique sharing identifier\n     */\n    /* package private */static final String KEY_SHARING_ID = ImageSharingLog.SHARING_ID;\n\n    /**\n     * Date of the sharing\n     */\n    /* package private */static final String KEY_TIMESTAMP = ImageSharingLog.TIMESTAMP;\n\n    /**\n     * ContactId formatted number of the remote contact\n     */\n    /* package private */static final String KEY_CONTACT = ImageSharingLog.CONTACT;\n\n    /**\n     * @see ImageSharing.State\n     */\n    /* package private */static final String KEY_STATE = ImageSharingLog.STATE;\n\n    /**\n     * Reason code associated with the image sharing state.\n     * \n     * @see ImageSharing.ReasonCode\n     */\n    /* package private */static final String KEY_REASON_CODE = ImageSharingLog.REASON_CODE;\n\n    /**\n     * Multipurpose Internet Mail Extensions (MIME) type of file\n     */\n    /* package private */static final String KEY_MIME_TYPE = ImageSharingLog.MIME_TYPE;\n\n    /**\n     * URI of the file\n     */\n    /* package private */static final String KEY_FILE = ImageSharingLog.FILE;\n\n    /**\n     * Filename\n     */\n    /* package private */static final String KEY_FILENAME = ImageSharingLog.FILENAME;\n\n    /**\n     * Size transferred in bytes\n     */\n    /* package private */static final String KEY_TRANSFERRED = ImageSharingLog.TRANSFERRED;\n\n    /**\n     * File size in bytes\n     */\n    /* package private */static final String KEY_FILESIZE = ImageSharingLog.FILESIZE;\n\n    /**\n     * Incoming sharing or outgoing sharing.\n     * \n     * @see RcsService.Direction\n     */\n    /* package private */static final String KEY_DIRECTION = ImageSharingLog.DIRECTION;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/ImageSharingDeleteTask.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.image.ImageTransferSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.ImageSharingServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\npublic class ImageSharingDeleteTask extends DeleteTask.GroupedByContactId {\n\n    private static final Logger sLogger = Logger.getLogger(ImageSharingDeleteTask.class.getName());\n\n    private final ImageSharingServiceImpl mImageSharingService;\n\n    private final RichcallService mRichcallService;\n\n    /**\n     * Deletion of all image sharing.\n     * \n     * @param imageSharingService the image service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     */\n    public ImageSharingDeleteTask(ImageSharingServiceImpl imageSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver) {\n        super(contentResolver, ImageSharingData.CONTENT_URI, ImageSharingData.KEY_SHARING_ID,\n                ImageSharingData.KEY_CONTACT, (String) null);\n        mImageSharingService = imageSharingService;\n        mRichcallService = richcallService;\n    }\n\n    /**\n     * Deletion of a specific image sharing.\n     * \n     * @param imageSharingService the image service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     * @param sharingId the sharing id\n     */\n    public ImageSharingDeleteTask(ImageSharingServiceImpl imageSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver, String sharingId) {\n        super(contentResolver, ImageSharingData.CONTENT_URI, ImageSharingData.KEY_SHARING_ID,\n                ImageSharingData.KEY_CONTACT, null, sharingId);\n        mImageSharingService = imageSharingService;\n        mRichcallService = richcallService;\n    }\n\n    /**\n     * Deletion of all image sharing with a specific contact.\n     *\n     * @param imageSharingService the image service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     * @param contact the contact id\n     */\n    public ImageSharingDeleteTask(ImageSharingServiceImpl imageSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver, ContactId contact) {\n        super(contentResolver, ImageSharingData.CONTENT_URI, ImageSharingData.KEY_SHARING_ID,\n                ImageSharingData.KEY_CONTACT, contact);\n        mImageSharingService = imageSharingService;\n        mRichcallService = richcallService;\n    }\n\n    @Override\n    protected void onRowDelete(ContactId contact, String sharingId) throws PayloadException {\n        ImageTransferSession session = mRichcallService.getImageTransferSession(sharingId);\n        if (session == null) {\n            mImageSharingService.ensureFileCopyIsDeletedIfExisting(sharingId);\n            mImageSharingService.removeImageSharing(sharingId);\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mImageSharingService.ensureFileCopyIsDeletedIfExisting(sharingId);\n        mImageSharingService.removeImageSharing(sharingId);\n    }\n\n    @Override\n    protected void onCompleted(ContactId contact, Set<String> deletedIds) {\n        mImageSharingService.broadcastDeleted(contact, deletedIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/ImageSharingPersistedStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * ImageSharingPersistedStorageAccessor helps in retrieving persisted data related to a image share\n * from the persisted storage. It can utilize caching for such data that will not be changed after\n * creation of the Image sharing to speed up consecutive access.\n */\npublic class ImageSharingPersistedStorageAccessor {\n\n    private final String mSharingId;\n\n    private final RichCallHistory mRichCallLog;\n\n    private ContactId mContact;\n\n    private Direction mDirection;\n\n    private String mFileName;\n\n    private Long mFileSize;\n\n    private String mMimeType;\n\n    private Uri mFile;\n\n    private long mTimestamp;\n\n    public ImageSharingPersistedStorageAccessor(String sharingId, RichCallHistory richCallLog) {\n        mSharingId = sharingId;\n        mRichCallLog = richCallLog;\n    }\n\n    public ImageSharingPersistedStorageAccessor(String sharingId, ContactId contact,\n            Direction direction, Uri file, String fileName, String mimeType, long fileSize,\n            RichCallHistory richCallLog, long timestamp) {\n        mSharingId = sharingId;\n        mContact = contact;\n        mDirection = direction;\n        mFile = file;\n        mFileName = fileName;\n        mFileSize = fileSize;\n        mMimeType = mimeType;\n        mRichCallLog = richCallLog;\n        mTimestamp = timestamp;\n    }\n\n    private void cacheData() {\n        Cursor cursor = null;\n        try {\n            cursor = mRichCallLog.getImageTransferData(mSharingId);\n            if (!cursor.moveToNext()) {\n                throw new ServerApiPersistentStorageException(\"Data not found for image sharing \"\n                        + mSharingId);\n            }\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingData.KEY_CONTACT));\n            if (contact != null) {\n                mContact = ContactUtil.createContactIdFromTrustedData(contact);\n            }\n            mDirection = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(ImageSharingData.KEY_DIRECTION)));\n            mFileName = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingData.KEY_FILENAME));\n            mMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingData.KEY_MIME_TYPE));\n            mFileSize = cursor.getLong(cursor.getColumnIndexOrThrow(ImageSharingData.KEY_FILESIZE));\n            mFile = Uri.parse(cursor.getString(cursor\n                    .getColumnIndexOrThrow(ImageSharingData.KEY_FILE)));\n            mTimestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ImageSharingData.KEY_TIMESTAMP));\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    public ContactId getRemoteContact() {\n        /*\n         * Utilizing cache here as contact can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mContact == null) {\n            cacheData();\n        }\n        return mContact;\n    }\n\n    public Uri getFile() {\n        /*\n         * Utilizing cache here as file can't be changed in persistent storage after entry insertion\n         * anyway so no need to query for it multiple times.\n         */\n        if (mFile == null) {\n            cacheData();\n        }\n        return mFile;\n    }\n\n    public String getFileName() {\n        /*\n         * Utilizing cache here as file name can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mFileName == null) {\n            cacheData();\n        }\n        return mFileName;\n    }\n\n    public long getFileSize() {\n        /*\n         * Utilizing cache here as file size can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mFileSize == null) {\n            cacheData();\n        }\n        return mFileSize;\n    }\n\n    public String getMimeType() {\n        /*\n         * Utilizing cache here as mime type can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mMimeType == null) {\n            cacheData();\n        }\n        return mMimeType;\n    }\n\n    public State getState() {\n        State state = mRichCallLog.getImageSharingState(mSharingId);\n        if (state == null) {\n            throw new ServerApiPersistentStorageException(\"State not found for image sharing \"\n                    + mSharingId);\n        }\n        return state;\n    }\n\n    public ReasonCode getReasonCode() {\n        ReasonCode reasonCode = mRichCallLog.getImageSharingReasonCode(mSharingId);\n        if (reasonCode == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Reason code not found for image sharing \" + mSharingId);\n        }\n        return reasonCode;\n    }\n\n    public Direction getDirection() {\n        /*\n         * Utilizing cache here as direction can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mDirection == null) {\n            cacheData();\n        }\n        return mDirection;\n    }\n\n    public long getTimestamp() {\n        /*\n         * Utilizing cache here as timestamp can't be changed in persistent storage after it has\n         * been set to some value bigger than zero, so no need to query for it multiple times.\n         */\n        if (mTimestamp == 0) {\n            cacheData();\n        }\n        return mTimestamp;\n    }\n\n    public boolean setStateAndReasonCode(State state, ReasonCode reasonCode) {\n        return mRichCallLog.setImageSharingStateAndReasonCode(mSharingId, state, reasonCode);\n    }\n\n    public boolean setProgress(long currentSize) {\n        return mRichCallLog.setImageSharingProgress(mSharingId, currentSize);\n    }\n\n    public Uri addImageSharing(ContactId contact, Direction direction, MmContent content,\n            State state, ReasonCode reasonCode, long timestamp) {\n        mContact = contact;\n        mDirection = direction;\n        mTimestamp = timestamp;\n        return mRichCallLog.addImageSharing(mSharingId, contact, direction, content, state,\n                reasonCode, timestamp);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/ImageSharingProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.history.HistoryMemberBaseIdCreator;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\n/**\n * Image sharing provider\n * \n * @author Jean-Marc AUFFRET\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class ImageSharingProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String SELECTION_WITH_SHARING_ID_ONLY = ImageSharingData.KEY_SHARING_ID\n            .concat(\"=?\");\n\n    private static final UriMatcher sUriMatcher;\n    static {\n        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n        sUriMatcher.addURI(ImageSharingData.CONTENT_URI.getAuthority(),\n                ImageSharingData.CONTENT_URI.getPath().substring(1),\n                UriType.InternalImageSharing.IMAGE_SHARING);\n        sUriMatcher.addURI(ImageSharingData.CONTENT_URI.getAuthority(),\n                ImageSharingData.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.InternalImageSharing.IMAGE_SHARING_WITH_ID);\n        sUriMatcher.addURI(ImageSharingLog.CONTENT_URI.getAuthority(), ImageSharingLog.CONTENT_URI\n                .getPath().substring(1), UriType.ImageSharing.IMAGE_SHARING);\n        sUriMatcher.addURI(ImageSharingLog.CONTENT_URI.getAuthority(), ImageSharingLog.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.ImageSharing.IMAGE_SHARING_WITH_ID);\n    }\n\n    /**\n     * Table name\n     */\n    public static final String TABLE = \"imageshare\";\n\n    /**\n     * Database name\n     */\n    public static final String DATABASE_NAME = \"imageshare.db\";\n\n    private static final class UriType {\n\n        private static final class ImageSharing {\n            private static final int IMAGE_SHARING = 1;\n\n            private static final int IMAGE_SHARING_WITH_ID = 2;\n        }\n\n        private static final class InternalImageSharing {\n            private static final int IMAGE_SHARING = 3;\n\n            private static final int IMAGE_SHARING_WITH_ID = 4;\n        }\n    }\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/imageshare\";\n\n        private static final String TYPE_ITEM = \"vnd.android.cursor.item/imageshare\";\n    }\n\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 6;\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE + '('\n                    + ImageSharingData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + ImageSharingData.KEY_SHARING_ID + \" TEXT NOT NULL PRIMARY KEY,\"\n                    + ImageSharingData.KEY_CONTACT + \" TEXT NOT NULL,\" \n                    + ImageSharingData.KEY_FILE + \" TEXT NOT NULL,\" \n                    + ImageSharingData.KEY_FILENAME + \" TEXT NOT NULL,\"\n                    + ImageSharingData.KEY_MIME_TYPE + \" TEXT NOT NULL,\"\n                    + ImageSharingData.KEY_STATE + \" INTEGER NOT NULL,\"\n                    + ImageSharingData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + ImageSharingData.KEY_DIRECTION + \" INTEGER NOT NULL,\"\n                    + ImageSharingData.KEY_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + ImageSharingData.KEY_TRANSFERRED + \" INTEGER NOT NULL,\"\n                    + ImageSharingData.KEY_FILESIZE + \" INTEGER NOT NULL)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + ImageSharingData.KEY_BASECOLUMN_ID + \"_idx\" + \" ON \"\n                    + TABLE + '(' + ImageSharingData.KEY_BASECOLUMN_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + ImageSharingData.KEY_CONTACT + \"_idx\" + \" ON \" + TABLE\n                    + '(' + ImageSharingData.KEY_CONTACT + ')');\n            db.execSQL(\"CREATE INDEX \" + ImageSharingData.KEY_TIMESTAMP + \"_idx\" + \" ON \" + TABLE\n                    + '(' + ImageSharingData.KEY_TIMESTAMP + ')');\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE));\n            onCreate(db);\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithSharingId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_SHARING_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_SHARING_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithSharingId(String[] selectionArgs, String sharingId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(sharingId, selectionArgs);\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalImageSharing.IMAGE_SHARING:\n                /* Intentional fall through */\n            case UriType.ImageSharing.IMAGE_SHARING:\n                return CursorType.TYPE_DIRECTORY;\n\n            case UriType.InternalImageSharing.IMAGE_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.ImageSharing.IMAGE_SHARING_WITH_ID:\n                return CursorType.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalImageSharing.IMAGE_SHARING_WITH_ID:\n                    String sharingId = uri.getLastPathSegment();\n                    selection = getSelectionWithSharingId(selection);\n                    selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(ImageSharingLog.CONTENT_URI, sharingId));\n                    return cursor;\n\n                case UriType.InternalImageSharing.IMAGE_SHARING:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            ImageSharingLog.CONTENT_URI);\n                    return cursor;\n\n                case UriType.ImageSharing.IMAGE_SHARING_WITH_ID:\n                    sharingId = uri.getLastPathSegment();\n                    selection = getSelectionWithSharingId(selection);\n                    selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.ImageSharing.IMAGE_SHARING:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n        }\n        /*\n         * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n         * exception.\n         */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        Uri notificationUri = ImageSharingLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalImageSharing.IMAGE_SHARING_WITH_ID:\n                String sharingId = uri.getLastPathSegment();\n                selection = getSelectionWithSharingId(selection);\n                selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                notificationUri = Uri.withAppendedPath(notificationUri, sharingId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalImageSharing.IMAGE_SHARING:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.ImageSharing.IMAGE_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.ImageSharing.IMAGE_SHARING:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalImageSharing.IMAGE_SHARING:\n                /* Intentional fall through */\n            case UriType.InternalImageSharing.IMAGE_SHARING_WITH_ID:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String sharingId = initialValues.getAsString(ImageSharingData.KEY_SHARING_ID);\n                initialValues.put(ImageSharingData.KEY_BASECOLUMN_ID, HistoryMemberBaseIdCreator\n                        .createUniqueId(getContext(), ImageSharingData.HISTORYLOG_MEMBER_ID));\n                if (db.insert(TABLE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri.toString() + '!');\n                }\n                Uri notificationUri = Uri.withAppendedPath(ImageSharingLog.CONTENT_URI, sharingId);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.ImageSharing.IMAGE_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.ImageSharing.IMAGE_SHARING:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        Uri notificationUri = ImageSharingLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalImageSharing.IMAGE_SHARING_WITH_ID:\n                String sharingId = uri.getLastPathSegment();\n                selection = getSelectionWithSharingId(selection);\n                selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                notificationUri = Uri.withAppendedPath(notificationUri, sharingId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalImageSharing.IMAGE_SHARING:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.ImageSharing.IMAGE_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.ImageSharing.IMAGE_SHARING:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/ImageSharingStateAndReasonCode.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\npublic class ImageSharingStateAndReasonCode {\n\n    private final State mState;\n\n    private final ReasonCode mReasonCode;\n\n    public ImageSharingStateAndReasonCode(State state, ReasonCode reasonCode) {\n        mState = state;\n        mReasonCode = reasonCode;\n    }\n\n    public State getState() {\n        return mState;\n    }\n\n    public ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/RichCallHistory.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.content.VideoContent;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * Rich call history\n *\n * @author Jean-Marc AUFFRET\n */\npublic class RichCallHistory {\n    /**\n     * Current instance\n     */\n    private static volatile RichCallHistory sInstance;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    /**\n     * The logger\n     */\n    private final static Logger logger = Logger.getLogger(RichCallHistory.class.getSimpleName());\n\n    private static final int FIRST_COLUMN_IDX = 0;\n\n    private static final String SELECTION_BY_INTERRUPTED_GEOLOC_SHARINGS = GeolocSharingData.KEY_STATE\n            + \" IN ('\"\n            + GeolocSharing.State.STARTED.toInt()\n            + \"','\"\n            + GeolocSharing.State.INVITED.toInt()\n            + \"','\"\n            + GeolocSharing.State.ACCEPTING.toInt()\n            + \"','\" + GeolocSharing.State.INITIATING.toInt() + \"')\";\n\n    private static final String SELECTION_BY_INTERRUPTED_IMAGE_SHARINGS = ImageSharingData.KEY_STATE\n            + \" IN ('\"\n            + ImageSharing.State.STARTED.toInt()\n            + \"','\"\n            + ImageSharing.State.INVITED.toInt()\n            + \"','\"\n            + ImageSharing.State.ACCEPTING.toInt()\n            + \"','\" + ImageSharing.State.INITIATING.toInt() + \"')\";\n\n    private static final String SELECTION_BY_INTERRUPTED_VIDEO_SHARINGS = VideoSharingData.KEY_STATE\n            + \" IN ('\"\n            + VideoSharing.State.STARTED.toInt()\n            + \"','\"\n            + VideoSharing.State.INVITED.toInt()\n            + \"','\"\n            + VideoSharing.State.ACCEPTING.toInt()\n            + \"','\" + VideoSharing.State.INITIATING.toInt() + \"')\";\n\n    private static final String ORDER_BY_TIMESTAMP_ASC = GeolocSharingData.KEY_TIMESTAMP\n            .concat(\" ASC\");\n\n    /**\n     * Get image transfer info from its unique Id\n     *\n     * @param columnName the column name\n     * @param sharingId the sharing ID\n     * @return Cursor the caller of this method has to close the cursor if a cursor is returned\n     */\n    private Cursor getImageTransferData(String columnName, String sharingId) {\n        String[] projection = new String[] {\n            columnName\n        };\n        Uri contentUri = Uri.withAppendedPath(ImageSharingData.CONTENT_URI, sharingId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, projection, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        if (!cursor.moveToNext()) {\n            CursorUtil.close(cursor);\n            return null;\n        }\n        return cursor;\n    }\n\n    /**\n     * Get video sharing info from its unique Id\n     *\n     * @param columnName the column name\n     * @param sharingId the sharing ID\n     * @return Cursor the caller of this method has to close the cursor if a cursor is returned\n     */\n    private Cursor getVideoSharingData(String columnName, String sharingId) {\n        String[] projection = new String[] {\n            columnName\n        };\n        Uri contentUri = Uri.withAppendedPath(VideoSharingData.CONTENT_URI, sharingId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, projection, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        if (!cursor.moveToNext()) {\n            CursorUtil.close(cursor);\n            return null;\n        }\n        return cursor;\n    }\n\n    /**\n     * Get geoloc sharing data\n     *\n     * @param columnName Column name\n     * @param sharingId Sharing ID\n     * @return Cursor\n     */\n    private Cursor getGeolocSharingData(String columnName, String sharingId) {\n        String[] projection = new String[] {\n            columnName\n        };\n        Uri contentUri = Uri.withAppendedPath(GeolocSharingData.CONTENT_URI, sharingId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, projection, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        if (!cursor.moveToNext()) {\n            CursorUtil.close(cursor);\n            return null;\n        }\n        return cursor;\n    }\n\n    private Integer getDataAsInteger(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getInt(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private Long getDataAsLong(Cursor cursor) {\n        try {\n            if (cursor.isNull(FIRST_COLUMN_IDX)) {\n                return null;\n            }\n            return cursor.getLong(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    private String getDataAsString(Cursor cursor) {\n        try {\n            return cursor.getString(FIRST_COLUMN_IDX);\n\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Get or Create Singleton instance of RichCallHistory\n     *\n     * @param localContentResolver Local content resolver\n     */\n    public static RichCallHistory getInstance(LocalContentResolver localContentResolver) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (RichCallHistory.class) {\n            if (sInstance == null) {\n                sInstance = new RichCallHistory(localContentResolver);\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Returns instance\n     *\n     * @return Instance\n     */\n    public static RichCallHistory getInstance() {\n        synchronized (RichCallHistory.class) {\n            return sInstance;\n        }\n    }\n\n    /**\n     * Constructor\n     *\n     * @param localContentResolver Local content resolver\n     */\n    private RichCallHistory(LocalContentResolver localContentResolver) {\n        super();\n        mLocalContentResolver = localContentResolver;\n    }\n\n    /**\n     * Read the total size of transferred image\n     *\n     * @param sharingId the sharing ID\n     * @return the total size\n     */\n    private Long getImageSharingTotalSize(String sharingId) {\n        Cursor cursor = getImageTransferData(ImageSharingData.KEY_FILESIZE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    /*--------------------- Video sharing update/add methods ----------------------*/\n\n    /**\n     * Add a new video sharing in the call history\n     *\n     * @param sharingId Session ID\n     * @param contact Remote contact ID\n     * @param direction Call event direction\n     * @param content Shared content\n     * @param state Call state\n     * @param reasonCode Reason Code\n     * @param timestamp Local timestamp for both incoming and outgoing video sharing\n     * @return image URI\n     */\n    public Uri addVideoSharing(String sharingId, ContactId contact, Direction direction,\n            VideoContent content, VideoSharing.State state, VideoSharing.ReasonCode reasonCode,\n            long timestamp) {\n        if (logger.isActivated()) {\n            logger.debug(\"Add new video sharing for contact \" + contact + \": sharingId=\"\n                    + sharingId + \", state=\" + state + \", reasonCode=\" + reasonCode);\n        }\n\n        ContentValues values = new ContentValues();\n        values.put(VideoSharingData.KEY_SHARING_ID, sharingId);\n        values.put(VideoSharingData.KEY_CONTACT, contact.toString());\n        values.put(VideoSharingData.KEY_DIRECTION, direction.toInt());\n        values.put(VideoSharingData.KEY_STATE, state.toInt());\n        values.put(VideoSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(VideoSharingData.KEY_TIMESTAMP, timestamp);\n        values.put(VideoSharingData.KEY_DURATION, 0);\n        values.put(VideoSharingData.KEY_VIDEO_ENCODING, content.getEncoding());\n        values.put(VideoSharingData.KEY_WIDTH, content.getWidth());\n        values.put(VideoSharingData.KEY_HEIGHT, content.getHeight());\n        return mLocalContentResolver.insert(VideoSharingData.CONTENT_URI, values);\n    }\n\n    /**\n     * Set the video sharing state, reason code and duration\n     *\n     * @param sharingId sharing ID of the entry\n     * @param state New state\n     * @param reasonCode Reason Code\n     * @param duration Duration\n     * @return true if updated\n     */\n    public boolean setVideoSharingStateReasonCodeAndDuration(String sharingId,\n            VideoSharing.State state, VideoSharing.ReasonCode reasonCode, long duration) {\n        if (logger.isActivated()) {\n            logger.debug(\"Update video sharing state of sharing \" + sharingId + \" state=\" + state\n                    + \", reasonCode=\" + reasonCode + \" duration=\" + duration);\n        }\n        ContentValues values = new ContentValues();\n        values.put(VideoSharingData.KEY_STATE, state.toInt());\n        values.put(VideoSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        if (duration > 0) {\n            values.put(VideoSharingData.KEY_DURATION, duration);\n        }\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(VideoSharingData.CONTENT_URI, sharingId), values, null, null) > 0;\n    }\n\n    /**\n     * Set the video sharing state, reason code\n     *\n     * @param sharingId sharing ID of the entry\n     * @param state New state\n     * @param reasonCode Reason Code\n     * @return true if updated\n     */\n    public boolean setVideoSharingStateReasonCode(String sharingId, VideoSharing.State state,\n            VideoSharing.ReasonCode reasonCode) {\n        if (logger.isActivated()) {\n            logger.debug(\"Update video sharing state of sharing \" + sharingId + \" state=\" + state\n                    + \", reasonCode=\" + reasonCode);\n        }\n        ContentValues values = new ContentValues();\n        values.put(VideoSharingData.KEY_STATE, state.toInt());\n        values.put(VideoSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(VideoSharingData.CONTENT_URI, sharingId), values, null, null) > 0;\n    }\n\n    /*--------------------- Image sharing update / add methods ----------------------*/\n\n    /**\n     * Add a new image sharing in the call history\n     *\n     * @param sharingId Session ID\n     * @param contact Remote contact ID\n     * @param direction Call event direction\n     * @param content Shared content\n     * @param state Call state\n     * @param reasonCode Reason Code\n     * @param timestamp Local timestamp for both incoming and outgoing image sharing\n     * @return uri\n     */\n    public Uri addImageSharing(String sharingId, ContactId contact, Direction direction,\n            MmContent content, ImageSharing.State state, ImageSharing.ReasonCode reasonCode,\n            long timestamp) {\n        if (logger.isActivated()) {\n            logger.debug(\"Add new image sharing for contact \" + contact + \": sharing =\" + sharingId\n                    + \", state=\" + state);\n        }\n\n        ContentValues values = new ContentValues();\n        values.put(ImageSharingData.KEY_SHARING_ID, sharingId);\n        values.put(ImageSharingData.KEY_CONTACT, contact.toString());\n        values.put(ImageSharingData.KEY_DIRECTION, direction.toInt());\n        values.put(ImageSharingData.KEY_FILE, content.getUri().toString());\n        values.put(ImageSharingData.KEY_FILENAME, content.getName());\n        values.put(ImageSharingData.KEY_MIME_TYPE, content.getEncoding());\n        values.put(ImageSharingData.KEY_TRANSFERRED, 0);\n        values.put(ImageSharingData.KEY_FILESIZE, content.getSize());\n        values.put(ImageSharingData.KEY_STATE, state.toInt());\n        values.put(ImageSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(ImageSharingData.KEY_TIMESTAMP, timestamp);\n        return mLocalContentResolver.insert(ImageSharingData.CONTENT_URI, values);\n    }\n\n    /**\n     * Set the image sharing state and reason code\n     *\n     * @param sharingId the sharing ID\n     * @param state New state\n     * @param reasonCode Reason Code\n     * @return true if updated\n     */\n    public boolean setImageSharingStateAndReasonCode(String sharingId, ImageSharing.State state,\n            ImageSharing.ReasonCode reasonCode) {\n        if (logger.isActivated()) {\n            logger.debug(\"Update status of image sharing \" + sharingId + \" to \" + state);\n        }\n        ContentValues values = new ContentValues();\n        values.put(ImageSharingData.KEY_STATE, state.toInt());\n        values.put(ImageSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        if (state == ImageSharing.State.TRANSFERRED) {\n            // Update the size of bytes if fully transferred\n            Long total = getImageSharingTotalSize(sharingId);\n            if (total != null && total != 0) {\n                values.put(ImageSharingData.KEY_TRANSFERRED, total);\n            }\n        }\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(ImageSharingData.CONTENT_URI, sharingId), values, null, null) > 0;\n    }\n\n    /**\n     * Update the image sharing progress\n     *\n     * @param sharingId Session ID of the entry\n     * @param currentSize Current size\n     * @return true if updated\n     */\n    public boolean setImageSharingProgress(String sharingId, long currentSize) {\n        ContentValues values = new ContentValues();\n        values.put(ImageSharingData.KEY_TRANSFERRED, currentSize);\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(ImageSharingData.CONTENT_URI, sharingId), values, null, null) > 0;\n    }\n\n    /*--------------------- Geoloc sharing update / add methods ----------------------*/\n\n    /**\n     * Add an incoming geoloc sharing\n     *\n     * @param contact Remote contact ID\n     * @param sharingId Sharing ID\n     * @param state Geoloc sharing state\n     * @param reasonCode Reason code of the state\n     * @param timestamp Local timestamp for incoming geoloc sharing\n     * @return Uri\n     */\n    public Uri addIncomingGeolocSharing(ContactId contact, String sharingId,\n            GeolocSharing.State state, GeolocSharing.ReasonCode reasonCode, long timestamp) {\n        ContentValues values = new ContentValues();\n        values.put(GeolocSharingData.KEY_SHARING_ID, sharingId);\n        values.put(GeolocSharingData.KEY_CONTACT, contact.toString());\n        values.put(GeolocSharingData.KEY_MIME_TYPE, MimeType.GEOLOC_MESSAGE);\n        values.put(GeolocSharingData.KEY_DIRECTION, Direction.INCOMING.toInt());\n        values.put(GeolocSharingData.KEY_STATE, state.toInt());\n        values.put(GeolocSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(GeolocSharingData.KEY_TIMESTAMP, timestamp);\n        return mLocalContentResolver.insert(GeolocSharingData.CONTENT_URI, values);\n    }\n\n    /**\n     * Add an outgoing geoloc sharing\n     *\n     * @param contact Remote contact ID\n     * @param sharingId Sharing ID\n     * @param geoloc Geolocation\n     * @param state Geoloc sharing state\n     * @param reasonCode Reason code of the state\n     * @param timestamp Local timestamp for outgoing geoloc sharing\n     * @return Uri\n     */\n    public Uri addOutgoingGeolocSharing(ContactId contact, String sharingId, Geoloc geoloc,\n            GeolocSharing.State state, GeolocSharing.ReasonCode reasonCode, long timestamp) {\n        ContentValues values = new ContentValues();\n        values.put(GeolocSharingData.KEY_SHARING_ID, sharingId);\n        values.put(GeolocSharingData.KEY_CONTACT, contact.toString());\n        values.put(GeolocSharingData.KEY_MIME_TYPE, MimeType.GEOLOC_MESSAGE);\n        values.put(GeolocSharingData.KEY_CONTENT, geoloc.toString());\n        values.put(GeolocSharingData.KEY_DIRECTION, Direction.OUTGOING.toInt());\n        values.put(GeolocSharingData.KEY_STATE, state.toInt());\n        values.put(GeolocSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        values.put(GeolocSharingData.KEY_TIMESTAMP, timestamp);\n        return mLocalContentResolver.insert(GeolocSharingData.CONTENT_URI, values);\n    }\n\n    /**\n     * Sets the data of a geoloc sharing and updates state to transferred\n     *\n     * @param sharingId Sharing ID\n     * @param geoloc Geolococation\n     * @return true if updated\n     */\n    public boolean setGeolocSharingTransferred(String sharingId, Geoloc geoloc) {\n        ContentValues values = new ContentValues();\n        values.put(GeolocSharingData.KEY_CONTENT, geoloc.toString());\n        values.put(GeolocSharingData.KEY_STATE, GeolocSharing.State.TRANSFERRED.toInt());\n        values.put(GeolocSharingData.KEY_REASON_CODE, GeolocSharing.ReasonCode.UNSPECIFIED.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GeolocSharingData.CONTENT_URI, sharingId), values, null, null) > 0;\n    }\n\n    /**\n     * Update the geoloc sharing state and reason code\n     *\n     * @param sharingId Sharing ID\n     * @param state Geoloc sharing state\n     * @param reasonCode Reason code of the state\n     * @return true if updated\n     */\n    public boolean setGeolocSharingStateAndReasonCode(String sharingId, GeolocSharing.State state,\n            GeolocSharing.ReasonCode reasonCode) {\n        ContentValues values = new ContentValues();\n        values.put(GeolocSharingData.KEY_STATE, state.toInt());\n        values.put(GeolocSharingData.KEY_REASON_CODE, reasonCode.toInt());\n        return mLocalContentResolver.update(\n                Uri.withAppendedPath(GeolocSharingData.CONTENT_URI, sharingId), values, null, null) > 0;\n    }\n\n    /**\n     * Get the geoloc sharing state\n     *\n     * @param sharingId Sharing ID\n     * @return state\n     */\n    public GeolocSharing.State getGeolocSharingState(String sharingId) {\n        Cursor cursor = getGeolocSharingData(GeolocSharingData.KEY_STATE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return GeolocSharing.State.valueOf(getDataAsInteger(cursor));\n    }\n\n    /**\n     * Get the geoloc sharing reason code\n     *\n     * @param sharingId Sharing ID\n     * @return reason code\n     */\n    public GeolocSharing.ReasonCode getGeolocSharingReasonCode(String sharingId) {\n        Cursor cursor = getGeolocSharingData(GeolocSharingData.KEY_REASON_CODE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return GeolocSharing.ReasonCode.valueOf(getDataAsInteger(cursor));\n    }\n\n    public Cursor getInterruptedGeolocSharings() {\n        Cursor cursor = mLocalContentResolver.query(GeolocSharingData.CONTENT_URI, null,\n                SELECTION_BY_INTERRUPTED_GEOLOC_SHARINGS, null, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, GeolocSharingData.CONTENT_URI);\n        return cursor;\n    }\n\n    public Cursor getInterruptedImageSharings() {\n        Cursor cursor = mLocalContentResolver.query(ImageSharingData.CONTENT_URI, null,\n                SELECTION_BY_INTERRUPTED_IMAGE_SHARINGS, null, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, GeolocSharingData.CONTENT_URI);\n        return cursor;\n    }\n\n    public Cursor getInterruptedVideoSharings() {\n        Cursor cursor = mLocalContentResolver.query(VideoSharingData.CONTENT_URI, null,\n                SELECTION_BY_INTERRUPTED_VIDEO_SHARINGS, null, ORDER_BY_TIMESTAMP_ASC);\n        CursorUtil.assertCursorIsNotNull(cursor, GeolocSharingData.CONTENT_URI);\n        return cursor;\n    }\n\n    /**\n     * Delete all entries in Rich Call history\n     */\n    public void deleteAllEntries() {\n        mLocalContentResolver.delete(ImageSharingData.CONTENT_URI, null, null);\n        mLocalContentResolver.delete(VideoSharingData.CONTENT_URI, null, null);\n        mLocalContentResolver.delete(GeolocSharingData.CONTENT_URI, null, null);\n    }\n\n    /**\n     * Get Image sharing state from unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return State\n     */\n    public ImageSharing.State getImageSharingState(String sharingId) {\n        Cursor cursor = getImageTransferData(ImageSharingData.KEY_STATE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return ImageSharing.State.valueOf(getDataAsInteger(cursor));\n    }\n\n    /**\n     * Get Image sharing reason code from unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return Reason code\n     */\n    public ImageSharing.ReasonCode getImageSharingReasonCode(String sharingId) {\n        Cursor cursor = getImageTransferData(ImageSharingData.KEY_REASON_CODE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return ImageSharing.ReasonCode.valueOf(getDataAsInteger(cursor));\n    }\n\n    /**\n     * Get Video sharing state from unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return State\n     */\n    public VideoSharing.State getVideoSharingState(String sharingId) {\n        Cursor cursor = getVideoSharingData(VideoSharingData.KEY_STATE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return VideoSharing.State.valueOf(getDataAsInteger(cursor));\n    }\n\n    /**\n     * Get Video sharing reason code from unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return Reason code\n     */\n    public VideoSharing.ReasonCode getVideoSharingReasonCode(String sharingId) {\n        Cursor cursor = getVideoSharingData(VideoSharingData.KEY_REASON_CODE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return VideoSharing.ReasonCode.valueOf(getDataAsInteger(cursor));\n    }\n\n    /**\n     * Returns video sharing duration\n     *\n     * @param sharingId the sharing ID\n     * @return duration\n     */\n    public Long getVideoSharingDuration(String sharingId) {\n        Cursor cursor = getVideoSharingData(VideoSharingData.KEY_DURATION, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return getDataAsLong(cursor);\n    }\n\n    /**\n     * Get geolocation sharing info from its unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return Cursor the caller of this method has to close the cursor if a cursor is returned\n     */\n    public Cursor getGeolocSharingData(String sharingId) {\n        Uri contentUri = Uri.withAppendedPath(GeolocSharingData.CONTENT_URI, sharingId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        return cursor;\n    }\n\n    /**\n     * Get image transfer info from its unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return Cursor the caller of this method has to close the cursor if a cursor is returned\n     */\n    public Cursor getImageTransferData(String sharingId) {\n        Uri contentUri = Uri.withAppendedPath(ImageSharingData.CONTENT_URI, sharingId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        return cursor;\n    }\n\n    /**\n     * Get video sharing info from its unique Id\n     *\n     * @param sharingId the sharing ID\n     * @return Cursor the caller of this method has to close the cursor if a cursor is returned\n     */\n    public Cursor getVideoSharingData(String sharingId) {\n        Uri contentUri = Uri.withAppendedPath(VideoSharingData.CONTENT_URI, sharingId);\n        Cursor cursor = mLocalContentResolver.query(contentUri, null, null, null, null);\n        CursorUtil.assertCursorIsNotNull(cursor, contentUri);\n        return cursor;\n    }\n\n    /**\n     * @param sharingId the sharing ID\n     * @return Cursor direction (INCOMING, ...)\n     */\n    public Direction getImageSharingDirection(String sharingId) {\n        Cursor cursor = getImageTransferData(ImageSharingData.KEY_DIRECTION, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return Direction.valueOf(getDataAsInteger(cursor));\n    }\n\n    /**\n     * @param sharingId the sharing ID\n     * @return uri of file\n     */\n    public Uri getFile(String sharingId) {\n        Cursor cursor = getImageTransferData(ImageSharingData.KEY_FILE, sharingId);\n        if (cursor == null) {\n            return null;\n        }\n        return Uri.parse(getDataAsString(cursor));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/UpdateGeolocSharingStateAfterUngracefulTerminationTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.GeolocSharingServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\n\nimport android.database.Cursor;\n\n/* Update the state of ungracefully terminated Geoloc sharing service object from\n * STARTED, INVITED and INITIATING to FAILED after rebooted. The reason of\n * ungracefully terminated could be sudden stack termination or battery drained,\n * which leads to wrong state in the database.\n * \n * This class is used for error correction purpose, if no error was detected in\n * the database, means graceful termination is executed, so no update process will\n * be done.*/\n\npublic class UpdateGeolocSharingStateAfterUngracefulTerminationTask implements Runnable {\n\n    private final RichCallHistory mRichCallHistory;\n\n    private final GeolocSharingServiceImpl mGeolocService;\n\n    private static final Logger sLogger = Logger\n            .getLogger(UpdateGeolocSharingStateAfterUngracefulTerminationTask.class.getName());\n\n    public UpdateGeolocSharingStateAfterUngracefulTerminationTask(RichCallHistory rcHistory,\n            GeolocSharingServiceImpl geolocService) {\n        mRichCallHistory = rcHistory;\n        mGeolocService = geolocService;\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"initiating.\");\n        }\n        Cursor cursor = null;\n        try {\n            cursor = mRichCallHistory.getInterruptedGeolocSharings();\n            int sharingIdx = cursor.getColumnIndexOrThrow(GeolocSharingData.KEY_SHARING_ID);\n            int contactIdx = cursor.getColumnIndexOrThrow(GeolocSharingData.KEY_CONTACT);\n            int stateIdx = cursor.getColumnIndexOrThrow(GeolocSharingData.KEY_STATE);\n            while (cursor.moveToNext()) {\n                String sharingId = cursor.getString(sharingIdx);\n                String contactNumber = cursor.getString(contactIdx);\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(contactNumber);\n                State state = State.valueOf(cursor.getInt(stateIdx));\n                switch (state) {\n                    case STARTED:\n                        mGeolocService.setGeolocSharingStateAndReasonCode(contact, sharingId,\n                                State.FAILED, ReasonCode.FAILED_SHARING);\n                        break;\n                    case ACCEPTING:\n                        mGeolocService.setGeolocSharingStateAndReasonCode(contact, sharingId,\n                                State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                        break;\n                    case INITIATING:\n                        mGeolocService.setGeolocSharingStateAndReasonCode(contact, sharingId,\n                                State.FAILED, ReasonCode.FAILED_INITIATION);\n                        break;\n                    case INVITED:\n                        mGeolocService.setGeolocSharingStateAndReasonCode(contact, sharingId,\n                                State.REJECTED, ReasonCode.REJECTED_BY_SYSTEM);\n                        break;\n                    default:\n                        sLogger.error(getClass().getName() + \" unexpected state (\" + state\n                                + \") detected! Error in SQL statement?\");\n                        break;\n                }\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    \"Exception occured while trying to update geoloc sharing state for interrupted geoloc sharing\",\n                    e);\n        } finally {\n            CursorUtil.close(cursor);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"done.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/UpdateImageSharingStateAfterUngracefulTerminationTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ImageSharingServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport android.database.Cursor;\n\n/* Update the state of ungracefully terminated Image sharing service object from\n * STARTED, INVITED and INITIATING to FAILED after rebooted. The reason of\n * ungracefully terminated could be sudden stack termination or battery drained,\n * which leads to wrong state in the database.\n * \n * This class is used for error correction purpose, if no error was detected in\n * the database, means graceful termination is executed, so no update process will\n * be done.*/\n\npublic class UpdateImageSharingStateAfterUngracefulTerminationTask implements Runnable {\n\n    private final RichCallHistory mRichCallHistory;\n\n    private final ImageSharingServiceImpl mImageService;\n\n    private static final Logger sLogger = Logger\n            .getLogger(UpdateImageSharingStateAfterUngracefulTerminationTask.class.getName());\n\n    public UpdateImageSharingStateAfterUngracefulTerminationTask(RichCallHistory rcHistory,\n            ImageSharingServiceImpl imageService) {\n        mRichCallHistory = rcHistory;\n        mImageService = imageService;\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"initiating.\");\n        }\n        Cursor cursor = null;\n        try {\n            cursor = mRichCallHistory.getInterruptedImageSharings();\n            int sharingIdx = cursor.getColumnIndexOrThrow(ImageSharingData.KEY_SHARING_ID);\n            int contactIdx = cursor.getColumnIndexOrThrow(ImageSharingData.KEY_CONTACT);\n            int stateIdx = cursor.getColumnIndexOrThrow(ImageSharingData.KEY_STATE);\n            while (cursor.moveToNext()) {\n                String sharingId = cursor.getString(sharingIdx);\n                String contactNumber = cursor.getString(contactIdx);\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(contactNumber);\n                State state = State.valueOf(cursor.getInt(stateIdx));\n                switch (state) {\n                    case STARTED:\n                        mImageService.setImageSharingStateAndReasonCode(contact, sharingId,\n                                State.FAILED, ReasonCode.FAILED_SHARING);\n                        break;\n                    case ACCEPTING:\n                        mImageService.setImageSharingStateAndReasonCode(contact, sharingId,\n                                State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                        break;\n                    case INITIATING:\n                        mImageService.setImageSharingStateAndReasonCode(contact, sharingId,\n                                State.FAILED, ReasonCode.FAILED_INITIATION);\n                        break;\n                    case INVITED:\n                        mImageService.setImageSharingStateAndReasonCode(contact, sharingId,\n                                State.REJECTED, ReasonCode.REJECTED_BY_SYSTEM);\n                        break;\n                    default:\n                        sLogger.error(getClass().getName() + \" unexpected state (\" + state\n                                + \") detected! Error in SQL statement?\");\n                        break;\n                }\n            }\n\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    \"Exception occured while trying to update image sharing state for interrupted geoloc sharing\",\n                    e);\n        } finally {\n            CursorUtil.close(cursor);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"done\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/UpdateVideoSharingStateAfterUngracefulTerminationTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.VideoSharingServiceImpl;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport android.database.Cursor;\n\n/* Update the state of ungracefully terminated Video sharing service object from\n * STARTED, INVITED and INITIATING to FAILED after rebooted. The reason of\n * ungracefully terminated could be sudden stack termination or battery drained,\n * which leads to wrong state in the database.\n * \n * This class is used for error correction purpose, if no error was detected in\n * the database, means graceful termination is executed, so no update process will\n * be done.*/\n\npublic class UpdateVideoSharingStateAfterUngracefulTerminationTask implements Runnable {\n\n    private final RichCallHistory mRichCallHistory;\n\n    private final VideoSharingServiceImpl mVideoService;\n\n    private static final Logger sLogger = Logger\n            .getLogger(UpdateVideoSharingStateAfterUngracefulTerminationTask.class.getName());\n\n    public UpdateVideoSharingStateAfterUngracefulTerminationTask(RichCallHistory rcHistory,\n            VideoSharingServiceImpl videoService) {\n        mRichCallHistory = rcHistory;\n        mVideoService = videoService;\n    }\n\n    @Override\n    public void run() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"initiating.\");\n        }\n        Cursor cursor = null;\n        try {\n            cursor = mRichCallHistory.getInterruptedVideoSharings();\n            int sharingIdx = cursor.getColumnIndexOrThrow(VideoSharingData.KEY_SHARING_ID);\n            int contactIdx = cursor.getColumnIndexOrThrow(VideoSharingData.KEY_CONTACT);\n            int stateIdx = cursor.getColumnIndexOrThrow(VideoSharingData.KEY_STATE);\n            while (cursor.moveToNext()) {\n                String sharingId = cursor.getString(sharingIdx);\n                String contactNumber = cursor.getString(contactIdx);\n                ContactId contact = ContactUtil.createContactIdFromTrustedData(contactNumber);\n                State state = State.valueOf(cursor.getInt(stateIdx));\n                switch (state) {\n                    case STARTED:\n                        mVideoService.setVideoSharingStateAndReasonCode(contact, sharingId,\n                                State.FAILED, ReasonCode.FAILED_SHARING);\n                        break;\n                    case ACCEPTING:\n                        mVideoService.setVideoSharingStateAndReasonCode(contact, sharingId,\n                                State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                        break;\n                    case INITIATING:\n                        mVideoService.setVideoSharingStateAndReasonCode(contact, sharingId,\n                                State.FAILED, ReasonCode.FAILED_INITIATION);\n                        break;\n                    case INVITED:\n                        mVideoService.setVideoSharingStateAndReasonCode(contact, sharingId,\n                                State.REJECTED, ReasonCode.REJECTED_BY_SYSTEM);\n                        break;\n                    default:\n                        sLogger.error(getClass().getName() + \" unexpected state (\" + state\n                                + \") detected! Error in SQL statement?\");\n                        break;\n                }\n            }\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    \"Exception occured while trying to update video sharing state for interrupted geoloc sharing\",\n                    e);\n        } finally {\n            CursorUtil.close(cursor);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"done.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/VideoSharingData.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport android.net.Uri;\n\n/**\n * Video sharing data constants\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoSharingData {\n\n    /**\n     * Content provider URI\n     */\n    /* package private */public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.rcs.videoshare/videoshare\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = VideoSharingLog.HISTORYLOG_MEMBER_ID;\n\n    /**\n     * Unique history log id\n     */\n    /* package private */static final String KEY_BASECOLUMN_ID = VideoSharingLog.BASECOLUMN_ID;\n\n    /**\n     * Unique sharing identifier\n     */\n    /* package private */static final String KEY_SHARING_ID = VideoSharingLog.SHARING_ID;\n\n    /**\n     * ContactId formatted number of the remote contact\n     */\n    /* package private */static final String KEY_CONTACT = VideoSharingLog.CONTACT;\n\n    /**\n     * Date of the sharing\n     */\n    /* package private */static final String KEY_TIMESTAMP = VideoSharingLog.TIMESTAMP;\n\n    /**\n     * @see VideoSharing.State for the list of states\n     */\n    /* package private */static final String KEY_STATE = VideoSharingLog.STATE;\n\n    /**\n     * Reason code associated with the video sharing state.\n     * \n     * @see VideoSharing.ReasonCode\n     */\n    /* package private */static final String KEY_REASON_CODE = VideoSharingLog.REASON_CODE;\n\n    /**\n     * Incoming sharing or outgoing sharing.\n     * \n     * @see RcsService.Direction\n     */\n    /* package private */static final String KEY_DIRECTION = VideoSharingLog.DIRECTION;\n\n    /**\n     * Duration of the sharing in milliseconds. The value is only set at the end of the sharing.\n     */\n    /* package private */static final String KEY_DURATION = VideoSharingLog.DURATION;\n\n    /**\n     * Encoding of the shared video\n     */\n    /* package private */static final String KEY_VIDEO_ENCODING = VideoSharingLog.VIDEO_ENCODING;\n\n    /**\n     * Width of the shared video\n     */\n    /* package private */static final String KEY_WIDTH = VideoSharingLog.WIDTH;\n\n    /**\n     * Height of the shared video\n     */\n    /* package private */static final String KEY_HEIGHT = VideoSharingLog.HEIGHT;\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/VideoSharingDeleteTask.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoStreamingSession;\nimport com.gsma.rcs.provider.DeleteTask;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.service.api.VideoSharingServiceImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\npublic class VideoSharingDeleteTask extends DeleteTask.GroupedByContactId {\n\n    private static final Logger sLogger = Logger.getLogger(VideoSharingDeleteTask.class.getName());\n\n    private final VideoSharingServiceImpl mVideoSharingService;\n\n    private final RichcallService mRichcallService;\n\n    /**\n     * Deletion of all video sharing .\n     * \n     * @param videoSharingService the video sharing service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     */\n    public VideoSharingDeleteTask(VideoSharingServiceImpl videoSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver) {\n        super(contentResolver, VideoSharingData.CONTENT_URI, VideoSharingData.KEY_SHARING_ID,\n                VideoSharingData.KEY_CONTACT, (String) null);\n        mVideoSharingService = videoSharingService;\n        mRichcallService = richcallService;\n    }\n\n    /**\n     * Deletion of a specific video sharing.\n     * \n     * @param videoSharingService the video sharing service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     * @param sharingId the sharing id\n     */\n    public VideoSharingDeleteTask(VideoSharingServiceImpl videoSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver, String sharingId) {\n        super(contentResolver, VideoSharingData.CONTENT_URI, VideoSharingData.KEY_SHARING_ID,\n                VideoSharingData.KEY_CONTACT, null, sharingId);\n        mVideoSharingService = videoSharingService;\n        mRichcallService = richcallService;\n    }\n\n    /**\n     * Deletion of all video sharing with a specific contact.\n     *\n     * @param videoSharingService the video sharing service impl\n     * @param richcallService the rich call service\n     * @param contentResolver the local content resolver\n     * @param contact the contact id\n     */\n    public VideoSharingDeleteTask(VideoSharingServiceImpl videoSharingService,\n            RichcallService richcallService, LocalContentResolver contentResolver, ContactId contact) {\n        super(contentResolver, VideoSharingData.CONTENT_URI, VideoSharingData.KEY_SHARING_ID,\n                VideoSharingData.KEY_CONTACT, contact);\n        mVideoSharingService = videoSharingService;\n        mRichcallService = richcallService;\n    }\n\n    @Override\n    protected void onRowDelete(ContactId contact, String sharingId) throws PayloadException {\n        VideoStreamingSession session = mRichcallService.getVideoSharingSession(sharingId);\n        if (session == null) {\n            mVideoSharingService.removeVideoSharing(sharingId);\n            return;\n\n        }\n        try {\n            session.deleteSession();\n        } catch (NetworkException e) {\n            /*\n             * If network is lost during a delete operation the remaining part of the delete\n             * operation (delete from persistent storage) can succeed to 100% anyway since delete\n             * can be executed anyway while no network connectivity is present and still succeed.\n             */\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n        mVideoSharingService.removeVideoSharing(sharingId);\n    }\n\n    @Override\n    protected void onCompleted(ContactId contact, Set<String> deletedIds) {\n        mVideoSharingService.broadcastDeleted(contact, deletedIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/VideoSharingPersistedStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.core.content.VideoContent;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoDescriptor;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport android.database.Cursor;\nimport android.net.Uri;\n\n/**\n * VideoSharingPersistedStorageAccessor helps in retrieving persisted data related to a video share\n * from the persisted storage. It can utilize caching for such data that will not be changed after\n * creation of the video sharing to speed up consecutive access.\n */\npublic class VideoSharingPersistedStorageAccessor {\n\n    private final String mSharingId;\n\n    private final RichCallHistory mRichCallLog;\n\n    private ContactId mContact;\n\n    private Direction mDirection;\n\n    private String mVideoEncoding;\n\n    private VideoDescriptor mVideoDescriptor;\n\n    private long mTimestamp;\n\n    /**\n     * Constructor\n     * \n     * @param sharingId the sharing ID\n     * @param richCallLog the richcall log accessor\n     */\n    public VideoSharingPersistedStorageAccessor(String sharingId, RichCallHistory richCallLog) {\n        mSharingId = sharingId;\n        mRichCallLog = richCallLog;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param sharingId the sharing ID\n     * @param contact the remote contact\n     * @param direction the direction\n     * @param richCallLog the richcall log accessor\n     * @param videoEncoding the video encoding\n     * @param height the height\n     * @param width the width\n     * @param timestamp the timestamp\n     */\n    public VideoSharingPersistedStorageAccessor(String sharingId, ContactId contact,\n            Direction direction, RichCallHistory richCallLog, String videoEncoding, int height,\n            int width, long timestamp) {\n        mSharingId = sharingId;\n        mContact = contact;\n        mDirection = direction;\n        mRichCallLog = richCallLog;\n        mVideoEncoding = videoEncoding;\n        mVideoDescriptor = new VideoDescriptor(width, height);\n        mTimestamp = timestamp;\n    }\n\n    private void cacheData() {\n        Cursor cursor = null;\n        try {\n            cursor = mRichCallLog.getVideoSharingData(mSharingId);\n            if (!cursor.moveToNext()) {\n                throw new ServerApiPersistentStorageException(\"Data not found for video sharing \"\n                        + mSharingId);\n            }\n            String contact = cursor.getString(cursor\n                    .getColumnIndexOrThrow(VideoSharingData.KEY_CONTACT));\n            if (contact != null) {\n                mContact = ContactUtil.createContactIdFromTrustedData(contact);\n            }\n            mDirection = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndexOrThrow(VideoSharingData.KEY_DIRECTION)));\n            mVideoEncoding = cursor.getString(cursor\n                    .getColumnIndexOrThrow(VideoSharingData.KEY_VIDEO_ENCODING));\n            int width = cursor.getInt(cursor.getColumnIndexOrThrow(VideoSharingData.KEY_WIDTH));\n            int height = cursor.getInt(cursor.getColumnIndexOrThrow(VideoSharingData.KEY_HEIGHT));\n            mVideoDescriptor = new VideoDescriptor(width, height);\n            mTimestamp = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(VideoSharingData.KEY_TIMESTAMP));\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Gets remote contact\n     * \n     * @return remote contact\n     */\n    public ContactId getRemoteContact() {\n        /*\n         * Utilizing cache here as contact can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mContact == null) {\n            cacheData();\n        }\n        return mContact;\n    }\n\n    /**\n     * Gets video sharing session state\n     * \n     * @return state\n     */\n    public State getState() {\n        State state = mRichCallLog.getVideoSharingState(mSharingId);\n        if (state == null) {\n            throw new ServerApiPersistentStorageException(\"State not found for video sharing \"\n                    + mSharingId);\n        }\n        return state;\n    }\n\n    /**\n     * Gets video sharing reason code\n     * \n     * @return reason code\n     */\n    public ReasonCode getReasonCode() {\n        ReasonCode reasonCode = mRichCallLog.getVideoSharingReasonCode(mSharingId);\n        if (reasonCode == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Reason code not found for video sharing \" + mSharingId);\n        }\n        return reasonCode;\n    }\n\n    /**\n     * Gets direction\n     * \n     * @return direction\n     */\n    public Direction getDirection() {\n        /*\n         * Utilizing cache here as direction can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mDirection == null) {\n            cacheData();\n        }\n        return mDirection;\n    }\n\n    /**\n     * Sets state, reason code and duration\n     * \n     * @param state the video session state\n     * @param reasonCode the reason code\n     * @param duration the duration\n     * @return true if updated\n     */\n    public boolean setStateReasonCodeAndDuration(State state, ReasonCode reasonCode, long duration) {\n        return mRichCallLog.setVideoSharingStateReasonCodeAndDuration(mSharingId, state,\n                reasonCode, duration);\n    }\n\n    /**\n     * Add video sharing session\n     * \n     * @param contact the remote contact\n     * @param direction the direction\n     * @param content the video content\n     * @param state the video session state\n     * @param reasonCode the reason code\n     * @param timestamp Local timestamp of the video sharing\n     * @return the URI of the newly inserted item\n     */\n    public Uri addVideoSharing(ContactId contact, Direction direction, VideoContent content,\n            State state, ReasonCode reasonCode, long timestamp) {\n        mContact = contact;\n        mDirection = direction;\n        mTimestamp = timestamp;\n        return mRichCallLog.addVideoSharing(mSharingId, contact, direction, content, state,\n                reasonCode, timestamp);\n    }\n\n    /**\n     * Gets video encoding\n     * \n     * @return video encoding\n     */\n    public String getVideoEncoding() {\n        /*\n         * Utilizing cache here as video encoding can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mVideoEncoding == null) {\n            cacheData();\n        }\n        return mVideoEncoding;\n    }\n\n    /**\n     * Gets video descriptor\n     * \n     * @return descriptor\n     */\n    public VideoDescriptor getVideoDescriptor() {\n        /*\n         * Utilizing cache here as video descriptor can't be changed in persistent storage after\n         * entry insertion anyway so no need to query for it multiple times.\n         */\n        if (mVideoDescriptor == null) {\n            cacheData();\n        }\n        return mVideoDescriptor;\n    }\n\n    /**\n     * Returns the local timestamp of when the video sharing was initiated for outgoing video\n     * sharing or the local timestamp of when the video sharing invitation was received for incoming\n     * video sharings.\n     * \n     * @return timestamp\n     */\n    public long getTimestamp() {\n        /*\n         * Utilizing cache here as timestamp can't be changed in persistent storage after entry\n         * insertion anyway so no need to query for it multiple times.\n         */\n        if (mTimestamp == 0) {\n            cacheData();\n        }\n        return mTimestamp;\n    }\n\n    /**\n     * Returns the duration of the video sharing\n     * \n     * @return duration\n     */\n    public long getDuration() {\n        Long duration = mRichCallLog.getVideoSharingDuration(mSharingId);\n        if (duration == null) {\n            throw new ServerApiPersistentStorageException(\"Duration not found for video sharing \"\n                    + mSharingId);\n        }\n        return duration;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/VideoSharingProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.history.HistoryMemberBaseIdCreator;\nimport com.gsma.rcs.service.api.ServerApiPersistentStorageException;\nimport com.gsma.rcs.utils.DatabaseUtils;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.UriMatcher;\nimport android.database.Cursor;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.database.sqlite.SQLiteOpenHelper;\nimport android.net.Uri;\nimport android.support.annotation.NonNull;\nimport android.text.TextUtils;\n\n/**\n * Video sharing provider\n * \n * @author Jean-Marc AUFFRET\n */\n@SuppressWarnings(\"ConstantConditions\")\npublic class VideoSharingProvider extends ContentProvider {\n\n    private static final int INVALID_ROW_ID = -1;\n\n    private static final String SELECTION_WITH_SHARING_ID_ONLY = VideoSharingData.KEY_SHARING_ID\n            .concat(\"=?\");\n\n    private static final UriMatcher sUriMatcher;\n    static {\n        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);\n        sUriMatcher.addURI(VideoSharingData.CONTENT_URI.getAuthority(),\n                VideoSharingData.CONTENT_URI.getPath().substring(1),\n                UriType.InternalVideoSharing.VIDEO_SHARING);\n        sUriMatcher.addURI(VideoSharingData.CONTENT_URI.getAuthority(),\n                VideoSharingData.CONTENT_URI.getPath().substring(1).concat(\"/*\"),\n                UriType.InternalVideoSharing.VIDEO_SHARING_WITH_ID);\n        sUriMatcher.addURI(VideoSharingLog.CONTENT_URI.getAuthority(), VideoSharingLog.CONTENT_URI\n                .getPath().substring(1), UriType.VideoSharing.VIDEO_SHARING);\n        sUriMatcher.addURI(VideoSharingLog.CONTENT_URI.getAuthority(), VideoSharingLog.CONTENT_URI\n                .getPath().substring(1).concat(\"/*\"), UriType.VideoSharing.VIDEO_SHARING_WITH_ID);\n    }\n\n    /**\n     * Table name\n     */\n    public static final String TABLE = \"videoshare\";\n\n    /**\n     * Database name\n     */\n    public static final String DATABASE_NAME = \"videoshare.db\";\n\n    private static final class UriType {\n\n        private static final class VideoSharing {\n            private static final int VIDEO_SHARING = 1;\n\n            private static final int VIDEO_SHARING_WITH_ID = 2;\n        }\n\n        private static final class InternalVideoSharing {\n            private static final int VIDEO_SHARING = 3;\n\n            private static final int VIDEO_SHARING_WITH_ID = 4;\n        }\n    }\n\n    private static final class CursorType {\n\n        private static final String TYPE_DIRECTORY = \"vnd.android.cursor.dir/videoshare\";\n\n        private static final String TYPE_ITEM = \"vnd.android.cursor.item/videoshare\";\n    }\n\n    /**\n     * Helper class for opening, creating and managing db version control\n     */\n    private static class DatabaseHelper extends SQLiteOpenHelper {\n        private static final int DATABASE_VERSION = 7;\n\n        public DatabaseHelper(Context ctx) {\n            super(ctx, DATABASE_NAME, null, DATABASE_VERSION);\n        }\n\n        @Override\n        public void onCreate(SQLiteDatabase db) {\n            // @formatter:off\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS \" + TABLE + '('\n                    + VideoSharingData.KEY_BASECOLUMN_ID + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_SHARING_ID + \" TEXT NOT NULL PRIMARY KEY,\"\n                    + VideoSharingData.KEY_CONTACT + \" TEXT NOT NULL,\"\n                    + VideoSharingData.KEY_STATE + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_REASON_CODE + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_DIRECTION + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_TIMESTAMP + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_DURATION + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_VIDEO_ENCODING + \" TEXT,\"\n                    + VideoSharingData.KEY_WIDTH + \" INTEGER NOT NULL,\"\n                    + VideoSharingData.KEY_HEIGHT + \" INTEGER NOT NULL)\");\n            // @formatter:on\n            db.execSQL(\"CREATE INDEX \" + VideoSharingData.KEY_BASECOLUMN_ID + \"_idx\" + \" ON \"\n                    + TABLE + '(' + VideoSharingData.KEY_BASECOLUMN_ID + ')');\n            db.execSQL(\"CREATE INDEX \" + VideoSharingData.KEY_CONTACT + \"_idx\" + \" ON \" + TABLE\n                    + '(' + VideoSharingData.KEY_CONTACT + ')');\n            db.execSQL(\"CREATE INDEX \" + VideoSharingData.KEY_TIMESTAMP + \"_idx\" + \" ON \" + TABLE\n                    + '(' + VideoSharingData.KEY_TIMESTAMP + ')');\n        }\n\n        @Override\n        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {\n            db.execSQL(\"DROP TABLE IF EXISTS \".concat(TABLE));\n            onCreate(db);\n        }\n    }\n\n    private SQLiteOpenHelper mOpenHelper;\n\n    private String getSelectionWithSharingId(String selection) {\n        if (TextUtils.isEmpty(selection)) {\n            return SELECTION_WITH_SHARING_ID_ONLY;\n        }\n        return \"(\" + SELECTION_WITH_SHARING_ID_ONLY + \") AND (\" + selection + ')';\n    }\n\n    private String[] getSelectionArgsWithSharingId(String[] selectionArgs, String sharingId) {\n        return DatabaseUtils.appendIdWithSelectionArgs(sharingId, selectionArgs);\n    }\n\n    @Override\n    public boolean onCreate() {\n        mOpenHelper = new DatabaseHelper(getContext());\n        return true;\n    }\n\n    @Override\n    public String getType(@NonNull Uri uri) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalVideoSharing.VIDEO_SHARING:\n                /* Intentional fall through */\n            case UriType.VideoSharing.VIDEO_SHARING:\n                return CursorType.TYPE_DIRECTORY;\n\n            case UriType.InternalVideoSharing.VIDEO_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.VideoSharing.VIDEO_SHARING_WITH_ID:\n                return CursorType.TYPE_ITEM;\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n            String[] selectionArgs, String sort) {\n        Cursor cursor = null;\n        try {\n            switch (sUriMatcher.match(uri)) {\n                case UriType.InternalVideoSharing.VIDEO_SHARING_WITH_ID:\n                    String sharingId = uri.getLastPathSegment();\n                    selection = getSelectionWithSharingId(selection);\n                    selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                    SQLiteDatabase db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            Uri.withAppendedPath(VideoSharingLog.CONTENT_URI, sharingId));\n                    return cursor;\n\n                case UriType.InternalVideoSharing.VIDEO_SHARING:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(),\n                            VideoSharingLog.CONTENT_URI);\n                    return cursor;\n\n                case UriType.VideoSharing.VIDEO_SHARING_WITH_ID:\n                    sharingId = uri.getLastPathSegment();\n                    selection = getSelectionWithSharingId(selection);\n                    selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                case UriType.VideoSharing.VIDEO_SHARING:\n                    db = mOpenHelper.getReadableDatabase();\n                    cursor = db\n                            .query(TABLE, projection, selection, selectionArgs, null, null, sort);\n                    CursorUtil.assertCursorIsNotNull(cursor, uri);\n                    cursor.setNotificationUri(getContext().getContentResolver(), uri);\n                    return cursor;\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n            }\n        } /*\n           * TODO: Do not catch, close cursor, and then throw same exception. Callers should handle\n           * exception.\n           */\n        catch (RuntimeException e) {\n            if (cursor != null) {\n                cursor.close();\n            }\n            throw e;\n        }\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, ContentValues values, String selection,\n            String[] selectionArgs) {\n        Uri notificationUri = VideoSharingLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalVideoSharing.VIDEO_SHARING_WITH_ID:\n                String sharingId = uri.getLastPathSegment();\n                selection = getSelectionWithSharingId(selection);\n                selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                notificationUri = Uri.withAppendedPath(notificationUri, sharingId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalVideoSharing.VIDEO_SHARING:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.update(TABLE, values, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.VideoSharing.VIDEO_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.VideoSharing.VIDEO_SHARING:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public Uri insert(@NonNull Uri uri, ContentValues initialValues) {\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalVideoSharing.VIDEO_SHARING:\n                /* Intentional fall through */\n            case UriType.InternalVideoSharing.VIDEO_SHARING_WITH_ID:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                String sharingId = initialValues.getAsString(VideoSharingData.KEY_SHARING_ID);\n                initialValues.put(VideoSharingData.KEY_BASECOLUMN_ID, HistoryMemberBaseIdCreator\n                        .createUniqueId(getContext(), VideoSharingData.HISTORYLOG_MEMBER_ID));\n                if (db.insert(TABLE, null, initialValues) == INVALID_ROW_ID) {\n                    throw new ServerApiPersistentStorageException(\"Unable to insert row for URI \"\n                            + uri.toString() + '!');\n                }\n                Uri notificationUri = Uri.withAppendedPath(VideoSharingLog.CONTENT_URI, sharingId);\n                getContext().getContentResolver().notifyChange(notificationUri, null);\n                return notificationUri;\n\n            case UriType.VideoSharing.VIDEO_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.VideoSharing.VIDEO_SHARING:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n        Uri notificationUri = VideoSharingLog.CONTENT_URI;\n        switch (sUriMatcher.match(uri)) {\n            case UriType.InternalVideoSharing.VIDEO_SHARING_WITH_ID:\n                String sharingId = uri.getLastPathSegment();\n                selection = getSelectionWithSharingId(selection);\n                selectionArgs = getSelectionArgsWithSharingId(selectionArgs, sharingId);\n                notificationUri = Uri.withAppendedPath(notificationUri, sharingId);\n                /* Intentional fall through */\n                //$FALL-THROUGH$\n            case UriType.InternalVideoSharing.VIDEO_SHARING:\n                SQLiteDatabase db = mOpenHelper.getWritableDatabase();\n                int count = db.delete(TABLE, selection, selectionArgs);\n                if (count > 0) {\n                    getContext().getContentResolver().notifyChange(notificationUri, null);\n                }\n                return count;\n\n            case UriType.VideoSharing.VIDEO_SHARING_WITH_ID:\n                /* Intentional fall through */\n            case UriType.VideoSharing.VIDEO_SHARING:\n                throw new UnsupportedOperationException(\"This provider (URI=\" + uri\n                        + \") supports read only access!\");\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI \" + uri + \"!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provider/sharing/VideoSharingStateAndReasonCode.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.provider.sharing;\n\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\npublic class VideoSharingStateAndReasonCode {\n\n    private final State mState;\n\n    private final ReasonCode mReasonCode;\n\n    public VideoSharingStateAndReasonCode(State state, ReasonCode reasonCode) {\n        mState = state;\n        mReasonCode = reasonCode;\n    }\n\n    public State getState() {\n        return mState;\n    }\n\n    public ReasonCode getReasonCode() {\n        return mReasonCode;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/Parameter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning;\n\n/**\n * Provisioning parameter\n * \n * @author jexa7410\n */\npublic class Parameter {\n    /**\n     * Parameter name\n     */\n    private String name;\n\n    /**\n     * Parameter value\n     */\n    private String value;\n\n    /**\n     * Parameter type\n     */\n    private String type;\n\n    /**\n     * Parameter path\n     */\n    private String path;\n\n    /**\n     * Constructor\n     * \n     * @param name Name\n     * @param value Value\n     * @param type Type\n     * @param path Path\n     */\n    public Parameter(String name, String value, String type, String path) {\n        this.name = name;\n        this.value = value;\n        this.type = type;\n        this.path = path;\n    }\n\n    /**\n     * Returns parameter name\n     * \n     * @return String\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns parameter value\n     * \n     * @return String\n     */\n    public String getValue() {\n        return value;\n    }\n\n    /**\n     * Returns parameter type\n     * \n     * @return String\n     */\n    public String getType() {\n        return type;\n    }\n\n    /**\n     * Returns the path associated to the parameter\n     * \n     * @return\n     */\n    public String getPath() {\n        return path;\n    }\n\n    /**\n     * Returns the string representtaion of the parameter\n     * \n     * @return String\n     */\n    public String toString() {\n        return \"Name: \" + name + \", value=\" + value + \", type=\" + type + \", path=\" + path;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/ProvisioningFailureReasons.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning;\n\n/**\n * Provisioning failure reasons\n * \n * @author Deutsche Telekom AG\n */\npublic class ProvisioningFailureReasons {\n\n    /**\n     * Action string for provisioning failure\n     */\n    public static final String ACTION_HTTPS_PROVISIONING_FAILS = \"ProvisioningFailed\";\n\n    /**\n     * Key string for provisioning failure reason in Intent's extra\n     */\n    public static final String EXTRA_PROVISIONING_FAILURE_REASON = \"ProvisioningFailedReason\";\n\n    /**\n     * Provisioning is blocked with this account\n     */\n    public static final int PROVISIONING_IS_BLOCKED_WITH_THIS_ACCOUNT = 0;\n\n    /**\n     * Invalid configuration (error in parsing the configuration document)\n     */\n    public static final int INVALID_CONFIGURATION = 1;\n\n    /**\n     * Unable to get configuration (503 \"Service unavailable \" on provisioning as a first launch)\n     */\n    public static final int UNABLE_TO_GET_CONFIGURATION = 2;\n\n    /**\n     * Provisioning forbidden (403 \"Forbidden\")\n     */\n    public static final int PROVISIONING_FORBIDDEN = 3;\n\n    /**\n     * Provisioning authentication required (511 \"Network authentication required\")\n     */\n    public static final int PROVISIONING_AUTHENTICATION_REQUIRED = 4;\n\n    /**\n     * No connectivity to HCS/RCS server\n     */\n    public static final int CONNECTIVITY_ISSUE = 5;\n\n    /**\n     * No configuration present (other error occurs)\n     */\n    public static final int NO_CONFIGURATION_PRESENT = 6;\n\n    /**\n     * No connectivity at all (Hotspot IP but not logged in)\n     */\n    public static final int SRV_SERVICE_UNAVAILABLE = 7;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/ProvisioningInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning;\n\n/**\n * Provisioning info\n * \n * @author jexa7410\n */\npublic class ProvisioningInfo {\n    /**\n     * Version of the provisioning document\n     */\n    private int mVersion;\n\n    /**\n     * Validity of the provisioning document\n     */\n    private long mValidity = 0L;\n\n    /**\n     * Token of the provisioning document\n     */\n    private String mToken;\n\n    /**\n     * Validity of the token of the provisioning document\n     */\n    private long mTokenValidity = 0L;\n\n    /**\n     * Title for terms and conditions\n     */\n    private String mTitle;\n\n    /**\n     * Message for terms and conditions\n     */\n    private String mMessage;\n\n    /**\n     * Accept button for terms and conditions\n     */\n    private boolean mAcceptBtn = false;\n\n    /**\n     * Reject button for terms and conditions\n     */\n    private boolean mRejectBtn = false;\n\n    /**\n     * Enumerated for the provisioning version\n     */\n    public enum Version {\n        /**\n         * The configuration is reseted : RCS client is temporary disabled.\n         */\n        RESETED(0),\n        /**\n         * The configuration is reseted : RCS client is forbidden.\n         */\n        RESETED_NOQUERY(-1),\n        /**\n         * The RCS client is disabled and configuration query stopped.\n         */\n        DISABLED_NOQUERY(-2),\n        /**\n         * The RCS client is in dormant state: RCS is disabled but provisioning is still running.\n         */\n        DISABLED_DORMANT(-3);\n\n        private int mVers;\n\n        private Version(int vers) {\n            mVers = vers;\n        }\n\n        public int toInt() {\n            return mVers;\n        }\n\n    }\n\n    /**\n     * Set version\n     * \n     * @param version\n     */\n    public void setVersion(int version) {\n        mVersion = version;\n    }\n\n    /**\n     * Set validity in milliseconds\n     * \n     * @param validity\n     */\n    public void setValidity(long validity) {\n        mValidity = validity;\n    }\n\n    /**\n     * Set title\n     * \n     * @param title\n     */\n    public void setTitle(String title) {\n        mTitle = title;\n    }\n\n    /**\n     * Set message\n     * \n     * @param message\n     */\n    public void setMessage(String message) {\n        mMessage = message;\n    }\n\n    /**\n     * Set AcceptBtn\n     * \n     * @param acceptBtn\n     */\n    public void setAcceptBtn(boolean acceptBtn) {\n        mAcceptBtn = acceptBtn;\n    }\n\n    /**\n     * Set RejectBtn\n     * \n     * @param rejectBtn\n     */\n    public void setRejectBtn(boolean rejectBtn) {\n        mRejectBtn = rejectBtn;\n    }\n\n    /**\n     * Get version\n     * \n     * @return version\n     */\n    public int getVersion() {\n        return mVersion;\n    }\n\n    /**\n     * Get validity in milliseconds\n     * \n     * @return validity\n     */\n    public long getValidity() {\n        return mValidity;\n    }\n\n    /**\n     * Get title\n     * \n     * @return title\n     */\n    public String getTitle() {\n        return mTitle;\n    }\n\n    /**\n     * Get message\n     * \n     * @return message\n     */\n    public String getMessage() {\n        return mMessage;\n    }\n\n    /**\n     * Get acceptBtn\n     * \n     * @return acceptBtn\n     */\n    public boolean getAcceptBtn() {\n        return mAcceptBtn;\n    }\n\n    /**\n     * Get rejectBtn\n     * \n     * @return rejectBtn\n     */\n    public boolean getRejectBtn() {\n        return mRejectBtn;\n    }\n\n    /**\n     * Get token\n     * \n     * @return token\n     */\n    public String getToken() {\n        return mToken;\n    }\n\n    /**\n     * Set token\n     * \n     * @param token\n     */\n    public void setToken(String token) {\n        mToken = token;\n    }\n\n    /**\n     * Get token validity\n     * \n     * @return token validity\n     */\n    public long getTokenValidity() {\n        return mTokenValidity;\n    }\n\n    /**\n     * Set token validity\n     * \n     * @param tokenValidity\n     */\n    public void setTokenValidity(long tokenValidity) {\n        mTokenValidity = tokenValidity;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/ProvisioningParser.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.AuthenticationProcedure;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.EnableRcseSwitch;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.GsmaRelease;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImMsgTech;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImSessionStartMode;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.DeviceUtils;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport org.w3c.dom.Document;\nimport org.w3c.dom.NamedNodeMap;\nimport org.w3c.dom.Node;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\n\nimport javax2.sip.ListeningPoint;\n\n/**\n * Provisioning parser\n * \n * @author jexa7410\n */\npublic class ProvisioningParser {\n    /**\n     * Parameter type text\n     */\n    private static final int TYPE_TXT = 0;\n\n    /**\n     * Parameter type integer\n     */\n    private static final int TYPE_INT = 1;\n\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    private static final String UUID_VALUE = \"uuid_Value\";\n\n    private static final String PROTOCOL_HTTPS = \"https\";\n\n    private ProvisioningInfo provisioningInfo = new ProvisioningInfo();\n\n    private String mContent;\n\n    private RcsSettings mRcsSettings;\n\n    private boolean mFirst = false;\n\n    private static final String STRING_BOOLEAN_TRUE = \"1\";\n\n    private static final Logger sLogger = Logger.getLogger(ProvisioningParser.class.getName());\n\n    /**\n     * Enumerated type for the root node\n     */\n    private enum RootNodeType {\n        VERS, TOKEN, MSG, APPLICATION, IMS, PRESENCE, XDMS, IM, CAPDISCOVERY, APN, OTHER, SERVICES, SUPL, SERVICEPROVIDEREXT, UX\n    }\n\n    /**\n     * Enumerated type for the IMS server version\n     */\n    enum ImsServerVersion {\n        JOYN, NON_JOYN\n    }\n\n    /**\n     * Constructor\n     * \n     * @param content The content to be parsed.\n     * @param rcsSettings the RCS settings.\n     */\n    public ProvisioningParser(String content, RcsSettings rcsSettings) {\n        mContent = content;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Returns provisioning info\n     * \n     * @return Provisioning info\n     */\n    public ProvisioningInfo getProvisioningInfo() {\n        return provisioningInfo;\n    }\n\n    /**\n     * Parse the provisioning document\n     * \n     * @param release The GSMA release (Albatros, Blackbird, Crane...) before parsing\n     * @param messagingMode the messaging mode\n     * @param first True if it is a first provisioning\n     * @throws SAXException\n     */\n    public void parse(GsmaRelease release, MessagingMode messagingMode, boolean first)\n            throws SAXException {\n        ByteArrayInputStream inputStream = null;\n        try {\n            final boolean logActivated = sLogger.isActivated();\n            if (logActivated) {\n                sLogger.debug(\"Start the parsing of content first=\".concat(Boolean.toString(first)));\n            }\n            mFirst = first;\n            inputStream = new ByteArrayInputStream(mContent.getBytes(UTF8));\n            DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();\n            DocumentBuilder dbuilder = dfactory.newDocumentBuilder();\n            Document doc = dbuilder.parse(inputStream);\n            if (doc == null) {\n                throw new SAXException(\"The provisioning content document is null!\");\n            }\n            if (logActivated) {\n                sLogger.debug(\"Parsed Doc =\" + doc);\n            }\n            Node rootnode = doc.getDocumentElement();\n            Node childnode = rootnode.getFirstChild();\n            if (childnode == null) {\n                throw new SAXException(\n                        \"The first chid node in the provisioning content document is null!\");\n            }\n            int nodeNumber = 0;\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    if (childnode.getAttributes().getLength() > 0) {\n                        Node typenode = childnode.getAttributes().getNamedItem(\"type\");\n                        if (typenode != null && typenode.getNodeValue() != null) {\n                            if (logActivated) {\n                                sLogger.debug(\"Node \" + childnode.getNodeName() + \" with type \"\n                                        + typenode.getNodeValue());\n                            }\n                            nodeNumber++;\n                            String nodeType = typenode.getNodeValue().toUpperCase();\n                            try {\n                                RootNodeType rootNodeType = RootNodeType.valueOf(nodeType);\n                                switch (rootNodeType) {\n                                    case VERS:\n                                        parseVersion(childnode);\n                                        break;\n                                    case TOKEN:\n                                        parseToken(childnode);\n                                        break;\n                                    case MSG:\n                                        parseTermsMessage(childnode);\n                                        break;\n                                    case APPLICATION:\n                                        parseApplication(childnode);\n                                        break;\n                                    case IMS:\n                                        parseIMS(childnode);\n                                        break;\n                                    case PRESENCE:\n                                        parsePresence(childnode);\n                                        break;\n                                    case XDMS:\n                                        parseXDMS(childnode);\n                                        break;\n                                    case IM:\n                                        parseIM(childnode);\n                                        break;\n                                    case APN:\n                                        parseAPN(childnode);\n                                        break;\n                                    case OTHER:\n                                        parseOther(childnode);\n                                        break;\n                                    case SERVICES:\n                                        parseServices(childnode);\n                                        break;\n                                    case SUPL:\n                                        parseSupl(childnode);\n                                        break;\n                                    case SERVICEPROVIDEREXT:\n                                        parseServiceProviderExt(childnode);\n                                        break;\n                                    case UX:\n                                        parseUx(childnode, ImsServerVersion.NON_JOYN);\n                                        break;\n                                    default:\n                                        if (sLogger.isActivated()) {\n                                            sLogger.warn(\"unhandled node type: \" + nodeType);\n                                        }\n                                }\n                            } catch (IllegalArgumentException e) {\n                                if (sLogger.isActivated()) {\n                                    sLogger.warn(\"invalid node type: \" + nodeType);\n                                }\n                            }\n                        }\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n            if (nodeNumber == 1) {\n                /*\n                 * We received a single node (the version one) ! This is the case if the version\n                 * number is negative or in order to extend the validity of the provisioning. In\n                 * that case we restore the relevant GSMA release saved before parsing.\n                 */\n                mRcsSettings.setGsmaRelease(release);\n                /* We do the same for the messaging mode */\n                mRcsSettings.setMessagingMode(messagingMode);\n            }\n        } catch (ParserConfigurationException | IOException e) {\n            throw new SAXException(\"Can't parse provisioning content document!\", e);\n\n        } finally {\n            CloseableUtils.tryToClose(inputStream);\n        }\n    }\n\n    /**\n     * Parse the provisioning version\n     * \n     * @param node Node\n     */\n    private void parseVersion(Node node) {\n        String version = null;\n        String validity = null;\n        Node versionchild = node.getFirstChild();\n        if (versionchild != null) {\n            do {\n                if (version == null) {\n                    if ((version = getValueByParamName(\"version\", versionchild, TYPE_TXT)) != null) {\n                        provisioningInfo.setVersion(Integer.parseInt(version));\n                        continue;\n                    }\n                }\n                if (validity == null) {\n                    if ((validity = getValueByParamName(\"validity\", versionchild, TYPE_INT)) != null) {\n                        provisioningInfo.setValidity(Long.parseLong(validity)\n                                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                    }\n                }\n            } while ((versionchild = versionchild.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse the provisioning Token\n     * \n     * @param node Node\n     */\n    private void parseToken(Node node) {\n        String token = null;\n        String tokenValidity = null;\n        Node tokenChild = node.getFirstChild();\n        if (tokenChild != null) {\n            do {\n                if (token == null) {\n                    if ((token = getValueByParamName(\"token\", tokenChild, TYPE_TXT)) != null) {\n                        provisioningInfo.setToken(token);\n                        continue;\n                    }\n                }\n                if (tokenValidity == null) {\n                    if ((tokenValidity = getValueByParamName(\"validity\", tokenChild, TYPE_INT)) != null) {\n                        provisioningInfo.setTokenValidity(Long.parseLong(tokenValidity));\n                    }\n                }\n            } while ((tokenChild = tokenChild.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse terms message\n     * \n     * @param node Node\n     */\n    private void parseTermsMessage(Node node) {\n        String title = null;\n        String message = null;\n        String acceptBtn = null;\n        String rejectBtn = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (title == null) {\n                    if ((title = getValueByParamName(\"title\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setProvisioningUserMessageTitle(\"\".equals(title) ? null\n                                : title);\n                        provisioningInfo.setTitle(title);\n                        continue;\n                    }\n                }\n                if (message == null) {\n                    if ((message = getValueByParamName(\"message\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setProvisioningUserMessageContent(\"\".equals(message) ? null\n                                : message);\n                        provisioningInfo.setMessage(message);\n                        continue;\n                    }\n                }\n                if (acceptBtn == null) {\n                    if ((acceptBtn = getValueByParamName(\"Accept_btn\", childnode, TYPE_INT)) != null) {\n                        boolean accept = STRING_BOOLEAN_TRUE.equals(acceptBtn);\n                        mRcsSettings.setProvisioningAcceptButton(accept);\n                        provisioningInfo.setAcceptBtn(accept);\n                        continue;\n                    }\n                }\n                if (rejectBtn == null) {\n                    if ((rejectBtn = getValueByParamName(\"Reject_btn\", childnode, TYPE_INT)) != null) {\n                        boolean reject = STRING_BOOLEAN_TRUE.equals(rejectBtn);\n                        mRcsSettings.setProvisioningRejectButton(reject);\n                        provisioningInfo.setRejectBtn(reject);\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse the application infos\n     * \n     * @param node Node\n     */\n    private void parseApplication(Node node) {\n        String appId = null;\n        String name = null;\n        String appRef = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (appId == null) {\n                    if ((appId = getValueByParamName(\"AppID\", childnode, TYPE_TXT)) != null) {\n                        continue;\n                    }\n                }\n                if (name == null) {\n                    if ((name = getValueByParamName(\"Name\", childnode, TYPE_TXT)) != null) {\n                        continue;\n                    }\n                }\n                if (appRef == null) {\n                    if ((appRef = getValueByParamName(\"AppRef\", childnode, TYPE_TXT)) != null) {\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n        if (appRef != null\n                && (appRef.equalsIgnoreCase(\"IMS-Settings\") || appRef.equalsIgnoreCase(\"ims-rcse\"))) {\n            parseIMS(node);\n        }\n        if (appRef != null && appRef.equalsIgnoreCase(\"RCSe-Settings\")) {\n            parseRCSe(node);\n        }\n    }\n\n    /**\n     * Parse presence favorite link\n     * \n     * @param node Node\n     */\n    private void parseFavoriteLink(Node node) {\n        // Not supported\n    }\n\n    /**\n     * Parse presence watcher\n     * \n     * @param node Node\n     */\n    private void parsePresenceWatcher(Node node) {\n        // TODO: \"FetchAuth\"\n        // TODO: \"ContactCapPresAut\"\n    }\n\n    /**\n     * Parse presentity watcher\n     * \n     * @param node Node\n     */\n    private void parsePresentityWatcher(Node node) {\n        // TODO: \"WATCHERFETCHAUTH\"\n    }\n\n    /**\n     * Parse presence\n     * \n     * @param node Node\n     */\n    private void parsePresence(Node node) {\n        String usePresence = null;\n        String presencePrfl = null;\n        String iconMaxSize = null;\n        String noteMaxSize = null;\n        String publishTimer = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    if (childnode.getAttributes().getLength() > 0) {\n                        Node typenode = childnode.getAttributes().getNamedItem(\"type\");\n                        if (typenode != null) {\n                            if (typenode.getNodeValue().equalsIgnoreCase(\"FAVLINK\")) {\n                                parseFavoriteLink(childnode);\n                            } else if (typenode.getNodeValue().equalsIgnoreCase(\"SERVCAPWATCH\")) {\n                                parsePresenceWatcher(childnode);\n                            } else if (typenode.getNodeValue()\n                                    .equalsIgnoreCase(\"ServCapPresentity\")) {\n                                parsePresentityWatcher(childnode);\n                            }\n                        }\n                    }\n                }\n                if (usePresence == null) {\n                    if ((usePresence = getValueByParamName(\"usePresence\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_SOCIAL_PRESENCE,\n                                !usePresence.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (presencePrfl == null) {\n                    if ((presencePrfl = getValueByParamName(\"presencePrfl\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_PRESENCE_DISCOVERY,\n                                !presencePrfl.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (iconMaxSize == null) {\n                    if ((iconMaxSize = getValueByParamName(\"IconMaxSize\", childnode, TYPE_INT)) != null) {\n                        long size = Long.parseLong(iconMaxSize);\n                        mRcsSettings.setMaxPhotoIconSize(size);\n                        continue;\n                    }\n                }\n                if (noteMaxSize == null) {\n                    if ((noteMaxSize = getValueByParamName(\"NoteMaxSize\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_FREETXT_LENGTH,\n                                Integer.parseInt(noteMaxSize));\n                        continue;\n                    }\n                }\n                if (publishTimer == null) {\n                    if ((publishTimer = getValueByParamName(\"PublishTimer\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.PUBLISH_EXPIRE_PERIOD,\n                                Long.parseLong(publishTimer)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                    }\n                }\n                // Not supported: \"AvailabilityAuth\"\n                // Not supported: \"client-obj-datalimit\"\n                // Not used for RCS: \"content-serveruri\"\n                // Not supported: \"source-throttlepublish\"\n                // Not supported: \"max-number-ofsubscriptions-inpresence-list\"\n                // TODO: \"service-uritemplate\"\n\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse services\n     * \n     * @param node Node\n     */\n    private void parseServices(Node node) {\n        String presencePrfl = null;\n        String chatAuth = null;\n        String groupChatAuth = null;\n        String ftAuth = null;\n        String geolocPushAuth = null;\n        String vsAuth = null;\n        String isAuth = null;\n        String rcsIPVoiceCallAuth = null;\n        String rcsIPVideoCallAuth = null;\n        String allowExtensions = null;\n        String composerAuth;\n        String sharedMapAuth;\n        String sharedSketchAuth;\n        String postCallAuth;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            // Node \"SERVICES\" is mandatory in GSMA release Blackbird and not present in previous\n            // one Albatros.\n            // Only if the parsing result contains a SERVICE tree, Blackbird is assumed as release.\n            // This trick is used to detect the GSMA release as provisioned by the network.\n            mRcsSettings.setGsmaRelease(GsmaRelease.BLACKBIRD);\n            do {\n\n                if (chatAuth == null) {\n                    if ((chatAuth = getValueByParamName(\"ChatAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_IM_SESSION,\n                                chatAuth.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (groupChatAuth == null) {\n                    if ((groupChatAuth = getValueByParamName(\"groupChatAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_IM_GROUP_SESSION,\n                                groupChatAuth.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (ftAuth == null) {\n                    if ((ftAuth = getValueByParamName(\"ftAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_FILE_TRANSFER,\n                                ftAuth.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (vsAuth == null) {\n                    if ((vsAuth = getValueByParamName(\"vsAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_VIDEO_SHARING,\n                                vsAuth.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (isAuth == null) {\n                    if ((isAuth = getValueByParamName(\"isAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_IMAGE_SHARING,\n                                isAuth.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (geolocPushAuth == null) {\n                    if ((geolocPushAuth = getValueByParamName(\"geolocPushAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH,\n                                geolocPushAuth.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (presencePrfl == null) {\n                    if ((presencePrfl = getValueByParamName(\"presencePrfl\", childnode, TYPE_INT)) != null) {\n                        if (presencePrfl.equals(\"1\")) {\n                            sLogger.error(\"Social presence is not supported in TAPI 1.5.1, ignoring capability received through provisioning.\");\n                        }\n                        mRcsSettings\n                                .writeBoolean(RcsSettingsData.CAPABILITY_SOCIAL_PRESENCE, false);\n                        continue;\n                    }\n                }\n                if (rcsIPVoiceCallAuth == null) {\n                    if ((rcsIPVoiceCallAuth = getValueByParamName(\"rcsIPVoiceCallAuth\", childnode,\n                            TYPE_INT)) != null) {\n                        int value = Integer.decode(rcsIPVoiceCallAuth);\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_IP_VOICE_CALL,\n                                (value % 16) != 0);\n                        continue;\n                    }\n                }\n                if (rcsIPVideoCallAuth == null) {\n                    if ((rcsIPVideoCallAuth = getValueByParamName(\"rcsIPVideoCallAuth\", childnode,\n                            TYPE_INT)) != null) {\n                        int value = Integer.decode(rcsIPVideoCallAuth);\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_IP_VIDEO_CALL,\n                                (value % 16) != 0);\n                        continue;\n                    }\n                }\n                if (allowExtensions == null) {\n                    if ((allowExtensions = getValueByParamName(\"allowRCSExtensions\", childnode,\n                            TYPE_INT)) != null) {\n                        int value = Integer.decode(allowExtensions);\n                        mRcsSettings.writeBoolean(RcsSettingsData.ALLOW_EXTENSIONS,\n                                (value % 16) != 0);\n                        continue;\n                    }\n                }\n                if ((composerAuth = getValueByParamName(\"composerAuth\", childnode, TYPE_INT)) != null) {\n                    int value = Integer.decode(composerAuth);\n                    mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_CALL_COMPOSER,\n                            (value % 16) != 0);\n                    continue;\n                }\n                if ((sharedMapAuth = getValueByParamName(\"sharedMapAuth\", childnode, TYPE_INT)) != null) {\n                    int value = Integer.decode(sharedMapAuth);\n                    mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_SHARED_MAP,\n                            (value % 16) != 0);\n                    continue;\n                }\n                if ((sharedSketchAuth = getValueByParamName(\"sharedSketchAuth\", childnode, TYPE_INT)) != null) {\n                    int value = Integer.decode(sharedSketchAuth);\n                    mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_SHARED_SKETCH,\n                            (value % 16) != 0);\n                    continue;\n                }\n                if ((postCallAuth = getValueByParamName(\"postCallAuth\", childnode, TYPE_INT)) != null) {\n                    int value = Integer.decode(postCallAuth);\n                    mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_POST_CALL,\n                            (value % 16) != 0);\n                }\n                // Not used: \"standaloneMsgAuth\"\n                // Not used: \"geolocPullAuth\"\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse XDMS\n     * \n     * @param node Node\n     */\n    private void parseXDMS(Node node) {\n        String revokeTimer = null;\n        String xcapRootURI = null;\n        String xcapAuthenticationUsername = null;\n        String xcapAuthenticationSecret = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (revokeTimer == null) {\n                    if ((revokeTimer = getValueByParamName(\"RevokeTimer\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.REVOKE_TIMEOUT,\n                                Long.parseLong(revokeTimer)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                        continue;\n                    }\n                }\n                if (xcapRootURI == null) {\n                    if ((xcapRootURI = getValueByParamName(\"XCAPRootURI\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setXdmServer(\"\".equals(xcapRootURI) ? null : Uri\n                                .parse(xcapRootURI));\n                        continue;\n                    }\n                }\n                if (xcapAuthenticationUsername == null) {\n                    if ((xcapAuthenticationUsername = getValueByParamName(\n                            \"XCAPAuthenticationUserName\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setXdmLogin(\"\".equals(xcapAuthenticationUsername) ? null\n                                : xcapAuthenticationUsername);\n                        continue;\n                    }\n                }\n                if (xcapAuthenticationSecret == null) {\n                    if ((xcapAuthenticationSecret = getValueByParamName(\"XCAPAuthenticationSecret\",\n                            childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setXdmPassword(\"\".equals(xcapAuthenticationSecret) ? null\n                                : xcapAuthenticationSecret);\n                    }\n                }\n                // Not used (only Digest is used): \"XCAPAuthenticationType\"\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse supl services\n     * \n     * @param node Node\n     */\n    private void parseSupl(Node node) {\n        String textMaxLength = null;\n        String locInfoMaxValidTime = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (textMaxLength == null) {\n                    if ((textMaxLength = getValueByParamName(\"TextMaxLength\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_GEOLOC_LABEL_LENGTH,\n                                Integer.parseInt(textMaxLength));\n                        continue;\n                    }\n                }\n                if (locInfoMaxValidTime == null) {\n                    if ((locInfoMaxValidTime = getValueByParamName(\"LocInfoMaxValidTime\",\n                            childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.GEOLOC_EXPIRATION_TIME,\n                                Long.parseLong(locInfoMaxValidTime)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                    }\n                }\n                // Not used: \"geolocPullOpenValue\"\n                // Not used: \"geolocPullApiGwAddress\"\n                // Not used: \"geolocPullBlockTimer\"\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse service provider ext\n     * \n     * @param node Node\n     */\n    private void parseServiceProviderExt(Node node) {\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    if (childnode.getAttributes().getLength() > 0) {\n                        Node typenode = childnode.getAttributes().getNamedItem(\"type\");\n                        if (typenode != null) {\n                            if (typenode.getNodeValue().equalsIgnoreCase(\"joyn\")) {\n                                parseRcs(childnode);\n                            }\n                        }\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse RCS\n     * \n     * @param node Node\n     */\n    private void parseRcs(Node node) {\n        if (node == null) {\n            return;\n        }\n        String msgCapValidity = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    NamedNodeMap attributes = childnode.getAttributes();\n                    if (attributes.getLength() > 0) {\n                        Node typenode = attributes.getNamedItem(\"type\");\n                        if (typenode != null) {\n                            String nodeValue = typenode.getNodeValue();\n                            if (nodeValue.equalsIgnoreCase(\"UX\")) {\n                                parseUx(childnode, ImsServerVersion.JOYN);\n                            } else if (nodeValue.equalsIgnoreCase(\"Messaging\")) {\n                                parseMessaging(childnode);\n                            }\n                        }\n                    }\n                }\n                if (msgCapValidity == null) {\n                    if ((msgCapValidity = getValueByParamName(\"msgCapValidity\", childnode, TYPE_INT)) != null) {\n                        long validity = Long.parseLong(msgCapValidity)\n                                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n                        mRcsSettings.writeLong(RcsSettingsData.MSG_CAP_VALIDITY_PERIOD, validity);\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse Messaging\n     * \n     * @param node Node\n     */\n    private void parseMessaging(Node node) {\n        String ftHTTPCapAlwaysOn = null;\n        String deliveryTimeout = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (ftHTTPCapAlwaysOn == null) {\n                    if ((ftHTTPCapAlwaysOn = getValueByParamName(\"ftHTTPCapAlwaysOn\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.FT_HTTP_CAP_ALWAYS_ON,\n                                !ftHTTPCapAlwaysOn.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (deliveryTimeout == null) {\n                    if ((deliveryTimeout = getValueByParamName(\"deliveryTimeout\", childnode,\n                            TYPE_INT)) != null) {\n                        long timeout = Long.parseLong(deliveryTimeout)\n                                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n                        mRcsSettings.writeLong(RcsSettingsData.MSG_DELIVERY_TIMEOUT, timeout);\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse Ux\n     * \n     * @param node Node\n     * @param isJoyn True if is Joyn\n     */\n    private void parseUx(Node node, ImsServerVersion isJoyn) {\n        String messagingUX = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (messagingUX == null) {\n                    if ((messagingUX = getValueByParamName(\"messagingUX\", childnode, TYPE_INT)) != null) {\n                        if (messagingUX.equals(\"1\")) {\n                            mRcsSettings.setMessagingMode(MessagingMode.INTEGRATED);\n                        } else {\n                            if (ImsServerVersion.JOYN.equals(isJoyn)) {\n                                mRcsSettings.setMessagingMode(MessagingMode.CONVERGED);\n                            } else {\n                                mRcsSettings.setMessagingMode(MessagingMode.SEAMLESS);\n                            }\n                        }\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n        // Not used: oneButtonVoiceCall\n        // Not used: oneButtonVideoCall\n    }\n\n    /**\n     * Parse IM\n     * \n     * @param node Node\n     */\n    private void parseIM(Node node) {\n        String imCapAlwaysOn = null;\n        String ftCapAlwaysOn = null;\n        String imWarnSF = null;\n        String imSessionStart = null;\n        String ftWarnSize = null;\n        String autoAcceptFt = null;\n        String ftHttpCsUri = null;\n        String ftHttpCsUser = null;\n        String ftHttpCsPwd = null;\n        String ftDefaultMech = null;\n        String ftSF = null;\n        String chatAuth = null;\n        String smsFallBackAuth = null;\n        String autoAcceptChat = null;\n        String autoAcceptGroupChat = null;\n        String maxSize1to1 = null;\n        String maxSize1toM = null;\n        String timerIdle = null;\n        String maxSizeFileTransfer = null;\n        String ftThumb = null;\n        String maxAdhocGroupSize = null;\n        String confFctyUri = null;\n        String groupChatSF = null;\n        String groupChatOnlySF = null;\n        String maxConcurrentSession = null;\n        String imMsgTech = null;\n        String firstMessageInvite = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (imCapAlwaysOn == null) {\n                    if ((imCapAlwaysOn = getValueByParamName(\"imCapAlwaysON\", childnode, TYPE_INT)) != null) {\n                        boolean _imCapAlwaysOn = !imCapAlwaysOn.equals(\"0\");\n                        mRcsSettings.writeBoolean(RcsSettingsData.IM_CAPABILITY_ALWAYS_ON,\n                                _imCapAlwaysOn);\n                        // set default IM messaging method if first provisioning\n                        if (mFirst) {\n                            if (_imCapAlwaysOn) {\n                                mRcsSettings.setDefaultMessagingMethod(MessagingMethod.RCS);\n                            } else {\n                                mRcsSettings.setDefaultMessagingMethod(MessagingMethod.AUTOMATIC);\n                            }\n                        }\n                        continue;\n                    }\n                }\n                if (ftCapAlwaysOn == null) {\n                    if ((ftCapAlwaysOn = getValueByParamName(\"ftCapAlwaysON\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.FT_CAPABILITY_ALWAYS_ON,\n                                !ftCapAlwaysOn.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (maxConcurrentSession == null) {\n                    if ((maxConcurrentSession = getValueByParamName(\"MaxConcurrentSession\",\n                            childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_CHAT_SESSIONS,\n                                Integer.parseInt(maxConcurrentSession));\n                        continue;\n                    }\n                }\n                if (groupChatSF == null) {\n                    if ((groupChatSF = getValueByParamName(\"GroupChatFullStandFwd\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_GROUP_CHAT_SF,\n                                !groupChatSF.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (groupChatOnlySF == null) {\n                    if ((groupChatOnlySF = getValueByParamName(\"GroupChatOnlyFStandFwd\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.GROUP_CHAT_INVITE_ONLY_FULL_SF,\n                                !groupChatOnlySF.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (imWarnSF == null) {\n                    if ((imWarnSF = getValueByParamName(\"imWarnSF\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.WARN_SF_SERVICE,\n                                !imWarnSF.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (autoAcceptFt == null) {\n                    if ((autoAcceptFt = getValueByParamName(\"ftAutAccept\", childnode, TYPE_INT)) != null) {\n                        boolean aaModeChangeable = !autoAcceptFt.equals(\"0\");\n                        // Check if first provisioning or transition of MNO setting\n                        if (mFirst\n                                || (aaModeChangeable != mRcsSettings\n                                        .isFtAutoAcceptedModeChangeable())) {\n                            // Save first or new setting value\n                            mRcsSettings.setFtAutoAcceptedModeChangeable(aaModeChangeable);\n                            if (aaModeChangeable) {\n                                // Enforce user settings for AA to default value\n                                // By default, AA is enabled in normal conditions\n                                mRcsSettings.setFileTransferAutoAccepted(true);\n                                // By default, AA is disabled in roaming\n                                mRcsSettings.setFileTransferAutoAcceptedInRoaming(false);\n                            } else {\n                                // Enforce user settings for AA for normal conditions and roaming\n                                mRcsSettings.setFileTransferAutoAccepted(false);\n                                mRcsSettings.setFileTransferAutoAcceptedInRoaming(false);\n                            }\n                        }\n                        continue;\n                    }\n                }\n                if (ftSF == null) {\n                    if ((ftSF = getValueByParamName(\"ftStAndFwEnabled\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_FILE_TRANSFER_SF,\n                                !ftSF.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (ftHttpCsUri == null) {\n                    if ((ftHttpCsUri = getValueByParamName(\"ftHTTPCSURI\", childnode, TYPE_TXT)) != null) {\n                        /*\n                         * According to \"Rich Communication Suite 5.1 Advanced Communications\n                         * Services and Client Specification Version 4.0\" 3.5.4.8.3 File transfer\n                         * procedure 3.5.4.8.3.1 Sender procedures This specification uses the term\n                         * 'HTTP POST' and 'HTTP GET' as a generic reference to the action of using\n                         * the POST or GET method. However, it is strongly recommended that whenever\n                         * the POST action contains sensitive information such as a user ID or\n                         * password, the action should take place over a secure connection and/or\n                         * via HTTPS explicitly.\n                         */\n                        Uri ftHttpServAddr = \"\".equals(ftHttpCsUri) ? null : Uri.parse(ftHttpCsUri);\n                        if (ftHttpServAddr != null\n                                && !PROTOCOL_HTTPS.equals(ftHttpServAddr.getScheme())) {\n                            sLogger.error(ftHttpCsUri\n                                    + \" is not a secure protocol, hence disabling ftHttp capability.\");\n                            continue;\n                        }\n                        mRcsSettings.setFtHttpServer(ftHttpServAddr);\n                        continue;\n                    }\n                }\n                if (ftHttpCsUser == null) {\n                    if ((ftHttpCsUser = getValueByParamName(\"ftHTTPCSUser\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setFtHttpLogin(\"\".equals(ftHttpCsUser) ? null : ftHttpCsUser);\n                        continue;\n                    }\n                }\n                if (ftHttpCsPwd == null) {\n                    if ((ftHttpCsPwd = getValueByParamName(\"ftHTTPCSPwd\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setFtHttpPassword(\"\".equals(ftHttpCsPwd) ? null : ftHttpCsPwd);\n                        continue;\n                    }\n                }\n                if (ftDefaultMech == null) {\n                    if ((ftDefaultMech = getValueByParamName(\"ftDefaultMech\", childnode, TYPE_TXT)) != null) {\n                        FileTransferProtocol protocol = FileTransferProtocol.valueOf(ftDefaultMech);\n                        mRcsSettings.setFtProtocol(protocol);\n                        continue;\n                    }\n                }\n                if (imSessionStart == null) {\n                    if ((imSessionStart = getValueByParamName(\"imSessionStart\", childnode, TYPE_INT)) != null) {\n                        ImSessionStartMode mode = ImSessionStartMode.valueOf(Integer\n                                .parseInt(imSessionStart));\n                        mRcsSettings.setImSessionStartMode(mode);\n                        continue;\n                    }\n                }\n                if (ftWarnSize == null) {\n                    if ((ftWarnSize = getValueByParamName(\"ftWarnSize\", childnode, TYPE_INT)) != null) {\n                        long size = Long.parseLong(ftWarnSize) * 1024L;\n                        mRcsSettings.setWarningMaxFileTransferSize(size);\n                        continue;\n                    }\n                }\n                if (chatAuth == null) {\n                    if ((chatAuth = getValueByParamName(\"ChatAuth\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_IM_SESSION,\n                                !chatAuth.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (smsFallBackAuth == null) {\n                    if ((smsFallBackAuth = getValueByParamName(\"SmsFallBackAuth\", childnode,\n                            TYPE_INT)) != null) {\n                        // Careful:\n                        // 0- Indicates authorization is ok\n                        // 1- Indicates authorization is non ok\n                        mRcsSettings.writeBoolean(RcsSettingsData.SMS_FALLBACK_SERVICE,\n                                smsFallBackAuth.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (autoAcceptChat == null) {\n                    if ((autoAcceptChat = getValueByParamName(\"AutAccept\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.AUTO_ACCEPT_CHAT,\n                                !autoAcceptChat.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (autoAcceptGroupChat == null) {\n                    if ((autoAcceptGroupChat = getValueByParamName(\"AutAcceptGroupChat\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.AUTO_ACCEPT_GROUP_CHAT,\n                                !autoAcceptGroupChat.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (maxSize1to1 == null) {\n                    if ((maxSize1to1 = getValueByParamName(\"MaxSize1to1\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_CHAT_MSG_LENGTH,\n                                Integer.parseInt(maxSize1to1));\n                        continue;\n                    }\n                }\n                if (maxSize1toM == null) {\n                    if ((maxSize1toM = getValueByParamName(\"MaxSize1toM\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_GROUPCHAT_MSG_LENGTH,\n                                Integer.parseInt(maxSize1toM));\n                        continue;\n                    }\n                }\n                if (timerIdle == null) {\n                    if ((timerIdle = getValueByParamName(\"TimerIdle\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings\n                                .writeLong(RcsSettingsData.CHAT_IDLE_DURATION,\n                                        Long.parseLong(timerIdle)\n                                                * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                        continue;\n                    }\n                }\n                if (maxSizeFileTransfer == null) {\n                    if ((maxSizeFileTransfer = getValueByParamName(\"MaxSizeFileTr\", childnode,\n                            TYPE_INT)) != null) {\n                        long size = Long.parseLong(maxSizeFileTransfer) * 1024L;\n                        mRcsSettings.setMaxFileTransferSize(size);\n                        continue;\n                    }\n                }\n                if (ftThumb == null) {\n                    if ((ftThumb = getValueByParamName(\"ftThumb\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(\n                                RcsSettingsData.CAPABILITY_FILE_TRANSFER_THUMBNAIL,\n                                !ftThumb.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (maxAdhocGroupSize == null) {\n                    if ((maxAdhocGroupSize = getValueByParamName(\"max_adhoc_group_size\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_CHAT_PARTICIPANTS,\n                                Integer.parseInt(maxAdhocGroupSize));\n                        continue;\n                    }\n                }\n                if (confFctyUri == null) {\n                    if ((confFctyUri = getValueByParamName(\"conf-fcty-uri\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setImConferenceUri(\"\".equals(confFctyUri) ? null\n                                : formatSipUri(confFctyUri.trim()));\n                        continue;\n                    }\n                }\n                if (imMsgTech == null) {\n                    if ((imMsgTech = getValueByParamName(\"imMsgTech\", childnode, TYPE_INT)) != null) {\n                        ImMsgTech value = ImMsgTech.valueOf(Integer.parseInt(imMsgTech));\n                        mRcsSettings.setImMsgTech(value);\n                        continue;\n                    }\n                }\n                if (firstMessageInvite == null) {\n                    if ((firstMessageInvite = getValueByParamName(\"firstMsgInvite\", childnode,\n                            TYPE_INT)) != null) {\n                        boolean isFirstMessageInvite = !firstMessageInvite.equals(\"0\");\n                        /*\n                         * Stack only support simple IM now, means isFirstMessageInvite must be set\n                         * to true. Specification reference: Rich Communication Suite 5.1 Advanced\n                         * Communications Services and Client Specification Version 3.0 Page 182\n                         * 3.3.4.2 Technical Realization of 1-to-1 Chat features when using OMA\n                         * SIMPLE IM For OMA SIMPLE IM, first message is always included in a\n                         * CPIM/IMDN wrapper carried in the SIP INVITE request. So the configuration\n                         * parameter FIRST MSG IN INVITE defined in Table 77 is always set to 1. A\n                         * client should always include \"positive-delivery\" in the value for the\n                         * Disposition-Notification header field in that message. That means that\n                         * the value of the header field is either \"positive-delivery\" or\n                         * \"positive-delivery,display\" depending on whether display notifications\n                         * were requested. The value of \"negativedelivery\" is not used in RCS for\n                         * 1-to-1 Chat. SIP INVITE requests for a one-to-one session that carry a\n                         * message in CPIM/IMDN wrapper shall be rejected by the server unless they\n                         * carry a Disposition-Notification header that at least includes\n                         * \"positivedelivery\".\n                         */\n                        if (!isFirstMessageInvite) {\n                            sLogger.error(\"isFirstMessageInInvite is set to false, it is incorrect according\"\n                                    + \" to Blackbird protocol, please check provisioning values. Ignoring the \"\n                                    + \"set to false request.\");\n                            continue;\n                        }\n                        mRcsSettings.setFirstMessageInInvite(isFirstMessageInvite);\n                    }\n                }\n                // Not used for RCS: \"pres-srv-cap\"\n                // Not used for RCS: \"deferred-msg-func-uri\"\n                // Not used for RCS: \"exploder-uri\"\n\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse capability discovery\n     * \n     * @param node Node\n     */\n    private void parseCapabilityDiscovery(Node node) {\n        String pollingPeriod = null;\n        String capInfoExpiry = null;\n        String presenceDiscovery = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    NamedNodeMap attributes = childnode.getAttributes();\n                    if (attributes.getLength() > 0) {\n                        Node typenode = attributes.getNamedItem(\"type\");\n                        if (typenode != null) {\n                            if (typenode.getNodeValue().equalsIgnoreCase(\"Ext\")) {\n                                parseExt(childnode);\n                            }\n                        }\n                    }\n                }\n                if (pollingPeriod == null) {\n                    if ((pollingPeriod = getValueByParamName(\"pollingPeriod\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.CAPABILITY_POLLING_PERIOD,\n                                Long.parseLong(pollingPeriod)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                        continue;\n                    }\n                }\n                if (capInfoExpiry == null) {\n                    if ((capInfoExpiry = getValueByParamName(\"capInfoExpiry\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.CAPABILITY_EXPIRY_TIMEOUT,\n                                Long.parseLong(capInfoExpiry)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                        continue;\n                    }\n                }\n                if (presenceDiscovery == null) {\n                    if ((presenceDiscovery = getValueByParamName(\"presenceDisc\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.CAPABILITY_PRESENCE_DISCOVERY,\n                                !presenceDiscovery.equals(\"0\"));\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse APN\n     * \n     * @param node Node\n     */\n    private void parseAPN(Node node) {\n        // Not supported: \"rcseOnlyAPN\"\n        String enableRcseSwitch = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (enableRcseSwitch == null) {\n                    if ((enableRcseSwitch = getValueByParamName(\"enableRcseSwitch\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.setEnableRcseSwitch(EnableRcseSwitch.valueOf(Integer\n                                .valueOf(enableRcseSwitch)));\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse transport protocol\n     * \n     * @param node Node\n     */\n    private void parseTransportProtocol(Node node) {\n        String psSignalling = null;\n        String psMedia = null;\n        String psRtMedia = null;\n        String wifiSignalling = null;\n        String wifiMedia = null;\n        String wifiRtMedia = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (psSignalling == null) {\n                    if ((psSignalling = getValueByParamName(\"psSignalling\", childnode, TYPE_TXT)) != null) {\n                        if (psSignalling.equals(\"SIPoUDP\")) {\n                            mRcsSettings.writeString(\n                                    RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_MOBILE,\n                                    ListeningPoint.UDP);\n                        } else if (psSignalling.equals(\"SIPoTCP\")) {\n                            mRcsSettings.writeString(\n                                    RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_MOBILE,\n                                    ListeningPoint.TCP);\n                        } else if (psSignalling.equals(\"SIPoTLS\")) {\n                            mRcsSettings.writeString(\n                                    RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_MOBILE,\n                                    ListeningPoint.TLS);\n                        }\n                        continue;\n                    }\n                }\n                if (wifiSignalling == null) {\n                    if ((wifiSignalling = getValueByParamName(\"wifiSignalling\", childnode, TYPE_TXT)) != null) {\n                        if (wifiSignalling.equals(\"SIPoUDP\")) {\n                            mRcsSettings.writeString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_WIFI,\n                                    ListeningPoint.UDP);\n                        } else if (wifiSignalling.equals(\"SIPoTCP\")) {\n                            mRcsSettings.writeString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_WIFI,\n                                    ListeningPoint.TCP);\n                        } else if (wifiSignalling.equals(\"SIPoTLS\")) {\n                            mRcsSettings.writeString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_WIFI,\n                                    ListeningPoint.TLS);\n                        }\n                        continue;\n                    }\n                }\n                if (wifiMedia == null) {\n                    if ((wifiMedia = getValueByParamName(\"wifiMedia\", childnode, TYPE_TXT)) != null) {\n                        if (wifiMedia.equals(\"MSRP\")) {\n                            mRcsSettings.writeBoolean(RcsSettingsData.SECURE_MSRP_OVER_WIFI, false);\n                        } else if (wifiMedia.equals(\"MSRPoTLS\")) {\n                            mRcsSettings.writeBoolean(RcsSettingsData.SECURE_MSRP_OVER_WIFI, true);\n                        }\n                        continue;\n                    }\n                }\n                if (wifiRtMedia == null) {\n                    if ((wifiRtMedia = getValueByParamName(\"wifiRTMedia\", childnode, TYPE_TXT)) != null) {\n                        if (\"RTP\".equals(wifiMedia)) {\n                            mRcsSettings.writeBoolean(RcsSettingsData.SECURE_RTP_OVER_WIFI, false);\n                        } else if (\"SRTP\".equals(wifiMedia)) {\n                            mRcsSettings.writeBoolean(RcsSettingsData.SECURE_RTP_OVER_WIFI, true);\n                        }\n                    }\n                }\n                if (psMedia == null) {\n                    if ((psMedia = getValueByParamName(\"psMedia\", childnode, TYPE_TXT)) != null) {\n                        if (\"MSRP\".equals(psMedia)) {\n                            mRcsSettings.writeBoolean(RcsSettingsData.SECURE_MSRP_OVER_MOBILE,\n                                    false);\n                        } else if (\"MSRPoTLS\".equals(psMedia)) {\n                            mRcsSettings\n                                    .writeBoolean(RcsSettingsData.SECURE_MSRP_OVER_MOBILE, true);\n                        }\n                        continue;\n                    }\n                }\n                if (psRtMedia == null) {\n                    if ((psRtMedia = getValueByParamName(\"psRTMedia\", childnode, TYPE_TXT)) != null) {\n                        if (\"RTP\".equals(psRtMedia)) {\n                            mRcsSettings\n                                    .writeBoolean(RcsSettingsData.SECURE_RTP_OVER_MOBILE, false);\n                        } else if (\"SRTP\".equals(psRtMedia)) {\n                            mRcsSettings.writeBoolean(RcsSettingsData.SECURE_RTP_OVER_MOBILE, true);\n                        }\n                    }\n                }\n\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse other\n     * \n     * @param node Node\n     */\n    private void parseOther(Node node) {\n        String endUserConfReqId = null;\n        String deviceID = null;\n        String uuidValue = null;\n        String aaIPCallBreakOut = null;\n        String csIPCallBreakOut = null;\n        String rcsIPVideoCallUpgradeFromCS = null;\n        String rcsIPVideoCallUpgradeOnCapError = null;\n        String beIPVideoCallUpgradeAttemptEarly = null;\n        String maxMsrpLengthExtensions = null;\n        String callComposerTimerIdle = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    if (childnode.getAttributes().getLength() > 0) {\n                        Node typenode = childnode.getAttributes().getNamedItem(\"type\");\n                        if (typenode != null) {\n                            if (typenode.getNodeValue().equalsIgnoreCase(\"transportProto\")) {\n                                parseTransportProtocol(childnode);\n                            }\n                        }\n                    }\n                }\n                if (endUserConfReqId == null) {\n                    if ((endUserConfReqId = getValueByParamName(\"endUserConfReqId\", childnode,\n                            TYPE_TXT)) != null) {\n                        mRcsSettings\n                                .setEndUserConfirmationRequestUri(\"\".equals(endUserConfReqId) ? null\n                                        : formatSipUri(endUserConfReqId.trim()));\n                        continue;\n                    }\n                }\n                if (deviceID == null) {\n                    if ((deviceID = getValueByParamName(\"deviceID\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.USE_IMEI_AS_DEVICE_ID,\n                                deviceID.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (uuidValue == null) {\n                    if ((uuidValue = getValueByParamName(UUID_VALUE, childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.writeString(RcsSettingsData.UUID, \"\".equals(uuidValue) ? null\n                                : uuidValue);\n                        continue;\n                    }\n                }\n                if (aaIPCallBreakOut == null) {\n                    if ((aaIPCallBreakOut = getValueByParamName(\"IPCallBreakOut\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.IPVOICECALL_BREAKOUT_AA,\n                                aaIPCallBreakOut.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (csIPCallBreakOut == null) {\n                    if ((csIPCallBreakOut = getValueByParamName(\"IPCallBreakOutCS\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.IPVOICECALL_BREAKOUT_CS,\n                                csIPCallBreakOut.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (rcsIPVideoCallUpgradeFromCS == null) {\n                    if ((rcsIPVideoCallUpgradeFromCS = getValueByParamName(\n                            \"rcsIPVideoCallUpgradeFromCS\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.IPVIDEOCALL_UPGRADE_FROM_CS,\n                                rcsIPVideoCallUpgradeFromCS.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (rcsIPVideoCallUpgradeOnCapError == null) {\n                    if ((rcsIPVideoCallUpgradeOnCapError = getValueByParamName(\n                            \"rcsIPVideoCallUpgradeOnCapError\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.IPVIDEOCALL_UPGRADE_ON_CAPERROR,\n                                rcsIPVideoCallUpgradeOnCapError.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (beIPVideoCallUpgradeAttemptEarly == null) {\n                    if ((beIPVideoCallUpgradeAttemptEarly = getValueByParamName(\n                            \"rcsIPVideoCallUpgradeAttemptEarly\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(\n                                RcsSettingsData.IPVIDEOCALL_UPGRADE_ATTEMPT_EARLY,\n                                beIPVideoCallUpgradeAttemptEarly.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (maxMsrpLengthExtensions == null) {\n                    if ((maxMsrpLengthExtensions = getValueByParamName(\"extensionsMaxMSRPSize\",\n                            childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.MAX_MSRP_SIZE_EXTENSIONS,\n                                Integer.parseInt(maxMsrpLengthExtensions));\n                        continue;\n                    }\n                }\n                if (callComposerTimerIdle == null) {\n                    if ((callComposerTimerIdle = getValueByParamName(\"callComposerTimerIdle\",\n                            childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeInteger(RcsSettingsData.CALL_COMPOSER_INACTIVITY_TIMEOUT,\n                                Integer.parseInt(maxMsrpLengthExtensions));\n                    }\n                }\n                // Not supported: \"WarnSizeImageShare\"\n            } while ((childnode = childnode.getNextSibling()) != null);\n            /**\n             * Check if UUID value is still null at this point. If NULL,then generate it as per\n             * RFC4122, section 4.2.\n             */\n            if (uuidValue == null) {\n                mRcsSettings.writeString(RcsSettingsData.UUID, DeviceUtils.generateUUID()\n                        .toString());\n            }\n        }\n    }\n\n    /**\n     * Parse connection reference\n     * \n     * @param node Node\n     */\n    private void parseConRefs(Node node) {\n        String conRef = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n\n        if (childnode != null) {\n            do {\n                if (conRef == null) {\n                    if ((conRef = getValueByParamName(\"ConRef\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.writeString(RcsSettingsData.RCS_APN, \"\".equals(conRef) ? null\n                                : conRef);\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse public user identity\n     * \n     * @param node Node\n     */\n    private void parsePublicUserIdentity(Node node) {\n        String publicUserIdentity = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (publicUserIdentity == null) {\n                    if ((publicUserIdentity = getValueByParamName(\"Public_User_Identity\",\n                            childnode, TYPE_TXT)) != null) {\n                        String username = extractUserNamePart(publicUserIdentity.trim());\n                        PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(username);\n                        if (number == null) {\n                            if (sLogger.isActivated()) {\n                                sLogger.error(\"Invalid public user identity '\" + username + \"'\");\n                            }\n                            mRcsSettings.setUserProfileImsUserName(null);\n                        } else {\n                            ContactId contact = ContactUtil\n                                    .createContactIdFromValidatedData(number);\n                            mRcsSettings.setUserProfileImsUserName(contact);\n                        }\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse the secondary device parameter\n     * \n     * @param node Node\n     */\n    private void parseSecondaryDevicePar(Node node) {\n        // TODO: to be managed thks to a flag main/secondary device\n        /*\n         * String voiceCall = null; String chat = null; String sendSms = null; String fileTranfer =\n         * null; String videoShare = null; String imageShare = null; String geolocPush = null; if\n         * (node == null) { return; } Node childnode = node.getFirstChild(); if (childnode != null)\n         * { do { if (chat == null) { if ((chat = getValueByParamName(\"Chat\", childnode, TYPE_INT))\n         * != null) { if (chat.equals(\"0\")) { mRcsSettings.writeParameter(\n         * RcsSettingsData.CAPABILITY_IM_SESSION, RcsSettingsData.TRUE); } else {\n         * mRcsSettings.writeParameter( RcsSettingsData.CAPABILITY_IM_SESSION,\n         * RcsSettingsData.FALSE); } continue; } } if (fileTranfer == null) { if ((fileTranfer =\n         * getValueByParamName(\"FileTranfer\", childnode, TYPE_INT)) != null) { if\n         * (fileTranfer.equals(\"0\")) { mRcsSettings.writeParameter(\n         * RcsSettingsData.CAPABILITY_FILE_TRANSFER, RcsSettingsData.TRUE); } else {\n         * mRcsSettings.writeParameter( RcsSettingsData.CAPABILITY_FILE_TRANSFER,\n         * RcsSettingsData.FALSE); } continue; } } if (videoShare == null) { if ((videoShare =\n         * getValueByParamName(\"VideoShare\", childnode, TYPE_INT)) != null) { if\n         * (videoShare.equals(\"0\")) { mRcsSettings.writeParameter(\n         * RcsSettingsData.CAPABILITY_VIDEO_SHARING, RcsSettingsData.TRUE); } else {\n         * mRcsSettings.writeParameter( RcsSettingsData.CAPABILITY_VIDEO_SHARING,\n         * RcsSettingsData.FALSE); } continue; } } if (imageShare == null) { if ((imageShare =\n         * getValueByParamName(\"ImageShare\", childnode, TYPE_INT)) != null) { if\n         * (imageShare.equals(\"0\")) { mRcsSettings.writeParameter(\n         * RcsSettingsData.CAPABILITY_IMAGE_SHARING, RcsSettingsData.TRUE); } else {\n         * mRcsSettings.writeParameter( RcsSettingsData.CAPABILITY_IMAGE_SHARING,\n         * RcsSettingsData.FALSE); } continue; } } if (geolocPush == null) { if ((geolocPush =\n         * getValueByParamName(\"GeoLocPush\", childnode, TYPE_INT)) != null) { if\n         * (geolocPush.equals(\"0\")) { mRcsSettings.writeParameter(\n         * RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH, RcsSettingsData.TRUE); } else {\n         * mRcsSettings.writeParameter( RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH,\n         * RcsSettingsData.FALSE); } continue; } } // Not used for RCS: \"SendSms\" // Not used for\n         * RCS: \"VoiceCall\" } while ((childnode = childnode.getNextSibling()) != null); }\n         */\n    }\n\n    /**\n     * Parse ext\n     * \n     * @param node Node\n     */\n    private void parseExt(Node node) {\n        String intUrlFmt = null;\n        String maxSizeImageShare = null;\n        String maxTimeVideoShare = null;\n        String maxTimeAudiomessage = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    if (childnode.getAttributes().getLength() > 0) {\n                        Node typenode = childnode.getAttributes().getNamedItem(\"type\");\n                        if (typenode != null) {\n                            String nodeValue = typenode.getNodeValue();\n                            if (nodeValue.equalsIgnoreCase(\"SecondaryDevicePar\")) {\n                                parseSecondaryDevicePar(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"joyn\")) {\n                                parseRcs(childnode);\n                            }\n                        }\n                    }\n                }\n                if (intUrlFmt == null) {\n                    if ((intUrlFmt = getValueByParamName(\"IntUrlFmt\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.TEL_URI_FORMAT,\n                                intUrlFmt.equals(\"0\"));\n                        continue;\n                    }\n                }\n                if (maxSizeImageShare == null) {\n                    if ((maxSizeImageShare = getValueByParamName(\"MaxSizeImageShare\", childnode,\n                            TYPE_INT)) != null) {\n                        long size = Long.parseLong(maxSizeImageShare);\n                        mRcsSettings.setMaxImageSharingSize(size);\n                        continue;\n                    }\n                }\n                if (maxTimeVideoShare == null) {\n                    if ((maxTimeVideoShare = getValueByParamName(\"MaxTimeVideoShare\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.MAX_VIDEO_SHARE_DURATION,\n                                Long.parseLong(maxTimeVideoShare)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                        continue;\n                    }\n                }\n                if (maxTimeAudiomessage == null) {\n                    if ((maxTimeAudiomessage = getValueByParamName(\"MaxTimeAudioMessage\",\n                            childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.MAX_AUDIO_MESSAGE_DURATION,\n                                Long.parseLong(maxTimeAudiomessage)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                    }\n                }\n                // Not used (all number are formatted in international format): \"NatUrlFmt\"\n                // Not supported: \"Q-Value\"\n\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse ICSI\n     * \n     * @param node Node\n     */\n    private void parseICSI(Node node) {\n        // Not used for RCS: \"ICSI\"\n        // Not used for RCS: \"ICSI_Resource_Allocation_Mode\"\n    }\n\n    /**\n     * Parse PCSCF address\n     * \n     * @param node Node\n     */\n    private void parsePcscfAddress(Node node) {\n        String addr = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (addr == null) {\n                    if ((addr = getValueByParamName(\"Address\", childnode, TYPE_TXT)) != null) {\n                        String[] address = addr.split(\":\");\n                        String proxyAddr = address[0];\n                        mRcsSettings.setImsProxyAddrForMobile(\"\".equals(proxyAddr) ? null\n                                : proxyAddr);\n                        mRcsSettings\n                                .setImsProxyAddrForWifi(\"\".equals(proxyAddr) ? null : proxyAddr);\n                        if (address.length > 1) {\n                            int port = Integer.valueOf(address[1]);\n                            mRcsSettings.setImsProxyPortForMobile(port);\n                            mRcsSettings.setImsProxyPortForWifi(port);\n                        }\n                    }\n                }\n                // Not used: \"AddressType\"\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse phone context\n     * \n     * @param node Node\n     */\n    private void parsePhoneContextList(Node node) {\n        // Not used: \"PhoneContext\"\n        // Not used: \"Public_user_identity\"\n    }\n\n    /**\n     * Parse application authentication\n     * \n     * @param node Node\n     */\n    private void parseAppAuthent(Node node) {\n        String authType = null;\n        String realm = null;\n        String userName = null;\n        String userPwd = null;\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (authType == null) {\n                    if ((authType = getValueByParamName(\"AuthType\", childnode, TYPE_TXT)) != null) {\n                        if (authType.equals(\"EarlyIMS\")) {\n                            mRcsSettings\n                                    .setImsAuthenticationProcedureForMobile(AuthenticationProcedure.GIBA);\n                        } else {\n                            mRcsSettings\n                                    .setImsAuthenticationProcedureForMobile(AuthenticationProcedure.DIGEST);\n                        }\n                        continue;\n                    }\n                }\n                if (realm == null) {\n                    if ((realm = getValueByParamName(\"Realm\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setUserProfileImsRealm(\"\".equals(realm) ? null : realm);\n                        continue;\n                    }\n                }\n                if (userName == null) {\n                    if ((userName = getValueByParamName(\"UserName\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setUserProfileImsPrivateId(\"\".equals(userName) ? null\n                                : userName);\n                        continue;\n                    }\n                }\n                if (userPwd == null) {\n                    if ((userPwd = getValueByParamName(\"UserPwd\", childnode, TYPE_TXT)) != null) {\n                        mRcsSettings.setUserProfileImsPassword(\"\".equals(userPwd) ? null : userPwd);\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse RCSe settings\n     * \n     * @param node Node\n     */\n    private void parseRCSe(Node node) {\n        if (node == null) {\n            return;\n        }\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    NamedNodeMap attributes = childnode.getAttributes();\n                    if (attributes.getLength() > 0) {\n                        Node typenode = attributes.getNamedItem(\"type\");\n                        if (typenode != null) {\n                            String nodeValue = typenode.getNodeValue();\n                            if (nodeValue.equalsIgnoreCase(\"IMS\")) {\n                                parseIMS(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"PRESENCE\")) {\n                                parsePresence(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"XDMS\")) {\n                                parseXDMS(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"IM\")) {\n                                parseIM(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"CAPDISCOVERY\")) {\n                                parseCapabilityDiscovery(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"APN\")) {\n                                parseAPN(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"OTHER\")) {\n                                parseOther(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"SERVICES\")) {\n                                parseServices(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"SUPL\")) {\n                                parseSupl(childnode);\n                            } else if (nodeValue.equalsIgnoreCase(\"SERVICEPROVIDEREXT\")) {\n                                parseServiceProviderExt(childnode);\n                            }\n                        }\n                    }\n                }\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Parse IMS settings\n     * \n     * @param node IMS settings node\n     */\n    private void parseIMS(Node node) {\n        String timert1 = null;\n        String timert2 = null;\n        String timert4 = null;\n        String privateUserIdentity = null;\n        String homeDomain = null;\n        String keepAliveEnabled = null;\n        String regRetryBasetime = null;\n        String regRetryMaxtime = null;\n        Node childnode = node.getFirstChild();\n        if (childnode != null) {\n            do {\n                if (childnode.getNodeName().equals(\"characteristic\")) {\n                    if (childnode.getAttributes().getLength() > 0) {\n                        Node typenode = childnode.getAttributes().getNamedItem(\"type\");\n                        if (typenode != null) {\n                            if (typenode.getNodeValue().equalsIgnoreCase(\"ConRefs\")) {\n                                parseConRefs(childnode);\n                            } else if (typenode.getNodeValue().equalsIgnoreCase(\n                                    \"Public_user_identity_List\")) {\n                                parsePublicUserIdentity(childnode);\n                            } else if (typenode.getNodeValue().equalsIgnoreCase(\"Ext\")) {\n                                parseExt(childnode);\n                            } else if (typenode.getNodeValue().equalsIgnoreCase(\"ICSI_List\")) {\n                                parseICSI(childnode);\n                            } else if (typenode.getNodeValue().equalsIgnoreCase(\n                                    \"LBO_P-CSCF_Address\")) {\n                                parsePcscfAddress(childnode);\n                            } else if (typenode.getNodeValue()\n                                    .equalsIgnoreCase(\"PhoneContext_List\")) {\n                                parsePhoneContextList(childnode);\n                            } else if (typenode.getNodeValue().equalsIgnoreCase(\"APPAUTH\")) {\n                                parseAppAuthent(childnode);\n                            }\n                        }\n                    }\n                }\n                if (timert1 == null) {\n                    if ((timert1 = getValueByParamName(\"Timer_T1\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.SIP_TIMER_T1,\n                                Long.parseLong(timert1));\n                        continue;\n                    }\n                }\n                if (timert2 == null) {\n                    if ((timert2 = getValueByParamName(\"Timer_T2\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.SIP_TIMER_T2,\n                                Long.parseLong(timert2));\n                        continue;\n                    }\n                }\n                if (timert4 == null) {\n                    if ((timert4 = getValueByParamName(\"Timer_T4\", childnode, TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.SIP_TIMER_T4,\n                                Long.parseLong(timert4));\n                        continue;\n                    }\n                }\n                if (privateUserIdentity == null) {\n                    if ((privateUserIdentity = getValueByParamName(\"Private_User_Identity\",\n                            childnode, TYPE_TXT)) != null) {\n                        mRcsSettings\n                                .setUserProfileImsPrivateId(\"\".equals(privateUserIdentity) ? null\n                                        : privateUserIdentity);\n                        continue;\n                    }\n                }\n                if (homeDomain == null) {\n                    if ((homeDomain = getValueByParamName(\"Home_network_domain_name\", childnode,\n                            TYPE_TXT)) != null) {\n                        mRcsSettings.setUserProfileImsDomain(\"\".equals(homeDomain) ? null\n                                : homeDomain);\n                        continue;\n                    }\n                }\n                if (keepAliveEnabled == null) {\n                    if ((keepAliveEnabled = getValueByParamName(\"Keep_Alive_Enabled\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeBoolean(RcsSettingsData.SIP_KEEP_ALIVE,\n                                keepAliveEnabled.equals(\"1\"));\n                        continue;\n                    }\n                }\n                if (regRetryBasetime == null) {\n                    if ((regRetryBasetime = getValueByParamName(\"RegRetryBaseTime\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.REGISTER_RETRY_BASE_TIME,\n                                Long.parseLong(regRetryBasetime)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                        continue;\n                    }\n                }\n                if (regRetryMaxtime == null) {\n                    if ((regRetryMaxtime = getValueByParamName(\"RegRetryMaxTime\", childnode,\n                            TYPE_INT)) != null) {\n                        mRcsSettings.writeLong(RcsSettingsData.REGISTER_RETRY_MAX_TIME,\n                                Long.parseLong(regRetryMaxtime)\n                                        * SECONDS_TO_MILLISECONDS_CONVERSION_RATE);\n                    }\n                }\n                // Not supported under Android: \"PDP_ContextOperPref\"\n                // Not used for RCS: \"Voice_Domain_Preference_E_UTRAN\"\n                // Not used for RCS: \"SMS_Over_IP_Networks_Indication\"\n                // Not used for RCS: \"Voice_Domain_Preference_UTRAN\"\n                // Not used for RCS: \"Mobility_Management_IMS_Voice_Termination\"\n            } while ((childnode = childnode.getNextSibling()) != null);\n        }\n    }\n\n    /**\n     * Get value of a parameter\n     * \n     * @param paramName Parameter name\n     * @param node Node\n     * @param type Parameter type\n     * @return Value or null\n     */\n    private String getValueByParamName(String paramName, Node node, int type) {\n        if ((node == null)\n                || !(node.getNodeName().equals(\"parm\") || node.getNodeName().equals(\"param\"))) {\n            return null;\n        }\n        if (node.getAttributes().getLength() > 0) {\n            Node nameNode = node.getAttributes().getNamedItem(\"name\");\n            if (nameNode == null) {\n                return null;\n            }\n            Node valueNode = node.getAttributes().getNamedItem(\"value\");\n            if (valueNode == null) {\n                return null;\n            }\n            if (nameNode.getNodeValue().equalsIgnoreCase(paramName)) {\n                String value = valueNode.getNodeValue();\n                // Check type\n                if (type == TYPE_INT) {\n                    try {\n                        Integer.parseInt(value);\n\n                    } catch (NumberFormatException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.warn(\"Bad value for integer parameter \" + paramName);\n                        }\n                        return null;\n                    }\n                }\n                return value;\n            }\n            return null;\n        }\n        return null;\n    }\n\n    /**\n     * Extract the username part of the SIP-URI\n     * \n     * @param uri SIP-URI\n     * @return Username\n     */\n    private String extractUserNamePart(String uri) {\n        int indexOfSipHeader = uri.indexOf(PhoneUtils.SIP_URI_HEADER);\n        if (indexOfSipHeader != -1) {\n            int startIndexOfUriAddress = uri.indexOf(\"@\", indexOfSipHeader);\n            return uri.substring(indexOfSipHeader + PhoneUtils.SIP_URI_HEADER.length(),\n                    startIndexOfUriAddress);\n        }\n        return uri;\n    }\n\n    /**\n     * Format to SIP-URI\n     * \n     * @param path Sip Uri path\n     * @return SIP-URI\n     */\n    private Uri formatSipUri(String path) {\n        return path.startsWith(PhoneUtils.SIP_URI_HEADER) ? Uri.parse(path) : Uri\n                .parse(PhoneUtils.SIP_URI_HEADER + path);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/TermsAndConditionsRequest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.addressbook.RcsAccountManager;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.provisioning.ProvisioningInfo.Version;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.app.Activity;\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.TextView;\n\n/**\n * Show the request for terms and conditions\n * \n * @author hlxn7157\n */\npublic class TermsAndConditionsRequest extends Activity {\n\n    private static final Logger sLogger = Logger.getLogger(TermsAndConditionsRequest.class\n            .getSimpleName());\n\n    private static final int TC_NOTIFICATION_ID = 1;\n    private static final String TC_NOTIFICATION_TAG = TermsAndConditionsRequest.class\n            .getSimpleName();\n\n    private String mMessage;\n\n    private String mTitle;\n\n    private RcsSettings mRcsSettings;\n\n    private LocalContentResolver mLocalContentResolver;\n\n    private ContactManager mContactManager;\n\n    private MessagingLog mMessaginLog;\n\n    private Context mContext;\n\n    @Override\n    public void onCreate(Bundle savedInstance) {\n        super.onCreate(savedInstance);\n\n        mContext = getApplicationContext();\n        ContentResolver contentResolver = mContext.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(contentResolver);\n        mRcsSettings = RcsSettings.getInstance(mLocalContentResolver);\n        mMessaginLog = MessagingLog.getInstance(mLocalContentResolver, mRcsSettings);\n        mContactManager = ContactManager.getInstance(mContext, contentResolver,\n                mLocalContentResolver, mRcsSettings);\n\n        setContentView(R.layout.rcs_terms_and_conditions);\n        setFinishOnTouchOutside(false);\n        mMessage = mRcsSettings.getProvisioningUserMessageContent();\n        mTitle = mRcsSettings.getProvisioningUserMessageTitle();\n        boolean accept_btn = mRcsSettings.isProvisioningAcceptButton();\n        boolean reject_btn = mRcsSettings.isProvisioningRejectButton();\n\n        Button okButton = (Button) findViewById(R.id.ok_button);\n        Button cancelButton = (Button) findViewById(R.id.cancel_button);\n        TextView titleText = (TextView) findViewById(R.id.title);\n        TextView messageText = (TextView) findViewById(R.id.message);\n\n        if (mTitle != null) {\n            titleText.setText(mTitle);\n        }\n        if (mMessage != null) {\n            messageText.setText(mMessage);\n        }\n\n        /*\n         * If both accept and reject are enabled then creates alert dialog with two buttons else\n         * with neutral button.\n         */\n        if (accept_btn && reject_btn) {\n            okButton.setOnClickListener(new OnClickListener() {\n\n                @Override\n                public void onClick(View v) {\n                    acceptTermsAndConditions();\n                }\n            });\n\n            cancelButton.setOnClickListener(new OnClickListener() {\n\n                @Override\n                public void onClick(View v) {\n                    declineTermsAndConditions();\n                }\n            });\n\n        } else {\n            cancelButton.setVisibility(View.GONE);\n            okButton.setText(R.string.rcs_core_terms_ok);\n            okButton.setOnClickListener(new OnClickListener() {\n\n                @Override\n                public void onClick(View v) {\n                    acceptTermsAndConditions();\n                    finish();\n                }\n            });\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        cancelTermsAndConditionsNotification(this);\n        super.onResume();\n    }\n\n    @Override\n    public void onPause() {\n        if (!isFinishing() && !isChangingConfigurations()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Terms and conditions windows closed\");\n            }\n            showTermsAndConditionsNotification();\n        }\n        super.onPause();\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"User discards terms and conditions\");\n        }\n        showTermsAndConditionsNotification();\n        super.onBackPressed();\n    }\n\n    private void declineTermsAndConditions() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"User declines terms and conditions\");\n        }\n        /*\n         * If the user declines the terms or does not answer, the RCS service is stopped and the RCS\n         * configuration is reset.\n         */\n        LauncherUtils.stopRcsService(mContext);\n        LauncherUtils.resetRcsConfig(mContext, mLocalContentResolver, mRcsSettings, mMessaginLog,\n                mContactManager);\n        mRcsSettings.setTermsAndConditionsResponse(TermsAndConditionsResponse.DECLINED);\n        mRcsSettings.setProvisioningVersion(Version.RESETED.toInt());\n        finish();\n    }\n\n    private void acceptTermsAndConditions() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"User accepts terms and conditions\");\n        }\n        String rcsAccountUsername = getString(R.string.rcs_core_account_username);\n        RcsAccountManager rcsAccountMngr = RcsAccountManager.getInstance(mContext,\n                mContactManager);\n        try {\n            rcsAccountMngr.createRcsAccount(rcsAccountUsername, true);\n            /* Set terms and conditions accepted */\n            mRcsSettings.setTermsAndConditionsResponse(TermsAndConditionsResponse.ACCEPTED);\n            /* We accept a configuration which was successfully parsed */\n            mRcsSettings.setConfigurationValid(true);\n            LauncherUtils.launchRcsCoreService(mContext, mRcsSettings);\n        } catch (RcsAccountException e) {\n            sLogger.error(\"Failed to launch RCS service!\", e);\n            // TODO report an error to end user\n        }\n        finish();\n    }\n\n    private void showTermsAndConditionsNotification() {\n        PendingIntent pi = PendingIntent.getActivity(this, 0, getIntent(),\n                PendingIntent.FLAG_UPDATE_CURRENT);\n\n        /* Create notification */\n        Notification.Builder notif = new Notification.Builder(this);\n        notif.setContentIntent(pi);\n        notif.setSmallIcon(R.drawable.rcs_notif_on_icon);\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(true);\n        notif.setOnlyAlertOnce(true);\n        notif.setContentTitle(getString(R.string.rcs_core_terms_title));\n        notif.setContentText(mTitle);\n        notif.setDefaults(Notification.DEFAULT_VIBRATE);\n\n        /* Send notification */\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(TC_NOTIFICATION_TAG, TC_NOTIFICATION_ID, notif.build());\n    }\n\n    /**\n     * Cancel the terms and conditions request notification\n     * \n     * @param context The context\n     */\n    public static void cancelTermsAndConditionsNotification(Context context) {\n        NotificationManager notificationManager = (NotificationManager) context\n                .getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.cancel(TC_NOTIFICATION_TAG, TC_NOTIFICATION_ID);\n    }\n\n    /**\n     * Show the terms and conditions request\n     * \n     * @param context The context\n     */\n    public static void showTermsAndConditions(Context context) {\n        final Intent intent = new Intent(context, TermsAndConditionsRequest.class);\n        /* Required as the activity is started outside of an Activity context */\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);\n        context.startActivity(intent);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/EasyX509TrustManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\nimport javax.net.ssl.X509TrustManager;\n\n/**\n * @author olamy\n * @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse $\n * @since 1.2.3\n */\npublic class EasyX509TrustManager implements X509TrustManager {\n\n    private X509TrustManager standardTrustManager = null;\n\n    /**\n     * Constructor for EasyX509TrustManager.\n     */\n    public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException,\n            KeyStoreException {\n        super();\n        TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory\n                .getDefaultAlgorithm());\n        factory.init(keystore);\n        TrustManager[] trustmanagers = factory.getTrustManagers();\n        if (trustmanagers.length == 0) {\n            throw new NoSuchAlgorithmException(\"no trust manager found\");\n        }\n        this.standardTrustManager = (X509TrustManager) trustmanagers[0];\n    }\n\n    /**\n     * @see javax2.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)\n     */\n    public void checkClientTrusted(X509Certificate[] certificates, String authType)\n            throws CertificateException {\n        standardTrustManager.checkClientTrusted(certificates, authType);\n    }\n\n    /**\n     * @see javax2.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)\n     */\n    public void checkServerTrusted(X509Certificate[] certificates, String authType)\n            throws CertificateException {\n        if ((certificates != null) && (certificates.length == 1)) {\n            certificates[0].checkValidity();\n        } else {\n            // standardTrustManager.checkServerTrusted( certificates, authType );\n        }\n    }\n\n    /**\n     * @see javax2.net.ssl.X509TrustManager#getAcceptedIssuers()\n     */\n    public X509Certificate[] getAcceptedIssuers() {\n        return this.standardTrustManager.getAcceptedIssuers();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningAlertDialog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.ContactUtil.PhoneNumber;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.os.CountDownTimer;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\n/**\n * HTTPS provisioning - MSISDN Pop-up activity\n * \n * @author Orange\n */\npublic class HttpsProvisioningAlertDialog extends Activity {\n\n    private static final long COUNTDOWN_INTERVAL_MSEC = 1000;\n\n    private CountDownTimer mCountDownTimer;\n    private LinearLayout mErrorLayout;\n    private LinearLayout mOkNormalLayout;\n    private TextView mMsisdn;\n    private Boolean normalCase = true;\n\n    private static final Logger sLogger = Logger.getLogger(HttpsProvisioningAlertDialog.class\n            .getName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.rcs_wifi_provisioning);\n        setFinishOnTouchOutside(false);\n\n        ContactId contact = getIntent().getParcelableExtra(\n                HttpsProvisioningMsisdnInput.EXTRA_CONTACT);\n\n        mErrorLayout = (LinearLayout) findViewById(R.id.error_layout);\n\n        mOkNormalLayout = (LinearLayout) findViewById(R.id.normal_layout);\n        mMsisdn = (TextView) findViewById(R.id.msisdn);\n\n        Button okButton = (Button) findViewById(R.id.ok_button);\n        okButton.setOnClickListener(mNormalButtonClickListener);\n\n        Button cancel_button = (Button) findViewById(R.id.cancel_button);\n        cancel_button.setOnClickListener(mCancelButtonClickListener);\n\n        Button okErrorButton = (Button) findViewById(R.id.ok_error_button);\n        okErrorButton.setOnClickListener(mErrorButtonClickListener);\n\n        mCountDownTimer = new CountDownTimer(HttpsProvisioningUtils.INPUT_MSISDN_TIMEOUT,\n                COUNTDOWN_INTERVAL_MSEC) {\n\n            @Override\n            public void onTick(long millisUntilFinished) {\n            }\n\n            @Override\n            public void onFinish() {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"MSISDN dialog has expired!\");\n                }\n                HttpsProvisioningMsisdnInput.getInstance().responseReceived(null);\n                mCountDownTimer = null;\n                finish();\n            }\n        }.start();\n\n        if (savedInstanceState != null) {\n            normalCase = savedInstanceState.getBoolean(\"normalCase\");\n        }\n        if (normalCase) {\n            showNormalCase();\n        } else {\n            showErrorCase();\n        }\n        if (contact != null) {\n            mMsisdn.setText(contact.toString());\n        }\n    }\n\n    private void showErrorCase() {\n        normalCase = false;\n        mErrorLayout.setVisibility(View.VISIBLE);\n        mOkNormalLayout.setVisibility(View.GONE);\n    }\n\n    private void showNormalCase() {\n        normalCase = true;\n        mErrorLayout.setVisibility(View.GONE);\n        mOkNormalLayout.setVisibility(View.VISIBLE);\n    }\n\n    @Override\n    public void onBackPressed() {\n        if (sLogger.isActivated()) {\n            sLogger.warn(\"User exited the MSISDN dialog!\");\n        }\n        HttpsProvisioningMsisdnInput.getInstance().responseReceived(null);\n        super.onBackPressed();\n    }\n\n    @Override\n    protected void onDestroy() {\n        if (mCountDownTimer != null) {\n            mCountDownTimer.cancel();\n        }\n        super.onDestroy();\n    }\n\n    @Override\n    public void onSaveInstanceState(Bundle outState) {\n        super.onSaveInstanceState(outState);\n        outState.putBoolean(\"normalCase\", normalCase);\n    }\n\n    private OnClickListener mNormalButtonClickListener = new OnClickListener() {\n        @Override\n        public void onClick(View v) {\n            String contact = mMsisdn.getText().toString();\n            PhoneNumber phoneNumber = ContactUtil.getValidPhoneNumberFromAndroid(contact);\n            if (phoneNumber == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"User entered a wrong MSISDN '\" + contact + \"'!\");\n                }\n                showErrorCase();\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"User entered MSISDN \".concat(phoneNumber.getNumber()));\n                }\n                HttpsProvisioningMsisdnInput.getInstance().responseReceived(\n                        ContactUtil.createContactIdFromValidatedData(phoneNumber));\n                finish();\n            }\n        }\n    };\n\n    private OnClickListener mCancelButtonClickListener = new OnClickListener() {\n        @Override\n        public void onClick(View v) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"User cancelled the MSISDN dialog!\");\n            }\n            HttpsProvisioningMsisdnInput.getInstance().responseReceived(null);\n            finish();\n        }\n    };\n\n    private OnClickListener mErrorButtonClickListener = new OnClickListener() {\n\n        @Override\n        public void onClick(View v) {\n            showNormalCase();\n        }\n    };\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.provisioning.ProvisioningFailureReasons;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.ConnectivityManager;\nimport android.net.wifi.WifiManager;\n\nimport java.io.IOException;\n\n/**\n * HTTPS provisioning connection management\n * \n * @author Orange\n */\npublic class HttpsProvisioningConnection {\n\n    /**\n     * HttpsProvisioningManager manages HTTP and SMS reception to load provisioning from network\n     */\n    private HttpsProvisioningManager mProvisioningManager;\n\n    private BroadcastReceiver mNetworkStateListener;\n\n    private ConnectivityManager mConnectionManager;\n\n    /**\n     * Wifi disabling listener\n     */\n    private BroadcastReceiver mWifiDisablingListener;\n\n    private final Context mContext;\n\n    private static final Logger sLogger = Logger.getLogger(HttpsProvisioningConnection.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param httpsProvisioningManager HTTP provisioning manager\n     * @param context The context\n     */\n    public HttpsProvisioningConnection(HttpsProvisioningManager httpsProvisioningManager,\n            Context context) {\n        mProvisioningManager = httpsProvisioningManager;\n        mContext = context;\n        mConnectionManager = (ConnectivityManager) context\n                .getSystemService(Context.CONNECTIVITY_SERVICE);\n    }\n\n    /**\n     * Get connection manager\n     * \n     * @return connection manager\n     */\n    public ConnectivityManager getConnectionMngr() {\n        return mConnectionManager;\n    }\n\n    /**\n     * Register the broadcast receiver for network state\n     */\n    protected void registerNetworkStateListener() {\n        // Check if network state listener is already registered\n        if (mNetworkStateListener != null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Network state listener already registered\");\n            }\n            return;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Registering network state listener\");\n        }\n\n        // Instantiate the network state listener\n        mNetworkStateListener = new BroadcastReceiver() {\n            @Override\n            public void onReceive(final Context context, final Intent intent) {\n                mProvisioningManager.scheduleProvisioningOperation(new Runnable() {\n                    @Override\n                    public void run() {\n                        String action = intent.getAction();\n                        try {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Network state listener - Received broadcast: \"\n                                        + action);\n                            }\n                            mProvisioningManager.connectionEvent(action);\n                        } catch (RcsAccountException e) {\n                            sLogger.error(\"Unable to handle connection event for intent action: \"\n                                    + action, e);\n                        } catch (IOException e) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(new StringBuilder(\n                                        \"Unable to handle connection event for intent action: \")\n                                        .append(action).append(\", Message=\").append(e.getMessage())\n                                        .toString());\n                            }\n                            /* Start the RCS service */\n                            if (mProvisioningManager.isFirstProvisioningAfterBoot()) {\n                                /* Reason: No configuration present */\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"Initial provisioning failed!\");\n                                }\n                                mProvisioningManager\n                                        .provisioningFails(ProvisioningFailureReasons.CONNECTIVITY_ISSUE);\n                                mProvisioningManager.retry();\n                            } else {\n                                mProvisioningManager.tryLaunchRcsCoreService(context, -1);\n                            }\n                        } catch (RuntimeException e) {\n                            /*\n                             * Normally we are not allowed to catch runtime exceptions as these are\n                             * genuine bugs which should be handled/fixed within the code. However\n                             * the cases when we are executing operations on a thread unhandling\n                             * such exceptions will eventually lead to exit the system and thus can\n                             * bring the whole system down, which is not intended.\n                             */\n                            sLogger.error(\"Unable to handle connection event for intent action: \"\n                                    + action, e);\n                        }\n                    }\n                });\n            }\n        };\n\n        // Register network state listener\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);\n        mContext.registerReceiver(mNetworkStateListener, intentFilter);\n    }\n\n    /**\n     * Unregister the broadcast receiver for network state\n     */\n    protected void unregisterNetworkStateListener() {\n        if (mNetworkStateListener != null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unregistering network state listener\");\n            }\n            mContext.unregisterReceiver(mNetworkStateListener);\n            mNetworkStateListener = null;\n        }\n    }\n\n    /**\n     * Register the broadcast receiver for wifi disabling\n     */\n    protected void registerWifiDisablingListener() {\n        if (mWifiDisablingListener != null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"WIFI disabling listener already registered\");\n            }\n            return;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Registering WIFI disabling listener\");\n        }\n\n        mWifiDisablingListener = new BroadcastReceiver() {\n            @Override\n            public void onReceive(final Context context, final Intent intent) {\n                mProvisioningManager.scheduleProvisioningOperation(new Runnable() {\n                    @Override\n                    public void run() {\n                        try {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Wifi disabling listener - Received broadcast: \"\n                                        + intent.toString());\n                            }\n\n                            if (intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,\n                                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_DISABLED) {\n                                mProvisioningManager.resetCounters();\n                                registerNetworkStateListener();\n                                unregisterWifiDisablingListener();\n                            }\n                        } catch (RuntimeException e) {\n                            /*\n                             * Normally we are not allowed to catch runtime exceptions as these are\n                             * genuine bugs which should be handled/fixed within the code. However\n                             * the cases when we are executing operations on a thread unhandling\n                             * such exceptions will eventually lead to exit the system and thus can\n                             * bring the whole system down, which is not intended.\n                             */\n                            sLogger.error(new StringBuilder(\n                                    \"Unable to handle wifi state change event for action : \")\n                                    .append(intent.getAction()).toString(), e);\n                        }\n                    }\n                });\n            }\n        };\n\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);\n        mContext.registerReceiver(mWifiDisablingListener, intentFilter);\n    }\n\n    /**\n     * Unregister the broadcast receiver for wifi disabling\n     */\n    protected void unregisterWifiDisablingListener() {\n        if (mWifiDisablingListener != null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unregistering WIFI disabling listener\");\n            }\n            try {\n                mContext.unregisterReceiver(mWifiDisablingListener);\n            } catch (IllegalArgumentException e) {\n                // Nothing to do\n            }\n            mWifiDisablingListener = null;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.addressbook.RcsAccountManager;\nimport com.gsma.rcs.core.TerminalInfo;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.GsmaRelease;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.provisioning.ProvisioningFailureReasons;\nimport com.gsma.rcs.provisioning.ProvisioningInfo;\nimport com.gsma.rcs.provisioning.ProvisioningInfo.Version;\nimport com.gsma.rcs.provisioning.ProvisioningParser;\nimport com.gsma.rcs.provisioning.TermsAndConditionsRequest;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.NetworkUtils;\nimport com.gsma.rcs.utils.StringUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.text.TextUtils;\n\nimport org.xml.sax.SAXException;\n\nimport java.io.BufferedReader;\nimport java.io.DataInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.net.CookieHandler;\nimport java.net.CookieManager;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.util.Locale;\n\n/**\n * Provisioning via network manager\n * \n * @author hlxn7157\n * @author G. LE PESSOT\n * @author Deutsche Telekom AG\n * @author yplo6403\n */\npublic class HttpsProvisioningManager {\n\n    /**\n     * Rate to convert from seconds to milliseconds\n     */\n    private static final long SECONDS_TO_MILLISECONDS_CONVERSION_RATE = 1000;\n\n    private static final int HTTP_STATUS_ERROR_NETWORK_AUTHENTICATION_REQUIRED = 511;\n\n    private static final String PROVISIONING_URI_FILENAME = \"rcs_provisioning_uri.txt\";\n\n    private static final String PARAM_VERS = \"vers\";\n\n    private static final String PARAM_RCS_VERSION = \"rcs_version\";\n\n    private static final String PARAM_RCS_PROFILE = \"rcs_profile\";\n\n    private static final String PARAM_CLIENT_VENDOR = \"client_vendor\";\n\n    private static final String PARAM_CLIENT_VERSION = \"client_version\";\n\n    private static final String PARAM_TERMINAL_VENDOR = \"terminal_vendor\";\n\n    private static final String PARAM_TERMINAL_MODEL = \"terminal_model\";\n\n    private static final String PARAM_TERMINAL_SW_VERSION = \"terminal_sw_version\";\n\n    private static final String PARAM_IMSI = \"IMSI\";\n\n    private static final String PARAM_IMEI = \"IMEI\";\n\n    private static final String PARAM_SMS_PORT = \"SMS_port\";\n\n    private static final String PARAM_MSISDN = \"msisdn\";\n\n    private static final String PARAM_TOKEN = \"token\";\n\n    private static final String PROVISIONING_OPERATIONS_THREAD_NAME = \"ProvisioningOps\";\n\n    /**\n     * Result content while waiting for OTP\n     */\n    private static final String RESULT_CONTENT = \"Otp sent to terminal\";\n\n    /**\n     * Timer internal for OTP\n     */\n    private static final int OTP_TIME_OUT = 120000;\n\n    /**\n     * Retry max count for OTP\n     */\n    private static final int RETRY_MAX_COUNT_OTP = 10;\n\n    /**\n     * First launch flag\n     */\n    private boolean mFirstProvAfterBoot = false;\n\n    /**\n     * User action flag\n     */\n    private boolean mUser = false;\n\n    private int mRetryCount = 0;\n\n    private HttpsProvisioningSMS mSmsManager;\n\n    private HttpsProvisioningConnection mNetworkCnx;\n\n    /**\n     * Waiting for OTP flag\n     */\n    private boolean mWaitingForOTP;\n\n    private final LocalContentResolver mLocalContentResolver;\n\n    private final Context mCtx;\n\n    /**\n     * Handler to process messages & runnable associated with background thread.\n     */\n    private Handler mProvisioningOperationHandler;\n\n    /**\n     * Retry after 511 \"Network authentication required\" counter\n     */\n    private int mRetryAfter511ErrorCount = 0;\n\n    private final PendingIntent mRetryIntent;\n\n    private final RcsSettings mRcsSettings;\n\n    private final MessagingLog mMessagingLog;\n\n    private final ContactManager mContactManager;\n\n    private RcsAccountManager mRcsAccountManager;\n\n    private final String mImsi;\n\n    private final String mImei;\n\n    private final static int BUFFER_READER_SIZE = 1000;\n\n    /**\n     * Builds HTTPS request parameters that are related to Terminal, PARAM_RCS_VERSION &\n     * PARAM_RCS_PROFILE.\n     * <p>\n     * EXCLUDE - PARAM_VERS & OPTIONAL ARGS\n     * </p>\n     * <p>\n     * OPTIONAL ARGS = PARAM_IMSI, PARAM_IMEI, PARAM_SMS_PORT, PARAM_MSISDN & PARAM_TOKEN\n     * </p>\n     */\n    private static Uri.Builder sHttpsReqUriBuilder;\n\n    private static final Logger sLogger = Logger\n            .getLogger(HttpsProvisioningManager.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param imei International Mobile Equipment Identity\n     * @param imsi International Mobile Subscriber Identity\n     * @param context application context\n     * @param localContentResolver Local content resolver\n     * @param retryIntent pending intent to update periodically the configuration\n     * @param first is provisioning service launch after (re)boot ?\n     * @param user is provisioning service launch after user action ?\n     * @param rcsSettings RCS settings accessor\n     * @param messagingLog Message log accessor\n     * @param contactManager Contact manager accessor\n     */\n    public HttpsProvisioningManager(String imei, String imsi, Context context,\n            LocalContentResolver localContentResolver, final PendingIntent retryIntent,\n            boolean first, boolean user, RcsSettings rcsSettings, MessagingLog messagingLog,\n            ContactManager contactManager) {\n        mImsi = imsi;\n        mImei = imei;\n        mCtx = context;\n        mLocalContentResolver = localContentResolver;\n        mRetryIntent = retryIntent;\n        mFirstProvAfterBoot = first;\n        mUser = user;\n        mRcsSettings = rcsSettings;\n        mMessagingLog = messagingLog;\n        mContactManager = contactManager;\n    }\n\n    /**\n     * Initialize Provisioning Manager\n     */\n    /* package private */void initialize() {\n        mProvisioningOperationHandler = allocateBgHandler(PROVISIONING_OPERATIONS_THREAD_NAME);\n        mRcsAccountManager = new RcsAccountManager(mCtx, mContactManager);\n        mNetworkCnx = new HttpsProvisioningConnection(this, mCtx);\n        mSmsManager = new HttpsProvisioningSMS(this, mCtx);\n    }\n\n    private Handler allocateBgHandler(String threadName) {\n        HandlerThread thread = new HandlerThread(threadName);\n        thread.start();\n        return new Handler(thread.getLooper());\n    }\n\n    /**\n     * Connection event\n     * \n     * @param action Connectivity action\n     * @return true if the updateConfig has been done\n     * @throws RcsAccountException\n     * @throws IOException\n     */\n    /* package private */boolean connectionEvent(String action) throws RcsAccountException,\n            IOException {\n        try {\n            if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {\n                return false;\n            }\n            // Check received network info\n            NetworkInfo networkInfo = mNetworkCnx.getConnectionMngr().getActiveNetworkInfo();\n            if (networkInfo == null) {\n                return false;\n            }\n            if (!networkInfo.isConnected()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Disconnection from network\");\n                }\n                return false;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Connected to data network\");\n            }\n            updateConfig();\n            return true;\n\n        } finally {\n            mNetworkCnx.unregisterNetworkStateListener();\n        }\n    }\n\n    private HttpURLConnection executeHttpRequest(boolean secured, String request)\n            throws IOException {\n        String protocol = (secured) ? \"https\" : \"http\";\n        URL url = new URL(protocol + \"://\" + request);\n        HttpURLConnection cnx = (HttpURLConnection) url.openConnection();\n        cnx.setRequestProperty(\"Accept-Language\", HttpsProvisioningUtils.getUserLanguage());\n        return cnx;\n    }\n\n    /**\n     * Get the HTTPS request arguments\n     * \n     * @param smsPort SMS port\n     * @param token Provisioning token\n     * @param msisdn MSISDN\n     * @return {@link String} with the HTTPS request arguments.\n     */\n    private String getHttpsRequestArguments(String smsPort, String token, ContactId msisdn) {\n        if (sHttpsReqUriBuilder == null) {\n            sHttpsReqUriBuilder = new Uri.Builder();\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_RCS_VERSION,\n                    HttpsProvisioningUtils.getRcsVersion());\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_RCS_PROFILE,\n                    HttpsProvisioningUtils.getRcsProfile());\n            if (mRcsSettings.isEnrichCallingServiceSupported()) {\n                sHttpsReqUriBuilder.appendQueryParameter(PARAM_RCS_PROFILE,\n                        HttpsProvisioningUtils.getEnrichCallingProfile());\n            }\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_CLIENT_VENDOR,\n                    TerminalInfo.getClientVendor());\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_CLIENT_VERSION,\n                    TerminalInfo.getClientVersion(mCtx));\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_TERMINAL_VENDOR,\n                    TerminalInfo.getTerminalVendor());\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_TERMINAL_MODEL,\n                    TerminalInfo.getTerminalModel());\n            sHttpsReqUriBuilder.appendQueryParameter(PARAM_TERMINAL_SW_VERSION,\n                    TerminalInfo.getTerminalSoftwareVersion());\n        }\n        int provisioningVersion = mRcsSettings.getProvisioningVersion();\n        if (mUser && Version.DISABLED_DORMANT.toInt() == provisioningVersion) {\n            provisioningVersion = LauncherUtils.getProvisioningVersion(mCtx);\n            mUser = false;\n        }\n        final Uri.Builder uriBuilder = sHttpsReqUriBuilder.build().buildUpon();\n        uriBuilder.appendQueryParameter(PARAM_VERS, String.valueOf(provisioningVersion));\n        uriBuilder.appendQueryParameter(PARAM_IMSI, mImsi);\n        uriBuilder.appendQueryParameter(PARAM_IMEI, mImei);\n        /*\n         * Add optional parameters only if available\n         */\n        if (smsPort != null) {\n            uriBuilder.appendQueryParameter(PARAM_SMS_PORT, smsPort);\n        }\n        if (msisdn != null) {\n            uriBuilder.appendQueryParameter(PARAM_MSISDN, msisdn.toString());\n        }\n        /*\n         * RCS standard: \"The token shall be stored on the device so it can be used in subsequent\n         * configuration requests over non-3GPP access.\" In 3GPP access, the token is only\n         * compulsory for non 3GPP access and is not used for 3GPP access. It shall then not be\n         * inserted as a URI parameter for 3GPP access.\n         */\n        if (NetworkUtils.getNetworkAccessType() == NetworkUtils.NETWORK_ACCESS_WIFI) {\n            /*\n             * According to the standard the token-parameter name should be part of the Uri even if\n             * the token is null here but only for non 3gpp access.\n             */\n            uriBuilder.appendQueryParameter(PARAM_TOKEN, token == null ? \"\" : token);\n        }\n\n        return uriBuilder.toString();\n    }\n\n    /**\n     * Send the first HTTPS request to require the one time password (OTP)\n     *\n     * @param msisdn the phone number\n     * @param primaryUri the primary URI\n     * @param secondaryUri the secondary URI\n     * @return Instance of {@link HttpsProvisioningResult} or null in case of internal exception\n     * @throws IOException\n     */\n    private HttpsProvisioningResult sendFirstRequestsToRequireOTP(ContactId msisdn,\n            String primaryUri, String secondaryUri) throws IOException {\n        HttpsProvisioningResult result = new HttpsProvisioningResult();\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Send 1rst HTTPS request to get OTP (msisdn=\" + msisdn + \")(retry_count=\"\n                    + mRetryCount + \")(waitingOTP=\" + mWaitingForOTP + \")\");\n        }\n        HttpURLConnection urlConnection = null;\n        try {\n            /* Condition to check to show MSISDN popup after OTP time out */\n            if (msisdn != null && mRetryCount > 0 && mWaitingForOTP) {\n                mWaitingForOTP = false;\n                ContactId contact = mRcsSettings.getUserProfileImsUserName();\n                /* Displays a popup with previously given MSISDN to edit and retry for OTP */\n                msisdn = HttpsProvisioningMsisdnInput.getInstance().displayPopupAndWaitResponse(\n                        mCtx, contact);\n                if (!contactIdEquals(contact, msisdn)) {\n                    mRcsSettings.setUserProfileImsUserName(msisdn);\n                }\n                if (msisdn == null) {\n                    if (logActivated) {\n                        sLogger.warn(\"No MSISDN set by end user: cannot authenticate!\");\n                    }\n                    result.code = HttpsProvisioningResult.UNKNOWN_MSISDN_CODE;\n                    return result;\n                }\n                if (logActivated) {\n                    sLogger.debug(\"MSISDN set by end user=\".concat(msisdn.toString()));\n                }\n            }\n            /* Generate the SMS port for provisioning */\n            String smsPortForOTP = HttpsProvisioningSMS.generateSmsPortForProvisioning();\n            /*\n             * Format first HTTPS request with extra parameters (IMSI and IMEI if available plus\n             * SMS_port and token).\n             */\n            String token = mRcsSettings.getProvisioningToken();\n            String args = getHttpsRequestArguments(smsPortForOTP, token, msisdn);\n\n            /* Execute first HTTPS request with extra parameters */\n            String request = primaryUri + args;\n            urlConnection = executeHttpRequest(true, request);\n            result.code = urlConnection.getResponseCode();\n            if (HttpURLConnection.HTTP_OK != result.code && !StringUtils.isEmpty(secondaryUri)) {\n                /* First server not available, try the secondaryUri */\n                request = secondaryUri + args;\n                urlConnection.disconnect();\n                urlConnection = null;\n                urlConnection = executeHttpRequest(true, request);\n                result.code = urlConnection.getResponseCode();\n            }\n            switch (result.code) {\n                case HttpURLConnection.HTTP_OK:\n                    if (logActivated) {\n                        sLogger.debug(\"HTTPS request returns with 200 OK\");\n                    }\n                    result.content = readStream(urlConnection.getInputStream());\n                    /*\n                     * If the content is empty, means that the configuration XML is not present and\n                     * the Token is invalid then we need to wait for the SMS with OTP.\n                     */\n                    if (TextUtils.isEmpty(result.content)\n                            || result.content.contains(RESULT_CONTENT)) {\n                        if (mRetryCount < RETRY_MAX_COUNT_OTP) {\n                            mRetryCount++;\n                            mWaitingForOTP = true;\n                            result.waitingForSMSOTP = true;\n                            /* Register SMS provisioning receiver */\n                            mSmsManager.registerSmsProvisioningReceiver(smsPortForOTP, primaryUri);\n                            /* Start retry alarm for OTP */\n                            HttpsProvisioningService.startRetryAlarm(mCtx, mRetryIntent,\n                                    OTP_TIME_OUT);\n                        }\n                    }\n                    return result;\n\n                case HttpURLConnection.HTTP_FORBIDDEN:\n                    if (logActivated) {\n                        sLogger.debug(\"Request to get OTP failed: Forbidden. MSISDN=\" + msisdn);\n                    }\n                    if (mRetryCount < HttpsProvisioningUtils.RETRY_MAX_COUNT) {\n                        mRetryCount++;\n                        ContactId contact = mRcsSettings.getUserProfileImsUserName();\n                        msisdn = HttpsProvisioningMsisdnInput.getInstance()\n                                .displayPopupAndWaitResponse(mCtx, contact);\n                        if (!contactIdEquals(contact, msisdn)) {\n                            mRcsSettings.setUserProfileImsUserName(msisdn);\n                        }\n                        if (msisdn == null) {\n                            if (logActivated) {\n                                sLogger.warn(\"No MSISDN set by end user: cannot authenticate!\");\n                            }\n                            result.code = HttpsProvisioningResult.UNKNOWN_MSISDN_CODE;\n                            return result;\n                        }\n                        if (logActivated) {\n                            sLogger.debug(\"MSISDN set by end user=\".concat(msisdn.toString()));\n                        }\n                        return sendFirstRequestsToRequireOTP(msisdn, primaryUri, secondaryUri);\n                    }\n\n                case HttpURLConnection.HTTP_UNAVAILABLE:\n                    result.retryAfter = getRetryAfter(urlConnection);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                default:\n                    if (logActivated) {\n                        sLogger.debug(\"Request to get OTP failed: code=\" + result.code);\n                    }\n                    return result;\n            }\n        } finally {\n            if (urlConnection != null) {\n                urlConnection.disconnect();\n            }\n            /* If not waiting for the SMS with OTP */\n            if (!result.waitingForSMSOTP && HttpURLConnection.HTTP_FORBIDDEN != result.code) {\n                mSmsManager.unregisterSmsProvisioningReceiver();\n            }\n        }\n    }\n\n    private boolean contactIdEquals(ContactId a, ContactId b) {\n        return a == b || (a != null && a.equals(b));\n    }\n\n    /**\n     * Update provisioning config with OTP\n     * \n     * @param otp One time password\n     * @param requestUri Request URI\n     * @throws RcsAccountException thrown if RCS account failed to be created\n     * @throws IOException\n     */\n    /* package private */void updateConfigWithOTP(String otp, String requestUri)\n            throws RcsAccountException, IOException {\n        // Cancel previous retry alarm\n        HttpsProvisioningService.cancelRetryAlarm(mCtx, mRetryIntent);\n\n        // Get config via HTTPS with OTP\n        HttpsProvisioningResult result = sendSecondHttpsRequestWithOTP(otp, requestUri);\n        //\n        // // Process HTTPS provisioning result\n        processProvisioningResult(result);\n    }\n\n    /**\n     * Build the provisioning address with operator information\n     * \n     * @return provisioning URI\n     */\n    private String buildProvisioningAddress() {\n        String mnc = String.format(Locale.US, \"%03d\", mRcsSettings.getMobileNetworkCode());\n        String mcc = String.format(Locale.US, \"%03d\", mRcsSettings.getMobileCountryCode());\n        return \"config.rcs.mnc\" + mnc + \".mcc\" + mcc + \".pub.3gppnetwork.org\";\n    }\n\n    private static String readStream(InputStream in) throws IOException {\n        StringBuilder sb = new StringBuilder();\n        try {\n            BufferedReader r = new BufferedReader(new InputStreamReader(in, UTF8),\n                    BUFFER_READER_SIZE);\n            for (String line = r.readLine(); line != null; line = r.readLine()) {\n                sb.append(line);\n            }\n            return sb.toString();\n        } finally {\n            CloseableUtils.tryToClose(in);\n        }\n    }\n\n    /**\n     * Get configuration\n     * \n     * @return Result or null in case of internal exception\n     * @throws IOException\n     */\n    private HttpsProvisioningResult getConfig() throws IOException {\n        HttpsProvisioningResult result = new HttpsProvisioningResult();\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Request config via HTTPS\");\n        }\n        HttpURLConnection urlConnection = null;\n        String primaryUri;\n        String secondaryUri = null;\n        try {\n            /* Get provisioning address */\n            String secondaryAddress = mRcsSettings.getSecondaryProvisioningAddress();\n            if (secondaryAddress != null && mRcsSettings.isSecondaryProvisioningAddressOnly()) {\n                primaryUri = secondaryAddress;\n            } else {\n                primaryUri = buildProvisioningAddress();\n                secondaryUri = mRcsSettings.getSecondaryProvisioningAddress();\n            }\n            /*\n             * Override primary URI if a file containing URI for HTTPS provisioning exists\n             */\n            File provFile = new File(mCtx.getFilesDir(), PROVISIONING_URI_FILENAME);\n            if (provFile.exists()) {\n                primaryUri = getPrimaryProvisionigServerUriFromFile(provFile);\n                secondaryUri = null;\n            }\n            if (logActivated) {\n                sLogger.debug(\"HCS/RCS Uri to connect: \" + primaryUri + \" or \" + secondaryUri);\n            }\n            CookieManager cookieManager = new CookieManager();\n            CookieHandler.setDefault(cookieManager);\n            NetworkInfo networkInfo = mNetworkCnx.getConnectionMngr().getActiveNetworkInfo();\n            /* If network is not mobile network, use request with OTP */\n            if (networkInfo != null && networkInfo.getType() != ConnectivityManager.TYPE_MOBILE) {\n                // Proceed with non mobile network registration\n                ContactId contactId = mRcsSettings.getUserProfileImsUserName();\n                return sendFirstRequestsToRequireOTP(contactId, primaryUri, secondaryUri);\n            }\n            if (logActivated) {\n                sLogger.debug(\"HTTP provisioning on mobile network\");\n            }\n            /* Execute first HTTP request */\n            String requestUri = primaryUri;\n            urlConnection = executeHttpRequest(false, primaryUri);\n            result.code = urlConnection.getResponseCode();\n            if (HttpURLConnection.HTTP_OK != result.code && !StringUtils.isEmpty(secondaryUri)) {\n                urlConnection.disconnect();\n                urlConnection = null;\n                /* First server not available, try the secondaryUri */\n                requestUri = secondaryUri;\n                urlConnection = executeHttpRequest(false, secondaryUri);\n                result.code = urlConnection.getResponseCode();\n            }\n            switch (result.code) {\n                case HttpURLConnection.HTTP_OK:\n                    break;\n\n                case HTTP_STATUS_ERROR_NETWORK_AUTHENTICATION_REQUIRED:\n                    /*\n                     * Blackbird guidelines ID_2_6 Configuration mechanism over PS without Header\n                     * Enrichment Use SMS provisioning on PS data network if server reply 511\n                     * NETWORK AUTHENTICATION REQUIRED\n                     */\n                    return sendFirstRequestsToRequireOTP(null, primaryUri, secondaryUri);\n\n                case HttpURLConnection.HTTP_UNAVAILABLE:\n                    result.retryAfter = getRetryAfter(urlConnection);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                default:\n                    if (logActivated) {\n                        sLogger.debug(\"First HTTPS request failed with code \" + result.code);\n                    }\n                    return result;\n            }\n            urlConnection.disconnect();\n            urlConnection = null;\n            /* Format second HTTPS request */\n            String request = requestUri + getHttpsRequestArguments(null, null, null);\n            if (logActivated) {\n                sLogger.info(\"Request provisioning: \".concat(request));\n            }\n            /* Execute second HTTPS request */\n            urlConnection = executeHttpRequest(true, request);\n            result.code = urlConnection.getResponseCode();\n            switch (result.code) {\n                case HttpURLConnection.HTTP_OK:\n                    result.content = readStream(urlConnection.getInputStream());\n                    return result;\n\n                case HttpURLConnection.HTTP_UNAVAILABLE:\n                    result.retryAfter = getRetryAfter(urlConnection);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                default:\n                    if (logActivated) {\n                        sLogger.debug(\"Second HTTPS request failed with code \" + result.code);\n                    }\n                    return result;\n            }\n        } finally {\n            if (urlConnection != null) {\n                urlConnection.disconnect();\n            }\n        }\n    }\n\n    private String getPrimaryProvisionigServerUriFromFile(File provFile) throws IOException {\n        DataInputStream dataInputStream = null;\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Provisioning URI file found !\");\n            }\n            FileInputStream fis = new FileInputStream(provFile);\n            dataInputStream = new DataInputStream(fis);\n            BufferedReader br = new BufferedReader(new InputStreamReader(dataInputStream));\n            return br.readLine();\n\n        } finally {\n            CloseableUtils.tryToClose(dataInputStream);\n        }\n    }\n\n    /**\n     * Update provisioning config\n     * \n     * @throws RcsAccountException thrown if RCS account failed to be created\n     * @throws IOException\n     */\n    /* package private */void updateConfig() throws RcsAccountException, IOException {\n        // Cancel previous retry alarm\n        HttpsProvisioningService.cancelRetryAlarm(mCtx, mRetryIntent);\n        // Get config via HTTPS\n        HttpsProvisioningResult result = getConfig();\n        // Process HTTPS provisioning result\n        processProvisioningResult(result);\n    }\n\n    /**\n     * Send the second HTTPS request with the one time password (OTP)\n     * \n     * @param otp One time password\n     * @param requestUri Request URI\n     * @return Instance of {@link HttpsProvisioningResult} or null in case of internal exception\n     * @throws IOException\n     */\n    /* package private */HttpsProvisioningResult sendSecondHttpsRequestWithOTP(String otp,\n            String requestUri) throws IOException {\n        HttpsProvisioningResult result = new HttpsProvisioningResult();\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Send second HTTPS with OTP\");\n        }\n        HttpURLConnection urlConnection = null;\n        try {\n            /* Format second HTTPS request */\n            String request = requestUri + \"?OTP=\" + otp;\n            if (logActivated) {\n                sLogger.info(\"Request provisioning with OTP: \".concat(request));\n            }\n            /* Execute second HTTPS request */\n            urlConnection = executeHttpRequest(true, request);\n            result.code = urlConnection.getResponseCode();\n            switch (result.code) {\n                case HttpURLConnection.HTTP_OK:\n                    result.content = readStream(urlConnection.getInputStream());\n                    return result;\n\n                case HttpURLConnection.HTTP_UNAVAILABLE:\n                    result.retryAfter = getRetryAfter(urlConnection);\n                    /* Intentional fall through */\n                    //$FALL-THROUGH$\n                default:\n                    if (logActivated) {\n                        sLogger.debug(\"Request with OTP failed code=\" + result.code);\n                    }\n                    return result;\n            }\n        } finally {\n            if (urlConnection != null) {\n                urlConnection.disconnect();\n            }\n        }\n    }\n\n    /**\n     * Get retry-after value\n     * \n     * @return retry-after value in milliseconds\n     */\n    private long getRetryAfter(HttpURLConnection response) {\n        String header = response.getHeaderField(\"Retry-After\");\n        if (header == null) {\n            return 0;\n        }\n        return Integer.valueOf(header) * SECONDS_TO_MILLISECONDS_CONVERSION_RATE;\n    }\n\n    /**\n     * Process provisioning result\n     * \n     * @param result Instance of {@link HttpsProvisioningResult}\n     * @throws RcsAccountException thrown if RCS account failed to be created\n     */\n    private void processProvisioningResult(HttpsProvisioningResult result)\n            throws RcsAccountException {\n        boolean logActivated = sLogger.isActivated();\n        if (HttpURLConnection.HTTP_OK == result.code) {\n            // Reset after 511 counter\n            mRetryAfter511ErrorCount = 0;\n            if (result.waitingForSMSOTP) {\n                if (logActivated) {\n                    sLogger.debug(\"Waiting for SMS with OTP.\");\n                }\n                return;\n            }\n            if (logActivated) {\n                sLogger.debug(\"Provisioning request successful\");\n            }\n            // Parse the received content\n            ProvisioningParser parser = new ProvisioningParser(result.content, mRcsSettings);\n            /*\n             * Save GSMA release set into the provider. The Node \"SERVICES\" is mandatory in GSMA\n             * release Blackbird and not present in previous one (i.e. Albatros). It is the absence\n             * of this node in the configuration which allows us to determine that current release\n             * is Albatros\n             */\n            GsmaRelease gsmaRelease = mRcsSettings.getGsmaRelease();\n            /*\n             * Save client Messaging Mode set into the provider. The message mode NONE value is not\n             * defined in the standard. It is the absence of the messagingUx parameter which allows\n             * us to determine that client Message Mode is set to NONE.\n             */\n            MessagingMode messagingMode = mRcsSettings.getMessagingMode();\n\n            /* Before parsing the provisioning, the GSMA release is set to Albatros */\n            mRcsSettings.setGsmaRelease(GsmaRelease.ALBATROS);\n            /* Before parsing the provisioning, the client Messaging mode is set to NONE */\n            mRcsSettings.setMessagingMode(MessagingMode.NONE);\n            try {\n                parser.parse(gsmaRelease, messagingMode, mFirstProvAfterBoot);\n                // Successfully provisioned, 1st time reg finalized\n                mFirstProvAfterBoot = false;\n                ProvisioningInfo info = parser.getProvisioningInfo();\n                // Save version\n                int version = info.getVersion();\n                long validity = info.getValidity();\n                if (logActivated) {\n                    sLogger.debug(\"Provisioning version=\" + version + \", validity=\" + validity);\n                }\n                // Save the latest positive version of the configuration\n                LauncherUtils.saveProvisioningVersion(mCtx, version);\n                // Save the validity of the configuration\n                LauncherUtils.saveProvisioningValidity(mCtx, validity);\n                mRcsSettings.setProvisioningVersion(version);\n                // Save token\n                String token = info.getToken();\n                mRcsSettings.setProvisioningToken(token);\n                mRcsSettings.setFileTransferHttpSupported(mRcsSettings.getFtHttpServer() != null\n                        && mRcsSettings.getFtHttpLogin() != null\n                        && mRcsSettings.getFtHttpPassword() != null);\n                // Reset retry alarm counter\n                mRetryCount = 0;\n                if (Version.DISABLED_DORMANT.toInt() == version) {\n                    // -3 : Put RCS client in dormant state\n                    if (logActivated) {\n                        sLogger.debug(\"Provisioning: RCS client in dormant state\");\n                    }\n                    // Start retry alarm\n                    if (validity > 0) {\n                        HttpsProvisioningService.startRetryAlarm(mCtx, mRetryIntent, validity);\n                    }\n                    // We parsed successfully the configuration\n                    mRcsSettings.setConfigurationValid(true);\n                    // Stop the RCS core service. Provisioning is still running.\n                    LauncherUtils.stopRcsCoreService(mCtx);\n\n                } else if (Version.DISABLED_NOQUERY.toInt() == version) {\n                    // -2 : Disable RCS client and stop configuration query\n                    if (logActivated) {\n                        sLogger.debug(\"Provisioning: disable RCS client\");\n                    }\n                    // We parsed successfully the configuration\n                    mRcsSettings.setConfigurationValid(true);\n                    // Disable and stop RCS service\n                    mRcsSettings.setServiceActivationState(false);\n                    LauncherUtils.stopRcsService(mCtx);\n\n                } else if (Version.RESETED_NOQUERY.toInt() == version) {\n                    // -1 Forbidden: reset account + version = 0-1 (doesn't restart)\n                    if (logActivated) {\n                        sLogger.debug(\"Provisioning forbidden: reset account\");\n                    }\n                    // Reset config\n                    LauncherUtils.resetRcsConfig(mCtx, mLocalContentResolver, mRcsSettings,\n                            mMessagingLog, mContactManager);\n                    // Force version to \"-1\" (resetRcs set version to \"0\")\n                    mRcsSettings.setProvisioningVersion(version);\n                    // Disable the RCS service\n                    mRcsSettings.setServiceActivationState(false);\n\n                } else if (Version.RESETED.toInt() == version) {\n                    if (logActivated) {\n                        sLogger.debug(\"Provisioning forbidden: no account\");\n                    }\n                    // Reset config\n                    LauncherUtils.resetRcsConfig(mCtx, mLocalContentResolver, mRcsSettings,\n                            mMessagingLog, mContactManager);\n\n                } else {\n                    /* Start retry alarm */\n                    if (validity > 0) {\n                        HttpsProvisioningService.startRetryAlarm(mCtx, mRetryIntent, validity);\n                    }\n                    boolean tcNotAnswered = TermsAndConditionsResponse.NO_ANSWER == mRcsSettings\n                            .getTermsAndConditionsResponse();\n                    boolean requestTermsAndConditions = mRcsSettings.isProvisioningAcceptButton()\n                            || mRcsSettings.isProvisioningRejectButton();\n                    /* Check if Terms and conditions should be requested. */\n                    if (requestTermsAndConditions && tcNotAnswered) {\n                        TermsAndConditionsRequest.showTermsAndConditions(mCtx);\n                    } else {\n                        if (tcNotAnswered) {\n                            if (logActivated) {\n                                sLogger.debug(\"Terms and conditions implicitly accepted\");\n                            }\n                            mRcsAccountManager.createRcsAccount(\n                                    mCtx.getString(R.string.rcs_core_account_username), true);\n                            mRcsSettings\n                                    .setTermsAndConditionsResponse(TermsAndConditionsResponse.ACCEPTED);\n                        }\n                        /* We parsed successfully the configuration */\n                        mRcsSettings.setConfigurationValid(true);\n                        LauncherUtils.launchRcsCoreService(mCtx, mRcsSettings);\n                    }\n                }\n                IntentUtils.sendBroadcastEvent(mCtx,\n                        RcsService.ACTION_SERVICE_PROVISIONING_DATA_CHANGED);\n\n            } catch (SAXException e) {\n                if (logActivated) {\n                    sLogger.debug(\"Can't parse provisioning document\");\n                }\n                // Restore GSMA release saved before parsing of the provisioning\n                mRcsSettings.setGsmaRelease(gsmaRelease);\n                // Restore the client messaging mode saved before parsing of the provisioning\n                mRcsSettings.setMessagingMode(messagingMode);\n                if (mFirstProvAfterBoot) {\n                    if (logActivated) {\n                        sLogger.debug(\"As this is first launch and we do not have a valid configuration yet, retry later\");\n                    }\n                    // Reason: Invalid configuration\n                    provisioningFails(ProvisioningFailureReasons.INVALID_CONFIGURATION);\n                    retry();\n                } else {\n                    if (logActivated) {\n                        sLogger.debug(\"This is not first launch, use old configuration to register\");\n                    }\n                    tryLaunchRcsCoreService(mCtx, -1);\n                }\n            }\n        } else if (HttpURLConnection.HTTP_UNAVAILABLE == result.code) {\n            // Server Unavailable\n            if (logActivated) {\n                sLogger.debug(\"Server Unavailable. Retry after: \" + result.retryAfter + \"ms\");\n            }\n            if (mFirstProvAfterBoot) {\n                // Reason: Unable to get configuration\n                provisioningFails(ProvisioningFailureReasons.UNABLE_TO_GET_CONFIGURATION);\n                if (result.retryAfter > 0) {\n                    HttpsProvisioningService.startRetryAlarm(mCtx, mRetryIntent, result.retryAfter);\n                }\n            } else {\n                tryLaunchRcsCoreService(mCtx, result.retryAfter);\n            }\n        } else if (HttpURLConnection.HTTP_FORBIDDEN == result.code) {\n            // Forbidden: reset account + version = 0\n            if (logActivated) {\n                sLogger.debug(\"Provisioning forbidden: reset account\");\n            }\n            // Reset version to \"0\"\n            mRcsSettings.setProvisioningVersion(Version.RESETED.toInt());\n            // Reset config\n            LauncherUtils.resetRcsConfig(mCtx, mLocalContentResolver, mRcsSettings, mMessagingLog,\n                    mContactManager);\n            // Reason: Provisioning forbidden\n            provisioningFails(ProvisioningFailureReasons.PROVISIONING_FORBIDDEN);\n\n        } else if (HTTP_STATUS_ERROR_NETWORK_AUTHENTICATION_REQUIRED == result.code) {\n            // Provisioning authentication required\n            if (logActivated) {\n                sLogger.debug(\"Provisioning authentication required\");\n            }\n            // Reset provisioning token\n            mRcsSettings.setProvisioningToken(null);\n            // Retry after reseting provisioning token\n            if (!retryAfter511Error()) {\n                // Reason: Provisioning authentication required\n                provisioningFails(ProvisioningFailureReasons.PROVISIONING_AUTHENTICATION_REQUIRED);\n            }\n        } else {\n            // Other error\n            if (logActivated) {\n                sLogger.debug(\"Provisioning error \" + result.code);\n            }\n            // Start the RCS service\n            if (mFirstProvAfterBoot) {\n                // Reason: No configuration present\n                provisioningFails(ProvisioningFailureReasons.CONNECTIVITY_ISSUE);\n                retry();\n            } else {\n                tryLaunchRcsCoreService(mCtx, -1);\n            }\n        }\n    }\n\n    /**\n     * Try to launch RCS Core Service. RCS Service is only launched if version is positive.\n     * \n     * @param context the context\n     * @param timerRetry timer in milliseconds to trigger next provisioning request. Only applicable\n     *            if greater than 0.\n     */\n    /* package private */void tryLaunchRcsCoreService(Context context, long timerRetry) {\n        int version = mRcsSettings.getProvisioningVersion();\n        // Only launch service if version is positive\n        if (version > 0) {\n            // Start the RCS service\n            LauncherUtils.launchRcsCoreService(context, mRcsSettings);\n            if (timerRetry > 0) {\n                HttpsProvisioningService.startRetryAlarm(context, mRetryIntent, timerRetry);\n            } else {\n                retry();\n            }\n        } else {\n            // Only retry provisioning if service is disabled dormant (-3)\n            if (Version.DISABLED_DORMANT.toInt() == version) {\n                if (timerRetry > 0) {\n                    HttpsProvisioningService.startRetryAlarm(context, mRetryIntent, timerRetry);\n                } else\n                    retry();\n            }\n        }\n    }\n\n    /**\n     * Retry after 511 \"Network authentication required\" procedure\n     * \n     * @return <code>true</code> if retry is performed, otherwise <code>false</code>\n     */\n    private boolean retryAfter511Error() {\n        if (mRetryAfter511ErrorCount < HttpsProvisioningUtils.RETRY_AFTER_511_ERROR_MAX_COUNT) {\n            mRetryAfter511ErrorCount++;\n            HttpsProvisioningService.startRetryAlarm(mCtx, mRetryIntent,\n                    HttpsProvisioningUtils.RETRY_AFTER_511_ERROR_TIMEOUT);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Retry after 511 error (\" + mRetryAfter511ErrorCount + \"/\"\n                        + HttpsProvisioningUtils.RETRY_AFTER_511_ERROR_MAX_COUNT\n                        + \") provisioning after \"\n                        + HttpsProvisioningUtils.RETRY_AFTER_511_ERROR_TIMEOUT + \"ms\");\n            }\n            return true;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"No more retry after 511 error for provisioning\");\n        }\n        // Reset after 511 counter\n        mRetryAfter511ErrorCount = 0;\n        return false;\n    }\n\n    /**\n     * Provisioning fails.\n     * \n     * @param reason Reason of failure\n     */\n    public void provisioningFails(int reason) {\n        // If wifi is active network access type\n        if (NetworkUtils.getNetworkAccessType() == NetworkUtils.NETWORK_ACCESS_WIFI) {\n            // Register Wifi disabling listener\n            mNetworkCnx.registerWifiDisablingListener();\n        }\n    }\n\n    /**\n     * Retry procedure\n     */\n    /* package private */void retry() {\n        if (mRetryCount < HttpsProvisioningUtils.RETRY_MAX_COUNT) {\n            mRetryCount++;\n            int retryDelay = HttpsProvisioningUtils.RETRY_BASE_TIMEOUT + 2 * (mRetryCount - 1)\n                    * HttpsProvisioningUtils.RETRY_BASE_TIMEOUT;\n            HttpsProvisioningService.startRetryAlarm(mCtx, mRetryIntent, retryDelay);\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Retry provisioning count: \" + mRetryCount);\n            }\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"No more retry for provisioning\");\n            }\n        }\n    }\n\n    /**\n     * Transmit to SMS unregister method\n     */\n    public void unregisterSmsProvisioningReceiver() {\n        mSmsManager.unregisterSmsProvisioningReceiver();\n    }\n\n    /**\n     * Transmit to Network unregister method\n     */\n    public void unregisterNetworkStateListener() {\n        mNetworkCnx.unregisterNetworkStateListener();\n    }\n\n    /**\n     * Transmit to Network unregister wifi method\n     */\n    public void unregisterWifiDisablingListener() {\n        mNetworkCnx.unregisterWifiDisablingListener();\n    }\n\n    /**\n     * Transmit to Network register method\n     */\n    public void registerNetworkStateListener() {\n        mNetworkCnx.registerNetworkStateListener();\n    }\n\n    /**\n     * Retry procedure\n     */\n    public void resetCounters() {\n        // Reset retry alarm counter\n        mRetryCount = 0;\n        // Reset after 511 counter\n        mRetryAfter511ErrorCount = 0;\n    }\n\n    /**\n     * Schedule a background task on Handler for execution\n     */\n    /* package private */void scheduleProvisioningOperation(Runnable task) {\n        mProvisioningOperationHandler.post(task);\n    }\n\n    /**\n     * Causes the provisioning handler to quit without processing any more messages in the message\n     * queue\n     */\n    /* package private */void quitProvisioningOperation() {\n        mProvisioningOperationHandler.getLooper().quit();\n    }\n\n    /**\n     * Checks if first provisioning after (re)boot.\n     * \n     * @return true if first provisioning after (re)boot.\n     */\n    public boolean isFirstProvisioningAfterBoot() {\n        return mFirstProvAfterBoot;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningMsisdnInput.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Parcelable;\n\n/**\n * HTTPS provisioning - Input of MSISDN\n * \n * @author Orange\n */\npublic final class HttpsProvisioningMsisdnInput {\n\n    /* package private */static final String EXTRA_CONTACT = \"contact\";\n\n    /**\n     * Singleton instance\n     */\n    private static volatile HttpsProvisioningMsisdnInput sInstance;\n\n    private ContactId mMsisdn;\n\n    /**\n     * Private constructor to prevent instantiation\n     */\n    private HttpsProvisioningMsisdnInput() {\n        super();\n    }\n\n    /**\n     * Get the MSISDN\n     * \n     * @return MSISDN\n     */\n    protected ContactId getMsisdn() {\n        return mMsisdn;\n    }\n\n    /**\n     * Returns the Instance of HttpsProvisioningMSISDNDialog\n     * \n     * @return Instance of HttpsProvisioningMSISDNDialog\n     */\n    public static HttpsProvisioningMsisdnInput getInstance() {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (HttpsProvisioningMsisdnInput.class) {\n            if (sInstance == null) {\n                sInstance = new HttpsProvisioningMsisdnInput();\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Display the MSISDN popup\n     *\n     * @param contact the contact ID to display/edit or null\n     * @return ContactId\n     */\n    protected ContactId displayPopupAndWaitResponse(Context context, ContactId contact) {\n        Intent intent = new Intent(context, HttpsProvisioningAlertDialog.class);\n        intent.putExtra(EXTRA_CONTACT, (Parcelable) contact);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n        try {\n            synchronized (sInstance) {\n                super.wait();\n            }\n        } catch (InterruptedException e) {\n            // nothing to do\n        }\n        return mMsisdn;\n    }\n\n    /**\n     * Callback of the MSISDN\n     * \n     * @param contact the contact ID\n     */\n    protected void responseReceived(ContactId contact) {\n        synchronized (sInstance) {\n            mMsisdn = contact;\n            super.notify();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningResult.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\n/**\n * HTTPS provisioning result\n * \n * @author jexa7410\n * @author Deutsche Telekom\n */\npublic class HttpsProvisioningResult {\n\n    public static int UNKNOWN_REASON_CODE = -1;\n\n    public static int UNKNOWN_MSISDN_CODE = -2;\n\n    /**\n     * Return code\n     */\n    public int code = UNKNOWN_REASON_CODE;\n\n    /**\n     * Value of header RetryAfter\n     */\n    public long retryAfter = 0;\n\n    /**\n     * Response content\n     */\n    public String content = null;\n\n    /**\n     * Controls if is waiting for the SMS with the one time password (OTP)\n     */\n    public boolean waitingForSMSOTP = false;\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningSMS.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport static com.gsma.rcs.utils.StringUtils.PDUS;\n\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.provisioning.ProvisioningFailureReasons;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.telephony.SmsMessage;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.Random;\n\n/**\n * HTTPS provisioning - SMS management\n * \n * @author Orange\n */\npublic class HttpsProvisioningSMS {\n\n    private static final String OTP_SMS_ENCODING_FORMAT = \"UCS2\";\n    /**\n     * HttpsProvisioningManager manages HTTP and SMS reception to load provisioning from network\n     */\n    private HttpsProvisioningManager mManager;\n\n    /**\n     * OTP SMS receiver\n     */\n    private BroadcastReceiver mOtpSmsReceiver;\n\n    private static final Logger sLogger = Logger.getLogger(HttpsProvisioningSMS.class.getName());\n\n    private final Context mContext;\n\n    /**\n     * Constructor\n     * \n     * @param httpsProvisioningManager HTTPs provisioning manager\n     * @param context application context\n     */\n    public HttpsProvisioningSMS(HttpsProvisioningManager httpsProvisioningManager, Context context) {\n        mManager = httpsProvisioningManager;\n        mContext = context;\n    }\n\n    /**\n     * Generate an SMS port for provisioning\n     * \n     * @return SMS port\n     */\n    protected static String generateSmsPortForProvisioning() {\n        int minPort = 10000;\n        int maxPort = 40000;\n        return String.valueOf((new Random()).nextInt(maxPort - minPort) + minPort);\n    }\n\n    /**\n     * Register the SMS provisioning receiver\n     * \n     * @param smsPort SMS port\n     * @param requestUri Request URI\n     */\n    public void registerSmsProvisioningReceiver(final String smsPort, final String requestUri) {\n        // Unregister previous one\n        unregisterSmsProvisioningReceiver();\n\n        final boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Registering SMS provider receiver in port: \".concat(smsPort));\n        }\n\n        /* Instantiate the receiver */\n        mOtpSmsReceiver = new BroadcastReceiver() {\n            @Override\n            public void onReceive(final Context ctx, final Intent intent) {\n                mManager.scheduleProvisioningOperation(new Runnable() {\n                    @Override\n                    public void run() {\n                        try {\n                            String action = intent.getAction();\n                            if (logActivated) {\n                                sLogger.debug(\"SMS provider receiver - Received broadcast: \"\n                                        + action);\n                            }\n                            if (!HttpsProvisioningUtils.ACTION_BINARY_SMS_RECEIVED.equals(action)) {\n                                return;\n                            }\n                            Bundle bundle = intent.getExtras();\n                            if (bundle == null) {\n                                return;\n                            }\n                            Object[] pdus = (Object[]) bundle.get(PDUS);\n                            if (pdus == null || pdus.length == 0) {\n                                if (logActivated) {\n                                    sLogger.debug(\"Bundle contains no raw PDUs\");\n                                }\n                                return;\n                            }\n                            if (logActivated) {\n                                sLogger.debug(\"Receiving binary SMS\");\n                            }\n                            SmsMessage[] msgs = new SmsMessage[pdus.length];\n                            byte[] data;\n                            byte[] smsBuffer = new byte[0];\n                            byte[] smsBufferTemp;\n\n                            for (int i = 0; i < msgs.length; i++) {\n                                msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);\n\n                                data = msgs[i].getUserData();\n                                smsBufferTemp = new byte[smsBuffer.length + data.length];\n                                System.arraycopy(smsBuffer, 0, smsBufferTemp, 0, smsBuffer.length);\n                                System.arraycopy(data, 0, smsBufferTemp, smsBuffer.length,\n                                        data.length);\n                                smsBuffer = smsBufferTemp;\n                            }\n\n                            final String smsData = new String(smsBuffer, OTP_SMS_ENCODING_FORMAT);\n\n                            if (logActivated) {\n                                sLogger.debug(\"Binary SMS received with :\".concat(smsData));\n                            }\n\n                            mManager.updateConfigWithOTP(smsData, requestUri);\n                            unregisterSmsProvisioningReceiver();\n\n                        } catch (UnsupportedEncodingException e) {\n                            sLogger.error(\"'\" + OTP_SMS_ENCODING_FORMAT\n                                    + \"'format not supported for requestUri : \" + requestUri, e);\n                        } catch (RcsAccountException e) {\n                            sLogger.error(\"Failed to update Config with OTP for requestUri : \"\n                                    + requestUri, e);\n                        } catch (IOException e) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Failed to update Config with OTP for requestUri : \"\n                                        + requestUri + \", Message=\" + e.getMessage());\n                            }\n                            /* Start the RCS service */\n                            if (mManager.isFirstProvisioningAfterBoot()) {\n                                // Reason: No configuration present\n                                mManager.provisioningFails(ProvisioningFailureReasons.CONNECTIVITY_ISSUE);\n                                mManager.retry();\n                            } else {\n                                mManager.tryLaunchRcsCoreService(ctx, -1);\n                            }\n                        } catch (RuntimeException e) {\n                            /*\n                             * Normally we are not allowed to catch runtime exceptions as these are\n                             * genuine bugs which should be handled/fixed within the code. However\n                             * the cases when we are executing operations on a thread unhandling\n                             * such exceptions will eventually lead to exit the system and thus can\n                             * bring the whole system down, which is not intended.\n                             */\n                            sLogger.error(\"Failed to update Config with OTP for requestUri : \"\n                                    + requestUri, e);\n                        }\n                    }\n                });\n            }\n        };\n\n        // Register receiver\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(HttpsProvisioningUtils.ACTION_BINARY_SMS_RECEIVED);\n        intentFilter.addDataScheme(\"sms\");\n        intentFilter.addDataAuthority(\"*\", smsPort);\n        intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);\n        mContext.registerReceiver(mOtpSmsReceiver, intentFilter);\n    }\n\n    /**\n     * Unregister the SMS provisioning receiver\n     */\n    public void unregisterSmsProvisioningReceiver() {\n        if (mOtpSmsReceiver == null) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Unregistering SMS provider receiver\");\n        }\n\n        try {\n            mContext.unregisterReceiver(mOtpSmsReceiver);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n        mOtpSmsReceiver = null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.provisioning.ProvisioningFailureReasons;\nimport com.gsma.rcs.provisioning.ProvisioningInfo.Version;\nimport com.gsma.rcs.provisioning.TermsAndConditionsRequest;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.TimerUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.ConnectivityManager;\nimport android.os.IBinder;\nimport android.telephony.TelephonyManager;\nimport android.text.format.DateUtils;\n\nimport java.io.IOException;\n\n/**\n * HTTPS auto configuration service\n * \n * @author hlxn7157\n * @author G. LE PESSOT\n * @author Deutsche Telekom AG\n * @author yplo6403\n */\npublic class HttpsProvisioningService extends Service {\n    /**\n     * Intent key - Provisioning requested after (re)boot\n     */\n    private static final String FIRST_KEY = \"first\";\n\n    /**\n     * Intent key - Provisioning requested by user\n     */\n    private static final String USER_KEY = \"user\";\n\n    /**\n     * Retry Intent\n     */\n    private PendingIntent mRetryIntent;\n\n    private RcsSettings mRcsSettings;\n\n    /**\n     * Provisioning manager\n     */\n    private HttpsProvisioningManager mHttpsProvisioningMng;\n\n    private LocalContentResolver mLocalContentResolver;\n\n    private Context mContext;\n\n    private MessagingLog mMessagingLog;\n\n    private ContactManager mContactManager;\n\n    /**\n     * Retry action for provisioning failure\n     */\n    private static final String ACTION_RETRY = \"com.gsma.rcs.provisioning.https.HttpsProvisioningService.ACTION_RETRY\";\n\n    private static final Logger sLogger = Logger\n            .getLogger(HttpsProvisioningService.class.getName());\n\n    @Override\n    public void onCreate() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"onCreate\");\n        }\n        mContext = getApplicationContext();\n        ContentResolver contentResolver = mContext.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(contentResolver);\n        mRcsSettings = RcsSettings.getInstance(mLocalContentResolver);\n        mMessagingLog = MessagingLog.getInstance(mLocalContentResolver, mRcsSettings);\n        mRetryIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_RETRY), 0);\n        mContactManager = ContactManager.getInstance(mContext, contentResolver,\n                mLocalContentResolver, mRcsSettings);\n    }\n\n    @Override\n    public int onStartCommand(final Intent intent, int flags, int startId) {\n        // @FIXME: Below code block needs a complete refactor, However at this\n        // moment due to other prior tasks the refactoring task has been kept in\n        // backlog.\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Start HTTPS provisioning\");\n        }\n\n        boolean first = false;\n        boolean user = false;\n        if (intent != null) {\n            first = intent.getBooleanExtra(FIRST_KEY, false);\n            user = intent.getBooleanExtra(USER_KEY, false);\n        }\n        int version = mRcsSettings.getProvisioningVersion();\n\n        if (Version.RESETED.toInt() == version) {\n            first = true;\n        }\n        registerReceiver(retryReceiver, new IntentFilter(ACTION_RETRY));\n\n        TelephonyManager tm = (TelephonyManager) mContext\n                .getSystemService(Context.TELEPHONY_SERVICE);\n        String imsi = tm.getSubscriberId();\n        if (imsi == null) {\n            /*\n             * IMSI may be null if SIM card is not present or Telephony manager is not fully\n             * initialized and it is not the first launch. We should then consider the last user\n             * account.\n             */\n            imsi = LauncherUtils.getLastUserAccount(mContext);\n        }\n        String imei = tm.getDeviceId();\n\n        mHttpsProvisioningMng = new HttpsProvisioningManager(imei, imsi, mContext,\n                mLocalContentResolver, mRetryIntent, first, user, mRcsSettings, mMessagingLog,\n                mContactManager);\n        mHttpsProvisioningMng.initialize();\n        if (logActivated) {\n            sLogger.debug(\"Provisioning (first=\" + first + \") (user=\" + user + \") (version=\"\n                    + version + \")\");\n        }\n\n        boolean requestConfig = false;\n        if (TermsAndConditionsResponse.DECLINED == mRcsSettings.getTermsAndConditionsResponse()) {\n            if (logActivated) {\n                sLogger.debug(\"Do not request configuration since TC were declined!\");\n            }\n        } else if (first) {\n            requestConfig = true;\n        } else if (Version.RESETED.toInt() == version) {\n            requestConfig = true;\n        } else if (Version.RESETED_NOQUERY.toInt() == version) {\n            // Nothing to do\n        } else if (Version.DISABLED_NOQUERY.toInt() == version) {\n            if (user) {\n                requestConfig = true;\n            }\n        } else if (Version.DISABLED_DORMANT.toInt() == version && user) {\n            requestConfig = true;\n        } else { // version > 0\n            long expiration = LauncherUtils.getProvisioningExpirationDate(this);\n            if (expiration <= 0) {\n                requestConfig = true;\n            } else {\n                long now = System.currentTimeMillis();\n                if (expiration <= now) {\n                    if (logActivated) {\n                        sLogger.debug(\"Configuration validity expired at \".concat(DateUtils\n                                .formatDateTime(mContext, expiration, DateUtils.FORMAT_SHOW_DATE\n                                        | DateUtils.FORMAT_SHOW_TIME\n                                        | DateUtils.FORMAT_NUMERIC_DATE)));\n                    }\n                    requestConfig = true;\n                } else {\n                    if (TermsAndConditionsResponse.NO_ANSWER == mRcsSettings\n                            .getTermsAndConditionsResponse()) {\n                        TermsAndConditionsRequest.showTermsAndConditions(mContext);\n                    }\n                    long delay = expiration - now;\n                    long validity = LauncherUtils.getProvisioningValidity(this);\n                    if (validity > 0 && delay > validity) {\n                        delay = validity;\n                    }\n                    if (logActivated) {\n                        sLogger.debug(\"Configuration will expire at \"\n                                + DateUtils.formatDateTime(mContext, expiration,\n                                        DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME\n                                                | DateUtils.FORMAT_NUMERIC_DATE));\n                    }\n                    startRetryAlarm(this, mRetryIntent, delay);\n                }\n            }\n        }\n\n        if (requestConfig) {\n            if (logActivated)\n                sLogger.debug(\"Request HTTP configuration update\");\n            mHttpsProvisioningMng.scheduleProvisioningOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        // Send default connection event\n                        if (!mHttpsProvisioningMng\n                                .connectionEvent(ConnectivityManager.CONNECTIVITY_ACTION)) {\n                            // If the UpdateConfig has NOT been done:\n                            mHttpsProvisioningMng.registerNetworkStateListener();\n                        }\n\n                    } catch (RcsAccountException e) {\n                        /**\n                         * This is a non revocable use-case as the RCS account itself was not\n                         * created, So we log this as error and stop the service itself.\n                         */\n                        sLogger.error(\"Failed to handle connection event!\", e);\n                        stopSelf();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Unable to handle connection event!\", e);\n\n                    } catch (IOException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Unable to handle connection event, Message=\"\n                                    + e.getMessage());\n                        }\n                        /* Start the RCS service */\n                        if (mHttpsProvisioningMng.isFirstProvisioningAfterBoot()) {\n                            /* Reason: No configuration present */\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Initial provisioning failed!\");\n                            }\n                            mHttpsProvisioningMng\n                                    .provisioningFails(ProvisioningFailureReasons.CONNECTIVITY_ISSUE);\n                            mHttpsProvisioningMng.retry();\n                        } else {\n                            mHttpsProvisioningMng.tryLaunchRcsCoreService(mContext, -1);\n                        }\n                    }\n                }\n            });\n        }\n        /*\n         * We want this service to continue running until it is explicitly stopped, so return\n         * sticky.\n         */\n        return START_STICKY;\n    }\n\n    /**\n     * Start retry alarm\n     * \n     * @param context the application context\n     * @param intent the pending intent to execute when alarm is raised\n     * @param delay delay in milliseconds\n     */\n    public static void startRetryAlarm(Context context, PendingIntent intent, long delay) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Retry HTTP configuration update in \"\n                    + DateUtils.formatElapsedTime(delay / 1000));\n        }\n        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        TimerUtils.setExactTimer(am, System.currentTimeMillis() + delay, intent);\n    }\n\n    /**\n     * Cancel retry alarm\n     * \n     * @param context the application context\n     * @param intent the pending intent to cancel\n     */\n    public static void cancelRetryAlarm(Context context, PendingIntent intent) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop retry configuration update\");\n        }\n        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        am.cancel(intent);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (mHttpsProvisioningMng != null) {\n            mHttpsProvisioningMng.unregisterNetworkStateListener();\n            mHttpsProvisioningMng.unregisterWifiDisablingListener();\n            mHttpsProvisioningMng.unregisterSmsProvisioningReceiver();\n            mHttpsProvisioningMng.quitProvisioningOperation();\n        }\n        cancelRetryAlarm(this, mRetryIntent);\n        try {\n            unregisterReceiver(retryReceiver);\n        } catch (IllegalArgumentException e) {\n            /* Nothing to be handled here */\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    /**\n     * Retry receiver\n     */\n    private BroadcastReceiver retryReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, final Intent intent) {\n            mHttpsProvisioningMng.scheduleProvisioningOperation(new Runnable() {\n                public void run() {\n                    try {\n                        mHttpsProvisioningMng.updateConfig();\n\n                    } catch (RcsAccountException | RuntimeException e) {\n                        sLogger.error(\"Failed to update configuration!\", e);\n\n                    } catch (IOException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Unable to handle connection event, Message=\"\n                                    + e.getMessage());\n                        }\n                        /* Start the RCS service */\n                        if (mHttpsProvisioningMng.isFirstProvisioningAfterBoot()) {\n                            /* Reason: No configuration present */\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Initial provisioning failed!\");\n                            }\n                            mHttpsProvisioningMng\n                                    .provisioningFails(ProvisioningFailureReasons.CONNECTIVITY_ISSUE);\n                            mHttpsProvisioningMng.retry();\n                        } else {\n                            mHttpsProvisioningMng.tryLaunchRcsCoreService(mContext, -1);\n                        }\n                    }\n                }\n            });\n        }\n    };\n\n    /**\n     * Start the HTTPs provisioning service\n     *\n     * @param ctx the application context\n     * @param firstLaunch first launch after (re)boot\n     * @param userLaunch launch is requested by user action\n     */\n    public static void startHttpsProvisioningService(Context ctx, boolean firstLaunch,\n            boolean userLaunch) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"startHttpsProvisioningService (first=\" + firstLaunch + \") (user=\"\n                    + userLaunch + \")\");\n        }\n        Intent provisioningIntent = new Intent(ctx, HttpsProvisioningService.class);\n        provisioningIntent.putExtra(FIRST_KEY, firstLaunch);\n        provisioningIntent.putExtra(USER_KEY, userLaunch);\n        ctx.startService(provisioningIntent);\n    }\n\n    /**\n     * Re-provision\n     *\n     * @param ctx the application context\n     */\n    public static void reProvisioning(Context ctx) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Request re-provisioning\");\n        }\n        ctx.sendBroadcast(new Intent(ACTION_RETRY));\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/HttpsProvisioningUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport java.util.Locale;\n\n/**\n * HTTPS provisioning - utils\n * \n * @author Orange\n */\npublic class HttpsProvisioningUtils {\n\n    /**\n     * Input MSISDN timeout\n     */\n    /* package private */static final int INPUT_MSISDN_TIMEOUT = 60000;\n\n    /**\n     * Retry base timeout - 5min (in milliseconds)\n     */\n    /* package private */static final int RETRY_BASE_TIMEOUT = 300000;\n\n    /**\n     * Retry after an 511 \"Network authentication required\" timeout (in milliseconds)\n     */\n    /* package private */static final int RETRY_AFTER_511_ERROR_TIMEOUT = 5000;\n\n    /**\n     * The action if a binary SMS received\n     */\n    /* package private */static final String ACTION_BINARY_SMS_RECEIVED = \"android.intent.action.DATA_SMS_RECEIVED\";\n\n    /**\n     * Char sequence in a binary SMS to indicate a network initiated configuration\n     */\n    /* package private */static final String RESET_CONFIG_SUFFIX = \"-rcscfg\";\n\n    /**\n     * Retry max count\n     */\n    /* package private */static final int RETRY_MAX_COUNT = 5;\n\n    /**\n     * Retry after 511 \"Network authentication required\" max count\n     */\n    /* package private */static final int RETRY_AFTER_511_ERROR_MAX_COUNT = 5;\n\n    /**\n     * Get the current device language\n     * \n     * @return Device language (like fr-FR)\n     */\n    /* package private */static String getUserLanguage() {\n        return Locale.getDefault().getLanguage() + \"-\" + Locale.getDefault().getCountry();\n    }\n\n    /**\n     * Returns the RCS version\n     * \n     * @return String(4)\n     */\n    /* package private */static String getRcsVersion() {\n        return \"5.1B\";\n    }\n\n    /**\n     * Returns the RCS profile\n     *\n     * @return String(15)\n     */\n    /* package private */static String getRcsProfile() {\n        return \"joyn_blackbird\";\n    }\n\n    /**\n     * Returns the Enrich Calling profile\n     *\n     * @return String(15)\n     */\n    /* package private */static String getEnrichCallingProfile() {\n        return \"enriched_call\";\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/https/ProvisioningPushSMSReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * \n * Copyright (C) 2016 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n *******************************************************************************/\n\npackage com.gsma.rcs.provisioning.https;\n\nimport static com.gsma.rcs.utils.StringUtils.PDUS;\nimport static com.gsma.rcs.utils.StringUtils.UTF16;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provisioning.ProvisioningInfo;\nimport com.gsma.rcs.service.LauncherUtils;\nimport com.gsma.rcs.utils.NetworkUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.BroadcastReceiver;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.telephony.SmsMessage;\nimport android.telephony.TelephonyManager;\n\n/**\n * Handles the network initiated configuration request i.e provisioning push sms sent to port 37273.\n * IMSI-rcscfg is sent for First time configuration request and Private_User_Identity-rcscfg is sent\n * for reconfiguration request.\n */\npublic class ProvisioningPushSMSReceiver extends BroadcastReceiver {\n\n    private static final Logger sLogger = Logger.getLogger(ProvisioningPushSMSReceiver.class\n            .getName());\n\n    @Override\n    public void onReceive(Context ctx, Intent intent) {\n        final boolean logActivated = sLogger.isActivated();\n        String action = intent.getAction();\n        if (logActivated) {\n            sLogger.debug(\"Configuration SMS receiver - Received broadcast: \" + action);\n        }\n        if (!HttpsProvisioningUtils.ACTION_BINARY_SMS_RECEIVED.equals(action)) {\n            return;\n        }\n        Bundle bundle = intent.getExtras();\n        if (bundle == null) {\n            if (logActivated) {\n                sLogger.debug(\"Bundle is received with null\");\n            }\n            return;\n        }\n        Object[] pdus = (Object[]) bundle.get(PDUS);\n        if (pdus == null || pdus.length == 0) {\n            if (logActivated) {\n                sLogger.debug(\"Bundle contains no raw PDUs\");\n            }\n            return;\n        }\n        final SmsMessage msg = SmsMessage.createFromPdu((byte[]) pdus[0]);\n        final String smsData = new String(msg.getUserData(), UTF16);\n        if (logActivated) {\n            sLogger.debug(\"Binary SMS received with :\".concat(smsData));\n        }\n\n        if (smsData.endsWith(HttpsProvisioningUtils.RESET_CONFIG_SUFFIX)) {\n            final ContentResolver resolver = ctx.getContentResolver();\n            final LocalContentResolver localResolver = new LocalContentResolver(resolver);\n            final RcsSettings rcsSettings = RcsSettings.getInstance(localResolver);\n            final TelephonyManager telephonyManager = (TelephonyManager) ctx\n                    .getSystemService(Context.TELEPHONY_SERVICE);\n\n            if (smsData.contains(telephonyManager.getSubscriberId())) {\n                resetConfigurationThenRestart(ctx, resolver, localResolver, rcsSettings);\n            } else if (smsData.contains(rcsSettings.getUserProfileImsPrivateId())) {\n                if (NetworkUtils.getNetworkAccessType() == NetworkUtils.NETWORK_ACCESS_WIFI) {\n                    tryUnRegister();\n                    /*\n                     * Only set version number to 0 in order to keep MSISDN and token.\n                     * Reprovisioning is done silently: the user is not prompted to enter its\n                     * MSISDN.\n                     */\n                    rcsSettings.setProvisioningVersion(ProvisioningInfo.Version.RESETED.toInt());\n                    HttpsProvisioningService.reProvisioning(ctx);\n                } else {\n                    resetConfigurationThenRestart(ctx, resolver, localResolver, rcsSettings);\n                }\n            }\n        }\n    }\n\n    private void resetConfigurationThenRestart(Context ctx, ContentResolver resolver,\n            LocalContentResolver localResolver, RcsSettings rcsSettings) {\n        /* IMSI in smsData : fresh provisioning */\n        LauncherUtils.stopRcsService(ctx);\n        final ContactManager contactManager = ContactManager.getInstance(ctx, resolver,\n                localResolver, rcsSettings);\n        final MessagingLog messagingLog = MessagingLog.getInstance(localResolver, rcsSettings);\n        LauncherUtils.resetRcsConfig(ctx, localResolver, rcsSettings, messagingLog, contactManager);\n        LauncherUtils.launchRcsService(ctx, true, false, rcsSettings);\n    }\n\n    private void tryUnRegister() {\n        new Thread(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    Core core = Core.getInstance();\n                    if (core != null) {\n                        ImsNetworkInterface networkInterface = core.getImsModule()\n                                .getCurrentNetworkInterface();\n                        if (networkInterface.isRegistered()) {\n                            networkInterface.unregister();\n                        }\n                    }\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Unable to unregister, error=\" + e.getMessage());\n                    }\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Unable to unregister!\", e);\n                }\n            }\n        }).start();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/CapabilitiesProvisioning.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Logger provisioning fragment\n * \n * @author jexa7410\n */\npublic class CapabilitiesProvisioning extends Fragment implements IProvisioningFragment {\n\n    private static final Logger sLogger = Logger\n            .getLogger(CapabilitiesProvisioning.class.getName());\n\n    private static RcsSettings sRcsSettings;\n    private ProvisioningHelper mHelper;\n\n    public static CapabilitiesProvisioning newInstance(RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"new instance\");\n        }\n        CapabilitiesProvisioning f = new CapabilitiesProvisioning();\n        /*\n         * If Android decides to recreate your Fragment later, it's going to call the no-argument\n         * constructor of your fragment. So overloading the constructor is not a solution. A way to\n         * pass argument to new fragment is to store it as static.\n         */\n        sRcsSettings = rcsSettings;\n        return f;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        View rootView = inflater.inflate(R.layout.provisioning_capabilities, container, false);\n        mHelper = new ProvisioningHelper(rootView, sRcsSettings);\n        displayRcsSettings();\n        return rootView;\n    }\n\n    @Override\n    public void displayRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"displayRcsSettings\");\n        }\n        mHelper.setBoolCheckBox(R.id.image_sharing, RcsSettingsData.CAPABILITY_IMAGE_SHARING);\n        mHelper.setBoolCheckBox(R.id.video_sharing, RcsSettingsData.CAPABILITY_VIDEO_SHARING);\n        mHelper.setBoolCheckBox(R.id.file_transfer_msrp, RcsSettingsData.CAPABILITY_FILE_TRANSFER);\n        mHelper.setBoolCheckBox(R.id.file_transfer_http,\n                RcsSettingsData.CAPABILITY_FILE_TRANSFER_HTTP);\n        mHelper.setBoolCheckBox(R.id.im, RcsSettingsData.CAPABILITY_IM_SESSION);\n        mHelper.setBoolCheckBox(R.id.im_group, RcsSettingsData.CAPABILITY_IM_GROUP_SESSION);\n        mHelper.setBoolCheckBox(R.id.ipvoicecall, RcsSettingsData.CAPABILITY_IP_VOICE_CALL);\n        mHelper.setBoolCheckBox(R.id.ipvideocall, RcsSettingsData.CAPABILITY_IP_VIDEO_CALL);\n        mHelper.setBoolCheckBox(R.id.cs_video, RcsSettingsData.CAPABILITY_CS_VIDEO);\n        mHelper.setBoolCheckBox(R.id.presence_discovery,\n                RcsSettingsData.CAPABILITY_PRESENCE_DISCOVERY);\n        mHelper.setBoolCheckBox(R.id.social_presence, RcsSettingsData.CAPABILITY_SOCIAL_PRESENCE);\n        mHelper.setBoolCheckBox(R.id.geolocation_push, RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH);\n        mHelper.setBoolCheckBox(R.id.file_transfer_thumbnail,\n                RcsSettingsData.CAPABILITY_FILE_TRANSFER_THUMBNAIL);\n        mHelper.setBoolCheckBox(R.id.file_transfer_sf, RcsSettingsData.CAPABILITY_FILE_TRANSFER_SF);\n        mHelper.setBoolCheckBox(R.id.group_chat_sf, RcsSettingsData.CAPABILITY_GROUP_CHAT_SF);\n        mHelper.setBoolCheckBox(R.id.sip_automata, RcsSettingsData.CAPABILITY_SIP_AUTOMATA);\n        mHelper.setBoolCheckBox(R.id.call_composer, RcsSettingsData.CAPABILITY_CALL_COMPOSER);\n        mHelper.setBoolCheckBox(R.id.shared_map, RcsSettingsData.CAPABILITY_SHARED_MAP);\n        mHelper.setBoolCheckBox(R.id.shared_sketch, RcsSettingsData.CAPABILITY_SHARED_SKETCH);\n        mHelper.setBoolCheckBox(R.id.post_call, RcsSettingsData.CAPABILITY_POST_CALL);\n    }\n\n    @Override\n    public void persistRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"persistRcsSettings\");\n        }\n        mHelper.saveBoolCheckBox(R.id.image_sharing, RcsSettingsData.CAPABILITY_IMAGE_SHARING);\n        mHelper.saveBoolCheckBox(R.id.video_sharing, RcsSettingsData.CAPABILITY_VIDEO_SHARING);\n        mHelper.saveBoolCheckBox(R.id.file_transfer_msrp, RcsSettingsData.CAPABILITY_FILE_TRANSFER);\n        mHelper.saveBoolCheckBox(R.id.file_transfer_http,\n                RcsSettingsData.CAPABILITY_FILE_TRANSFER_HTTP);\n        mHelper.saveBoolCheckBox(R.id.im, RcsSettingsData.CAPABILITY_IM_SESSION);\n        mHelper.saveBoolCheckBox(R.id.im_group, RcsSettingsData.CAPABILITY_IM_GROUP_SESSION);\n        mHelper.saveBoolCheckBox(R.id.ipvoicecall, RcsSettingsData.CAPABILITY_IP_VOICE_CALL);\n        mHelper.saveBoolCheckBox(R.id.ipvideocall, RcsSettingsData.CAPABILITY_IP_VIDEO_CALL);\n        mHelper.saveBoolCheckBox(R.id.cs_video, RcsSettingsData.CAPABILITY_CS_VIDEO);\n        mHelper.saveBoolCheckBox(R.id.presence_discovery,\n                RcsSettingsData.CAPABILITY_PRESENCE_DISCOVERY);\n        mHelper.saveBoolCheckBox(R.id.social_presence, RcsSettingsData.CAPABILITY_SOCIAL_PRESENCE);\n        mHelper.saveBoolCheckBox(R.id.geolocation_push, RcsSettingsData.CAPABILITY_GEOLOCATION_PUSH);\n        mHelper.saveBoolCheckBox(R.id.file_transfer_thumbnail,\n                RcsSettingsData.CAPABILITY_FILE_TRANSFER_THUMBNAIL);\n        mHelper.saveBoolCheckBox(R.id.file_transfer_sf, RcsSettingsData.CAPABILITY_FILE_TRANSFER_SF);\n        mHelper.saveBoolCheckBox(R.id.group_chat_sf, RcsSettingsData.CAPABILITY_GROUP_CHAT_SF);\n        mHelper.saveBoolCheckBox(R.id.sip_automata, RcsSettingsData.CAPABILITY_SIP_AUTOMATA);\n        mHelper.saveBoolCheckBox(R.id.call_composer, RcsSettingsData.CAPABILITY_CALL_COMPOSER);\n        mHelper.saveBoolCheckBox(R.id.shared_map, RcsSettingsData.CAPABILITY_SHARED_MAP);\n        mHelper.saveBoolCheckBox(R.id.shared_sketch, RcsSettingsData.CAPABILITY_SHARED_SKETCH);\n        mHelper.saveBoolCheckBox(R.id.post_call, RcsSettingsData.CAPABILITY_POST_CALL);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/IProvisioningFragment.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\n/**\n * Provisioning\n * \n * @author Philippe LEMORDANT\n */\npublic interface IProvisioningFragment {\n\n    void persistRcsSettings();\n\n    void displayRcsSettings();\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/LoggerProvisioning.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.Spinner;\n\n/**\n * Logger provisioning fragment\n * \n * @author jexa7410\n */\npublic class LoggerProvisioning extends Fragment implements IProvisioningFragment {\n\n    private static final Logger sLogger = Logger.getLogger(LoggerProvisioning.class.getName());\n\n    private static final String[] TRACE_LEVEL = {\n            \"DEBUG\", \"INFO\", \"WARN\", \"ERROR\", \"FATAL\"\n    };\n\n    private static RcsSettings sRcsSettings;\n    private View mRootView;\n    private ProvisioningHelper mHelper;\n\n    public static LoggerProvisioning newInstance(RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"new instance\");\n        }\n        LoggerProvisioning f = new LoggerProvisioning();\n        /*\n         * If Android decides to recreate your Fragment later, it's going to call the no-argument\n         * constructor of your fragment. So overloading the constructor is not a solution. A way to\n         * pass argument to new fragment is to store it as static.\n         */\n        sRcsSettings = rcsSettings;\n        return f;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        mRootView = inflater.inflate(R.layout.provisioning_logger, container, false);\n        mHelper = new ProvisioningHelper(mRootView, sRcsSettings);\n        displayRcsSettings();\n        return mRootView;\n    }\n\n    @Override\n    public void displayRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"displayRcsSettings\");\n        }\n        mHelper.setBoolCheckBox(R.id.TraceActivated, RcsSettingsData.TRACE_ACTIVATED);\n        mHelper.setBoolCheckBox(R.id.SipTraceActivated, RcsSettingsData.SIP_TRACE_ACTIVATED);\n        mHelper.setBoolCheckBox(R.id.MediaTraceActivated, RcsSettingsData.MEDIA_TRACE_ACTIVATED);\n        mHelper.setStringEditText(R.id.SipTraceFile, RcsSettingsData.SIP_TRACE_FILE);\n\n        Spinner spinner = (Spinner) mRootView.findViewById(R.id.TraceLevel);\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),\n                android.R.layout.simple_spinner_item, TRACE_LEVEL);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        spinner.setSelection(sRcsSettings.getTraceLevel());\n    }\n\n    @Override\n    public void persistRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"persistRcsSettings\");\n        }\n        mHelper.saveBoolCheckBox(R.id.TraceActivated, RcsSettingsData.TRACE_ACTIVATED);\n        mHelper.saveBoolCheckBox(R.id.SipTraceActivated, RcsSettingsData.SIP_TRACE_ACTIVATED);\n        mHelper.saveBoolCheckBox(R.id.MediaTraceActivated, RcsSettingsData.MEDIA_TRACE_ACTIVATED);\n        mHelper.saveStringEditText(R.id.SipTraceFile, RcsSettingsData.SIP_TRACE_FILE);\n        Spinner spinner = (Spinner) mRootView.findViewById(R.id.TraceLevel);\n        sRcsSettings.writeInteger(RcsSettingsData.TRACE_LEVEL, spinner.getSelectedItemPosition());\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/ProfileProvisioning.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.AuthenticationProcedure;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\n/**\n * End user profile parameters provisioning\n *\n * @author Philippe LEMORDANT\n */\npublic class ProfileProvisioning extends Fragment implements IProvisioningFragment {\n\n    private static final Logger sLogger = Logger.getLogger(ProfileProvisioning.class.getName());\n\n    /**\n     * IMS authentication for mobile access\n     */\n    private static final String[] MOBILE_IMS_AUTHENT = {\n            AuthenticationProcedure.GIBA.name(), AuthenticationProcedure.DIGEST.name()\n    };\n\n    private static RcsSettings sRcsSettings;\n    private View mRootView;\n    private ProvisioningHelper mHelper;\n\n    public static ProfileProvisioning newInstance(RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"new instance\");\n        }\n        ProfileProvisioning f = new ProfileProvisioning();\n        /*\n         * If Android decides to recreate your Fragment later, it's going to call the no-argument\n         * constructor of your fragment. So overloading the constructor is not a solution. A way to\n         * pass argument to new fragment is to store it as static.\n         */\n        sRcsSettings = rcsSettings;\n        return f;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        mRootView = inflater.inflate(R.layout.provisioning_profile, container, false);\n        mHelper = new ProvisioningHelper(mRootView, sRcsSettings);\n        displayRcsSettings();\n        return mRootView;\n    }\n\n    @Override\n    public void displayRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"displayRcsSettings\");\n        }\n        Spinner spinner = (Spinner) mRootView\n                .findViewById(R.id.ImsAuthenticationProcedureForMobile);\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),\n                android.R.layout.simple_spinner_item, MOBILE_IMS_AUTHENT);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        spinner.setSelection(sRcsSettings.getImsAuthenticationProcedureForMobile().toInt());\n\n        mHelper.setContactIdEditText(R.id.ImsUsername, RcsSettingsData.USERPROFILE_IMS_USERNAME);\n        mHelper.setStringEditText(R.id.ImsDisplayName, RcsSettingsData.USERPROFILE_IMS_DISPLAY_NAME);\n        mHelper.setStringEditText(R.id.ImsHomeDomain, RcsSettingsData.USERPROFILE_IMS_HOME_DOMAIN);\n        mHelper.setStringEditText(R.id.ImsPrivateId, RcsSettingsData.USERPROFILE_IMS_PRIVATE_ID);\n        mHelper.setStringEditText(R.id.ImsPassword, RcsSettingsData.USERPROFILE_IMS_PASSWORD);\n        mHelper.setStringEditText(R.id.ImsRealm, RcsSettingsData.USERPROFILE_IMS_REALM);\n        mHelper.setStringEditText(R.id.ImsOutboundProxyAddrForMobile,\n                RcsSettingsData.IMS_PROXY_ADDR_MOBILE);\n        mHelper.setIntEditText(R.id.ImsOutboundProxyPortForMobile,\n                RcsSettingsData.IMS_PROXY_PORT_MOBILE);\n        mHelper.setStringEditText(R.id.ImsOutboundProxyAddrForWifi,\n                RcsSettingsData.IMS_PROXY_ADDR_WIFI);\n        mHelper.setIntEditText(R.id.ImsOutboundProxyPortForWifi,\n                RcsSettingsData.IMS_PROXY_PORT_WIFI);\n        mHelper.setUriEditText(R.id.XdmServerAddr, RcsSettingsData.XDM_SERVER);\n        mHelper.setStringEditText(R.id.XdmServerLogin, RcsSettingsData.XDM_LOGIN);\n        mHelper.setStringEditText(R.id.XdmServerPassword, RcsSettingsData.XDM_PASSWORD);\n        mHelper.setUriEditText(R.id.FtHttpServerAddr, RcsSettingsData.FT_HTTP_SERVER);\n        mHelper.setStringEditText(R.id.FtHttpServerLogin, RcsSettingsData.FT_HTTP_LOGIN);\n        mHelper.setStringEditText(R.id.FtHttpServerPassword, RcsSettingsData.FT_HTTP_PASSWORD);\n        mHelper.setUriEditText(R.id.ImConferenceUri, RcsSettingsData.IM_CONF_URI);\n        mHelper.setUriEditText(R.id.EndUserConfReqUri, RcsSettingsData.ENDUSER_CONFIRMATION_URI);\n        mHelper.setStringEditText(R.id.RcsApn, RcsSettingsData.RCS_APN);\n\n        TextView txt = (TextView) mRootView.findViewById(R.id.release);\n        txt.setText(sRcsSettings.getGsmaRelease().name());\n        txt = (TextView) mRootView.findViewById(R.id.user_msg_title);\n        String title = sRcsSettings.getProvisioningUserMessageTitle();\n        if (title != null) {\n            txt.setText(title);\n        }\n        txt = (TextView) mRootView.findViewById(R.id.user_msg_content);\n        String content = sRcsSettings.getProvisioningUserMessageContent();\n        if (content != null) {\n            txt.setText(content);\n        }\n    }\n\n    @Override\n    public void persistRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"persistRcsSettings\");\n        }\n        Spinner spinner = (Spinner) mRootView\n                .findViewById(R.id.ImsAuthenticationProcedureForMobile);\n        AuthenticationProcedure procedure = AuthenticationProcedure.valueOf((String) spinner\n                .getSelectedItem());\n        sRcsSettings.setImsAuthenticationProcedureForMobile(procedure);\n\n        mHelper.saveContactIdEditText(R.id.ImsUsername, RcsSettingsData.USERPROFILE_IMS_USERNAME);\n        mHelper.saveStringEditText(R.id.ImsDisplayName,\n                RcsSettingsData.USERPROFILE_IMS_DISPLAY_NAME);\n        mHelper.saveStringEditText(R.id.ImsHomeDomain, RcsSettingsData.USERPROFILE_IMS_HOME_DOMAIN);\n        mHelper.saveStringEditText(R.id.ImsPrivateId, RcsSettingsData.USERPROFILE_IMS_PRIVATE_ID);\n        mHelper.saveStringEditText(R.id.ImsPassword, RcsSettingsData.USERPROFILE_IMS_PASSWORD);\n        mHelper.saveStringEditText(R.id.ImsRealm, RcsSettingsData.USERPROFILE_IMS_REALM);\n        mHelper.saveStringEditText(R.id.ImsOutboundProxyAddrForMobile,\n                RcsSettingsData.IMS_PROXY_ADDR_MOBILE);\n        mHelper.saveIntEditText(R.id.ImsOutboundProxyPortForMobile,\n                RcsSettingsData.IMS_PROXY_PORT_MOBILE);\n        mHelper.saveStringEditText(R.id.ImsOutboundProxyAddrForWifi,\n                RcsSettingsData.IMS_PROXY_ADDR_WIFI);\n        mHelper.saveIntEditText(R.id.ImsOutboundProxyPortForWifi,\n                RcsSettingsData.IMS_PROXY_PORT_WIFI);\n        mHelper.saveUriEditText(R.id.XdmServerAddr, RcsSettingsData.XDM_SERVER);\n        mHelper.saveStringEditText(R.id.XdmServerLogin, RcsSettingsData.XDM_LOGIN);\n        mHelper.saveStringEditText(R.id.XdmServerPassword, RcsSettingsData.XDM_PASSWORD);\n        mHelper.saveUriEditText(R.id.FtHttpServerAddr, RcsSettingsData.FT_HTTP_SERVER);\n        mHelper.saveStringEditText(R.id.FtHttpServerLogin, RcsSettingsData.FT_HTTP_LOGIN);\n        mHelper.saveStringEditText(R.id.FtHttpServerPassword, RcsSettingsData.FT_HTTP_PASSWORD);\n\n        sRcsSettings.setFileTransferHttpSupported(sRcsSettings.getFtHttpServer() != null\n                && sRcsSettings.getFtHttpLogin() != null\n                && sRcsSettings.getFtHttpPassword() != null);\n\n        mHelper.saveUriEditText(R.id.ImConferenceUri, RcsSettingsData.IM_CONF_URI);\n        mHelper.saveUriEditText(R.id.EndUserConfReqUri, RcsSettingsData.ENDUSER_CONFIRMATION_URI);\n        mHelper.saveStringEditText(R.id.RcsApn, RcsSettingsData.RCS_APN);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/Provisioning.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.provisioning.ProvisioningParser;\nimport com.gsma.rcs.utils.CloseableUtils;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.Manifest;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.support.annotation.NonNull;\nimport android.support.v4.app.ActivityCompat;\nimport android.support.v4.content.ContextCompat;\nimport android.support.v4.view.ViewPager;\nimport android.support.v7.app.AlertDialog;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.EditText;\nimport android.widget.Spinner;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport org.xml.sax.SAXException;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\n\n/**\n * A tool to handle the provisioning locally\n *\n * @author Philippe LEMORDANT\n */\npublic class Provisioning extends AppCompatActivity {\n\n    private static final String PROVISIONING_EXTENSION = \".xml\";\n    private static final int MY_PERMISSION_REQUEST_ALL = 5428;\n\n    /**\n     * The XML provisioning file loaded manually contains a MSISDN token which must be replaced by\n     * the actual value\n     */\n    private static final String TOKEN_MSISDN = \"__s__MSISDN__e__\";\n\n    /**\n     * Folder path for provisioning file\n     */\n    private static final String PROVISIONING_FOLDER_PATH = Environment\n            .getExternalStorageDirectory().getPath();\n    private String[] titles = new String[] {\n            \"Profile\", \"Stack\", \"Service\", \"Capabilities\", \"Logger\"\n    };\n\n    private static final Logger sLogger = Logger.getLogger(Provisioning.class.getName());\n    private ViewPagerAdapter mAdapter;\n    private RcsSettings mRcsSettings;\n    private Provisioning mActivity;\n    private BroadcastReceiver mReceiver;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mActivity = this;\n        setContentView(R.layout.provisioning);\n\n        LocalContentResolver localContentResolver = new LocalContentResolver(\n                getApplicationContext());\n        mRcsSettings = RcsSettings.getInstance(localContentResolver);\n        AndroidFactory.setApplicationContext(this, mRcsSettings);\n\n        ViewPager pager = (ViewPager) findViewById(R.id.viewpager);\n        SlidingTabLayout slidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);\n        mAdapter = new ViewPagerAdapter(getSupportFragmentManager(), titles, mRcsSettings);\n        pager.setAdapter(mAdapter);\n\n        slidingTabLayout.setViewPager(pager);\n        slidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {\n            @Override\n            public int getIndicatorColor(int position) {\n                return Color.WHITE;\n            }\n        });\n\n        IntentFilter filter = new IntentFilter(RcsService.ACTION_SERVICE_UP);\n        mReceiver = new BroadcastReceiver() {\n            @Override\n            public void onReceive(Context context, Intent intent) {\n                for (IProvisioningFragment fragment : mAdapter.getFragments()) {\n                    fragment.displayRcsSettings();\n                }\n            }\n        };\n        registerReceiver(mReceiver, filter);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        // Inflate the menu; this adds items to the action bar if it is present.\n        getMenuInflater().inflate(R.menu.menu_provisioning, menu);\n        return true;\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        try {\n            if (mReceiver != null) {\n                unregisterReceiver(mReceiver);\n            }\n        } catch (Exception ignored) {\n        }\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        switch (item.getItemId()) {\n            case R.id.save:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Save provisioning\");\n                }\n                for (IProvisioningFragment fragment : mAdapter.getFragments()) {\n                    fragment.persistRcsSettings();\n                }\n                Toast.makeText(this, getString(R.string.label_reboot_service), Toast.LENGTH_LONG)\n                        .show();\n                return true;\n\n            case R.id.load:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Load provisioning\");\n                }\n                loadXmlFile();\n                return true;\n\n            case R.id.about:\n                displayInfo();\n                return true;\n\n            default:\n                return super.onOptionsItemSelected(item);\n        }\n    }\n\n    /**\n     * Returns the application version from manifest file\n     *\n     * @return Application version or null if not found\n     */\n    private String getAppVersion() {\n        String version = \"\";\n        try {\n            PackageInfo info = getPackageManager().getPackageInfo(\n                    RcsServiceControl.RCS_STACK_PACKAGENAME, 0);\n            version = info.versionName + \".\" + info.versionCode;\n\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        return version;\n    }\n\n    /**\n     * Returns the GSMA version\n     *\n     * @return String\n     */\n    private String getGsmaVersion() {\n        StringBuilder version = new StringBuilder(\"API \");\n        version.append(RcsService.Build.API_CODENAME);\n        version.append(\" \");\n        switch (RcsService.Build.API_VERSION) {\n            case RcsService.Build.VERSION_CODES.BASE:\n                version.append(\"Albatros 2.0.\");\n                break;\n            case RcsService.Build.VERSION_CODES.BLACKBIRD:\n                version.append(\"Blackbird 1.5.\");\n                break;\n            case RcsService.Build.VERSION_CODES.CPR:\n                version.append(\"Crane PR 1.6.\");\n                break;\n            default:\n                version.append(\"Unknown 0.0\");\n        }\n        version.append(RcsService.Build.API_INCREMENTAL);\n        return version.toString();\n    }\n\n    private void displayInfo() {\n        View view = View.inflate(mActivity, R.layout.rcs_provisioning_about, null);\n        // Display application release\n        TextView releaseView = (TextView) view.findViewById(R.id.app_version);\n        releaseView.setText(getString(R.string.label_about_app_version, getAppVersion()));\n        // Display GSMA version\n        TextView gsmaView = (TextView) view.findViewById(R.id.gsma_version);\n        gsmaView.setText(getGsmaVersion());\n        AlertDialog.Builder builder = new AlertDialog.Builder(this).setTitle(R.string.label_about)\n                .setView(view).setPositiveButton(R.string.label_ok, null);\n        AlertDialog dialog = builder.create();\n        dialog.setCanceledOnTouchOutside(false);\n        dialog.show();\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,\n            @NonNull int[] grantResults) {\n        super.onRequestPermissionsResult(requestCode, permissions, grantResults);\n        if (MY_PERMISSION_REQUEST_ALL == requestCode) {\n            // Check if the only required permission has been granted\n            if (grantResults.length == 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {\n                // SDCARD permission has been granted, preview can be displayed\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"SDCARD permission has now been granted\");\n                }\n                loadXmlFile();\n\n            } else {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"SDCARD read permission was not granted!\");\n                }\n                Toast.makeText(mActivity, getString(R.string.label_sdcard_permission_not_granted),\n                        Toast.LENGTH_LONG).show();\n            }\n        }\n    }\n\n    private void loadXmlFile() {\n        final boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"load XML provisioning File\");\n        }\n        try {\n            String[] xmlFiles = getProvisioningFiles();\n            View view = View.inflate(mActivity, R.layout.rcs_provisioning_generate_profile, null);\n            final EditText textEdit = (EditText) view.findViewById(R.id.msisdn);\n            ContactId me = mRcsSettings.getUserProfileImsUserName();\n            textEdit.setText(me == null ? \"\" : me.toString());\n            final Spinner spinner = (Spinner) view.findViewById(R.id.XmlProvisioningFile);\n            ArrayAdapter<String> adapter = new ArrayAdapter<>(this,\n                    android.R.layout.simple_spinner_item, xmlFiles);\n            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n            spinner.setAdapter(adapter);\n\n            AlertDialog.Builder builder = new AlertDialog.Builder(this)\n                    .setTitle(R.string.label_generate_profile).setView(view)\n                    .setNegativeButton(R.string.label_cancel, null)\n                    .setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n                        public void onClick(DialogInterface dialog, int whichButton) {\n                            ContactUtil.PhoneNumber number = ContactUtil\n                                    .getValidPhoneNumberFromAndroid(textEdit.getText().toString());\n                            if (number == null) {\n                                Toast.makeText(mActivity, getString(R.string.label_load_failed),\n                                        Toast.LENGTH_LONG).show();\n                                return;\n                            }\n                            ContactId contact = ContactUtil\n                                    .createContactIdFromValidatedData(number);\n                            String selectedProvisioningFile = (String) spinner.getSelectedItem();\n                            if (selectedProvisioningFile == null\n                                    || selectedProvisioningFile\n                                            .equals(getString(R.string.label_no_xml_file))) {\n                                Toast.makeText(mActivity, getString(R.string.label_load_failed),\n                                        Toast.LENGTH_LONG).show();\n                                return;\n                            }\n                            loadProfile(contact, Uri.fromFile(new File(PROVISIONING_FOLDER_PATH,\n                                    selectedProvisioningFile)));\n                        }\n                    });\n            AlertDialog dialog = builder.create();\n            dialog.setCanceledOnTouchOutside(false);\n            dialog.show();\n\n        } catch (SecurityException e) {\n            if (logActivated) {\n                sLogger.warn(\"Failed to load provisioning file!\", e);\n            }\n        }\n    }\n\n    private String[] getProvisioningFiles() {\n        if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this,\n                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {\n            ActivityCompat.requestPermissions(this, new String[] {\n                Manifest.permission.WRITE_EXTERNAL_STORAGE\n            }, MY_PERMISSION_REQUEST_ALL);\n            throw new SecurityException(\"Permission not granted to access SD card!\");\n        }\n        String[] files = null;\n        File folder = new File(PROVISIONING_FOLDER_PATH);\n        // noinspection ResultOfMethodCallIgnored\n        folder.mkdirs();\n        if (folder.exists()) {\n            // filter\n            FilenameFilter filter = new FilenameFilter() {\n                public boolean accept(File dir, String filename) {\n                    return filename.endsWith(PROVISIONING_EXTENSION);\n                }\n            };\n            files = folder.list(filter);\n        }\n        if (files == null || files.length == 0) {\n            // No provisioning file\n            return new String[] {\n                getString(R.string.label_no_xml_file)\n            };\n        }\n        return files;\n    }\n\n    private void loadProfile(ContactId contact, Uri provisioningFile) {\n        final boolean logActivated = sLogger.isActivated();\n        try {\n            if (logActivated) {\n                sLogger.debug(\"Selection of provisioning file: \".concat(provisioningFile.getPath()));\n            }\n            String xMLFileContent = getFileContent(provisioningFile);\n            LoadXmlPovisioningTask mProvisionTask = new LoadXmlPovisioningTask();\n            mProvisionTask.execute(xMLFileContent, contact.toString());\n\n        } catch (IOException e) {\n            if (logActivated) {\n                sLogger.debug(\"Loading of provisioning failed: invalid XML file '\"\n                        + provisioningFile + \"', Message=\" + e.getMessage());\n            }\n            Toast.makeText(mActivity, getString(R.string.label_load_failed), Toast.LENGTH_LONG)\n                    .show();\n        }\n    }\n\n    /**\n     * Read a text file and convert it into a string\n     *\n     * @param provisioningFile Uri for the file\n     * @return the result string\n     * @throws IOException\n     */\n    private String getFileContent(Uri provisioningFile) throws IOException {\n        File file = new File(provisioningFile.getPath());\n        StringBuilder text = new StringBuilder();\n        BufferedReader br = null;\n        try {\n            br = new BufferedReader(new FileReader(file));\n            String line;\n\n            while ((line = br.readLine()) != null) {\n                text.append(line);\n                text.append('\\n');\n            }\n            return text.toString();\n\n        } finally {\n            // noinspection ThrowableResultOfMethodCallIgnored\n            CloseableUtils.tryToClose(br);\n        }\n    }\n\n    /**\n     * Asynchronous Tasks that loads the provisioning file.\n     */\n    private class LoadXmlPovisioningTask extends AsyncTask<String, Void, Boolean> {\n\n        @Override\n        protected Boolean doInBackground(String... params) {\n            ContactId UserPhoneNumber = ContactUtil.createContactIdFromTrustedData(params[1]);\n            String mXMLFileContent = params[0];\n            return createProvisioning(mXMLFileContent, UserPhoneNumber);\n        }\n\n        /**\n         * Parse the provisioning data then save it into RCS settings provider\n         *\n         * @param xmlFileContent the XML file containing provisioning data\n         * @param myContact the user phone number\n         * @return true if loading the provisioning is successful\n         */\n        private boolean createProvisioning(String xmlFileContent, ContactId myContact) {\n            String phoneNumber = myContact.toString();\n            String configToParse = xmlFileContent\n                    .replaceAll(TOKEN_MSISDN, phoneNumber.substring(1));\n            ProvisioningParser parser = new ProvisioningParser(configToParse, mRcsSettings);\n            // Save GSMA release set into the provider\n            RcsSettingsData.GsmaRelease release = mRcsSettings.getGsmaRelease();\n            // Save client Messaging Mode set into the provider\n            CommonServiceConfiguration.MessagingMode messagingMode = mRcsSettings\n                    .getMessagingMode();\n            // Before parsing the provisioning, the GSMA release is set to Albatros\n            mRcsSettings.setGsmaRelease(RcsSettingsData.GsmaRelease.ALBATROS);\n            // Before parsing the provisioning, the client Messaging mode is set to NONE\n            mRcsSettings.setMessagingMode(CommonServiceConfiguration.MessagingMode.NONE);\n            try {\n                parser.parse(release, messagingMode, true);\n                /* Customize display name with user phone number */\n                mRcsSettings.setUserProfileImsDisplayName(phoneNumber);\n                mRcsSettings.setFileTransferHttpSupported(mRcsSettings.getFtHttpServer() != null\n                        && mRcsSettings.getFtHttpLogin() != null\n                        && mRcsSettings.getFtHttpPassword() != null);\n                return true;\n\n            } catch (SAXException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(e.getMessage());\n                }\n                // Restore GSMA release saved before parsing of the provisioning\n                mRcsSettings.setGsmaRelease(release);\n                // Restore the client messaging mode saved before parsing of the provisioning\n                mRcsSettings.setMessagingMode(messagingMode);\n                return false;\n            }\n        }\n\n        @Override\n        protected void onPostExecute(Boolean result) {\n            super.onPostExecute(result);\n            // set configuration mode to manual\n            mRcsSettings.setConfigurationMode(RcsSettingsData.ConfigurationMode.MANUAL);\n            for (IProvisioningFragment fragment : mAdapter.getFragments()) {\n                fragment.displayRcsSettings();\n            }\n            if (result)\n                Toast.makeText(mActivity, getString(R.string.label_reboot_service),\n                        Toast.LENGTH_LONG).show();\n            else\n                Toast.makeText(mActivity, getString(R.string.label_parse_failed), Toast.LENGTH_LONG)\n                        .show();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/ProvisioningHelper.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.view.View;\nimport android.widget.CheckBox;\nimport android.widget.EditText;\n\n/**\n * A class to bind RCS settings with UI.\n * \n * @author Philippe LEMORDANT\n */\npublic class ProvisioningHelper {\n\n    private final View mRootView;\n    private final RcsSettings mRcsSettings;\n\n    public ProvisioningHelper(View view, RcsSettings rcsSettings) {\n        mRootView = view;\n        mRcsSettings = rcsSettings;\n    }\n\n    public void setStringEditText(int resViewTextId, String settingsKey) {\n        EditText editText = (EditText) mRootView.findViewById(resViewTextId);\n        editText.setText(mRcsSettings.readString(settingsKey));\n    }\n\n    public void setIntEditText(int resViewTextId, String settingsKey) {\n        String value = Integer.toString(mRcsSettings.readInteger((settingsKey)));\n        EditText editText = (EditText) mRootView.findViewById(resViewTextId);\n        editText.setText(value);\n    }\n\n    public void setLongEditText(int resViewTextId, String settingsKey) {\n        String parameter = Long.toString(mRcsSettings.readLong((settingsKey)));\n        EditText editText = (EditText) mRootView.findViewById(resViewTextId);\n        editText.setText(parameter);\n    }\n\n    public void setUriEditText(int resViewTextId, String settingsKey) {\n        Uri dbValue = mRcsSettings.readUri(settingsKey);\n        String parameter = (dbValue == null ? \"\" : dbValue.toString());\n        EditText editText = (EditText) mRootView.findViewById(resViewTextId);\n        editText.setText(parameter);\n    }\n\n    public void setBoolCheckBox(int resViewTextId, String settingsKey) {\n        Boolean parameter = mRcsSettings.readBoolean((settingsKey));\n        CheckBox box = (CheckBox) mRootView.findViewById(resViewTextId);\n        box.setChecked(parameter);\n    }\n\n    public void setContactIdEditText(int resViewTextId, String settingsKey) {\n        ContactId dbValue = mRcsSettings.readContactId(settingsKey);\n        String parameter = (dbValue == null ? \"\" : dbValue.toString());\n        EditText editText = (EditText) mRootView.findViewById(resViewTextId);\n        editText.setText(parameter);\n    }\n\n    public void saveContactIdEditText(int resViewTextId, String settingsKey) {\n        EditText txt = (EditText) mRootView.findViewById(resViewTextId);\n        String text = txt.getText().toString();\n        ContactUtil.PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(text);\n        if (number == null) {\n            txt.setText(\"\");\n        }\n        mRcsSettings.writeContactId(settingsKey,\n                \"\".equals(text) ? null : ContactUtil.createContactIdFromValidatedData(number));\n    }\n\n    public void saveLongEditText(int resViewTextId, String settingsKey) {\n        EditText txt = (EditText) mRootView.findViewById(resViewTextId);\n        mRcsSettings.writeLong(settingsKey, Long.parseLong(txt.getText().toString()));\n    }\n\n    public void saveIntEditText(int resViewTextId, String settingsKey) {\n        EditText txt = (EditText) mRootView.findViewById(resViewTextId);\n        mRcsSettings.writeInteger(settingsKey, Integer.parseInt(txt.getText().toString()));\n    }\n\n    public void saveStringEditText(int resViewTextId, String settingsKey) {\n        EditText editText = (EditText) mRootView.findViewById(resViewTextId);\n        String text = editText.getText().toString().trim();\n        mRcsSettings.writeString(settingsKey, \"\".equals(text) ? null : text);\n    }\n\n    public void saveBoolCheckBox(int resViewTextId, String settingsKey) {\n        CheckBox box = (CheckBox) mRootView.findViewById(resViewTextId);\n        mRcsSettings.writeBoolean(settingsKey, box.isChecked());\n    }\n\n    public void saveUriEditText(int resViewTextId, String settingsKey) {\n        EditText txt = (EditText) mRootView.findViewById(resViewTextId);\n        String text = txt.getText().toString();\n        mRcsSettings.writeUri(settingsKey, \"\".equals(text) ? null : Uri.parse(text));\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/ServiceProvisioning.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.os.Bundle;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.Spinner;\n\n/**\n * Service parameters provisioning\n * \n * @author jexa7410\n * @author Philippe LEMORDANT\n */\npublic class ServiceProvisioning extends Fragment implements IProvisioningFragment {\n    /**\n     * IM session start modes\n     */\n    private static final String[] IM_SESSION_START_MODES = {\n            \"0\", \"1\", \"2\"\n    };\n\n    private static RcsSettings sRcsSettings;\n    private View mRootView;\n    private static final Logger sLogger = Logger.getLogger(ServiceProvisioning.class.getName());\n    private ProvisioningHelper mHelper;\n\n    public static ServiceProvisioning newInstance(RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"new instance\");\n        }\n        ServiceProvisioning f = new ServiceProvisioning();\n        /*\n         * If Android decides to recreate your Fragment later, it's going to call the no-argument\n         * constructor of your fragment. So overloading the constructor is not a solution. A way to\n         * pass argument to new fragment is to store it as static.\n         */\n        sRcsSettings = rcsSettings;\n        return f;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        mRootView = inflater.inflate(R.layout.provisioning_service, container, false);\n        mHelper = new ProvisioningHelper(mRootView, sRcsSettings);\n        displayRcsSettings();\n        return mRootView;\n    }\n\n    @Override\n    public void displayRcsSettings() {\n        mHelper.setLongEditText(R.id.MaxPhotoIconSize, RcsSettingsData.MAX_PHOTO_ICON_SIZE);\n        mHelper.setIntEditText(R.id.MaxFreetextLength, RcsSettingsData.MAX_FREETXT_LENGTH);\n        mHelper.setIntEditText(R.id.MaxChatParticipants, RcsSettingsData.MAX_CHAT_PARTICIPANTS);\n        mHelper.setIntEditText(R.id.MaxChatMessageLength, RcsSettingsData.MAX_CHAT_MSG_LENGTH);\n        mHelper.setIntEditText(R.id.MaxGroupChatMessageLength,\n                RcsSettingsData.MAX_GROUPCHAT_MSG_LENGTH);\n        mHelper.setLongEditText(R.id.ChatIdleDuration, RcsSettingsData.CHAT_IDLE_DURATION);\n        mHelper.setLongEditText(R.id.MaxFileTransferSize, RcsSettingsData.MAX_FILE_TRANSFER_SIZE);\n        mHelper.setLongEditText(R.id.WarnFileTransferSize, RcsSettingsData.WARN_FILE_TRANSFER_SIZE);\n        mHelper.setLongEditText(R.id.MaxImageShareSize, RcsSettingsData.MAX_IMAGE_SHARE_SIZE);\n        mHelper.setLongEditText(R.id.MaxVideoShareDuration,\n                RcsSettingsData.MAX_VIDEO_SHARE_DURATION);\n        mHelper.setLongEditText(R.id.MaxAudioMessageDuration,\n                RcsSettingsData.MAX_AUDIO_MESSAGE_DURATION);\n        mHelper.setIntEditText(R.id.MaxChatSessions, RcsSettingsData.MAX_CHAT_SESSIONS);\n        mHelper.setIntEditText(R.id.MaxFileTransferSessions,\n                RcsSettingsData.MAX_FILE_TRANSFER_SESSIONS);\n        mHelper.setIntEditText(R.id.MaxConcurrentOutgoingFileTransferSessions,\n                RcsSettingsData.MAX_CONCURRENT_OUTGOING_FILE_TRANSFERS);\n        mHelper.setIntEditText(R.id.MaxIpCallSessions, RcsSettingsData.MAX_IP_CALL_SESSIONS);\n        mHelper.setIntEditText(R.id.MaxChatLogEntries, RcsSettingsData.MAX_CHAT_LOG_ENTRIES);\n        mHelper.setIntEditText(R.id.MaxRichcallLogEntries, RcsSettingsData.MAX_RICHCALL_LOG_ENTRIES);\n        mHelper.setIntEditText(R.id.MaxIpcallLogEntries, RcsSettingsData.MAX_IPCALL_LOG_ENTRIES);\n        mHelper.setStringEditText(R.id.DirectoryPathPhotos, RcsSettingsData.DIRECTORY_PATH_PHOTOS);\n        mHelper.setStringEditText(R.id.DirectoryPathVideos, RcsSettingsData.DIRECTORY_PATH_VIDEOS);\n        mHelper.setStringEditText(R.id.DirectoryPathAudios, RcsSettingsData.DIRECTORY_PATH_AUDIOS);\n        mHelper.setStringEditText(R.id.DirectoryPathFiles, RcsSettingsData.DIRECTORY_PATH_FILES);\n        mHelper.setStringEditText(R.id.DirectoryPathFileIcons,\n                RcsSettingsData.DIRECTORY_PATH_FILEICONS);\n        mHelper.setIntEditText(R.id.MaxGeolocLabelLength, RcsSettingsData.MAX_GEOLOC_LABEL_LENGTH);\n        mHelper.setLongEditText(R.id.GeolocExpirationTime, RcsSettingsData.GEOLOC_EXPIRATION_TIME);\n        mHelper.setLongEditText(R.id.CallComposerIdleDuration,\n                RcsSettingsData.CALL_COMPOSER_INACTIVITY_TIMEOUT);\n        Spinner spinner = (Spinner) mRootView.findViewById(R.id.ImSessionStart);\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),\n                android.R.layout.simple_spinner_item, IM_SESSION_START_MODES);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        setSpinnerParameter(spinner, RcsSettingsData.IM_SESSION_START, true, IM_SESSION_START_MODES);\n\n        mHelper.setBoolCheckBox(R.id.SmsFallbackService, RcsSettingsData.SMS_FALLBACK_SERVICE);\n        mHelper.setBoolCheckBox(R.id.StoreForwardServiceWarning, RcsSettingsData.WARN_SF_SERVICE);\n        mHelper.setBoolCheckBox(R.id.AutoAcceptFileTransfer,\n                RcsSettingsData.AUTO_ACCEPT_FILE_TRANSFER);\n        mHelper.setBoolCheckBox(R.id.AutoAcceptFileTransferInRoaming,\n                RcsSettingsData.AUTO_ACCEPT_FT_IN_ROAMING);\n        mHelper.setBoolCheckBox(R.id.AutoAcceptFileTransferChangeable,\n                RcsSettingsData.AUTO_ACCEPT_FT_CHANGEABLE);\n        mHelper.setBoolCheckBox(R.id.AutoAcceptChat, RcsSettingsData.AUTO_ACCEPT_CHAT);\n        mHelper.setBoolCheckBox(R.id.AutoAcceptGroupChat, RcsSettingsData.AUTO_ACCEPT_GROUP_CHAT);\n        mHelper.setBoolCheckBox(R.id.EnrichCalling, RcsSettingsData.ENRICH_CALLING_SERVICE);\n    }\n\n    @Override\n    public void persistRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"persistRcsSettings\");\n        }\n        mHelper.saveLongEditText(R.id.MaxPhotoIconSize, RcsSettingsData.MAX_PHOTO_ICON_SIZE);\n        mHelper.saveIntEditText(R.id.MaxFreetextLength, RcsSettingsData.MAX_FREETXT_LENGTH);\n        mHelper.saveIntEditText(R.id.MaxChatParticipants, RcsSettingsData.MAX_CHAT_PARTICIPANTS);\n        mHelper.saveIntEditText(R.id.MaxChatMessageLength, RcsSettingsData.MAX_CHAT_MSG_LENGTH);\n        mHelper.saveIntEditText(R.id.MaxGroupChatMessageLength,\n                RcsSettingsData.MAX_GROUPCHAT_MSG_LENGTH);\n        mHelper.saveLongEditText(R.id.ChatIdleDuration, RcsSettingsData.CHAT_IDLE_DURATION);\n        mHelper.saveLongEditText(R.id.MaxFileTransferSize, RcsSettingsData.MAX_FILE_TRANSFER_SIZE);\n        mHelper.saveLongEditText(R.id.WarnFileTransferSize, RcsSettingsData.WARN_FILE_TRANSFER_SIZE);\n        mHelper.saveLongEditText(R.id.MaxImageShareSize, RcsSettingsData.MAX_IMAGE_SHARE_SIZE);\n        mHelper.saveLongEditText(R.id.MaxVideoShareDuration,\n                RcsSettingsData.MAX_VIDEO_SHARE_DURATION);\n        mHelper.saveLongEditText(R.id.MaxAudioMessageDuration,\n                RcsSettingsData.MAX_AUDIO_MESSAGE_DURATION);\n        mHelper.saveIntEditText(R.id.MaxChatSessions, RcsSettingsData.MAX_CHAT_SESSIONS);\n        mHelper.saveIntEditText(R.id.MaxFileTransferSessions,\n                RcsSettingsData.MAX_FILE_TRANSFER_SESSIONS);\n        mHelper.saveIntEditText(R.id.MaxConcurrentOutgoingFileTransferSessions,\n                RcsSettingsData.MAX_CONCURRENT_OUTGOING_FILE_TRANSFERS);\n        mHelper.saveIntEditText(R.id.MaxIpCallSessions, RcsSettingsData.MAX_IP_CALL_SESSIONS);\n        mHelper.saveIntEditText(R.id.MaxChatLogEntries, RcsSettingsData.MAX_CHAT_LOG_ENTRIES);\n        mHelper.saveIntEditText(R.id.MaxRichcallLogEntries,\n                RcsSettingsData.MAX_RICHCALL_LOG_ENTRIES);\n        mHelper.saveIntEditText(R.id.MaxIpcallLogEntries, RcsSettingsData.MAX_IPCALL_LOG_ENTRIES);\n        mHelper.saveIntEditText(R.id.MaxGeolocLabelLength, RcsSettingsData.MAX_GEOLOC_LABEL_LENGTH);\n        mHelper.saveLongEditText(R.id.GeolocExpirationTime, RcsSettingsData.GEOLOC_EXPIRATION_TIME);\n        mHelper.saveStringEditText(R.id.DirectoryPathPhotos, RcsSettingsData.DIRECTORY_PATH_PHOTOS);\n        mHelper.saveStringEditText(R.id.DirectoryPathVideos, RcsSettingsData.DIRECTORY_PATH_VIDEOS);\n        mHelper.saveStringEditText(R.id.DirectoryPathAudios, RcsSettingsData.DIRECTORY_PATH_AUDIOS);\n        mHelper.saveStringEditText(R.id.DirectoryPathFiles, RcsSettingsData.DIRECTORY_PATH_FILES);\n        mHelper.saveLongEditText(R.id.CallComposerIdleDuration,\n                RcsSettingsData.CALL_COMPOSER_INACTIVITY_TIMEOUT);\n        mHelper.saveStringEditText(R.id.DirectoryPathFileIcons,\n                RcsSettingsData.DIRECTORY_PATH_FILEICONS);\n\n        Spinner spinner = (Spinner) mRootView.findViewById(R.id.ImSessionStart);\n        sRcsSettings.writeInteger(RcsSettingsData.IM_SESSION_START,\n                spinner.getSelectedItemPosition());\n\n        mHelper.saveBoolCheckBox(R.id.SmsFallbackService, RcsSettingsData.SMS_FALLBACK_SERVICE);\n        mHelper.saveBoolCheckBox(R.id.StoreForwardServiceWarning, RcsSettingsData.WARN_SF_SERVICE);\n        mHelper.saveBoolCheckBox(R.id.AutoAcceptFileTransfer,\n                RcsSettingsData.AUTO_ACCEPT_FILE_TRANSFER);\n        mHelper.saveBoolCheckBox(R.id.AutoAcceptFileTransferInRoaming,\n                RcsSettingsData.AUTO_ACCEPT_FT_IN_ROAMING);\n        mHelper.saveBoolCheckBox(R.id.AutoAcceptFileTransferChangeable,\n                RcsSettingsData.AUTO_ACCEPT_FT_CHANGEABLE);\n        mHelper.saveBoolCheckBox(R.id.AutoAcceptChat, RcsSettingsData.AUTO_ACCEPT_CHAT);\n        mHelper.saveBoolCheckBox(R.id.AutoAcceptGroupChat, RcsSettingsData.AUTO_ACCEPT_GROUP_CHAT);\n        mHelper.saveBoolCheckBox(R.id.EnrichCalling, RcsSettingsData.ENRICH_CALLING_SERVICE);\n    }\n\n    int setSpinnerParameter(final Spinner spinner, String settingsKey, boolean isSettingInteger,\n            final String[] selection) {\n        Integer parameter;\n        if (isSettingInteger) {\n            parameter = sRcsSettings.readInteger(settingsKey);\n        } else {\n            String selected = sRcsSettings.readString(settingsKey);\n            parameter = java.util.Arrays.asList(selection).indexOf(selected);\n        }\n        spinner.setSelection(parameter % selection.length);\n        return parameter;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/SlidingTabLayout.java",
    "content": "/*\n * Copyright 2014 Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.gsma.rcs.provisioning.local;\n\nimport android.content.Context;\nimport android.graphics.Typeface;\nimport android.support.v4.view.PagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport android.util.AttributeSet;\nimport android.util.SparseArray;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.HorizontalScrollView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\n/**\n * To be used with ViewPager to provide a tab indicator component which give constant feedback as to\n * the user's scroll progress.\n * <p>\n * To use the component, simply add it to your view hierarchy. Then in your\n * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call\n * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.\n * <p>\n * The colors can be customized in two ways. The first and simplest is to provide an array of colors\n * via {@link #setSelectedIndicatorColors(int...)}. The alternative is via the {@link TabColorizer}\n * interface which provides you complete control over which color is used for any individual\n * position.\n * <p>\n * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},\n * providing the layout ID of your custom layout.\n */\npublic class SlidingTabLayout extends HorizontalScrollView {\n    /**\n     * Allows complete control over the colors drawn in the tab layout. Set with\n     * {@link #setCustomTabColorizer(TabColorizer)}.\n     */\n    public interface TabColorizer {\n\n        /**\n         * @return return the color of the indicator used when {@code position} is selected.\n         */\n        int getIndicatorColor(int position);\n\n    }\n\n    private static final int TITLE_OFFSET_DIPS = 24;\n    private static final int TAB_VIEW_PADDING_DIPS = 16;\n    private static final int TAB_VIEW_TEXT_SIZE_SP = 12;\n\n    private int mTitleOffset;\n\n    private int mTabViewLayoutId;\n    private int mTabViewTextViewId;\n    private boolean mDistributeEvenly;\n\n    private ViewPager mViewPager;\n    private SparseArray<String> mContentDescriptions = new SparseArray<>();\n    private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;\n\n    private final SlidingTabStrip mTabStrip;\n\n    public SlidingTabLayout(Context context) {\n        this(context, null);\n    }\n\n    public SlidingTabLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n\n        // Disable the Scroll Bar\n        setHorizontalScrollBarEnabled(false);\n        // Make sure that the Tab Strips fills this View\n        setFillViewport(true);\n\n        mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);\n\n        mTabStrip = new SlidingTabStrip(context);\n        addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);\n    }\n\n    /**\n     * Set the custom {@link TabColorizer} to be used. If you only require simple custmisation then\n     * you can use {@link #setSelectedIndicatorColors(int...)} to achieve similar effects.\n     */\n    public void setCustomTabColorizer(TabColorizer tabColorizer) {\n        mTabStrip.setCustomTabColorizer(tabColorizer);\n    }\n\n    public void setDistributeEvenly(boolean distributeEvenly) {\n        mDistributeEvenly = distributeEvenly;\n    }\n\n    /**\n     * Sets the colors to be used for indicating the selected tab. These colors are treated as a\n     * circular array. Providing one color will mean that all tabs are indicated with the same\n     * color.\n     */\n    public void setSelectedIndicatorColors(int... colors) {\n        mTabStrip.setSelectedIndicatorColors(colors);\n    }\n\n    /**\n     * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are\n     * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so\n     * that the layout can update it's scroll position correctly.\n     *\n     * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)\n     */\n    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {\n        mViewPagerPageChangeListener = listener;\n    }\n\n    /**\n     * Set the custom layout to be inflated for the tab views.\n     *\n     * @param layoutResId Layout id to be inflated\n     * @param textViewId id of the {@link TextView} in the inflated view\n     */\n    public void setCustomTabView(int layoutResId, int textViewId) {\n        mTabViewLayoutId = layoutResId;\n        mTabViewTextViewId = textViewId;\n    }\n\n    /**\n     * Sets the associated view pager. Note that the assumption here is that the pager content\n     * (number of tabs and tab titles) does not change after this call has been made.\n     */\n    public void setViewPager(ViewPager viewPager) {\n        mTabStrip.removeAllViews();\n\n        mViewPager = viewPager;\n        if (viewPager != null) {\n            viewPager.setOnPageChangeListener(new InternalViewPagerListener());\n            populateTabStrip();\n        }\n    }\n\n    /**\n     * Create a default view to be used for tabs. This is called if a custom tab view is not set via\n     * {@link #setCustomTabView(int, int)}.\n     */\n    protected TextView createDefaultTabView(Context context) {\n        TextView textView = new TextView(context);\n        textView.setGravity(Gravity.CENTER);\n        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);\n        textView.setTypeface(Typeface.DEFAULT_BOLD);\n        textView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,\n                ViewGroup.LayoutParams.WRAP_CONTENT));\n\n        TypedValue outValue = new TypedValue();\n        getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue,\n                true);\n        textView.setBackgroundResource(outValue.resourceId);\n        // textView.setAllCaps(true);\n\n        int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);\n        textView.setPadding(padding, padding, padding, padding);\n\n        return textView;\n    }\n\n    private void populateTabStrip() {\n        final PagerAdapter adapter = mViewPager.getAdapter();\n        final View.OnClickListener tabClickListener = new TabClickListener();\n\n        for (int i = 0; i < adapter.getCount(); i++) {\n            View tabView = null;\n            TextView tabTitleView = null;\n\n            if (mTabViewLayoutId != 0) {\n                // If there is a custom tab view layout id set, try and inflate it\n                tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,\n                        false);\n                tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);\n            }\n\n            if (tabView == null) {\n                tabView = createDefaultTabView(getContext());\n            }\n\n            if (tabTitleView == null && TextView.class.isInstance(tabView)) {\n                tabTitleView = (TextView) tabView;\n            }\n\n            if (mDistributeEvenly) {\n                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView\n                        .getLayoutParams();\n                lp.width = 0;\n                lp.weight = 1;\n            }\n\n            tabTitleView.setText(adapter.getPageTitle(i));\n            tabView.setOnClickListener(tabClickListener);\n            String desc = mContentDescriptions.get(i, null);\n            if (desc != null) {\n                tabView.setContentDescription(desc);\n            }\n\n            mTabStrip.addView(tabView);\n            if (i == mViewPager.getCurrentItem()) {\n                tabView.setSelected(true);\n            }\n        }\n    }\n\n    public void setContentDescription(int i, String desc) {\n        mContentDescriptions.put(i, desc);\n    }\n\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n\n        if (mViewPager != null) {\n            scrollToTab(mViewPager.getCurrentItem(), 0);\n        }\n    }\n\n    private void scrollToTab(int tabIndex, int positionOffset) {\n        final int tabStripChildCount = mTabStrip.getChildCount();\n        if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {\n            return;\n        }\n\n        View selectedChild = mTabStrip.getChildAt(tabIndex);\n        if (selectedChild != null) {\n            int targetScrollX = selectedChild.getLeft() + positionOffset;\n\n            if (tabIndex > 0 || positionOffset > 0) {\n                // If we're not at the first child and are mid-scroll, make sure we obey the offset\n                targetScrollX -= mTitleOffset;\n            }\n\n            scrollTo(targetScrollX, 0);\n        }\n    }\n\n    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {\n        private int mScrollState;\n\n        @Override\n        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {\n            int tabStripChildCount = mTabStrip.getChildCount();\n            if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {\n                return;\n            }\n\n            mTabStrip.onViewPagerPageChanged(position, positionOffset);\n\n            View selectedTitle = mTabStrip.getChildAt(position);\n            int extraOffset = (selectedTitle != null) ? (int) (positionOffset * selectedTitle\n                    .getWidth()) : 0;\n            scrollToTab(position, extraOffset);\n\n            if (mViewPagerPageChangeListener != null) {\n                mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,\n                        positionOffsetPixels);\n            }\n        }\n\n        @Override\n        public void onPageScrollStateChanged(int state) {\n            mScrollState = state;\n\n            if (mViewPagerPageChangeListener != null) {\n                mViewPagerPageChangeListener.onPageScrollStateChanged(state);\n            }\n        }\n\n        @Override\n        public void onPageSelected(int position) {\n            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {\n                mTabStrip.onViewPagerPageChanged(position, 0f);\n                scrollToTab(position, 0);\n            }\n            for (int i = 0; i < mTabStrip.getChildCount(); i++) {\n                mTabStrip.getChildAt(i).setSelected(position == i);\n            }\n            if (mViewPagerPageChangeListener != null) {\n                mViewPagerPageChangeListener.onPageSelected(position);\n            }\n        }\n\n    }\n\n    private class TabClickListener implements View.OnClickListener {\n        @Override\n        public void onClick(View v) {\n            for (int i = 0; i < mTabStrip.getChildCount(); i++) {\n                if (v == mTabStrip.getChildAt(i)) {\n                    mViewPager.setCurrentItem(i);\n                    return;\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/SlidingTabStrip.java",
    "content": "/*\n * Copyright 2014 Google Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.gsma.rcs.provisioning.local;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.widget.LinearLayout;\n\nclass SlidingTabStrip extends LinearLayout {\n\n    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;\n    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;\n    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3;\n    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;\n\n    private final int mBottomBorderThickness;\n    private final Paint mBottomBorderPaint;\n\n    private final int mSelectedIndicatorThickness;\n    private final Paint mSelectedIndicatorPaint;\n\n    private int mSelectedPosition;\n    private float mSelectionOffset;\n\n    private SlidingTabLayout.TabColorizer mCustomTabColorizer;\n    private final SimpleTabColorizer mDefaultTabColorizer;\n\n    SlidingTabStrip(Context context) {\n        this(context, null);\n    }\n\n    SlidingTabStrip(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        setWillNotDraw(false);\n\n        final float density = getResources().getDisplayMetrics().density;\n\n        TypedValue outValue = new TypedValue();\n        context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);\n        final int themeForegroundColor = outValue.data;\n\n        int defaultBottomBorderColor = setColorAlpha(themeForegroundColor,\n                DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);\n\n        mDefaultTabColorizer = new SimpleTabColorizer();\n        mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);\n\n        mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);\n        mBottomBorderPaint = new Paint();\n        mBottomBorderPaint.setColor(defaultBottomBorderColor);\n\n        mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);\n        mSelectedIndicatorPaint = new Paint();\n    }\n\n    void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {\n        mCustomTabColorizer = customTabColorizer;\n        invalidate();\n    }\n\n    void setSelectedIndicatorColors(int... colors) {\n        // Make sure that the custom colorizer is removed\n        mCustomTabColorizer = null;\n        mDefaultTabColorizer.setIndicatorColors(colors);\n        invalidate();\n    }\n\n    void onViewPagerPageChanged(int position, float positionOffset) {\n        mSelectedPosition = position;\n        mSelectionOffset = positionOffset;\n        invalidate();\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        final int height = getHeight();\n        final int childCount = getChildCount();\n        final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null ? mCustomTabColorizer\n                : mDefaultTabColorizer;\n\n        // Thick colored underline below the current selection\n        if (childCount > 0) {\n            View selectedTitle = getChildAt(mSelectedPosition);\n            int left = selectedTitle.getLeft();\n            int right = selectedTitle.getRight();\n            int color = tabColorizer.getIndicatorColor(mSelectedPosition);\n\n            if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {\n                int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);\n                if (color != nextColor) {\n                    color = blendColors(nextColor, color, mSelectionOffset);\n                }\n\n                // Draw the selection partway between the tabs\n                View nextTitle = getChildAt(mSelectedPosition + 1);\n                left = (int) (mSelectionOffset * nextTitle.getLeft() + (1.0f - mSelectionOffset)\n                        * left);\n                right = (int) (mSelectionOffset * nextTitle.getRight() + (1.0f - mSelectionOffset)\n                        * right);\n            }\n\n            mSelectedIndicatorPaint.setColor(color);\n\n            canvas.drawRect(left, height - mSelectedIndicatorThickness, right, height,\n                    mSelectedIndicatorPaint);\n        }\n\n        // Thin underline along the entire bottom edge\n        canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);\n    }\n\n    /**\n     * Set the alpha value of the {@code color} to be the given {@code alpha} value.\n     */\n    private static int setColorAlpha(int color, byte alpha) {\n        return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));\n    }\n\n    /**\n     * Blend {@code color1} and {@code color2} using the given ratio.\n     *\n     * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,\n     *            0.0 will return {@code color2}.\n     */\n    private static int blendColors(int color1, int color2, float ratio) {\n        final float inverseRation = 1f - ratio;\n        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);\n        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);\n        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);\n        return Color.rgb((int) r, (int) g, (int) b);\n    }\n\n    private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {\n        private int[] mIndicatorColors;\n\n        @Override\n        public final int getIndicatorColor(int position) {\n            return mIndicatorColors[position % mIndicatorColors.length];\n        }\n\n        void setIndicatorColors(int... colors) {\n            mIndicatorColors = colors;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/StackProvisioning.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ConfigurationMode;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.EnableRcseSwitch;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.NetworkAccessType;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.support.v4.app.Fragment;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.io.File;\nimport java.io.FilenameFilter;\n\n/**\n * Stack parameters provisioning File\n * \n * @author jexa7410\n */\npublic class StackProvisioning extends Fragment implements IProvisioningFragment {\n\n    private static final Logger sLogger = Logger.getLogger(StackProvisioning.class.getName());\n\n    /**\n     * Folder path for certificate\n     */\n    public static final String CERTIFICATE_FOLDER_PATH = Environment.getExternalStorageDirectory()\n            .getPath();\n\n    /**\n     * Configuration modes\n     */\n    private String[] mConfigModes;\n\n    /**\n     * SIP protocol\n     */\n    private static final String[] SIP_PROTOCOL = {\n            \"UDP\", \"TCP\", \"TLS\"\n    };\n\n    /**\n     * Enable RCS switch\n     */\n    private String[] mEnableRcseSwitch;\n\n    /**\n     * Network accesses\n     */\n    private String[] mNetworkAccesses;\n\n    /**\n     * FT protocol\n     */\n    private static final String[] FT_PROTOCOL = {\n            FileTransferProtocol.HTTP.name(), FileTransferProtocol.MSRP.name()\n    };\n\n    private static RcsSettings sRcsSettings;\n    private View mRootView;\n    private ProvisioningHelper mHelper;\n\n    public static StackProvisioning newInstance(RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"new instance\");\n        }\n        StackProvisioning f = new StackProvisioning();\n        /*\n         * If Android decides to recreate your Fragment later, it's going to call the no-argument\n         * constructor of your fragment. So overloading the constructor is not a solution. A way to\n         * pass argument to new fragment is to store it as static.\n         */\n        sRcsSettings = rcsSettings;\n        return f;\n    }\n\n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        mRootView = inflater.inflate(R.layout.provisioning_stack, container, false);\n        mHelper = new ProvisioningHelper(mRootView, sRcsSettings);\n        mConfigModes = getResources().getStringArray(R.array.provisioning_config_mode);\n        mNetworkAccesses = getResources().getStringArray(R.array.provisioning_network_access);\n        mEnableRcseSwitch = getResources().getStringArray(R.array.provisioning_enable_rcs_switch);\n        displayRcsSettings();\n        return mRootView;\n    }\n\n    @Override\n    public void displayRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"displayRcsSettings\");\n        }\n        Context ctx = getContext();\n        Spinner spinner = (Spinner) mRootView.findViewById(R.id.Autoconfig);\n        ArrayAdapter<String> adapter = new ArrayAdapter<>(ctx,\n                android.R.layout.simple_spinner_item, mConfigModes);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        ConfigurationMode mode = sRcsSettings.getConfigurationMode();\n        spinner.setSelection(ConfigurationMode.AUTO.equals(mode) ? 1 : 0);\n\n        TextView textView = (TextView) mRootView.findViewById(R.id.client_vendor);\n        textView.setText(Build.MANUFACTURER);\n\n        spinner = (Spinner) mRootView.findViewById(R.id.EnableRcsSwitch);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, mEnableRcseSwitch);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        EnableRcseSwitch rcsSwitch = sRcsSettings.getEnableRcseSwitch();\n        switch (rcsSwitch) {\n            case ALWAYS_SHOW:\n            case ONLY_SHOW_IN_ROAMING:\n                spinner.setSelection(rcsSwitch.toInt());\n                break;\n            default:\n                spinner.setSelection(2);\n        }\n        mHelper.setStringEditText(R.id.SecondaryProvisioningAddress,\n                RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS);\n        mHelper.setBoolCheckBox(R.id.SecondaryProvisioningAddressOnly,\n                RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS_ONLY);\n\n        spinner = (Spinner) mRootView.findViewById(R.id.NetworkAccess);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, mNetworkAccesses);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        NetworkAccessType access = sRcsSettings.getNetworkAccess();\n        switch (access) {\n            case MOBILE:\n                spinner.setSelection(1);\n                break;\n            case WIFI:\n                spinner.setSelection(2);\n                break;\n            case ANY:\n            default:\n                spinner.setSelection(0);\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.SipDefaultProtocolForMobile);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, SIP_PROTOCOL);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        String sipMobile = sRcsSettings.getSipDefaultProtocolForMobile();\n        if (SIP_PROTOCOL[0].equalsIgnoreCase(sipMobile)) {\n            spinner.setSelection(0);\n        } else if (SIP_PROTOCOL[1].equalsIgnoreCase(sipMobile)) {\n            spinner.setSelection(1);\n        } else {\n            spinner.setSelection(2);\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.SipDefaultProtocolForWifi);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, SIP_PROTOCOL);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        String sipWifi = sRcsSettings.getSipDefaultProtocolForWifi();\n        if (SIP_PROTOCOL[0].equalsIgnoreCase(sipWifi)) {\n            spinner.setSelection(0);\n        } else if (SIP_PROTOCOL[1].equalsIgnoreCase(sipWifi)) {\n            spinner.setSelection(1);\n        } else {\n            spinner.setSelection(2);\n        }\n        String[] certificates = loadCertificatesList();\n        spinner = (Spinner) mRootView.findViewById(R.id.TlsCertificateRoot);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, certificates);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        boolean found = false;\n        String certRoot = sRcsSettings.getTlsCertificateRoot();\n        for (int i = 0; i < certificates.length; i++) {\n            if (certRoot != null && certRoot.contains(certificates[i])) {\n                spinner.setSelection(i);\n                found = true;\n            }\n        }\n        if (!found) {\n            spinner.setSelection(0);\n            sRcsSettings.writeString(RcsSettingsData.TLS_CERTIFICATE_ROOT, \"\");\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.TlsCertificateIntermediate);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, certificates);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        spinner.setSelection(0);\n        found = false;\n        String certInt = sRcsSettings.getTlsCertificateIntermediate();\n        for (int i = 0; i < certificates.length; i++) {\n            if (certInt != null && certInt.contains(certificates[i])) {\n                spinner.setSelection(i);\n                found = true;\n            }\n        }\n        if (!found) {\n            spinner.setSelection(0);\n            sRcsSettings.writeString(RcsSettingsData.TLS_CERTIFICATE_INTERMEDIATE, \"\");\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.FtProtocol);\n        adapter = new ArrayAdapter<>(ctx, android.R.layout.simple_spinner_item, FT_PROTOCOL);\n        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\n        spinner.setAdapter(adapter);\n        FileTransferProtocol ftProtocol = sRcsSettings.getFtProtocol();\n        if (FileTransferProtocol.HTTP.equals(ftProtocol)) {\n            spinner.setSelection(0);\n        } else {\n            spinner.setSelection(1);\n        }\n        mHelper.setLongEditText(R.id.ImsServicePollingPeriod,\n                RcsSettingsData.IMS_SERVICE_POLLING_PERIOD);\n        mHelper.setIntEditText(R.id.SipListeningPort, RcsSettingsData.SIP_DEFAULT_PORT);\n        mHelper.setLongEditText(R.id.SipTimerT1, RcsSettingsData.SIP_TIMER_T1);\n        mHelper.setLongEditText(R.id.SipTimerT2, RcsSettingsData.SIP_TIMER_T2);\n        mHelper.setLongEditText(R.id.SipTimerT4, RcsSettingsData.SIP_TIMER_T4);\n        mHelper.setLongEditText(R.id.SipTransactionTimeout, RcsSettingsData.SIP_TRANSACTION_TIMEOUT);\n        mHelper.setLongEditText(R.id.SipKeepAlivePeriod, RcsSettingsData.SIP_KEEP_ALIVE_PERIOD);\n        mHelper.setIntEditText(R.id.DefaultMsrpPort, RcsSettingsData.MSRP_DEFAULT_PORT);\n        mHelper.setIntEditText(R.id.DefaultRtpPort, RcsSettingsData.RTP_DEFAULT_PORT);\n        mHelper.setLongEditText(R.id.MsrpTransactionTimeout,\n                RcsSettingsData.MSRP_TRANSACTION_TIMEOUT);\n        mHelper.setLongEditText(R.id.RegisterExpirePeriod, RcsSettingsData.REGISTER_EXPIRE_PERIOD);\n        mHelper.setLongEditText(R.id.RegisterRetryBaseTime,\n                RcsSettingsData.REGISTER_RETRY_BASE_TIME);\n        mHelper.setLongEditText(R.id.RegisterRetryMaxTime, RcsSettingsData.REGISTER_RETRY_MAX_TIME);\n        mHelper.setLongEditText(R.id.PublishExpirePeriod, RcsSettingsData.PUBLISH_EXPIRE_PERIOD);\n        mHelper.setLongEditText(R.id.RevokeTimeout, RcsSettingsData.REVOKE_TIMEOUT);\n        mHelper.setLongEditText(R.id.RingingPeriod, RcsSettingsData.RINGING_SESSION_PERIOD);\n        mHelper.setLongEditText(R.id.SubscribeExpirePeriod, RcsSettingsData.SUBSCRIBE_EXPIRE_PERIOD);\n        mHelper.setLongEditText(R.id.IsComposingTimeout, RcsSettingsData.IS_COMPOSING_TIMEOUT);\n        mHelper.setLongEditText(R.id.SessionRefreshExpirePeriod,\n                RcsSettingsData.SESSION_REFRESH_EXPIRE_PERIOD);\n        mHelper.setLongEditText(R.id.CapabilityRefreshTimeout,\n                RcsSettingsData.CAPABILITY_REFRESH_TIMEOUT);\n        mHelper.setLongEditText(R.id.CapabilityExpiryTimeout,\n                RcsSettingsData.CAPABILITY_EXPIRY_TIMEOUT);\n        mHelper.setLongEditText(R.id.CapabilityPollingPeriod,\n                RcsSettingsData.CAPABILITY_POLLING_PERIOD);\n        mHelper.setBoolCheckBox(R.id.TcpFallback, RcsSettingsData.TCP_FALLBACK);\n        mHelper.setBoolCheckBox(R.id.SipKeepAlive, RcsSettingsData.SIP_KEEP_ALIVE);\n        mHelper.setBoolCheckBox(R.id.PermanentState, RcsSettingsData.PERMANENT_STATE_MODE);\n        mHelper.setBoolCheckBox(R.id.TelUriFormat, RcsSettingsData.TEL_URI_FORMAT);\n        mHelper.setBoolCheckBox(R.id.ImAlwaysOn, RcsSettingsData.IM_CAPABILITY_ALWAYS_ON);\n        mHelper.setBoolCheckBox(R.id.FtAlwaysOn, RcsSettingsData.FT_CAPABILITY_ALWAYS_ON);\n        mHelper.setBoolCheckBox(R.id.FtHttpAlwaysOn, RcsSettingsData.FT_HTTP_CAP_ALWAYS_ON);\n        mHelper.setBoolCheckBox(R.id.InviteOnlyGroupchatSF,\n                RcsSettingsData.GROUP_CHAT_INVITE_ONLY_FULL_SF);\n        mHelper.setBoolCheckBox(R.id.ImUseReports, RcsSettingsData.IM_USE_REPORTS);\n        mHelper.setBoolCheckBox(R.id.Gruu, RcsSettingsData.GRUU);\n        mHelper.setBoolCheckBox(R.id.CpuAlwaysOn, RcsSettingsData.CPU_ALWAYS_ON);\n        mHelper.setBoolCheckBox(R.id.SecureMsrpOverWifi, RcsSettingsData.SECURE_MSRP_OVER_WIFI);\n        mHelper.setBoolCheckBox(R.id.SecureRtpOverWifi, RcsSettingsData.SECURE_RTP_OVER_WIFI);\n        mHelper.setBoolCheckBox(R.id.ImeiAsDeviceId, RcsSettingsData.USE_IMEI_AS_DEVICE_ID);\n        mHelper.setBoolCheckBox(R.id.ControlExtensions, RcsSettingsData.CONTROL_EXTENSIONS);\n        mHelper.setBoolCheckBox(R.id.AllowExtensions, RcsSettingsData.ALLOW_EXTENSIONS);\n        mHelper.setIntEditText(R.id.MaxMsrpLengthExtensions,\n                RcsSettingsData.MAX_MSRP_SIZE_EXTENSIONS);\n        mHelper.setLongEditText(R.id.MessagingCapabilitiesValidity,\n                RcsSettingsData.MSG_CAP_VALIDITY_PERIOD);\n    }\n\n    /**\n     * Load a list of certificates from the SDCARD\n     * \n     * @return List of certificates\n     */\n    private String[] loadCertificatesList() {\n        String[] files = null;\n        File folder = new File(CERTIFICATE_FOLDER_PATH);\n        try {\n            // noinspection ResultOfMethodCallIgnored\n            folder.mkdirs();\n            if (folder.exists()) {\n                // filter\n                FilenameFilter filter = new FilenameFilter() {\n                    public boolean accept(File dir, String filename) {\n                        return filename.contains(RcsSettingsData.CERTIFICATE_FILE_TYPE);\n                    }\n                };\n                files = folder.list(filter);\n            }\n        } catch (SecurityException e) {\n            // intentionally blank\n        }\n        if (files == null) {\n            // No certificate\n            return new String[] {\n                getString(R.string.label_no_certificate)\n            };\n        }\n        // Add certificates in the list\n        String[] temp = new String[files.length + 1];\n        temp[0] = getString(R.string.label_no_certificate);\n        if (files.length > 0) {\n            System.arraycopy(files, 0, temp, 1, files.length);\n        }\n        return temp;\n    }\n\n    @Override\n    public void persistRcsSettings() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"persistRcsSettings\");\n        }\n        Spinner spinner = (Spinner) mRootView.findViewById(R.id.Autoconfig);\n        switch (spinner.getSelectedItemPosition()) {\n            case 0:\n                sRcsSettings.setConfigurationMode(ConfigurationMode.MANUAL);\n                break;\n            default:\n                sRcsSettings.setConfigurationMode(ConfigurationMode.AUTO);\n                break;\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.SipDefaultProtocolForMobile);\n        sRcsSettings.writeString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_MOBILE,\n                (String) spinner.getSelectedItem());\n\n        spinner = (Spinner) mRootView.findViewById(R.id.EnableRcsSwitch);\n        switch (spinner.getSelectedItemPosition()) {\n            case 1:\n                sRcsSettings.setEnableRcseSwitch(EnableRcseSwitch.ALWAYS_SHOW);\n                break;\n            case 0:\n                sRcsSettings.setEnableRcseSwitch(EnableRcseSwitch.ONLY_SHOW_IN_ROAMING);\n                break;\n            default:\n                sRcsSettings.setEnableRcseSwitch(EnableRcseSwitch.NEVER_SHOW);\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.SipDefaultProtocolForWifi);\n        sRcsSettings.writeString(RcsSettingsData.SIP_DEFAULT_PROTOCOL_FOR_WIFI,\n                (String) spinner.getSelectedItem());\n\n        mHelper.saveBoolCheckBox(R.id.TcpFallback, RcsSettingsData.TCP_FALLBACK);\n\n        spinner = (Spinner) mRootView.findViewById(R.id.TlsCertificateRoot);\n        if (spinner.getSelectedItemPosition() == 0) {\n            sRcsSettings.writeString(RcsSettingsData.TLS_CERTIFICATE_ROOT, null);\n        } else {\n            String path = CERTIFICATE_FOLDER_PATH + File.separator + spinner.getSelectedItem();\n            sRcsSettings.writeString(RcsSettingsData.TLS_CERTIFICATE_ROOT, path);\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.TlsCertificateIntermediate);\n        if (spinner.getSelectedItemPosition() == 0) {\n            sRcsSettings.writeString(RcsSettingsData.TLS_CERTIFICATE_INTERMEDIATE, null);\n        } else {\n            String path = CERTIFICATE_FOLDER_PATH + File.separator + spinner.getSelectedItem();\n            sRcsSettings.writeString(RcsSettingsData.TLS_CERTIFICATE_INTERMEDIATE, path);\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.NetworkAccess);\n        switch (spinner.getSelectedItemPosition()) {\n            case 1:\n                sRcsSettings.setNetworkAccess(NetworkAccessType.MOBILE);\n                break;\n            case 2:\n                sRcsSettings.setNetworkAccess(NetworkAccessType.WIFI);\n                break;\n            default:\n                sRcsSettings.setNetworkAccess(NetworkAccessType.ANY);\n        }\n        spinner = (Spinner) mRootView.findViewById(R.id.FtProtocol);\n        FileTransferProtocol protocol = FileTransferProtocol.valueOf((String) spinner\n                .getSelectedItem());\n        sRcsSettings.setFtProtocol(protocol);\n\n        mHelper.saveStringEditText(R.id.SecondaryProvisioningAddress,\n                RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS);\n        mHelper.saveBoolCheckBox(R.id.SecondaryProvisioningAddressOnly,\n                RcsSettingsData.SECONDARY_PROVISIONING_ADDRESS_ONLY);\n        mHelper.saveLongEditText(R.id.ImsServicePollingPeriod,\n                RcsSettingsData.IMS_SERVICE_POLLING_PERIOD);\n        mHelper.saveIntEditText(R.id.SipListeningPort, RcsSettingsData.SIP_DEFAULT_PORT);\n        mHelper.saveLongEditText(R.id.SipTimerT1, RcsSettingsData.SIP_TIMER_T1);\n        mHelper.saveLongEditText(R.id.SipTimerT2, RcsSettingsData.SIP_TIMER_T2);\n        mHelper.saveLongEditText(R.id.SipTimerT4, RcsSettingsData.SIP_TIMER_T4);\n        mHelper.saveLongEditText(R.id.SipTransactionTimeout,\n                RcsSettingsData.SIP_TRANSACTION_TIMEOUT);\n        mHelper.saveLongEditText(R.id.SipKeepAlivePeriod, RcsSettingsData.SIP_KEEP_ALIVE_PERIOD);\n        mHelper.saveIntEditText(R.id.DefaultMsrpPort, RcsSettingsData.MSRP_DEFAULT_PORT);\n        mHelper.saveIntEditText(R.id.DefaultRtpPort, RcsSettingsData.RTP_DEFAULT_PORT);\n        mHelper.saveLongEditText(R.id.MsrpTransactionTimeout,\n                RcsSettingsData.MSRP_TRANSACTION_TIMEOUT);\n        mHelper.saveLongEditText(R.id.RegisterExpirePeriod, RcsSettingsData.REGISTER_EXPIRE_PERIOD);\n        mHelper.saveLongEditText(R.id.RegisterRetryBaseTime,\n                RcsSettingsData.REGISTER_RETRY_BASE_TIME);\n        mHelper.saveLongEditText(R.id.RegisterRetryMaxTime, RcsSettingsData.REGISTER_RETRY_MAX_TIME);\n        mHelper.saveLongEditText(R.id.PublishExpirePeriod, RcsSettingsData.PUBLISH_EXPIRE_PERIOD);\n        mHelper.saveLongEditText(R.id.RevokeTimeout, RcsSettingsData.REVOKE_TIMEOUT);\n        mHelper.saveLongEditText(R.id.RingingPeriod, RcsSettingsData.RINGING_SESSION_PERIOD);\n        mHelper.saveLongEditText(R.id.SubscribeExpirePeriod,\n                RcsSettingsData.SUBSCRIBE_EXPIRE_PERIOD);\n        mHelper.saveLongEditText(R.id.IsComposingTimeout, RcsSettingsData.IS_COMPOSING_TIMEOUT);\n        mHelper.saveLongEditText(R.id.SessionRefreshExpirePeriod,\n                RcsSettingsData.SESSION_REFRESH_EXPIRE_PERIOD);\n        mHelper.saveLongEditText(R.id.CapabilityRefreshTimeout,\n                RcsSettingsData.CAPABILITY_REFRESH_TIMEOUT);\n        mHelper.saveLongEditText(R.id.CapabilityExpiryTimeout,\n                RcsSettingsData.CAPABILITY_EXPIRY_TIMEOUT);\n        mHelper.saveLongEditText(R.id.CapabilityPollingPeriod,\n                RcsSettingsData.CAPABILITY_POLLING_PERIOD);\n        mHelper.saveBoolCheckBox(R.id.SipKeepAlive, RcsSettingsData.SIP_KEEP_ALIVE);\n        mHelper.saveBoolCheckBox(R.id.PermanentState, RcsSettingsData.PERMANENT_STATE_MODE);\n        mHelper.saveBoolCheckBox(R.id.TelUriFormat, RcsSettingsData.TEL_URI_FORMAT);\n        mHelper.saveBoolCheckBox(R.id.ImAlwaysOn, RcsSettingsData.IM_CAPABILITY_ALWAYS_ON);\n        mHelper.saveBoolCheckBox(R.id.FtAlwaysOn, RcsSettingsData.FT_CAPABILITY_ALWAYS_ON);\n        mHelper.saveBoolCheckBox(R.id.FtHttpAlwaysOn, RcsSettingsData.FT_HTTP_CAP_ALWAYS_ON);\n        mHelper.saveBoolCheckBox(R.id.InviteOnlyGroupchatSF,\n                RcsSettingsData.GROUP_CHAT_INVITE_ONLY_FULL_SF);\n        mHelper.saveBoolCheckBox(R.id.ImUseReports, RcsSettingsData.IM_USE_REPORTS);\n        mHelper.saveBoolCheckBox(R.id.Gruu, RcsSettingsData.GRUU);\n        mHelper.saveBoolCheckBox(R.id.CpuAlwaysOn, RcsSettingsData.CPU_ALWAYS_ON);\n        mHelper.saveBoolCheckBox(R.id.SecureMsrpOverWifi, RcsSettingsData.SECURE_MSRP_OVER_WIFI);\n        mHelper.saveBoolCheckBox(R.id.SecureRtpOverWifi, RcsSettingsData.SECURE_RTP_OVER_WIFI);\n        mHelper.saveBoolCheckBox(R.id.ImeiAsDeviceId, RcsSettingsData.USE_IMEI_AS_DEVICE_ID);\n        mHelper.saveBoolCheckBox(R.id.ControlExtensions, RcsSettingsData.CONTROL_EXTENSIONS);\n        mHelper.saveBoolCheckBox(R.id.AllowExtensions, RcsSettingsData.ALLOW_EXTENSIONS);\n        mHelper.saveIntEditText(R.id.MaxMsrpLengthExtensions,\n                RcsSettingsData.MAX_MSRP_SIZE_EXTENSIONS);\n        mHelper.saveLongEditText(R.id.MessagingCapabilitiesValidity,\n                RcsSettingsData.MSG_CAP_VALIDITY_PERIOD);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/provisioning/local/ViewPagerAdapter.java",
    "content": "\npackage com.gsma.rcs.provisioning.local;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport android.support.v4.app.Fragment;\nimport android.support.v4.app.FragmentManager;\nimport android.support.v4.app.FragmentPagerAdapter;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ViewPagerAdapter extends FragmentPagerAdapter {\n\n    private final static int PAGE_COUNT = 5;\n    private final RcsSettings mRcsSettings;\n    private final String[] mTitles;\n    private Map<String, IProvisioningFragment> fragments;\n\n    public ViewPagerAdapter(FragmentManager fm, String[] titles, RcsSettings rcsSettings) {\n        super(fm);\n        mTitles = titles;\n        mRcsSettings = rcsSettings;\n        fragments = new HashMap<>();\n    }\n\n    @Override\n    public Fragment getItem(int position) {\n        switch (position) {\n            case 0:\n                ProfileProvisioning profileFragment = ProfileProvisioning.newInstance(mRcsSettings);\n                fragments.put(ProfileProvisioning.class.getName(), profileFragment);\n                return profileFragment;\n\n            case 1:\n                StackProvisioning stackFragment = StackProvisioning.newInstance(mRcsSettings);\n                fragments.put(StackProvisioning.class.getName(), stackFragment);\n                return stackFragment;\n\n            case 2:\n                ServiceProvisioning serviceFragment = ServiceProvisioning.newInstance(mRcsSettings);\n                fragments.put(ServiceProvisioning.class.getName(), serviceFragment);\n                return serviceFragment;\n\n            case 3:\n                CapabilitiesProvisioning capaFragment = CapabilitiesProvisioning.newInstance(mRcsSettings);\n                fragments.put(CapabilitiesProvisioning.class.getName(), capaFragment);\n                return capaFragment;\n\n            case 4:\n                LoggerProvisioning loggerFragment = LoggerProvisioning.newInstance(mRcsSettings);\n                fragments.put(LoggerProvisioning.class.getName(), loggerFragment);\n                return loggerFragment;\n        }\n        return null;\n    }\n\n    public CharSequence getPageTitle(int position) {\n        return mTitles[position];\n    }\n\n    @Override\n    public int getCount() {\n        return PAGE_COUNT;\n    }\n\n    public Collection<IProvisioningFragment> getFragments() {\n        return fragments.values();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/CpuManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.Context;\nimport android.os.PowerManager;\n\n/**\n * CPU manager\n * \n * @author jexa7410\n */\npublic class CpuManager {\n    /**\n     * Power lock\n     */\n    private PowerManager.WakeLock mPowerLock;\n\n    /**\n     * The logger\n     */\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings The RCS settings accessor\n     */\n    public CpuManager(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Init\n     */\n    public void init() {\n        if (!mRcsSettings.isCpuAlwaysOn()) {\n            return;\n        }\n        // Activate the always-on procedure even if the device wakes up\n        PowerManager pm = (PowerManager) AndroidFactory.getApplicationContext().getSystemService(\n                Context.POWER_SERVICE);\n        mPowerLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"RcsCore\");\n        mPowerLock.acquire();\n        if (logger.isActivated()) {\n            logger.info(\"Always-on CPU activated\");\n        }\n    }\n\n    /**\n     * Stop\n     */\n    public void close() {\n        // Release power manager wave lock\n        if (mPowerLock != null) {\n            mPowerLock.release();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/DequeueTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.ServerApiUtils;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.content.Context;\nimport android.net.Uri;\n\npublic abstract class DequeueTask implements Runnable {\n\n    private final Core mCore;\n\n    protected final Context mCtx;\n\n    protected final InstantMessagingService mImService;\n\n    protected final ContactManager mContactManager;\n\n    protected final MessagingLog mMessagingLog;\n\n    protected final RcsSettings mRcsSettings;\n\n    protected final ChatServiceImpl mChatService;\n\n    protected final FileTransferServiceImpl mFileTransferService;\n\n    protected final Logger mLogger = Logger.getLogger(getClass().getName());\n\n    public DequeueTask(Context ctx, Core core, ContactManager contactManager,\n            MessagingLog messagingLog, RcsSettings rcsSettings, ChatServiceImpl chatService,\n            FileTransferServiceImpl fileTransferService) {\n        mCtx = ctx;\n        mCore = core;\n        mImService = core.getImService();\n        mContactManager = contactManager;\n        mMessagingLog = messagingLog;\n        mRcsSettings = rcsSettings;\n        mChatService = chatService;\n        mFileTransferService = fileTransferService;\n    }\n\n    /**\n     * Check if it is possible to dequeue and transfer one-one/ group file\n     * \n     * @return boolean\n     */\n    private boolean isAllowedToDequeueFileTransfer() {\n        if (mImService.isMaxConcurrentOutgoingFileTransfersReached()) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Cannot dequeue file transfer as the limit of allowed concurrent outgoing file transfers is reached.\");\n            }\n            return false;\n        }\n        if (!mImService.isFileTransferSessionAvailable()) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Cannot dequeue file transfer as there are no available file transfer sessions.\");\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Check if it is possible to dequeue and transfer one-one file\n     * \n     * @param contact Remote contact\n     * @param fileTransferService File transfer service\n     * @return boolean\n     */\n    protected boolean isAllowedToDequeueOneToOneFileTransfer(ContactId contact,\n            FileTransferServiceImpl fileTransferService) {\n        if (fileTransferService.getFileTransferProtocolForOneToOneFileTransfer(contact) == null) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(new StringBuilder(\n                        \"Cannot dequeue one-to-one file transfer right now as there are no enough capabilities for remote contact '\")\n                        .append(contact).append(\"'\").toString());\n            }\n            return false;\n        }\n        return isAllowedToDequeueFileTransfer();\n    }\n\n    /**\n     * Check if it is possible to dequeue and transfer one-one file\n     * \n     * @return boolean\n     */\n    protected boolean isAllowedToDequeueGroupFileTransfer() {\n        return isAllowedToDequeueFileTransfer();\n    }\n\n    /**\n     * Check if dequeueing and sending of 1-1 chat messages to specified contact is allowed\n     * \n     * @param contact Remote contact\n     * @return boolean\n     */\n    protected boolean isAllowedToDequeueOneToOneChatMessage(ContactId contact) {\n        Capabilities remoteCapabilities = mContactManager.getContactCapabilities(contact);\n        if (!remoteCapabilities.isImSessionSupported()) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(new StringBuilder(\n                        \"Cannot dequeue one-to-one chat messages right now as IM session capabilities are not supported for remote contact \")\n                        .append(contact).append(\" and IM_CAP_ALWAYS_ON is false!\").toString());\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Check if dequeueing and sending of 1-1 chat messages to specified contact is possible\n     * \n     * @param contact Remote contact\n     * @return boolean\n     */\n    protected boolean isPossibleToDequeueOneToOneChatMessage(ContactId contact) {\n        Capabilities remoteCapabilities = mContactManager.getContactCapabilities(contact);\n        if (remoteCapabilities == null) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(new StringBuilder(\n                        \"Cannot dequeue one-to-one chat messages as the capabilities are not known for remote contact \")\n                        .append(contact).toString());\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Check if it is possible to dequeue group chat messages and group file transfers\n     * \n     * @param chatId Chat ID\n     * @return boolean\n     */\n    protected boolean isPossibleToDequeueGroupChatMessagesAndGroupFileTransfers(String chatId) {\n        if (!mRcsSettings.isGroupChatActivated()) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Cannot dequeue group chat messages and file transfers right now as group chat feature is not activated!\");\n            }\n            return false;\n        }\n        if (mChatService.isGroupChatAbandoned(chatId)) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(new StringBuilder(\n                        \"Cannot dequeue group chat messages and group file transfers right now as the group chat with chatId '\")\n                        .append(chatId)\n                        .append(\"' is abandoned and can be no more used to send or receive messages.\")\n                        .toString());\n            }\n            return false;\n        }\n        final GroupChatSession groupChatSession = mImService.getGroupChatSession(chatId);\n        if (groupChatSession == null) {\n            GroupChatInfo groupChat = mMessagingLog.getGroupChatInfo(chatId);\n            if (groupChat == null) {\n                if (mLogger.isActivated()) {\n                    mLogger.debug(new StringBuilder(\n                            \"Cannot dequeue group chat messages and group file transfers as the group chat with group chat Id '\")\n                            .append(chatId)\n                            .append(\"' is not rejoinable as the group chat does not exist in DB.\")\n                            .toString());\n                }\n                return false;\n            }\n            if (groupChat.getRejoinId() == null) {\n                if (mLogger.isActivated()) {\n                    mLogger.debug(new StringBuilder(\n                            \"Cannot dequeue group chat messages and group file transfers as thr group chat with group chat Id '\")\n                            .append(chatId)\n                            .append(\"' is not rejoinable as there is no ongoing session with \"\n                                    + \"corresponding chatId and there exists no rejoinId to \"\n                                    + \"rejoin the group chat.\").toString());\n                }\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Check if it is possible to dequeue file transfer\n     * \n     * @return boolean\n     */\n    private boolean isPossibleToDequeueFileTransfer(Uri file, long size) {\n        if (!FileUtils.isReadFromUriPossible(mCtx, file)) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Cannot dequeue file as file data can not be read from Uri \"\n                        .concat(file.toString()));\n            }\n            return false;\n        }\n        if (mImService.isFileSizeExceeded(size)) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(new StringBuilder(\n                        \"Cannot dequeue file as there the maximum allowed size is exceeded by the file \")\n                        .append(file).append(\" size: \").append(size).toString());\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Check if it is possible to dequeue one-one file transfer\n     * \n     * @param contact Remote contact\n     * @param file file Uri\n     * @param size file size\n     * @return boolean\n     */\n    protected boolean isPossibleToDequeueOneToOneFileTransfer(ContactId contact, Uri file, long size) {\n        Capabilities remoteCapabilities = mContactManager.getContactCapabilities(contact);\n        if (remoteCapabilities == null) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(new StringBuilder(\n                        \"Cannot dequeue one-to-one file transfer as the capabilities are not known for remote contact \")\n                        .append(contact).toString());\n            }\n            return false;\n        }\n        return isPossibleToDequeueFileTransfer(file, size);\n    }\n\n    /**\n     * Check if it is possible to dequeue group file transfer\n     * \n     * @param chatId Chat ID\n     * @param file file Uri\n     * @param size file size\n     * @return boolean\n     */\n    protected boolean isPossibleToDequeueGroupFileTransfer(String chatId, Uri file, long size) {\n        if (!isPossibleToDequeueFileTransfer(file, size)) {\n            return false;\n        }\n        if (!isPossibleToDequeueGroupChatMessagesAndGroupFileTransfers(chatId)) {\n            return false;\n        }\n        if (!mRcsSettings.getMyCapabilities().isFileTransferHttpSupported()) {\n            if (mLogger.isActivated()) {\n                mLogger.debug(\"Cannot transfer file to group chat as FT over HTTP capabilities are not supported for self.\");\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Set one-one chat message as failed\n     * \n     * @param contact Remote contact\n     * @param msgId message ID\n     * @param mimeType mime type\n     */\n    protected void setOneToOneChatMessageAsFailedDequeue(ContactId contact, String msgId,\n            String mimeType) {\n        mChatService.setOneToOneChatMessageStatusAndReasonCode(msgId, mimeType, contact,\n                Status.FAILED, Content.ReasonCode.FAILED_SEND);\n    }\n\n    /**\n     * Set group chat message as failed\n     * \n     * @param chatId Chat ID\n     * @param msgId Message ID\n     * @param mimeType mime type\n     */\n    protected void setGroupChatMessageAsFailedDequeue(String chatId, String msgId, String mimeType) {\n        mChatService.setGroupChatMessageStatusAndReasonCode(msgId, mimeType, chatId, Status.FAILED,\n                Content.ReasonCode.FAILED_SEND);\n    }\n\n    /**\n     * Set one-one file transfer as failed\n     * \n     * @param contact Remote contact\n     * @param fileTransferId File transfer ID\n     */\n    protected void setOneToOneFileTransferAsFailedDequeue(ContactId contact, String fileTransferId) {\n        mFileTransferService.setOneToOneFileTransferStateAndReasonCode(fileTransferId, contact,\n                State.FAILED, FileTransfer.ReasonCode.FAILED_NOT_ALLOWED_TO_SEND);\n    }\n\n    /**\n     * Set group file transfer as failed\n     * \n     * @param chatId Chat ID\n     * @param fileTransferId File transfer ID\n     */\n    protected void setGroupFileTransferAsFailedDequeue(String chatId, String fileTransferId) {\n        mFileTransferService.setGroupFileTransferStateAndReasonCode(fileTransferId, chatId,\n                State.FAILED, FileTransfer.ReasonCode.FAILED_NOT_ALLOWED_TO_SEND);\n    }\n\n    /**\n     * Is IMS connected\n     * \n     * @return boolean\n     */\n    protected boolean isImsConnected() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Is Core shutting down right now or already stopped\n     * \n     * @return boolean\n     */\n    protected boolean isShuttingDownOrStopped() {\n        return mCore.isStopping() || !mCore.isStarted();\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/DeviceBoot.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Device boot event receiver: automatically starts the RCS service\n * \n * @author jexa7410\n */\npublic class DeviceBoot extends BroadcastReceiver {\n    private static Logger logger = Logger.getLogger(DeviceBoot.class.getSimpleName());\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (logger.isActivated())\n            logger.debug(\"Start RCS service after boot\");\n        LocalContentResolver localContentResolver = new LocalContentResolver(context);\n        RcsSettings rcsSettings = RcsSettings.getInstance(localContentResolver);\n        LauncherUtils.launchRcsService(context, true, false, rcsSettings);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/DeviceShutdown.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Device shutdown event receiver: automatically stops the RCS service\n * \n * @author jexa7410\n */\npublic class DeviceShutdown extends BroadcastReceiver {\n\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (logger.isActivated()) {\n            logger.debug(\"Device shutdown\");\n        }\n        LauncherUtils.stopRcsService(context);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/GroupChatInviteQueuedParticipantsTask.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.GroupChatImpl;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class GroupChatInviteQueuedParticipantsTask implements Runnable {\n\n    private static final Set<ParticipantStatus> INVITE_QUEUED_STATUSES = new HashSet<>();\n    static {\n        INVITE_QUEUED_STATUSES.add(ParticipantStatus.INVITE_QUEUED);\n    }\n\n    private final String mChatId;\n\n    private final ChatServiceImpl mChatService;\n\n    private final InstantMessagingService mImService;\n\n    private static final Logger sLogger = Logger\n            .getLogger(GroupChatInviteQueuedParticipantsTask.class.getName());\n\n    public GroupChatInviteQueuedParticipantsTask(String chatId, ChatServiceImpl chatService,\n            InstantMessagingService imService) {\n        mChatId = chatId;\n        mChatService = chatService;\n        mImService = imService;\n    }\n\n    @Override\n    public void run() {\n        try {\n            GroupChatImpl groupChat = mChatService.getOrCreateGroupChat(mChatId);\n            final Set<ContactId> participantsToBeInvited = groupChat.getParticipants(\n                    INVITE_QUEUED_STATUSES).keySet();\n            if (participantsToBeInvited.size() == 0) {\n                return;\n            }\n\n            final GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session != null && session.isMediaEstablished()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(new StringBuilder(\"Adding \")\n                            .append(Arrays.toString(participantsToBeInvited.toArray()))\n                            .append(\" to the group chat session \").append(mChatId).append(\".\")\n                            .toString());\n                }\n\n                if (session.getMaxNumberOfAdditionalParticipants() < participantsToBeInvited.size()) {\n                    for (ContactId contact : participantsToBeInvited) {\n                        groupChat.onAddParticipantFailed(contact,\n                                \"Maximum number of participants reached\");\n                    }\n                    return;\n                }\n                session.inviteParticipants(participantsToBeInvited);\n            }\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (PayloadException e) {\n            sLogger.error(\n                    \"Exception occured while trying to invite queued participants to group chat with chatId \"\n                            .concat(mChatId), e);\n        } catch (RuntimeException e) {\n            /*\n             * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n             * which should be handled/fixed within the code. However the cases when we are\n             * executing operations on a thread unhandling such exceptions will eventually lead to\n             * exit the system and thus can bring the whole system down, which is not intended.\n             */\n            sLogger.error(\n                    new StringBuilder(\n                            \"Exception occured while trying to invite queued participants to group chat with chatId \")\n                            .append(mChatId).toString(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/LauncherUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.addressbook.AccountChangedReceiver;\nimport com.gsma.rcs.addressbook.RcsAccountManager;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.platform.registry.AndroidRegistryFactory;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.provisioning.ProvisioningInfo;\nimport com.gsma.rcs.provisioning.https.HttpsProvisioningService;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.telephony.TelephonyManager;\n\n/**\n * Launcher utility functions\n * \n * @author hlxn7157\n */\npublic class LauncherUtils {\n\n    private static final long DEFAULT_PROVISIONING_VALIDITY = 24 * 3600 * 1000L;\n\n    /**\n     * Last user account used\n     */\n    public static final String REGISTRY_LAST_USER_ACCOUNT = \"LastUserAccount\";\n\n    /**\n     * Key for storing the latest positive provisioning version\n     */\n    private static final String REGISTRY_PROVISIONING_VERSION = \"ProvisioningVersion\";\n\n    /**\n     * Key for storing the latest positive provisioning validity\n     */\n    private static final String REGISTRY_PROVISIONING_VALIDITY = \"ProvisioningValidity\";\n\n    /**\n     * Key for storing the expiration date of the provisioning\n     */\n    private static final String REGISTRY_PROVISIONING_EXPIRATION = \"ProvisioningExpiration\";\n\n    /**\n     * Count of Registration 403 response\n     */\n    private static final String REGISTRATION_FORBIDDEN_COUNT = \"RegForbiddenCount\";\n\n    private static final Logger sLogger = Logger.getLogger(LauncherUtils.class.getName());\n\n    /**\n     * Launch the RCS service\n     * \n     * @param context application context\n     * @param boot Boot flag\n     * @param user restart is required by user\n     * @param rcsSettings RCS settings accessor\n     */\n    public static void launchRcsService(Context context, boolean boot, boolean user,\n            RcsSettings rcsSettings) {\n        /* Set the logger properties */\n        Logger.sActivationFlag = rcsSettings.isTraceActivated();\n        Logger.traceLevel = rcsSettings.getTraceLevel();\n        if (rcsSettings.isServiceActivated()) {\n            StartService.LaunchRcsStartService(context, boot, user);\n        }\n    }\n\n    /**\n     * Launch the RCS core service\n     * \n     * @param context Application context\n     * @param rcsSettings RCS settings accessor\n     */\n    public static void launchRcsCoreService(Context context, RcsSettings rcsSettings) {\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Launch core service\");\n        }\n        if (!rcsSettings.isServiceActivated()) {\n            if (logActivated) {\n                sLogger.debug(\"RCS service is disabled\");\n            }\n            return;\n        }\n        if (!rcsSettings.isUserProfileConfigured()) {\n            if (logActivated) {\n                sLogger.debug(\"RCS service not configured\");\n            }\n            return;\n        }\n        TermsAndConditionsResponse tcResponse = rcsSettings.getTermsAndConditionsResponse();\n        if (TermsAndConditionsResponse.ACCEPTED != tcResponse) {\n            if (logActivated) {\n                sLogger.debug(\"Terms and conditions response: \".concat(tcResponse.name()));\n            }\n            return;\n        }\n        context.startService(new Intent(context, RcsCoreService.class));\n    }\n\n    /**\n     * Stop the RCS service\n     * \n     * @param context Application context\n     */\n    public static void stopRcsService(Context context) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop RCS service\");\n        }\n        context.stopService(new Intent(context, StartService.class));\n        context.stopService(new Intent(context, HttpsProvisioningService.class));\n        context.stopService(new Intent(context, RcsCoreService.class));\n    }\n\n    /**\n     * Stop the RCS core service (but keep provisioning)\n     * \n     * @param context Application context\n     */\n    public static void stopRcsCoreService(Context context) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop RCS core service\");\n        }\n        context.stopService(new Intent(context, StartService.class));\n        context.stopService(new Intent(context, RcsCoreService.class));\n    }\n\n    /**\n     * Reset RCS configuration\n     * \n     * @param ctx Application context\n     * @param localContentResolver Local content resolver\n     * @param rcsSettings RCS settings accessor\n     * @param mMessagingLog Message log accessor\n     * @param contactManager Contact manager accessor\n     */\n    public static void resetRcsConfig(Context ctx, LocalContentResolver localContentResolver,\n            RcsSettings rcsSettings, MessagingLog mMessagingLog, ContactManager contactManager) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Reset RCS config\");\n        }\n        /* Stop the Core service */\n        ctx.stopService(new Intent(ctx, RcsCoreService.class));\n\n        /* Reset existing configuration parameters */\n        rcsSettings.resetConfigParameters();\n\n        /* Clear all entries in chat, message and file transfer tables */\n        mMessagingLog.deleteAllEntries();\n\n        /* Clear all entries in Rich Call tables (image and video) */\n        RichCallHistory.getInstance(localContentResolver);\n        RichCallHistory.getInstance().deleteAllEntries();\n\n        /*\n         * Clean the previous account RCS databases : because they may not be overwritten in the\n         * case of a very new account or if the back-up files of an older one have been destroyed.\n         */\n        contactManager.deleteRCSEntries();\n\n        /* Remove the RCS account */\n        RcsAccountManager accountUtility = RcsAccountManager.getInstance(ctx, contactManager);\n        accountUtility.removeRcsAccount(null);\n        /*\n         * Ensure that factory is set up properly to avoid NullPointerException in\n         * AccountChangedReceiver.setAccountResetByEndUser\n         */\n        AndroidFactory.setApplicationContext(ctx, rcsSettings);\n        AccountChangedReceiver.setAccountResetByEndUser(false);\n\n        /* Clean terms status */\n        rcsSettings.setTermsAndConditionsResponse(TermsAndConditionsResponse.NO_ANSWER);\n\n        /* Set the configuration validity flag to false */\n        rcsSettings.setConfigurationValid(false);\n    }\n\n    /**\n     * Get the last user account\n     * \n     * @param context Application context\n     * @return last user account\n     */\n    public static String getLastUserAccount(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        return preferences.getString(REGISTRY_LAST_USER_ACCOUNT, null);\n    }\n\n    /**\n     * Set the last user account\n     * \n     * @param context Application context\n     * @param value last user account\n     */\n    public static void setLastUserAccount(Context context, String value) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putString(REGISTRY_LAST_USER_ACCOUNT, value);\n        editor.commit();\n    }\n\n    /**\n     * Get current user account\n     * \n     * @param context Application context\n     * @return current user account\n     */\n    public static String getCurrentUserAccount(Context context) {\n        TelephonyManager mgr = (TelephonyManager) context\n                .getSystemService(Context.TELEPHONY_SERVICE);\n        String currentUserAccount = mgr.getSubscriberId();\n        if (currentUserAccount == null) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Cannot get subscriber ID from telephony manager!\");\n            }\n        }\n        return currentUserAccount;\n    }\n\n    /**\n     * Get the latest positive provisioning version\n     * \n     * @param context Application context\n     * @return the latest positive provisioning version\n     */\n    public static int getProvisioningVersion(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        return preferences.getInt(REGISTRY_PROVISIONING_VERSION,\n                ProvisioningInfo.Version.RESETED.toInt());\n    }\n\n    /**\n     * Save the latest positive provisioning version in shared preferences\n     * \n     * @param context Application context\n     * @param version the latest positive provisioning version\n     */\n    public static void saveProvisioningVersion(Context context, int version) {\n        if (version > 0) {\n            SharedPreferences preferences = context.getSharedPreferences(\n                    AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n            SharedPreferences.Editor editor = preferences.edit();\n            editor.putInt(REGISTRY_PROVISIONING_VERSION, version);\n            editor.commit();\n        }\n    }\n\n    /**\n     * Get the expiration date of the provisioning\n     * \n     * @param context Application context\n     * @return the expiration date in milliseconds or 0 if not applicable\n     */\n    public static long getProvisioningExpirationDate(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        return preferences.getLong(REGISTRY_PROVISIONING_EXPIRATION, 0L);\n    }\n\n    /**\n     * Get the expiration date of the provisioning\n     * \n     * @param context Application context\n     * @return the expiration date in milliseconds\n     */\n    public static long getProvisioningValidity(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        return preferences.getLong(REGISTRY_PROVISIONING_VALIDITY, DEFAULT_PROVISIONING_VALIDITY);\n    }\n\n    /**\n     * Save the provisioning validity in shared preferences\n     * \n     * @param context Context\n     * @param validity validity of the provisioning expressed in milliseconds\n     */\n    public static void saveProvisioningValidity(Context context, long validity) {\n        if (validity <= 0L) {\n            return;\n        }\n        /* Calculate next expiration time in milliseconds */\n        long next = System.currentTimeMillis() + validity;\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putLong(REGISTRY_PROVISIONING_VALIDITY, validity);\n        editor.putLong(REGISTRY_PROVISIONING_EXPIRATION, next);\n        editor.commit();\n    }\n\n    /**\n     * Write the registration forbidden count in the registry\n     *\n     * @param context application context\n     * @param value count of registration forbidden failures\n     */\n    public static void setRegForbiddenCount(Context context, int value) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putInt(REGISTRATION_FORBIDDEN_COUNT, value);\n        editor.apply();\n    }\n\n    /**\n     * Get the registration forbidden count from the registry\n     *\n     * @param context application context\n     * @return Number of registration forbidden failures\n     */\n    public static int getRegForbiddenCount(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        return preferences.getInt(REGISTRATION_FORBIDDEN_COUNT, 0);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/RcsCoreService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.addressbook.AccountChangedReceiver;\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.CoreListener;\nimport com.gsma.rcs.core.TerminalInfo;\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.ims.ImsError;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.history.HistoryLog;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.service.api.CapabilityServiceImpl;\nimport com.gsma.rcs.service.api.ChatServiceImpl;\nimport com.gsma.rcs.service.api.ContactServiceImpl;\nimport com.gsma.rcs.service.api.FileTransferServiceImpl;\nimport com.gsma.rcs.service.api.FileUploadServiceImpl;\nimport com.gsma.rcs.service.api.GeolocSharingServiceImpl;\nimport com.gsma.rcs.service.api.HistoryServiceImpl;\nimport com.gsma.rcs.service.api.ImageSharingServiceImpl;\nimport com.gsma.rcs.service.api.MultimediaSessionServiceImpl;\nimport com.gsma.rcs.service.api.VideoSharingServiceImpl;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.capability.ICapabilityService;\nimport com.gsma.services.rcs.chat.IChatService;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.IContactService;\nimport com.gsma.services.rcs.extension.IMultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.IFileTransferService;\nimport com.gsma.services.rcs.history.IHistoryService;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.IImageSharingService;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingService;\nimport com.gsma.services.rcs.upload.IFileUploadService;\n\nimport android.app.Service;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\n\nimport java.io.IOException;\nimport java.security.KeyStoreException;\nimport java.util.concurrent.CountDownLatch;\n\n/**\n * RCS core service. This service offers a flat API to any other process (activities) to access to\n * RCS features. This service is started automatically at device boot.\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RcsCoreService extends Service implements CoreListener {\n\n    private static final String BACKGROUND_THREAD_NAME = RcsCoreService.class.getSimpleName();\n\n    private CpuManager mCpuManager;\n\n    private AccountChangedReceiver mAccountChangedReceiver;\n\n    // --------------------- RCSJTA API -------------------------\n\n    private ContactServiceImpl mContactApi;\n\n    private CapabilityServiceImpl mCapabilityApi;\n\n    private ChatServiceImpl mChatApi;\n\n    private FileTransferServiceImpl mFtApi;\n\n    private VideoSharingServiceImpl mVshApi;\n\n    private ImageSharingServiceImpl mIshApi;\n\n    private GeolocSharingServiceImpl mGshApi;\n\n    private HistoryServiceImpl mHistoryApi;\n\n    private MultimediaSessionServiceImpl mMmSessionApi;\n\n    private FileUploadServiceImpl mUploadApi;\n\n    /**\n     * Need to start the core after stop if a StartService is called before the end of stopCore\n     */\n    private boolean mRestartCoreRequested = false;\n\n    private Context mCtx;\n\n    private RcsSettings mRcsSettings;\n\n    private ContentResolver mContentResolver;\n\n    private LocalContentResolver mLocalContentResolver;\n\n    private MessagingLog mMessagingLog;\n\n    private RichCallHistory mRichCallHistory;\n\n    private HistoryLog mHistoryLog;\n\n    private ContactManager mContactManager;\n\n    private CountDownLatch mLatch;\n\n    /**\n     * Handler to process messages & runnable associated with background thread.\n     */\n    private Handler mBackgroundHandler;\n\n    private final static Logger sLogger = Logger.getLogger(RcsCoreService.class.getSimpleName());\n\n    @Override\n    public void onCreate() {\n        mCtx = getApplicationContext();\n        mContentResolver = mCtx.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(mContentResolver);\n        mRcsSettings = RcsSettings.getInstance(mLocalContentResolver);\n        mHistoryLog = HistoryLog.getInstance(mLocalContentResolver);\n        mRichCallHistory = RichCallHistory.getInstance(mLocalContentResolver);\n        mMessagingLog = MessagingLog.getInstance(mLocalContentResolver, mRcsSettings);\n        mContactManager = ContactManager.getInstance(mCtx, mContentResolver, mLocalContentResolver,\n                mRcsSettings);\n        AndroidFactory.setApplicationContext(mCtx, mRcsSettings);\n        final HandlerThread backgroundThread = new HandlerThread(BACKGROUND_THREAD_NAME);\n        backgroundThread.start();\n\n        mBackgroundHandler = new Handler(backgroundThread.getLooper());\n\n        mLatch = new CountDownLatch(1);\n        mBackgroundHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    startCore();\n                    mLatch.countDown();\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Unable to start IMS core!\", e);\n                    mLatch.countDown();\n                }\n            }\n        });\n        try {\n            /*\n             * After moving startcore() to a side thread, onCreate will finish before startcore is\n             * done. This will lead to return null binder object when clients are trying to bind.\n             * And android will cache the binder object which means it will always return null\n             * afterward. Block main thread and wait for completion of startcore will prevent the\n             * issue mentioned above.\n             */\n            mLatch.await();\n        } catch (InterruptedException e) {\n            /* Do nothing */\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        // Unregister account changed broadcast receiver\n        if (mAccountChangedReceiver != null) {\n            try {\n                unregisterReceiver(mAccountChangedReceiver);\n            } catch (IllegalArgumentException e) {\n                // Nothing to do\n            }\n        }\n\n        // @FIXME: This is not the final implementation, this is certainly an improvement over the\n        // previous Handler implementation as for now stop core will run on worker thread instead of\n        // main thread. However there is a need to properly refactor the whole start & stop core\n        // functionality to properly handle simultaneous start/stop request's.\n        mBackgroundHandler.post(new Runnable() {\n            /**\n             * Processing\n             */\n            public void run() {\n                // TODO : This logic of stopping core during onDestroy() needs to be refactored\n                // as it's not recommended to do such tasks in onDestroy() and as this method\n                // eventually will also perform a de-register to IMS so this needs to be moved to a\n                // much appropriate level.\n                try {\n                    stopCore();\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n\n                } catch (ContactManagerException | RuntimeException | PayloadException e) {\n                    sLogger.error(\"Unable to stop IMS core!\", e);\n\n                } finally {\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {\n                        mBackgroundHandler.getLooper().quitSafely();\n                    } else {\n                        mBackgroundHandler.getLooper().quit();\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Start core\n     */\n    private synchronized void startCore() {\n        Core core = Core.getInstance();\n        boolean logActivated = sLogger.isActivated();\n        if (core != null) {\n            if (core.isStopping()) {\n                if (logActivated) {\n                    sLogger.debug(\"The core is stopping, we will restart it when core is stopped\");\n                }\n                core.setListener(this);\n                mRestartCoreRequested = true;\n            }\n            if (core.isStarted()) {\n                // Already started\n                return;\n            }\n        }\n\n        mRestartCoreRequested = false;\n        com.gsma.services.rcs.contact.ContactUtil contactUtil = com.gsma.services.rcs.contact.ContactUtil\n                .getInstance(this);\n        if (!contactUtil.isMyCountryCodeDefined()) {\n            if (logActivated) {\n                sLogger.debug(\"Can't instantiate RCS core service, Reason : Country code not defined!\");\n            }\n            stopSelf();\n            return;\n        }\n        try {\n            core = Core.createCore(mCtx, this, mRcsSettings, mContentResolver,\n                    mLocalContentResolver, mContactManager, mMessagingLog, mHistoryLog,\n                    mRichCallHistory);\n\n            InstantMessagingService imService = core.getImService();\n            RichcallService richCallService = core.getRichcallService();\n            SipService sipService = core.getSipService();\n            CapabilityService capabilityService = core.getCapabilityService();\n\n            mContactApi = new ContactServiceImpl(mContactManager, mRcsSettings);\n            mCapabilityApi = new CapabilityServiceImpl(capabilityService, mContactManager,\n                    mRcsSettings);\n            mChatApi = new ChatServiceImpl(imService, mMessagingLog, mHistoryLog, mRcsSettings,\n                    mContactManager);\n            mFtApi = new FileTransferServiceImpl(imService, mChatApi, mMessagingLog, mRcsSettings,\n                    mContactManager, mCtx);\n            mVshApi = new VideoSharingServiceImpl(richCallService, mRichCallHistory, mRcsSettings);\n            mIshApi = new ImageSharingServiceImpl(richCallService, mRichCallHistory, mRcsSettings);\n            mGshApi = new GeolocSharingServiceImpl(richCallService, mRichCallHistory, mRcsSettings);\n            mHistoryApi = new HistoryServiceImpl(mCtx);\n            mMmSessionApi = new MultimediaSessionServiceImpl(sipService, mRcsSettings);\n            mUploadApi = new FileUploadServiceImpl(imService, mRcsSettings);\n\n            Logger.sActivationFlag = mRcsSettings.isTraceActivated();\n            Logger.traceLevel = mRcsSettings.getTraceLevel();\n\n            if (logActivated) {\n                sLogger.info(\"RCS stack release is \".concat(TerminalInfo.getProductVersion(mCtx)));\n            }\n\n            core.initialize();\n\n            core.startCore();\n\n            // Create multimedia directory on sdcard\n            FileFactory.createDirectory(mRcsSettings.getPhotoRootDirectory());\n            FileFactory.createDirectory(mRcsSettings.getVideoRootDirectory());\n            FileFactory.createDirectory(mRcsSettings.getAudioRootDirectory());\n            FileFactory.createDirectory(mRcsSettings.getFileRootDirectory());\n            String fileIconDirectory = mRcsSettings.getFileIconRootDirectory();\n            FileFactory.createDirectory(fileIconDirectory);\n            FileFactory.setNoMedia(fileIconDirectory);\n            String sentPhotoDirectory = ContentManager.getSentPhotoRootDirectory(mRcsSettings);\n            FileFactory.createDirectory(sentPhotoDirectory);\n            FileFactory.setNoMedia(sentPhotoDirectory);\n            String sentVideoDirectory = ContentManager.getSentVideoRootDirectory(mRcsSettings);\n            FileFactory.createDirectory(sentVideoDirectory);\n            FileFactory.setNoMedia(sentVideoDirectory);\n            String sentAudioDirectory = ContentManager.getSentAudioRootDirectory(mRcsSettings);\n            FileFactory.createDirectory(sentAudioDirectory);\n            FileFactory.setNoMedia(sentAudioDirectory);\n            String sentFileDirectory = ContentManager.getSentFileRootDirectory(mRcsSettings);\n            FileFactory.createDirectory(sentFileDirectory);\n            FileFactory.setNoMedia(sentFileDirectory);\n\n            // Init CPU manager\n            mCpuManager = new CpuManager(mRcsSettings);\n            mCpuManager.init();\n\n            // Register account changed event receiver\n            if (mAccountChangedReceiver == null) {\n                mAccountChangedReceiver = new AccountChangedReceiver();\n\n                // Register account changed broadcast receiver after a timeout of 2s (This is not\n                // done immediately, as we do not want to catch\n                // the removal of the account (creating and removing accounts is done\n                // asynchronously). We can reasonably assume that no\n                // RCS account deletion will be done by user during this amount of time, as he just\n                // started his service.\n                Handler handler = new Handler();\n                handler.postDelayed(new Runnable() {\n                    public void run() {\n                        registerReceiver(mAccountChangedReceiver, new IntentFilter(\n                                \"android.accounts.LOGIN_ACCOUNTS_CHANGED\"));\n                    }\n                }, 2000);\n            }\n\n            if (logActivated) {\n                sLogger.info(\"RCS core service started with success\");\n            }\n        } catch (IOException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        } catch (KeyStoreException e) {\n            sLogger.error(\"Can't instanciate the RCS core service\", e);\n            stopSelf();\n        }\n    }\n\n    /**\n     * Stop core\n     * \n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws ContactManagerException\n     */\n    private synchronized void stopCore() throws PayloadException, NetworkException,\n            ContactManagerException {\n        if (Core.getInstance() == null) {\n            // Already stopped\n            return;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop RCS core service\");\n        }\n\n        // Close APIs\n        if (mContactApi != null) {\n            mContactApi.close();\n            mContactApi = null;\n        }\n        if (mCapabilityApi != null) {\n            mCapabilityApi.close();\n            mCapabilityApi = null;\n        }\n        if (mFtApi != null) {\n            mFtApi.close();\n            mFtApi = null;\n        }\n        if (mChatApi != null) {\n            mChatApi.close();\n            mChatApi = null;\n        }\n        if (mIshApi != null) {\n            mIshApi.close();\n            mIshApi = null;\n        }\n        if (mGshApi != null) {\n            mGshApi.close();\n            mGshApi = null;\n        }\n        if (mVshApi != null) {\n            mVshApi.close();\n            mVshApi = null;\n        }\n        if (mHistoryApi != null) {\n            mHistoryApi.close();\n            mHistoryApi = null;\n        }\n        if (mMmSessionApi != null) {\n            mMmSessionApi.close();\n            mMmSessionApi = null;\n        }\n        if (mUploadApi != null) {\n            mUploadApi.close();\n            mUploadApi = null;\n        }\n        // Terminate the core in background\n        Core.terminateCore();\n\n        // Close CPU manager\n        if (mCpuManager != null) {\n            mCpuManager.close();\n            mCpuManager = null;\n        }\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"RCS core service stopped with success\");\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        if (IContactService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Contact service API binding\");\n            }\n            return mContactApi;\n        } else if (ICapabilityService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Capability service API binding\");\n            }\n            return mCapabilityApi;\n        } else if (IFileTransferService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"File transfer service API binding\");\n            }\n            return mFtApi;\n        } else if (IChatService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Chat service API binding\");\n            }\n            return mChatApi;\n        } else if (IVideoSharingService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Video sharing service API binding\");\n            }\n            return mVshApi;\n        } else if (IImageSharingService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Image sharing service API binding\");\n            }\n            return mIshApi;\n        } else if (IGeolocSharingService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Geoloc sharing service API binding\");\n            }\n            return mGshApi;\n        } else if (IHistoryService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"History service API binding\");\n            }\n            return mHistoryApi;\n        } else if (IMultimediaSessionService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Multimedia session API binding\");\n            }\n            return mMmSessionApi;\n        } else if (IFileUploadService.class.getName().equals(intent.getAction())) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"File upload service API binding\");\n            }\n            return mUploadApi;\n        } else {\n            return null;\n        }\n    }\n\n    /*---------------------------- CORE EVENTS ---------------------------*/\n\n    /**\n     * Notify registration to API\n     */\n    private void notifyRegistrationToApi() {\n        if (mCapabilityApi != null) {\n            mCapabilityApi.notifyRegistration();\n        }\n        if (mChatApi != null) {\n            mChatApi.notifyRegistration();\n        }\n        if (mContactApi != null) {\n            mContactApi.notifyRegistration();\n        }\n        if (mFtApi != null) {\n            mFtApi.notifyRegistration();\n        }\n        if (mVshApi != null) {\n            mVshApi.notifyRegistration();\n        }\n        if (mIshApi != null) {\n            mIshApi.notifyRegistration();\n        }\n        if (mGshApi != null) {\n            mGshApi.notifyRegistration();\n        }\n        if (mMmSessionApi != null) {\n            mMmSessionApi.notifyRegistration();\n        }\n    }\n\n    /**\n     * Notify unregistration to API\n     * \n     * @param reason reason Code\n     */\n    private void notifyUnRegistrationToApi(RcsServiceRegistration.ReasonCode reason) {\n        if (mCapabilityApi != null) {\n            mCapabilityApi.notifyUnRegistration(reason);\n        }\n        if (mChatApi != null) {\n            mChatApi.notifyUnRegistration(reason);\n        }\n        if (mContactApi != null) {\n            mContactApi.notifyUnRegistration(reason);\n        }\n        if (mFtApi != null) {\n            mFtApi.notifyUnRegistration(reason);\n        }\n        if (mVshApi != null) {\n            mVshApi.notifyUnRegistration(reason);\n        }\n        if (mIshApi != null) {\n            mIshApi.notifyUnRegistration(reason);\n        }\n        if (mGshApi != null) {\n            mGshApi.notifyUnRegistration(reason);\n        }\n        if (mMmSessionApi != null) {\n            mMmSessionApi.notifyUnRegistration(reason);\n        }\n    }\n\n    @Override\n    public void onCoreLayerStarted() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event core started\");\n        }\n\n        Core core = Core.getInstance();\n        core.getImService().onCoreLayerStarted();\n        core.getRichcallService().onCoreLayerStarted();\n\n        IntentUtils.sendBroadcastEvent(mCtx, RcsService.ACTION_SERVICE_UP);\n    }\n\n    @Override\n    public void onCoreLayerStopped() {\n        boolean logActivated = sLogger.isActivated();\n        // Display a notification\n        if (logActivated) {\n            sLogger.debug(\"Handle event core terminated\");\n        }\n        if (!mRestartCoreRequested) {\n            return;\n        }\n        if (logActivated) {\n            sLogger.debug(\"Start the core after previous instance is stopped\");\n        }\n\n        // @FIXME: This is not the final implementation, this is certainly an improvement over the\n        // previous implementation as for now start core will run on worker thread instead of\n        // main thread. However there is a need to properly refactor the whole start & stop core\n        // functionality to properly handle simultaneous start/stop request's.\n        mBackgroundHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    startCore();\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Unable to start IMS core!\", e);\n                }\n\n            }\n        });\n    }\n\n    @Override\n    public void onRegistrationSuccessful() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event registration ok\");\n        }\n        notifyRegistrationToApi();\n    }\n\n    @Override\n    public void onRegistrationFailed(ImsError error) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event registration failed\");\n        }\n        notifyUnRegistrationToApi(RcsServiceRegistration.ReasonCode.CONNECTION_LOST);\n    }\n\n    @Override\n    public void onRegistrationTerminated(RcsServiceRegistration.ReasonCode reason) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event registration terminated: \".concat(reason.name()));\n        }\n        notifyUnRegistrationToApi(reason);\n    }\n\n    @Override\n    public void onUserConfirmationRequest(ContactId remote, String id, String type, boolean pin,\n            String subject, String text, String acceptButtonLabel, String rejectButtonLabel,\n            long timeout) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event user terms confirmation request\");\n        }\n        // Nothing to do here\n    }\n\n    @Override\n    public void onUserConfirmationAck(ContactId remote, String id, String status, String subject,\n            String text) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event user terms confirmation ack\");\n        }\n        // Nothing to do here\n    }\n\n    @Override\n    public void onUserNotification(ContactId remote, String id, String subject, String text,\n            String okButtonLabel) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle event user terms notification\");\n        }\n        // Nothing to do here\n    }\n\n    @Override\n    public void onSimChangeDetected() {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Handle SIM has changed\");\n        }\n        // Restart the RCS service\n        LauncherUtils.stopRcsService(mCtx);\n        LauncherUtils.launchRcsService(mCtx, true, false, mRcsSettings);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/RcsServiceControlReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.provisioning.TermsAndConditionsRequest;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Intents;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.history.HistoryService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.os.Bundle;\nimport android.text.TextUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * A class to control the service activation.\n *\n * @author yplo6403\n */\npublic class RcsServiceControlReceiver extends BroadcastReceiver {\n\n    private static final long INTENT_RESPONSE_TIMEOUT = 1000;\n\n    private static final int INVALID_EXTRA = -1;\n\n    private static final Logger sLogger = Logger.getLogger(RcsServiceControlReceiver.class\n            .getName());\n\n    private RcsSettings mRcsSettings;\n\n    private static boolean sAccurateLog = false;\n\n    private interface IRcsCompatibility {\n        boolean isCompatible(String serviceName, String codename, int version, int increment);\n    }\n\n    private static IRcsCompatibility sRcsCompatibility = new IRcsCompatibility() {\n        @Override\n        public boolean isCompatible(String serviceName, String codename, int version, int increment) {\n            if (!RcsService.Build.API_CODENAME.equals(codename)) {\n                return false;\n            }\n            switch (version) {\n                case RcsService.Build.VERSION_CODES.BLACKBIRD:\n                case RcsService.Build.VERSION_CODES.CPR:\n                    return true;\n                default:\n                    return false;\n            }\n        }\n    };\n\n    private static final Map<String, IRcsCompatibility> sServiceCompatibilityMap = new HashMap<>();\n    static {\n        sServiceCompatibilityMap.put(CapabilityService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(ContactService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(ChatService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(FileTransferService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(FileUploadService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(GeolocSharingService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(HistoryService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(ImageSharingService.class.getSimpleName(), sRcsCompatibility);\n        sServiceCompatibilityMap.put(MultimediaSessionService.class.getSimpleName(),\n                sRcsCompatibility);\n        sServiceCompatibilityMap.put(VideoSharingService.class.getSimpleName(), sRcsCompatibility);\n    }\n\n    private boolean getActivationModeChangeable(Context ctx) {\n        switch (mRcsSettings.getEnableRcseSwitch()) {\n            case ALWAYS_SHOW:\n                return true;\n            case ONLY_SHOW_IN_ROAMING:\n                return isDataRoamingEnabled(ctx);\n            case NEVER_SHOW:\n            default:\n                return false;\n        }\n    }\n\n    private boolean getActivationMode() {\n        return mRcsSettings.isServiceActivated();\n    }\n\n    private boolean isDataRoamingEnabled(Context ctx) {\n        ConnectivityManager cm = (ConnectivityManager) ctx\n                .getSystemService(Context.CONNECTIVITY_SERVICE);\n        return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isRoaming();\n    }\n\n    private boolean setActivationMode(Context ctx, boolean active) {\n        boolean wasActivated = mRcsSettings.isServiceActivated();\n        if (wasActivated == active) {\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"setActivationMode: Already set to \" + active);\n            }\n            return active;\n        }\n        if (!getActivationModeChangeable(ctx)) {\n            sLogger.warn(\"setActivationMode: Cannot change activation mode - permission denied!\");\n            return wasActivated;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"setActivationMode: \" + active);\n        }\n        mRcsSettings.setServiceActivationState(active);\n        if (active) {\n            if (TermsAndConditionsResponse.DECLINED == mRcsSettings.getTermsAndConditionsResponse()) {\n                /*\n                 * Since user activates the stack he does not decline RCS service anymore.\n                 */\n                mRcsSettings.setTermsAndConditionsResponse(TermsAndConditionsResponse.NO_ANSWER);\n            }\n            LauncherUtils.launchRcsService(ctx, false, true, mRcsSettings);\n        } else {\n            TermsAndConditionsRequest.cancelTermsAndConditionsNotification(ctx);\n            LauncherUtils.stopRcsService(ctx);\n        }\n        return active;\n    }\n\n    private boolean isCompatible(String serviceName, String codename, int version, int increment) {\n        if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(codename)\n                || version == INVALID_EXTRA || increment == INVALID_EXTRA) {\n            return false;\n        }\n\n        IRcsCompatibility iRcsCompatibility = sServiceCompatibilityMap.get(serviceName);\n        return iRcsCompatibility != null\n                && iRcsCompatibility.isCompatible(serviceName, codename, version, increment);\n    }\n\n    private class IntentProcessor extends Thread {\n\n        public volatile boolean mHaveResult = false;\n\n        private final Context mCtx;\n        private final Intent mIntent;\n        private final Bundle mResult;\n\n        private IntentProcessor(Context ctx, Intent intent, Bundle result) {\n            mCtx = ctx;\n            mIntent = intent;\n            mResult = result;\n        }\n\n        @Override\n        public void run() {\n            String action = mIntent.getAction();\n            synchronized (mResult) {\n                switch (action) {\n                    case Intents.Service.ACTION_GET_ACTIVATION_MODE:\n                        boolean activationMode = getActivationMode();\n                        mResult.putBoolean(Intents.Service.EXTRA_GET_ACTIVATION_MODE,\n                                activationMode);\n                        if (sAccurateLog && sLogger.isActivated()) {\n                            sLogger.debug(\"isActivated() -> \" + activationMode);\n                        }\n                        break;\n\n                    case Intents.Service.ACTION_GET_COMPATIBILITY:\n                        String serviceName = mIntent\n                                .getStringExtra(Intents.Service.EXTRA_GET_COMPATIBILITY_SERVICE);\n                        String codename = mIntent\n                                .getStringExtra(Intents.Service.EXTRA_GET_COMPATIBILITY_CODENAME);\n                        int version = mIntent.getIntExtra(\n                                Intents.Service.EXTRA_GET_COMPATIBILITY_VERSION, INVALID_EXTRA);\n                        int increment = mIntent.getIntExtra(\n                                Intents.Service.EXTRA_GET_COMPATIBILITY_INCREMENT, INVALID_EXTRA);\n                        boolean compatible = isCompatible(serviceName, codename, version, increment);\n                        mResult.putBoolean(Intents.Service.EXTRA_GET_COMPATIBILITY_RESPONSE,\n                                compatible);\n                        if (sAccurateLog && sLogger.isActivated()) {\n                            sLogger.debug(\"isCompatible(\" + serviceName + \") -> \" + compatible);\n                        }\n                        break;\n\n                    case Intents.Service.ACTION_GET_SERVICE_STARTING_STATE:\n                        Core core = Core.getInstance();\n                        boolean started = core != null && core.isStarted();\n                        mResult.putBoolean(Intents.Service.EXTRA_GET_SERVICE_STARTING_STATE,\n                                started);\n                        if (sAccurateLog && sLogger.isActivated()) {\n                            sLogger.debug(\"isServiceStarted() -> \" + started);\n                        }\n                        break;\n\n                    case Intents.Service.ACTION_GET_ACTIVATION_MODE_CHANGEABLE:\n                        boolean activationModeChangeable = getActivationModeChangeable(mCtx);\n                        mResult.putBoolean(Intents.Service.EXTRA_GET_ACTIVATION_MODE_CHANGEABLE,\n                                activationModeChangeable);\n                        if (sAccurateLog && sLogger.isActivated()) {\n                            sLogger.debug(\"isActivationModeChangeAble() -> \"\n                                    + activationModeChangeable);\n                        }\n                        break;\n\n                    case Intents.Service.ACTION_SET_ACTIVATION_MODE: {\n                        boolean active = mIntent.getBooleanExtra(\n                                Intents.Service.EXTRA_SET_ACTIVATION_MODE, true);\n                        activationMode = setActivationMode(mCtx, active);\n                        mResult.putBoolean(Intents.Service.EXTRA_SET_ACTIVATION_MODE,\n                                activationMode);\n                        if (sAccurateLog && sLogger.isActivated()) {\n                            sLogger.debug(\"setActivationMode(\" + active + \") -> \" + activationMode);\n                        }\n                        break;\n                    }\n                }\n                mHaveResult = true;\n                mResult.notify();\n            }\n        }\n\n    }\n\n    @SuppressWarnings(\"SynchronizationOnLocalVariableOrMethodParameter\")\n    @Override\n    public void onReceive(Context ctx, Intent intent) {\n        final String action = intent.getAction();\n        if (sAccurateLog && sLogger.isActivated()) {\n            sLogger.debug(\"Received: \" + action);\n        }\n        LocalContentResolver localContentResolver = new LocalContentResolver(ctx);\n        mRcsSettings = RcsSettings.getInstance(localContentResolver);\n\n        Bundle result = getResultExtras(true);\n        IntentProcessor intentProcessor = new IntentProcessor(ctx, intent, result);\n        intentProcessor.start();\n        long endTime = System.currentTimeMillis() + INTENT_RESPONSE_TIMEOUT;\n        synchronized (result) {\n            while (!intentProcessor.mHaveResult) {\n                long delay = endTime - System.currentTimeMillis();\n                if (delay <= 0) {\n                    sLogger.warn(\"Waiting for result for \" + action + \" has reached deadline!\");\n                    break;\n                }\n                try {\n                    if (sAccurateLog) {\n                        sLogger.debug(\"Waiting for result for \" + action + \" during max \" + delay\n                                + \"ms\");\n                    }\n                    result.wait(delay);\n\n                } catch (InterruptedException e) {\n                    sLogger.warn(\"Waiting for result for \" + action + \" was interrupted!\");\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/StartService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.addressbook.AccountChangedReceiver;\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.addressbook.RcsAccountManager;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.platform.registry.AndroidRegistryFactory;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.UserProfilePersistedStorageUtil;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ConfigurationMode;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.TermsAndConditionsResponse;\nimport com.gsma.rcs.provisioning.ProvisioningInfo.Version;\nimport com.gsma.rcs.provisioning.https.HttpsProvisioningService;\nimport com.gsma.rcs.service.permissions.PermissionsManager;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.TimerUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService;\n\nimport android.accounts.Account;\nimport android.app.Activity;\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.content.res.Configuration;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\n\nimport java.io.IOException;\n\n/**\n * RCS start service.\n *\n * @author hlxn7157\n */\npublic class StartService extends Service {\n\n    /**\n     * RCS new user account\n     */\n    public static final String REGISTRY_NEW_USER_ACCOUNT = \"NewUserAccount\";\n\n    private static final String STARTSERVICE_OPERATIONS_THREAD_NAME = \"StartServiceOps\";\n\n    private LocalContentResolver mLocalContentResolver;\n\n    private ConnectivityManager mConnMgr;\n\n    private BroadcastReceiver mNetworkStateListener;\n\n    private String mLastUserAccount;\n\n    private String mCurrentUserAccount;\n\n    /**\n     * Launch boot flag\n     */\n    private boolean mBoot = false;\n\n    /**\n     * Launch user flag\n     */\n    private boolean mUser = false;\n\n    private RcsSettings mRcsSettings;\n\n    private MessagingLog mMessagingLog;\n\n    private RcsAccountManager mAccountUtility;\n\n    private ContactManager mContactManager;\n\n    private PendingIntent mPoolTelephonyManagerIntent;\n\n    private static final Logger sLogger = Logger.getLogger(StartService.class.getSimpleName());\n\n    private static final String INTENT_KEY_BOOT = \"boot\";\n    private static final String INTENT_KEY_USER = \"user\";\n\n    private static final String ACTION_POOL_TELEPHONY_MANAGER = \"com.gsma.rcs.service.ACTION_POOL_TELEPHONY_MANAGER\";\n\n    private static final long TELEPHONY_MANAGER_POOLING_PERIOD = 1000;\n\n    private BroadcastReceiver mPollingTelephonyManagerReceiver;\n\n    private String mRcsAccountUsername;\n\n    /**\n     * Handler to process messages & runnable associated with background thread.\n     */\n    private Handler mStartServiceHandler;\n\n    private Context mCtx;\n\n    private static final int MNC_UNDEFINED = 0;\n    private static final int MCC_UNDEFINED = 0;\n\n    @Override\n    public void onCreate() {\n        mCtx = getApplicationContext();\n        ContentResolver contentResolver = mCtx.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(mCtx);\n        mRcsSettings = RcsSettings.getInstance(mLocalContentResolver);\n        mMessagingLog = MessagingLog.getInstance(mLocalContentResolver, mRcsSettings);\n\n        mContactManager = ContactManager.getInstance(mCtx, contentResolver, mLocalContentResolver,\n                mRcsSettings);\n        mAccountUtility = RcsAccountManager.getInstance(mCtx, mContactManager);\n\n        mRcsAccountUsername = getString(R.string.rcs_core_account_username);\n\n        mPoolTelephonyManagerIntent = PendingIntent.getBroadcast(mCtx, 0, new Intent(\n                ACTION_POOL_TELEPHONY_MANAGER), 0);\n    }\n\n    private Handler allocateBgHandler(String threadName) {\n        HandlerThread thread = new HandlerThread(threadName);\n        thread.start();\n        return new Handler(thread.getLooper());\n    }\n\n    @Override\n    public void onDestroy() {\n        if (mPollingTelephonyManagerReceiver != null) {\n            unregisterReceiver(mPollingTelephonyManagerReceiver);\n            mPollingTelephonyManagerReceiver = null;\n        }\n        if (mNetworkStateListener != null) {\n            unregisterReceiver(mNetworkStateListener);\n            mNetworkStateListener = null;\n        }\n        if (mStartServiceHandler != null) {\n            mStartServiceHandler.getLooper().quit();\n            mStartServiceHandler = null;\n        }\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public int onStartCommand(final Intent intent, final int flags, final int startId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start RCS service\");\n        }\n        mStartServiceHandler = allocateBgHandler(STARTSERVICE_OPERATIONS_THREAD_NAME);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n\n            mStartServiceHandler.post(new Runnable() {\n\n                @Override\n                public void run() {\n                    PermissionsManager pm = PermissionsManager.getInstance();\n                    Boolean allPermissionsGranted = pm.requestForPermissionsAndWaitResponse(mCtx);\n                    if (allPermissionsGranted) {\n                        startCore(intent);\n                    } else {\n                        StartService.this.stopSelf();\n                    }\n                }\n            });\n        } else {\n            startCore(intent);\n        }\n\n        /*\n         * We want this service to continue running until it is explicitly stopped, so return\n         * sticky.\n         */\n        return START_STICKY;\n    }\n\n    private void startCore(final Intent intent) {\n        ConfigurationMode mode = mRcsSettings.getConfigurationMode();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"onCreate ConfigurationMode=\".concat(mode.toString()));\n        }\n        /*\n         * In manual configuration, use a network listener to start RCS core when the data will be\n         * ON\n         */\n        if (ConfigurationMode.MANUAL == mode) {\n            registerNetworkStateListener();\n        }\n        mStartServiceHandler.post(new Runnable() {\n            @Override\n            public void run() {\n                /* Check boot */\n                if (intent != null) {\n                    mBoot = intent.getBooleanExtra(INTENT_KEY_BOOT, false);\n                    mUser = intent.getBooleanExtra(INTENT_KEY_USER, false);\n                }\n                try {\n                    /*\n                     * Services can be started only if MCC is available because then the ContactUtil\n                     * can be used by client applications. If available once, the MCC is accessible\n                     * through the Android Configuration even if the SIM card is not inserted. The\n                     * Service can be started only if MNC is defined because it is used for the\n                     * initial provisioning. The MNC is not available if the SIM card is not\n                     * inserted : this is why it is persisted to be defined after first\n                     * provisioning.\n                     */\n                    boolean accountAvailable = checkAccount();\n                    Configuration config = mCtx.getResources().getConfiguration();\n                    boolean mccAvailable = MCC_UNDEFINED != config.mcc;\n\n                    boolean mncDefined = isMobileNetworkCodeDefined();\n                    if (!mncDefined) {\n                        mncDefined = trySetMyNetworkMobileCode(config.mnc);\n                    }\n                    if (mccAvailable && mncDefined && accountAvailable) {\n                        mRcsSettings.setMobileCountryCode(config.mcc);\n                        launchRcsService(mBoot, mUser);\n                    } else {\n                        /*\n                         * Services cannot be started: IMSI cannot be read from Telephony Manager or\n                         * MCC from Android Configuration or MNC from the settings provider.\n                         */\n                        if (sLogger.isActivated()) {\n                            sLogger.warn(\"Can't create current user account: pool the telephony manager\");\n                        }\n                        mPollingTelephonyManagerReceiver = getPollingTelephonyManagerReceiver();\n                        registerReceiver(mPollingTelephonyManagerReceiver, new IntentFilter(\n                                ACTION_POOL_TELEPHONY_MANAGER));\n                        retryPollingTelephonyManagerPooling(config.mcc,\n                                mRcsSettings.getMobileNetworkCode());\n                    }\n\n                } catch (IOException e) {\n                    logIOException(intent.getAction(), e);\n\n                } catch (RcsAccountException | RuntimeException e) {\n                    /**\n                     * This is a non revocable use-case as the RCS account itself was not created,\n                     * So we log this as error and stop the service itself.\n                     */\n                    sLogger.error(\"Failed to start the service for intent: \" + intent, e);\n                    stopSelf();\n                }\n            }\n        });\n    }\n\n    /**\n     * Register a broadcast receiver for network state changes\n     */\n    private void registerNetworkStateListener() {\n        // Get connectivity manager\n        if (mConnMgr == null) {\n            mConnMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);\n        }\n\n        // Instantiate the network listener\n        mNetworkStateListener = new BroadcastReceiver() {\n            @Override\n            public void onReceive(Context context, final Intent intent) {\n                if (intent == null) {\n                    return;\n                }\n                final String action = intent.getAction();\n                if (action == null) {\n                    return;\n                }\n                mStartServiceHandler.post(new Runnable() {\n                    @Override\n                    public void run() {\n                        try {\n                            connectionEvent(action);\n\n                        } catch (RuntimeException e) {\n                            /*\n                             * Normally we are not allowed to catch runtime exceptions as these are\n                             * genuine bugs which should be handled/fixed within the code. However\n                             * the cases when we are executing operations on a thread unhandling\n                             * such exceptions will eventually lead to exit the system and thus can\n                             * bring the whole system down, which is not intended.\n                             */\n                            sLogger.error(\"Unable to handle connection event for intent action : \"\n                                    + intent.getAction(), e);\n                        }\n                    }\n                });\n            }\n        };\n        // Register network state listener\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);\n        registerReceiver(mNetworkStateListener, intentFilter);\n    }\n\n    /**\n     * Connection event\n     *\n     * @param action Connectivity action\n     */\n    private void connectionEvent(String action) {\n        // Try to start the service only if a data connectivity is available\n        if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {\n            return;\n        }\n        NetworkInfo networkInfo = mConnMgr.getActiveNetworkInfo();\n        if (networkInfo == null) {\n            return;\n        }\n        if (!networkInfo.isConnected()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Device disconnected\");\n            }\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Device connected - Launch RCS service\");\n        }\n\n        // Start the RCS core service\n        LauncherUtils.launchRcsCoreService(mCtx, mRcsSettings);\n\n        // Stop Network listener\n        if (mNetworkStateListener == null) {\n            return;\n        }\n        unregisterReceiver(mNetworkStateListener);\n        mNetworkStateListener = null;\n    }\n\n    /**\n     * Check account\n     *\n     * @return true if an account is available\n     * @throws IOException\n     * @throws RcsAccountException\n     */\n    private boolean checkAccount() throws IOException, RcsAccountException {\n        AndroidFactory.setApplicationContext(mCtx, mRcsSettings);\n\n        /* Read the current and last end user accounts */\n        mCurrentUserAccount = LauncherUtils.getCurrentUserAccount(mCtx);\n        mLastUserAccount = LauncherUtils.getLastUserAccount(mCtx);\n\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            /* Use StringBuilder instead of concat since argument may be null */\n            sLogger.info(\"Last user account is \" + mLastUserAccount);\n            sLogger.info(\"Current user account is \" + mCurrentUserAccount);\n        }\n\n        /* Check the current SIM */\n        if (mCurrentUserAccount == null) {\n            if (isFirstLaunch()) {\n                /*\n                 * If it's a first launch the IMSI is required to initialize the service the first\n                 * time.\n                 */\n                return false;\n            }\n            /* If it is not the first launch then set the user account ID from the last used IMSI */\n            mCurrentUserAccount = mLastUserAccount;\n        }\n\n        // On the first launch and if SIM card has changed\n        if (isFirstLaunch()) {\n            /* Set new user flag */\n            setNewUserAccount(true);\n        } else if (hasChangedAccount()) {\n            /* keep a maximum of saved accounts */\n            UserProfilePersistedStorageUtil.normalizeFileBackup(mCurrentUserAccount);\n            /* Backup last account settings */\n            if (mLastUserAccount != null) {\n                if (logActivated) {\n                    sLogger.info(\"Backup \".concat(mLastUserAccount));\n                }\n                UserProfilePersistedStorageUtil.tryToBackupAccount(mLastUserAccount);\n            }\n\n            /* Reset RCS account */\n            LauncherUtils.resetRcsConfig(mCtx, mLocalContentResolver, mRcsSettings, mMessagingLog,\n                    mContactManager);\n\n            Configuration config = mCtx.getResources().getConfiguration();\n            mRcsSettings.setMobileNetworkCode(config.mnc);\n            mRcsSettings.setMobileCountryCode(config.mcc);\n\n            /* Restore current account settings */\n            if (logActivated) {\n                sLogger.info(\"Restore \".concat(mCurrentUserAccount));\n            }\n            UserProfilePersistedStorageUtil.tryToRestoreAccount(mCurrentUserAccount);\n            /*\n             * Send service provisioned intent as the configuration settings are now loaded by means\n             * of restoring previous values that were backed up during SIM Swap.\n             */\n            IntentUtils.sendBroadcastEvent(mCtx,\n                    RcsService.ACTION_SERVICE_PROVISIONING_DATA_CHANGED);\n\n            /* Activate service if new account */\n            mRcsSettings.setServiceActivationState(true);\n\n            /* Set new user flag */\n            setNewUserAccount(true);\n        } else {\n            /* Set new user flag */\n            setNewUserAccount(false);\n        }\n\n        /* Check if the RCS account exists */\n        Account account = mAccountUtility.getAccount(mRcsAccountUsername);\n        if (account == null) {\n            /* No account exists */\n            if (logActivated) {\n                sLogger.debug(\"The RCS account does not exist\");\n            }\n            if (AccountChangedReceiver.isAccountResetByEndUser()) {\n                /* It was manually destroyed by the user */\n                if (logActivated) {\n                    sLogger.debug(\"It was manually destroyed by the user, we do not recreate it\");\n                }\n                return false;\n            }\n        } else if (hasChangedAccount()) {\n            /*\n             * Account has changed (i.e. new SIM card): delete the current account and create a new\n             * one.\n             */\n            if (logActivated) {\n                sLogger.debug(\"Deleting the old RCS account for \" + mLastUserAccount);\n            }\n            mContactManager.deleteRCSEntries();\n            mAccountUtility.removeRcsAccount(null);\n        }\n\n        /* Save the current end user account */\n        LauncherUtils.setLastUserAccount(mCtx, mCurrentUserAccount);\n        return true;\n    }\n\n    /**\n     * Launch the RCS service.\n     *\n     * @param boot indicates if RCS is launched from the device boot\n     * @param user indicates if RCS is launched from the user interface\n     * @throws RcsAccountException\n     */\n    private void launchRcsService(boolean boot, boolean user) throws RcsAccountException {\n        ConfigurationMode mode = mRcsSettings.getConfigurationMode();\n        boolean logActivated = sLogger.isActivated();\n        if (logActivated) {\n            sLogger.debug(\"Launch RCS service: HTTPS=\" + mode + \", boot=\" + boot + \", user=\" + user);\n        }\n        if (ConfigurationMode.AUTO != mode) {\n            mAccountUtility.createRcsAccount(mRcsAccountUsername, true);\n            /* Manual provisioning: accept terms and conditions */\n            mRcsSettings.setTermsAndConditionsResponse(TermsAndConditionsResponse.ACCEPTED);\n            /* No auto configuration: directly start the RCS core service */\n            LauncherUtils.launchRcsCoreService(mCtx, mRcsSettings);\n            return;\n        }\n\n        /* HTTPS auto configuration */\n        int version = mRcsSettings.getProvisioningVersion();\n        // Check the last provisioning version\n        if (Version.RESETED_NOQUERY.toInt() == version) {\n            // (-1) : RCS service is permanently disabled. SIM change is required\n            if (hasChangedAccount()) {\n                // Start provisioning as a first launch\n                HttpsProvisioningService.startHttpsProvisioningService(mCtx, true, user);\n            } else {\n                if (logActivated) {\n                    sLogger.debug(\"Provisioning is blocked with this account\");\n                }\n            }\n\n        } else if (isFirstLaunch() || hasChangedAccount()) {\n            // First launch: start the auto config service with special tag\n            HttpsProvisioningService.startHttpsProvisioningService(mCtx, true, user);\n\n        } else if (Version.DISABLED_NOQUERY.toInt() == version) {\n            // -2 : RCS client and configuration query is disabled\n            if (user) {\n                // Only start query if requested by user action\n                HttpsProvisioningService.startHttpsProvisioningService(mCtx, false, user);\n            }\n\n        } else {\n            // Start or restart the HTTP provisioning service\n            HttpsProvisioningService.startHttpsProvisioningService(mCtx, false, user);\n            if (Version.DISABLED_DORMANT.toInt() == version) {\n                // -3 : RCS client is disabled but configuration query is not\n            } else {\n                // Start the RCS core service\n                LauncherUtils.launchRcsCoreService(mCtx, mRcsSettings);\n            }\n        }\n    }\n\n    /**\n     * Is the first RCs is launched ?\n     *\n     * @return true if it's the first time RCS is launched\n     */\n    private boolean isFirstLaunch() {\n        return mLastUserAccount == null;\n    }\n\n    /**\n     * Check if RCS account has changed since the last time we started the service\n     *\n     * @return true if the active account was changed\n     */\n    private boolean hasChangedAccount() {\n        return mLastUserAccount == null || mCurrentUserAccount != null\n                && (!mCurrentUserAccount.equalsIgnoreCase(mLastUserAccount));\n    }\n\n    /**\n     * Set true if new user account\n     *\n     * @param value true if new user account\n     */\n    private void setNewUserAccount(boolean value) {\n        SharedPreferences preferences = getSharedPreferences(AndroidRegistryFactory.RCS_PREFS_NAME,\n                Activity.MODE_PRIVATE);\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putBoolean(REGISTRY_NEW_USER_ACCOUNT, value);\n        editor.commit();\n    }\n\n    /**\n     * Check if new user account\n     *\n     * @param context Application context\n     * @return true if new user account\n     */\n    public static boolean getNewUserAccount(Context context) {\n        SharedPreferences preferences = context.getSharedPreferences(\n                AndroidRegistryFactory.RCS_PREFS_NAME, Activity.MODE_PRIVATE);\n        return preferences.getBoolean(REGISTRY_NEW_USER_ACCOUNT, false);\n    }\n\n    /**\n     * Launch the RCS start service\n     *\n     * @param context the context\n     * @param boot start RCS service upon boot\n     * @param user start RCS service upon user action\n     */\n    static void LaunchRcsStartService(Context context, boolean boot, boolean user) {\n        if (sLogger.isActivated())\n            sLogger.debug(\"Launch RCS service (boot=\" + boot + \") (user=\" + user + \")\");\n        Intent intent = new Intent(context, StartService.class);\n        intent.putExtra(INTENT_KEY_BOOT, boot);\n        intent.putExtra(INTENT_KEY_USER, user);\n        context.startService(intent);\n    }\n\n    private void retryPollingTelephonyManagerPooling(int mcc, int mnc) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Retry polling telephony manager (mcc=\" + mcc + \",mnc=\" + mnc + \")\");\n        }\n        AlarmManager am = (AlarmManager) mCtx.getSystemService(Context.ALARM_SERVICE);\n        TimerUtils.setExactTimer(am, System.currentTimeMillis() + TELEPHONY_MANAGER_POOLING_PERIOD,\n                mPoolTelephonyManagerIntent);\n    }\n\n    private BroadcastReceiver getPollingTelephonyManagerReceiver() {\n        return new BroadcastReceiver() {\n            @Override\n            public void onReceive(final Context context, final Intent intent) {\n                mStartServiceHandler.post(new Runnable() {\n                    @Override\n                    public void run() {\n                        try {\n                            boolean rcsAccountAvailable = checkAccount();\n                            Configuration config = context.getResources().getConfiguration();\n                            boolean mccAvailable = MCC_UNDEFINED != config.mcc;\n\n                            boolean mncDefined = isMobileNetworkCodeDefined();\n                            if (!mncDefined) {\n                                mncDefined = trySetMyNetworkMobileCode(config.mnc);\n                            }\n                            if (mccAvailable && mncDefined && rcsAccountAvailable) {\n                                /*\n                                 * Finally we succeed to read the IMSI from SIM card, the MCC from\n                                 * the Android configuration and the MNC from the settings provider.\n                                 */\n                                mRcsSettings.setMobileCountryCode(config.mcc);\n\n                                if (mPollingTelephonyManagerReceiver != null) {\n                                    unregisterReceiver(mPollingTelephonyManagerReceiver);\n                                    mPollingTelephonyManagerReceiver = null;\n                                }\n                                launchRcsService(mBoot, mUser);\n                            } else {\n                                /*\n                                 * User account can't be initialized: IMSI or MCC cannot be read\n                                 * from SIM card or MNC cannot be read from settings provider. Retry\n                                 * pooling the telephony manager.\n                                 */\n                                retryPollingTelephonyManagerPooling(config.mcc,\n                                        mRcsSettings.getMobileNetworkCode());\n                            }\n\n                        } catch (IOException e) {\n                            logIOException(intent.getAction(), e);\n\n                        } catch (RcsAccountException e) {\n                            /**\n                             * This is a non revocable use-case as the RCS account itself was not\n                             * created, So we log this as error and stop the service itself.\n                             */\n                            sLogger.error(\"Failed to start the service for intent action : \"\n                                    .concat(intent.getAction()), e);\n                            stopSelf();\n\n                        } catch (RuntimeException e) {\n                            /*\n                             * Normally we are not allowed to catch runtime exceptions as these are\n                             * genuine bugs which should be handled/fixed within the code. However\n                             * the cases when we are executing operations on a thread unhandling\n                             * such exceptions will eventually lead to exit the system and thus can\n                             * bring the whole system down, which is not intended.\n                             */\n                            sLogger.error(\"Unable to handle connection event for intent action : \"\n                                    .concat(intent.getAction()), e);\n                            stopSelf();\n                        }\n                    }\n\n                });\n            }\n        };\n    }\n\n    private boolean trySetMyNetworkMobileCode(int mnc) {\n        if (mnc == MNC_UNDEFINED) {\n            return false;\n        }\n        mRcsSettings.setMobileNetworkCode(mnc);\n        return true;\n    }\n\n    private boolean isMobileNetworkCodeDefined() {\n        int mnc = mRcsSettings.getMobileNetworkCode();\n        return mnc != MNC_UNDEFINED;\n    }\n\n    private void logIOException(String action, IOException e) {\n        if (action == null) {\n            sLogger.debug(\"Failed to start the service, Message=\" + e.getMessage());\n        } else {\n            sLogger.warn(\"Failed to start the service for action: \" + action + \", Message=\"\n                    + e.getMessage());\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/CapabilityServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.service.capability.CapabilityService;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.broadcaster.CapabilitiesBroadcaster;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.capability.ICapabilitiesListener;\nimport com.gsma.services.rcs.capability.ICapabilityService;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteException;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Capability service API implementation\n * \n * @author Jean-Marc AUFFRET\n * @author YPLO6403\n */\npublic class CapabilityServiceImpl extends ICapabilityService.Stub {\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final CapabilitiesBroadcaster mCapabilitiesBroadcaster = new CapabilitiesBroadcaster();\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(CapabilityServiceImpl.class.getName());\n\n    private final ContactManager mContactManager;\n\n    private final CapabilityService mCapabilityService;\n\n    private class CapabilitiesRequester implements Runnable {\n\n        private final ContactId mContact;\n\n        public CapabilitiesRequester(ContactId contact) {\n            mContact = contact;\n        }\n\n        public void run() {\n            try {\n                mCapabilityService.requestContactCapabilities(mContact);\n\n            } catch (RuntimeException e) {\n                /*\n                 * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n                 * which should be handled/fixed within the code. However the cases when we are\n                 * executing operations on a thread unhandling such exceptions will eventually lead\n                 * to exit the system and thus can bring the whole system down, which is not\n                 * intended.\n                 */\n                sLogger.error(\"Failed to handle capabilities request for contact: \" + mContact, e);\n            }\n        }\n    }\n\n    private class AllCapabilitiesRequester implements Runnable {\n\n        public void run() {\n            try {\n                mCapabilityService.requestContactCapabilities(mContactManager\n                        .getAllContactsFromRcsContactProvider());\n            } catch (RuntimeException e) {\n                /*\n                 * Normally we are not allowed to catch runtime exceptions as these are genuine bugs\n                 * which should be handled/fixed within the code. However the cases when we are\n                 * executing operations on a thread unhandling such exceptions will eventually lead\n                 * to exit the system and thus can bring the whole system down, which is not\n                 * intended.\n                 */\n                sLogger.error(\"Failed to handle capabilities request for contacts!\", e);\n            }\n        }\n    }\n\n    /**\n     * Constructor\n     * \n     * @param contactManager Contacts manager\n     * @param rcsSettings RCS settings accessor\n     * @param capabilityService Capacility service\n     */\n    public CapabilityServiceImpl(CapabilityService capabilityService,\n            ContactManager contactManager, RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Capability service API is loaded\");\n        }\n        mCapabilityService = capabilityService;\n        mCapabilityService.register(this);\n        mContactManager = contactManager;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Capability service API is closed\");\n        }\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return Returns true if registered else returns false\n     */\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Return the reason code for IMS service registration\n     * \n     * @return the reason code for IMS service registration\n     */\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        // Notify listeners\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     * \n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        // Notify listeners\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Returns the capabilities supported by the local end user. The supported capabilities are\n     * fixed by the MNO and read during the provisioning.\n     * \n     * @return Capabilities\n     * @throws RemoteException\n     */\n    public Capabilities getMyCapabilities() throws RemoteException {\n        try {\n            return ContactServiceImpl.getCapabilities(mRcsSettings.getMyCapabilities());\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the capabilities of a given contact from the local database. This method does not\n     * request any network update to the remote contact. The parameter contact supports the\n     * following formats: MSISDN in national or international format, SIP address, SIP-URI or\n     * Tel-URI. If the format of the contact is not supported an exception is thrown.\n     * \n     * @param contact ContactId\n     * @return Capabilities\n     * @throws RemoteException\n     */\n    public Capabilities getContactCapabilities(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        try {\n            com.gsma.rcs.core.ims.service.capability.Capabilities caps = mContactManager\n                    .getContactCapabilities(contact);\n            // TODO update code so not to insert default capabilities in provider\n            if (caps == null\n                    || caps.getTimestampOfLastResponse() == com.gsma.rcs.core.ims.service.capability.Capabilities.INVALID_TIMESTAMP) {\n                // no capabilities are known, returns null as per 1.5.1 specification\n                return null;\n            }\n            // Read capabilities in the local database\n            return ContactServiceImpl.getCapabilities(mContactManager\n                    .getContactCapabilities(contact));\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Requests capabilities to a remote contact. This method initiates in background a new\n     * capability request to the remote contact by sending a SIP OPTIONS. The result of the\n     * capability request is sent asynchronously via callback method of the capabilities listener. A\n     * capability refresh is only sent if the timestamp associated to the capability has expired\n     * (the expiration value is fixed via MNO provisioning). The parameter contact supports the\n     * following formats: MSISDN in national or international format, SIP address, SIP-URI or\n     * Tel-URI. If the format of the contact is not supported an exception is thrown. The result of\n     * the capability refresh request is provided to all the clients that have registered the\n     * listener for this event.\n     * \n     * @param contact ContactId\n     * @throws RemoteException\n     */\n    public void requestContactCapabilities(final ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        ServerApiUtils.testIms();\n        mCapabilityService.scheduleCapabilityOperation(new CapabilitiesRequester(contact));\n    }\n\n    /**\n     * Receive capabilities from a contact\n     * \n     * @param contact ContactId\n     * @param capabilities Capabilities\n     */\n    public void receiveCapabilities(ContactId contact,\n            com.gsma.rcs.core.ims.service.capability.Capabilities capabilities) {\n        synchronized (mLock) {\n            // Create capabilities instance\n            Capabilities c = ContactServiceImpl.getCapabilities(capabilities);\n            // Notify capabilities listeners\n            notifyListeners(contact, c);\n        }\n    }\n\n    /**\n     * Notify listeners\n     * \n     * @param contact ContactId\n     * @param capabilities Capabilities\n     */\n    private void notifyListeners(ContactId contact, Capabilities capabilities) {\n        mCapabilitiesBroadcaster.broadcastCapabilitiesReceived(contact, capabilities);\n    }\n\n    /**\n     * Requests capabilities for all contacts existing in the local address book. This method\n     * initiates in background new capability requests for each contact of the address book by\n     * sending SIP OPTIONS. The result of a capability request is sent asynchronously via callback\n     * method of the capabilities listener. A capability refresh is only sent if the timestamp\n     * associated to the capability has expired (the expiration value is fixed via MNO\n     * provisioning). The result of the capability refresh request is provided to all the clients\n     * that have registered the listener for this event.\n     * \n     * @throws RemoteException\n     */\n    public void requestAllContactsCapabilities() throws RemoteException {\n        ServerApiUtils.testIms();\n        mCapabilityService.scheduleCapabilityOperation(new AllCapabilitiesRequester());\n    }\n\n    @Override\n    public void requestContactCapabilities2(List<ContactId> contacts) throws RemoteException {\n        ServerApiUtils.testIms();\n        if (contacts == null) {\n            throw new ServerApiIllegalArgumentException(\"contacts must not be null!\");\n        }\n        final Set<ContactId> setOfContacts = new HashSet<>(contacts);\n        mCapabilityService.scheduleCapabilityOperation(new Runnable() {\n\n            @Override\n            public void run() {\n                mCapabilityService.requestContactCapabilities(setOfContacts);\n            }\n        });\n    }\n\n    /**\n     * Registers a capabilities listener on any contact\n     * \n     * @param listener Capabilities listener\n     * @throws RemoteException\n     */\n    public void addCapabilitiesListener(ICapabilitiesListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mCapabilitiesBroadcaster.addCapabilitiesListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Unregisters a capabilities listener\n     * \n     * @param listener Capabilities listener\n     * @throws RemoteException\n     */\n    public void removeCapabilitiesListener(ICapabilitiesListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mCapabilitiesBroadcaster.removeCapabilitiesListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Registers a listener for receiving capabilities of a given contact\n     * \n     * @param contact ContactId\n     * @param listener Capabilities listener\n     * @throws RemoteException\n     */\n    public void addCapabilitiesListener2(ContactId contact, ICapabilitiesListener listener)\n            throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mCapabilitiesBroadcaster.addContactCapabilitiesListener(contact, listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Unregisters a listener of capabilities for a given contact\n     * \n     * @param contact ContactId\n     * @param listener Capabilities listener\n     * @throws RemoteException\n     */\n    public void removeCapabilitiesListener2(ContactId contact, ICapabilitiesListener listener)\n            throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mCapabilitiesBroadcaster.removeContactCapabilitiesListener(contact, listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ChatMessageImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.provider.messaging.ChatMessagePersistedStorageAccessor;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteException;\n\npublic class ChatMessageImpl extends IChatMessage.Stub {\n\n    private static final Logger sLogger = Logger.getLogger(ChatMessageImpl.class.getSimpleName());\n\n    private final ChatMessagePersistedStorageAccessor mPersistentStorage;\n\n    /**\n     * Constructor\n     * \n     * @param persistentStorage ChatMessagePersistedStorageAccessor\n     */\n    public ChatMessageImpl(ChatMessagePersistedStorageAccessor persistentStorage) {\n        mPersistentStorage = persistentStorage;\n    }\n\n    public ContactId getContact() throws RemoteException {\n        try {\n            return mPersistentStorage.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public String getId() throws RemoteException {\n        try {\n            return mPersistentStorage.getId();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public String getContent() throws RemoteException {\n        try {\n            return mPersistentStorage.getContent();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public String getMimeType() throws RemoteException {\n        try {\n            return mPersistentStorage.getMimeType();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public int getDirection() throws RemoteException {\n        try {\n            return mPersistentStorage.getDirection().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public long getTimestamp() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public long getTimestampSent() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestampSent();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public long getTimestampDelivered() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestampDelivered();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public long getTimestampDisplayed() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestampDisplayed();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public int getStatus() throws RemoteException {\n        try {\n            return mPersistentStorage.getStatus().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public int getReasonCode() throws RemoteException {\n        try {\n            return mPersistentStorage.getReasonCode().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public String getChatId() throws RemoteException {\n        try {\n            return mPersistentStorage.getChatId();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public boolean isRead() throws RemoteException {\n        try {\n            return mPersistentStorage.isRead();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public boolean isExpiredDelivery() throws RemoteException {\n        try {\n            return mPersistentStorage.isExpiredDelivery();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ChatServiceConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.IChatServiceConfiguration;\n\nimport android.os.RemoteException;\n\n/**\n * A class that implements interface to allow access to chat service configuration from API\n * \n * @author yplo6403\n */\npublic class ChatServiceConfigurationImpl extends IChatServiceConfiguration.Stub {\n\n    private static final Logger sLogger = Logger.getLogger(ChatServiceConfigurationImpl.class\n            .getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings RCS settings accessor\n     */\n    public ChatServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public long getIsComposingTimeout() throws RemoteException {\n        try {\n            return mRcsSettings.getIsComposingTimeout();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getGeolocExpirationTime() throws RemoteException {\n        try {\n            return mRcsSettings.getGeolocExpirationTime();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getGeolocLabelMaxLength() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxGeolocLabelLength();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getGroupChatMaxParticipants() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxChatParticipants();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getGroupChatMessageMaxLength() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxGroupChatMessageLength();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getGroupChatMinParticipants() throws RemoteException {\n        try {\n            return mRcsSettings.getMinGroupChatParticipants();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getGroupChatSubjectMaxLength() throws RemoteException {\n        try {\n            return mRcsSettings.getGroupChatSubjectMaxLength();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getOneToOneChatMessageMaxLength() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxChatMessageLength();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isChatWarnSF() throws RemoteException {\n        try {\n            return mRcsSettings.isStoreForwardWarningActivated();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isGroupChatSupported() throws RemoteException {\n        try {\n            return mRcsSettings.isGroupChatActivated();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isRespondToDisplayReportsEnabled() throws RemoteException {\n        try {\n            return mRcsSettings.isRespondToDisplayReports();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isSmsFallback() throws RemoteException {\n        try {\n            return mRcsSettings.isSmsFallbackServiceActivated();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void setRespondToDisplayReports(boolean enable) throws RemoteException {\n        try {\n            mRcsSettings.setRespondToDisplayReports(enable);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ChatServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnManager;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.history.HistoryLog;\nimport com.gsma.rcs.provider.messaging.ChatMessagePersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.GroupChatPersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.broadcaster.GroupChatEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.OneToOneChatEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.chat.IChatService;\nimport com.gsma.services.rcs.chat.IChatServiceConfiguration;\nimport com.gsma.services.rcs.chat.IGroupChat;\nimport com.gsma.services.rcs.chat.IGroupChatListener;\nimport com.gsma.services.rcs.chat.IOneToOneChat;\nimport com.gsma.services.rcs.chat.IOneToOneChatListener;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Chat service implementation\n *\n * @author Jean-Marc AUFFRET\n */\npublic class ChatServiceImpl extends IChatService.Stub {\n\n    private final OneToOneChatEventBroadcaster mOneToOneChatEventBroadcaster = new OneToOneChatEventBroadcaster();\n\n    private final GroupChatEventBroadcaster mGroupChatEventBroadcaster = new GroupChatEventBroadcaster();\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final InstantMessagingService mImService;\n\n    private final MessagingLog mMessagingLog;\n\n    private final HistoryLog mHistoryLog;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private final Map<ContactId, OneToOneChatImpl> mOneToOneChatCache = new HashMap<>();\n\n    private final Map<String, GroupChatImpl> mGroupChatCache = new HashMap<>();\n\n    private static final Logger sLogger = Logger.getLogger(ChatServiceImpl.class.getSimpleName());\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    /**\n     * Constructor\n     *\n     * @param imService InstantMessagingService\n     * @param messagingLog MessagingLog\n     * @param historyLog HistoryLog\n     * @param rcsSettings RcsSettings\n     * @param contactManager ContactManager\n     */\n    public ChatServiceImpl(InstantMessagingService imService, MessagingLog messagingLog,\n            HistoryLog historyLog, RcsSettings rcsSettings, ContactManager contactManager) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Chat service API is loaded\");\n        }\n        mImService = imService;\n        mImService.register(this);\n        mMessagingLog = messagingLog;\n        mHistoryLog = historyLog;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n    }\n\n    private ReasonCode imdnToFailedReasonCode(ImdnDocument imdn) {\n        String notificationType = imdn.getNotificationType();\n        if (ImdnDocument.DELIVERY_NOTIFICATION.equals(notificationType)) {\n            return ReasonCode.FAILED_DELIVERY;\n\n        } else if (ImdnDocument.DISPLAY_NOTIFICATION.equals(notificationType)) {\n            return ReasonCode.FAILED_DISPLAY;\n        }\n        throw new IllegalArgumentException(\"Received invalid imdn notification type:'\"\n                + notificationType + \"'\");\n    }\n\n    /**\n     * Tries to send a displayed delivery report for a one to one chat\n     *\n     * @param msgId Message ID\n     * @param remote the remote contact\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     * @throws NetworkException\n     */\n    public void sendOne2OneDisplayedDeliveryReport(String msgId, ContactId remote, long timestamp)\n            throws NetworkException {\n        getOrCreateOneToOneChat(remote).sendDisplayedDeliveryReport(remote, msgId, timestamp);\n    }\n\n    /**\n     * Tries to send a displayed delivery report for a group chat\n     *\n     * @param msgId Message ID\n     * @param contact the remote contact\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     * @param chatId the chat ID\n     * @throws NetworkException\n     */\n    public void sendGroupChatDisplayedDeliveryReport(String msgId, ContactId contact,\n            long timestamp, String chatId) throws NetworkException {\n        final GroupChatSession session = mImService.getGroupChatSession(chatId);\n        if (session == null || !session.isMediaEstablished()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"No suitable session found to send the delivery status for \" + msgId\n                        + \" : use SIP message\");\n            }\n            mImService.getImdnManager().sendMessageDeliveryStatus(chatId, contact, msgId,\n                    ImdnDocument.DeliveryStatus.DISPLAYED, timestamp);\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Using the available session to send displayed for \" + msgId);\n        }\n        session.sendMsrpMessageDeliveryStatus(contact, msgId,\n                ImdnDocument.DeliveryStatus.DISPLAYED, timestamp);\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        // Clear list of sessions\n        mOneToOneChatCache.clear();\n        mGroupChatCache.clear();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Chat service API is closed\");\n        }\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     *\n     * @return Returns true if registered else returns false\n     */\n    @Override\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Return the reason code for IMS service registration\n     *\n     * @return the reason code for IMS service registration\n     */\n    @Override\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     *\n     * @param listener Service registration listener\n     */\n    @Override\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     *\n     * @param listener Service registration listener\n     */\n    @Override\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     *\n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Receive a new chat invitation\n     *\n     * @param session Chat session\n     */\n    public void receiveOneToOneChatInvitation(OneToOneChatSession session) {\n        ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Chat invitation from \" + contact + \" (display=\"\n                    + session.getRemoteDisplayName() + \")\");\n        }\n        OneToOneChatImpl oneToOneChat = getOrCreateOneToOneChat(contact);\n        session.addListener(oneToOneChat);\n\n        ChatMessage firstMessage = session.getFirstMessage();\n        if (firstMessage != null) {\n            mOneToOneChatEventBroadcaster.broadcastMessageReceived(firstMessage.getMimeType(),\n                    firstMessage.getMessageId());\n        }\n    }\n\n    /**\n     * Receive message delivery status\n     *\n     * @param contact Contact ID\n     * @param imdn Imdn document\n     */\n    public void onOneToOneMessageDeliveryStatusReceived(ContactId contact, ImdnDocument imdn) {\n        ImdnDocument.DeliveryStatus status = imdn.getStatus();\n        String msgId = imdn.getMsgId();\n        String notificationType = imdn.getNotificationType();\n        long timestamp = imdn.getDateTime();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Receive IMDN for message \" + msgId + \", status=\" + status + \", Type=\"\n                    + notificationType);\n        }\n        String mimeType = mMessagingLog.getMessageMimeType(msgId);\n        if (ImdnDocument.DeliveryStatus.ERROR == status\n                || ImdnDocument.DeliveryStatus.FAILED == status\n                || ImdnDocument.DeliveryStatus.FORBIDDEN == status) {\n            ReasonCode reasonCode = imdnToFailedReasonCode(imdn);\n            synchronized (mLock) {\n                if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, Status.FAILED,\n                        reasonCode)) {\n                    mOneToOneChatEventBroadcaster.broadcastMessageStatusChanged(contact, mimeType,\n                            msgId, Status.FAILED, reasonCode);\n                }\n            }\n        } else if (ImdnDocument.DeliveryStatus.DELIVERED == status) {\n            mImService.getDeliveryExpirationManager().cancelDeliveryTimeoutAlarm(msgId);\n            synchronized (mLock) {\n                if (mMessagingLog.setChatMessageStatusDelivered(msgId, timestamp)) {\n                    mOneToOneChatEventBroadcaster.broadcastMessageStatusChanged(contact, mimeType,\n                            msgId, Status.DELIVERED, ReasonCode.UNSPECIFIED);\n                }\n            }\n        } else if (ImdnDocument.DeliveryStatus.DISPLAYED == status) {\n            mImService.getDeliveryExpirationManager().cancelDeliveryTimeoutAlarm(msgId);\n            synchronized (mLock) {\n                if (mMessagingLog.setChatMessageStatusDisplayed(msgId, timestamp)) {\n                    mOneToOneChatEventBroadcaster.broadcastMessageStatusChanged(contact, mimeType,\n                            msgId, Status.DISPLAYED, ReasonCode.UNSPECIFIED);\n                }\n            }\n        }\n    }\n\n    /**\n     * Remove a oneToOne chat from the list\n     *\n     * @param contact Contact ID\n     */\n    public void removeOneToOneChat(ContactId contact) {\n        mOneToOneChatCache.remove(contact);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove oneToOne chat from list (size=\" + mOneToOneChatCache.size()\n                    + \") for \" + contact);\n        }\n    }\n\n    public OneToOneChatImpl getOrCreateOneToOneChat(ContactId contact) {\n        OneToOneChatImpl oneToOneChat = mOneToOneChatCache.get(contact);\n        if (oneToOneChat == null) {\n            oneToOneChat = new OneToOneChatImpl(mImService, contact, mOneToOneChatEventBroadcaster,\n                    mMessagingLog, mRcsSettings, this, mContactManager);\n            mOneToOneChatCache.put(contact, oneToOneChat);\n        }\n        return oneToOneChat;\n    }\n\n    /**\n     * Returns a chat from its unique ID\n     *\n     * @param contact Contact ID\n     * @return IOneToOneChat\n     * @throws RemoteException\n     */\n    @Override\n    public IOneToOneChat getOneToOneChat(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        try {\n            return getOrCreateOneToOneChat(contact);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Receive a new group chat invitation\n     *\n     * @param session Chat session\n     */\n    public void receiveGroupChatInvitation(GroupChatSession session) {\n        ContactId remote = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Group chat invitation from \" + remote + \" (display=\"\n                    + session.getRemoteDisplayName() + \")\");\n        }\n        String chatId = session.getContributionID();\n        GroupChatImpl groupChat = getOrCreateGroupChat(chatId);\n        session.addListener(groupChat);\n    }\n\n    /**\n     * Add a group chat in the list\n     *\n     * @param groupChat Group chat\n     */\n    /* package private */void addGroupChat(GroupChatImpl groupChat) {\n        String chatId = groupChat.getChatId();\n        mGroupChatCache.put(chatId, groupChat);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add Group Chat to list (size=\" + mGroupChatCache.size()\n                    + \") for chatId \" + chatId);\n        }\n    }\n\n    /**\n     * Remove a group chat from the list\n     *\n     * @param chatId Chat ID\n     */\n    public void removeGroupChat(String chatId) {\n        mGroupChatCache.remove(chatId);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove Group Chat to list (size=\" + mGroupChatCache.size()\n                    + \") for chatId \" + chatId);\n        }\n    }\n\n    /**\n     * Initiates a group chat with a group of contact and returns a GroupChat instance. The subject\n     * is optional and may be null.\n     *\n     * @param contacts List of contact IDs\n     * @param subject Subject\n     * @return instance of IGroupChat\n     * @throws RemoteException <p>\n     *             Note: List is used instead of Set because AIDL does only support List\n     *             </p>\n     */\n    @Override\n    public IGroupChat initiateGroupChat(List<ContactId> contacts, String subject)\n            throws RemoteException {\n        if (contacts == null || contacts.isEmpty()) {\n            throw new ServerApiIllegalArgumentException(\n                    \"GroupChat participants list must not be null or empty!\");\n        }\n        if (contacts.size() > mRcsSettings.getMaxChatParticipants() - 1) {\n            throw new ServerApiIllegalArgumentException(\n                    \"Number of contacts exeeds maximum number that can be added to a group chat!\");\n        }\n        if (!mRcsSettings.isGroupChatActivated()) {\n            throw new ServerApiPermissionDeniedException(\n                    \"The GroupChat feature is not activated on the connected IMS server!\");\n        }\n        ServerApiUtils.testIms();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate an ad-hoc group chat session\");\n        }\n        try {\n            long timestamp = System.currentTimeMillis();\n            final GroupChatSession session = mImService.createOriginatingAdHocGroupChatSession(\n                    new HashSet<>(contacts), subject, timestamp);\n            final String chatId = session.getContributionID();\n            final GroupChatImpl groupChat = getOrCreateGroupChat(chatId);\n\n            mMessagingLog.addGroupChat(session.getContributionID(), session.getRemoteContact(),\n                    session.getSubject(), session.getParticipants(), GroupChat.State.INITIATING,\n                    GroupChat.ReasonCode.UNSPECIFIED, Direction.OUTGOING, timestamp);\n\n            mImService.scheduleImOperation(new Runnable() {\n                public void run() {\n                    try {\n                        if (!isServiceRegistered() || !mImService.isChatSessionAvailable()) {\n                            sLogger.error(\"Failed to initiate group chat with chatId '\" + chatId\n                                    + \"'!\");\n                            setGroupChatStateAndReasonCode(chatId, GroupChat.State.FAILED,\n                                    GroupChat.ReasonCode.FAILED_INITIATION);\n                            return;\n                        }\n                        session.addListener(groupChat);\n                        session.startSession();\n\n                    } catch (PayloadException | RuntimeException e) {\n                        sLogger.error(\n                                \"Failed to initiate group chat with chatId '\" + chatId + \"'!\", e);\n                        setGroupChatStateAndReasonCode(chatId, GroupChat.State.FAILED,\n                                GroupChat.ReasonCode.FAILED_INITIATION);\n\n                    } catch (NetworkException e) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Failed to initiate group chat with chatId '\" + chatId\n                                    + \"'! (\" + e.getMessage() + \")\");\n                        }\n                        setGroupChatStateAndReasonCode(chatId, GroupChat.State.FAILED,\n                                GroupChat.ReasonCode.FAILED_INITIATION);\n                    }\n                }\n            });\n            return groupChat;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    public GroupChatImpl getOrCreateGroupChat(String chatId) {\n        GroupChatImpl groupChat = mGroupChatCache.get(chatId);\n        if (groupChat == null) {\n            GroupChatPersistedStorageAccessor persistedStorage = new GroupChatPersistedStorageAccessor(\n                    chatId, mMessagingLog, mRcsSettings);\n            groupChat = new GroupChatImpl(mImService, chatId, mGroupChatEventBroadcaster,\n                    persistedStorage, mRcsSettings, this, mContactManager, mMessagingLog,\n                    mHistoryLog);\n            mGroupChatCache.put(chatId, groupChat);\n        }\n        return groupChat;\n    }\n\n    /**\n     * Returns a group chat from its unique ID. An exception is thrown if the chat ID does not exist\n     *\n     * @param chatId Chat ID\n     * @return IGroupChat\n     * @throws RemoteException\n     */\n    @Override\n    public IGroupChat getGroupChat(String chatId) throws RemoteException {\n        if (TextUtils.isEmpty(chatId)) {\n            throw new ServerApiIllegalArgumentException(\"chatId must not be null or empty!\");\n        }\n        try {\n            return getOrCreateGroupChat(chatId);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to initiate a group chat now, else returns false.\n     *\n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToInitiateGroupChat() throws RemoteException {\n        try {\n            if (!mRcsSettings.isGroupChatActivated()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot initiate group chat as group chat feature is not supported.\");\n                }\n                return false;\n            }\n            if (!mRcsSettings.getMyCapabilities().isImSessionSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot initiate group chat as IM capabilities are not supported for self.\");\n                }\n                return false;\n            }\n            if (!ServerApiUtils.isImsConnected()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot initiate group chat as IMS is not connected.\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it's possible to initiate a new group chat with the specified contactId right\n     * now, else returns false.\n     *\n     * @param contact Remote contact\n     * @return true if it's possible to initiate a new group chat\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToInitiateGroupChat2(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        try {\n            if (!isAllowedToInitiateGroupChat()) {\n                return false;\n            }\n            Capabilities contactCapabilities = mContactManager.getContactCapabilities(contact);\n            if (contactCapabilities == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot initiate group chat as the capabilities of the participant '\"\n                            + contact + \"' are not known.\");\n                }\n                return false;\n            }\n            if (!contactCapabilities.isImSessionSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot initiate group chat as the participant '\" + contact\n                            + \"' does not have IM capabilities.\");\n                }\n                return false;\n            }\n            if (mRcsSettings.isGroupChatInviteIfFullStoreForwardSupported()\n                    && !contactCapabilities.isGroupChatStoreForwardSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot initiate group chat as the participant '\" + contact\n                            + \"' does not have store and forward feature supported.\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all one to one chat from history and abort/reject any associated ongoing session if\n     * such exists.\n     */\n    @Override\n    public void deleteOneToOneChats() {\n        mImService.tryToDeleteOneToOneChats();\n    }\n\n    /**\n     * Deletes all group chat from history and abort/reject any associated ongoing session if such\n     * exists.\n     */\n    @Override\n    public void deleteGroupChats() {\n        mImService.tryToDeleteGroupChats();\n    }\n\n    /**\n     * Deletes a one to one chat with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     *\n     * @param contact Remote contact\n     */\n    @Override\n    public void deleteOneToOneChat(ContactId contact) {\n        mImService.tryToDeleteOneToOneChat(contact);\n    }\n\n    /**\n     * Delete a group chat by its chat id from history and abort/reject any associated ongoing\n     * session if such exists.\n     *\n     * @param chatId Chat id\n     */\n    @Override\n    public void deleteGroupChat(String chatId) {\n        mImService.tryToDeleteGroupChat(chatId);\n    }\n\n    /**\n     * Delete a message from its message id from history. Will resolve if the message is one to one\n     * or from a group chat.\n     *\n     * @param msgId Message Id\n     */\n    @Override\n    public void deleteMessage(String msgId) {\n        mImService.tryToDeleteChatMessage(msgId);\n    }\n\n    /**\n     * Disables and clears any delivery expiration for a set of chat messages regardless if the\n     * delivery of them has expired already or not.\n     *\n     * @param msgIds Message ID\n     * @throws RemoteException\n     */\n    @Override\n    public void clearMessageDeliveryExpiration(final List<String> msgIds) throws RemoteException {\n        if (msgIds == null || msgIds.isEmpty()) {\n            throw new ServerApiIllegalArgumentException(\n                    \"Undelivered chat messageId list must not be null and empty!\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    for (String msgId : msgIds) {\n                        mImService.getDeliveryExpirationManager().cancelDeliveryTimeoutAlarm(msgId);\n                    }\n                    mMessagingLog.clearMessageDeliveryExpiration(msgIds);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to mark message as read!\", e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Adds a listener on one-to-one chat events\n     *\n     * @param listener One-to-One chat event listener\n     * @throws RemoteException\n     */\n    @Override\n    public void addEventListener2(IOneToOneChatListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mOneToOneChatEventBroadcaster.addOneToOneChatEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on one-to-one chat events\n     *\n     * @param listener One-to-One chat event listener\n     * @throws RemoteException\n     */\n    @Override\n    public void removeEventListener2(IOneToOneChatListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mOneToOneChatEventBroadcaster.removeOneToOneChatEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on group chat events\n     *\n     * @param listener Group chat event listener\n     * @throws RemoteException\n     */\n    @Override\n    public void addEventListener3(IGroupChatListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mGroupChatEventBroadcaster.addGroupChatEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on group chat events\n     *\n     * @param listener Group chat event listener\n     * @throws RemoteException\n     */\n    @Override\n    public void removeEventListener3(IGroupChatListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mGroupChatEventBroadcaster.removeGroupChatEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the configuration of the chat service\n     *\n     * @return Configuration\n     */\n    @Override\n    public IChatServiceConfiguration getConfiguration() {\n        return new ChatServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Mark a received message as read (ie. displayed in the UI)\n     *\n     * @param msgId Message ID\n     * @throws RemoteException\n     */\n    @Override\n    public void markMessageAsRead(final String msgId) throws RemoteException {\n        if (TextUtils.isEmpty(msgId)) {\n            throw new ServerApiIllegalArgumentException(\"msgId must not be null or empty!\");\n        }\n        /*\n         * Firstly message is marked as read in the chat provider. Operation is done synchronously\n         * to avoid multiple mark as read requests.\n         */\n        try {\n            if (mMessagingLog.markMessageAsRead(msgId, System.currentTimeMillis()) == 0) {\n                /* no reporting towards the network if message is already marked as read */\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Message with ID \" + msgId + \" is already marked as read!\");\n                }\n                return;\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n        /*\n         * Then reporting towards the network is performed asynchronously (i.e. in background).\n         */\n        mImService.scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    if (mRcsSettings.isImReportsActivated()\n                            && mRcsSettings.isRespondToDisplayReports()) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"tryToDispatchAllPendingDisplayNotifications for msgID \"\n                                    .concat(msgId));\n                        }\n                        ImdnManager imdnManager = mImService.getImdnManager();\n                        if (imdnManager.isSendOneToOneDeliveryDisplayedReportsEnabled()\n                                || imdnManager.isSendGroupDeliveryDisplayedReportsEnabled()) {\n                            mImService.tryToDispatchAllPendingDisplayNotifications();\n                        }\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to mark message as read!\", e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Returns service version\n     *\n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Add and broadcast group chat invitation rejections.\n     *\n     * @param chatId Chat ID\n     * @param contact Contact ID\n     * @param subject Subject\n     * @param participants Participants\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void addGroupChatInvitationRejected(String chatId, ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, GroupChat.ReasonCode reasonCode,\n            long timestamp) {\n\n        mMessagingLog.addGroupChat(chatId, contact, subject, participants,\n                GroupChat.State.REJECTED, reasonCode, Direction.INCOMING, timestamp);\n\n        mGroupChatEventBroadcaster.broadcastInvitation(chatId);\n    }\n\n    /**\n     * Handle one-to-one chat session initiation\n     *\n     * @param session OneToOneChatSession\n     */\n    public void receiveOneToOneChatSessionInitiation(OneToOneChatSession session) {\n        ContactId contact = session.getRemoteContact();\n        OneToOneChatImpl oneToOneChat = getOrCreateOneToOneChat(contact);\n        session.addListener(oneToOneChat);\n    }\n\n    /**\n     * Returns a chat message from its unique ID\n     *\n     * @param msgId Message Id\n     * @return IChatMessage\n     * @throws RemoteException\n     */\n    @Override\n    public IChatMessage getChatMessage(String msgId) throws RemoteException {\n        if (TextUtils.isEmpty(msgId)) {\n            throw new ServerApiIllegalArgumentException(\"msgId must not be null or empty!\");\n        }\n        try {\n            ChatMessagePersistedStorageAccessor persistedStorage = new ChatMessagePersistedStorageAccessor(\n                    mMessagingLog, msgId);\n            return new ChatMessageImpl(persistedStorage);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Handle rejoin group chat as part of send operation\n     *\n     * @param chatId Chat Id\n     */\n    public void rejoinGroupChatAsPartOfSendOperation(String chatId) throws PayloadException,\n            NetworkException {\n        GroupChatImpl groupChat = getOrCreateGroupChat(chatId);\n        groupChat.setRejoinedAsPartOfSendOperation(true);\n        groupChat.rejoinGroupChat();\n    }\n\n    /**\n     * Handle rejoin group chat\n     *\n     * @param chatId Chat Id\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void rejoinGroupChat(String chatId) throws PayloadException, NetworkException {\n        GroupChatImpl groupChat = getOrCreateGroupChat(chatId);\n        groupChat.rejoinGroupChat();\n    }\n\n    /**\n     * Returns the common service configuration\n     *\n     * @return the common service configuration\n     */\n    @Override\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Set one-one chat message status and reason code\n     *\n     * @param msgId Message Id\n     * @param mimeType Mime type\n     * @param contact Remote contact\n     * @param status Status\n     * @param reasonCode Reason code\n     */\n    public void setOneToOneChatMessageStatusAndReasonCode(String msgId, String mimeType,\n            ContactId contact, Status status, ReasonCode reasonCode) {\n        if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, status, reasonCode)) {\n            mOneToOneChatEventBroadcaster.broadcastMessageStatusChanged(contact, mimeType, msgId,\n                    status, reasonCode);\n        }\n    }\n\n    /**\n     * Set group chat message status and reason code\n     *\n     * @param msgId Message Id\n     * @param mimeType Mime type\n     * @param chatId Chat id\n     * @param status Status\n     * @param reasonCode Reason code\n     */\n    public void setGroupChatMessageStatusAndReasonCode(String msgId, String mimeType,\n            String chatId, Status status, ReasonCode reasonCode) {\n        if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, status, reasonCode)) {\n            mGroupChatEventBroadcaster.broadcastMessageStatusChanged(chatId, mimeType, msgId,\n                    status, reasonCode);\n        }\n    }\n\n    public void broadcastGroupChatMessagesDeleted(String chatId, Set<String> msgIds) {\n        mGroupChatEventBroadcaster.broadcastMessagesDeleted(chatId, msgIds);\n    }\n\n    public void broadcastGroupChatsDeleted(Set<String> chatIds) {\n        mGroupChatEventBroadcaster.broadcastGroupChatsDeleted(chatIds);\n    }\n\n    public void broadcastOneToOneMessagesDeleted(ContactId contact, Set<String> msgIds) {\n        mOneToOneChatEventBroadcaster.broadcastMessagesDeleted(contact, msgIds);\n    }\n\n    /**\n     * Set group chat state and reason code\n     *\n     * @param chatId Chat id\n     * @param state State\n     * @param reasonCode Reason code\n     */\n    public void setGroupChatStateAndReasonCode(String chatId, State state,\n            GroupChat.ReasonCode reasonCode) {\n        if (mMessagingLog.setGroupChatStateAndReasonCode(chatId, state, reasonCode)) {\n            mGroupChatEventBroadcaster.broadcastStateChanged(chatId, state, reasonCode);\n        }\n    }\n\n    /**\n     * Broadcasts Group Chat state change\n     *\n     * @param chatId Chat id\n     * @param state State\n     * @param reasonCode Reason code\n     */\n    public void broadcastGroupChatStateChange(String chatId, State state,\n            GroupChat.ReasonCode reasonCode) {\n        mGroupChatEventBroadcaster.broadcastStateChanged(chatId, state, reasonCode);\n    }\n\n    /**\n     * Checks if the group chat with specific chatId is active\n     *\n     * @param chatId Chat id\n     * @return boolean\n     */\n    public boolean isGroupChatActive(String chatId) {\n        return getOrCreateGroupChat(chatId).isGroupChatActive();\n    }\n\n    /**\n     * Checks if the group chat is abandoned and can never be used to send or receive messages.\n     *\n     * @param chatId Chat id\n     * @return boolean\n     */\n    public boolean isGroupChatAbandoned(String chatId) {\n        return getOrCreateGroupChat(chatId).isGroupChatAbandoned();\n    }\n\n    public void onDisplayReportSent(String chatId, ContactId remote, String msgId) {\n        if (remote != null && chatId.equals(remote.toString())) {\n            getOrCreateOneToOneChat(remote).onChatMessageDisplayReportSent(msgId);\n        } else {\n            getOrCreateGroupChat(chatId).onChatMessageDisplayReportSent(msgId);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/CommonServiceConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\n/**\n * A class that implements interface to allow access to common service configuration from APIs\n * \n * @author Philippe LEMORDANT\n */\npublic class CommonServiceConfigurationImpl extends ICommonServiceConfiguration.Stub {\n\n    private static final Logger sLogger = Logger.getLogger(CommonServiceConfigurationImpl.class\n            .getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings RCS settings accessor\n     */\n    public CommonServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public int getDefaultMessagingMethod() throws RemoteException {\n        try {\n            return mRcsSettings.getDefaultMessagingMethod().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getMessagingUX() throws RemoteException {\n        try {\n            return mRcsSettings.getMessagingMode().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public ContactId getMyContactId() throws RemoteException {\n        try {\n            return mRcsSettings.getUserProfileImsUserName();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getMyDisplayName() throws RemoteException {\n        try {\n            String displayName = mRcsSettings.getUserProfileImsDisplayName();\n            if (TextUtils.isEmpty(displayName)) {\n                return null;\n            }\n            return displayName;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isConfigValid() throws RemoteException {\n        try {\n            return mRcsSettings.isConfigurationValid();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void setDefaultMessagingMethod(int method) throws RemoteException {\n        try {\n            mRcsSettings.setDefaultMessagingMethod(MessagingMethod.valueOf(method));\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void setMyDisplayName(String name) throws RemoteException {\n        try {\n            if (TextUtils.isEmpty(name)) {\n                mRcsSettings.setUserProfileImsDisplayName(\"\");\n                return;\n            }\n            if (name.length() > mRcsSettings.getMaxAllowedDisplayNameChars()) {\n                throw new ServerApiIllegalArgumentException(\"name exceeds max allowed characters!\");\n            }\n            mRcsSettings.setUserProfileImsDisplayName(name);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getMinimumBatteryLevel() throws RemoteException {\n        try {\n            return mRcsSettings.getMinBatteryLevel().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void setMinimumBatteryLevel(int level) throws RemoteException {\n        try {\n            mRcsSettings.setMinBatteryLevel(MinimumBatteryLevel.valueOf(level));\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ContactServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.service.ContactInfo;\nimport com.gsma.rcs.core.ims.service.ContactInfo.BlockingState;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.IContactService;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Contact service API implementation\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class ContactServiceImpl extends IContactService.Stub {\n\n    private static final Logger logger = Logger.getLogger(ContactServiceImpl.class.getSimpleName());\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Contacts manager\n     */\n    private final ContactManager mContactManager;\n\n    /**\n     * Constructor\n     * \n     * @param contactManager Contacts manager\n     * @param rcsSettings RCS settings accessor\n     */\n    public ContactServiceImpl(ContactManager contactManager, RcsSettings rcsSettings) {\n        if (logger.isActivated()) {\n            logger.info(\"Contacts service API is loaded\");\n        }\n        mContactManager = contactManager;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        if (logger.isActivated()) {\n            logger.info(\"Contacts service API is closed\");\n        }\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return Returns true if registered else returns false\n     */\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        // Notify listeners\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     * \n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        // Notify listeners\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Returns the RCS contact infos from its contact ID (i.e. MSISDN)\n     * \n     * @param contact Contact ID\n     * @return Contact\n     * @throws RemoteException\n     */\n    public RcsContact getRcsContact(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        try {\n            // Read capabilities in the local database\n            return getRcsContact(mContactManager.getContactInfo(contact));\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                logger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            logger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Convert the com.gsma.rcs.core.ims.service.capability.Capabilities instance into a\n     * Capabilities instance\n     * \n     * @param capabilities com.gsma.rcs.core.ims.service.capability.Capabilities instance\n     * @return Capabilities instance\n     */\n    /* package private */static Capabilities getCapabilities(\n            com.gsma.rcs.core.ims.service.capability.Capabilities capabilities) {\n        if (capabilities == null) {\n            return null;\n        }\n        return new Capabilities(capabilities.isImageSharingSupported(),\n                capabilities.isVideoSharingSupported(), capabilities.isImSessionSupported(),\n                capabilities.isFileTransferMsrpSupported()\n                        || capabilities.isFileTransferHttpSupported(),\n                capabilities.isGeolocationPushSupported(), capabilities.getSupportedExtensions(),\n                capabilities.isSipAutomata(), capabilities.getTimestampOfLastResponse());\n    }\n\n    /**\n     * Convert the ContactInfo instance into a RcsContact instance\n     * \n     * @param contactInfo the ContactInfo instance\n     * @return RcsContact instance\n     */\n    private RcsContact getRcsContact(ContactInfo contactInfo) {\n        // Discard if argument is null\n        if (contactInfo == null) {\n            return null;\n        }\n        if (!contactInfo.isRcsContact()) {\n            return null;\n        }\n        Capabilities capaApi = getCapabilities(contactInfo.getCapabilities());\n        boolean registered = RegistrationState.ONLINE.equals(contactInfo.getRegistrationState());\n        boolean blocked = (contactInfo.getBlockingState() == BlockingState.BLOCKED);\n        return new RcsContact(contactInfo.getContact(), registered, capaApi,\n                contactInfo.getDisplayName(), blocked, contactInfo.getBlockingTimestamp());\n    }\n\n    /**\n     * Interface to filter ContactInfo\n     * \n     * @author YPLO6403\n     */\n    private interface FilterContactInfo {\n        /**\n         * The filtering method\n         * \n         * @param contactInfo Contact information\n         * @return true if contactInfo is in the scope\n         */\n        boolean inScope(ContactInfo contactInfo);\n    }\n\n    /**\n     * Get a filtered list of RcsContact\n     * \n     * @param filterContactInfo the filter (or null if not applicable)\n     * @return the filtered list of RcsContact\n     */\n    private List<RcsContact> getRcsContacts(FilterContactInfo filterContactInfo) {\n        List<RcsContact> rcsContacts = new ArrayList<>();\n        /* Read capabilities in the local database */\n        Set<ContactId> contacts = mContactManager.getRcsContactsFromRcsContactProvider();\n        for (ContactId contact : contacts) {\n            ContactInfo contactInfo = mContactManager.getContactInfo(contact);\n            if (contactInfo != null) {\n                if (filterContactInfo == null || filterContactInfo.inScope(contactInfo)) {\n                    RcsContact contact2add = getRcsContact(contactInfo);\n                    if (contact2add != null) {\n                        rcsContacts.add(getRcsContact(contactInfo));\n                    }\n                }\n            }\n        }\n        return rcsContacts;\n    }\n\n    /**\n     * Returns the list of rcs contacts\n     * \n     * @return List of contacts\n     * @throws RemoteException\n     */\n    public List<RcsContact> getRcsContacts() throws RemoteException {\n        if (logger.isActivated()) {\n            logger.info(\"Get rcs contacts\");\n        }\n        try {\n            return getRcsContacts(null);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                logger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            logger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of online contacts (i.e. registered)\n     * \n     * @return List of contacts\n     * @throws RemoteException\n     */\n    public List<RcsContact> getRcsContactsOnline() throws RemoteException {\n        if (logger.isActivated()) {\n            logger.info(\"Get registered rcs contacts\");\n        }\n        try {\n            return getRcsContacts(new FilterContactInfo() {\n\n                @Override\n                public boolean inScope(ContactInfo contactInfo) {\n                    return RegistrationState.ONLINE.equals(contactInfo.getRegistrationState());\n                }\n            });\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                logger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            logger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of contacts supporting a given extension (i.e. feature tag)\n     * \n     * @param serviceId Service ID\n     * @return List of contacts\n     * @throws RemoteException\n     */\n    public List<RcsContact> getRcsContactsSupporting(final String serviceId) throws RemoteException {\n        if (TextUtils.isEmpty(serviceId)) {\n            throw new ServerApiIllegalArgumentException(\"serviceId must not be null or empty!\");\n        }\n        if (logger.isActivated()) {\n            logger.info(\"Get rcs contacts supporting \" + serviceId);\n        }\n        try {\n            return getRcsContacts(new FilterContactInfo() {\n\n                @Override\n                public boolean inScope(ContactInfo contactInfo) {\n                    com.gsma.rcs.core.ims.service.capability.Capabilities capabilities = contactInfo\n                            .getCapabilities();\n                    if (capabilities != null) {\n                        Set<String> supportedExtensions = capabilities.getSupportedExtensions();\n                        if (supportedExtensions != null) {\n                            for (String supportedExtension : supportedExtensions) {\n                                if (supportedExtension.equals(serviceId)) {\n                                    return true;\n                                }\n                            }\n                        }\n                    }\n                    return false;\n                }\n            });\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                logger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            logger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        if (logger.isActivated()) {\n            logger.debug(\"getCommonConfiguration\");\n        }\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Block a contact. Any communication from the given contact will be blocked and redirected to\n     * the corresponding spambox.\n     * \n     * @param contact Contact ID\n     * @throws RemoteException\n     */\n    public void blockContact(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (logger.isActivated()) {\n            logger.info(\"Block contact \" + contact);\n        }\n        try {\n            mContactManager.setBlockingState(contact, BlockingState.BLOCKED);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                logger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            logger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Unblock a contact\n     * \n     * @param contact Contact ID\n     * @throws RemoteException\n     */\n    public void unblockContact(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (logger.isActivated()) {\n            logger.info(\"Unblock contact \" + contact);\n        }\n        try {\n            mContactManager.setBlockingState(contact, BlockingState.NOT_BLOCKED);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                logger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            logger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ExceptionUtil.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\npublic class ExceptionUtil {\n\n    /**\n     * Special Delimiter that will be appended while propagating server exceptions over AIDL layer.\n     */\n    private static final char DELIMITER_PIPE = '|';\n\n    private static void addTrace(StringBuilder sb, Throwable t, boolean first) {\n        StackTraceElement[] traces = t.getStackTrace();\n        if (null != traces && traces.length > 0) {\n            if (!first) {\n                sb.append(\"Caused by: \");\n            }\n            sb.append(t.getClass().getName());\n            String msg = t.getMessage();\n            if (msg != null) {\n                sb.append(\": \");\n                if (first) {\n                    final int delimiterIndex = msg.indexOf(DELIMITER_PIPE);\n                    if (delimiterIndex > 0 && delimiterIndex < msg.length() - 1) {\n                        sb.append(msg.substring(delimiterIndex + 1));\n                    } else {\n                        sb.append(msg);\n                    }\n                } else {\n                    sb.append(msg);\n                }\n            }\n            sb.append('\\n');\n            for (StackTraceElement trace : traces) {\n                sb.append(\"\\tat \").append(trace.getClassName()).append('.')\n                        .append(trace.getMethodName()).append('(');\n                int lineNumber = trace.getLineNumber();\n                if (lineNumber > 0) {\n                    sb.append(trace.getFileName()).append(':').append(lineNumber);\n                } else {\n                    sb.append(\"Native Method\");\n                }\n                sb.append(')').append('\\n');\n            }\n        }\n    }\n\n    public static String getFullStackTrace(Throwable t) {\n        StringBuilder sb = new StringBuilder();\n        addTrace(sb, t, true);\n        Throwable cause = t.getCause();\n        while (null != cause) {\n            addTrace(sb, cause, false);\n            cause = cause.getCause();\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/FileTransferServiceConfigurationImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption;\nimport com.gsma.services.rcs.filetransfer.IFileTransferServiceConfiguration;\n\nimport android.os.RemoteException;\n\n/**\n * A class that implements interface to allow access to file transfer service configuration from API\n * \n * @author yplo6403\n */\npublic class FileTransferServiceConfigurationImpl extends IFileTransferServiceConfiguration.Stub {\n\n    private final Logger mLogger = Logger.getLogger(FileTransferServiceConfigurationImpl.class\n            .getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * @param rcsSettings RCS settings accessor\n     */\n    public FileTransferServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public void setImageResizeOption(int option) throws RemoteException {\n        try {\n            mRcsSettings.setImageResizeOption(ImageResizeOption.valueOf(option));\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void setAutoAcceptInRoaming(boolean enable) throws RemoteException {\n        try {\n            if (!mRcsSettings.isFtAutoAcceptedModeChangeable()) {\n                throw new ServerApiUnsupportedOperationException(\n                        \"Auto accept mode in roaming is not changeable\");\n            }\n            if (!mRcsSettings.isFileTransferAutoAccepted()) {\n                throw new ServerApiPermissionDeniedException(\n                        \"Auto accept mode in normal conditions must be enabled\");\n            }\n            mRcsSettings.setFileTransferAutoAcceptedInRoaming(enable);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void setAutoAccept(boolean enable) throws RemoteException {\n        try {\n            if (!mRcsSettings.isFtAutoAcceptedModeChangeable()) {\n                throw new ServerApiUnsupportedOperationException(\n                        \"Auto accept mode is not changeable\");\n            }\n            mRcsSettings.setFileTransferAutoAccepted(enable);\n            if (!enable) {\n                /* If AA is disabled in normal conditions then it must be disabled while roaming. */\n                mRcsSettings.setFileTransferAutoAcceptedInRoaming(false);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isGroupFileTransferSupported() throws RemoteException {\n        try {\n            return mRcsSettings.getMyCapabilities().isFileTransferHttpSupported()\n                    && mRcsSettings.isGroupChatActivated();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isAutoAcceptModeChangeable() throws RemoteException {\n        try {\n            return mRcsSettings.isFtAutoAcceptedModeChangeable();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isAutoAcceptInRoamingEnabled() throws RemoteException {\n        try {\n            return mRcsSettings.isFileTransferAutoAcceptedInRoaming();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isAutoAcceptEnabled() throws RemoteException {\n        try {\n            return mRcsSettings.isFileTransferAutoAccepted();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getWarnSize() throws RemoteException {\n        try {\n            return mRcsSettings.getWarningMaxFileTransferSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getMaxSize() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxFileTransferSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getMaxAudioMessageDuration() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxAudioMessageDuration();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getMaxFileTransfers() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxFileTransferSessions();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getImageResizeOption() throws RemoteException {\n        try {\n            return mRcsSettings.getImageResizeOption().toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/FileTransferServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.SessionNotEstablishedException;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.platform.file.FileDescription;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.FileTransferPersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.service.broadcaster.GroupFileTransferBroadcaster;\nimport com.gsma.rcs.service.broadcaster.OneToOneFileTransferBroadcaster;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.MimeManager;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.filetransfer.IFileTransfer;\nimport com.gsma.services.rcs.filetransfer.IFileTransferService;\nimport com.gsma.services.rcs.filetransfer.IFileTransferServiceConfiguration;\nimport com.gsma.services.rcs.filetransfer.IGroupFileTransferListener;\nimport com.gsma.services.rcs.filetransfer.IOneToOneFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * File transfer service implementation\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class FileTransferServiceImpl extends IFileTransferService.Stub {\n\n    private final OneToOneFileTransferBroadcaster mOneToOneFileTransferBroadcaster = new OneToOneFileTransferBroadcaster();\n\n    private final GroupFileTransferBroadcaster mGroupFileTransferBroadcaster = new GroupFileTransferBroadcaster();\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final InstantMessagingService mImService;\n\n    private final ChatServiceImpl mChatService;\n\n    private final MessagingLog mMessagingLog;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private final Context mCtx;\n\n    private final Map<String, OneToOneFileTransferImpl> mOneToOneFileTransferCache = new HashMap<>();\n\n    private final Map<String, GroupFileTransferImpl> mGroupFileTransferCache = new HashMap<>();\n\n    private static final Logger sLogger = Logger.getLogger(FileTransferServiceImpl.class\n            .getSimpleName());\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    /**\n     * Constructor\n     * \n     * @param imService Instant Messaging Service\n     * @param chatService Chat service\n     * @param messagingLog Messaging Log\n     * @param rcsSettings Rcs Settings\n     * @param contactManager Contact Manager\n     * @param ctx the context\n     */\n    public FileTransferServiceImpl(InstantMessagingService imService, ChatServiceImpl chatService,\n            MessagingLog messagingLog, RcsSettings rcsSettings, ContactManager contactManager,\n            Context ctx) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"File transfer service API is loaded\");\n        }\n        mImService = imService;\n        mImService.register(this);\n        mChatService = chatService;\n        mMessagingLog = messagingLog;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n        mCtx = ctx;\n    }\n\n    private ReasonCode imdnToFileTransferFailedReasonCode(ImdnDocument imdn) {\n        String notificationType = imdn.getNotificationType();\n        if (ImdnDocument.DELIVERY_NOTIFICATION.equals(notificationType)) {\n            return ReasonCode.FAILED_DELIVERY;\n\n        } else if (ImdnDocument.DISPLAY_NOTIFICATION.equals(notificationType)) {\n            return ReasonCode.FAILED_DISPLAY;\n        }\n\n        throw new IllegalArgumentException(\"Received invalid IMDN notification type:'\"\n                + notificationType + \"'\");\n    }\n\n    public void ensureThumbnailIsDeleted(String transferId) {\n        Uri icon = mMessagingLog.getFileTransferIcon(transferId);\n        if (icon != null) {\n            new File(icon.getPath()).delete();\n        }\n    }\n\n    /**\n     * Ensure copy of file if existing is deleted\n     * \n     * @param transferId Unique Id of file transfer\n     */\n    public void ensureFileCopyIsDeletedIfExisting(String transferId) {\n        if (Direction.INCOMING == mMessagingLog.getFileTransferDirection(transferId)) {\n            return;\n        }\n        Uri file = mMessagingLog.getFile(transferId);\n        if (file != null) {\n            new File(file.getPath()).delete();\n        }\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        /* Clear list of sessions */\n        mOneToOneFileTransferCache.clear();\n        mGroupFileTransferCache.clear();\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"File transfer service API is closed\");\n        }\n    }\n\n    /**\n     * Remove a 1-2-1 file transfer from the list\n     * \n     * @param fileTransferId File transfer ID\n     */\n    public void removeOneToOneFileTransfer(String fileTransferId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a file transfer from the list (size=\"\n                    + mOneToOneFileTransferCache.size() + \")\");\n        }\n\n        mOneToOneFileTransferCache.remove(fileTransferId);\n    }\n\n    /**\n     * Remove a group file transfer from the list\n     * \n     * @param fileTransferId File transfer ID\n     */\n    public void removeGroupFileTransfer(String fileTransferId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a file transfer from the list (size=\"\n                    + mGroupFileTransferCache.size() + \")\");\n        }\n\n        mGroupFileTransferCache.remove(fileTransferId);\n    }\n\n    @Override\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    @Override\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Get or create group file transfer\n     * \n     * @param chatId the chat ID\n     * @param transferId th file transfer ID\n     * @return GroupFileTransferImpl\n     */\n    public GroupFileTransferImpl getOrCreateGroupFileTransfer(String chatId, String transferId) {\n        GroupFileTransferImpl groupFileTransfer = mGroupFileTransferCache.get(transferId);\n        if (groupFileTransfer == null) {\n            FileTransferPersistedStorageAccessor persistedStorage = new FileTransferPersistedStorageAccessor(\n                    transferId, mMessagingLog);\n            groupFileTransfer = new GroupFileTransferImpl(mImService, transferId,\n                    mGroupFileTransferBroadcaster, persistedStorage, this, mRcsSettings,\n                    mMessagingLog, mContactManager, chatId);\n            mGroupFileTransferCache.put(transferId, groupFileTransfer);\n        }\n        return groupFileTransfer;\n    }\n\n    /**\n     * Get or create one-one file transfer\n     * \n     * @param transferId th file transfer ID\n     * @return OneToOneFileTransferImpl\n     */\n    public OneToOneFileTransferImpl getOrCreateOneToOneFileTransfer(String transferId) {\n        OneToOneFileTransferImpl oneToOneFileTransfer = mOneToOneFileTransferCache.get(transferId);\n        if (oneToOneFileTransfer == null) {\n            FileTransferPersistedStorageAccessor persistedStorage = new FileTransferPersistedStorageAccessor(\n                    transferId, mMessagingLog);\n            oneToOneFileTransfer = new OneToOneFileTransferImpl(mImService, transferId,\n                    mOneToOneFileTransferBroadcaster, persistedStorage, this, mRcsSettings,\n                    mMessagingLog, mContactManager);\n            mOneToOneFileTransferCache.put(transferId, oneToOneFileTransfer);\n        }\n        return oneToOneFileTransfer;\n    }\n\n    @Override\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    @Override\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies un registration event\n     * \n     * @param reasonCode for un registration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Receive a new file transfer invitation\n     * \n     * @param session File transfer session\n     * @param isGroup is group file transfer\n     * @param contact Contact ID\n     * @param displayName the display name of the remote contact\n     */\n    public void receiveFileTransferInvitation(FileSharingSession session, boolean isGroup,\n            ContactId contact, String displayName) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Receive FT invitation from \" + contact + \" file=\"\n                    + session.getContent().getName() + \" size=\" + session.getContent().getSize()\n                    + \" displayName=\" + displayName + \" isGroup=\" + isGroup);\n        }\n        String fileTransferId = session.getFileTransferId();\n        if (isGroup) {\n            GroupFileTransferImpl groupFileTransfer = getOrCreateGroupFileTransfer(\n                    session.getContributionID(), fileTransferId);\n            session.addListener(groupFileTransfer);\n        } else {\n            OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(fileTransferId);\n            session.addListener(oneToOneFileTransfer);\n        }\n    }\n\n    /**\n     * Receive a new resend file transfer invitation\n     * \n     * @param session File transfer session\n     * @param remoteContact Contact ID of remote contact\n     * @param displayName the display name of the remote contact\n     */\n    public void receiveResendFileTransferInvitation(FileSharingSession session,\n            ContactId remoteContact, String displayName) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Receive resend FT invitation from \" + remoteContact + \" displayName=\"\n                    + displayName);\n        }\n        OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(session\n                .getFileTransferId());\n        session.addListener(oneToOneFileTransfer);\n    }\n\n    /**\n     * Returns the interface to the configuration of the file transfer service\n     * \n     * @return IFileTransferServiceConfiguration instance\n     * @throws RemoteException\n     */\n    public IFileTransferServiceConfiguration getConfiguration() throws RemoteException {\n        try {\n            return new FileTransferServiceConfigurationImpl(mRcsSettings);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Add outgoing one to one file transfer to DB\n     * \n     * @param fileTransferId File transfer ID\n     * @param contact ContactId\n     * @param content Content of file\n     * @param fileicon Content of file icon\n     * @param state State of the file transfer\n     * @param timestamp Local timestamp of the file transfer\n     * @param timestampSent Timestamp sent in payload of the file transfer\n     */\n    private void addOutgoingOneToOneFileTransfer(String fileTransferId, ContactId contact,\n            MmContent content, MmContent fileicon, State state, long timestamp, long timestampSent) {\n        mMessagingLog.addOneToOneFileTransfer(fileTransferId, contact, Direction.OUTGOING, content,\n                fileicon, state, ReasonCode.UNSPECIFIED, timestamp, timestampSent,\n                FileTransferData.UNKNOWN_EXPIRATION, FileTransferData.UNKNOWN_EXPIRATION);\n    }\n\n    /**\n     * Add outgoing group file transfer to DB\n     * \n     * @param fileTransferId File transfer ID\n     * @param chatId Chat ID of group chat\n     * @param content Content of file\n     * @param fileicon Content of fileicon\n     * @param state state of file transfer\n     * @param timestamp Local timestamp of the file transfer\n     * @param timestampSent Timestamp sent in payload of the file transfer\n     */\n    private void addOutgoingGroupFileTransfer(String fileTransferId, String chatId,\n            MmContent content, MmContent fileicon, State state, long timestamp, long timestampSent) {\n        Set<ContactId> recipients = mChatService.getOrCreateGroupChat(chatId).getRecipients();\n        if (recipients == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Unable to determine recipients of the group chat \" + chatId\n                            + \" to set as recipients for the the group file transfer \"\n                            + fileTransferId + \"!\");\n        }\n        mMessagingLog.addOutgoingGroupFileTransfer(fileTransferId, chatId, content, fileicon,\n                recipients, state, FileTransfer.ReasonCode.UNSPECIFIED, timestamp, timestampSent);\n    }\n\n    public FileTransferProtocol getFileTransferProtocolForOneToOneFileTransfer(ContactId contact) {\n        Capabilities myCapabilities = mRcsSettings.getMyCapabilities();\n        Capabilities remoteCapabilities = mContactManager.getContactCapabilities(contact);\n        if (remoteCapabilities == null) {\n            return null;\n        }\n        boolean ftMsrpSupportedforSelf = myCapabilities.isFileTransferMsrpSupported();\n        boolean ftHttpSupportedforSelf = myCapabilities.isFileTransferHttpSupported();\n        boolean ftMsrpSupportedforRemote = remoteCapabilities.isFileTransferMsrpSupported();\n        boolean ftHttpSupportedforRemote = remoteCapabilities.isFileTransferHttpSupported();\n        if (ftMsrpSupportedforSelf && ftMsrpSupportedforRemote) {\n            if (ftHttpSupportedforSelf && ftHttpSupportedforRemote) {\n                return mRcsSettings.getFtProtocol();\n            }\n            return FileTransferProtocol.MSRP;\n        } else if (ftHttpSupportedforSelf && ftHttpSupportedforRemote) {\n            return FileTransferProtocol.HTTP;\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"There are are no available capabilities : FTMsrp(Self)\"\n                        + ftMsrpSupportedforSelf + \" FTHttp(Self)\" + ftHttpSupportedforSelf\n                        + \" FTMsrp(Remote)\" + ftMsrpSupportedforRemote + \" FTHttp(Remote)\"\n                        + ftHttpSupportedforRemote);\n            }\n            return null;\n        }\n    }\n\n    /**\n     * Set one-one file transfer state and timestamps\n     * \n     * @param fileTransferId the file transfer ID\n     * @param contact the contact\n     * @param state the file transfer state\n     * @param timestamp the timestamp\n     * @param timestampSent the sent timestamp\n     */\n    public void setOneToOneFileTransferStateAndTimestamp(String fileTransferId, ContactId contact,\n            State state, long timestamp, long timestampSent) {\n        if (mMessagingLog.setFileTransferStateAndTimestamp(fileTransferId, state,\n                ReasonCode.UNSPECIFIED, timestamp, timestampSent)) {\n            mOneToOneFileTransferBroadcaster.broadcastStateChanged(contact, fileTransferId, state,\n                    ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    /**\n     * Set group file transfer state and timestamp\n     * \n     * @param fileTransferId the file transfer ID\n     * @param chatId the chat ID\n     * @param state the file transfer state\n     */\n    public void setGroupFileTransferStateAndTimestamp(String fileTransferId, String chatId,\n            State state, long timestamp, long timestampSent) {\n        if (mMessagingLog.setFileTransferStateAndTimestamp(fileTransferId, state,\n                ReasonCode.UNSPECIFIED, timestamp, timestampSent)) {\n            mGroupFileTransferBroadcaster.broadcastStateChanged(chatId, fileTransferId, state,\n                    ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    /**\n     * Dequeue one-to-one file transfer\n     * \n     * @param fileTransferId the file transfer ID\n     * @param contact the contact\n     * @param file the file\n     * @param fileIcon the file icon\n     */\n    public void dequeueOneToOneFileTransfer(String fileTransferId, ContactId contact,\n            MmContent file, MmContent fileIcon) {\n        long timestamp = System.currentTimeMillis();\n        /* For outgoing file transfer, timestampSent = timestamp */\n        long timestampSent = timestamp;\n        FileTransferProtocol ftProtocol = getFileTransferProtocolForOneToOneFileTransfer(contact);\n        if (ftProtocol == null) {\n            throw new ServerApiGenericException(\n                    \"No valid file transfer protocol could be determined for dequeueing file with fileTransferId '\"\n                            + fileTransferId + \"'!\");\n        }\n        FileSharingSession session = mImService.createFileTransferSession(fileTransferId, contact,\n                file, fileIcon, timestamp, ftProtocol);\n        OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(fileTransferId);\n        session.addListener(oneToOneFileTransfer);\n        setOneToOneFileTransferStateAndTimestamp(fileTransferId, contact, State.INITIATING,\n                timestamp, timestampSent);\n        session.startSession();\n    }\n\n    /**\n     * 1-1 file re-send operation initiated\n     * \n     * @param contact the contact\n     * @param file the file\n     * @param fileIcon the file icon\n     * @param fileTransferId the file transfer ID\n     */\n    /* package private */void resendOneToOneFile(ContactId contact, MmContent file,\n            MmContent fileIcon, String fileTransferId) {\n        /* Set new timestamp for the resend file */\n        long timestamp = System.currentTimeMillis();\n        /* For outgoing file transfer, timestampSent = timestamp */\n        long timestampSent = timestamp;\n        if (!ServerApiUtils.isImsConnected()) {\n            /*\n             * If the IMS is NOT connected at this time then re-queue transfer.\n             */\n            setOneToOneFileTransferStateAndTimestamp(fileTransferId, contact, State.QUEUED,\n                    timestamp, timestampSent);\n            return;\n        }\n        if (!mImService.isFileTransferSessionAvailable()\n                || mImService.isMaxConcurrentOutgoingFileTransfersReached()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"The max number of file transfer sessions is achieved: re-queue the file transfer with Id \"\n                        .concat(fileTransferId));\n            }\n            setOneToOneFileTransferStateAndTimestamp(fileTransferId, contact, State.QUEUED,\n                    timestamp, timestampSent);\n            return;\n        }\n\n        setOneToOneFileTransferStateAndTimestamp(fileTransferId, contact, State.INITIATING,\n                timestamp, timestampSent);\n        FileTransferProtocol ftProtocol = getFileTransferProtocolForOneToOneFileTransfer(contact);\n        if (ftProtocol == null) {\n            throw new ServerApiGenericException(\n                    \"No valid file transfer protocol could be determined for resending file with Id '\"\n                            + fileTransferId + \"'!\");\n        }\n\n        final FileSharingSession session = mImService.createFileTransferSession(fileTransferId,\n                contact, file, fileIcon, timestamp, ftProtocol);\n        OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(fileTransferId);\n        session.addListener(oneToOneFileTransfer);\n        session.startSession();\n    }\n\n    /**\n     * Returns true if it is possible to initiate file transfer to the contact specified by the\n     * contact parameter, else returns false.\n     * \n     * @param contact Remote contact\n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToTransferFile(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        try {\n            Capabilities remoteCapabilities = mContactManager.getContactCapabilities(contact);\n            if (remoteCapabilities == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot transfer file as the capabilities of contact \" + contact\n                            + \" are not known.\");\n                }\n                return false;\n            }\n            FileTransferProtocol protocol = getFileTransferProtocolForOneToOneFileTransfer(contact);\n            if (protocol == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot transfer file as no valid file transfer protocol could be determined.\");\n                }\n                return false;\n            }\n            MessagingMode mode = mRcsSettings.getMessagingMode();\n            switch (mode) {\n                case INTEGRATED:\n                case SEAMLESS:\n                    if ((FileTransferProtocol.MSRP == protocol && mRcsSettings.isFtAlwaysOn())\n                            || (FileTransferProtocol.HTTP == protocol && mRcsSettings\n                                    .isFtHttpCapAlwaysOn())) {\n                        break;\n                    }\n                    if (!mImService.isCapabilitiesValid(remoteCapabilities)) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot transfer file as the cached capabilities of contact \"\n                                    + contact\n                                    + \" are not valid anymore for one-to-one communication.\");\n                        }\n                        return false;\n                    }\n                    break;\n                default:\n                    break;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Transfers a file to a contact. The parameter file contains the URI of the file to be\n     * transferred (for a local or a remote file). The parameter contact supports the following\n     * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI. If the\n     * format of the contact is not supported an exception is thrown.\n     * \n     * @param contact Contact\n     * @param file URI of file to transfer\n     * @param attachFileIcon true if the stack must try to attach fileIcon\n     * @return FileTransfer\n     * @throws RemoteException\n     */\n    public IFileTransfer transferFile(final ContactId contact, Uri file, boolean attachFileIcon)\n            throws RemoteException {\n        return transferFile2(contact, file, Disposition.ATTACH.toInt(), attachFileIcon);\n    }\n\n    /**\n     * Transfers a file to a contact. The parameter file contains the URI of the file to be\n     * transferred (for a local or a remote file). The parameter contact supports the following\n     * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI. If the\n     * format of the contact is not supported an exception is thrown.\n     *\n     * @param contact Contact\n     * @param file URI of file to transfer\n     * @param disposition File disposition\n     * @param attachFileIcon true if the stack must try to attach fileIcon\n     * @return FileTransfer\n     * @throws RemoteException\n     */\n    public IFileTransfer transferFile2(final ContactId contact, Uri file, int disposition,\n            boolean attachFileIcon) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (file == null) {\n            throw new ServerApiIllegalArgumentException(\"file must not be null!\");\n        }\n        if (!FileUtils.isReadFromUriPossible(mCtx, file)) {\n            throw new ServerApiIllegalArgumentException(\"file '\" + file\n                    + \"' must refer to a file that exists and that is readable by stack!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer file \" + file + \" to \" + contact + \" (fileIcon=\"\n                    + attachFileIcon + \")\");\n        }\n        try {\n            Uri localFile = FileUtils.createCopyOfSentFile(file, mRcsSettings);\n            FileDescription fileDescription = FileFactory.getFactory()\n                    .getFileDescription(localFile);\n            String mime = FileUtils.getMimeType(localFile);\n            MmContent fileIconContent = null;\n            final MmContent content = ContentManager.createMmContent(localFile, mime,\n                    fileDescription.getSize(), fileDescription.getName());\n            if (Disposition.RENDER == Disposition.valueOf(disposition)) {\n                content.setPlayable(true);\n            }\n            final String fileTransferId = IdGenerator.generateMessageID();\n            if (attachFileIcon && MimeManager.isImageType(content.getEncoding())) {\n                fileIconContent = FileTransferUtils.createFileicon(localFile, fileTransferId,\n                        mRcsSettings);\n            }\n            final long timestamp = System.currentTimeMillis();\n            /* For outgoing file transfer, timestampSent = timestamp */\n            final long timestampSent = timestamp;\n            /* Always insert with State QUEUED */\n            addOutgoingOneToOneFileTransfer(fileTransferId, contact, content, fileIconContent,\n                    State.QUEUED, timestamp, timestampSent);\n\n            OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(fileTransferId);\n            mImService.tryToDequeueFileTransfers();\n            return oneToOneFileTransfer;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to initiate file transfer to the group chat specified by the\n     * chatId parameter, else returns false.\n     * \n     * @param chatId the chat ID\n     * @return boolean\n     * @throws RemoteException\n     */\n    public boolean isAllowedToTransferFileToGroupChat(String chatId) throws RemoteException {\n        if (TextUtils.isEmpty(chatId)) {\n            throw new ServerApiIllegalArgumentException(\"chatId must not be null or empty!\");\n        }\n        try {\n            if (!mRcsSettings.isGroupChatActivated()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot transfer file to group chat with group chat Id '\"\n                            + chatId + \"' as group chat feature is not supported.\");\n                }\n                return false;\n            }\n            if (!mRcsSettings.getMyCapabilities().isFileTransferHttpSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot transfer file to group chat with group chat Id '\"\n                            + chatId + \"' as FT over HTTP capabilities are not supported for self.\");\n                }\n                return false;\n            }\n            if (mChatService.isGroupChatAbandoned(chatId)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot transfer file to group chat with group chat Id '\"\n                            + chatId\n                            + \"' as the group chat is abandoned and can no more be used to send or receive messages.\");\n                }\n                return false;\n            }\n            GroupChatSession session = mImService.getGroupChatSession(chatId);\n            if (session == null) {\n                GroupChatInfo groupChat = mMessagingLog.getGroupChatInfo(chatId);\n                if (groupChat == null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot transfer file to group chat with group chat Id '\"\n                                + chatId + \"' as the group chat does not exist in DB.\");\n                    }\n                    return false;\n                }\n                if (groupChat.getRejoinId() == null) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot transfer file to group chat with group chat Id '\"\n                                + chatId\n                                + \"' as there is no ongoing session with corresponding chatId and there exists no rejoinId to rejoin the group chat.\");\n                    }\n                    return false;\n                }\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Dequeue group file transfer\n     * \n     * @param fileTransferId the file transfer ID\n     * @param content the file content\n     * @param fileIcon the file icon content\n     * @param chatId the chat ID\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws SessionNotEstablishedException\n     */\n    public void dequeueGroupFileTransfer(String chatId, String fileTransferId, MmContent content,\n            MmContent fileIcon) throws PayloadException, NetworkException,\n            SessionNotEstablishedException {\n        GroupChatSession groupChatSession = mImService.getGroupChatSession(chatId);\n        if (groupChatSession == null) {\n            mImService.rejoinGroupChatAsPartOfSendOperation(chatId);\n        } else if (groupChatSession.isMediaEstablished()) {\n            long timestamp = System.currentTimeMillis();\n            /* For outgoing file transfer, timestampSent = timestamp */\n            long timestampSent = timestamp;\n            FileSharingSession session = mImService.createGroupFileTransferSession(fileTransferId,\n                    content, fileIcon, chatId, timestamp);\n            GroupFileTransferImpl groupFileTransfer = getOrCreateGroupFileTransfer(chatId,\n                    fileTransferId);\n            session.addListener(groupFileTransfer);\n            setGroupFileTransferStateAndTimestamp(fileTransferId, chatId, State.INITIATING,\n                    timestamp, timestampSent);\n            session.startSession();\n        } else if (groupChatSession.isInitiatedByRemote()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Group chat session with chatId '\" + chatId\n                        + \"' is pending for acceptance, accept it.\");\n            }\n            groupChatSession.acceptSession();\n        } else {\n            throw new SessionNotEstablishedException(\n                    \"The existing group chat session with chatId '\" + chatId\n                            + \"' is not established right now!\");\n        }\n    }\n\n    /**\n     * Transfers a file to participants. The parameter file contains the URI of the file to be\n     * transferred (for a local or a remote file).\n     * \n     * @param chatId ChatId of group chat\n     * @param file Uri of file to transfer\n     * @param attachFileIcon true if the stack must try to attach fileIcon\n     * @return FileTransfer\n     * @throws RemoteException\n     */\n    @Override\n    public IFileTransfer transferFileToGroupChat(final String chatId, Uri file,\n            boolean attachFileIcon) throws RemoteException {\n        return transferFileToGroupChat2(chatId, file, Disposition.ATTACH.toInt(), attachFileIcon);\n    }\n\n    /**\n     * Transfers a file to participants. The parameter file contains the URI of the file to be\n     * transferred (for a local or a remote file).\n     *\n     * @param chatId ChatId of group chat\n     * @param file Uri of file to transfer\n     * @param disposition File disposition\n     * @param attachFileIcon true if the stack must try to attach fileIcon\n     * @return FileTransfer\n     * @throws RemoteException\n     */\n    @Override\n    public IFileTransfer transferFileToGroupChat2(final String chatId, Uri file, int disposition,\n            boolean attachFileIcon) throws RemoteException {\n        if (TextUtils.isEmpty(chatId)) {\n            throw new ServerApiIllegalArgumentException(\"chatId must not be null or empty!\");\n        }\n        if (file == null) {\n            throw new ServerApiIllegalArgumentException(\"file must not be null!\");\n        }\n        if (!FileUtils.isReadFromUriPossible(mCtx, file)) {\n            throw new ServerApiIllegalArgumentException(\"file '\" + file.toString()\n                    + \"' must refer to a file that exists and that is readable by stack!\");\n        }\n        if (!isAllowedToTransferFileToGroupChat(chatId)) {\n            throw new ServerApiPermissionDeniedException(\n                    \"No sufficient capabilities to transfer file to group chat!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"sendFile (file=\" + file + \") (fileicon=\" + attachFileIcon + \")\");\n        }\n        try {\n            Uri localFile = FileUtils.createCopyOfSentFile(file, mRcsSettings);\n            FileDescription fileDescription = FileFactory.getFactory()\n                    .getFileDescription(localFile);\n            String mime = FileUtils.getMimeType(localFile);\n            final MmContent content = ContentManager.createMmContent(localFile, mime,\n                    fileDescription.getSize(), fileDescription.getName());\n            if (Disposition.valueOf(disposition) == Disposition.RENDER) {\n                content.setPlayable(true);\n            }\n            final String fileTransferId = IdGenerator.generateMessageID();\n            MmContent fileIconContent = null;\n            if (attachFileIcon && MimeManager.isImageType(content.getEncoding())) {\n                fileIconContent = FileTransferUtils.createFileicon(content.getUri(),\n                        fileTransferId, mRcsSettings);\n            }\n            final long timestamp = System.currentTimeMillis();\n            /* For outgoing file transfer, timestampSent = timestamp */\n            /* Always insert file transfer with status QUEUED */\n            addOutgoingGroupFileTransfer(fileTransferId, chatId, content, fileIconContent,\n                    State.QUEUED, timestamp, timestamp);\n            if (!mChatService.isGroupChatActive(chatId)) {\n                /*\n                 * Set inactive group chat as active as it now has a queued entry that has to be\n                 * dequeued after rejoining to the group chat on regaining IMS connection.\n                 */\n                mChatService.setGroupChatStateAndReasonCode(chatId, GroupChat.State.STARTED,\n                        GroupChat.ReasonCode.UNSPECIFIED);\n            }\n\n            GroupFileTransferImpl groupFileTransfer = getOrCreateGroupFileTransfer(chatId,\n                    fileTransferId);\n            mImService.tryToDequeueGroupChatMessagesAndGroupFileTransfers(chatId);\n            return groupFileTransfer;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current file transfer from its unique ID\n     * \n     * @param transferId the file transfer ID\n     * @return File transfer\n     * @throws RemoteException\n     */\n    @Override\n    public IFileTransfer getFileTransfer(String transferId) throws RemoteException {\n        if (TextUtils.isEmpty(transferId)) {\n            throw new ServerApiIllegalArgumentException(\"transferId must not be null or empty!\");\n        }\n        try {\n            IFileTransfer fileTransfer = mOneToOneFileTransferCache.get(transferId);\n            if (fileTransfer != null) {\n                return fileTransfer;\n            }\n\n            fileTransfer = mGroupFileTransferCache.get(transferId);\n            if (fileTransfer != null) {\n                return fileTransfer;\n            }\n            // FIXME: This is not fully thread safe\n            if (mMessagingLog.isGroupFileTransfer(transferId)) {\n                String chatId = mMessagingLog.getFileTransferChatId(transferId);\n                return getOrCreateGroupFileTransfer(chatId, transferId);\n            }\n            // FIXME: This is not entirely correct... If there is no o2o ft in db matching this\n            // transferId a ServerApiIllegalArgumentException should be thrown from here.\n            return getOrCreateOneToOneFileTransfer(transferId);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on file transfer events\n     * \n     * @param listener OneToOne file transfer listener\n     * @throws RemoteException\n     */\n    @Override\n    public void addEventListener2(IOneToOneFileTransferListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mOneToOneFileTransferBroadcaster.addOneToOneFileTransferListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on file transfer events\n     * \n     * @param listener OneToOne file transfer listener\n     * @throws RemoteException\n     */\n    @Override\n    public void removeEventListener2(IOneToOneFileTransferListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mOneToOneFileTransferBroadcaster.removeOneToOneFileTransferListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on group file transfer events\n     * \n     * @param listener Group file transfer listener\n     * @throws RemoteException\n     */\n    @Override\n    public void addEventListener3(IGroupFileTransferListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mGroupFileTransferBroadcaster.addGroupFileTransferListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on group file transfer events\n     * \n     * @param listener Group file transfer listener\n     * @throws RemoteException\n     */\n    @Override\n    public void removeEventListener3(IGroupFileTransferListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mGroupFileTransferBroadcaster.removeGroupFileTransferListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * File Transfer delivery status. In FToHTTP, Delivered status is done just after download\n     * information are received by the terminating, and Displayed status is done when the file is\n     * downloaded. In FToMSRP, the two status are directly done just after MSRP transfer complete.\n     * \n     * @param imdn Imdn document\n     * @param contact contact who received file\n     */\n    public void receiveOneToOneFileDeliveryStatus(ImdnDocument imdn, ContactId contact) {\n        ImdnDocument.DeliveryStatus status = imdn.getStatus();\n        long timestamp = imdn.getDateTime();\n        /* Note: File transfer ID always corresponds to message ID in the imdn pay-load */\n        String fileTransferId = imdn.getMsgId();\n        switch (status) {\n            case DELIVERED:\n                mImService.getDeliveryExpirationManager()\n                        .cancelDeliveryTimeoutAlarm(fileTransferId);\n                if (mMessagingLog.setFileTransferDelivered(fileTransferId, timestamp)) {\n                    mOneToOneFileTransferBroadcaster.broadcastStateChanged(contact, fileTransferId,\n                            State.DELIVERED, ReasonCode.UNSPECIFIED);\n                }\n\n                break;\n            case DISPLAYED:\n                mImService.getDeliveryExpirationManager()\n                        .cancelDeliveryTimeoutAlarm(fileTransferId);\n                if (mMessagingLog.setFileTransferDisplayed(fileTransferId, timestamp)) {\n                    mOneToOneFileTransferBroadcaster.broadcastStateChanged(contact, fileTransferId,\n                            State.DISPLAYED, ReasonCode.UNSPECIFIED);\n                }\n\n                break;\n            case ERROR:\n            case FAILED:\n            case FORBIDDEN:\n                ReasonCode reasonCode = imdnToFileTransferFailedReasonCode(imdn);\n\n                if (mMessagingLog.setFileTransferStateAndReasonCode(fileTransferId, State.FAILED,\n                        reasonCode)) {\n                    mOneToOneFileTransferBroadcaster.broadcastStateChanged(contact, fileTransferId,\n                            State.FAILED, reasonCode);\n                }\n                break;\n        }\n    }\n\n    private void setGroupFileDeliveryStatusDelivered(String chatId, String fileTransferId,\n            ContactId contact, long timestampDelivered) {\n        if (mMessagingLog.setGroupChatDeliveryInfoDelivered(chatId, contact, fileTransferId,\n                timestampDelivered)) {\n            mGroupFileTransferBroadcaster.broadcastDeliveryInfoChanged(chatId, contact,\n                    fileTransferId, GroupDeliveryInfo.Status.DELIVERED,\n                    GroupDeliveryInfo.ReasonCode.UNSPECIFIED);\n            if (mMessagingLog.isDeliveredToAllRecipients(fileTransferId)) {\n                if (mMessagingLog.setFileTransferDelivered(fileTransferId, timestampDelivered)) {\n                    mGroupFileTransferBroadcaster.broadcastStateChanged(chatId, fileTransferId,\n                            State.DELIVERED, ReasonCode.UNSPECIFIED);\n                }\n            }\n        }\n    }\n\n    private void setGroupFileDeliveryStatusDisplayed(String chatId, String fileTransferId,\n            ContactId contact, long timestampDisplayed) {\n        if (mMessagingLog.setGroupChatDeliveryInfoDisplayed(chatId, contact, fileTransferId,\n                timestampDisplayed)) {\n            mGroupFileTransferBroadcaster.broadcastDeliveryInfoChanged(chatId, contact,\n                    fileTransferId, GroupDeliveryInfo.Status.DISPLAYED,\n                    GroupDeliveryInfo.ReasonCode.UNSPECIFIED);\n            if (mMessagingLog.isDisplayedByAllRecipients(fileTransferId)) {\n                if (mMessagingLog.setFileTransferDisplayed(fileTransferId, timestampDisplayed)) {\n                    mGroupFileTransferBroadcaster.broadcastStateChanged(chatId, fileTransferId,\n                            State.DISPLAYED, ReasonCode.UNSPECIFIED);\n                }\n            }\n        }\n    }\n\n    private void setGroupFileDeliveryStatusFailed(String chatId, String fileTransferId,\n            ContactId contact, ReasonCode reasonCode) {\n        if (ReasonCode.FAILED_DELIVERY == reasonCode) {\n            if (!mMessagingLog.setGroupChatDeliveryInfoStatusAndReasonCode(chatId, contact,\n                    fileTransferId, GroupDeliveryInfo.Status.FAILED,\n                    GroupDeliveryInfo.ReasonCode.FAILED_DELIVERY)) {\n                /* Add entry with delivered and displayed timestamps set to 0. */\n                mMessagingLog.addGroupChatDeliveryInfoEntry(chatId, contact, fileTransferId,\n                        GroupDeliveryInfo.Status.FAILED,\n                        GroupDeliveryInfo.ReasonCode.FAILED_DELIVERY, 0, 0);\n            }\n            mGroupFileTransferBroadcaster.broadcastDeliveryInfoChanged(chatId, contact,\n                    fileTransferId, GroupDeliveryInfo.Status.FAILED,\n                    GroupDeliveryInfo.ReasonCode.FAILED_DELIVERY);\n            return;\n        }\n        if (!mMessagingLog.setGroupChatDeliveryInfoStatusAndReasonCode(chatId, contact,\n                fileTransferId, GroupDeliveryInfo.Status.FAILED,\n                GroupDeliveryInfo.ReasonCode.FAILED_DISPLAY)) {\n            /* Add entry with delivered and displayed timestamps set to 0. */\n            mMessagingLog.addGroupChatDeliveryInfoEntry(chatId, contact, fileTransferId,\n                    GroupDeliveryInfo.Status.FAILED, GroupDeliveryInfo.ReasonCode.FAILED_DISPLAY,\n                    0, 0);\n        }\n        mGroupFileTransferBroadcaster.broadcastDeliveryInfoChanged(chatId, contact, fileTransferId,\n                GroupDeliveryInfo.Status.FAILED, GroupDeliveryInfo.ReasonCode.FAILED_DISPLAY);\n    }\n\n    /**\n     * Handles group file transfer delivery status.\n     * \n     * @param chatId Chat ID\n     * @param imdn Imdn Document\n     * @param contact Contact ID\n     */\n    public void receiveGroupFileDeliveryStatus(String chatId, ImdnDocument imdn, ContactId contact) {\n        ImdnDocument.DeliveryStatus status = imdn.getStatus();\n        String msgId = imdn.getMsgId();\n        long timestamp = imdn.getDateTime();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Handling group file delivery status; contact=\" + contact + \", msgId=\"\n                    + msgId + \", status=\" + status + \", notificationType=\"\n                    + imdn.getNotificationType());\n        }\n        switch (status) {\n            case DELIVERED:\n                setGroupFileDeliveryStatusDelivered(chatId, msgId, contact, timestamp);\n                break;\n            case DISPLAYED:\n                setGroupFileDeliveryStatusDisplayed(chatId, msgId, contact, timestamp);\n                break;\n            case ERROR:\n            case FAILED:\n            case FORBIDDEN:\n                ReasonCode reasonCode = imdnToFileTransferFailedReasonCode(imdn);\n                setGroupFileDeliveryStatusFailed(chatId, msgId, contact, reasonCode);\n                break;\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Resume an outgoing HTTP file transfer\n     * \n     * @param session File transfer session\n     * @param isGroup is group file transfer\n     */\n    public void resumeOutgoingFileTransfer(FileSharingSession session, boolean isGroup) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Resume outgoing file transfer from \" + session.getRemoteContact());\n        }\n        if (isGroup) {\n            GroupFileTransferImpl groupFileTransfer = getOrCreateGroupFileTransfer(\n                    session.getContributionID(), session.getFileTransferId());\n            session.addListener(groupFileTransfer);\n        } else {\n            OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(session\n                    .getFileTransferId());\n            session.addListener(oneToOneFileTransfer);\n        }\n    }\n\n    /**\n     * Resume an incoming HTTP file transfer\n     * \n     * @param session File transfer session\n     * @param isGroup is group file transfer\n     */\n    public void resumeIncomingFileTransfer(FileSharingSession session, boolean isGroup) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Resume incoming file transfer from \" + session.getRemoteContact());\n        }\n        if (isGroup) {\n            GroupFileTransferImpl groupFileTransfer = getOrCreateGroupFileTransfer(\n                    session.getContributionID(), session.getFileTransferId());\n            session.addListener(groupFileTransfer);\n        } else {\n            OneToOneFileTransferImpl oneToOneFileTransfer = getOrCreateOneToOneFileTransfer(session\n                    .getFileTransferId());\n            session.addListener(oneToOneFileTransfer);\n        }\n    }\n\n    /**\n     * Mark a received file transfer as read (i.e. the invitation or the file has been displayed in\n     * the UI).\n     * \n     * @param transferId File transfer ID\n     * @throws RemoteException\n     */\n    @Override\n    public void markFileTransferAsRead(final String transferId) throws RemoteException {\n        if (TextUtils.isEmpty(transferId)) {\n            throw new ServerApiIllegalArgumentException(\"transferId must not be null or empty!\");\n        }\n        try {\n            /* No notification type corresponds currently to mark as read */\n            mMessagingLog.markFileTransferAsRead(transferId, System.currentTimeMillis());\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all one to one file transfer history and abort/reject any associated ongoing session\n     * if such exists.\n     * \n     * @throws RemoteException\n     */\n    public void deleteOneToOneFileTransfers() throws RemoteException {\n        mImService.tryToDeleteOneToOneFileTransfers();\n    }\n\n    /**\n     * Deletes all group file transfer from history and abort/reject any associated ongoing session\n     * if such exists.\n     * \n     * @throws RemoteException\n     */\n    public void deleteGroupFileTransfers() throws RemoteException {\n        mImService.tryToDeleteGroupFileTransfers();\n    }\n\n    /**\n     * Deletes file transfer corresponding to a given one to one chat specified by contact from\n     * history and abort/reject any associated ongoing session if such exists.\n     * \n     * @param contact the contact\n     * @throws RemoteException\n     */\n    public void deleteOneToOneFileTransfers2(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        mImService.tryToDeleteFileTransfers(contact);\n    }\n\n    /**\n     * Deletes file transfer corresponding to a given group chat specified by chat id from history\n     * and abort/reject any associated ongoing session if such exists.\n     * \n     * @param chatId the chat ID\n     * @throws RemoteException\n     */\n    public void deleteGroupFileTransfers2(String chatId) throws RemoteException {\n        if (TextUtils.isEmpty(chatId)) {\n            throw new ServerApiIllegalArgumentException(\"chatId must not be null or empty!\");\n        }\n        mImService.tryToDeleteGroupChat(chatId);\n    }\n\n    /**\n     * Deletes a file transfer by its unique id from history and abort/reject any associated ongoing\n     * session if such exists.\n     * \n     * @param transferId the file transfer ID\n     * @throws RemoteException\n     */\n    public void deleteFileTransfer(String transferId) throws RemoteException {\n        if (TextUtils.isEmpty(transferId)) {\n            throw new ServerApiIllegalArgumentException(\"transferId must not be null or empty!\");\n        }\n        mImService.tryToDeleteFileTransfer(transferId);\n    }\n\n    /**\n     * Disables and clears any delivery expiration for a set of file transfers regardless if the\n     * delivery of them has expired already or not.\n     * \n     * @param transferIds the file transfer IDs\n     * @throws RemoteException\n     */\n    @Override\n    public void clearFileTransferDeliveryExpiration(final List<String> transferIds)\n            throws RemoteException {\n        if (transferIds == null || transferIds.isEmpty()) {\n            throw new ServerApiIllegalArgumentException(\n                    \"transferId list must not be null or empty!\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    for (String transferId : transferIds) {\n                        mImService.getDeliveryExpirationManager().cancelDeliveryTimeoutAlarm(\n                                transferId);\n                    }\n                    mMessagingLog.clearFileTransferDeliveryExpiration(transferIds);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to mark message as read!\", e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Add and broadcast file transfer invitation rejections\n     * \n     * @param contact Contact\n     * @param content File content\n     * @param fileIcon File content\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp when got invitation\n     * @param timestampSent Timestamp sent in payload for the file transfer\n     */\n    public void addFileTransferInvitationRejected(ContactId contact, MmContent content,\n            MmContent fileIcon, ReasonCode reasonCode, long timestamp, long timestampSent) {\n        String fileTransferId = IdGenerator.generateMessageID();\n        mMessagingLog.addOneToOneFileTransfer(fileTransferId, contact, Direction.INCOMING, content,\n                fileIcon, State.REJECTED, reasonCode, timestamp, timestampSent,\n                FileTransferData.UNKNOWN_EXPIRATION, FileTransferData.UNKNOWN_EXPIRATION);\n\n        mOneToOneFileTransferBroadcaster.broadcastInvitation(fileTransferId);\n    }\n\n    /**\n     * Set and broadcast resend file transfer invitation rejections\n     * \n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp when got invitation\n     * @param timestampSent Timestamp sent in payload for the file transfer\n     */\n    public void setResendFileTransferInvitationRejected(String fileTransferId,\n            ReasonCode reasonCode, long timestamp, long timestampSent) {\n        mMessagingLog.setFileTransferStateAndTimestamp(fileTransferId, State.REJECTED, reasonCode,\n                timestamp, timestampSent);\n\n        mOneToOneFileTransferBroadcaster.broadcastInvitation(fileTransferId);\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Set one-one file transfer state and reason code\n     * \n     * @param fileTransferId the file transfer ID\n     * @param contact the contact\n     * @param state the file transfer state\n     * @param reasonCode the reason code\n     */\n    public void setOneToOneFileTransferStateAndReasonCode(String fileTransferId, ContactId contact,\n            State state, ReasonCode reasonCode) {\n        if (mMessagingLog.setFileTransferStateAndReasonCode(fileTransferId, state, reasonCode)) {\n            mOneToOneFileTransferBroadcaster.broadcastStateChanged(contact, fileTransferId, state,\n                    reasonCode);\n        }\n    }\n\n    /**\n     * Set group file transfer state and reason code\n     * \n     * @param fileTransferId the file transfer ID\n     * @param chatId the chat ID\n     * @param state the file transfer state\n     * @param reasonCode the reason code\n     */\n    public void setGroupFileTransferStateAndReasonCode(String fileTransferId, String chatId,\n            State state, ReasonCode reasonCode) {\n        if (mMessagingLog.setFileTransferStateAndReasonCode(fileTransferId, state, reasonCode)) {\n            mGroupFileTransferBroadcaster.broadcastStateChanged(chatId, fileTransferId, state,\n                    reasonCode);\n        }\n    }\n\n    public void broadcastOneToOneFileTransferDeleted(ContactId contact, Set<String> transferIds) {\n        mOneToOneFileTransferBroadcaster.broadcastFileTransferDeleted(contact, transferIds);\n    }\n\n    public void broadcastGroupFileTransfersDeleted(String chatId, Set<String> transferIds) {\n        mGroupFileTransferBroadcaster.broadcastFileTransfersDeleted(chatId, transferIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/FileUploadImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpThumbnail;\nimport com.gsma.rcs.core.ims.service.upload.FileUploadSession;\nimport com.gsma.rcs.core.ims.service.upload.FileUploadSessionListener;\nimport com.gsma.rcs.service.broadcaster.IFileUploadEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.upload.FileUpload;\nimport com.gsma.services.rcs.upload.FileUpload.State;\nimport com.gsma.services.rcs.upload.FileUploadInfo;\nimport com.gsma.services.rcs.upload.IFileUpload;\n\nimport android.net.Uri;\nimport android.os.RemoteException;\n\n/**\n * File upload implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileUploadImpl extends IFileUpload.Stub implements FileUploadSessionListener {\n\n    private final String mUploadId;\n\n    private final IFileUploadEventBroadcaster mBroadcaster;\n\n    private final InstantMessagingService mImService;\n\n    private final FileUploadServiceImpl mFileUploadService;\n\n    private final FileUploadStorageAccessor mPersistedStorage;\n\n    private final Object mLock = new Object();\n\n    private final Logger mLogger = Logger.getLogger(getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param uploadId Unique ID of FileUpload\n     * @param broadcaster Event broadcaster\n     * @param imService InstantMessagingService\n     * @param fileUploadService FileUploadServiceImpl\n     * @param file the URI of file to upload\n     */\n    public FileUploadImpl(String uploadId, IFileUploadEventBroadcaster broadcaster,\n            InstantMessagingService imService, FileUploadServiceImpl fileUploadService, Uri file) {\n        mUploadId = uploadId;\n        mBroadcaster = broadcaster;\n        mImService = imService;\n        mFileUploadService = fileUploadService;\n        mPersistedStorage = new FileUploadStorageAccessor(file, State.INITIATING);\n    }\n\n    /**\n     * Returns the upload ID of the upload\n     * \n     * @return Upload ID\n     * @throws RemoteException\n     */\n    public String getUploadId() throws RemoteException {\n        try {\n            return mUploadId;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns info related to upload file\n     * \n     * @return Upload info or null if not yet uploaded or in case of error\n     * @throws RemoteException\n     * @see FileUploadInfo\n     */\n    public FileUploadInfo getUploadInfo() throws RemoteException {\n        try {\n            FileUploadSession session = mImService.getFileUploadSession(mUploadId);\n            FileTransferHttpInfoDocument file;\n            if (session == null) {\n                return mPersistedStorage.getInfo();\n            }\n            if ((file = session.getFileInfoDocument()) == null) {\n                return null;\n            }\n            return createFileUploadInfo(file);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the URI of the file to upload\n     * \n     * @return the file URI\n     * @throws RemoteException\n     */\n    public Uri getFile() throws RemoteException {\n        try {\n            FileUploadSession session = mImService.getFileUploadSession(mUploadId);\n            if (session == null) {\n                return mPersistedStorage.getFile();\n            }\n            return session.getContent().getUri();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the file upload\n     * \n     * @return State\n     * @throws RemoteException\n     */\n    public int getState() throws RemoteException {\n        try {\n            FileUploadSession session = mImService.getFileUploadSession(mUploadId);\n            if (session == null) {\n                return mPersistedStorage.getState().toInt();\n            }\n            synchronized (mLock) {\n                if (FileUploadSession.State.PENDING == session.getSessionState()) {\n                    return FileUpload.State.INITIATING.toInt();\n                }\n                return FileUpload.State.STARTED.toInt();\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the upload\n     * \n     * @throws RemoteException\n     */\n    public void abortUpload() throws RemoteException {\n        try {\n            if (mLogger.isActivated()) {\n                mLogger.info(\"Cancel session\");\n            }\n            final FileUploadSession session = mImService.getFileUploadSession(mUploadId);\n            if (session == null) {\n                throw new ServerApiGenericException(new StringBuilder(\n                        \"Cannot cancel session with ID= \").append(mUploadId).toString());\n            }\n            session.interrupt();\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    private FileUploadInfo createFileUploadInfo(FileTransferHttpInfoDocument file) {\n        FileTransferHttpThumbnail fileicon = file.getFileThumbnail();\n        if (fileicon != null) {\n            return new FileUploadInfo(file.getUri(), file.getExpiration(), file.getFilename(),\n                    file.getSize(), file.getMimeType(), fileicon.getUri(),\n                    fileicon.getExpiration(), fileicon.getSize(), fileicon.getMimeType());\n        }\n        return new FileUploadInfo(file.getUri(), file.getExpiration(), file.getFilename(),\n                file.getSize(), file.getMimeType());\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    private void setState(FileUpload.State state) {\n        mPersistedStorage.setState(state);\n        mBroadcaster.broadcastStateChanged(mUploadId, state);\n    }\n\n    /**\n     * Upload started\n     */\n    public void handleUploadStarted() {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"File upload started\");\n        }\n        synchronized (mLock) {\n            setState(FileUpload.State.STARTED);\n        }\n    }\n\n    /**\n     * Upload progress\n     * \n     * @param currentSize Data size transfered\n     * @param totalSize Total size to be transfered\n     */\n    public void handleUploadProgress(long currentSize, long totalSize) {\n        synchronized (mLock) {\n            mBroadcaster.broadcastProgressUpdate(mUploadId, currentSize, totalSize);\n        }\n    }\n\n    private void setStateAndInfoThenBroadcast(String uploadId, FileUpload.State state,\n            FileUploadInfo info) {\n        mPersistedStorage.setInfo(info);\n        setState(state);\n        mBroadcaster.broadcastUploaded(uploadId, info);\n    }\n\n    /**\n     * Upload terminated with success\n     * \n     * @param info File info document\n     */\n    public void handleUploadTerminated(FileTransferHttpInfoDocument info) {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"File upload terminated\");\n        }\n        synchronized (mLock) {\n            mFileUploadService.removeFileUpload(mUploadId);\n            setStateAndInfoThenBroadcast(mUploadId, FileUpload.State.TRANSFERRED,\n                    createFileUploadInfo(info));\n\n        }\n    }\n\n    /**\n     * Upload error\n     * \n     * @param error Error\n     */\n    public void handleUploadError(int error) {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"File upload failed\");\n        }\n        synchronized (mLock) {\n            mFileUploadService.removeFileUpload(mUploadId);\n            setState(FileUpload.State.FAILED);\n        }\n    }\n\n    /**\n     * Upload aborted\n     */\n    public void handleUploadAborted() {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"File upload aborted\");\n        }\n        synchronized (mLock) {\n            mFileUploadService.removeFileUpload(mUploadId);\n            setState(FileUpload.State.ABORTED);\n        }\n    }\n\n    @Override\n    public void handleUploadNotAllowedToSend() {\n        if (mLogger.isActivated()) {\n            mLogger.debug(\"File upload not allowed\");\n        }\n        synchronized (mLock) {\n            mFileUploadService.removeFileUpload(mUploadId);\n            setState(FileUpload.State.FAILED);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/FileUploadServiceConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.upload.IFileUploadServiceConfiguration;\n\nimport android.os.RemoteException;\n\n/**\n * A class that implements interface to allow access to file upload service configuration from API\n * \n * @author yplo6403\n */\npublic class FileUploadServiceConfigurationImpl extends IFileUploadServiceConfiguration.Stub {\n\n    private final RcsSettings mRcsSettings;\n\n    private final Logger mLogger = Logger.getLogger(getClass().getName());\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings RCS settings accessor\n     */\n    public FileUploadServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public long getMaxSize() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxImageSharingSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/FileUploadServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.upload.FileUploadSession;\nimport com.gsma.rcs.platform.file.FileDescription;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.broadcaster.FileUploadEventBroadcaster;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.upload.IFileUpload;\nimport com.gsma.services.rcs.upload.IFileUploadListener;\nimport com.gsma.services.rcs.upload.IFileUploadService;\nimport com.gsma.services.rcs.upload.IFileUploadServiceConfiguration;\n\nimport android.net.Uri;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * File upload service implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileUploadServiceImpl extends IFileUploadService.Stub {\n\n    private final FileUploadEventBroadcaster mBroadcaster = new FileUploadEventBroadcaster();\n\n    private final InstantMessagingService mImService;\n\n    private final Map<String, IFileUpload> mFileUploadCache = new HashMap<>();\n\n    private static final Logger sLogger = Logger.getLogger(FileUploadServiceImpl.class\n            .getSimpleName());\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object lock = new Object();\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param imService InstantMessagingService\n     * @param rcsSettings RCS settings accessor\n     */\n    public FileUploadServiceImpl(InstantMessagingService imService, RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"File upload service API is loaded\");\n        }\n        mImService = imService;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        mFileUploadCache.clear();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"File upload service API is closed\");\n        }\n    }\n\n    /**\n     * Add a file upload in the list\n     * \n     * @param filUpload File upload\n     */\n    private void addFileUpload(String sessionId, FileUploadImpl filUpload) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add a file upload in the list (size=\" + mFileUploadCache.size() + \")\");\n        }\n        mFileUploadCache.put(sessionId, filUpload);\n    }\n\n    /**\n     * Remove a file upload from the list\n     * \n     * @param sessionId Upload ID\n     */\n    /* package private */void removeFileUpload(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a file upload from the list (size=\" + mFileUploadCache.size()\n                    + \")\");\n        }\n        mFileUploadCache.remove(sessionId);\n    }\n\n    /**\n     * Returns the configuration of the file upload service\n     * \n     * @return Configuration\n     * @throws RemoteException\n     */\n    public IFileUploadServiceConfiguration getConfiguration() throws RemoteException {\n        try {\n            return new FileUploadServiceConfigurationImpl(mRcsSettings);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     *\n     * @return Returns true if registered else returns false\n     */\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Uploads a file to the RCS content server. The parameter file contains the URI of the file to\n     * be uploaded (for a local or a remote file).\n     * \n     * @param file Uri of file to upload\n     * @param fileicon File icon option. If true and if it's an image, a file icon is attached.\n     * @return File upload\n     * @throws RemoteException\n     */\n    public IFileUpload uploadFile(Uri file, boolean fileicon) throws RemoteException {\n        if (file == null) {\n            throw new ServerApiIllegalArgumentException(\"file must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a file upload session (thumbnail option \" + fileicon + \")\");\n        }\n        ServerApiUtils.testCore();\n        ServerApiUtils.testIms();\n\n        try {\n            FileDescription desc = FileFactory.getFactory().getFileDescription(file);\n            String mime = FileUtils.getMimeType(file);\n            MmContent content = ContentManager.createMmContent(file, mime, desc.getSize(),\n                    desc.getName());\n\n            mImService.assertFileSizeNotExceedingMaxLimit(content.getSize(),\n                    \"File exceeds max size.\");\n            mImService.assertAvailableFileTransferSession(\"Max file transfer sessions achieved.\");\n\n            final FileUploadSession session = new FileUploadSession(content, fileicon, mRcsSettings);\n            final FileUploadImpl fileUpload = new FileUploadImpl(session.getUploadID(),\n                    mBroadcaster, mImService, this, file);\n\n            final FileUploadServiceImpl fileUploadService = this;\n            mImService.scheduleImOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        if (!isServiceRegistered() || !mImService.isFileTransferSessionAvailable()) {\n                            sLogger.error(\"Failed initiate file upload right now!\");\n                        }\n                        session.addListener(fileUpload);\n                        fileUploadService.addFileUpload(session.getUploadID(), fileUpload);\n                        session.startSession();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed initiate file upload right now!\", e);\n                    }\n                }\n            });\n            return fileUpload;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Can a file be uploaded now\n     * \n     * @return Returns true if a file can be uploaded, else returns false\n     * @throws RemoteException\n     */\n    public boolean canUploadFile() throws RemoteException {\n        try {\n            if (!ServerApiUtils.isImsConnected()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot upload file now as IMS is not connected.\");\n                }\n                return false;\n            }\n            if (!mImService.isFileTransferSessionAvailable()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot upload file now as no sessions available.\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of file uploads in progress\n     * \n     * @return List of file uploads\n     * @throws RemoteException\n     */\n    public List<IBinder> getFileUploads() throws RemoteException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get file upload sessions\");\n        }\n        try {\n            List<IBinder> fileUploads = new ArrayList<>(mFileUploadCache.size());\n            for (IFileUpload fileUpload : mFileUploadCache.values()) {\n                fileUploads.add(fileUpload.asBinder());\n            }\n            return fileUploads;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current file upload from its unique ID\n     * \n     * @param uploadId session ID\n     * @return File upload\n     * @throws RemoteException\n     */\n    public IFileUpload getFileUpload(String uploadId) throws RemoteException {\n        if (TextUtils.isEmpty(uploadId)) {\n            throw new ServerApiIllegalArgumentException(\"uploadId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get file upload \".concat(uploadId));\n        }\n        try {\n            return mFileUploadCache.get(uploadId);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on file upload events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    public void addEventListener(IFileUploadListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add a file upload event listener\");\n        }\n        try {\n            synchronized (lock) {\n                mBroadcaster.addEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on file upload events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    public void removeEventListener(IFileUploadListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove a file upload event listener\");\n        }\n        try {\n            synchronized (lock) {\n                mBroadcaster.removeEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/FileUploadStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.upload.FileUpload.State;\nimport com.gsma.services.rcs.upload.FileUploadInfo;\n\nimport android.net.Uri;\n\n/**\n * FileUploadStorageAccessor helps in retrieving data related to a File upload.\n */\npublic class FileUploadStorageAccessor {\n\n    private final Uri mFile;\n\n    private FileUploadInfo mInfo;\n\n    private State mState;\n\n    /**\n     * Constructor\n     * \n     * @param file the file URI\n     * @param state State of the file upload\n     */\n    public FileUploadStorageAccessor(Uri file, State state) {\n        mFile = file;\n        mState = state;\n    }\n\n    /**\n     * Gets the file URI\n     * \n     * @return the file URI\n     */\n    public Uri getFile() {\n        return mFile;\n    }\n\n    /**\n     * Gets the information on the uploaded file\n     * \n     * @return the information on the uploaded file\n     */\n    public FileUploadInfo getInfo() {\n        return mInfo;\n    }\n\n    /**\n     * Sets the information of the uploaded file\n     * \n     * @param info the information of the uploaded file\n     */\n    public void setInfo(FileUploadInfo info) {\n        mInfo = info;\n    }\n\n    /**\n     * Gets the state of the file upload\n     * \n     * @return the state of the file upload\n     */\n    public State getState() {\n        return mState;\n    }\n\n    /**\n     * Sets the state of the file upload\n     * \n     * @param state the state of the file upload\n     */\n    public void setState(State state) {\n        mState = state;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/GeolocSharingImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.GeolocTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.GeolocTransferSessionListener;\nimport com.gsma.rcs.provider.sharing.GeolocSharingPersistedStorageAccessor;\nimport com.gsma.rcs.provider.sharing.GeolocSharingStateAndReasonCode;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.service.broadcaster.IGeolocSharingEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharing;\n\nimport android.os.RemoteException;\n\n/**\n * Geoloc sharing implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GeolocSharingImpl extends IGeolocSharing.Stub implements GeolocTransferSessionListener {\n\n    private final String mSharingId;\n\n    private final IGeolocSharingEventBroadcaster mBroadcaster;\n\n    private final RichcallService mRichcallService;\n\n    private final GeolocSharingPersistedStorageAccessor mPersistentStorage;\n\n    private final GeolocSharingServiceImpl mGeolocSharingService;\n\n    /**\n     * Lock used for synchronisation\n     */\n    private final Object mLock = new Object();\n\n    private final static Logger sLogger = Logger.getLogger(GeolocSharingImpl.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param sharingId Unique Id of Geoloc sharing\n     * @param broadcaster IGeolocSharingEventBroadcaster\n     * @param richcallService RichcallService\n     * @param geolocSharingService GeolocSharingServiceImpl\n     * @param persistedStorage GeolocSharing persisted storage\n     */\n    public GeolocSharingImpl(String sharingId, IGeolocSharingEventBroadcaster broadcaster,\n            RichcallService richcallService, GeolocSharingServiceImpl geolocSharingService,\n            GeolocSharingPersistedStorageAccessor persistedStorage) {\n        mSharingId = sharingId;\n        mBroadcaster = broadcaster;\n        mRichcallService = richcallService;\n        mGeolocSharingService = geolocSharingService;\n        mPersistentStorage = persistedStorage;\n    }\n\n    /**\n     * Returns the sharing ID of the geoloc sharing\n     * \n     * @return Sharing ID\n     * @throws RemoteException\n     */\n    public String getSharingId() throws RemoteException {\n        try {\n            return mSharingId;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Gets the geolocation\n     * \n     * @return Geolocation\n     * @throws RemoteException\n     */\n    public Geoloc getGeoloc() throws RemoteException {\n        try {\n            GeolocTransferSession session = mRichcallService.getGeolocTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getGeoloc();\n            }\n\n            return session.getGeoloc();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RemoteException\n     */\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            GeolocTransferSession session = mRichcallService.getGeolocTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the geoloc sharing\n     * \n     * @return State\n     * @throws RemoteException\n     */\n    public int getState() throws RemoteException {\n        try {\n            GeolocTransferSession session = mRichcallService.getGeolocTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getState().toInt();\n            }\n            if (session.isGeolocTransferred()) {\n                return State.TRANSFERRED.toInt();\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return State.STARTED.toInt();\n\n            } else if (session.isInitiatedByRemote()) {\n                if (session.isSessionAccepted()) {\n                    return State.ACCEPTING.toInt();\n                }\n                return State.INVITED.toInt();\n            }\n            return State.INITIATING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the geoloc sharing\n     * \n     * @return ReasonCode\n     * @throws RemoteException\n     */\n    public int getReasonCode() throws RemoteException {\n        try {\n            GeolocTransferSession session = mRichcallService.getGeolocTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getReasonCode().toInt();\n            }\n            return ReasonCode.UNSPECIFIED.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the sharing (incoming or outgoing)\n     * \n     * @return Direction\n     * @throws RemoteException\n     * @see Direction\n     */\n    public int getDirection() throws RemoteException {\n        try {\n            GeolocTransferSession session = mRichcallService.getGeolocTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the geoloc sharing was initiated for outgoing geoloc\n     * sharing or the local timestamp of when the geoloc sharing invitation was received for\n     * incoming geoloc sharings.\n     * \n     * @return long\n     * @throws RemoteException\n     */\n    public long getTimestamp() throws RemoteException {\n        try {\n            GeolocTransferSession session = mRichcallService.getGeolocTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getTimestamp();\n            }\n            return session.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts geoloc sharing invitation\n     * \n     * @throws RemoteException\n     */\n    public void acceptInvitation() throws RemoteException {\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Accept session invitation\");\n                    }\n                    final GeolocTransferSession session = mRichcallService\n                            .getGeolocTransferSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"Cannot accept sharing: no session with ID=\"\n                                .concat(mSharingId));\n                        return;\n                    }\n                    session.acceptSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\"Failed to accept invitation with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejects geoloc sharing invitation\n     * \n     * @throws RemoteException\n     */\n    public void rejectInvitation() throws RemoteException {\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Reject session invitation\");\n                    }\n                    final GeolocTransferSession session = mRichcallService\n                            .getGeolocTransferSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"Cannot reject sharing: no session with ID=\"\n                                .concat(mSharingId));\n                        return;\n                    }\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\"Failed to reject invitation with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Aborts the sharing\n     * \n     * @throws RemoteException\n     */\n    public void abortSharing() throws RemoteException {\n        mRichcallService.scheduleGeolocShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Abort session\");\n                    }\n                    final GeolocTransferSession session = mRichcallService\n                            .getGeolocTransferSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"No ongoing session with sharing ID:\" + mSharingId\n                                + \" is found so nothing to abort!\");\n                        return;\n                    }\n                    if (session.isGeolocTransferred()) {\n                        sLogger.debug(\"Session with sharing ID:\" + mSharingId\n                                + \" is already transferred so nothing to abort!\");\n                        return;\n                    }\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n\n                } catch (PayloadException e) {\n                    sLogger.error(\n                            new StringBuilder(\"Failed to terminate session with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\"Failed to terminate session with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                }\n            }\n        });\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    /*\n     * TODO : Fix reasoncode mapping in the switch.\n     */\n    private GeolocSharingStateAndReasonCode toStateAndReasonCode(ContentSharingError error) {\n        int contentSharingError = error.getErrorCode();\n        switch (contentSharingError) {\n            case ContentSharingError.SESSION_INITIATION_FAILED:\n            case ContentSharingError.SEND_RESPONSE_FAILED:\n                return new GeolocSharingStateAndReasonCode(State.FAILED,\n                        ReasonCode.FAILED_INITIATION);\n            case ContentSharingError.SESSION_INITIATION_CANCELLED:\n            case ContentSharingError.SESSION_INITIATION_DECLINED:\n                return new GeolocSharingStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_BY_REMOTE);\n            case ContentSharingError.MEDIA_SAVING_FAILED:\n            case ContentSharingError.MEDIA_TRANSFER_FAILED:\n            case ContentSharingError.MEDIA_STREAMING_FAILED:\n            case ContentSharingError.UNSUPPORTED_MEDIA_TYPE:\n                return new GeolocSharingStateAndReasonCode(State.FAILED, ReasonCode.FAILED_SHARING);\n            default:\n                throw new IllegalArgumentException(\n                        new StringBuilder(\n                                \"Unknown reason in GeolocSharingImpl.toStateAndReasonCode; contentSharingError=\")\n                                .append(contentSharingError).append(\"!\").toString());\n        }\n    }\n\n    private void setStateAndReasonCode(ContactId contact, State state, ReasonCode reasonCode) {\n        if (mPersistentStorage.setStateAndReasonCode(state, reasonCode)) {\n            mBroadcaster.broadcastStateChanged(contact, mSharingId, state, reasonCode);\n        }\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session rejected; reasonCode=\" + reasonCode + \".\");\n        }\n        synchronized (mLock) {\n            mGeolocSharingService.removeGeolocSharing(mSharingId);\n            setStateAndReasonCode(contact, State.REJECTED, reasonCode);\n        }\n    }\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session started.\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(new StringBuilder(\"Session aborted; reason=\").append(reason).append(\".\")\n                    .toString());\n        }\n        synchronized (mLock) {\n            mGeolocSharingService.removeGeolocSharing(mSharingId);\n            switch (reason) {\n                case TERMINATION_BY_TIMEOUT:\n                case TERMINATION_BY_SYSTEM:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    setStateAndReasonCode(contact, State.FAILED, ReasonCode.FAILED_SHARING);\n                    break;\n                case TERMINATION_BY_USER:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    /*\n                     * TODO : Fix sending of SIP BYE by sender once transfer is completed and media\n                     * session is closed. Then this check of state can be removed. Also need to\n                     * check if it is storing and broadcasting right state and reasoncode.\n                     */\n                    if (State.TRANSFERRED != mPersistentStorage.getState()) {\n                        setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    }\n                    break;\n                default:\n                    throw new IllegalArgumentException(new StringBuilder(\n                            \"Unknown reason ; sessionAbortedReason=\").append(reason).append(\"!\")\n                            .toString());\n            }\n        }\n    }\n\n    @Override\n    public void onSharingError(ContactId contact, ContentSharingError error) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(new StringBuilder(\"Sharing error \").append(error.getErrorCode())\n                    .append(\".\").toString());\n        }\n        GeolocSharingStateAndReasonCode stateAndReasonCode = toStateAndReasonCode(error);\n        State state = stateAndReasonCode.getState();\n        ReasonCode reasonCode = stateAndReasonCode.getReasonCode();\n        synchronized (mLock) {\n            mGeolocSharingService.removeGeolocSharing(mSharingId);\n            setStateAndReasonCode(contact, state, reasonCode);\n        }\n    }\n\n    @Override\n    public void onContentTransferred(ContactId contact, Geoloc geoloc, boolean initiatedByRemote) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Geoloc transferred.\");\n        }\n        synchronized (mLock) {\n            mGeolocSharingService.removeGeolocSharing(mSharingId);\n            if (initiatedByRemote) {\n                if (RichCallHistory.getInstance().setGeolocSharingTransferred(mSharingId, geoloc)) {\n                    mBroadcaster.broadcastStateChanged(contact, mSharingId, State.TRANSFERRED,\n                            ReasonCode.UNSPECIFIED);\n                }\n            } else {\n                if (mPersistentStorage.setStateAndReasonCode(State.TRANSFERRED,\n                        ReasonCode.UNSPECIFIED)) {\n                    mBroadcaster.broadcastStateChanged(contact, mSharingId, State.TRANSFERRED,\n                            ReasonCode.UNSPECIFIED);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Accepting sharing.\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER, contact);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM, contact);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT, contact);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE, contact);\n                break;\n            default:\n                throw new IllegalArgumentException(new StringBuilder(\n                        \"Unknown reason RejectedReason=\").append(reason).append(\"!\").toString());\n        }\n    }\n\n    @Override\n    public void onInvitationReceived(ContactId contact, long timestamp) {\n        synchronized (mLock) {\n            mPersistentStorage.addIncomingGeolocSharing(contact, State.INVITED,\n                    ReasonCode.UNSPECIFIED, timestamp);\n            mBroadcaster.broadcastInvitation(mSharingId);\n        }\n    }\n\n    @Override\n    public void onSessionRinging(ContactId contact) {\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.RINGING, ReasonCode.UNSPECIFIED);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/GeolocSharingServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.content.GeolocContent;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.service.SessionIdGenerator;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.geoloc.GeolocTransferSession;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.GeolocSharingPersistedStorageAccessor;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.service.broadcaster.GeolocSharingEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.IdGenerator;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharingListener;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharingService;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Geoloc sharing service implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GeolocSharingServiceImpl extends IGeolocSharingService.Stub {\n\n    private final GeolocSharingEventBroadcaster mBroadcaster = new GeolocSharingEventBroadcaster();\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final RichcallService mRichcallService;\n\n    private final RichCallHistory mRichcallLog;\n\n    private final Map<String, IGeolocSharing> mGeolocSharingCache = new HashMap<>();\n\n    private static final Logger sLogger = Logger.getLogger(GeolocSharingServiceImpl.class\n            .getSimpleName());\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * Constructor\n     * \n     * @param richcallService RichcallService\n     * @param rcsSettings Rcs settings accessor\n     * @param richCallHistory Richcall history log accessor\n     */\n    public GeolocSharingServiceImpl(RichcallService richcallService,\n            RichCallHistory richCallHistory, RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Geoloc sharing service API is loaded.\");\n        }\n        mRichcallService = richcallService;\n        mRichcallService.register(this);\n        mRichcallLog = richCallHistory;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        // Clear list of sessions\n        mGeolocSharingCache.clear();\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Geoloc sharing service API is closed\");\n        }\n    }\n\n    /**\n     * Add an geoloc sharing in the list\n     * \n     * @param geolocSharing Geoloc sharing\n     * @param sharingId String\n     */\n    private void addGeolocSharing(GeolocSharingImpl geolocSharing, String sharingId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(new StringBuilder(\"Add an geoloc sharing in the list (size=\")\n                    .append(mGeolocSharingCache.size()).append(\")\").toString());\n        }\n        mGeolocSharingCache.put(sharingId, geolocSharing);\n    }\n\n    /**\n     * Remove an geoloc sharing from the list\n     * \n     * @param sharingId Sharing ID\n     */\n    public void removeGeolocSharing(String sharingId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a geoloc sharing from the list (size=\"\n                    + mGeolocSharingCache.size() + \")\");\n        }\n        mGeolocSharingCache.remove(sharingId);\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return Returns true if registered else returns false\n     */\n    @Override\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Return the reason code for IMS service registration\n     * \n     * @return the reason code for IMS service registration\n     */\n    @Override\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    @Override\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add a service listener\");\n        }\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    @Override\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove a service listener\");\n        }\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        // Notify listeners\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     * \n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        // Notify listeners\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Receive a new geoloc sharing invitation\n     * \n     * @param session Geoloc sharing session\n     */\n    public void receiveGeolocSharingInvitation(GeolocTransferSession session) {\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Receive geoloc sharing invitation from \")\n                    .append(session.getRemoteContact()).append(\"; displayName=\")\n                    .append(session.getRemoteDisplayName()).append(\".\").toString());\n        }\n        ContactId contact = session.getRemoteContact();\n        String sharingId = session.getSessionID();\n        GeolocSharingPersistedStorageAccessor persistedStorage = new GeolocSharingPersistedStorageAccessor(\n                sharingId, contact, session.getGeoloc(), Direction.INCOMING, mRichcallLog,\n                session.getTimestamp());\n        GeolocSharingImpl geolocSharing = new GeolocSharingImpl(sharingId, mBroadcaster,\n                mRichcallService, this, persistedStorage);\n        addGeolocSharing(geolocSharing, sharingId);\n        session.addListener(geolocSharing);\n    }\n\n    /**\n     * Shares a geolocation with a contact. An exception if thrown if there is no ongoing CS call.\n     * The parameter contact supports the following formats: MSISDN in national or international\n     * format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an\n     * exception is thrown.\n     * \n     * @param contact Contact\n     * @param geoloc Geolocation info\n     * @return Geoloc sharing\n     * @throws RemoteException\n     */\n    public IGeolocSharing shareGeoloc(ContactId contact, Geoloc geoloc) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (geoloc == null) {\n            throw new ServerApiIllegalArgumentException(\"geoloc must not be null!\");\n        }\n        String label = geoloc.getLabel();\n        if (label != null) {\n            int labelLength = label.length();\n            int labelMaxLength = mRcsSettings.getMaxGeolocLabelLength();\n            if (labelLength > labelMaxLength) {\n                throw new ServerApiIllegalArgumentException(new StringBuilder()\n                        .append(\"geoloc message label length: \").append(labelLength)\n                        .append(\" exeeds max length: \").append(labelMaxLength).append(\"!\")\n                        .toString());\n            }\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a geoloc sharing session with \".concat(contact.toString()));\n        }\n        ServerApiUtils.testIms();\n        try {\n            String msgId = IdGenerator.generateMessageID();\n            long timestamp = System.currentTimeMillis();\n            String geolocDoc = ChatUtils.buildGeolocDocument(geoloc, ImsModule.getImsUserProfile()\n                    .getPublicUri(), msgId, timestamp);\n            byte[] data = geolocDoc.getBytes(UTF8);\n            MmContent content = new GeolocContent(\"geoloc.xml\", data.length, data);\n\n            final GeolocTransferSession session = mRichcallService.createGeolocSharingSession(\n                    contact, content, geoloc, timestamp);\n            final String sharingId = session.getSessionID();\n            final GeolocSharingPersistedStorageAccessor persistedStorage = new GeolocSharingPersistedStorageAccessor(\n                    sharingId, contact, geoloc, Direction.OUTGOING, mRichcallLog, timestamp);\n            final GeolocSharingImpl geolocSharing = new GeolocSharingImpl(sharingId, mBroadcaster,\n                    mRichcallService, this, persistedStorage);\n\n            mRichcallLog.addOutgoingGeolocSharing(contact, sharingId, geoloc, State.INITIATING,\n                    ReasonCode.UNSPECIFIED, timestamp);\n\n            final GeolocSharingServiceImpl geolocSharingService = this;\n            mRichcallService.scheduleGeolocShareOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        session.addListener(geolocSharing);\n                        geolocSharingService.addGeolocSharing(geolocSharing, sharingId);\n                        session.startSession();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed initiate geoloc sharing right now!\", e);\n                    }\n                }\n            });\n            return geolocSharing;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current geoloc sharing from its unique ID\n     * \n     * @param sharingId sharing ID\n     * @return Geoloc sharing\n     * @throws RemoteException\n     */\n    public IGeolocSharing getGeolocSharing(String sharingId) throws RemoteException {\n        if (TextUtils.isEmpty(sharingId)) {\n            throw new ServerApiIllegalArgumentException(\"sharingId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get geoloc sharing session \".concat(sharingId));\n        }\n        try {\n            IGeolocSharing geolocSharing = mGeolocSharingCache.get(sharingId);\n            if (geolocSharing != null) {\n                return geolocSharing;\n            }\n            GeolocSharingPersistedStorageAccessor persistedStorage = new GeolocSharingPersistedStorageAccessor(\n                    sharingId, mRichcallLog);\n            return new GeolocSharingImpl(sharingId, mBroadcaster, mRichcallService, this,\n                    persistedStorage);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on geoloc sharing events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    @Override\n    public void addEventListener2(IGeolocSharingListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add a Geoloc sharing event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mBroadcaster.addEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on geoloc sharing events\n     * \n     * @param listener Listener\n     */\n    @Override\n    public void removeEventListener2(IGeolocSharingListener listener) {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove a Geoloc sharing event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mBroadcaster.removeEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    @Override\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Adds and broadcast that a geoloc sharing invitation was rejected\n     * \n     * @param contact Contact ID\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void addGeolocSharingInvitationRejected(ContactId contact, ReasonCode reasonCode,\n            long timestamp) {\n        String sharingId = SessionIdGenerator.getNewId();\n        mRichcallLog.addIncomingGeolocSharing(contact, sharingId, GeolocSharing.State.REJECTED,\n                reasonCode, timestamp);\n        mBroadcaster.broadcastInvitation(sharingId);\n    }\n\n    public void setGeolocSharingStateAndReasonCode(ContactId contact, String sharingId,\n            State state, ReasonCode reasonCode) {\n        mRichcallLog.setGeolocSharingStateAndReasonCode(sharingId, state, reasonCode);\n        mBroadcaster.broadcastStateChanged(contact, sharingId, state, reasonCode);\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Deletes all geoloc sharing from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RemoteException\n     */\n    public void deleteGeolocSharings() throws RemoteException {\n        mRichcallService.tryToDeleteGeolocSharings();\n    }\n\n    /**\n     * Deletes geoloc sharing with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param contact remote contact\n     * @throws RemoteException\n     */\n    public void deleteGeolocSharings2(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        mRichcallService.tryToDeleteGeolocSharings(contact);\n    }\n\n    /**\n     * Deletes a geoloc sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId sharing ID\n     * @throws RemoteException\n     */\n    public void deleteGeolocSharing(String sharingId) throws RemoteException {\n        if (TextUtils.isEmpty(sharingId)) {\n            throw new ServerApiIllegalArgumentException(\"sharingId must not be null or empty!\");\n        }\n        mRichcallService.tryToDeleteGeolocSharing(sharingId);\n    }\n\n    public void broadcastDeleted(ContactId contact, Set<String> sharingIds) {\n        mBroadcaster.broadcastDeleted(contact, sharingIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/GroupChatImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.SessionNotEstablishedException;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatError;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatInfo;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.GroupChatSessionListener;\nimport com.gsma.rcs.core.ims.service.im.chat.RejoinGroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.RestartGroupChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.history.HistoryLog;\nimport com.gsma.rcs.provider.messaging.ChatMessagePersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.GroupChatPersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImSessionStartMode;\nimport com.gsma.rcs.service.broadcaster.IGroupChatEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.chat.IGroupChat;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Group chat implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GroupChatImpl extends IGroupChat.Stub implements GroupChatSessionListener {\n\n    private final String mChatId;\n\n    private final IGroupChatEventBroadcaster mBroadcaster;\n\n    private final InstantMessagingService mImService;\n\n    private final GroupChatPersistedStorageAccessor mPersistedStorage;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    private final ChatServiceImpl mChatService;\n\n    private final MessagingLog mMessagingLog;\n\n    private final HistoryLog mHistoryLog;\n\n    private boolean mGroupChatRejoinedAsPartOfSendOperation = false;\n\n    private static final Set<ParticipantStatus> RECIPIENT_STATUSES = new HashSet<>();\n    static {\n        RECIPIENT_STATUSES.add(ParticipantStatus.INVITE_QUEUED);\n        RECIPIENT_STATUSES.add(ParticipantStatus.INVITING);\n        RECIPIENT_STATUSES.add(ParticipantStatus.INVITED);\n        RECIPIENT_STATUSES.add(ParticipantStatus.CONNECTED);\n        RECIPIENT_STATUSES.add(ParticipantStatus.DISCONNECTED);\n    }\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(GroupChatImpl.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param chatId Chat Id\n     * @param broadcaster IGroupChatEventBroadcaster\n     * @param imService InstantMessagingService\n     * @param persistentStorage GroupChatPersistedStorageAccessor\n     * @param rcsSettings RcsSettings\n     * @param contactManager ContactManager\n     * @param chatService ChatServiceImpl\n     * @param messagingLog MessagingLog\n     * @param historyLog HistoryLog\n     */\n    public GroupChatImpl(InstantMessagingService imService, String chatId,\n            IGroupChatEventBroadcaster broadcaster,\n            GroupChatPersistedStorageAccessor persistentStorage, RcsSettings rcsSettings,\n            ChatServiceImpl chatService, ContactManager contactManager, MessagingLog messagingLog,\n            HistoryLog historyLog) {\n        mImService = imService;\n        mChatId = chatId;\n        mBroadcaster = broadcaster;\n        mPersistedStorage = persistentStorage;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n        mChatService = chatService;\n        mMessagingLog = messagingLog;\n        mHistoryLog = historyLog;\n    }\n\n    private Content.ReasonCode imdnToMessageFailedReasonCode(ImdnDocument imdn) {\n        String notificationType = imdn.getNotificationType();\n        if (ImdnDocument.DELIVERY_NOTIFICATION.equals(notificationType)) {\n            return Content.ReasonCode.FAILED_DELIVERY;\n\n        } else if (ImdnDocument.DISPLAY_NOTIFICATION.equals(notificationType)) {\n            return Content.ReasonCode.FAILED_DISPLAY;\n        }\n        throw new IllegalArgumentException(\"Received invalid imdn notification type:'\"\n                + notificationType + \"'\");\n    }\n\n    private void setStateAndReasonCode(State state, ReasonCode reasonCode) {\n        if (mPersistedStorage.setStateAndReasonCode(state, reasonCode)) {\n            mBroadcaster.broadcastStateChanged(mChatId, state, reasonCode);\n        }\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode) {\n        setRejoinedAsPartOfSendOperation(false);\n        synchronized (mLock) {\n            mChatService.removeGroupChat(mChatId);\n            setStateAndReasonCode(State.REJECTED, reasonCode);\n        }\n        /*\n         * Try to dequeue all one-one chat messages and file transfers as a chat session is torn\n         * down now.\n         */\n        mImService.tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers();\n    }\n\n    private void onMessageDeliveryStatusDelivered(ContactId contact, String msgId,\n            long timestampDelivered) {\n        String mimeType = mMessagingLog.getMessageMimeType(msgId);\n        synchronized (mLock) {\n            if (mPersistedStorage.setGroupChatDeliveryInfoDelivered(mChatId, contact, msgId,\n                    timestampDelivered)) {\n                mBroadcaster.broadcastMessageGroupDeliveryInfoChanged(mChatId, contact, mimeType,\n                        msgId, GroupDeliveryInfo.Status.DELIVERED,\n                        GroupDeliveryInfo.ReasonCode.UNSPECIFIED);\n                if (mPersistedStorage.isDeliveredToAllRecipients(msgId)) {\n                    if (mPersistedStorage.setMessageStatusDelivered(msgId, timestampDelivered)) {\n                        mBroadcaster.broadcastMessageStatusChanged(mChatId, mimeType, msgId,\n                                Status.DELIVERED, Content.ReasonCode.UNSPECIFIED);\n                    }\n                }\n            }\n        }\n    }\n\n    private void onMessageDeliveryStatusDisplayed(ContactId contact, String msgId,\n            long timestampDisplayed) {\n        String mimeType = mMessagingLog.getMessageMimeType(msgId);\n        synchronized (mLock) {\n            if (mPersistedStorage.setDeliveryInfoDisplayed(mChatId, contact, msgId,\n                    timestampDisplayed)) {\n                mBroadcaster.broadcastMessageGroupDeliveryInfoChanged(mChatId, contact, mimeType,\n                        msgId, GroupDeliveryInfo.Status.DISPLAYED,\n                        GroupDeliveryInfo.ReasonCode.UNSPECIFIED);\n                if (mPersistedStorage.isDisplayedByAllRecipients(msgId)) {\n                    if (mPersistedStorage.setMessageStatusDisplayed(msgId, timestampDisplayed)) {\n                        mBroadcaster.broadcastMessageStatusChanged(mChatId, mimeType, msgId,\n                                Status.DISPLAYED, Content.ReasonCode.UNSPECIFIED);\n                    }\n                }\n            }\n        }\n    }\n\n    private void onMessageDeliveryStatusFailed(ContactId contact, String msgId,\n            Content.ReasonCode reasonCode) {\n        String mimeType = mMessagingLog.getMessageMimeType(msgId);\n        synchronized (mLock) {\n            if (Content.ReasonCode.FAILED_DELIVERY == reasonCode) {\n                if (!mPersistedStorage.setGroupDeliveryInfoStatusAndReasonCode(mChatId, contact,\n                        msgId, GroupDeliveryInfo.Status.FAILED,\n                        GroupDeliveryInfo.ReasonCode.FAILED_DELIVERY)) {\n                    /* Add entry with delivered and displayed timestamps set to 0. */\n                    mMessagingLog.addGroupChatDeliveryInfoEntry(mChatId, contact, msgId,\n                            GroupDeliveryInfo.Status.FAILED,\n                            GroupDeliveryInfo.ReasonCode.FAILED_DELIVERY, 0, 0);\n                }\n                mBroadcaster.broadcastMessageGroupDeliveryInfoChanged(mChatId, contact, mimeType,\n                        msgId, GroupDeliveryInfo.Status.FAILED,\n                        GroupDeliveryInfo.ReasonCode.FAILED_DELIVERY);\n            } else {\n                if (!mPersistedStorage.setGroupDeliveryInfoStatusAndReasonCode(mChatId, contact,\n                        msgId, GroupDeliveryInfo.Status.FAILED,\n                        GroupDeliveryInfo.ReasonCode.FAILED_DISPLAY)) {\n                    /* Add entry with delivered and displayed timestamps set to 0. */\n                    mMessagingLog.addGroupChatDeliveryInfoEntry(mChatId, contact, msgId,\n                            GroupDeliveryInfo.Status.FAILED,\n                            GroupDeliveryInfo.ReasonCode.FAILED_DISPLAY, 0, 0);\n                }\n                mBroadcaster.broadcastMessageGroupDeliveryInfoChanged(mChatId, contact, mimeType,\n                        msgId, GroupDeliveryInfo.Status.FAILED,\n                        GroupDeliveryInfo.ReasonCode.FAILED_DISPLAY);\n            }\n        }\n    }\n\n    public boolean isGroupChatAbandoned() {\n        GroupChatSession session = mImService.getGroupChatSession(mChatId);\n        if (session != null) {\n            /* Group chat is not abandoned if there exists a session */\n            return false;\n        }\n        ReasonCode reasonCode = mPersistedStorage.getReasonCode();\n        if (reasonCode == null) {\n            return false;\n        }\n        switch (reasonCode) {\n            case ABORTED_BY_USER:\n            case ABORTED_BY_REMOTE:\n            case FAILED_INITIATION:\n            case REJECTED_BY_REMOTE:\n            case REJECTED_MAX_CHATS:\n            case REJECTED_SPAM:\n            case REJECTED_BY_TIMEOUT:\n            case REJECTED_BY_SYSTEM:\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Group chat with chatId '\" + mChatId + \"' is \" + reasonCode);\n                }\n                return true;\n            default:\n                break;\n        }\n        return false;\n    }\n\n    private boolean isAllowedToInviteAdditionalParticipants(int additionalParticipants)\n            throws RemoteException {\n        int nrOfParticipants = getParticipants().size() + additionalParticipants;\n        int maxNrOfAllowedParticipants = mRcsSettings.getMaxChatParticipants();\n        return nrOfParticipants < maxNrOfAllowedParticipants;\n    }\n\n    private boolean isGroupChatCapableOfReceivingParticipantInvitations() {\n        if (!mRcsSettings.isGroupChatActivated()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Cannot add participants to on group chat with group chat Id '\"\n                        + mChatId + \"' as group chat feature has been disabled by the operator.\");\n            }\n            return false;\n        }\n        if (isGroupChatAbandoned()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Cannot invite participants to group chat with group chat Id '\"\n                        + mChatId + \"'\");\n            }\n            return false;\n        }\n        return true;\n    }\n\n    private boolean isGroupChatRejoinable() {\n        GroupChatInfo groupChat = mMessagingLog.getGroupChatInfo(mChatId);\n        if (groupChat == null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Group chat with group chat Id '\" + mChatId\n                        + \"' is not rejoinable as the group chat does not exist in DB.\");\n            }\n            return false;\n        }\n        if (groupChat.getRejoinId() == null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Group chat with group chat Id '\" + mChatId\n                        + \"' is not rejoinable as there is no ongoing session with \"\n                        + \"corresponding chatId and there exists no rejoinId to \"\n                        + \"rejoin the group chat.\");\n            }\n            return false;\n        }\n        return true;\n    }\n\n    private boolean isParticipantEligibleToBeInvited(ContactId participant) {\n        Map<ContactId, ParticipantStatus> currentParticipants = mMessagingLog\n                .getParticipants(mChatId);\n        for (Map.Entry<ContactId, ParticipantStatus> currentParticipant : currentParticipants\n                .entrySet()) {\n            if (currentParticipant.getKey().equals(participant)) {\n                ParticipantStatus status = currentParticipant.getValue();\n                switch (status) {\n                    case INVITE_QUEUED:\n                    case INVITED:\n                    case INVITING:\n                    case CONNECTED:\n                    case DISCONNECTED:\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot invite participant to group chat with group chat Id '\"\n                                    + mChatId\n                                    + \"' as the participant '\"\n                                    + participant\n                                    + \"' is .\"\n                                    + status);\n                        }\n                        return false;\n                    default:\n                        break;\n                }\n            }\n        }\n        return true;\n    }\n\n    private boolean isParticipantCapableToBeInvited(ContactId participant) {\n        boolean inviteOnlyFullSF = mRcsSettings.isGroupChatInviteIfFullStoreForwardSupported();\n        Capabilities remoteCapabilities = mContactManager.getContactCapabilities(participant);\n        if (remoteCapabilities == null) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Cannot invite participant to group chat with group chat Id '\"\n                        + mChatId + \"' as the capabilities of participant '\" + participant\n                        + \"' are not known.\");\n            }\n            return false;\n        }\n        if (!remoteCapabilities.isImSessionSupported()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Cannot invite participant to group chat with group chat Id '\"\n                        + mChatId + \"' as the participant '\" + participant\n                        + \"' does not have IM capabilities.\");\n            }\n            return false;\n        }\n        if (inviteOnlyFullSF && !remoteCapabilities.isGroupChatStoreForwardSupported()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Cannot invite participant to group chat with group chat Id '\"\n                        + mChatId + \"' as full store and forward is required and the participant '\"\n                        + participant + \"' does not have that feature supported.\");\n            }\n            return false;\n        }\n        return true;\n    }\n\n    private void addOutgoingGroupChatMessage(ChatMessage msg, Status status,\n            Content.ReasonCode reasonCode) throws PayloadException {\n        Set<ContactId> recipients = getRecipients();\n        if (recipients == null) {\n            throw new ServerApiPersistentStorageException(\n                    \"Unable to determine recipients of the group chat \" + mChatId\n                            + \" to set as recipients for the the group chat message \"\n                            + msg.getMessageId() + \"!\");\n        }\n        mPersistedStorage.addOutgoingGroupChatMessage(msg, recipients, status, reasonCode);\n    }\n\n    /**\n     * Checks if the group chat is active\n     * \n     * @return boolean\n     */\n    public boolean isGroupChatActive() {\n        GroupChatSession session = mImService.getGroupChatSession(mChatId);\n        return session != null || State.STARTED == mPersistedStorage.getState();\n    }\n\n    /**\n     * Get the participants of a group chat matching any of the specified statuses\n     * \n     * @param statuses PatricipantStatues to match\n     * @return Set of ContactIds\n     */\n    public Map<ContactId, ParticipantStatus> getParticipants(Set<ParticipantStatus> statuses) {\n        GroupChatSession session = mImService.getGroupChatSession(mChatId);\n        if (session == null) {\n            return mPersistedStorage.getParticipants(statuses);\n        }\n        return session.getParticipants(statuses);\n    }\n\n    /**\n     * Get the recipients of a group chat message or a group file transfer in this group chat\n     * \n     * @return Set of ContactIds\n     */\n    public Set<ContactId> getRecipients() {\n        return getParticipants(RECIPIENT_STATUSES).keySet();\n    }\n\n    /**\n     * Get chat ID\n     * \n     * @return Chat ID\n     */\n    @Override\n    public String getChatId() {\n        return mChatId;\n    }\n\n    /**\n     * Get remote contact identifier\n     * \n     * @return ContactId\n     * @throws RemoteException\n     */\n    @Override\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n\n    }\n\n    /**\n     * Returns the direction of the group chat (incoming or outgoing)\n     * \n     * @return Direction\n     * @throws RemoteException\n     */\n    @Override\n    public int getDirection() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n\n    }\n\n    /**\n     * Returns the state of the group chat\n     * \n     * @return State\n     * @throws RemoteException\n     */\n    @Override\n    public int getState() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getState().toInt();\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return State.STARTED.toInt();\n\n            } else if (session.isInitiatedByRemote()) {\n                if (session.isSessionAccepted()) {\n                    return State.ACCEPTING.toInt();\n                }\n                return State.INVITED.toInt();\n            }\n            return State.INITIATING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the group chat\n     * \n     * @return ReasonCode\n     * @throws RemoteException\n     */\n    @Override\n    public int getReasonCode() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getReasonCode().toInt();\n            }\n            return ReasonCode.UNSPECIFIED.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the group chat invitation was initiated for outgoing\n     * group chats or the local timestamp of when the group chat invitation was received for\n     * incoming group chat invitations.\n     * \n     * @return Timestamp\n     * @throws RemoteException\n     */\n    @Override\n    public long getTimestamp() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getTimestamp();\n            }\n            return session.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Get subject associated to the session\n     * \n     * @return String\n     * @throws RemoteException\n     */\n    @Override\n    public String getSubject() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getSubject();\n            }\n            return session.getSubject();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n\n    }\n\n    /**\n     * Returns true if it is possible to leave this group chat.\n     * \n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToLeave() throws RemoteException {\n        try {\n            if (isGroupChatAbandoned()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot leave group chat with group chat Id '\" + mChatId + \"'\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Quits a group chat conversation. The conversation will continue between other participants if\n     * there are enough participants.\n     * \n     * @throws RemoteException\n     */\n    @Override\n    public void leave() throws RemoteException {\n        if (isGroupChatAbandoned()) {\n            throw new ServerApiUnsupportedOperationException(\n                    \"Cannot leave group chat with group chat Id : \" + mChatId);\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    final GroupChatSession session = mImService.getGroupChatSession(mChatId);\n                    if (session == null || !ServerApiUtils.isImsConnected()) {\n                        /*\n                         * Quitting group chat that is inactive/ not available due to network drop\n                         * should reject the next group chat invitation that is received\n                         */\n                        mPersistedStorage.setStateAndReasonCode(State.ABORTED,\n                                ReasonCode.ABORTED_BY_USER);\n                        mPersistedStorage.setRejectNextGroupChatNextInvitation();\n                        mImService\n                                .tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(mChatId);\n                        return;\n                    }\n\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Cancel session\");\n                    }\n\n                    /* Terminate the session */\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to terminate session with sessionId : \" + mChatId, e);\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Returns the participants. A participant is identified by its MSISDN in national or\n     * international format, SIP address, SIP-URI or Tel-URI.\n     * \n     * @return Participants\n     * @throws RemoteException\n     */\n    @Override\n    public Map<ContactId, Integer> getParticipants() throws RemoteException {\n        try {\n            Map<ContactId, Integer> apiParticipants = new HashMap<>();\n            Map<ContactId, ParticipantStatus> participants;\n\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                participants = mPersistedStorage.getParticipants();\n                if (participants == null) {\n                    throw new ServerApiPersistentStorageException(\n                            \"No participants found for chatId : \" + mChatId);\n                }\n            } else {\n                participants = session.getParticipants();\n            }\n\n            for (Map.Entry<ContactId, ParticipantStatus> participant : participants.entrySet()) {\n                apiParticipants.put(participant.getKey(), participant.getValue().toInt());\n            }\n\n            return apiParticipants;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the max number of participants for a group chat from the group chat info subscription\n     * (this value overrides the provisioning parameter)\n     * \n     * @return Number\n     * @throws RemoteException\n     */\n    @Override\n    public int getMaxParticipants() throws RemoteException {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                return mPersistedStorage.getMaxParticipants();\n            }\n            return session.getMaxParticipants();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to invite additional participants to the group chat right now,\n     * else returns false.\n     * \n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToInviteParticipants() throws RemoteException {\n        try {\n            if (!isGroupChatCapableOfReceivingParticipantInvitations()) {\n                return false;\n            }\n            if (!isAllowedToInviteAdditionalParticipants(1)) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot invite participants to group chat with group chat Id '\"\n                            + mChatId + \"' as max number of participants has been reached already.\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to invite the specified participants to the group chat right\n     * now, else returns false.\n     * \n     * @param participant ContactId\n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToInviteParticipant(ContactId participant) throws RemoteException {\n        if (participant == null) {\n            throw new ServerApiIllegalArgumentException(\"participant must not be null!\");\n        }\n        if (!isAllowedToInviteParticipants()) {\n            return false;\n        }\n        try {\n            return isParticipantEligibleToBeInvited(participant)\n                    && isParticipantCapableToBeInvited(participant);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Invite additional participants to this group chat.\n     * \n     * @param participants Set of participants\n     * @throws RemoteException\n     */\n    @Override\n    public void inviteParticipants(final List<ContactId> participants) throws RemoteException {\n        if (participants == null || participants.isEmpty()) {\n            throw new ServerApiIllegalArgumentException(\n                    \"participants list must not be null or empty!\");\n        }\n        if (!isGroupChatCapableOfReceivingParticipantInvitations()) {\n            throw new ServerApiUnsupportedOperationException(\n                    \"Not capable of receiving participant invitations!\");\n        }\n        try {\n            for (ContactId participant : participants) {\n                if (!isParticipantEligibleToBeInvited(participant)) {\n                    throw new ServerApiPermissionDeniedException(\n                            \"Participant not eligible to be invited!\");\n                }\n            }\n            mImService.scheduleImOperation(new Runnable() {\n                public void run() {\n                    GroupChatSession session = mImService.getGroupChatSession(mChatId);\n                    try {\n                        boolean mediaEstablished = (session != null && session.isMediaEstablished());\n                        if (mediaEstablished) {\n                            inviteParticipants(session, new HashSet<>(participants));\n                            return;\n                        }\n                        Map<ContactId, ParticipantStatus> participantsToStore = mMessagingLog\n                                .getParticipants(mChatId);\n                        for (ContactId contact : participants) {\n                            participantsToStore.put(contact, ParticipantStatus.INVITE_QUEUED);\n                        }\n                        if (session != null) {\n                            session.updateParticipants(participantsToStore);\n                        } else {\n                            mMessagingLog.setGroupChatParticipants(mChatId, participantsToStore);\n                        }\n                        if (session == null) {\n                            if (isGroupChatRejoinable() && ServerApiUtils.isImsConnected()) {\n                                rejoinGroupChat();\n                            }\n                        }\n                    } catch (PayloadException | NetworkException | RuntimeException e) {\n                        if (session != null) {\n                            session.handleError(new ChatError(ChatError.SEND_RESPONSE_FAILED, e));\n                        } else {\n                            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n                        }\n                    }\n                }\n            });\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Invite additional participants to this group chat inviteParticipants\n     * \n     * @param session Group session\n     * @param participants Set of participants\n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void inviteParticipants(final GroupChatSession session, final Set<ContactId> participants)\n            throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Adding \" + Arrays.toString(participants.toArray()) + \" to the session.\");\n        }\n        int maxNumberOfAdditionalParticipants = session.getMaxNumberOfAdditionalParticipants();\n        if (maxNumberOfAdditionalParticipants < participants.size()) {\n            throw new ServerApiPermissionDeniedException(\"Invite of \" + participants.size()\n                    + \" participants failed, max number of additional participants: \"\n                    + maxNumberOfAdditionalParticipants + \"!\");\n        }\n        session.inviteParticipants(participants);\n    }\n\n    private void sendChatMessageWithinSession(final GroupChatSession session, final ChatMessage msg)\n            throws NetworkException {\n        session.sendChatMessage(msg);\n    }\n\n    /**\n     * Set chat message status and timestamp\n     * \n     * @param msg Chat message\n     * @param status status of message\n     */\n    private void setChatMessageStatusAndTimestamp(ChatMessage msg, Status status) {\n        String msgId = msg.getMessageId();\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndTimestamp(msgId, status,\n                    Content.ReasonCode.UNSPECIFIED, msg.getTimestamp(), msg.getTimestampSent())) {\n                mBroadcaster.broadcastMessageStatusChanged(mChatId, msg.getMimeType(),\n                        msg.getMessageId(), Status.SENDING, Content.ReasonCode.UNSPECIFIED);\n            }\n        }\n    }\n\n    /**\n     * Dequeue group chat message\n     * \n     * @param msg Chat message\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws SessionNotEstablishedException\n     */\n    public void dequeueGroupChatMessage(ChatMessage msg) throws PayloadException, NetworkException,\n            SessionNotEstablishedException {\n        final GroupChatSession session = mImService.getGroupChatSession(mChatId);\n        if (session == null) {\n            mImService.rejoinGroupChatAsPartOfSendOperation(mChatId);\n\n        } else if (session.isMediaEstablished()) {\n            setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n            sendChatMessageWithinSession(session, msg);\n\n        } else if (session.isInitiatedByRemote()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Group chat session with chatId '\" + mChatId\n                        + \"' is pending for acceptance, accept it.\");\n            }\n            session.acceptSession();\n\n        } else {\n            throw new SessionNotEstablishedException(\n                    \"The existing group chat session with chatId '\" + mChatId\n                            + \"' is not established right now!\");\n        }\n    }\n\n    /**\n     * Dequeue group file info\n     * \n     * @param fileTransferId File transfer ID\n     * @param fileInfo File information\n     * @param displayedReportEnabled Display report enabled\n     * @param deliveredReportEnabled Delivery report enabled\n     * @param groupFileTransfer Group file implementation\n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws SessionNotEstablishedException\n     */\n    public void dequeueGroupFileInfo(String fileTransferId, String fileInfo,\n            boolean displayedReportEnabled, boolean deliveredReportEnabled,\n            GroupFileTransferImpl groupFileTransfer) throws PayloadException, NetworkException,\n            SessionNotEstablishedException {\n        GroupChatSession session = mImService.getGroupChatSession(mChatId);\n        if (session == null) {\n            mImService.rejoinGroupChatAsPartOfSendOperation(mChatId);\n\n        } else if (session.isMediaEstablished()) {\n            session.sendFileInfo(groupFileTransfer, fileTransferId, fileInfo,\n                    displayedReportEnabled, deliveredReportEnabled);\n\n        } else if (session.isInitiatedByRemote()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Group chat session with chatId '\" + mChatId\n                        + \"' is pending for acceptance, accept it.\");\n            }\n            session.acceptSession();\n\n        } else {\n            throw new SessionNotEstablishedException(\n                    \"The existing group chat session with chatId '\" + mChatId\n                            + \"' is not established right now!\");\n        }\n    }\n\n    /**\n     * Returns true if it is possible to send messages in the group chat right now, else returns\n     * false.\n     * \n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToSendMessage() throws RemoteException {\n        try {\n            if (!mRcsSettings.isGroupChatActivated()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot send message on group chat with group chat Id '\"\n                            + mChatId + \"' as group chat feature is not supported.\");\n                }\n                return false;\n            }\n            if (isGroupChatAbandoned()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot send message on group chat with group chat Id '\"\n                            + mChatId + \"'\");\n                }\n                return false;\n            }\n            if (!mRcsSettings.getMyCapabilities().isImSessionSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot send message on group chat with group chat Id '\"\n                            + mChatId + \"' as IM capabilities are not supported for self.\");\n                }\n                return false;\n            }\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            if (session == null) {\n                if (!isGroupChatRejoinable()) {\n                    return false;\n                }\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a text message to the group\n     * \n     * @param text Message\n     * @return Chat message\n     * @throws RemoteException\n     */\n    @Override\n    public IChatMessage sendMessage(final String text) throws RemoteException {\n        if (TextUtils.isEmpty(text)) {\n            throw new ServerApiIllegalArgumentException(\n                    \"GroupChat message must not be null or empty!\");\n        }\n        int messageLength = text.length();\n        int maxMessageLength = mRcsSettings.getMaxGroupChatMessageLength();\n        if (messageLength > maxMessageLength) {\n            throw new ServerApiIllegalArgumentException(\"chat message length: \" + messageLength\n                    + \" exceeds max group chat message length: \" + maxMessageLength + \"!\");\n        }\n        if (!isAllowedToSendMessage()) {\n            throw new ServerApiPermissionDeniedException(\n                    \"Not allowed to send GroupChat message on the connected IMS server!\");\n        }\n        try {\n            mImService.removeGroupChatComposingStatus(mChatId); /* clear cache */\n            long timestamp = System.currentTimeMillis();\n            /* For outgoing message, timestampSent = timestamp */\n            final ChatMessage msg = ChatUtils.createTextMessage(null, text, timestamp, timestamp);\n            ChatMessagePersistedStorageAccessor persistedStorage = new ChatMessagePersistedStorageAccessor(\n                    mMessagingLog, msg.getMessageId(), msg.getRemoteContact(), text,\n                    msg.getMimeType(), mChatId, Direction.OUTGOING);\n            /* Always insert message with status QUEUED */\n            addOutgoingGroupChatMessage(msg, Content.Status.QUEUED, Content.ReasonCode.UNSPECIFIED);\n            if (!mChatService.isGroupChatActive(mChatId)) {\n                /*\n                 * Set inactive group chat as active as it now has a queued entry that has to be\n                 * dequeued after rejoining to the group chat on regaining IMS connection.\n                 */\n                mChatService.setGroupChatStateAndReasonCode(mChatId, GroupChat.State.STARTED,\n                        GroupChat.ReasonCode.UNSPECIFIED);\n            }\n\n            mImService.tryToDequeueGroupChatMessagesAndGroupFileTransfers(mChatId);\n            return new ChatMessageImpl(persistedStorage);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a geoloc message\n     * \n     * @param geoloc Geoloc\n     * @return ChatMessage\n     * @throws RemoteException\n     */\n    public IChatMessage sendMessage2(Geoloc geoloc) throws RemoteException {\n        if (geoloc == null) {\n            throw new ServerApiIllegalArgumentException(\"Geoloc message must not be null!\");\n        }\n        if (!isAllowedToSendMessage()) {\n            throw new ServerApiPermissionDeniedException(\n                    \"Not allowed to send Geoloc message on the connected IMS server!\");\n        }\n        String label = geoloc.getLabel();\n        if (label != null) {\n            int labelLength = label.length();\n            int labelMaxLength = mRcsSettings.getMaxGeolocLabelLength();\n            if (labelLength > labelMaxLength) {\n                throw new ServerApiIllegalArgumentException(\"geoloc message label length: \"\n                        + labelLength + \" exeeds max length: \" + labelMaxLength + \"!\");\n            }\n        }\n        try {\n            long timestamp = System.currentTimeMillis();\n            /** For outgoing message, timestampSent = timestamp */\n            final ChatMessage geolocMsg = ChatUtils.createGeolocMessage(null, geoloc, timestamp,\n                    timestamp);\n            ChatMessagePersistedStorageAccessor persistedStorage = new ChatMessagePersistedStorageAccessor(\n                    mMessagingLog, geolocMsg.getMessageId(), geolocMsg.getRemoteContact(),\n                    geolocMsg.getContent(), geolocMsg.getMimeType(), mChatId, Direction.OUTGOING);\n            addOutgoingGroupChatMessage(geolocMsg, Content.Status.QUEUED,\n                    Content.ReasonCode.UNSPECIFIED);\n            if (!mChatService.isGroupChatActive(mChatId)) {\n                /*\n                 * Set inactive group chat as active as it now has a queued entry that has to be\n                 * dequeued after rejoining to the group chat on regaining IMS connection.\n                 */\n                mChatService.setGroupChatStateAndReasonCode(mChatId, GroupChat.State.STARTED,\n                        GroupChat.ReasonCode.UNSPECIFIED);\n            }\n\n            mImService.tryToDequeueGroupChatMessagesAndGroupFileTransfers(mChatId);\n            return new ChatMessageImpl(persistedStorage);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Sends an is-composing event. The status is set to true when typing a message, else it is set\n     * to false.\n     * \n     * @param status Composing status\n     * @throws RemoteException\n     */\n    @Override\n    public void setComposingStatus(final boolean status) throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    mImService.removeGroupChatComposingStatus(mChatId);\n                    final GroupChatSession session = mImService.getGroupChatSession(mChatId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Unable to send composing event '\" + status\n                                    + \"' since Group chat session found with ChatId '\" + mChatId\n                                    + \"' does not exist for now.\");\n                        }\n                        mImService.addGroupChatComposingStatus(mChatId, status);\n                    } else if (session.getDialogPath().isSessionEstablished()) {\n                        session.sendIsComposingStatus(status);\n                    } else if (!session.isInitiatedByRemote()) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Unable to send composing event '\" + status\n                                    + \"' since Group chat session found with ChatId '\" + mChatId\n                                    + \"' is initiated locally.\");\n                        }\n                        mImService.addGroupChatComposingStatus(mChatId, status);\n                    } else {\n                        ImSessionStartMode imSessionStartMode = mRcsSettings\n                                .getImSessionStartMode();\n                        switch (imSessionStartMode) {\n                            case ON_OPENING:\n                            case ON_COMPOSING:\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"Group chat session found with ChatId '\"\n                                            + mChatId\n                                            + \"' is not established and imSessionStartMode = \"\n                                            + imSessionStartMode\n                                            + \" so accepting it and sending composing event '\"\n                                            + status + \"'\");\n                                }\n                                session.acceptSession();\n                                session.sendIsComposingStatus(status);\n                                break;\n                            default:\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"Group chat session found with ChatId '\"\n                                            + mChatId\n                                            + \"' is not established and imSessionStartMode = \"\n                                            + imSessionStartMode\n                                            + \" so can't accept it and sending composing event '\"\n                                            + status + \"' yet.\");\n                                }\n                                mImService.addGroupChatComposingStatus(mChatId, status);\n                                break;\n                        }\n                    }\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to send composing status in group chat : \" + mChatId, e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejoins an existing group chat from its unique chat ID\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void rejoinGroupChat() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Rejoin group chat session related to the conversation \" + mChatId);\n        }\n        ServerApiUtils.testIms();\n        RejoinGroupChatSession session = mImService.rejoinGroupChatSession(mChatId);\n        session.addListener(this);\n        mChatService.addGroupChat(this);\n        session.startSession();\n    }\n\n    /**\n     * Restarts a previous group chat from its unique chat ID\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    public void restartGroupChat() throws PayloadException, NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Restart group chat session related to the conversation \" + mChatId);\n        }\n        ServerApiUtils.testIms();\n        RestartGroupChatSession session = mImService.restartGroupChatSession(mChatId);\n        session.addListener(this);\n        mChatService.addGroupChat(this);\n        session.startSession();\n    }\n\n    @Override\n    public void openChat() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Open a group chat session with chatId \" + mChatId);\n                }\n                try {\n                    final GroupChatSession session = mImService.getGroupChatSession(mChatId);\n                    if (session == null) {\n                        /*\n                         * If there is no session ongoing right now then we do not need to open\n                         * anything right now so we just return here. A sending of a new message on\n                         * this group chat will anyway result in a rejoin attempt if this group chat\n                         * has not been left by choice so we do not need to do anything more here\n                         * for now.\n                         */\n                        return;\n                    }\n                    if (session.getDialogPath().isSessionEstablished()) {\n                        return;\n                    }\n                    ImSessionStartMode imSessionStartMode = mRcsSettings.getImSessionStartMode();\n                    if (!session.isInitiatedByRemote()) {\n                        /*\n                         * This method needs to accept pending invitation if IM_SESSION_START_MODE\n                         * is 0, which is not applicable if session is remote originated so we\n                         * return here.\n                         */\n                        return;\n                    }\n                    if (ImSessionStartMode.ON_OPENING == imSessionStartMode) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Core chat session is pending: auto accept it, as IM_SESSION_START mode = 0\");\n                        }\n                        session.acceptSession();\n                    }\n                } catch (ServerApiBaseException e) {\n                    if (!e.shouldNotBeLogged()) {\n                        sLogger.error(ExceptionUtil.getFullStackTrace(e));\n                    }\n                    throw e;\n\n                } catch (Exception e) {\n                    sLogger.error(ExceptionUtil.getFullStackTrace(e));\n                    throw new ServerApiGenericException(e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Try to restart group chat session on failure of restart\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     */\n    private void handleGroupChatRejoinAsPartOfSendOperationFailed() throws PayloadException,\n            NetworkException {\n        restartGroupChat();\n    }\n\n    /**\n     * @param enable Enable rejoin as part of send operation\n     */\n    public void setRejoinedAsPartOfSendOperation(boolean enable) {\n        mGroupChatRejoinedAsPartOfSendOperation = enable;\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        boolean loggerActivated = sLogger.isActivated();\n        if (loggerActivated) {\n            sLogger.info(\"Session started\");\n        }\n        setRejoinedAsPartOfSendOperation(false);\n        synchronized (mLock) {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            Boolean composingStatus = mImService.getGroupChatComposingStatus(mChatId);\n            if (composingStatus != null) {\n                if (loggerActivated) {\n                    sLogger.debug(\"Sending isComposing command with status :\"\n                            .concat(composingStatus.toString()));\n                }\n                try {\n                    session.sendIsComposingStatus(composingStatus);\n                    mImService.removeGroupChatComposingStatus(mChatId);\n                } catch (NetworkException e) {\n                    /*\n                     * Nothing to be handled here as we are not able to send composing status for\n                     * now, should try later and hence we don't remove it from the map.\n                     */\n                    if (loggerActivated) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n            }\n            boolean updateStateToStarted = State.STARTED != mPersistedStorage.getState();\n            mPersistedStorage.setRejoinId(session.getImSessionIdentity(), updateStateToStarted);\n            if (updateStateToStarted) {\n                mChatService.broadcastGroupChatStateChange(mChatId, State.STARTED,\n                        ReasonCode.UNSPECIFIED);\n            }\n        }\n        mImService.tryToInviteQueuedGroupChatParticipantInvitations(mChatId);\n        mImService.tryToDequeueGroupChatMessagesAndGroupFileTransfers(mChatId);\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        GroupChatSession session = mImService.getGroupChatSession(mChatId);\n        if (session != null && session.isPendingForRemoval()) {\n            /*\n             * If there is an ongoing group chat session with same chatId, this session has to be\n             * silently aborted so after aborting the session we make sure to not call the rest of\n             * this method that would otherwise abort the \"current\" session also and the GroupChat\n             * as a whole which is of course not the intention here\n             */\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Session marked pending for removal status \" + State.ABORTED\n                        + \" terminationReason \" + reason);\n            }\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session status \" + State.ABORTED + \" terminationReason \" + reason);\n        }\n        setRejoinedAsPartOfSendOperation(false);\n        synchronized (mLock) {\n            mChatService.removeGroupChat(mChatId);\n            switch (reason) {\n                case TERMINATION_BY_CONNECTION_LOST:\n                case TERMINATION_BY_SYSTEM:\n                    /*\n                     * This error is caused because of a network drop so the group chat is not set\n                     * to ABORTED state in this case as it will try to be auto-rejoined when IMS\n                     * connection is regained\n                     */\n                    break;\n                case TERMINATION_BY_USER:\n                    setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    mImService\n                            .tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(mChatId);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    mImService\n                            .tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(mChatId);\n                    break;\n                case TERMINATION_BY_TIMEOUT:\n                case TERMINATION_BY_INACTIVITY:\n                    setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_INACTIVITY);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\n                            \"Unknown reason in GroupChatImpl.handleSessionAborted; terminationReason=\"\n                                    + reason + \"!\");\n            }\n        }\n        /*\n         * Try to dequeue all one-one chat messages and file transfers as a chat session is torn\n         * down now.\n         */\n        mImService.tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers();\n    }\n\n    @Override\n    public void onMessageReceived(ChatMessage msg, boolean imdnDisplayedRequested,\n            boolean deliverySuccess) {\n        String msgId = null;\n        ContactId remote = null;\n        try {\n            msgId = msg.getMessageId();\n            remote = msg.getRemoteContact();\n            if (sLogger.isActivated()) {\n                sLogger.info(\"New IM with Id '\" + msgId + \"' received from \" + remote);\n            }\n            synchronized (mLock) {\n                if (deliverySuccess) {\n                    mPersistedStorage.addIncomingGroupChatMessage(msg, imdnDisplayedRequested);\n                    if (remote != null) {\n                        mContactManager.mergeContactCapabilities(remote, new CapabilitiesBuilder()\n                                .setImSession(true).setTimestampOfLastResponse(msg.getTimestamp())\n                                .build(), RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE,\n                                msg.getDisplayName());\n                    }\n                } else {\n                    mPersistedStorage.addGroupChatFailedDeliveryMessage(msg);\n                }\n                mBroadcaster.broadcastMessageReceived(msg.getMimeType(), msgId);\n            }\n        } catch (ContactManagerException | FileAccessException | RuntimeException e) {\n            sLogger.error(\n                    \"Failed to handle new IM with Id '\" + msgId + \"' received from \" + remote, e);\n        }\n    }\n\n    @Override\n    public void onImError(ChatError error) {\n        try {\n            GroupChatSession session = mImService.getGroupChatSession(mChatId);\n            int chatErrorCode = error.getErrorCode();\n            if (session != null && session.isPendingForRemoval()) {\n                /*\n                 * If there is an ongoing group chat session with same chatId, this session has to\n                 * be silently aborted so after aborting the session we make sure to not call the\n                 * rest of this method that would otherwise abort the \"current\" session also and the\n                 * GroupChat as a whole which is of course not the intention here\n                 */\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Session marked pending for removal - Error \" + chatErrorCode);\n                }\n                return;\n            }\n            if (sLogger.isActivated()) {\n                sLogger.info(\"IM error \" + chatErrorCode);\n            }\n            synchronized (mLock) {\n                mChatService.removeGroupChat(mChatId);\n                int chatError = error.getErrorCode();\n                switch (chatError) {\n                    case ChatError.SESSION_INITIATION_CANCELLED:\n                        /* Intentional fall through */\n                    case ChatError.SESSION_INITIATION_DECLINED:\n                        setStateAndReasonCode(State.REJECTED, ReasonCode.REJECTED_BY_REMOTE);\n                        mImService\n                                .tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(mChatId);\n                        break;\n                    case ChatError.SESSION_NOT_FOUND:\n                        if (mGroupChatRejoinedAsPartOfSendOperation) {\n                            handleGroupChatRejoinAsPartOfSendOperationFailed();\n                        }\n                        break;\n                    case ChatError.SESSION_INITIATION_FAILED:\n                        /* Intentional fall through */\n                    case ChatError.SESSION_RESTART_FAILED:\n                        /* Intentional fall through */\n                    case ChatError.SUBSCRIBE_CONFERENCE_FAILED:\n                        /* Intentional fall through */\n                    case ChatError.UNEXPECTED_EXCEPTION:\n                        setStateAndReasonCode(State.FAILED, ReasonCode.FAILED_INITIATION);\n                        mImService\n                                .tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(mChatId);\n                        break;\n                    /*\n                     * For cases where rejoin has failed or send response failed due to no ACK/200\n                     * OK response, we should not change Chat state.\n                     */\n                    /* Intentional fall through */\n                    case ChatError.SESSION_REJOIN_FAILED:\n                        /* Intentional fall through */\n                    case ChatError.SEND_RESPONSE_FAILED:\n                        break;\n                    /*\n                     * This error is caused because of a network drop so the group chat is not set\n                     * to ABORTED state in this case as it will be auto-rejoined when network\n                     * connection is regained\n                     */\n                    case ChatError.MEDIA_SESSION_FAILED:\n                    case ChatError.MEDIA_SESSION_BROKEN:\n                        break;\n                    default:\n                        throw new IllegalArgumentException(\"Unknown reason; chatError=\" + chatError\n                                + \"!\");\n                }\n            }\n            setRejoinedAsPartOfSendOperation(false);\n            /*\n             * Try to dequeue all one-one chat messages and file transfers as a chat session is torn\n             * down now.\n             */\n            mImService.tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers();\n\n        } catch (PayloadException | RuntimeException e) {\n            sLogger.error(\"Failed to handle error\" + error + \"!\", e);\n\n        } catch (NetworkException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(e.getMessage());\n            }\n        }\n    }\n\n    @Override\n    public void onIsComposingEventReceived(ContactId contact, boolean status) {\n        if (sLogger.isActivated()) {\n            sLogger.info(String.valueOf(contact) + \" is composing status set to \" + status);\n        }\n        synchronized (mLock) {\n            // Notify event listeners\n            mBroadcaster.broadcastComposingEvent(mChatId, contact, status);\n        }\n    }\n\n    @Override\n    public void onMessageFailedSend(String msgId, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Message sending failed; msgId=\" + msgId + \"mimeType=\" + mimeType + \".\");\n        }\n        synchronized (mLock) {\n            if (mPersistedStorage.setMessageStatusAndReasonCode(msgId, Status.FAILED,\n                    Content.ReasonCode.FAILED_SEND)) {\n                mBroadcaster.broadcastMessageStatusChanged(getChatId(), mimeType, msgId,\n                        Status.FAILED, Content.ReasonCode.FAILED_SEND);\n            }\n        }\n    }\n\n    @Override\n    public void onMessageSent(String msgId, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Text message sent; msgId=\" + msgId + \"mimeType=\" + mimeType + \".\");\n        }\n        synchronized (mLock) {\n            if (mPersistedStorage.setMessageStatusAndReasonCode(msgId, Status.SENT,\n                    Content.ReasonCode.UNSPECIFIED)) {\n                mBroadcaster.broadcastMessageStatusChanged(getChatId(), mimeType, msgId,\n                        Status.SENT, Content.ReasonCode.UNSPECIFIED);\n            }\n        }\n    }\n\n    @Override\n    public void onConferenceEventReceived(ContactId contact, ParticipantStatus status,\n            long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"New conference event \" + status.toString() + \" for \" + contact);\n        }\n        synchronized (mLock) {\n            if (ParticipantStatus.CONNECTED.equals(status)) {\n                mPersistedStorage.addGroupChatEvent(contact, GroupChatEvent.Status.JOINED,\n                        timestamp);\n\n            } else if (ParticipantStatus.DEPARTED.equals(status)) {\n                mPersistedStorage.addGroupChatEvent(contact, GroupChatEvent.Status.DEPARTED,\n                        timestamp);\n            }\n        }\n    }\n\n    @Override\n    public void onMessageDeliveryStatusReceived(ContactId contact, ImdnDocument imdn) {\n        ImdnDocument.DeliveryStatus status = imdn.getStatus();\n        String msgId = imdn.getMsgId();\n        long timestamp = imdn.getDateTime();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Handling message delivery status; contact=\" + contact + \", msgId=\"\n                    + msgId + \", status=\" + status + \", notificationType=\"\n                    + imdn.getNotificationType());\n        }\n        switch (status) {\n            case DELIVERED:\n                onMessageDeliveryStatusDelivered(contact, msgId, timestamp);\n                break;\n            case DISPLAYED:\n                onMessageDeliveryStatusDisplayed(contact, msgId, timestamp);\n                break;\n            case ERROR:\n            case FAILED:\n            case FORBIDDEN:\n                Content.ReasonCode reasonCode = imdnToMessageFailedReasonCode(imdn);\n                onMessageDeliveryStatusFailed(contact, msgId, reasonCode);\n                break;\n        }\n    }\n\n    @Override\n    public void onDeliveryStatusReceived(String contributionId, ContactId contact, ImdnDocument imdn) {\n        String msgId = imdn.getMsgId();\n        // TODO: Potential race condition, after we've checked that the message is persisted\n        // it may be removed before the handle method executes.\n        if (mMessagingLog.isMessagePersisted(msgId)) {\n            onMessageDeliveryStatusReceived(contact, imdn);\n            return;\n        }\n        if (mMessagingLog.isFileTransfer(msgId)) {\n            mImService.receiveGroupFileDeliveryStatus(contributionId, contact, imdn);\n            return;\n        }\n        sLogger.error(\"Imdn delivery report received referencing an entry that was \"\n                + \"not found in our database. Message id \" + msgId + \", ignoring.\");\n    }\n\n    /**\n     * Request to add participant has failed\n     * \n     * @param contact Contact ID\n     * @param reason Error reason\n     */\n    public void onAddParticipantFailed(ContactId contact, String reason) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add participant request has failed \" + reason);\n        }\n        synchronized (mLock) {\n            mBroadcaster.broadcastParticipantStatusChanged(mChatId, contact,\n                    ParticipantStatus.FAILED);\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Accepting group chat session\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE);\n                mImService.tryToMarkQueuedGroupChatMessagesAndGroupFileTransfersAsFailed(mChatId);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason + \"!\");\n        }\n    }\n\n    @Override\n    public void onSessionInvited(ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Invited to group chat session\");\n        }\n        synchronized (mLock) {\n            if (mMessagingLog.isGroupChatPersisted(mChatId)\n                    && mPersistedStorage.setParticipantsStateAndReasonCode(participants,\n                            State.INVITED, ReasonCode.UNSPECIFIED)) {\n                mBroadcaster.broadcastInvitation(mChatId);\n            } else {\n                mPersistedStorage.addGroupChat(contact, subject, participants, State.INVITED,\n                        ReasonCode.UNSPECIFIED, Direction.INCOMING, timestamp);\n                mBroadcaster.broadcastInvitation(mChatId);\n            }\n        }\n    }\n\n    @Override\n    public void onSessionAutoAccepted(ContactId contact, String subject,\n            Map<ContactId, ParticipantStatus> participants, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session auto accepted\");\n        }\n        synchronized (mLock) {\n            if (mMessagingLog.isGroupChatPersisted(mChatId)\n                    && mPersistedStorage.setParticipantsStateAndReasonCode(participants,\n                            State.ACCEPTING, ReasonCode.UNSPECIFIED)) {\n                mBroadcaster.broadcastInvitation(mChatId);\n            } else {\n                mPersistedStorage.addGroupChat(contact, subject, participants, State.ACCEPTING,\n                        ReasonCode.UNSPECIFIED, Direction.INCOMING, timestamp);\n                mBroadcaster.broadcastInvitation(mChatId);\n            }\n        }\n    }\n\n    @Override\n    public void onParticipantsUpdated(Map<ContactId, ParticipantStatus> updatedParticipants,\n            Map<ContactId, ParticipantStatus> allParticipants) {\n        synchronized (mLock) {\n            if (!mMessagingLog.setGroupChatParticipants(mChatId, allParticipants)) {\n                return;\n            }\n        }\n        for (Map.Entry<ContactId, ParticipantStatus> updatedParticipant : updatedParticipants\n                .entrySet()) {\n            ContactId contact = updatedParticipant.getKey();\n            ParticipantStatus status = updatedParticipant.getValue();\n\n            if (sLogger.isActivated()) {\n                sLogger.info(\"ParticipantUpdate for: \" + contact + \" status: \" + status);\n            }\n            mBroadcaster.broadcastParticipantStatusChanged(mChatId, contact, status);\n        }\n    }\n\n    @Override\n    public void onChatMessageDisplayReportSent(String msgId) {\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, Content.Status.RECEIVED,\n                    Content.ReasonCode.UNSPECIFIED)) {\n                String apiMimeType = mMessagingLog.getMessageMimeType(msgId);\n                mBroadcaster.broadcastMessageStatusChanged(mChatId, apiMimeType, msgId,\n                        Content.Status.RECEIVED, Content.ReasonCode.UNSPECIFIED);\n            }\n        }\n    }\n\n    @Override\n    public void onDeliveryReportSendViaMsrpFailure(String msgId, String chatId,\n            TypeMsrpChunk typeMsrpChunk) {\n        ContactId remote = mHistoryLog.getRemoteContact(msgId);\n        if (TypeMsrpChunk.MessageDeliveredReport.equals(typeMsrpChunk)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to send delivered message via MSRP, so try to send via SIP message to \"\n                        + remote + \"(msgId = \" + msgId);\n            }\n            mImService.getImdnManager().sendMessageDeliveryStatus(chatId, remote, msgId,\n                    ImdnDocument.DeliveryStatus.DELIVERED, System.currentTimeMillis());\n\n        } else if (TypeMsrpChunk.MessageDisplayedReport.equals(typeMsrpChunk)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Failed to send displayed message via MSRP, so try to send via SIP message to \"\n                        + remote + \"(msgId = \" + msgId);\n            }\n            mImService.getImdnManager().sendMessageDeliveryStatus(chatId, remote, msgId,\n                    ImdnDocument.DeliveryStatus.DISPLAYED, System.currentTimeMillis());\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/GroupFileTransferImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.DownloadFromAcceptFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.DownloadFromResumeFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.HttpFileTransferSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.ResumeUploadGroupFileSharingSession;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeDownload;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.FileTransferPersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.FileTransferStateAndReasonCode;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.service.broadcaster.GroupFileTransferBroadcaster;\nimport com.gsma.rcs.service.broadcaster.IGroupFileTransferBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.filetransfer.IFileTransfer;\n\nimport android.net.Uri;\nimport android.os.RemoteException;\n\n/**\n * Group file transfer implementation\n */\npublic class GroupFileTransferImpl extends IFileTransfer.Stub implements FileSharingSessionListener {\n\n    private final String mFileTransferId;\n\n    private final IGroupFileTransferBroadcaster mBroadcaster;\n\n    private final InstantMessagingService mImService;\n\n    private final FileTransferPersistedStorageAccessor mPersistedStorage;\n\n    private final FileTransferServiceImpl mFileTransferService;\n\n    private final RcsSettings mRcsSettings;\n\n    private final MessagingLog mMessagingLog;\n\n    private String mChatId;\n\n    private final Object mLock = new Object();\n\n    private final ContactManager mContactManager;\n\n    private final static Logger sLogger = Logger.getLogger(GroupFileTransferImpl.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param transferId Transfer ID\n     * @param broadcaster IGroupFileTransferBroadcaster\n     * @param imService InstantMessagingService\n     * @param persistedStorage FileTransferPersistedStorageAccessor\n     * @param fileTransferService FileTransferServiceImpl\n     * @param rcsSettings The RCS settings accessor\n     * @param messagingLog The messaging log accessor\n     * @param contactManager The contact manager accessor\n     * @param chatId Chat Id\n     */\n    public GroupFileTransferImpl(InstantMessagingService imService, String transferId,\n            GroupFileTransferBroadcaster broadcaster,\n            FileTransferPersistedStorageAccessor persistedStorage,\n            FileTransferServiceImpl fileTransferService, RcsSettings rcsSettings,\n            MessagingLog messagingLog, ContactManager contactManager, String chatId) {\n        mImService = imService;\n        mFileTransferId = transferId;\n        mBroadcaster = broadcaster;\n        mPersistedStorage = persistedStorage;\n        mFileTransferService = fileTransferService;\n        mRcsSettings = rcsSettings;\n        mMessagingLog = messagingLog;\n        mContactManager = contactManager;\n        mChatId = chatId;\n    }\n\n    private State getRcsState(FileSharingSession session) {\n        HttpFileTransferSession.State state = ((HttpFileTransferSession) session).getSessionState();\n        if (HttpFileTransferSession.State.ESTABLISHED == state) {\n            if (isSessionPaused(session)) {\n                return State.PAUSED;\n            }\n            return State.STARTED;\n\n        } else if (session.isInitiatedByRemote()) {\n            if (session.isSessionAccepted()) {\n                return State.ACCEPTING;\n            }\n            return State.INVITED;\n        }\n        return State.INITIATING;\n    }\n\n    private ReasonCode getRcsReasonCode(FileSharingSession session) {\n        if (isSessionPaused(session)) {\n            /*\n             * If session is paused and still established it must have been paused by user\n             */\n            return ReasonCode.PAUSED_BY_USER;\n        }\n        return ReasonCode.UNSPECIFIED;\n    }\n\n    @Override\n    public String getChatId() throws RemoteException {\n        try {\n            if (mChatId != null) {\n                return mChatId;\n            }\n            return mPersistedStorage.getChatId();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getTransferId() throws RemoteException {\n        return mFileTransferId;\n    }\n\n    @Override\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getFileName() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFileName();\n            }\n            return session.getContent().getName();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public Uri getFile() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFile();\n            }\n            return session.getContent().getUri();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getFileSize() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFileSize();\n            }\n            return session.getContent().getSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getMimeType() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getMimeType();\n            }\n            return session.getContent().getEncoding();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public Uri getFileIcon() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFileIcon();\n            }\n            MmContent fileIcon = session.getFileicon();\n            return fileIcon != null ? fileIcon.getUri() : null;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getFileIconMimeType() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFileIconMimeType();\n            }\n            MmContent fileIcon = session.getFileicon();\n            return fileIcon != null ? fileIcon.getEncoding() : null;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestamp() throws RemoteException {\n        try {\n            return mPersistedStorage.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestampSent() throws RemoteException {\n        try {\n            return mPersistedStorage.getTimestampSent();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestampDelivered() throws RemoteException {\n        try {\n            return mPersistedStorage.getTimestampDelivered();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestampDisplayed() throws RemoteException {\n        try {\n            return mPersistedStorage.getTimestampDisplayed();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getState() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getState().toInt();\n            }\n            return getRcsState(session).toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getReasonCode() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getReasonCode().toInt();\n            }\n            return getRcsReasonCode(session).toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getDisposition() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getDisposition().toInt();\n            }\n            if (session.getContent().isPlayable()) {\n                return FileTransfer.Disposition.RENDER.toInt();\n            }\n            return FileTransfer.Disposition.ATTACH.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getDirection() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void acceptInvitation() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Accept session invitation\");\n                    }\n                    final FileSharingSession ongoingSession = mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (ongoingSession != null) {\n                        if (!ongoingSession.isInitiatedByRemote()) {\n                            sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                    + mFileTransferId + \"': wrong direction\");\n                            return;\n                        }\n                        if (ongoingSession.isSessionAccepted()) {\n                            sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                    + mFileTransferId + \"': already accepted\");\n                            return;\n                        }\n                        ongoingSession.acceptSession();\n                        return;\n                    }\n                    /* No active session: restore session from provider */\n                    FtHttpResume resume = mPersistedStorage.getFileTransferResumeInfo();\n                    if (resume == null) {\n                        sLogger.error(\"Cannot find session with file transfer ID= \"\n                                .concat(mFileTransferId));\n                        return;\n                    }\n                    if (!(resume instanceof FtHttpResumeDownload)) {\n                        sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                + mFileTransferId + \"': wrong direction\");\n                        return;\n                    }\n                    FtHttpResumeDownload download = (FtHttpResumeDownload) resume;\n                    if (download.isAccepted()) {\n                        sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                + mFileTransferId + \"': already accepted\");\n                        return;\n                    }\n                    if (download.getFileExpiration() < System.currentTimeMillis()) {\n                        sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                + mFileTransferId + \"': file has expired\");\n                        return;\n                    }\n                    FileSharingSession session = new DownloadFromAcceptFileSharingSession(\n                            mImService, ContentManager.createMmContent(resume.getFile(),\n                                    resume.getMimeType(), resume.getSize(), resume.getFileName()),\n                            download, mRcsSettings, mMessagingLog, mContactManager);\n                    session.addListener(GroupFileTransferImpl.this);\n                    session.startSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to accept file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void rejectInvitation() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Reject session invitation\");\n                    }\n                    final FileSharingSession session = mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session == null) {\n                        if (Direction.INCOMING != mPersistedStorage.getDirection()) {\n                            sLogger.error(\"Cannot reject transfer with fileTransferId '\"\n                                    + mFileTransferId + \"': wrong direction\");\n                            return;\n                        }\n                        State state = mPersistedStorage.getState();\n                        switch (state) {\n                            case INVITED:\n                                handleSessionRejected(ReasonCode.REJECTED_BY_USER);\n                                return;\n\n                            case REJECTED:\n                                if (sLogger.isActivated()) {\n                                    sLogger.info(\"Transfer already rejected for ID=\"\n                                            .concat(mFileTransferId));\n                                }\n                                return;\n\n                            default:\n                                sLogger.error(\"Illegal state to reject file transfer with ID=\"\n                                        .concat(mFileTransferId));\n                                return;\n                        }\n                    }\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to reject file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void abortTransfer() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Cancel session\");\n                    }\n                    final FileSharingSession session = mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session == null) {\n                        /*\n                         * File transfer can be aborted only if it is in state QUEUED/ PAUSED when\n                         * there is no session.\n                         */\n                        State state = mPersistedStorage.getState();\n                        switch (state) {\n                            case QUEUED:\n                            case PAUSED:\n                                setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                                return;\n                            default:\n                                sLogger.error(\"Session with file transfer ID '\" + mFileTransferId\n                                        + \"' not available!\");\n                                return;\n                        }\n                    }\n                    if (session.isFileTransferred()) {\n                        /* File already transferred and session automatically closed after transfer */\n                        sLogger.error(\"Cannot abort as file is already transferred!\");\n                        return;\n                    }\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to terminate session with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean isAllowedToPauseTransfer() throws RemoteException {\n        return isAllowedToPauseTransfer(false);\n    }\n\n    private boolean isAllowedToPauseTransfer(boolean internalRequest) throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\"\n                            + mFileTransferId\n                            + \"' as there is no ongoing session corresponding to the fileTransferId.\");\n                }\n                return false;\n            }\n            State state = getRcsState(session);\n            if (State.STARTED != state) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\" + mFileTransferId\n                            + \"' as it is in state \" + state);\n                }\n                return false;\n            }\n            if (mPersistedStorage.getFileTransferProgress() == mPersistedStorage.getFileSize()) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\" + mFileTransferId\n                            + \"' as full content is transferred\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void pauseTransfer() throws RemoteException {\n        if (!isAllowedToPauseTransfer(true)) {\n            throw new ServerApiPermissionDeniedException(\"Not allowed to pause transfer.\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Pause session\");\n                }\n                try {\n                    HttpFileTransferSession session = (HttpFileTransferSession) mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session == null) {\n                        sLogger.error(\"Failed to pause file transfer with fileTransferId : \"\n                                + mFileTransferId + \"since no such session exists anymore.\");\n                        return;\n                    }\n                    session.onPause();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to pause file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Is session paused (only for HTTP transfer)\n     */\n    private boolean isSessionPaused(FileSharingSession session) {\n        if (session == null) {\n            throw new ServerApiGenericException(\n                    \"Unable to check if transfer is paused since session with file transfer ID '\"\n                            + mFileTransferId + \"' not available!\");\n        }\n        return session.isFileTransferPaused();\n    }\n\n    @Override\n    public boolean isAllowedToResumeTransfer() throws RemoteException {\n        return isAllowedToResumeTransfer(false);\n    }\n\n    private boolean isAllowedToResumeTransfer(boolean internalRequest) throws RemoteException {\n        try {\n            ReasonCode reasonCode;\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session != null) {\n                reasonCode = getRcsReasonCode(session);\n            } else {\n                reasonCode = mPersistedStorage.getReasonCode();\n            }\n            if (ReasonCode.PAUSED_BY_USER != reasonCode) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                            + mFileTransferId + \"' as it is \" + reasonCode);\n                }\n                return false;\n            }\n            if (!ServerApiUtils.isImsConnected()) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                            + mFileTransferId + \"' as it there is no IMS connection right now.\");\n                }\n                return false;\n            }\n            if (session == null) {\n                if (!mImService.isFileTransferSessionAvailable()) {\n                    if (internalRequest && sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                                + mFileTransferId\n                                + \"' as the limit of available file transfer session is reached.\");\n                    }\n                    return false;\n                }\n                if (Direction.OUTGOING == mPersistedStorage.getDirection()) {\n                    if (mImService.isMaxConcurrentOutgoingFileTransfersReached()) {\n                        if (internalRequest && sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                                    + mFileTransferId\n                                    + \"' as the limit of maximum concurrent outgoing file transfer is reached.\");\n                        }\n                        return false;\n                    }\n                }\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void resumeTransfer() throws RemoteException {\n        if (!isAllowedToResumeTransfer(true)) {\n            throw new ServerApiPermissionDeniedException(\"Not allowed to resume transfer.\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Resume session\");\n                }\n                try {\n                    HttpFileTransferSession session = (HttpFileTransferSession) mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session != null) {\n                        session.onResume();\n                        return;\n                    }\n                    FtHttpResume resume = mPersistedStorage.getFileTransferResumeInfo();\n                    if (resume == null) {\n                        sLogger.error(\"Unable to resume file with fileTransferId \"\n                                + mFileTransferId\n                                + \" since it no longer exists in persistent storage!\");\n                        return;\n                    }\n                    MmContent content = ContentManager.createMmContent(resume.getFile(),\n                            resume.getMimeType(), resume.getSize(), resume.getFileName());\n                    if (Direction.OUTGOING == resume.getDirection()) {\n                        session = new ResumeUploadGroupFileSharingSession(mImService, content,\n                                (FtHttpResumeUpload) resume, mRcsSettings, mMessagingLog,\n                                mContactManager);\n                    } else {\n                        session = new DownloadFromResumeFileSharingSession(mImService, content,\n                                (FtHttpResumeDownload) resume, mRcsSettings, mMessagingLog,\n                                mContactManager);\n                    }\n                    session.addListener(GroupFileTransferImpl.this);\n                    session.startSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to resume file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean isAllowedToResendTransfer() throws RemoteException {\n        /* Resend file transfer is supported only for one-to-one transfers */\n        return false;\n    }\n\n    @Override\n    public boolean isRead() throws RemoteException {\n        try {\n            return mPersistedStorage.isRead();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void resendTransfer() throws RemoteException {\n        throw new ServerApiUnsupportedOperationException(\n                \"Resend operation not supported for group file transfer with file transfer ID \"\n                        + mFileTransferId);\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session started\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    /**\n     * Handle file info dequeued\n     */\n    public void onFileInfoDequeued() {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Group file info with transferId \" + mFileTransferId\n                    + \" dequeued successfully.\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeGroupFileTransfer(mFileTransferId);\n            setStateAndReasonCode(State.TRANSFERRED, ReasonCode.UNSPECIFIED);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    /*\n     * TODO : Fix reasoncode mapping in the switch.\n     */\n    private FileTransferStateAndReasonCode toStateAndReasonCode(FileSharingError error) {\n        int fileSharingError = error.getErrorCode();\n        switch (fileSharingError) {\n            case FileSharingError.SESSION_INITIATION_DECLINED:\n            case FileSharingError.SESSION_INITIATION_CANCELLED:\n                return new FileTransferStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_BY_REMOTE);\n            case FileSharingError.MEDIA_SAVING_FAILED:\n                return new FileTransferStateAndReasonCode(State.FAILED, ReasonCode.FAILED_SAVING);\n            case FileSharingError.MEDIA_SIZE_TOO_BIG:\n                return new FileTransferStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_MAX_SIZE);\n            case FileSharingError.MEDIA_TRANSFER_FAILED:\n            case FileSharingError.MEDIA_UPLOAD_FAILED:\n            case FileSharingError.MEDIA_DOWNLOAD_FAILED:\n                return new FileTransferStateAndReasonCode(State.FAILED,\n                        ReasonCode.FAILED_DATA_TRANSFER);\n            case FileSharingError.NO_CHAT_SESSION:\n            case FileSharingError.SESSION_INITIATION_FAILED:\n                return new FileTransferStateAndReasonCode(State.FAILED,\n                        ReasonCode.FAILED_INITIATION);\n            case FileSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                return new FileTransferStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_LOW_SPACE);\n            default:\n                throw new IllegalArgumentException(\n                        \"Unknown reason in GroupFileTransferImpl.toStateAndReasonCode; fileSharingError=\"\n                                + fileSharingError + \"!\");\n        }\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session rejected; reasonCode=\" + reasonCode + \".\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeGroupFileTransfer(mFileTransferId);\n\n            setStateAndReasonCode(State.REJECTED, reasonCode);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    private void setStateAndReasonCode(State state, ReasonCode reasonCode) {\n        if (mPersistedStorage.setStateAndReasonCode(state, reasonCode)) {\n            mBroadcaster.broadcastStateChanged(mChatId, mFileTransferId, state, reasonCode);\n        }\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session aborted (reason \" + reason + \")\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeGroupFileTransfer(mFileTransferId);\n            switch (reason) {\n                case TERMINATION_BY_TIMEOUT:\n                case TERMINATION_BY_SYSTEM:\n                    setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    setStateAndReasonCode(State.FAILED, ReasonCode.FAILED_DATA_TRANSFER);\n                    break;\n                case TERMINATION_BY_USER:\n                    setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    /*\n                     * TODO : Fix sending of SIP BYE by sender once transfer is completed and media\n                     * session is closed. Then this check of state can be removed. Also need to\n                     * check if it is storing and broadcasting right state and reasoncode.\n                     */\n                    if (State.TRANSFERRED != mPersistedStorage.getState()) {\n                        setStateAndReasonCode(State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    }\n                    break;\n                default:\n                    throw new IllegalArgumentException(\n                            \"Unknown reason in GroupFileTransferImpl.handleSessionAborted; terminationReason=\"\n                                    + reason + \"!\");\n            }\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onTransferError(FileSharingError error, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Sharing error \" + error.getErrorCode());\n        }\n        FileTransferStateAndReasonCode stateAndReasonCode = toStateAndReasonCode(error);\n        State state = stateAndReasonCode.getState();\n        ReasonCode reasonCode = stateAndReasonCode.getReasonCode();\n        synchronized (mLock) {\n            mFileTransferService.removeGroupFileTransfer(mFileTransferId);\n            setStateAndReasonCode(state, reasonCode);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onTransferProgress(ContactId contact, long currentSize, long totalSize) {\n        synchronized (mLock) {\n            if (mPersistedStorage.setProgress(currentSize)) {\n                mBroadcaster.broadcastProgressUpdate(mChatId, mFileTransferId, currentSize,\n                        totalSize);\n            }\n        }\n    }\n\n    @Override\n    public void onTransferNotAllowedToSend(ContactId contact) {\n        synchronized (mLock) {\n            setStateAndReasonCode(State.FAILED, ReasonCode.FAILED_NOT_ALLOWED_TO_SEND);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onFileTransferred(MmContent content, ContactId contact, long fileExpiration,\n            long fileIconExpiration, FileTransferProtocol ftProtocol) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Content transferred\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeGroupFileTransfer(mFileTransferId);\n            long deliveryExpiration = 0;\n            if (mPersistedStorage.setTransferred(content, fileExpiration, fileIconExpiration,\n                    deliveryExpiration)) {\n                mBroadcaster.broadcastStateChanged(mChatId, mFileTransferId, State.TRANSFERRED,\n                        ReasonCode.UNSPECIFIED);\n            }\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onFileTransferPausedByUser(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer paused by user\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(State.PAUSED, ReasonCode.PAUSED_BY_USER);\n        }\n    }\n\n    @Override\n    public void onFileTransferPausedBySystem(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer paused by system\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeGroupFileTransfer(mFileTransferId);\n            setStateAndReasonCode(State.PAUSED, ReasonCode.PAUSED_BY_SYSTEM);\n        }\n    }\n\n    @Override\n    public void onFileTransferResumed(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer resumed\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Accepting transfer\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason + \"!\");\n        }\n    }\n\n    @Override\n    public void onSessionInvited(ContactId contact, MmContent file, MmContent fileIcon,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Invited to group file transfer session\");\n        }\n        synchronized (mLock) {\n            mPersistedStorage.addIncomingGroupFileTransfer(mChatId, contact, file, fileIcon,\n                    State.INVITED, ReasonCode.UNSPECIFIED, timestamp, timestampSent,\n                    fileExpiration, fileIconExpiration);\n        }\n\n        mBroadcaster.broadcastInvitation(mFileTransferId);\n    }\n\n    @Override\n    public void onSessionAutoAccepted(ContactId contact, MmContent file, MmContent fileIcon,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session auto accepted\");\n        }\n        synchronized (mLock) {\n            mPersistedStorage.addIncomingGroupFileTransfer(mChatId, contact, file, fileIcon,\n                    State.ACCEPTING, ReasonCode.UNSPECIFIED, timestamp, timestampSent,\n                    fileExpiration, fileIconExpiration);\n        }\n\n        mBroadcaster.broadcastInvitation(mFileTransferId);\n    }\n\n    @Override\n    public long getFileExpiration() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFileExpiration();\n            }\n            return session.getFileExpiration();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getFileIconExpiration() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistedStorage.getFileIconExpiration();\n            }\n            return session.getIconExpiration();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isExpiredDelivery() throws RemoteException {\n        /* Delivery expiration is not applicable for group file transfers. */\n        return false;\n    }\n\n    @Override\n    public void onHttpDownloadInfoAvailable() {\n        mImService.tryToDequeueFileTransfers();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/HistoryServiceImpl.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.provider.history.HistoryLogData;\nimport com.gsma.rcs.provider.history.HistoryMemberBaseIdCreator;\nimport com.gsma.rcs.provider.history.HistoryProvider;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.sharing.GeolocSharingData;\nimport com.gsma.rcs.provider.sharing.ImageSharingData;\nimport com.gsma.rcs.provider.sharing.VideoSharingData;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.history.IHistoryService;\n\nimport android.content.ContentProvider;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.RemoteException;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * History service implementation\n */\npublic class HistoryServiceImpl extends IHistoryService.Stub {\n\n    private static final Set<Integer> INTERNAL_MEMBER_IDS = new HashSet<>(Arrays.asList(\n            MessageData.HISTORYLOG_MEMBER_ID, FileTransferData.HISTORYLOG_MEMBER_ID,\n            ImageSharingData.HISTORYLOG_MEMBER_ID, VideoSharingData.HISTORYLOG_MEMBER_ID,\n            GeolocSharingData.HISTORYLOG_MEMBER_ID));\n\n    private static final Logger sLogger = Logger\n            .getLogger(HistoryServiceImpl.class.getSimpleName());\n\n    private final Context mCtx;\n\n    private HistoryProvider mHistoryProvider;\n\n    public HistoryServiceImpl(Context ctx) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"History service API is loaded.\");\n        }\n        mCtx = ctx;\n    }\n\n    private HistoryProvider retrieveHistoryLogProvider() {\n        if (mHistoryProvider != null) {\n            return mHistoryProvider;\n        }\n        String historyLogAuthority = HistoryLogData.CONTENT_URI.getAuthority();\n        ContentProvider provider = mCtx.getContentResolver()\n                .acquireContentProviderClient(historyLogAuthority).getLocalContentProvider();\n        mHistoryProvider = (HistoryProvider) provider;\n        return mHistoryProvider;\n    }\n\n    /**\n     * Validates that the provided map is of generic type Map<String, String>.\n     * \n     * @param columnMapping column mapping\n     */\n    /* Only raw map types are supported by AIDL. */\n    private static void assertMapTypeOfString(@SuppressWarnings(\"rawtypes\") Map columnMapping) {\n        if (columnMapping == null) {\n            throw new ServerApiIllegalArgumentException(\n                    \"Column mapping of history log field names to internal field names must not be null!\");\n        }\n        for (Object key : columnMapping.keySet()) {\n            if (!((key instanceof String) && (columnMapping.get(key) instanceof String))) {\n                throw new ServerApiIllegalArgumentException(new StringBuilder(\n                        \"Map not valid when registering provider with key \").append(key)\n                        .append(\"!\").toString());\n            }\n        }\n    }\n\n    public void close() {\n        mHistoryProvider = null;\n        if (sLogger.isActivated()) {\n            sLogger.info(\"History service API is closed\");\n        }\n    }\n\n    /**\n     * Registers an external history log member.\n     * \n     * @param providerId Id of provider\n     * @param providerUri Provider URI\n     * @param databaseUri Database URI\n     * @param table Table name\n     * @param columnMapping Translator of history log field names to internal field names\n     * @throws RemoteException\n     */\n    /*\n     * Unchecked cast must be suppressed since AIDL provides a raw Map type that must be cast.\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public void registerExtraHistoryLogMember(int providerId, Uri providerUri, Uri databaseUri,\n            String table,\n            /* Only raw map types are supported by AIDL. */\n            @SuppressWarnings(\"rawtypes\") Map columnMapping) throws RemoteException {\n        try {\n            assertMapTypeOfString(columnMapping);\n            retrieveHistoryLogProvider().registerDatabase(providerId, providerUri, databaseUri,\n                    table, columnMapping);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Unregisters an external history log member.\n     * \n     * @param providerId Id of history log member\n     * @throws RemoteException\n     */\n    @Override\n    public void unregisterExtraHistoryLogMember(int providerId) throws RemoteException {\n        try {\n            retrieveHistoryLogProvider().unregisterDatabaseByProviderId(providerId);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long createUniqueId(int providerId) throws RemoteException {\n        try {\n            if (INTERNAL_MEMBER_IDS.contains(providerId)\n                    || providerId > HistoryProvider.MAX_ATTACHED_PROVIDERS) {\n                throw new ServerApiIllegalArgumentException(new StringBuilder()\n                        .append(\"Cannot create ID (not allowed) for internal provider \")\n                        .append(providerId).toString());\n            }\n            return HistoryMemberBaseIdCreator.createUniqueId(mCtx, providerId);\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ImageSharingImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.image.ImageTransferSession;\nimport com.gsma.rcs.core.ims.service.richcall.image.ImageTransferSessionListener;\nimport com.gsma.rcs.provider.sharing.ImageSharingPersistedStorageAccessor;\nimport com.gsma.rcs.provider.sharing.ImageSharingStateAndReasonCode;\nimport com.gsma.rcs.service.broadcaster.IImageSharingEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.IImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport android.net.Uri;\nimport android.os.RemoteException;\n\n/**\n * Image sharing implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ImageSharingImpl extends IImageSharing.Stub implements ImageTransferSessionListener {\n\n    private final String mSharingId;\n\n    private final IImageSharingEventBroadcaster mBroadcaster;\n\n    private final RichcallService mRichcallService;\n\n    private final ImageSharingPersistedStorageAccessor mPersistentStorage;\n\n    private final ImageSharingServiceImpl mImageSharingService;\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(ImageSharingImpl.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param sharingId Unique Id of Image Sharing\n     * @param richcallService RichcallService\n     * @param broadcaster IImageSharingEventBroadcaster\n     * @param persistentStorage ImageSharingPersistedStorageAccessor\n     * @param imageSharingService ImageSharingServiceImpl\n     */\n    public ImageSharingImpl(String sharingId, RichcallService richcallService,\n            IImageSharingEventBroadcaster broadcaster,\n            ImageSharingPersistedStorageAccessor persistentStorage,\n            ImageSharingServiceImpl imageSharingService) {\n        mSharingId = sharingId;\n        mRichcallService = richcallService;\n        mBroadcaster = broadcaster;\n        mPersistentStorage = persistentStorage;\n        mImageSharingService = imageSharingService;\n    }\n\n    /*\n     * TODO: Fix reasoncode mapping in the switch.\n     */\n    private ImageSharingStateAndReasonCode toStateAndReasonCode(ContentSharingError error) {\n        int contentSharingError = error.getErrorCode();\n        switch (contentSharingError) {\n            case ContentSharingError.SESSION_INITIATION_FAILED:\n            case ContentSharingError.SEND_RESPONSE_FAILED:\n                return new ImageSharingStateAndReasonCode(ImageSharing.State.FAILED,\n                        ReasonCode.FAILED_INITIATION);\n            case ContentSharingError.SESSION_INITIATION_CANCELLED:\n            case ContentSharingError.SESSION_INITIATION_DECLINED:\n                return new ImageSharingStateAndReasonCode(ImageSharing.State.REJECTED,\n                        ReasonCode.REJECTED_BY_REMOTE);\n            case ContentSharingError.MEDIA_SAVING_FAILED:\n                return new ImageSharingStateAndReasonCode(ImageSharing.State.FAILED,\n                        ReasonCode.FAILED_SAVING);\n            case ContentSharingError.MEDIA_TRANSFER_FAILED:\n            case ContentSharingError.MEDIA_STREAMING_FAILED:\n            case ContentSharingError.UNSUPPORTED_MEDIA_TYPE:\n                return new ImageSharingStateAndReasonCode(ImageSharing.State.FAILED,\n                        ReasonCode.FAILED_SHARING);\n            case ContentSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                return new ImageSharingStateAndReasonCode(ImageSharing.State.REJECTED,\n                        ReasonCode.REJECTED_LOW_SPACE);\n            case ContentSharingError.MEDIA_SIZE_TOO_BIG:\n                return new ImageSharingStateAndReasonCode(ImageSharing.State.REJECTED,\n                        ReasonCode.REJECTED_MAX_SIZE);\n            default:\n                throw new IllegalArgumentException(\n                        \"Unknown reason in ImageSharingImpl.toStateAndReasonCode; contentSharingError=\"\n                                + contentSharingError + \"!\");\n        }\n    }\n\n    private void setStateAndReasonCode(ContactId contact, State state, ReasonCode reasonCode) {\n        if (mPersistentStorage.setStateAndReasonCode(state, reasonCode)) {\n            mBroadcaster.broadcastStateChanged(contact, mSharingId, state, reasonCode);\n        }\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session rejected; reasonCode=\" + reasonCode + \".\");\n        }\n        synchronized (mLock) {\n            mImageSharingService.removeImageSharing(mSharingId);\n            setStateAndReasonCode(contact, ImageSharing.State.REJECTED, reasonCode);\n        }\n    }\n\n    /**\n     * Returns the sharing ID of the image sharing\n     * \n     * @return Sharing ID\n     * @throws RemoteException\n     */\n    public String getSharingId() throws RemoteException {\n        try {\n            return mSharingId;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RemoteException\n     */\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the complete filename including the path of the file to be transferred\n     * \n     * @return Filename\n     * @throws RemoteException\n     */\n    public String getFileName() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getFileName();\n            }\n            return session.getContent().getName();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the Uri of the file to be transferred\n     * \n     * @return Filename\n     * @throws RemoteException\n     */\n    public Uri getFile() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getFile();\n            }\n            return session.getContent().getUri();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the size of the file to be transferred\n     * \n     * @return Size in bytes\n     * @throws RemoteException\n     */\n    public long getFileSize() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getFileSize();\n            }\n            return session.getContent().getSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the MIME type of the file to be transferred\n     * \n     * @return Type\n     * @throws RemoteException\n     */\n    public String getMimeType() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getMimeType();\n            }\n            return session.getContent().getEncoding();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the image sharing\n     * \n     * @return State\n     * @throws RemoteException\n     */\n    public int getState() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getState().toInt();\n            }\n            if (session.isImageTransferred()) {\n                return ImageSharing.State.TRANSFERRED.toInt();\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return ImageSharing.State.STARTED.toInt();\n\n            } else if (session.isInitiatedByRemote()) {\n                if (session.isSessionAccepted()) {\n                    return ImageSharing.State.ACCEPTING.toInt();\n                }\n                return ImageSharing.State.INVITED.toInt();\n            }\n            return ImageSharing.State.INITIATING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the image sharing\n     * \n     * @return ReasonCode\n     * @throws RemoteException\n     */\n    public int getReasonCode() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getReasonCode().toInt();\n            }\n            return ReasonCode.UNSPECIFIED.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the sharing (incoming or outgoing)\n     * \n     * @return Direction\n     * @throws RemoteException\n     * @see Direction\n     */\n    public int getDirection() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the image sharing was initiated for outgoing image\n     * sharing or the local timestamp of when the image sharing invitation was received for incoming\n     * image sharings.\n     * \n     * @return long\n     * @throws RemoteException\n     */\n    public long getTimestamp() throws RemoteException {\n        try {\n            ImageTransferSession session = mRichcallService.getImageTransferSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getTimestamp();\n            }\n            return session.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts image sharing invitation\n     * \n     * @throws RemoteException\n     */\n    public void acceptInvitation() throws RemoteException {\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Accept session invitation\");\n                    }\n                    final ImageTransferSession session = mRichcallService\n                            .getImageTransferSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"Cannot accept sharing: no session with ID=\"\n                                .concat(mSharingId));\n                        return;\n                    }\n                    session.acceptSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to accept invitation with sharing ID: \" + mSharingId, e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejects image sharing invitation\n     * \n     * @throws RemoteException\n     */\n    public void rejectInvitation() throws RemoteException {\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Reject session invitation\");\n                    }\n                    final ImageTransferSession session = mRichcallService\n                            .getImageTransferSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"Cannot reject sharing: no session with ID=\"\n                                .concat(mSharingId));\n                        return;\n                    }\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to reject invitation with sharing ID: \" + mSharingId, e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Aborts the sharing\n     * \n     * @throws RemoteException\n     */\n    public void abortSharing() throws RemoteException {\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Abort session\");\n                    }\n                    final ImageTransferSession session = mRichcallService\n                            .getImageTransferSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"No ongoing session with sharing ID:\" + mSharingId\n                                + \" is found so nothing to abort!\");\n                        return;\n                    }\n                    if (session.isImageTransferred()) {\n                        sLogger.debug(\"Session with sharing ID:\" + mSharingId\n                                + \" is already transferred so nothing to abort!\");\n                        return;\n                    }\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to terminate session with sharing ID: \" + mSharingId, e);\n                }\n            }\n        });\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session started\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, ImageSharing.State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session aborted (terminationReason \" + reason + \")\");\n        }\n        synchronized (mLock) {\n            mImageSharingService.removeImageSharing(mSharingId);\n            switch (reason) {\n                case TERMINATION_BY_SYSTEM:\n                case TERMINATION_BY_TIMEOUT:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    setStateAndReasonCode(contact, State.FAILED, ReasonCode.FAILED_SHARING);\n                    break;\n                case TERMINATION_BY_USER:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    /*\n                     * TODO : Fix sending of SIP BYE by sender once transfer is completed and media\n                     * session is closed. Then this check of state can be removed.\n                     */\n                    if (State.TRANSFERRED != mPersistentStorage.getState()) {\n                        setStateAndReasonCode(contact, ImageSharing.State.ABORTED,\n                                ReasonCode.ABORTED_BY_REMOTE);\n                    }\n                    break;\n                default:\n                    throw new IllegalArgumentException(\n                            \"Unknown reason in ImageSharingImpl.handleSessionAborted; terminationReason=\"\n                                    + reason + \"!\");\n            }\n        }\n    }\n\n    @Override\n    public void onSharingError(ContactId contact, ContentSharingError error) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Sharing error \" + error.getErrorCode());\n        }\n        ImageSharingStateAndReasonCode stateAndReasonCode = toStateAndReasonCode(error);\n        State state = stateAndReasonCode.getState();\n        ReasonCode reasonCode = stateAndReasonCode.getReasonCode();\n        synchronized (mLock) {\n            mImageSharingService.removeImageSharing(mSharingId);\n            setStateAndReasonCode(contact, state, reasonCode);\n        }\n    }\n\n    @Override\n    public void onSharingProgress(ContactId contact, long currentSize, long totalSize) {\n        synchronized (mLock) {\n            if (mPersistentStorage.setProgress(currentSize)) {\n                mBroadcaster.broadcastProgressUpdate(contact, mSharingId, currentSize, totalSize);\n            }\n        }\n    }\n\n    @Override\n    public void onContentTransferred(ContactId contact, Uri file) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Image transferred\");\n        }\n        synchronized (mLock) {\n            mImageSharingService.removeImageSharing(mSharingId);\n            setStateAndReasonCode(contact, ImageSharing.State.TRANSFERRED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Accepting sharing\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, ImageSharing.State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER, contact);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM, contact);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT, contact);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE, contact);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason + \"!\");\n        }\n    }\n\n    @Override\n    public void onInvitationReceived(ContactId contact, MmContent content, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Invited to image sharing session\");\n        }\n        synchronized (mLock) {\n            mPersistentStorage.addImageSharing(contact, Direction.INCOMING, content,\n                    ImageSharing.State.INVITED, ReasonCode.UNSPECIFIED, timestamp);\n        }\n\n        mBroadcaster.broadcastInvitation(mSharingId);\n    }\n\n    @Override\n    public void onSessionRinging(ContactId contact) {\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, ImageSharing.State.RINGING, ReasonCode.UNSPECIFIED);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ImageSharingServiceConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport android.os.RemoteException;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.sharing.image.IImageSharingServiceConfiguration;\n\n/**\n * A class that implements interface to allow access to image sharing service configuration from API\n * \n * @author yplo6403\n */\npublic class ImageSharingServiceConfigurationImpl extends IImageSharingServiceConfiguration.Stub {\n\n    private final RcsSettings mRcsSettings;\n\n    private final Logger mLogger = Logger.getLogger(getClass().getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings RCS settings accessor\n     */\n    public ImageSharingServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public long getMaxSize() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxImageSharingSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ImageSharingServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.service.SessionIdGenerator;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.image.ImageTransferSession;\nimport com.gsma.rcs.platform.file.FileDescription;\nimport com.gsma.rcs.platform.file.FileFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.ImageSharingPersistedStorageAccessor;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.service.broadcaster.ImageSharingEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.IImageSharing;\nimport com.gsma.services.rcs.sharing.image.IImageSharingListener;\nimport com.gsma.services.rcs.sharing.image.IImageSharingService;\nimport com.gsma.services.rcs.sharing.image.IImageSharingServiceConfiguration;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Image sharing service implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ImageSharingServiceImpl extends IImageSharingService.Stub {\n\n    private final ImageSharingEventBroadcaster mBroadcaster = new ImageSharingEventBroadcaster();\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final RichcallService mRichcallService;\n\n    private final RichCallHistory mRichCallLog;\n\n    private final RcsSettings mRcsSettings;\n\n    private final Map<String, IImageSharing> mImageSharingCache = new HashMap<>();\n\n    private static final Logger sLogger = Logger.getLogger(ImageSharingServiceImpl.class\n            .getSimpleName());\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    /**\n     * Constructor\n     * \n     * @param richcallService Richcall Service\n     * @param richCallLog RichCallHistory accessor\n     * @param rcsSettings RcsSettings accessor\n     */\n    public ImageSharingServiceImpl(RichcallService richcallService, RichCallHistory richCallLog,\n            RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Image sharing service API is loaded\");\n        }\n        mRichcallService = richcallService;\n        mRichcallService.register(this);\n        mRichCallLog = richCallLog;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        mImageSharingCache.clear();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Image sharing service API is closed\");\n        }\n    }\n\n    /**\n     * Add an image sharing in the list\n     * \n     * @param imageSharing Image sharing\n     * @param sharingId String\n     */\n    private void addImageSharing(ImageSharingImpl imageSharing, String sharingId) {\n        mImageSharingCache.put(sharingId, imageSharing);\n    }\n\n    /**\n     * Remove an image sharing from the list\n     * \n     * @param sharingId Sharing ID\n     */\n    public void removeImageSharing(String sharingId) {\n        mImageSharingCache.remove(sharingId);\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return Returns true if registered else returns false\n     */\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Return the reason code for IMS service registration\n     * \n     * @return the reason code for IMS service registration\n     */\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    public void setImageSharingStateAndReasonCode(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode) {\n        mRichCallLog.setImageSharingStateAndReasonCode(sharingId, state, reasonCode);\n        mBroadcaster.broadcastStateChanged(contact, sharingId, state, reasonCode);\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     * \n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Receive a new image sharing invitation\n     * \n     * @param session Image sharing session\n     */\n    public void receiveImageSharingInvitation(ImageTransferSession session) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Receive image sharing invitation from \" + session.getRemoteContact()\n                    + \" displayName=\" + session.getRemoteDisplayName());\n        }\n        String sharingId = session.getSessionID();\n        ImageSharingPersistedStorageAccessor persistedStorage = new ImageSharingPersistedStorageAccessor(\n                sharingId, mRichCallLog);\n        ImageSharingImpl imageSharing = new ImageSharingImpl(sharingId, mRichcallService,\n                mBroadcaster, persistedStorage, this);\n        addImageSharing(imageSharing, sharingId);\n        session.addListener(imageSharing);\n    }\n\n    /**\n     * Returns the configuration of image sharing service\n     * \n     * @return Configuration\n     * @throws RemoteException\n     */\n    public IImageSharingServiceConfiguration getConfiguration() throws RemoteException {\n        try {\n            return new ImageSharingServiceConfigurationImpl(mRcsSettings);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Shares an image with a contact. The parameter file contains the URI of the image to be\n     * shared(for a local or a remote image). An exception if thrown if there is no ongoing CS call.\n     * The parameter contact supports the following formats: MSISDN in national or international\n     * format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an\n     * exception is thrown.\n     * \n     * @param contact Contact ID\n     * @param file Uri of file to share\n     * @return Image sharing\n     * @throws RemoteException\n     */\n    public IImageSharing shareImage(ContactId contact, Uri file) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (file == null) {\n            throw new ServerApiIllegalArgumentException(\"file must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate an image sharing session with \".concat(contact.toString()));\n        }\n        ServerApiUtils.testIms();\n        try {\n            Uri localFile = FileUtils.createCopyOfSentFile(file, mRcsSettings);\n            FileDescription desc = FileFactory.getFactory().getFileDescription(localFile);\n            String mime = FileUtils.getMimeTypeFromExtension(desc.getName());\n            MmContent content = ContentManager.createMmContent(localFile, mime, desc.getSize(),\n                    desc.getName());\n            long timestamp = System.currentTimeMillis();\n            final ImageTransferSession session = mRichcallService.createImageSharingSession(\n                    contact, content, null, timestamp);\n            final String sharingId = session.getSessionID();\n            mRichCallLog.addImageSharing(sharingId, contact, Direction.OUTGOING,\n                    session.getContent(), ImageSharing.State.INITIATING, ReasonCode.UNSPECIFIED,\n                    timestamp);\n\n            ImageSharingPersistedStorageAccessor persistedStorage = new ImageSharingPersistedStorageAccessor(\n                    sharingId, contact, Direction.OUTGOING, localFile, content.getName(),\n                    content.getEncoding(), content.getSize(), mRichCallLog, timestamp);\n            final ImageSharingImpl imageSharing = new ImageSharingImpl(sharingId, mRichcallService,\n                    mBroadcaster, persistedStorage, this);\n\n            final ImageSharingServiceImpl imageSharingService = this;\n            mRichcallService.scheduleImageShareOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        session.addListener(imageSharing);\n                        imageSharingService.addImageSharing(imageSharing, sharingId);\n                        session.startSession();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed initiate image sharing right now!\", e);\n                    }\n                }\n            });\n            return imageSharing;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current image sharing from its unique ID\n     * \n     * @param sharingId Sharing ID\n     * @return Image sharing\n     * @throws RemoteException\n     */\n    public IImageSharing getImageSharing(String sharingId) throws RemoteException {\n        if (TextUtils.isEmpty(sharingId)) {\n            throw new ServerApiIllegalArgumentException(\"sharingId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get image sharing session \".concat(sharingId));\n        }\n        try {\n            IImageSharing imageSharing = mImageSharingCache.get(sharingId);\n            if (imageSharing != null) {\n                return imageSharing;\n            }\n            ImageSharingPersistedStorageAccessor persistedStorage = new ImageSharingPersistedStorageAccessor(\n                    sharingId, mRichCallLog);\n            return new ImageSharingImpl(sharingId, mRichcallService, mBroadcaster,\n                    persistedStorage, this);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Add and broadcast image sharing invitation rejection invitation.\n     * \n     * @param contact Contact\n     * @param content Image content\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void addImageSharingInvitationRejected(ContactId contact, MmContent content,\n            ReasonCode reasonCode, long timestamp) {\n        String sessionId = SessionIdGenerator.getNewId();\n        mRichCallLog.addImageSharing(sessionId, contact, Direction.INCOMING, content,\n                ImageSharing.State.REJECTED, reasonCode, timestamp);\n        mBroadcaster.broadcastInvitation(sessionId);\n    }\n\n    /**\n     * Adds a listener on image sharing events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    public void addEventListener2(IImageSharingListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mBroadcaster.addEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on image sharing events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    public void removeEventListener2(IImageSharingListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        try {\n            synchronized (mLock) {\n                mBroadcaster.removeEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all image sharing from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RemoteException\n     */\n    public void deleteImageSharings() throws RemoteException {\n        mRichcallService.tryToDeleteImageSharings();\n    }\n\n    /**\n     * Deletes image sharing with a given contact from history and abort/reject any associated\n     * ongoing session if such exists\n     * \n     * @param contact Remote contact\n     * @throws RemoteException\n     */\n    public void deleteImageSharings2(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        mRichcallService.tryToDeleteImageSharings(contact);\n    }\n\n    /**\n     * deletes an image sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId Sharing ID\n     * @throws RemoteException\n     */\n    public void deleteImageSharing(String sharingId) throws RemoteException {\n        if (TextUtils.isEmpty(sharingId)) {\n            throw new ServerApiIllegalArgumentException(\"sharingId must not be null or empty!\");\n        }\n        mRichcallService.tryToDeleteImageSharing(sharingId);\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    public void broadcastDeleted(ContactId contact, Set<String> sharingIds) {\n        mBroadcaster.broadcastDeleted(contact, sharingIds);\n    }\n\n    /**\n     * Ensure copy of file if existing is deleted\n     *\n     * @param sharingId Unique Id of file transfer\n     */\n    public void ensureFileCopyIsDeletedIfExisting(String sharingId) {\n        if (Direction.INCOMING == mRichCallLog.getImageSharingDirection(sharingId)) {\n            return;\n        }\n        Uri file = mRichCallLog.getFile(sharingId);\n        if (file != null) {\n            new File(file.getPath()).delete();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/MultimediaMessagingSessionImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.core.ims.service.sip.messaging.GenericSipMsrpSession;\nimport com.gsma.rcs.service.broadcaster.IMultimediaMessagingSessionEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.IMultimediaMessagingSession;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\nimport android.os.RemoteException;\n\n/**\n * Multimedia messaging session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaMessagingSessionImpl extends IMultimediaMessagingSession.Stub implements\n        SipSessionListener {\n\n    private final String mSessionId;\n\n    private final IMultimediaMessagingSessionEventBroadcaster mBroadcaster;\n\n    private final SipService mSipService;\n\n    private final MultimediaSessionServiceImpl mMultimediaSessionService;\n\n    private final MultimediaSessionStorageAccessor mPersistedStorage;\n\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(MultimediaMessagingSessionImpl.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param sessionId Session ID\n     * @param broadcaster IMultimediaMessagingSessionEventBroadcaster\n     * @param sipService SipService\n     * @param multimediaSessionService MultimediaSessionServiceImpl\n     * @param direction Direction\n     * @param contact remote contact\n     * @param serviceId Service ID\n     * @param state State of the multimedia session\n     */\n    public MultimediaMessagingSessionImpl(String sessionId,\n            IMultimediaMessagingSessionEventBroadcaster broadcaster, SipService sipService,\n            MultimediaSessionServiceImpl multimediaSessionService, Direction direction,\n            ContactId contact, String serviceId, State state) {\n        mSessionId = sessionId;\n        mBroadcaster = broadcaster;\n        mSipService = sipService;\n        mMultimediaSessionService = multimediaSessionService;\n        mPersistedStorage = new MultimediaSessionStorageAccessor(direction, contact, serviceId,\n                state);\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session rejected; reasonCode=\" + reasonCode + \".\");\n        }\n        String sessionId = getSessionId();\n        synchronized (mLock) {\n            mMultimediaSessionService.removeMultimediaMessaging(sessionId);\n            setStateAndReason(contact, State.REJECTED, reasonCode);\n        }\n    }\n\n    private void removeSession(ContactId contact, State state, ReasonCode reasonCode) {\n        mMultimediaSessionService.removeMultimediaMessaging(mSessionId);\n        setStateAndReason(contact, state, reasonCode);\n    }\n\n    private void setStateAndReason(ContactId contact, State state, ReasonCode reason) {\n        mPersistedStorage.setStateAndReasonCode(state, reason);\n        mBroadcaster.broadcastStateChanged(contact, mSessionId, state, reason);\n    }\n\n    /**\n     * Returns the session ID of the multimedia session\n     * \n     * @return Session ID\n     */\n    public String getSessionId() {\n        return mSessionId;\n    }\n\n    /**\n     * Returns the remote contact ID\n     * \n     * @return ContactId\n     * @throws RemoteException\n     */\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            GenericSipMsrpSession session = mSipService.getGenericSipMsrpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the session\n     * \n     * @return State\n     * @throws RemoteException\n     */\n    public int getState() throws RemoteException {\n        try {\n            GenericSipMsrpSession session = mSipService.getGenericSipMsrpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getState().toInt();\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return State.STARTED.toInt();\n\n            } else if (session.isInitiatedByRemote()) {\n                if (session.isSessionAccepted()) {\n                    return State.ACCEPTING.toInt();\n                }\n                return State.INVITED.toInt();\n            }\n            return State.INITIATING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the multimedia messaging session\n     * \n     * @return ReasonCode\n     * @throws RemoteException\n     */\n    public int getReasonCode() throws RemoteException {\n        try {\n            GenericSipMsrpSession session = mSipService.getGenericSipMsrpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getReasonCode().toInt();\n            }\n            return ReasonCode.UNSPECIFIED.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the session (incoming or outgoing)\n     * \n     * @return Direction\n     * @throws RemoteException\n     * @see Direction\n     */\n    public int getDirection() throws RemoteException {\n        try {\n            GenericSipMsrpSession session = mSipService.getGenericSipMsrpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the service ID\n     * \n     * @return Service ID\n     * @throws RemoteException\n     */\n    public String getServiceId() throws RemoteException {\n        try {\n            GenericSipMsrpSession session = mSipService.getGenericSipMsrpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getServiceId();\n            }\n            return session.getServiceId();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts session invitation\n     * \n     * @throws RemoteException\n     */\n    public void acceptInvitation() throws RemoteException {\n        mSipService.scheduleMultimediaMessagingOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Accept session invitation\");\n                    }\n                    final GenericSipMsrpSession session = mSipService\n                            .getGenericSipMsrpSession(mSessionId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot accept: no session ID=\".concat(mSessionId));\n                        }\n                        return;\n                    }\n                    ServerApiUtils.testImsExtension(session.getServiceId());\n                    session.acceptSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to accept session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejects session invitation\n     * \n     * @throws RemoteException\n     */\n    public void rejectInvitation() throws RemoteException {\n        mSipService.scheduleMultimediaMessagingOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Reject session invitation\");\n                    }\n                    final GenericSipMsrpSession session = mSipService\n                            .getGenericSipMsrpSession(mSessionId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot reject: no session ID=\".concat(mSessionId));\n                        }\n                        return;\n                    }\n                    ServerApiUtils.testImsExtension(session.getServiceId());\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to reject session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Aborts the session\n     * \n     * @throws RemoteException\n     */\n    public void abortSession() throws RemoteException {\n        mSipService.scheduleMultimediaMessagingOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Abort session\");\n                    }\n                    final GenericSipMsrpSession session = mSipService\n                            .getGenericSipMsrpSession(mSessionId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"No ongoing session with id:\" + mSessionId\n                                    + \" is found so nothing to abort!\");\n                        }\n                        return;\n                    }\n                    if (session.isSessionInterrupted()) {\n                        sLogger.debug(\"Session with sharing ID:\" + mSessionId\n                                + \" is already aborted!\");\n                        return;\n                    }\n                    ServerApiUtils.testImsExtension(session.getServiceId());\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to abort session with ID: \".concat(mSessionId), e);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n\n                }\n            }\n        });\n    }\n\n    /**\n     * Sends a message in real time\n     * \n     * @param content Message content\n     * @throws RemoteException\n     */\n    public void sendMessage(final byte[] content) throws RemoteException {\n        sendMessage2(content, SipService.DEFAULT_MIME_TYPE);\n    }\n\n    /**\n     * Sends a message in real time\n     *\n     * @param content Message content\n     * @param contentType Message content type\n     * @throws RemoteException\n     */\n    public void sendMessage2(final byte[] content, final String contentType) throws RemoteException {\n        if (content == null || content.length == 0) {\n            throw new ServerApiIllegalArgumentException(\"content must not be null or empty!\");\n        }\n        if (contentType == null || contentType.length() == 0) {\n            throw new ServerApiIllegalArgumentException(\"content type must not be null or empty!\");\n        }\n        mSipService.scheduleMultimediaMessagingOperation(new Runnable() {\n            public void run() {\n                try {\n                    GenericSipMsrpSession session = mSipService\n                            .getGenericSipMsrpSession(mSessionId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session with session ID '\" + mSessionId\n                                    + \"' not available!\");\n                        }\n                        return;\n                    }\n\n                    /* Do not consider max message size if null */\n                    int maxMessageSize = session.getMaxMessageSize();\n                    if (maxMessageSize != 0 && content.length > maxMessageSize) {\n                        sLogger.error(\"Failed to send message: max length exceeded!\");\n                        return;\n                    }\n                    session.sendMessage(content, contentType);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            \"Failed to send message within session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Flush all messages of the session\n     *\n     * @throws RemoteException\n     */\n    public void flushMessages() throws RemoteException {\n        mSipService.scheduleMultimediaMessagingOperation(new Runnable() {\n            public void run() {\n                try {\n                    final GenericSipMsrpSession session = mSipService\n                            .getGenericSipMsrpSession(mSessionId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot flush: no session ID=\".concat(mSessionId));\n                        }\n                        return;\n                    }\n                    session.flushMessages();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            \"Failed to flush messages for session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session started\");\n        }\n        synchronized (mLock) {\n            setStateAndReason(contact, State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session aborted (terminationReason \" + reason + \")\");\n        }\n        synchronized (mLock) {\n            switch (reason) {\n                case TERMINATION_BY_SYSTEM:\n                case TERMINATION_BY_TIMEOUT:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_USER:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    removeSession(contact, State.FAILED, ReasonCode.FAILED_SESSION);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    break;\n                case TERMINATION_BY_INACTIVITY:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_INACTIVITY);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown TerminationReason=\" + reason);\n            }\n        }\n    }\n\n    @Override\n    public void onSessionError(ContactId contact, SipSessionError error) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session error \" + error.getErrorCode());\n        }\n        synchronized (mLock) {\n            mMultimediaSessionService.removeMultimediaMessaging(mSessionId);\n\n            switch (error.getErrorCode()) {\n                case SipSessionError.SESSION_INITIATION_DECLINED:\n                    setStateAndReason(contact, State.REJECTED, ReasonCode.REJECTED_BY_REMOTE);\n                    break;\n                case SipSessionError.MEDIA_FAILED:\n                    setStateAndReason(contact, State.FAILED, ReasonCode.FAILED_MEDIA);\n                    break;\n                case SipSessionError.SESSION_INITIATION_CANCELLED:\n                case SipSessionError.SESSION_INITIATION_FAILED:\n                    setStateAndReason(contact, State.FAILED, ReasonCode.FAILED_INITIATION);\n                    break;\n                default:\n                    setStateAndReason(contact, State.FAILED, ReasonCode.FAILED_SESSION);\n            }\n        }\n    }\n\n    @Override\n    public void onDataReceived(ContactId contact, byte[] data, String contentType) {\n        synchronized (mLock) {\n            mBroadcaster.broadcastMessageReceived(contact, mSessionId, data, contentType);\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Accepting session\");\n        }\n        synchronized (mLock) {\n            setStateAndReason(contact, State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER, contact);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM, contact);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT, contact);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE, contact);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason + \"!\");\n        }\n    }\n\n    @Override\n    public void onInvitationReceived(ContactId contact, Intent sessionInvite) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Invited to multimedia messaging session\");\n        }\n        mBroadcaster.broadcastInvitation(getSessionId(), sessionInvite);\n    }\n\n    @Override\n    public void onSessionRinging(ContactId contact) {\n        synchronized (mLock) {\n            setStateAndReason(contact, State.RINGING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onDataFlushed(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Messages have been flushed\");\n        }\n        synchronized (mLock) {\n            mBroadcaster.broadcastMessagesFlushed(contact, mSessionId);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/MultimediaSessionServiceConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.service.sip.EnrichCallingService;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.extension.IMultimediaSessionServiceConfiguration;\n\nimport android.os.RemoteException;\n\n/**\n * A class that implements interface to allow access to multimedia session service configuration\n * from API\n * \n * @author Philippe LEMORDANT\n */\npublic class MultimediaSessionServiceConfigurationImpl extends\n        IMultimediaSessionServiceConfiguration.Stub {\n\n    private static final Logger sLogger = Logger\n            .getLogger(MultimediaSessionServiceConfigurationImpl.class.getSimpleName());\n\n    private final RcsSettings mRcsSettings;\n\n    /**\n     * @param rcsSettings RCS settings accessor\n     */\n    public MultimediaSessionServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public int getMessageMaxLength() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxMsrpLengthForExtensions();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getMessagingSessionInactivityTimeout(String serviceId) throws RemoteException {\n        try {\n            if (EnrichCallingService.CALL_COMPOSER_SERVICE_ID.equals(serviceId)) {\n                return mRcsSettings.getCallComposerInactivityTimeout();\n            } else {\n                return mRcsSettings.getChatIdleDuration();\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isServiceActivated(String serviceId) throws RemoteException {\n        try {\n            return mRcsSettings.isExtensionAuthorized(serviceId);\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/MultimediaSessionServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.network.sip.FeatureTags;\nimport com.gsma.rcs.core.ims.protocol.rtp.format.data.DataFormat;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.messaging.GenericSipMsrpSession;\nimport com.gsma.rcs.core.ims.service.sip.streaming.GenericSipRtpSession;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.service.broadcaster.MultimediaMessagingSessionEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.MultimediaStreamingSessionEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.IMultimediaMessagingSession;\nimport com.gsma.services.rcs.extension.IMultimediaMessagingSessionListener;\nimport com.gsma.services.rcs.extension.IMultimediaSessionService;\nimport com.gsma.services.rcs.extension.IMultimediaSessionServiceConfiguration;\nimport com.gsma.services.rcs.extension.IMultimediaStreamingSession;\nimport com.gsma.services.rcs.extension.IMultimediaStreamingSessionListener;\nimport com.gsma.services.rcs.extension.InstantMultimediaMessageIntent;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Multimedia session API service\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaSessionServiceImpl extends IMultimediaSessionService.Stub {\n\n    private final MultimediaMessagingSessionEventBroadcaster mMultimediaMessagingSessionEventBroadcaster = new MultimediaMessagingSessionEventBroadcaster();\n\n    private final MultimediaStreamingSessionEventBroadcaster mMultimediaStreamingSessionEventBroadcaster = new MultimediaStreamingSessionEventBroadcaster();\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final SipService mSipService;\n\n    private final RcsSettings mRcsSettings;\n\n    private final Map<String, IMultimediaMessagingSession> mMultimediaMessagingCache = new HashMap<>();\n\n    private final Map<String, IMultimediaStreamingSession> mMultimediaStreamingCache = new HashMap<>();\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(MultimediaSessionServiceImpl.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param sipService SipService\n     * @param rcsSettings RcsSettings\n     */\n    public MultimediaSessionServiceImpl(SipService sipService, RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Multimedia session API is loaded\");\n        }\n        mSipService = sipService;\n        mSipService.register(this);\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        // Clear list of sessions\n        mMultimediaMessagingCache.clear();\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Multimedia session service API is closed\");\n        }\n    }\n\n    /**\n     * Add a multimedia messaging in the list\n     * \n     * @param multimediaMessaging Multimedia messaging implementation\n     */\n    private void addMultimediaMessaging(MultimediaMessagingSessionImpl multimediaMessaging) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add a MultimediaMessaging in the list (size=\"\n                    + mMultimediaMessagingCache.size() + \")\");\n        }\n\n        mMultimediaMessagingCache.put(multimediaMessaging.getSessionId(), multimediaMessaging);\n    }\n\n    /**\n     * Remove a multimedia messaging from the list\n     * \n     * @param sessionId Session ID\n     */\n    /* package private */void removeMultimediaMessaging(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a MultimediaMessaging from the list (size=\"\n                    + mMultimediaMessagingCache.size() + \")\");\n        }\n\n        mMultimediaMessagingCache.remove(sessionId);\n    }\n\n    /**\n     * Add a multimedia streaming in the list\n     * \n     * @param multimediaStreaming Multimedia streaming implementation\n     */\n    private void addMultimediaStreaming(MultimediaStreamingSessionImpl multimediaStreaming) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Add a MultimediaStreaming in the list (size=\"\n                    + mMultimediaMessagingCache.size() + \")\");\n        }\n\n        mMultimediaStreamingCache.put(multimediaStreaming.getSessionId(), multimediaStreaming);\n    }\n\n    /**\n     * Remove a multimedia streaming from the list\n     * \n     * @param sessionId Session ID\n     */\n    /* package private */void removeMultimediaStreaming(String sessionId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a MultimediaStreaming from the list (size=\"\n                    + mMultimediaMessagingCache.size() + \")\");\n        }\n\n        mMultimediaStreamingCache.remove(sessionId);\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return Returns true if registered else returns false\n     */\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Return the reason code for IMS service registration\n     * \n     * @return the reason code for IMS service registration\n     */\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add a service listener\");\n        }\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove a service listener\");\n        }\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     * \n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    /**\n     * Receive a new SIP session invitation with MRSP media\n     * \n     * @param session SIP session\n     */\n    public void receiveSipMsrpSessionInvitation(GenericSipMsrpSession session) {\n        ContactId remote = session.getRemoteContact();\n        MultimediaMessagingSessionImpl multimediaMessaging = new MultimediaMessagingSessionImpl(\n                session.getSessionID(), mMultimediaMessagingSessionEventBroadcaster, mSipService,\n                this, Direction.INCOMING, remote, session.getServiceId(), State.INVITED);\n        session.addListener(multimediaMessaging);\n        addMultimediaMessaging(multimediaMessaging);\n    }\n\n    /**\n     * Receive a new SIP session invitation with RTP media\n     * \n     * @param session SIP session\n     */\n    public void receiveSipRtpSessionInvitation(GenericSipRtpSession session) {\n        ContactId remote = session.getRemoteContact();\n        MultimediaStreamingSessionImpl multimediaStreaming = new MultimediaStreamingSessionImpl(\n                session.getSessionID(), mMultimediaStreamingSessionEventBroadcaster, mSipService,\n                this, Direction.INCOMING, remote, session.getServiceId(), State.INVITED);\n        session.addListener(multimediaStreaming);\n        addMultimediaStreaming(multimediaStreaming);\n    }\n\n    /**\n     * Returns the configuration of the multimedia session service\n     * \n     * @return Configuration\n     * @throws RemoteException\n     */\n    public IMultimediaSessionServiceConfiguration getConfiguration() throws RemoteException {\n        try {\n            return new MultimediaSessionServiceConfigurationImpl(mRcsSettings);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a new session for real time messaging with a remote contact and for a given service\n     * extension. The messages are exchanged in real time during the session and may be from any\n     * type. The parameter contact supports the following formats: MSISDN in national or\n     * international format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not\n     * supported an exception is thrown.\n     * \n     * @param serviceId Service ID\n     * @param contact Contact ID\n     * @return Multimedia messaging session\n     * @throws RemoteException\n     */\n    public IMultimediaMessagingSession initiateMessagingSession(String serviceId, ContactId contact)\n            throws RemoteException {\n        return initiateMessagingSession2(serviceId, contact, null, null);\n    }\n\n    /**\n     * Initiates a new session for real time messaging with a remote contact and for a given service\n     * extension. The messages are exchanged in real time during the session are specified by the\n     * parameter accept-types and accept-wrapped-types. The parameter contact supports the following\n     * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI. If the\n     * format of the contact is not supported an exception is thrown.\n     *\n     * @param serviceId Service ID\n     * @param contact Contact ID\n     * @param acceptTypes Accept-types related to exchanged messages (may be null or empty)\n     * @param acceptWrappedTypes Accept-wrapped-types related to exchanged messages (may be null or\n     *            empty)\n     * @return Multimedia messaging session\n     * @throws RemoteException\n     */\n    public IMultimediaMessagingSession initiateMessagingSession2(String serviceId,\n            ContactId contact, String[] acceptTypes, String[] acceptWrappedTypes)\n            throws RemoteException {\n        if (TextUtils.isEmpty(serviceId)) {\n            throw new ServerApiIllegalArgumentException(\"serviceId must not be null or empty!\");\n        }\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a multimedia messaging session with \" + contact);\n        }\n        ServerApiUtils.testImsExtension(serviceId);\n        try {\n            String featureTag = FeatureTags.FEATURE_RCSE + \"=\\\"\"\n                    + FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".\" + serviceId + \"\\\"\";\n            final GenericSipMsrpSession session = mSipService.createMsrpSession(contact,\n                    featureTag, acceptTypes, acceptWrappedTypes);\n            MultimediaMessagingSessionImpl multiMediaMessaging = new MultimediaMessagingSessionImpl(\n                    session.getSessionID(), mMultimediaMessagingSessionEventBroadcaster,\n                    mSipService, this, Direction.OUTGOING, contact, serviceId, State.INITIATING);\n\n            session.addListener(multiMediaMessaging);\n            addMultimediaMessaging(multiMediaMessaging);\n            session.startSession();\n            return multiMediaMessaging;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current messaging session from its unique session ID\n     * \n     * @param sessionId Session ID\n     * @return Multimedia messaging session\n     * @throws RemoteException\n     */\n    public IMultimediaMessagingSession getMessagingSession(String sessionId) throws RemoteException {\n        if (TextUtils.isEmpty(sessionId)) {\n            throw new ServerApiIllegalArgumentException(\"sessionId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get multimedia messaging \".concat(sessionId));\n        }\n        try {\n            return mMultimediaMessagingCache.get(sessionId);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of messaging sessions associated to a given service ID\n     * \n     * @param serviceId Service ID\n     * @return List of sessions\n     * @throws RemoteException\n     */\n    public List<IBinder> getMessagingSessions(String serviceId) throws RemoteException {\n        if (TextUtils.isEmpty(serviceId)) {\n            throw new ServerApiIllegalArgumentException(\"serviceId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get multimedia messaging sessions for service \".concat(serviceId));\n        }\n        try {\n            List<IBinder> multimediaMessagingSessions = new ArrayList<>();\n            for (IMultimediaMessagingSession multimediaMessagingSession : mMultimediaMessagingCache\n                    .values()) {\n                if (multimediaMessagingSession.getServiceId().contains(serviceId)) {\n                    multimediaMessagingSessions.add(multimediaMessagingSession.asBinder());\n                }\n            }\n            return multimediaMessagingSessions;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a new session for real time streaming with a remote contact and for a given service\n     * extension. The payload are exchanged in real time during the session and may be from any\n     * type. The parameter contact supports the following formats: MSISDN in national or\n     * international format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not\n     * supported an exception is thrown.\n     * \n     * @param serviceId Service ID\n     * @param contact Contact ID\n     * @return Multimedia streaming session\n     * @throws RemoteException\n     */\n    public IMultimediaStreamingSession initiateStreamingSession(String serviceId, ContactId contact)\n            throws RemoteException {\n        return initiateStreamingSession2(serviceId, contact, DataFormat.ENCODING);\n    }\n\n    /**\n     * Initiates a new session for real time streaming with a remote contact for a given service\n     * extension and encoding (ie. rtpmap format containing <encoding name>/<clock rate> and\n     * optional parameters if needed. The payload are exchanged in real time during the session and\n     * may be from any type. The parameter contact supports the following formats: MSISDN in\n     * national or international format, SIP address, SIP-URI or Tel-URI. If the format of the\n     * contact is not supported an exception is thrown.\n     *\n     * @param serviceId Service ID\n     * @param contact Contact ID\n     ** @param encoding Encoding payload format\n     * @return Multimedia streaming session\n     * @throws RemoteException\n     */\n    public IMultimediaStreamingSession initiateStreamingSession2(String serviceId,\n            ContactId contact, String encoding) throws RemoteException {\n        if (TextUtils.isEmpty(serviceId)) {\n            throw new ServerApiIllegalArgumentException(\"serviceId must not be null or empty!\");\n        }\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Initiate a multimedia streaming session with \" + contact);\n        }\n        ServerApiUtils.testImsExtension(serviceId);\n        try {\n            String featureTag = FeatureTags.FEATURE_RCSE + \"=\\\"\"\n                    + FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".\" + serviceId + \"\\\"\";\n            final GenericSipRtpSession session = mSipService.createRtpSession(contact, featureTag,\n                    encoding);\n\n            MultimediaStreamingSessionImpl multimediaStreaming = new MultimediaStreamingSessionImpl(\n                    session.getSessionID(), mMultimediaStreamingSessionEventBroadcaster,\n                    mSipService, this, Direction.OUTGOING, contact, serviceId, State.INITIATING);\n\n            session.addListener(multimediaStreaming);\n            addMultimediaStreaming(multimediaStreaming);\n            session.startSession();\n            return multimediaStreaming;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n\n    }\n\n    /**\n     * Returns a current streaming session from its unique session ID\n     * \n     * @param sessionId Session ID\n     * @return Multimedia streaming session or null if not found\n     * @throws RemoteException\n     */\n    public IMultimediaStreamingSession getStreamingSession(String sessionId) throws RemoteException {\n        if (TextUtils.isEmpty(sessionId)) {\n            throw new ServerApiIllegalArgumentException(\"sessionId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get multimedia streaming \".concat(sessionId));\n        }\n        try {\n            return mMultimediaStreamingCache.get(sessionId);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of streaming sessions associated to a given service ID\n     * \n     * @param serviceId Service ID\n     * @return List of sessions\n     * @throws RemoteException\n     */\n    public List<IBinder> getStreamingSessions(String serviceId) throws RemoteException {\n        if (TextUtils.isEmpty(serviceId)) {\n            throw new ServerApiIllegalArgumentException(\"serviceId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get multimedia streaming sessions for service \" + serviceId);\n        }\n        try {\n            List<IBinder> multimediaStreamingSessions = new ArrayList<>();\n            for (IMultimediaStreamingSession multimediaStreamingSession : mMultimediaStreamingCache\n                    .values()) {\n                if (multimediaStreamingSession.getServiceId().contains(serviceId)) {\n                    multimediaStreamingSessions.add(multimediaStreamingSession.asBinder());\n                }\n            }\n            return multimediaStreamingSessions;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Adds a listener on multimedia messaging session events\n     * \n     * @param listener Session event listener\n     * @throws RemoteException\n     */\n    public void addEventListener2(IMultimediaMessagingSessionListener listener)\n            throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add an event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mMultimediaMessagingSessionEventBroadcaster\n                        .addMultimediaMessagingEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on multimedia messaging session events\n     * \n     * @param listener Session event listener\n     * @throws RemoteException\n     */\n    public void removeEventListener2(IMultimediaMessagingSessionListener listener)\n            throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove an event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mMultimediaMessagingSessionEventBroadcaster\n                        .removeMultimediaMessagingEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on multimedia streaming session events\n     * \n     * @param listener Session event listener\n     * @throws RemoteException\n     */\n    public void addEventListener3(IMultimediaStreamingSessionListener listener)\n            throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add an event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mMultimediaStreamingSessionEventBroadcaster\n                        .addMultimediaStreamingEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on multimedia streaming session events\n     * \n     * @param listener Session event listener\n     * @throws RemoteException\n     */\n    public void removeEventListener3(IMultimediaStreamingSessionListener listener)\n            throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove an event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mMultimediaStreamingSessionEventBroadcaster\n                        .removeMultimediaStreamingEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Sends an instant multimedia message to a remote contact and for a given service extension.\n     * The content takes part of the message, so any multimedia session is needed to exchange\n     * content here. The parameter contact supports the following formats: MSISDN in national or\n     * international format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not\n     * supported an exception is thrown.\n     *\n     * @param serviceId Service ID\n     * @param contact Contact identifier\n     * @param content Content of the message\n     * @param contentType Content type of the the message\n     * @throws RemoteException\n     */\n    public void sendInstantMultimediaMessage(final String serviceId, final ContactId contact,\n            final byte[] content, final String contentType) throws RemoteException {\n        if (TextUtils.isEmpty(serviceId)) {\n            throw new ServerApiIllegalArgumentException(\"serviceId must not be null or empty!\");\n        }\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (content == null) {\n            throw new ServerApiIllegalArgumentException(\"content must not be null!\");\n        }\n        if (contentType == null) {\n            throw new ServerApiIllegalArgumentException(\"content type must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Send an instant multimedia message to \" + contact);\n        }\n        ServerApiUtils.testImsExtension(serviceId);\n        mSipService.scheduleMultimediaMessageOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    String featureTag = FeatureTags.FEATURE_RCSE + \"=\\\"\"\n                            + FeatureTags.FEATURE_RCSE_IARI_EXTENSION + \".\" + serviceId + \"\\\"\";\n                    mSipService.sendInstantMultimediaMessage(contact, featureTag, content,\n                            contentType);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to send message for service ID:\".concat(serviceId), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Receive a new SIP instant message\n     *\n     * @param intent Received intent\n     * @param contact Remote contact\n     * @param content Message content\n     * @param contentType Message content type\n     * @param serviceId Service ID\n     */\n    public void receiveSipInstantMessage(Intent intent, ContactId contact, byte[] content,\n            String contentType, String serviceId) {\n        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(intent);\n        intent.putExtra(InstantMultimediaMessageIntent.EXTRA_CONTACT, (Parcelable) contact);\n        intent.putExtra(InstantMultimediaMessageIntent.EXTRA_SERVICE_ID, serviceId);\n        intent.putExtra(InstantMultimediaMessageIntent.EXTRA_CONTENT, content);\n        intent.putExtra(InstantMultimediaMessageIntent.EXTRA_CONTENT_TYPE, contentType);\n        AndroidFactory.getApplicationContext().sendBroadcast(intent);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/MultimediaSessionStorageAccessor.java",
    "content": "/*\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\n/**\n * MultimediaSessionStorageAccessor helps in retrieving data related to a multimedia session.\n */\npublic class MultimediaSessionStorageAccessor {\n\n    private State mState;\n\n    private ReasonCode mReason;\n\n    private final ContactId mRemoteContact;\n\n    private final Direction mDirection;\n\n    private final String mServiceId;\n\n    /**\n     * Constructor\n     * \n     * @param direction Direction\n     * @param remoteContact Remote contact\n     * @param serviceId Service ID\n     * @param state State\n     */\n    public MultimediaSessionStorageAccessor(Direction direction, ContactId remoteContact,\n            String serviceId, State state) {\n        mState = state;\n        mDirection = direction;\n        mRemoteContact = remoteContact;\n        mServiceId = serviceId;\n    }\n\n    /**\n     * Gets the state of the multimedia session\n     * \n     * @return the state of the multimedia session\n     */\n    public State getState() {\n        return mState;\n    }\n\n    /**\n     * Gets the remote contact\n     * \n     * @return the remote contact\n     */\n    public ContactId getRemoteContact() {\n        return mRemoteContact;\n    }\n\n    /**\n     * Gets the direction\n     * \n     * @return the direction\n     */\n    public Direction getDirection() {\n        return mDirection;\n    }\n\n    /**\n     * Gets the service identifier\n     * \n     * @return the service identifier\n     */\n    public String getServiceId() {\n        return mServiceId;\n    }\n\n    /**\n     * Sets the state and reason code of the multimedia session\n     * \n     * @param state the state of the multimedia session\n     * @param reason the reason code for the multimedia session\n     */\n    public void setStateAndReasonCode(State state, ReasonCode reason) {\n        mState = state;\n        mReason = reason;\n    }\n\n    /**\n     * Gets reason code for the multimedia session\n     * \n     * @return the reason code for the multimedia session\n     */\n    public ReasonCode getReasonCode() {\n        return mReason;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/MultimediaStreamingSessionImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.SessionNotEstablishedException;\nimport com.gsma.rcs.core.ims.service.sip.SipService;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionError;\nimport com.gsma.rcs.core.ims.service.sip.SipSessionListener;\nimport com.gsma.rcs.core.ims.service.sip.streaming.GenericSipRtpSession;\nimport com.gsma.rcs.service.broadcaster.IMultimediaStreamingSessionEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.IMultimediaStreamingSession;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\nimport android.os.RemoteException;\n\n/**\n * Multimedia streaming session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaStreamingSessionImpl extends IMultimediaStreamingSession.Stub implements\n        SipSessionListener {\n\n    private final String mSessionId;\n\n    private final IMultimediaStreamingSessionEventBroadcaster mBroadcaster;\n\n    private final SipService mSipService;\n\n    private final MultimediaSessionServiceImpl mMultimediaSessionService;\n\n    private final MultimediaSessionStorageAccessor mPersistedStorage;\n\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(MultimediaStreamingSessionImpl.class\n            .getName());\n\n    /**\n     * Constructor\n     * \n     * @param sessionId Session Id\n     * @param broadcaster IMultimediaStreamingSessionEventBroadcaster\n     * @param sipService SipService\n     * @param multimediaSessionService MultimediaSessionServiceImpl\n     * @param direction Direction\n     * @param contact remote contact\n     * @param serviceId Service ID\n     * @param state State of the multimedia session\n     */\n    public MultimediaStreamingSessionImpl(String sessionId,\n            IMultimediaStreamingSessionEventBroadcaster broadcaster, SipService sipService,\n            MultimediaSessionServiceImpl multimediaSessionService, Direction direction,\n            ContactId contact, String serviceId, State state) {\n        mSessionId = sessionId;\n        mBroadcaster = broadcaster;\n        mSipService = sipService;\n        mMultimediaSessionService = multimediaSessionService;\n        mPersistedStorage = new MultimediaSessionStorageAccessor(direction, contact, serviceId,\n                state);\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session rejected; reasonCode=\" + reasonCode);\n        }\n        String sessionId = getSessionId();\n        synchronized (mLock) {\n            mMultimediaSessionService.removeMultimediaStreaming(sessionId);\n            mPersistedStorage.setStateAndReasonCode(State.REJECTED, reasonCode);\n            mBroadcaster.broadcastStateChanged(contact, sessionId, State.REJECTED, reasonCode);\n        }\n    }\n\n    private void removeSession(ContactId contact, State state, ReasonCode reasonCode) {\n        mMultimediaSessionService.removeMultimediaStreaming(mSessionId);\n        mPersistedStorage.setStateAndReasonCode(state, reasonCode);\n        mBroadcaster.broadcastStateChanged(contact, mSessionId, state, reasonCode);\n    }\n\n    private void setStateAndReason(ContactId contact, State state, ReasonCode reason) {\n        mPersistedStorage.setStateAndReasonCode(state, reason);\n        mBroadcaster.broadcastStateChanged(contact, mSessionId, state, reason);\n    }\n\n    /**\n     * Returns the session ID of the multimedia session\n     * \n     * @return Session ID\n     */\n    public String getSessionId() {\n        return mSessionId;\n    }\n\n    /**\n     * Returns the remote contact ID\n     * \n     * @return ContactId\n     * @throws RemoteException\n     */\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            GenericSipRtpSession session = mSipService.getGenericSipRtpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the session\n     * \n     * @return State\n     * @throws RemoteException\n     */\n    public int getState() throws RemoteException {\n        try {\n            GenericSipRtpSession session = mSipService.getGenericSipRtpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getState().toInt();\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return State.STARTED.toInt();\n\n            } else if (session.isInitiatedByRemote()) {\n                if (session.isSessionAccepted()) {\n                    return State.ACCEPTING.toInt();\n                }\n                return State.INVITED.toInt();\n            }\n            return State.INITIATING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the multimedia streaming session\n     * \n     * @return ReasonCode\n     * @throws RemoteException\n     */\n    public int getReasonCode() throws RemoteException {\n        try {\n            GenericSipRtpSession session = mSipService.getGenericSipRtpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getReasonCode().toInt();\n            }\n            return ReasonCode.UNSPECIFIED.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the session (incoming or outgoing)\n     * \n     * @return Direction\n     * @throws RemoteException\n     * @see Direction\n     */\n    public int getDirection() throws RemoteException {\n        try {\n            GenericSipRtpSession session = mSipService.getGenericSipRtpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the service ID\n     * \n     * @return Service ID\n     * @throws RemoteException\n     */\n    public String getServiceId() throws RemoteException {\n        try {\n            GenericSipRtpSession session = mSipService.getGenericSipRtpSession(mSessionId);\n            if (session == null) {\n                return mPersistedStorage.getServiceId();\n            }\n            return session.getServiceId();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts session invitation\n     * \n     * @throws RemoteException\n     */\n    public void acceptInvitation() throws RemoteException {\n        mSipService.scheduleMultimediaStreamingOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Accept session invitation\");\n                    }\n                    final GenericSipRtpSession session = mSipService\n                            .getGenericSipRtpSession(mSessionId);\n                    if (session == null) {\n                        sLogger.debug(\"Cannot accept: no session ID=\".concat(mSessionId));\n                        return;\n                    }\n                    ServerApiUtils.testImsExtension(session.getServiceId());\n                    session.acceptSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to accept session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejects session invitation\n     * \n     * @throws RemoteException\n     */\n    public void rejectInvitation() throws RemoteException {\n        mSipService.scheduleMultimediaStreamingOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Reject session invitation\");\n                    }\n                    final GenericSipRtpSession session = mSipService\n                            .getGenericSipRtpSession(mSessionId);\n                    if (session == null) {\n                        sLogger.debug(\"Cannot reject: no session ID=\".concat(mSessionId));\n                        return;\n                    }\n                    ServerApiUtils.testImsExtension(session.getServiceId());\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to reject session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Aborts the session\n     * \n     * @throws RemoteException\n     */\n    public void abortSession() throws RemoteException {\n        mSipService.scheduleMultimediaStreamingOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Abort session\");\n                    }\n                    final GenericSipRtpSession session = mSipService\n                            .getGenericSipRtpSession(mSessionId);\n                    if (session == null) {\n                        sLogger.debug(\"No ongoing session with id:\" + mSessionId\n                                + \" is found so nothing to abort!\");\n                        return;\n                    }\n                    if (session.isSessionInterrupted()) {\n                        sLogger.debug(\"Session with sharing ID:\" + mSessionId\n                                + \" is already aborted!\");\n                        return;\n                    }\n                    ServerApiUtils.testImsExtension(session.getServiceId());\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to abort session with ID: \".concat(mSessionId), e);\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n            }\n        });\n    }\n\n    /**\n     * Sends a payload in real time\n     * \n     * @param content Payload content\n     * @throws RemoteException\n     */\n    public void sendPayload(final byte[] content) throws RemoteException {\n        if (content == null || content.length == 0) {\n            throw new ServerApiIllegalArgumentException(\"content must not be null or empty!\");\n        }\n        mSipService.scheduleMultimediaStreamingOperation(new Runnable() {\n            public void run() {\n                try {\n                    GenericSipRtpSession session = mSipService.getGenericSipRtpSession(mSessionId);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Session with session ID '\" + mSessionId\n                                    + \"' not available!\");\n                        }\n                        return;\n                    }\n\n                    session.sendPlayload(content);\n\n                } catch (SessionNotEstablishedException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to send payload within session with ID '\"\n                                + mSessionId + \"' due to: \" + e.getMessage());\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            \"Failed to send payload within session with ID: \".concat(mSessionId), e);\n                }\n            }\n        });\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session started\");\n        }\n        synchronized (mLock) {\n            setStateAndReason(contact, State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session aborted (terminationReason \" + reason + \")\");\n        }\n        synchronized (mLock) {\n            switch (reason) {\n                case TERMINATION_BY_SYSTEM:\n                case TERMINATION_BY_TIMEOUT:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_USER:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    removeSession(contact, State.FAILED, ReasonCode.FAILED_SESSION);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    removeSession(contact, State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown TerminationReason=\" + reason);\n            }\n        }\n    }\n\n    @Override\n    public void onSessionError(ContactId contact, SipSessionError error) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session error \" + error.getErrorCode());\n        }\n        synchronized (mLock) {\n            mMultimediaSessionService.removeMultimediaStreaming(mSessionId);\n\n            switch (error.getErrorCode()) {\n                case SipSessionError.SESSION_INITIATION_DECLINED:\n                    setStateAndReason(contact, State.REJECTED, ReasonCode.REJECTED_BY_REMOTE);\n                    break;\n                case SipSessionError.MEDIA_FAILED:\n                    setStateAndReason(contact, State.FAILED, ReasonCode.FAILED_MEDIA);\n                    break;\n                case SipSessionError.SESSION_INITIATION_CANCELLED:\n                case SipSessionError.SESSION_INITIATION_FAILED:\n                    setStateAndReason(contact, State.FAILED, ReasonCode.FAILED_INITIATION);\n                    break;\n                default:\n                    setStateAndReason(contact, State.FAILED, ReasonCode.FAILED_SESSION);\n            }\n        }\n    }\n\n    @Override\n    public void onDataReceived(ContactId contact, byte[] data, String contentType) {\n        synchronized (mLock) {\n            mBroadcaster.broadcastPayloadReceived(contact, mSessionId, data);\n        }\n    }\n\n    /**\n     * Data has been flushed\n     *\n     * @param contact Remote contact\n     */\n    public void onDataFlushed(ContactId contact) {\n        // Not applicable for RTP streaming session\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Accepting session\");\n        }\n        synchronized (mLock) {\n            setStateAndReason(contact, State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER, contact);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM, contact);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT, contact);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE, contact);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason + \"!\");\n        }\n    }\n\n    @Override\n    public void onInvitationReceived(ContactId contact, Intent sessionInvite) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Invited to multimedia streaming session\");\n        }\n        mBroadcaster.broadcastInvitation(mSessionId, sessionInvite);\n    }\n\n    @Override\n    public void onSessionRinging(ContactId contact) {\n        synchronized (mLock) {\n            setStateAndReason(contact, State.RINGING, ReasonCode.UNSPECIFIED);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/OneToOneChatImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.msrp.MsrpSession.TypeMsrpChunk;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatError;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSession;\nimport com.gsma.rcs.core.ims.service.im.chat.OneToOneChatSessionListener;\nimport com.gsma.rcs.core.ims.service.im.chat.SessionUnavailableException;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.standfw.TerminatingStoreAndForwardOneToOneChatMessageSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.messaging.ChatMessagePersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.ImSessionStartMode;\nimport com.gsma.rcs.service.broadcaster.IOneToOneChatEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.chat.IOneToOneChat;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\n/**\n * One-to-One Chat implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class OneToOneChatImpl extends IOneToOneChat.Stub implements OneToOneChatSessionListener {\n\n    private final ContactId mContact;\n\n    private final IOneToOneChatEventBroadcaster mBroadcaster;\n\n    private final InstantMessagingService mImService;\n\n    private final MessagingLog mMessagingLog;\n\n    private final ChatServiceImpl mChatService;\n\n    private final RcsSettings mRcsSettings;\n\n    private final ContactManager mContactManager;\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(OneToOneChatImpl.class.getName());\n\n    /**\n     * Constructor\n     * \n     * @param contact Remote contact ID\n     * @param broadcaster IChatEventBroadcaster\n     * @param imService InstantMessagingService\n     * @param messagingLog MessagingLog\n     * @param rcsSettings RcsSettings\n     * @param chatService ChatServiceImpl\n     * @param contactManager ContactManager\n     */\n    public OneToOneChatImpl(InstantMessagingService imService, ContactId contact,\n            IOneToOneChatEventBroadcaster broadcaster, MessagingLog messagingLog,\n            RcsSettings rcsSettings, ChatServiceImpl chatService, ContactManager contactManager) {\n        mImService = imService;\n        mContact = contact;\n        mBroadcaster = broadcaster;\n        mMessagingLog = messagingLog;\n        mChatService = chatService;\n        mRcsSettings = rcsSettings;\n        mContactManager = contactManager;\n    }\n\n    private void sendChatMessageInNewSession(final ChatMessage msg) throws PayloadException,\n            NetworkException {\n        final OneToOneChatSession newSession = mImService.createOneToOneChatSession(mContact, msg);\n        newSession.addListener(OneToOneChatImpl.this);\n        newSession.startSession();\n        onMessageSent(msg.getMessageId(), msg.getMimeType());\n    }\n\n    private void sendChatMessageWithinSession(final OneToOneChatSession session,\n            final ChatMessage msg) throws NetworkException {\n        session.sendChatMessage(msg);\n    }\n\n    /**\n     * Resends a chat message\n     * \n     * @param msg Message\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws FileAccessException\n     */\n    private void resendChatMessage(final ChatMessage msg) throws PayloadException,\n            NetworkException, FileAccessException {\n        synchronized (mLock) {\n            String msgId = msg.getMessageId();\n            String mimeType = msg.getMimeType();\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Resend chat message, msgId \" + msgId + \" and mimeType \" + mimeType);\n            }\n            mImService.acceptStoreAndForwardMessageSessionIfSuchExists(mContact);\n            final OneToOneChatSession session = mImService.getOneToOneChatSession(mContact);\n            if (session == null) {\n                if (!mImService.isChatSessionAvailable()) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot start new session since to limit of sessions is reached. MessageId=\"\n                                .concat(msgId));\n                    }\n                    setChatMessageStatusAndTimestamp(msg, Status.QUEUED);\n                    return;\n                }\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Core session is not yet established: initiate a new session to send the message\");\n                }\n                setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n                sendChatMessageInNewSession(msg);\n                return;\n            }\n            if (session.isMediaEstablished()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Core session is established: use existing one to send the message\");\n                }\n                setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n                sendChatMessageWithinSession(session, msg);\n                return;\n            }\n            /*\n             * If session is originated by remote, then queue the message and accept the pending\n             * session as part of this re-send operation\n             */\n            if (session.isInitiatedByRemote()) {\n                setChatMessageStatusAndTimestamp(msg, Status.QUEUED);\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Accept one-to-one chat session with contact \".concat(mContact\n                            .toString()));\n                }\n                session.acceptSession();\n            } else {\n                if (!mImService.isChatSessionAvailable()) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot start new session since to limit of sessions is reached. MessageId=\"\n                                .concat(msgId));\n                    }\n                    setChatMessageStatusAndTimestamp(msg, Status.QUEUED);\n                    return;\n                }\n                setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n                sendChatMessageInNewSession(msg);\n            }\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     */\n    @Override\n    public ContactId getRemoteContact() {\n        return mContact;\n    }\n\n    /**\n     * Returns true if it is possible to send messages in this one to one chat right now, else\n     * return false.\n     * \n     * @return boolean\n     * @throws RemoteException\n     */\n    @Override\n    public boolean isAllowedToSendMessage() throws RemoteException {\n        try {\n            if (!mRcsSettings.getMyCapabilities().isImSessionSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot send message on one-to-one chat with contact '\"\n                            + mContact + \"' as IM capabilities are not supported for self.\");\n                }\n                return false;\n            }\n            Capabilities remoteCapabilities = mContactManager.getContactCapabilities(mContact);\n            if (remoteCapabilities == null) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot send message on one-to-one chat with contact '\"\n                            + mContact + \"' as the contact's capabilities are not known.\");\n                }\n                return false;\n            }\n            MessagingMode mode = mRcsSettings.getMessagingMode();\n            switch (mode) {\n                case INTEGRATED:\n                case SEAMLESS:\n                    if (!mRcsSettings.isImAlwaysOn()\n                            && !mImService.isCapabilitiesValid(remoteCapabilities)) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot send message on one-to-one chat with contact '\"\n                                    + mContact\n                                    + \"' as the contact's cached capabilities are not valid anymore for one-to-one communication.\");\n                        }\n                        return false;\n                    }\n                    break;\n                default:\n                    break;\n            }\n            if (!remoteCapabilities.isImSessionSupported()) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot send message on one-to-one chat with contact '\"\n                            + mContact + \"' as IM capabilities are not supported for that contact.\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    private long getDeliveryExpirationTime(long timestampSent) {\n        if (mRcsSettings.isImAlwaysOn()) {\n            return 0;\n        }\n        final long timeout = mRcsSettings.getMsgDeliveryTimeoutPeriod();\n        if (timeout == 0L) {\n            return 0;\n        }\n        return timestampSent + timeout;\n    }\n\n    /**\n     * Add chat message to Db\n     * \n     * @param msg InstantMessage\n     * @param status status of message\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void addOutgoingChatMessage(ChatMessage msg, Status status) throws PayloadException,\n            NetworkException {\n        String msgId = msg.getMessageId();\n        long timestampSent = msg.getTimestampSent();\n        long deliveryExpiration = getDeliveryExpirationTime(timestampSent);\n        mMessagingLog.addOutgoingOneToOneChatMessage(msg, status, ReasonCode.UNSPECIFIED,\n                deliveryExpiration);\n        if (deliveryExpiration != 0) {\n            mImService.getDeliveryExpirationManager()\n                    .scheduleOneToOneChatMessageDeliveryTimeoutAlarm(mContact, msgId,\n                            deliveryExpiration);\n        }\n    }\n\n    /**\n     * Set chat message status\n     * \n     * @param msgId message ID\n     * @param mimeType mime type\n     * @param status status of message\n     * @param reasonCode Reason code\n     */\n    private void setChatMessageStatusAndReasonCode(String msgId, String mimeType, Status status,\n            ReasonCode reasonCode) {\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, status, reasonCode)) {\n                mBroadcaster.broadcastMessageStatusChanged(mContact, mimeType, msgId, status,\n                        reasonCode);\n            }\n        }\n    }\n\n    /**\n     * Set chat message status and timestamp\n     * \n     * @param msg Chat message\n     * @param status status of message\n     */\n    private void setChatMessageStatusAndTimestamp(ChatMessage msg, Status status) {\n        String msgId = msg.getMessageId();\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndTimestamp(msgId, status,\n                    ReasonCode.UNSPECIFIED, msg.getTimestamp(), msg.getTimestampSent())) {\n                mBroadcaster.broadcastMessageStatusChanged(mContact, msg.getMimeType(), msgId,\n                        status, ReasonCode.UNSPECIFIED);\n            }\n        }\n    }\n\n    /**\n     * Sends a plain text message\n     * \n     * @param message Text message\n     * @return Chat message\n     * @throws RemoteException\n     */\n    @Override\n    public IChatMessage sendMessage(String message) throws RemoteException {\n        if (TextUtils.isEmpty(message)) {\n            throw new ServerApiIllegalArgumentException(\"message must not be null or empty!\");\n        }\n        int messageLength = message.length();\n        int maxMessageLength = mRcsSettings.getMaxChatMessageLength();\n        if (messageLength > maxMessageLength) {\n            throw new ServerApiIllegalArgumentException(\"chat message length: \" + messageLength\n                    + \" exeeds max chat message length: \" + maxMessageLength + \"!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send text message.\");\n        }\n        try {\n            mImService.removeOneToOneChatComposingStatus(mContact); /* clear cache */\n            long timestamp = System.currentTimeMillis();\n            /* For outgoing message, timestampSent = timestamp */\n            final ChatMessage msg = ChatUtils.createTextMessage(mContact, message, timestamp,\n                    timestamp);\n            ChatMessagePersistedStorageAccessor persistedStorage = new ChatMessagePersistedStorageAccessor(\n                    mMessagingLog, msg.getMessageId(), msg.getRemoteContact(), message,\n                    msg.getMimeType(), mContact.toString(), Direction.OUTGOING);\n            /* Always insert message with status QUEUED */\n            addOutgoingChatMessage(msg, Status.QUEUED);\n\n            mImService.tryToDequeueOneToOneChatMessages(mContact);\n            return new ChatMessageImpl(persistedStorage);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a geoloc message\n     * \n     * @param geoloc Geoloc\n     * @return ChatMessage\n     * @throws RemoteException\n     */\n    @Override\n    public IChatMessage sendMessage2(Geoloc geoloc) throws RemoteException {\n        if (geoloc == null) {\n            throw new ServerApiIllegalArgumentException(\"geoloc must not be null!\");\n        }\n        String label = geoloc.getLabel();\n        if (label != null) {\n            int labelLength = label.length();\n            int labelMaxLength = mRcsSettings.getMaxGeolocLabelLength();\n            if (labelLength > labelMaxLength) {\n                throw new ServerApiIllegalArgumentException(\"geoloc message label length: \"\n                        + labelLength + \" exeeds max length: \" + labelMaxLength + \"!\");\n            }\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Send geolocation message.\");\n        }\n        try {\n            long timestamp = System.currentTimeMillis();\n            /** For outgoing message, timestampSent = timestamp */\n            final ChatMessage geolocMsg = ChatUtils.createGeolocMessage(mContact, geoloc,\n                    timestamp, timestamp);\n            ChatMessagePersistedStorageAccessor persistentStorage = new ChatMessagePersistedStorageAccessor(\n                    mMessagingLog, geolocMsg.getMessageId(), geolocMsg.getRemoteContact(),\n                    geolocMsg.getContent(), geolocMsg.getMimeType(), mContact.toString(),\n                    Direction.OUTGOING);\n            /* Always insert message with status QUEUED */\n            addOutgoingChatMessage(geolocMsg, Status.QUEUED);\n\n            mImService.tryToDequeueOneToOneChatMessages(mContact);\n            return new ChatMessageImpl(persistentStorage);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Dequeue one-one chat message\n     * \n     * @param msg Chat message\n     * @throws SessionUnavailableException\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    public void dequeueOneToOneChatMessage(ChatMessage msg) throws SessionUnavailableException,\n            PayloadException, NetworkException {\n        String msgId = msg.getMessageId();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Dequeue chat message msgId=\".concat(msgId));\n        }\n        mImService.acceptStoreAndForwardMessageSessionIfSuchExists(mContact);\n        OneToOneChatSession session = mImService.getOneToOneChatSession(mContact);\n        if (session == null) {\n            if (mImService.isChatSessionAvailable()) {\n                setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n                sendChatMessageInNewSession(msg);\n            } else {\n                throw new SessionUnavailableException(\n                        \"There is no available chat session for contact '\" + mContact + \"'!\");\n            }\n        } else if (session.isMediaEstablished()) {\n            setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n            sendChatMessageWithinSession(session, msg);\n        } else if (session.isInitiatedByRemote()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Accept one-to-one chat session with contact \".concat(mContact\n                        .toString()));\n            }\n            session.acceptSession();\n        } else {\n            if (mImService.isChatSessionAvailable()) {\n                setChatMessageStatusAndTimestamp(msg, Status.SENDING);\n                sendChatMessageInNewSession(msg);\n            } else {\n                throw new SessionUnavailableException(\n                        \"There is no available chat session for contact '\" + mContact + \"'!\");\n            }\n        }\n    }\n\n    /**\n     * Send file info in a new one-one chat session\n     * \n     * @param fileTransferId File transfer ID\n     * @param fileInfo File information\n     * @param oneToOneFileTransfer One to one file transfer implementation\n     * @throws PayloadException\n     * @throws NetworkException\n     */\n    private void sendFileInfoInNewSession(String fileTransferId, String fileInfo,\n            OneToOneFileTransferImpl oneToOneFileTransfer) throws PayloadException,\n            NetworkException {\n        long timestamp = System.currentTimeMillis();\n        /* For outgoing file transfer, timestampSent = timestamp */\n        long timestampSent = timestamp;\n        mMessagingLog.setFileTransferTimestamps(fileTransferId, timestamp, timestampSent);\n        ChatMessage firstMsg = ChatUtils.createFileTransferMessage(getRemoteContact(), fileInfo,\n                fileTransferId, timestamp, timestampSent);\n        OneToOneChatSession chatSession = mImService.createOneToOneChatSession(getRemoteContact(),\n                firstMsg);\n        chatSession.startSession();\n        mImService.receiveOneOneChatSessionInitiation(chatSession);\n        oneToOneFileTransfer.onFileInfoDequeued(getRemoteContact());\n    }\n\n    /**\n     * Dequeue one-one file info\n     * \n     * @param fileTransferId File transfer ID\n     * @param fileInfo File information\n     * @param displayReportsEnabled Display report enabled\n     * @param deliverReportsEnabled Deliver report enabled\n     * @param oneToOneFileTransfer One to one file transfer implementation\n     * @throws PayloadException\n     * @throws NetworkException\n     * @throws SessionUnavailableException\n     */\n    public void dequeueOneToOneFileInfo(String fileTransferId, String fileInfo,\n            boolean displayReportsEnabled, boolean deliverReportsEnabled,\n            OneToOneFileTransferImpl oneToOneFileTransfer) throws PayloadException,\n            NetworkException, SessionUnavailableException {\n        mImService.acceptStoreAndForwardMessageSessionIfSuchExists(mContact);\n        OneToOneChatSession session = mImService.getOneToOneChatSession(mContact);\n        if (session == null) {\n            if (mImService.isChatSessionAvailable()) {\n                sendFileInfoInNewSession(fileTransferId, fileInfo, oneToOneFileTransfer);\n            } else {\n                throw new SessionUnavailableException(\n                        \"There is no available chat session for contact '\" + mContact + \"'!\");\n            }\n        } else if (session.isMediaEstablished()) {\n            session.sendFileInfo(oneToOneFileTransfer, fileTransferId, fileInfo,\n                    displayReportsEnabled, deliverReportsEnabled);\n        } else if (session.isInitiatedByRemote()) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Accept one-to-one chat session with contact \".concat(mContact\n                        .toString()));\n            }\n            session.acceptSession();\n        } else {\n            if (mImService.isChatSessionAvailable()) {\n                sendFileInfoInNewSession(fileTransferId, fileInfo, oneToOneFileTransfer);\n            } else {\n                throw new SessionUnavailableException(\n                        \"There is no available chat session for contact '\" + mContact + \"'!\");\n            }\n        }\n    }\n\n    /**\n     * Sends a displayed delivery report for a given message ID\n     * \n     * @param remote Remote contact\n     * @param msgId Message ID\n     * @param timestamp Timestamp sent in payload for IMDN datetime\n     * @throws NetworkException\n     */\n    /* package private */void sendDisplayedDeliveryReport(final ContactId remote,\n            final String msgId, final long timestamp) throws NetworkException {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Set displayed delivery report for \" + msgId);\n        }\n        TerminatingStoreAndForwardOneToOneChatMessageSession storeAndForwardSession = mImService\n                .getStoreAndForwardMsgSession(mContact);\n        final OneToOneChatSession session = storeAndForwardSession != null ? storeAndForwardSession\n                : mImService.getOneToOneChatSession(mContact);\n        if (session != null && session.isMediaEstablished()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Use the original session to send the delivery display status for \"\n                        + msgId);\n            }\n            session.sendMsrpMessageDeliveryStatus(remote, msgId,\n                    ImdnDocument.DeliveryStatus.DISPLAYED, timestamp);\n        } else {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Use SIP message to send the delivery display status for \" + msgId);\n            }\n            mImService.getImdnManager().sendMessageDeliveryStatus(remote.toString(), remote, msgId,\n                    ImdnDocument.DeliveryStatus.DISPLAYED, timestamp);\n        }\n    }\n\n    /**\n     * Sends an is-composing event. The status is set to true when typing a message, else it is set\n     * to false.\n     * \n     * @param status Composing status\n     * @throws RemoteException\n     */\n    @Override\n    public void setComposingStatus(final boolean status) throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    mImService.removeOneToOneChatComposingStatus(mContact);\n                    ImSessionStartMode imSessionStartMode = mRcsSettings.getImSessionStartMode();\n                    switch (imSessionStartMode) {\n                        case ON_OPENING:\n                        case ON_COMPOSING:\n                            mImService.acceptStoreAndForwardMessageSessionIfSuchExists(mContact);\n                            break;\n                        default:\n                            break;\n                    }\n                    final OneToOneChatSession session = mImService.getOneToOneChatSession(mContact);\n                    if (session == null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Unable to send composing event '\" + status\n                                    + \"' since oneToOne chat session found with contact '\"\n                                    + mContact + \"' does not exist for now.\");\n                        }\n                        mImService.addOneToOneChatComposingStatus(mContact, status);\n                    } else if (session.getDialogPath().isSessionEstablished()) {\n                        session.sendIsComposingStatus(status);\n                    } else if (!session.isInitiatedByRemote()) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Unable to send composing event '\" + status\n                                    + \"' since oneToOne chat session found with contact '\"\n                                    + mContact + \"' is initiated locally.\");\n                        }\n                        mImService.addOneToOneChatComposingStatus(mContact, status);\n                    } else {\n                        switch (imSessionStartMode) {\n                            case ON_OPENING:\n                            case ON_COMPOSING:\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"OneToOne chat session found with contact '\"\n                                            + mContact\n                                            + \"' is not established and imSessionStartMode = \"\n                                            + imSessionStartMode\n                                            + \" so accepting it and sending composing event '\"\n                                            + status + \"'\");\n                                }\n                                session.acceptSession();\n                                session.sendIsComposingStatus(status);\n                                break;\n                            default:\n                                if (sLogger.isActivated()) {\n                                    sLogger.debug(\"OneToOne chat session found with contact '\"\n                                            + mContact\n                                            + \"' is not established and imSessionStartMode = \"\n                                            + imSessionStartMode\n                                            + \" so can't accept it and sending composing event '\"\n                                            + status + \"' yet.\");\n                                }\n                                mImService.addOneToOneChatComposingStatus(mContact, status);\n                                break;\n                        }\n                    }\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to send composing status to contact '\" + mContact + \"'\",\n                            e);\n                }\n            }\n        });\n    }\n\n    /**\n     * open the chat conversation. Note: if its an incoming pending chat session and the parameter\n     * IM SESSION START is 0 then the session is accepted now.\n     * \n     * @see ImSessionStartMode\n     * @throws RemoteException\n     */\n    @Override\n    public void openChat() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.info(\"Open a 1-1 chat session with \" + mContact);\n                }\n                try {\n                    ImSessionStartMode imSessionStartMode = mRcsSettings.getImSessionStartMode();\n                    if (ImSessionStartMode.ON_OPENING == imSessionStartMode) {\n                        mImService.acceptStoreAndForwardMessageSessionIfSuchExists(mContact);\n                    }\n                    final OneToOneChatSession session = mImService.getOneToOneChatSession(mContact);\n                    if (session == null) {\n                        /*\n                         * If there is no session ongoing right now then we do not need to open\n                         * anything right now so we just return here. A sending of a new message on\n                         * this one-to-one chat will anyway result in creating a new session so we\n                         * do not need to do anything more here for now.\n                         */\n                        return;\n                    }\n                    if (!session.getDialogPath().isSessionEstablished()) {\n                        if (!session.isInitiatedByRemote()) {\n                            /*\n                             * This method needs to accept pending invitation if\n                             * IM_SESSION_START_MODE is 0, which is not applicable if session is\n                             * remote originated so we return here.\n                             */\n                            return;\n                        }\n                        if (ImSessionStartMode.ON_OPENING == imSessionStartMode) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Accept one-to-one chat session with contact \"\n                                        .concat(mContact.toString()));\n                            }\n                            session.acceptSession();\n                        }\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to open one-one chat with contact : '\" + mContact + \"'\",\n                            e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Resend a message which previously failed.\n     * \n     * @param msgId message ID\n     * @throws RemoteException\n     */\n    @Override\n    public void resendMessage(final String msgId) throws RemoteException {\n        if (TextUtils.isEmpty(msgId)) {\n            throw new ServerApiIllegalArgumentException(\n                    \"OnetoOneChat messageId must not be null or empty!\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                ChatMessagePersistedStorageAccessor persistentStorage = new ChatMessagePersistedStorageAccessor(\n                        mMessagingLog, msgId);\n                final String mimeType = persistentStorage.getMimeType();\n                /* Set new timestamp for resend message */\n                long timestamp = System.currentTimeMillis();\n                /* For outgoing message, timestampSent = timestamp */\n                final ChatMessage msg = new ChatMessage(msgId, mContact, persistentStorage\n                        .getContent(), mimeType, timestamp, timestamp, null);\n                try {\n                    if (ServerApiUtils.isImsConnected()) {\n                        resendChatMessage(msg);\n                    } else {\n                        /* If the IMS is NOT connected at this time then re-queue message. */\n                        setChatMessageStatusAndReasonCode(msgId, mimeType, Status.QUEUED,\n                                ReasonCode.UNSPECIFIED);\n                    }\n                } catch (FileAccessException | PayloadException e) {\n                    sLogger.error(\"Failed to send chat message with msgId '\" + msgId + \"'\", e);\n                    setChatMessageStatusAndReasonCode(msgId, mimeType, Status.FAILED,\n                            ReasonCode.FAILED_SEND);\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to send chat message with msgId '\"\n                                + msg.getMessageId() + \"'! (\" + e.getMessage() + \")\");\n                    }\n                    setChatMessageStatusAndReasonCode(msgId, mimeType, Status.FAILED,\n                            ReasonCode.FAILED_SEND);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\"Failed to send chat message with msgId '\" + msg.getMessageId()\n                            + \"'\", e);\n                }\n            }\n        });\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        boolean loggerActivated = sLogger.isActivated();\n        if (loggerActivated) {\n            sLogger.info(\"Session started\");\n        }\n        synchronized (mLock) {\n            Boolean composingStatus = mImService.getOneToOneChatComposingStatus(mContact);\n            if (composingStatus != null) {\n                OneToOneChatSession session = mImService.getOneToOneChatSession(mContact);\n                try {\n                    if (session != null) {\n                        if (loggerActivated) {\n                            sLogger.debug(\"Sending isComposing command with status :\"\n                                    .concat(composingStatus.toString()));\n                        }\n                        session.sendIsComposingStatus(composingStatus);\n                    }\n                    mImService.removeOneToOneChatComposingStatus(mContact);\n                } catch (NetworkException e) {\n                    /*\n                     * Nothing to be handled here as we are not able to send composing status for\n                     * now, should try later and hence we don't remove it from the map.\n                     */\n                    if (loggerActivated) {\n                        sLogger.debug(e.getMessage());\n                    }\n                }\n            }\n        }\n        mImService.tryToDequeueOneToOneChatMessages(contact);\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session aborted (reason \" + reason + \")\");\n        }\n        synchronized (mLock) {\n            mChatService.removeOneToOneChat(mContact);\n        }\n        mImService.tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers();\n    }\n\n    @Override\n    public void onMessageReceived(final ChatMessage msg, final boolean imdnDisplayedRequested,\n            final boolean deliverySuccess) {\n        mImService.scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                try {\n                    String msgId = msg.getMessageId();\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"New IM with messageId '\" + msgId + \"' received from \"\n                                + mContact + \".\");\n                    }\n                    synchronized (mLock) {\n                        if (mContactManager.isBlockedForContact(mContact)) {\n                            if (sLogger.isActivated()) {\n                                sLogger.debug(\"Contact \"\n                                        + mContact\n                                        + \" is blocked: automatically abort the chat session and store message to spam folder.\");\n                            }\n                            OneToOneChatSession session = mImService\n                                    .getOneToOneChatSession(mContact);\n                            if (session != null) {\n                                session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n                            }\n                            mMessagingLog.addOneToOneSpamMessage(msg);\n                            mBroadcaster.broadcastMessageReceived(msg.getMimeType(), msgId);\n                            return;\n                        }\n                        if (deliverySuccess) {\n                            mMessagingLog.addIncomingOneToOneChatMessage(msg,\n                                    imdnDisplayedRequested);\n                        } else {\n                            mMessagingLog.addOneToOneFailedDeliveryMessage(msg);\n                        }\n                        mBroadcaster.broadcastMessageReceived(msg.getMimeType(), msgId);\n                    }\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to receive chat message! (\" + e.getMessage() + \")\");\n                    }\n                } catch (PayloadException | RuntimeException e) {\n                    sLogger.error(\"Failed to receive chat message!\", e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void onImError(ChatError error, String msgId, String mimeType) {\n        int errorCode = error.getErrorCode();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"IM error \" + errorCode + \" ; First message '\" + msgId + \"'\");\n        }\n        synchronized (mLock) {\n            mChatService.removeOneToOneChat(mContact);\n            switch (errorCode) {\n                case ChatError.SESSION_INITIATION_FAILED:\n                case ChatError.SESSION_INITIATION_CANCELLED:\n                    mImService.getDeliveryExpirationManager().cancelDeliveryTimeoutAlarm(msgId);\n                    if (FileTransferUtils.isFileTransferHttpType(mimeType)) {\n                        mImService.setOneToOneFileTransferFailureReasonCode(msgId, mContact,\n                                FileTransfer.ReasonCode.FAILED_DATA_TRANSFER);\n                    } else if (ChatUtils.isTextPlainType(mimeType)\n                            || MimeType.GEOLOC_MESSAGE.equals(mimeType)) {\n                        setChatMessageStatusAndReasonCode(msgId, mimeType, Status.FAILED,\n                                ReasonCode.FAILED_SEND);\n                    }\n                    break;\n                /*\n                 * For cases where send response failed due to no ACK/200 OK response, we should not\n                 * change Chat state.\n                 */\n                /* Intentional fall through */\n                case ChatError.SEND_RESPONSE_FAILED:\n                    break;\n                default:\n                    break;\n            }\n        }\n        mImService.tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers();\n    }\n\n    @Override\n    public void onIsComposingEventReceived(ContactId contact, boolean status) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"\" + contact + \" is composing status set to \" + status);\n        }\n        synchronized (mLock) {\n            mBroadcaster.broadcastComposingEvent(contact, status);\n        }\n    }\n\n    @Override\n    public void onMessageSent(String msgId, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Message sent; msgId=\" + msgId + \".\");\n        }\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, Status.SENT,\n                    ReasonCode.UNSPECIFIED)) {\n                mBroadcaster.broadcastMessageStatusChanged(mContact, mimeType, msgId, Status.SENT,\n                        ReasonCode.UNSPECIFIED);\n            }\n        }\n    }\n\n    @Override\n    public void onMessageFailedSend(String msgId, String mimeType) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Message sent; msgId=\" + msgId + \".\");\n        }\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, Status.FAILED,\n                    ReasonCode.FAILED_SEND)) {\n                mBroadcaster.broadcastMessageStatusChanged(mContact, mimeType, msgId,\n                        Status.FAILED, ReasonCode.FAILED_SEND);\n            }\n        }\n    }\n\n    @Override\n    public void onMessageDeliveryStatusReceived(ContactId contact, ImdnDocument imdn) {\n        mChatService.onOneToOneMessageDeliveryStatusReceived(contact, imdn);\n    }\n\n    @Override\n    public void onDeliveryStatusReceived(String contributionId, ContactId contact, ImdnDocument imdn) {\n        String msgId = imdn.getMsgId();\n        if (mMessagingLog.isMessagePersisted(msgId)) {\n            onMessageDeliveryStatusReceived(contact, imdn);\n            return;\n        }\n        if (mMessagingLog.isFileTransfer(msgId)) {\n            mImService.receiveOneToOneFileDeliveryStatus(contact, imdn);\n            return;\n        }\n        sLogger.error(\"Imdn delivery report received referencing an entry that was \"\n                + \"not found in our database. Message id \" + msgId + \", ignoring.\");\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            switch (reason) {\n                case TERMINATION_BY_USER:\n                    sLogger.info(\"Session rejected by user.\");\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    /* Intentional fall through */\n                case TERMINATION_BY_SYSTEM:\n                    sLogger.info(\"Session rejected by system.\");\n                    break;\n                case TERMINATION_BY_TIMEOUT:\n                    sLogger.info(\"Session rejected by timeout.\");\n                    break;\n                case TERMINATION_BY_INACTIVITY:\n                    sLogger.info(\"Session rejected by inactivity.\");\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    sLogger.info(\"Session rejected by remote.\");\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason\n                            + \"!\");\n            }\n        }\n        synchronized (mLock) {\n            mChatService.removeOneToOneChat(mContact);\n        }\n        mImService.tryToDequeueAllOneToOneChatMessagesAndOneToOneFileTransfers();\n    }\n\n    @Override\n    public void onSessionInvited(ContactId contact) {\n        /* Not used by one-to-one chat */\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        /* Not used by one-to-one chat */\n    }\n\n    @Override\n    public void onSessionAutoAccepted(ContactId contact) {\n        /* Not used by one-to-one chat */\n    }\n\n    @Override\n    public void onChatMessageDisplayReportSent(String msgId) {\n        synchronized (mLock) {\n            if (mMessagingLog.setChatMessageStatusAndReasonCode(msgId, Status.RECEIVED,\n                    ReasonCode.UNSPECIFIED)) {\n                String apiMimeType = mMessagingLog.getMessageMimeType(msgId);\n                mBroadcaster.broadcastMessageStatusChanged(mContact, apiMimeType, msgId,\n                        Status.RECEIVED, ReasonCode.UNSPECIFIED);\n            }\n        }\n    }\n\n    @Override\n    public void onDeliveryReportSendViaMsrpFailure(String msgId, ContactId contact,\n            TypeMsrpChunk typeMsrpChunk) {\n        if (TypeMsrpChunk.MessageDeliveredReport.equals(typeMsrpChunk)) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Failed to send delivered message via MSRP, so try to send via SIP message to \"\n                        + contact + \"(msgId = \" + msgId);\n            }\n            /* Send the delivered notification by SIP */\n            ContactId remote = getRemoteContact();\n            mImService.getImdnManager().sendMessageDeliveryStatus(remote.toString(), remote, msgId,\n                    ImdnDocument.DeliveryStatus.DELIVERED, System.currentTimeMillis());\n\n        } else if (TypeMsrpChunk.MessageDisplayedReport.equals(typeMsrpChunk)) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Failed to send displayed message via MSRP, so try to send via SIP message to \"\n                        + contact + \"(msgId = \" + msgId);\n            }\n            /* Send the displayed notification by SIP */\n            ContactId remote = getRemoteContact();\n            mImService.getImdnManager().sendMessageDeliveryStatus(remote.toString(), remote, msgId,\n                    ImdnDocument.DeliveryStatus.DISPLAYED, System.currentTimeMillis());\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/OneToOneDeliveryExpirationService.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.DeliveryExpirationManager;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.app.IntentService;\nimport android.content.Intent;\n\npublic class OneToOneDeliveryExpirationService extends IntentService {\n\n    private final Logger sLogger = Logger.getLogger(OneToOneDeliveryExpirationService.class\n            .getName());\n\n    public OneToOneDeliveryExpirationService() {\n        super(OneToOneDeliveryExpirationService.class.getCanonicalName());\n    }\n\n    @Override\n    protected void onHandleIntent(final Intent intent) {\n        final Core core = Core.getInstance();\n        if (core == null || !core.isStarted()) {\n            /* Stack is not started, don't process this intent */\n            if (sLogger.isActivated()) {\n                sLogger.warn(\"Stack is not running, do not process the delivery expiration intent!\");\n            }\n            return;\n        }\n        InstantMessagingService imService = core.getImService();\n        final DeliveryExpirationManager deliveryExpirarationManager = imService\n                .getDeliveryExpirationManager();\n        imService.scheduleImOperation(new Runnable() {\n            @Override\n            public void run() {\n                String action = intent.getAction();\n                try {\n                    if (DeliveryExpirationManager.ACTION_CHAT_MESSAGE_DELIVERY_TIMEOUT\n                            .equals(action)) {\n                        deliveryExpirarationManager.onChatMessageDeliveryExpirationReceived(intent);\n                    } else if (DeliveryExpirationManager.ACTION_FILE_TRANSFER_DELIVERY_TIMEOUT\n                            .equals(action)) {\n                        deliveryExpirarationManager\n                                .onFileTransferDeliveryExpirationReceived(intent);\n                    }\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\n                                    \"Unable to handle one to one delivery expiration event for intent action : \")\n                                    .append(action).toString(), e);\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/OneToOneFileTransferImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.im.InstantMessagingService;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingError;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileSharingSessionListener;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.ImsFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.DownloadFromAcceptFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.DownloadFromResumeFileSharingSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.HttpFileTransferSession;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.ResumeUploadFileSharingSession;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.fthttp.FtHttpResume;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeDownload;\nimport com.gsma.rcs.provider.fthttp.FtHttpResumeUpload;\nimport com.gsma.rcs.provider.messaging.FileTransferPersistedStorageAccessor;\nimport com.gsma.rcs.provider.messaging.FileTransferStateAndReasonCode;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.settings.RcsSettingsData.FileTransferProtocol;\nimport com.gsma.rcs.service.broadcaster.IOneToOneFileTransferBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.filetransfer.IFileTransfer;\n\nimport android.net.Uri;\nimport android.os.RemoteException;\n\n/**\n * File transfer implementation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class OneToOneFileTransferImpl extends IFileTransfer.Stub implements\n        FileSharingSessionListener {\n\n    private final String mFileTransferId;\n\n    private final IOneToOneFileTransferBroadcaster mBroadcaster;\n\n    private final InstantMessagingService mImService;\n\n    private final FileTransferPersistedStorageAccessor mPersistentStorage;\n\n    private final FileTransferServiceImpl mFileTransferService;\n\n    private final RcsSettings mRcsSettings;\n\n    private final MessagingLog mMessagingLog;\n\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger\n            .getLogger(OneToOneFileTransferImpl.class.getName());\n\n    private final ContactManager mContactManager;\n\n    /**\n     * Constructor\n     * \n     * @param transferId Transfer ID\n     * @param broadcaster IOneToOneFileTransferBroadcaster\n     * @param imService InstantMessagingService\n     * @param persistentStorage FileTransferPersistedStorageAccessor\n     * @param fileTransferService FileTransferServiceImpl\n     * @param rcsSettings The RCS settings accessor\n     * @param messagingLog The messaging log accessor\n     * @param contactManager The contact manager accessor\n     */\n    public OneToOneFileTransferImpl(InstantMessagingService imService, String transferId,\n            IOneToOneFileTransferBroadcaster broadcaster,\n            FileTransferPersistedStorageAccessor persistentStorage,\n            FileTransferServiceImpl fileTransferService, RcsSettings rcsSettings,\n            MessagingLog messagingLog, ContactManager contactManager) {\n        mImService = imService;\n        mFileTransferId = transferId;\n        mBroadcaster = broadcaster;\n        mPersistentStorage = persistentStorage;\n        mFileTransferService = fileTransferService;\n        mRcsSettings = rcsSettings;\n        mMessagingLog = messagingLog;\n        mContactManager = contactManager;\n    }\n\n    private State getRcsState(FileSharingSession session) {\n        if (session instanceof HttpFileTransferSession) {\n            HttpFileTransferSession.State state = ((HttpFileTransferSession) session)\n                    .getSessionState();\n            if (HttpFileTransferSession.State.ESTABLISHED == state) {\n                if (isSessionPaused(session)) {\n                    return State.PAUSED;\n                }\n                return State.STARTED;\n            }\n        } else if (session instanceof ImsFileSharingSession) {\n            if (session.isFileTransferred()) {\n                return State.TRANSFERRED;\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return State.STARTED;\n            }\n        } else {\n            throw new IllegalArgumentException(\"Unsupported Filetransfer session type\");\n        }\n        if (session.isInitiatedByRemote()) {\n            if (session.isSessionAccepted()) {\n                return State.ACCEPTING;\n            }\n            return State.INVITED;\n        }\n        return State.INITIATING;\n    }\n\n    private ReasonCode getRcsReasonCode(FileSharingSession session) {\n        if (isSessionPaused(session)) {\n            /*\n             * If session is paused and still established it must have been paused by user\n             */\n            return ReasonCode.PAUSED_BY_USER;\n        }\n        return ReasonCode.UNSPECIFIED;\n    }\n\n    @Override\n    public String getChatId() throws RemoteException {\n        try {\n            /* For 1-1 file transfer, chat ID corresponds to the formatted contact number */\n            return getRemoteContact().toString();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getTransferId() throws RemoteException {\n        return mFileTransferId;\n    }\n\n    @Override\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getFileName() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFileName();\n            }\n            return session.getContent().getName();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public Uri getFile() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFile();\n            }\n            return session.getContent().getUri();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getFileSize() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFileSize();\n            }\n            return session.getContent().getSize();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getMimeType() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getMimeType();\n            }\n            return session.getContent().getEncoding();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public Uri getFileIcon() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFileIcon();\n            }\n            MmContent fileIcon = session.getFileicon();\n            return fileIcon != null ? fileIcon.getUri() : null;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public String getFileIconMimeType() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFileIconMimeType();\n            }\n            MmContent fileIconContent = session.getFileicon();\n            return fileIconContent != null ? fileIconContent.getEncoding() : null;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getState() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getState().toInt();\n            }\n            return getRcsState(session).toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getReasonCode() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getReasonCode().toInt();\n            }\n            return getRcsReasonCode(session).toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getDisposition() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getDisposition().toInt();\n            }\n            if (session.getContent().isPlayable()) {\n                return Disposition.RENDER.toInt();\n            }\n            return Disposition.ATTACH.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public int getDirection() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestamp() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestampSent() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestampSent();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestampDelivered() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestampDelivered();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getTimestampDisplayed() throws RemoteException {\n        try {\n            return mPersistentStorage.getTimestampDisplayed();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void acceptInvitation() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Accept session invitation\");\n                    }\n                    final FileSharingSession ongoingSession = mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (ongoingSession != null) {\n                        if (!ongoingSession.isInitiatedByRemote()) {\n                            sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                    + mFileTransferId + \"': wrong direction\");\n                            return;\n                        }\n                        if (ongoingSession.isSessionAccepted()) {\n                            sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                    + mFileTransferId + \"': already accepted\");\n                            return;\n                        }\n                        ongoingSession.acceptSession();\n                        return;\n                    }\n                    /* No active session: restore session from provider */\n                    FtHttpResume resume = mPersistentStorage.getFileTransferResumeInfo();\n                    if (resume == null) {\n                        sLogger.error(\"Cannot find session sith file transfer ID=\"\n                                .concat(mFileTransferId));\n                        return;\n                    }\n                    if (!(resume instanceof FtHttpResumeDownload)) {\n                        sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                + mFileTransferId + \"': wrong direction\");\n                        return;\n                    }\n                    FtHttpResumeDownload download = (FtHttpResumeDownload) resume;\n                    if (download.isAccepted()) {\n                        sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                + mFileTransferId + \"': already accepted\");\n                        return;\n                    }\n                    if (download.getFileExpiration() < System.currentTimeMillis()) {\n                        sLogger.error(\"Cannot accept transfer with fileTransferId '\"\n                                + mFileTransferId + \"': file has expired\");\n                        return;\n                    }\n                    FileSharingSession session = new DownloadFromAcceptFileSharingSession(\n                            mImService, ContentManager.createMmContent(resume.getFile(),\n                                    resume.getMimeType(), resume.getSize(), resume.getFileName()),\n                            download, mRcsSettings, mMessagingLog, mContactManager);\n                    session.addListener(OneToOneFileTransferImpl.this);\n                    session.startSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to accept file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void rejectInvitation() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Reject session invitation\");\n                    }\n                    final FileSharingSession session = mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session == null) {\n                        if (Direction.INCOMING != mPersistentStorage.getDirection()) {\n                            sLogger.error(\"Cannot reject transfer with fileTransferId '\"\n                                    + mFileTransferId + \"': wrong direction\");\n                            return;\n                        }\n                        State state = mPersistentStorage.getState();\n                        switch (state) {\n                            case INVITED:\n                                handleSessionRejected(ReasonCode.REJECTED_BY_USER,\n                                        mPersistentStorage.getRemoteContact());\n                                return;\n\n                            case REJECTED:\n                                if (sLogger.isActivated()) {\n                                    sLogger.info(\"Transfer already rejected for ID=\"\n                                            .concat(mFileTransferId));\n                                }\n                                return;\n\n                            default:\n                                sLogger.error(\"Illegal state to reject file transfer with ID=\"\n                                        .concat(mFileTransferId));\n                                return;\n                        }\n                    }\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to reject file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public void abortTransfer() throws RemoteException {\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.info(\"Cancel session\");\n                    }\n                    final FileSharingSession session = mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session == null) {\n                        /*\n                         * File transfer can be aborted only if it is in state QUEUED/ PAUSED when\n                         * there is no session.\n                         */\n                        State state = mPersistentStorage.getState();\n                        switch (state) {\n                            case QUEUED:\n                            case PAUSED:\n                                setStateAndReasonCode(getRemoteContact(), State.ABORTED,\n                                        ReasonCode.ABORTED_BY_SYSTEM);\n                                return;\n                            default:\n                                sLogger.error(\"Session with file transfer ID '\" + mFileTransferId\n                                        + \"' not available!\");\n                                return;\n                        }\n                    }\n                    if (session.isFileTransferred()) {\n                        /* File already transferred and session automatically closed after transfer */\n                        sLogger.error(\"Cannot abort as file is already transferred!\");\n                        return;\n                    }\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (PayloadException | RemoteException | RuntimeException e) {\n                    sLogger.error(\"Failed to terminate session with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    private boolean isHttpTransfer() {\n        FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n        if (session == null) {\n            throw new ServerApiGenericException(\n                    \"Unable to check if it is HTTP transfer since session with file transfer ID '\"\n                            + mFileTransferId + \"' not available!\");\n        }\n        return session.isHttpTransfer();\n    }\n\n    @Override\n    public boolean isAllowedToPauseTransfer() throws RemoteException {\n        return isAllowedToPauseTransfer(false);\n    }\n\n    private boolean isAllowedToPauseTransfer(boolean internalRequest) {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\"\n                            + mFileTransferId\n                            + \"' as there is no ongoing session corresponding to the fileTransferId.\");\n                }\n                return false;\n            }\n            if (!session.isHttpTransfer()) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\" + mFileTransferId\n                            + \"' as it is not a HTTP File transfer.\");\n                }\n                return false;\n            }\n            State state = getRcsState(session);\n            if (State.STARTED != state) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\" + mFileTransferId\n                            + \"' as it is in state \" + state);\n                }\n                return false;\n            }\n            if (mPersistentStorage.getFileTransferProgress() == mPersistentStorage.getFileSize()) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot pause transfer with file transfer Id '\" + mFileTransferId\n                            + \"' as full content is transferred\");\n                }\n                return false;\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void pauseTransfer() throws RemoteException {\n        if (!isAllowedToPauseTransfer(true)) {\n            throw new ServerApiPermissionDeniedException(\"Not allowed to pause transfer.\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Pause session\");\n                }\n                try {\n                    HttpFileTransferSession session = (HttpFileTransferSession) mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session == null) {\n                        sLogger.error(\"Failed to pause file transfer with fileTransferId : \"\n                                + mFileTransferId + \"since no such session exists anymore.\");\n                        return;\n                    }\n                    session.onPause();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to pause file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    private boolean isSessionPaused(FileSharingSession session) {\n        if (session == null) {\n            throw new ServerApiGenericException(\n                    \"Unable to check if transfer is paused since session with file transfer ID '\"\n                            + mFileTransferId + \"' not available!\");\n        }\n        if (!isHttpTransfer()) {\n            if (sLogger.isActivated()) {\n                sLogger.info(\"Pause available only for HTTP transfer\");\n            }\n            return false;\n        }\n        return session.isFileTransferPaused();\n    }\n\n    @Override\n    public boolean isAllowedToResumeTransfer() throws RemoteException {\n        return isAllowedToResumeTransfer(false);\n    }\n\n    private boolean isAllowedToResumeTransfer(boolean internalRequest) throws RemoteException {\n        try {\n            ReasonCode reasonCode;\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session != null) {\n                reasonCode = getRcsReasonCode(session);\n            } else {\n                reasonCode = mPersistentStorage.getReasonCode();\n            }\n            if (ReasonCode.PAUSED_BY_USER != reasonCode) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                            + mFileTransferId + \"' as it is \" + reasonCode);\n                }\n                return false;\n            }\n            if (!ServerApiUtils.isImsConnected()) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                            + mFileTransferId + \"' as it there is no IMS connection right now.\");\n                }\n                return false;\n            }\n            if (session == null) {\n                if (!mImService.isFileTransferSessionAvailable()) {\n                    if (internalRequest && sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                                + mFileTransferId\n                                + \"' as the limit of available file transfer session is reached.\");\n                    }\n                    return false;\n                }\n                if (Direction.OUTGOING == mPersistentStorage.getDirection()) {\n                    if (mImService.isMaxConcurrentOutgoingFileTransfersReached()) {\n                        if (internalRequest && sLogger.isActivated()) {\n                            sLogger.debug(\"Cannot resume transfer with file transfer Id '\"\n                                    + mFileTransferId\n                                    + \"' as the limit of maximum concurrent outgoing file transfer is reached.\");\n                        }\n                        return false;\n                    }\n                }\n            }\n            return true;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void resumeTransfer() throws RemoteException {\n        if (!isAllowedToResumeTransfer(true)) {\n            throw new ServerApiPermissionDeniedException(\"Not allowed to resume transfer.\");\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Resume session\");\n                }\n                try {\n                    HttpFileTransferSession session = (HttpFileTransferSession) mImService\n                            .getFileSharingSession(mFileTransferId);\n                    if (session != null) {\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(\"Resume file transfer from existing session: interrupted \"\n                                    + session.isInterrupted() + \" state=\" + session.getState());\n                        }\n\n                        session.onResume();\n                        return;\n                    }\n                    FtHttpResume resume = mPersistentStorage.getFileTransferResumeInfo();\n                    if (resume == null) {\n                        sLogger.error(\"Unable to resume file with fileTransferId \"\n                                + mFileTransferId\n                                + \" since it no longer exists in persistent storage!\");\n                        return;\n                    }\n                    if (Direction.OUTGOING == resume.getDirection()) {\n                        session = new ResumeUploadFileSharingSession(mImService, ContentManager\n                                .createMmContent(resume.getFile(), resume.getMimeType(),\n                                        resume.getSize(), resume.getFileName()),\n                                (FtHttpResumeUpload) resume, mRcsSettings, mMessagingLog,\n                                mContactManager);\n                    } else {\n                        session = new DownloadFromResumeFileSharingSession(mImService,\n                                ContentManager.createMmContent(resume.getFile(),\n                                        resume.getMimeType(), resume.getSize(),\n                                        resume.getFileName()), (FtHttpResumeDownload) resume,\n                                mRcsSettings, mMessagingLog, mContactManager);\n                    }\n                    session.addListener(OneToOneFileTransferImpl.this);\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Resume file transfer from new session\");\n                    }\n                    session.startSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to resume file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean isAllowedToResendTransfer() throws RemoteException {\n        return isAllowedToResendTransfer(false);\n    }\n\n    private boolean isAllowedToResendTransfer(boolean internalRequest) throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session != null) {\n                if (internalRequest && sLogger.isActivated()) {\n                    sLogger.debug(\"Cannot resend transfer with fileTransferId \"\n                            + mFileTransferId\n                            + \" as there is already an ongoing session corresponding to this fileTransferId\");\n                }\n                return false;\n            }\n            State rcsState = mPersistentStorage.getState();\n            ReasonCode rcsReasonCode = mPersistentStorage.getReasonCode();\n            /*\n             * According to Blackbird PDD v3.0, \"When a File Transfer is interrupted by sender\n             * interaction (or fails), then resend button shall be offered to allow the user to\n             * re-send the file without selecting a new receiver or selecting the file again.\"\n             */\n            switch (rcsState) {\n                case FAILED:\n                    return true;\n                case REJECTED:\n                    switch (rcsReasonCode) {\n                        case REJECTED_BY_SYSTEM:\n                            return true;\n                        default:\n                            if (internalRequest && sLogger.isActivated()) {\n                                sLogger.debug(\"Cannot resend transfer with fileTransferId \"\n                                        + mFileTransferId + \" as reasonCode=\" + rcsReasonCode);\n                            }\n                            return false;\n                    }\n                case ABORTED:\n                    switch (rcsReasonCode) {\n                        case ABORTED_BY_SYSTEM:\n                        case ABORTED_BY_USER:\n                            return true;\n                        default:\n                            if (internalRequest && sLogger.isActivated()) {\n                                sLogger.debug(\"Cannot resend transfer with fileTransferId \"\n                                        + mFileTransferId + \" as reasonCode=\" + rcsReasonCode);\n                            }\n                            return false;\n                    }\n                default:\n                    if (internalRequest && sLogger.isActivated()) {\n                        sLogger.debug(\"Cannot resend transfer with fileTransferId \"\n                                + mFileTransferId + \" as state=\" + rcsState);\n                    }\n                    return false;\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void resendTransfer() throws RemoteException {\n        if (!isAllowedToResendTransfer(true)) {\n            throw new ServerApiPermissionDeniedException(\n                    \"Unable to resend file with fileTransferId \" + mFileTransferId);\n        }\n        mImService.scheduleImOperation(new Runnable() {\n            public void run() {\n                try {\n                    MmContent file = FileTransferUtils.createMmContent(getFile(), getMimeType(),\n                            Disposition.valueOf(getDisposition()));\n                    Uri fileIcon = getFileIcon();\n                    MmContent fileIconContent = fileIcon != null ? FileTransferUtils\n                            .createIconContent(fileIcon) : null;\n\n                    mFileTransferService.resendOneToOneFile(getRemoteContact(), file,\n                            fileIconContent, mFileTransferId);\n                } catch (RuntimeException | RemoteException e) {\n                    /*\n                     * Intentionally catch runtime exceptions as else it will abruptly end the\n                     * thread and eventually bring the whole system down, which is not intended.\n                     */\n                    sLogger.error(\"Failed to resume file transfer with fileTransferId : \"\n                            + mFileTransferId, e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean isRead() throws RemoteException {\n        try {\n            return mPersistentStorage.isRead();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n    /*\n     * TODO : Fix reasoncode mapping in the switch.\n     */\n    private FileTransferStateAndReasonCode toStateAndReasonCode(FileSharingError error) {\n        int fileSharingError = error.getErrorCode();\n        switch (fileSharingError) {\n            case FileSharingError.SESSION_INITIATION_DECLINED:\n            case FileSharingError.SESSION_INITIATION_CANCELLED:\n                return new FileTransferStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_BY_REMOTE);\n            case FileSharingError.MEDIA_SAVING_FAILED:\n                return new FileTransferStateAndReasonCode(State.FAILED, ReasonCode.FAILED_SAVING);\n            case FileSharingError.MEDIA_SIZE_TOO_BIG:\n                return new FileTransferStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_MAX_SIZE);\n            case FileSharingError.MEDIA_TRANSFER_FAILED:\n            case FileSharingError.MEDIA_UPLOAD_FAILED:\n            case FileSharingError.MEDIA_DOWNLOAD_FAILED:\n                return new FileTransferStateAndReasonCode(State.FAILED,\n                        ReasonCode.FAILED_DATA_TRANSFER);\n            case FileSharingError.NO_CHAT_SESSION:\n                /* Intentional fall through */\n            case FileSharingError.SESSION_INITIATION_FAILED:\n                /* Intentional fall through */\n            case FileSharingError.SEND_RESPONSE_FAILED:\n                return new FileTransferStateAndReasonCode(State.FAILED,\n                        ReasonCode.FAILED_INITIATION);\n            case FileSharingError.NOT_ENOUGH_STORAGE_SPACE:\n                return new FileTransferStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_LOW_SPACE);\n            default:\n                throw new IllegalArgumentException(\n                        \"Unknown reason in OneToOneFileTransferImpl.toStateAndReasonCode; fileSharingError=\"\n                                + fileSharingError + \"!\");\n        }\n    }\n\n    private void setStateAndReasonCode(ContactId contact, State state, ReasonCode reasonCode) {\n        if (mPersistentStorage.setStateAndReasonCode(state, reasonCode)) {\n            mBroadcaster.broadcastStateChanged(contact, mFileTransferId, state, reasonCode);\n        }\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session rejected; reasonCode=\" + reasonCode + \".\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            setStateAndReasonCode(contact, State.REJECTED, reasonCode);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session started\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    /**\n     * Handle file info dequeued\n     */\n    public void onFileInfoDequeued(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"One-One file info with transferId \" + mFileTransferId\n                    + \" dequeued successfully.\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            long deliveryExpiration = 0;\n            if (!mRcsSettings.isFtHttpCapAlwaysOn()) {\n                long timeout = mRcsSettings.getMsgDeliveryTimeoutPeriod();\n                if (timeout > 0) {\n                    deliveryExpiration = System.currentTimeMillis() + timeout;\n                    mImService.getDeliveryExpirationManager()\n                            .scheduleOneToOneFileTransferDeliveryTimeoutAlarm(contact,\n                                    mFileTransferId, deliveryExpiration);\n                }\n            }\n            if (mPersistentStorage.setFileInfoDequeued(deliveryExpiration)) {\n                mBroadcaster.broadcastStateChanged(contact, mFileTransferId, State.TRANSFERRED,\n                        ReasonCode.UNSPECIFIED);\n            }\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session aborted (reason \" + reason + \")\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            switch (reason) {\n                case TERMINATION_BY_TIMEOUT:\n                case TERMINATION_BY_SYSTEM:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    setStateAndReasonCode(contact, State.FAILED, ReasonCode.FAILED_DATA_TRANSFER);\n                    break;\n                case TERMINATION_BY_USER:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    /*\n                     * TODO : Fix sending of SIP BYE by sender once transfer is completed and media\n                     * session is closed. Then this check of state can be removed.\n                     */\n                    if (State.TRANSFERRED != mPersistentStorage.getState()) {\n                        setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    }\n                    break;\n                default:\n                    throw new IllegalArgumentException(\n                            \"Unknown reason in OneToOneFileTransferImpl.handleSessionAborted; terminationReason=\"\n                                    + reason + \"!\");\n            }\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onTransferError(FileSharingError error, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Sharing error \" + error.getErrorCode());\n        }\n\n        FileTransferStateAndReasonCode stateAndReasonCode = toStateAndReasonCode(error);\n        State state = stateAndReasonCode.getState();\n        ReasonCode reasonCode = stateAndReasonCode.getReasonCode();\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            setStateAndReasonCode(contact, state, reasonCode);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onTransferProgress(ContactId contact, long currentSize, long totalSize) {\n        synchronized (mLock) {\n            if (mPersistentStorage.setProgress(currentSize)) {\n                mBroadcaster.broadcastProgressUpdate(contact, mFileTransferId, currentSize,\n                        totalSize);\n            }\n        }\n    }\n\n    @Override\n    public void onTransferNotAllowedToSend(ContactId contact) {\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            setStateAndReasonCode(contact, State.FAILED, ReasonCode.FAILED_NOT_ALLOWED_TO_SEND);\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onFileTransferred(MmContent content, ContactId contact, long fileExpiration,\n            long fileIconExpiration, FileTransferProtocol ftProtocol) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Content transferred\");\n        }\n\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            long deliveryExpiration = 0;\n            if (FileTransferProtocol.HTTP == ftProtocol && !mRcsSettings.isFtHttpCapAlwaysOn()\n                    && Direction.OUTGOING == mPersistentStorage.getDirection()) {\n                long timeout = mRcsSettings.getMsgDeliveryTimeoutPeriod();\n                if (timeout > 0) {\n                    deliveryExpiration = System.currentTimeMillis() + timeout;\n                    mImService.getDeliveryExpirationManager()\n                            .scheduleOneToOneFileTransferDeliveryTimeoutAlarm(contact,\n                                    mFileTransferId, deliveryExpiration);\n                }\n            }\n            if (mPersistentStorage.setTransferred(content, fileExpiration, fileIconExpiration,\n                    deliveryExpiration)) {\n                mBroadcaster.broadcastStateChanged(contact, mFileTransferId, State.TRANSFERRED,\n                        ReasonCode.UNSPECIFIED);\n            }\n        }\n        mImService.tryToDequeueFileTransfers();\n    }\n\n    @Override\n    public void onFileTransferPausedByUser(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer paused by user\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.PAUSED, ReasonCode.PAUSED_BY_USER);\n        }\n    }\n\n    @Override\n    public void onFileTransferPausedBySystem(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer paused by system\");\n        }\n        synchronized (mLock) {\n            mFileTransferService.removeOneToOneFileTransfer(mFileTransferId);\n            setStateAndReasonCode(contact, State.PAUSED, ReasonCode.PAUSED_BY_SYSTEM);\n        }\n    }\n\n    @Override\n    public void onFileTransferResumed(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Transfer resumed\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Accepting transfer\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER, contact);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM, contact);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT, contact);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE, contact);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown reason RejectedReason=\" + reason + \"!\");\n        }\n    }\n\n    @Override\n    public void onSessionInvited(ContactId contact, MmContent file, MmContent fileIcon,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Invited to one-to-one file transfer session\");\n        }\n        synchronized (mLock) {\n            if (!mPersistentStorage.setStateAndTimestamp(State.INVITED, ReasonCode.UNSPECIFIED,\n                    timestamp, timestampSent)) {\n                mPersistentStorage.addOneToOneFileTransfer(contact, Direction.INCOMING, file,\n                        fileIcon, State.INVITED, ReasonCode.UNSPECIFIED, timestamp, timestampSent,\n                        fileExpiration, fileIconExpiration);\n            }\n        }\n\n        mBroadcaster.broadcastInvitation(mFileTransferId);\n    }\n\n    @Override\n    public void onSessionAutoAccepted(ContactId contact, MmContent file, MmContent fileIcon,\n            long timestamp, long timestampSent, long fileExpiration, long fileIconExpiration) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Session auto accepted\");\n        }\n        synchronized (mLock) {\n            if (!mPersistentStorage.setStateAndTimestamp(State.ACCEPTING, ReasonCode.UNSPECIFIED,\n                    timestamp, timestampSent)) {\n                mPersistentStorage.addOneToOneFileTransfer(contact, Direction.INCOMING, file,\n                        fileIcon, State.ACCEPTING, ReasonCode.UNSPECIFIED, timestamp,\n                        timestampSent, fileExpiration, fileIconExpiration);\n            }\n        }\n\n        mBroadcaster.broadcastInvitation(mFileTransferId);\n    }\n\n    @Override\n    public long getFileExpiration() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFileExpiration();\n            }\n            return session.getFileExpiration();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public long getFileIconExpiration() throws RemoteException {\n        try {\n            FileSharingSession session = mImService.getFileSharingSession(mFileTransferId);\n            if (session == null) {\n                return mPersistentStorage.getFileIconExpiration();\n            }\n            return session.getIconExpiration();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public boolean isExpiredDelivery() throws RemoteException {\n        try {\n            return mPersistentStorage.isExpiredDelivery();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    @Override\n    public void onHttpDownloadInfoAvailable() {\n        mImService.tryToDequeueFileTransfers();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiBaseException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport android.text.TextUtils;\n\n/**\n * Parent for those exception subclasses which are intended to be thrown over AIDL layer.\n * <p>\n * <b>Un-Checked Exception. </b>\n * </p>\n * <p>\n * To avoid over-logging this class doesn't intend to log exceptions for each of the sub-classes\n * that extend this class, as some of them might have occurred due to improper usage of terminal api\n * and hence should be corrected on that layer.\n * </p>\n * <p>\n * The decision for sub-classes that whether they want to be get logged or not is based on the\n * implementation of <i>shouldBeLogged()</i>\n * </p>\n */\npublic abstract class ServerApiBaseException extends IllegalStateException {\n\n    /**\n     * Special Delimiter that will be appended while propagating server exceptions over AIDL layer.\n     */\n    private static final char DELIMITER_PIPE = '|';\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Helper method to validate exception message.\n     * <p>\n     * Exception message should never be NULL or EMPTY, this is strictly mandated for RCS customized\n     * exceptions as there will never be an instance where we should not be able to specify the\n     * reason for the thrown exception\n     * </p>\n     * \n     * @param message message\n     * @return String\n     */\n    private static String validateExceptionMessage(String message) {\n        if (TextUtils.isEmpty(message)) {\n            throw new IllegalArgumentException(\"Exception message must never be NULL or EMPTY!\");\n        }\n\n        return message;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param clazz <i>Class.class</i> of the SubClasses\n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    protected ServerApiBaseException(Class<?> clazz, String message) {\n        super(new StringBuilder(clazz.getName()).append(DELIMITER_PIPE)\n                .append(validateExceptionMessage(message)).toString());\n\n    }\n\n    /**\n     * Constructor\n     * \n     * @param clazz <i>Class.class</i> of the SubClasses\n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    protected ServerApiBaseException(Class<?> clazz, String message, Throwable cause) {\n        super(new StringBuilder(clazz.getName()).append(DELIMITER_PIPE)\n                .append(validateExceptionMessage(message)).toString(), cause);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    public abstract boolean shouldNotBeLogged();\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiGenericException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\n/**\n * Server side implementation of {@link RcsGenericException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a {@link RcsGenericException}\n * on the client side.\n * </p>\n * <p>\n * This Generic exception must be thrown when the requested operation failed to fully complete its\n * scope of responsibility and none of the more specified exceptions can be thrown. The client must\n * be able to trust that in case of any failure what so ever and its not possible to throw a more\n * specific exception this exception will be thrown as a kind of default exception to signify that\n * some error occurred that not necessarily need to be more specific than that.\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiGenericException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiGenericException(String message) {\n        super(RcsGenericException.class, message);\n    }\n\n    /**\n     * Constructs a new Exception with the current stack trace and the specified cause.\n     * \n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ServerApiGenericException(Throwable cause) {\n        super(RcsGenericException.class, cause.getMessage(), cause);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ServerApiGenericException(String message, Throwable cause) {\n        super(RcsGenericException.class, message, cause);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiIllegalArgumentException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\n\n/**\n * Server side implementation of {@link RcsIllegalArgumentException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a\n * {@link RcsIllegalArgumentException} on the client side.\n * </p>\n * <p>\n * Thrown when a method of the service API is called with one or multiple illegal input parameter.\n * Such as a calling a method and passing null as a parameter in the case that null is not valid for\n * that parameter.\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiIllegalArgumentException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiIllegalArgumentException(String message) {\n        super(RcsIllegalArgumentException.class, message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ServerApiIllegalArgumentException(String message, Throwable cause) {\n        super(RcsIllegalArgumentException.class, message, cause);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiMaxAllowedSessionLimitReachedException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException;\n\n/**\n * Server side implementation of {@link RcsMaxAllowedSessionLimitReachedException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a\n * {@link RcsMaxAllowedSessionLimitReachedException} on the client side.\n * </p>\n * <p>\n * Thrown if the SERVICE TYPE (message/filetransfer/imageshare/geolocationshare etc) cannot be\n * sent/transfered/resent or a new groupchat invitation cannot be sent right now since the limit of\n * allowed ongoing sessions has already been reached and the client needs to wait for at least one\n * session to be released back to the stack first.\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiMaxAllowedSessionLimitReachedException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiMaxAllowedSessionLimitReachedException(String message) {\n        super(RcsMaxAllowedSessionLimitReachedException.class, message);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiPermissionDeniedException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\n\n/**\n * Server side implementation of {@link RcsPermissionDeniedException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a\n * {@link RcsPermissionDeniedException} on the client side.\n * </p>\n * <p>\n * Thrown when a method of the service API is called that not allowed right now. This can be for\n * multiple reasons like it is not possible to call accept() on a file transfer invitation that has\n * previously already been rejected, the file trying to be sent is not allowed to be read back due\n * to security aspects or any other operation that fails because the operation is not allowed or has\n * been blocked for some other reason.\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiPermissionDeniedException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiPermissionDeniedException(String message) {\n        super(RcsPermissionDeniedException.class, message);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiPersistentStorageException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsPersistentStorageException;\n\n/**\n * Server side implementation of {@link RcsPersistentStorageException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a\n * {@link RcsPersistentStorageException} on the client side.\n * </p>\n * <p>\n * Thrown when a method of the service API is called to persist data or read back persisted data\n * failed. This can be because the underlying persistent storage database (or possibly further on a\n * CPM cloud) reported an error such as no more entries can be added perhaps because disk is full,\n * or just that a SQL operation failed or even a unsuccessful read operation from persistent\n * storage.\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiPersistentStorageException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiPersistentStorageException(String message) {\n        super(RcsPersistentStorageException.class, message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public ServerApiPersistentStorageException(String message, Throwable cause) {\n        super(RcsPersistentStorageException.class, message, cause);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiServiceNotRegisteredException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\n\n/**\n * Server side implementation of {@link RcsServiceNotRegisteredException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a\n * {@link RcsServiceNotRegisteredException} on the client side.\n * </p>\n * <p>\n * Thrown when a method of the service API using the RCS service platform is called and the terminal\n * which requires that the RcsCoreService is registered and connected to the IMS server is not\n * registered to the RCS service platform (e.g. not yet registered)\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiServiceNotRegisteredException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiServiceNotRegisteredException(String message) {\n        super(RcsServiceNotRegisteredException.class, message);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiUnsupportedOperationException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.services.rcs.RcsUnsupportedOperationException;\n\n/**\n * Server side implementation of {@link RcsUnsupportedOperationException},\n * <p>\n * This exception will be thrown across AIDL layers and will come as a\n * {@link RcsUnsupportedOperationException} on the client side.\n * </p>\n * <p>\n * Thrown when a method of the service API is called that is not supported (ie does not make sense\n * within the scope of the use case) like trying to call pauseTransfer() on a non pausable file\n * transfer that does not support that etc.\n * </p>\n * <p>\n * <b> Should never be used on client side.</b>\n * </p>\n */\npublic class ServerApiUnsupportedOperationException extends ServerApiBaseException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public ServerApiUnsupportedOperationException(String message) {\n        super(RcsUnsupportedOperationException.class, message);\n    }\n\n    /**\n     * Api for the subclasses to decide if this exception should be treated as a bug and hence to be\n     * get logged or not in the service layer just before AIDL connection to client.\n     * \n     * @return boolean TRUE if exception should not be logged.\n     */\n    @Override\n    public boolean shouldNotBeLogged() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/ServerApiUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.network.ImsNetworkInterface;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Server API utils\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ServerApiUtils {\n    /**\n     * Test core\n     */\n    public static void testCore() {\n        if (Core.getInstance() == null) {\n            throw new ServerApiGenericException(\"Core is not instanciated\");\n        }\n    }\n\n    /**\n     * Test IMS connection\n     */\n    public static void testIms() {\n        if (!isImsConnected()) {\n            throw new ServerApiServiceNotRegisteredException(\"Core is not connected to IMS\");\n        }\n    }\n\n    /**\n     * Is connected to IMS\n     * \n     * @return Boolean\n     */\n    public static boolean isImsConnected() {\n        Core core = Core.getInstance();\n        if (core == null) {\n            return false;\n        }\n        ImsNetworkInterface networkInterface = core.getImsModule().getCurrentNetworkInterface();\n        return networkInterface != null && networkInterface.isRegistered();\n    }\n\n    /**\n     * Gets the reason code for IMS service registration\n     * \n     * @return reason code\n     */\n    public static RcsServiceRegistration.ReasonCode getServiceRegistrationReasonCode() {\n        Core core = Core.getInstance();\n        if (core == null) {\n            return RcsServiceRegistration.ReasonCode.UNSPECIFIED;\n        }\n        ImsNetworkInterface networkInterface = core.getImsModule().getCurrentNetworkInterface();\n        if (networkInterface == null) {\n            return RcsServiceRegistration.ReasonCode.UNSPECIFIED;\n        }\n        return networkInterface.getRegistrationReasonCode();\n    }\n\n    /**\n     * Test IMS extension\n     * \n     * @param ext Extension ID\n     * @throws ServerApiPermissionDeniedException\n     * @throws ServerApiServiceNotRegisteredException\n     */\n    public static void testImsExtension(String ext) throws ServerApiPermissionDeniedException,\n            ServerApiServiceNotRegisteredException {\n        if (!isImsConnected()) {\n            throw new ServerApiServiceNotRegisteredException(\"Core is not connected to IMS\");\n        }\n        if (!Core.getInstance().getImsModule().getExtensionManager().isExtensionAuthorized(ext)) {\n            throw new ServerApiPermissionDeniedException(\"Extension not authorized\");\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/VideoSharingImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.content.VideoContent;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.protocol.sip.SipDialogPath;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.InvitationStatus;\nimport com.gsma.rcs.core.ims.service.ImsServiceSession.TerminationReason;\nimport com.gsma.rcs.core.ims.service.richcall.ContentSharingError;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoStreamingSession;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoStreamingSessionListener;\nimport com.gsma.rcs.provider.sharing.VideoSharingPersistedStorageAccessor;\nimport com.gsma.rcs.provider.sharing.VideoSharingStateAndReasonCode;\nimport com.gsma.rcs.service.broadcaster.IVideoSharingEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.sharing.video.IVideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\nimport com.gsma.services.rcs.sharing.video.VideoDescriptor;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport android.os.RemoteException;\n\n/**\n * Video sharing session\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoSharingImpl extends IVideoSharing.Stub implements VideoStreamingSessionListener {\n\n    private final String mSharingId;\n\n    private long mStartTime = 0;\n\n    private final IVideoSharingEventBroadcaster mBroadcaster;\n\n    private final RichcallService mRichcallService;\n\n    private final VideoSharingPersistedStorageAccessor mPersistentStorage;\n\n    private final VideoSharingServiceImpl mVideoSharingService;\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(VideoSharingImpl.class.getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param sharingId Unique Id of video sharing\n     * @param richcallService RichcallService\n     * @param broadcaster IVideoSharingEventBroadcaster\n     * @param persistentStorage VideoSharingPersistedStorageAccessor\n     * @param videoSharingService VideoSharingServiceImpl\n     */\n    public VideoSharingImpl(String sharingId, RichcallService richcallService,\n            IVideoSharingEventBroadcaster broadcaster,\n            VideoSharingPersistedStorageAccessor persistentStorage,\n            VideoSharingServiceImpl videoSharingService) {\n        mSharingId = sharingId;\n        mRichcallService = richcallService;\n        mBroadcaster = broadcaster;\n        mPersistentStorage = persistentStorage;\n        mVideoSharingService = videoSharingService;\n    }\n\n    /*\n     * TODO: Fix reasoncode mapping in the switch.\n     */\n    private VideoSharingStateAndReasonCode toStateAndReasonCode(ContentSharingError error) {\n        int code = error.getErrorCode();\n        switch (code) {\n            case ContentSharingError.SESSION_INITIATION_FAILED:\n            case ContentSharingError.SEND_RESPONSE_FAILED:\n                return new VideoSharingStateAndReasonCode(State.FAILED,\n                        ReasonCode.FAILED_INITIATION);\n            case ContentSharingError.SESSION_INITIATION_CANCELLED:\n            case ContentSharingError.SESSION_INITIATION_DECLINED:\n                return new VideoSharingStateAndReasonCode(State.REJECTED,\n                        ReasonCode.REJECTED_BY_REMOTE);\n            case ContentSharingError.MEDIA_TRANSFER_FAILED:\n            case ContentSharingError.MEDIA_STREAMING_FAILED:\n            case ContentSharingError.UNSUPPORTED_MEDIA_TYPE:\n            case ContentSharingError.MEDIA_PLAYER_NOT_INITIALIZED:\n                return new VideoSharingStateAndReasonCode(State.FAILED, ReasonCode.FAILED_SHARING);\n            default:\n                throw new IllegalArgumentException(new StringBuilder(\"Unknown errorCode=\").append(\n                        code).toString());\n        }\n    }\n\n    private void handleSessionRejected(ReasonCode reasonCode, ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session rejected; reasonCode=\".concat(String.valueOf(reasonCode)));\n        }\n        synchronized (mLock) {\n            mVideoSharingService.removeVideoSharing(mSharingId);\n            setStateAndReasonCode(contact, State.REJECTED, reasonCode);\n        }\n    }\n\n    private void setStateAndReasonCode(ContactId contact, State state, ReasonCode reasonCode) {\n        long duration = 0;\n\n        switch (state) {\n            case STARTED:\n                mStartTime = System.currentTimeMillis();\n                break;\n            case ABORTED:\n            case FAILED:\n                duration = mStartTime > 0 ? System.currentTimeMillis() - mStartTime : 0;\n                //$FALL-THROUGH$\n            default:\n                break;\n        }\n\n        if (mPersistentStorage.setStateReasonCodeAndDuration(state, reasonCode, duration)) {\n            mBroadcaster.broadcastStateChanged(contact, mSharingId, state, reasonCode);\n        }\n    }\n\n    /**\n     * Returns the sharing ID of the video sharing\n     * \n     * @return Sharing ID\n     * @throws RemoteException\n     */\n    public String getSharingId() throws RemoteException {\n        try {\n            return mSharingId;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact ID\n     * \n     * @return ContactId\n     * @throws RemoteException\n     */\n    public ContactId getRemoteContact() throws RemoteException {\n        try {\n            VideoStreamingSession session = mRichcallService.getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getRemoteContact();\n            }\n            return session.getRemoteContact();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the sharing\n     * \n     * @return State\n     * @throws RemoteException\n     * @see State\n     */\n    public int getState() throws RemoteException {\n        try {\n            VideoStreamingSession session = mRichcallService.getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getState().toInt();\n            }\n            SipDialogPath dialogPath = session.getDialogPath();\n            if (dialogPath != null && dialogPath.isSessionEstablished()) {\n                return State.STARTED.toInt();\n\n            } else if (session.isInitiatedByRemote()) {\n                if (session.isSessionAccepted()) {\n                    return State.ACCEPTING.toInt();\n                }\n                return State.INVITED.toInt();\n            }\n            return State.INITIATING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the video sharing\n     * \n     * @return ReasonCode\n     * @throws RemoteException\n     * @see ReasonCode\n     */\n    public int getReasonCode() throws RemoteException {\n        try {\n            VideoStreamingSession session = mRichcallService.getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getReasonCode().toInt();\n            }\n            return ReasonCode.UNSPECIFIED.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the sharing (incoming or outgoing)\n     * \n     * @return Direction\n     * @throws RemoteException\n     * @see Direction\n     */\n    public int getDirection() throws RemoteException {\n        try {\n            VideoStreamingSession session = mRichcallService.getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getDirection().toInt();\n            }\n            if (session.isInitiatedByRemote()) {\n                return Direction.INCOMING.toInt();\n            }\n            return Direction.OUTGOING.toInt();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts video sharing invitation\n     * \n     * @param player Video player\n     * @throws RemoteException\n     */\n    public void acceptInvitation(final IVideoPlayer player) throws RemoteException {\n        if (player == null) {\n            throw new ServerApiIllegalArgumentException(\"player must not be null!\");\n        }\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"Accept session invitation\");\n                }\n                try {\n                    final VideoStreamingSession session = mRichcallService\n                            .getVideoSharingSession(mSharingId);\n                    if (session == null) {\n                        sLogger.error(\"Cannot accept sharing: no session with ID=\"\n                                .concat(mSharingId));\n                        return;\n                    }\n                    session.setPlayer(player);\n                    session.acceptSession();\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\"Failed to accept invitation with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Rejects video sharing invitation\n     * \n     * @throws RemoteException\n     */\n    public void rejectInvitation() throws RemoteException {\n        mRichcallService.scheduleImageShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Reject session invitation\");\n                    }\n                    final VideoStreamingSession session = mRichcallService\n                            .getVideoSharingSession(mSharingId);\n                    if (session == null) {\n                        sLogger.error(\"Cannot reject sharing: so session with ID=\"\n                                .concat(mSharingId));\n                        return;\n                    }\n                    session.rejectSession(InvitationStatus.INVITATION_REJECTED_DECLINE);\n\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\"Failed to reject invitation with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Aborts the sharing\n     * \n     * @throws RemoteException\n     */\n    public void abortSharing() throws RemoteException {\n        mRichcallService.scheduleVideoShareOperation(new Runnable() {\n            public void run() {\n                try {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Abort session\");\n                    }\n                    final VideoStreamingSession session = mRichcallService\n                            .getVideoSharingSession(mSharingId);\n                    if (session == null) {\n                        sLogger.debug(\"No ongoing session with sharing ID:\" + mSharingId\n                                + \" is found so nothing to abort!\");\n                        return;\n                    }\n                    session.terminateSession(TerminationReason.TERMINATION_BY_USER);\n\n                } catch (NetworkException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(e.getMessage());\n                    }\n                } catch (PayloadException e) {\n                    sLogger.error(\n                            new StringBuilder(\"Failed to terminate session with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                } catch (RuntimeException e) {\n                    /*\n                     * Normally we are not allowed to catch runtime exceptions as these are genuine\n                     * bugs which should be handled/fixed within the code. However the cases when we\n                     * are executing operations on a thread unhandling such exceptions will\n                     * eventually lead to exit the system and thus can bring the whole system down,\n                     * which is not intended.\n                     */\n                    sLogger.error(\n                            new StringBuilder(\"Failed to terminate session with sharing ID: \")\n                                    .append(mSharingId).toString(), e);\n                }\n            }\n        });\n    }\n\n    /**\n     * Return the video encoding (eg. H.264)\n     * \n     * @return Encoding\n     * @throws RemoteException\n     */\n    public String getVideoEncoding() throws RemoteException {\n        try {\n            final VideoStreamingSession session = mRichcallService\n                    .getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getVideoEncoding();\n            }\n            IVideoPlayer player = session.getPlayer();\n            if (player == null) {\n                throw new ServerApiGenericException(new StringBuilder(\n                        \"Cannot get video encoding for session with sharing ID:\")\n                        .append(mSharingId).toString());\n            }\n            VideoCodec codec = player.getCodec();\n            if (codec == null) {\n                throw new ServerApiGenericException(new StringBuilder(\n                        \"Cannot get video codec for session with sharing ID:\").append(mSharingId)\n                        .toString());\n            }\n            return codec.getEncoding();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the video sharing was initiated for outgoing video\n     * sharing or the local timestamp of when the video sharing invitation was received for incoming\n     * video sharings.\n     * \n     * @return Timestamp in milliseconds\n     * @throws RemoteException\n     */\n    public long getTimestamp() throws RemoteException {\n        try {\n            final VideoStreamingSession session = mRichcallService\n                    .getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getTimestamp();\n            }\n            return session.getTimestamp();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the duration of the video sharing\n     * \n     * @return Duration in milliseconds\n     * @throws RemoteException\n     */\n    public long getDuration() throws RemoteException {\n        try {\n            final VideoStreamingSession session = mRichcallService\n                    .getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getDuration();\n            }\n            return mStartTime > 0 ? System.currentTimeMillis() - mStartTime : 0;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the video descriptor\n     * \n     * @return Video descriptor\n     * @throws RemoteException\n     * @see VideoDescriptor\n     */\n    public VideoDescriptor getVideoDescriptor() throws RemoteException {\n        try {\n            final VideoStreamingSession session = mRichcallService\n                    .getVideoSharingSession(mSharingId);\n            if (session == null) {\n                return mPersistentStorage.getVideoDescriptor();\n            }\n            IVideoPlayer player = session.getPlayer();\n            if (player != null) {\n                VideoCodec codec = player.getCodec();\n                return new VideoDescriptor(codec.getWidth(), codec.getHeight());\n\n            }\n            VideoContent content = (VideoContent) session.getContent();\n            return new VideoDescriptor(content.getWidth(), content.getHeight());\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /*------------------------------- SESSION EVENTS ----------------------------------*/\n\n    @Override\n    public void onSessionStarted(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session started\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.STARTED, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionAborted(ContactId contact, TerminationReason reason) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Session aborted, reason=\".concat(String.valueOf(reason)));\n        }\n        synchronized (mLock) {\n            mVideoSharingService.removeVideoSharing(mSharingId);\n            switch (reason) {\n                case TERMINATION_BY_SYSTEM:\n                case TERMINATION_BY_TIMEOUT:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_SYSTEM);\n                    break;\n                case TERMINATION_BY_CONNECTION_LOST:\n                    setStateAndReasonCode(contact, State.FAILED, ReasonCode.FAILED_SHARING);\n                    break;\n                case TERMINATION_BY_USER:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_USER);\n                    break;\n                case TERMINATION_BY_REMOTE:\n                    setStateAndReasonCode(contact, State.ABORTED, ReasonCode.ABORTED_BY_REMOTE);\n                    break;\n                default:\n                    throw new IllegalArgumentException(new StringBuilder(\n                            \"Unknown imsServiceSessionError=\").append(reason).toString());\n            }\n        }\n    }\n\n    @Override\n    public void onSharingError(ContactId contact, ContentSharingError error) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Sharing error \".concat(String.valueOf(error.getErrorCode())));\n        }\n        VideoSharingStateAndReasonCode stateAndReasonCode = toStateAndReasonCode(error);\n        State state = stateAndReasonCode.getState();\n        ReasonCode reasonCode = stateAndReasonCode.getReasonCode();\n        synchronized (mLock) {\n            mVideoSharingService.removeVideoSharing(mSharingId);\n            setStateAndReasonCode(contact, state, reasonCode);\n        }\n    }\n\n    @Override\n    public void onSessionAccepting(ContactId contact) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Accepting sharing\");\n        }\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.ACCEPTING, ReasonCode.UNSPECIFIED);\n        }\n    }\n\n    @Override\n    public void onSessionRejected(ContactId contact, TerminationReason reason) {\n        switch (reason) {\n            case TERMINATION_BY_USER:\n                handleSessionRejected(ReasonCode.REJECTED_BY_USER, contact);\n                break;\n            case TERMINATION_BY_SYSTEM:\n                /* Intentional fall through */\n            case TERMINATION_BY_CONNECTION_LOST:\n                handleSessionRejected(ReasonCode.REJECTED_BY_SYSTEM, contact);\n                break;\n            case TERMINATION_BY_TIMEOUT:\n                handleSessionRejected(ReasonCode.REJECTED_BY_TIMEOUT, contact);\n                break;\n            case TERMINATION_BY_REMOTE:\n                handleSessionRejected(ReasonCode.REJECTED_BY_REMOTE, contact);\n                break;\n            default:\n                throw new IllegalArgumentException(new StringBuilder(\n                        \"Unknown reason RejectedReason=\").append(reason).append(\"!\").toString());\n        }\n    }\n\n    @Override\n    public void onInvitationReceived(ContactId contact, MmContent content, long timestamp) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Invited to video sharing session\");\n        }\n        synchronized (mLock) {\n            mPersistentStorage.addVideoSharing(contact, Direction.INCOMING, (VideoContent) content,\n                    State.INVITED, ReasonCode.UNSPECIFIED, timestamp);\n        }\n        mBroadcaster.broadcastInvitation(mSharingId);\n    }\n\n    @Override\n    public void onSessionRinging(ContactId contact) {\n        synchronized (mLock) {\n            setStateAndReasonCode(contact, State.RINGING, ReasonCode.UNSPECIFIED);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/VideoSharingServiceConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport android.os.RemoteException;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingServiceConfiguration;\n\n/**\n * A class that implements interface to allow access to video sharing service configuration from API\n * \n * @author yplo6403\n */\npublic class VideoSharingServiceConfigurationImpl extends IVideoSharingServiceConfiguration.Stub {\n\n    private RcsSettings mRcsSettings;\n\n    private final Logger mLogger = Logger.getLogger(getClass().getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param rcsSettings RCS settings accessor\n     */\n    public VideoSharingServiceConfigurationImpl(RcsSettings rcsSettings) {\n        mRcsSettings = rcsSettings;\n    }\n\n    @Override\n    public long getMaxTime() throws RemoteException {\n        try {\n            return mRcsSettings.getMaxVideoShareDuration();\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            mLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/api/VideoSharingServiceImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.api;\n\nimport com.gsma.rcs.core.content.VideoContent;\nimport com.gsma.rcs.core.ims.service.SessionIdGenerator;\nimport com.gsma.rcs.core.ims.service.richcall.RichcallService;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoStreamingSession;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.provider.sharing.VideoSharingPersistedStorageAccessor;\nimport com.gsma.rcs.service.broadcaster.RcsServiceRegistrationEventBroadcaster;\nimport com.gsma.rcs.service.broadcaster.VideoSharingEventBroadcaster;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsService.Build.VERSION_CODES;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.sharing.video.IVideoSharing;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingListener;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingService;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingServiceConfiguration;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Rich call API service\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoSharingServiceImpl extends IVideoSharingService.Stub {\n\n    private final VideoSharingEventBroadcaster mBroadcaster = new VideoSharingEventBroadcaster();\n\n    private final RcsServiceRegistrationEventBroadcaster mRcsServiceRegistrationEventBroadcaster = new RcsServiceRegistrationEventBroadcaster();\n\n    private final RichcallService mRichcallService;\n\n    private final RichCallHistory mRichCallLog;\n\n    private final RcsSettings mRcsSettings;\n\n    private final Map<String, IVideoSharing> mVideoSharingCache = new HashMap<>();\n\n    /**\n     * Lock used for synchronization\n     */\n    private final Object mLock = new Object();\n\n    private static final Logger sLogger = Logger.getLogger(VideoSharingServiceImpl.class\n            .getSimpleName());\n\n    /**\n     * Constructor\n     * \n     * @param richcallService RichcallService\n     * @param richCallLog RichCallHistory\n     * @param rcsSettings RcsSettings\n     */\n    public VideoSharingServiceImpl(RichcallService richcallService, RichCallHistory richCallLog,\n            RcsSettings rcsSettings) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Video sharing API is loaded\");\n        }\n        mRichcallService = richcallService;\n        mRichcallService.register(this);\n        mRichCallLog = richCallLog;\n        mRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Close API\n     */\n    public void close() {\n        mVideoSharingCache.clear();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Video sharing service API is closed\");\n        }\n    }\n\n    /**\n     * Add a video sharing in the list\n     * \n     * @param videoSharing Video sharing\n     * @param sharingId String\n     */\n    private void addVideoSharing(VideoSharingImpl videoSharing, String sharingId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(new StringBuilder(\"Add an video sharing in the list (size=\")\n                    .append(mVideoSharingCache.size()).append(\")\").toString());\n        }\n        mVideoSharingCache.put(sharingId, videoSharing);\n    }\n\n    /**\n     * Remove a video sharing from the list\n     * \n     * @param sharingId Sharing ID\n     */\n    public void removeVideoSharing(String sharingId) {\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Remove a video sharing\");\n        }\n        mVideoSharingCache.remove(sharingId);\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return Returns true if registered else returns false\n     */\n    @Override\n    public boolean isServiceRegistered() {\n        return ServerApiUtils.isImsConnected();\n    }\n\n    /**\n     * Return the reason code for IMS service registration\n     * \n     * @return the reason code for IMS service registration\n     */\n    @Override\n    public int getServiceRegistrationReasonCode() {\n        return ServerApiUtils.getServiceRegistrationReasonCode().toInt();\n    }\n\n    /**\n     * Registers a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    @Override\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add a service listener\");\n        }\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.addEventListener(listener);\n        }\n    }\n\n    /**\n     * Unregisters a listener on service registration events\n     * \n     * @param listener Service registration listener\n     */\n    @Override\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove a service listener\");\n        }\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.removeEventListener(listener);\n        }\n    }\n\n    /**\n     * Notifies registration event\n     */\n    public void notifyRegistration() {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceRegistered();\n        }\n    }\n\n    /**\n     * Notifies unregistration event\n     * \n     * @param reasonCode for unregistration\n     */\n    public void notifyUnRegistration(RcsServiceRegistration.ReasonCode reasonCode) {\n        synchronized (mLock) {\n            mRcsServiceRegistrationEventBroadcaster.broadcastServiceUnRegistered(reasonCode);\n        }\n    }\n\n    public void setVideoSharingStateAndReasonCode(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode) {\n        mRichCallLog.setVideoSharingStateReasonCode(sharingId, state, reasonCode);\n        mBroadcaster.broadcastStateChanged(contact, sharingId, state, reasonCode);\n    }\n\n    /**\n     * Receive a new video sharing invitation\n     * \n     * @param session Video sharing session\n     */\n    public void receiveVideoSharingInvitation(VideoStreamingSession session) {\n        ContactId contact = session.getRemoteContact();\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Receive video sharing invitation from \")\n                    .append(contact.toString()).append(\" displayName=\")\n                    .append(session.getRemoteDisplayName()).toString());\n        }\n\n        String sharingId = session.getSessionID();\n        VideoSharingPersistedStorageAccessor persistedStorage = new VideoSharingPersistedStorageAccessor(\n                sharingId, mRichCallLog);\n        VideoSharingImpl videoSharing = new VideoSharingImpl(sharingId, mRichcallService,\n                mBroadcaster, persistedStorage, this);\n        addVideoSharing(videoSharing, sharingId);\n        session.addListener(videoSharing);\n    }\n\n    /**\n     * Returns the configuration of video sharing service\n     * \n     * @return Configuration\n     * @throws RemoteException\n     */\n    @Override\n    public IVideoSharingServiceConfiguration getConfiguration() throws RemoteException {\n        try {\n            return new VideoSharingServiceConfigurationImpl(mRcsSettings);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Shares a live video with a contact. The parameter renderer contains the video player provided\n     * by the application. An exception if thrown if there is no ongoing CS call. The parameter\n     * contact supports the following formats: MSISDN in national or international format, SIP\n     * address, SIP-URI or Tel-URI. If the format of the contact is not supported an exception is\n     * thrown.\n     * \n     * @param contact Contact ID\n     * @param player Video player\n     * @return Video sharing\n     * @throws RemoteException\n     */\n    @Override\n    public IVideoSharing shareVideo(ContactId contact, IVideoPlayer player) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        if (player == null) {\n            throw new ServerApiIllegalArgumentException(\"player must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(new StringBuilder(\"Initiate a live video session with \").append(contact)\n                    .toString());\n        }\n        ServerApiUtils.testIms();\n        try {\n            long timestamp = System.currentTimeMillis();\n            final VideoStreamingSession session = mRichcallService.createLiveVideoSharingSession(\n                    contact, player, timestamp);\n            final String sharingId = session.getSessionID();\n            VideoContent content = (VideoContent) session.getContent();\n            mRichCallLog.addVideoSharing(sharingId, contact, Direction.OUTGOING, content,\n                    VideoSharing.State.INITIATING, ReasonCode.UNSPECIFIED, timestamp);\n\n            VideoSharingPersistedStorageAccessor persistedStorage = new VideoSharingPersistedStorageAccessor(\n                    sharingId, contact, Direction.OUTGOING, mRichCallLog, content.getEncoding(),\n                    content.getHeight(), content.getWidth(), timestamp);\n            final VideoSharingImpl videoSharing = new VideoSharingImpl(sharingId, mRichcallService,\n                    mBroadcaster, persistedStorage, this);\n\n            final VideoSharingServiceImpl videoSharingService = this;\n            mRichcallService.scheduleImageShareOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        session.addListener(videoSharing);\n                        videoSharingService.addVideoSharing(videoSharing, sharingId);\n                        session.startSession();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"Failed initiate video sharing right now!\", e);\n                    }\n                }\n            });\n            return videoSharing;\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current video sharing from its unique ID\n     * \n     * @param sharingId Sharing ID\n     * @return Video sharing\n     * @throws RemoteException\n     */\n    public IVideoSharing getVideoSharing(String sharingId) throws RemoteException {\n        if (TextUtils.isEmpty(sharingId)) {\n            throw new ServerApiIllegalArgumentException(\"sharingId must not be null or empty!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Get video sharing \".concat(sharingId));\n        }\n        try {\n            IVideoSharing videoSharing = mVideoSharingCache.get(sharingId);\n            if (videoSharing != null) {\n                return videoSharing;\n            }\n            VideoSharingPersistedStorageAccessor persistedStorage = new VideoSharingPersistedStorageAccessor(\n                    sharingId, mRichCallLog);\n            return new VideoSharingImpl(sharingId, mRichcallService, mBroadcaster,\n                    persistedStorage, this);\n\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Add and broadcast video sharing invitation rejections\n     * \n     * @param contact Contact ID\n     * @param content Video content\n     * @param reasonCode Reason code\n     * @param timestamp Local timestamp when got invitation\n     */\n    public void addVideoSharingInvitationRejected(ContactId contact, VideoContent content,\n            ReasonCode reasonCode, long timestamp) {\n        String sessionId = SessionIdGenerator.getNewId();\n        mRichCallLog.addVideoSharing(sessionId, contact, Direction.INCOMING, content,\n                VideoSharing.State.REJECTED, reasonCode, timestamp);\n        mBroadcaster.broadcastInvitation(sessionId);\n    }\n\n    /**\n     * Adds a listener on video sharing events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    public void addEventListener2(IVideoSharingListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Add a video sharing event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mBroadcaster.addEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener from video sharing events\n     * \n     * @param listener Listener\n     * @throws RemoteException\n     */\n    public void removeEventListener2(IVideoSharingListener listener) throws RemoteException {\n        if (listener == null) {\n            throw new ServerApiIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (sLogger.isActivated()) {\n            sLogger.info(\"Remove a video sharing event listener\");\n        }\n        try {\n            synchronized (mLock) {\n                mBroadcaster.removeEventListener(listener);\n            }\n        } catch (ServerApiBaseException e) {\n            if (!e.shouldNotBeLogged()) {\n                sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            }\n            throw e;\n\n        } catch (Exception e) {\n            sLogger.error(ExceptionUtil.getFullStackTrace(e));\n            throw new ServerApiGenericException(e);\n        }\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return Version\n     * @see VERSION_CODES\n     */\n    public int getServiceVersion() {\n        return RcsService.Build.API_VERSION;\n    }\n\n    /**\n     * Returns the common service configuration\n     * \n     * @return the common service configuration\n     */\n    public ICommonServiceConfiguration getCommonConfiguration() {\n        return new CommonServiceConfigurationImpl(mRcsSettings);\n    }\n\n    /**\n     * Deletes all video sharing from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RemoteException\n     */\n    public void deleteVideoSharings() throws RemoteException {\n        mRichcallService.tryToDeleteVideoSharings();\n    }\n\n    /**\n     * Delete video sharing associated with a given contact from history and abort/reject any\n     * associated ongoing session if such exists.\n     * \n     * @param contact contact\n     * @throws RemoteException\n     */\n    public void deleteVideoSharings2(ContactId contact) throws RemoteException {\n        if (contact == null) {\n            throw new ServerApiIllegalArgumentException(\"contact must not be null!\");\n        }\n        mRichcallService.tryToDeleteVideoSharings(contact);\n    }\n\n    /**\n     * Deletes a video sharing by its sharing ID from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId Sharing ID\n     * @throws RemoteException\n     */\n    public void deleteVideoSharing(String sharingId) throws RemoteException {\n        if (TextUtils.isEmpty(sharingId)) {\n            throw new ServerApiIllegalArgumentException(\"sharingId must not be null or empty!\");\n        }\n        mRichcallService.tryToDeleteVideoSharing(sharingId);\n    }\n\n    public void broadcastDeleted(ContactId contact, Set<String> sharingIds) {\n        mBroadcaster.broadcastDeleted(contact, sharingIds);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/CapabilitiesBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.capability.ICapabilitiesListener;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.HashMap;\n\n/**\n * CapabilitiesBroadcaster maintains the registering and unregistering of ICapabilitiesListener and\n * also performs broadcast events on these listeners upon the trigger of corresponding callbacks.\n */\npublic class CapabilitiesBroadcaster {\n\n    private RemoteCallbackList<ICapabilitiesListener> mCapabilitiesListeners = new RemoteCallbackList<>();\n\n    private HashMap<ContactId, RemoteCallbackList<ICapabilitiesListener>> mCapalitiesListenersPerContact = new HashMap<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public CapabilitiesBroadcaster() {\n    }\n\n    private void broadcastCapabilitiesReceivedForAllContacts(ContactId contact,\n            Capabilities contactCapabilities) {\n        final int N = mCapabilitiesListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mCapabilitiesListeners.getBroadcastItem(i).onCapabilitiesReceived(contact,\n                        contactCapabilities);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mCapabilitiesListeners.finishBroadcast();\n    }\n\n    private void broadcastCapabilitiesReceivedOnPerContact(ContactId contact,\n            Capabilities contactCapabilities) {\n        RemoteCallbackList<ICapabilitiesListener> capabilitiesListeners = mCapalitiesListenersPerContact\n                .get(contact);\n        if (capabilitiesListeners == null) {\n            return;\n        }\n        final int N = capabilitiesListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                capabilitiesListeners.getBroadcastItem(i).onCapabilitiesReceived(contact,\n                        contactCapabilities);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        capabilitiesListeners.finishBroadcast();\n    }\n\n    public void addCapabilitiesListener(ICapabilitiesListener listener) {\n        mCapabilitiesListeners.register(listener);\n    }\n\n    public void removeCapabilitiesListener(ICapabilitiesListener listener) {\n        mCapabilitiesListeners.unregister(listener);\n    }\n\n    public void addContactCapabilitiesListener(ContactId contact, ICapabilitiesListener listener) {\n        RemoteCallbackList<ICapabilitiesListener> capabilitiesListeners = mCapalitiesListenersPerContact\n                .get(contact);\n        if (capabilitiesListeners == null) {\n            capabilitiesListeners = new RemoteCallbackList<>();\n            mCapalitiesListenersPerContact.put(contact, capabilitiesListeners);\n        }\n        capabilitiesListeners.register(listener);\n    }\n\n    public void removeContactCapabilitiesListener(ContactId contact, ICapabilitiesListener listener) {\n        RemoteCallbackList<ICapabilitiesListener> listeners = mCapalitiesListenersPerContact\n                .get(contact);\n        if (listeners != null) {\n            listeners.unregister(listener);\n        }\n    }\n\n    public void broadcastCapabilitiesReceived(ContactId contact, Capabilities contactCapabilities) {\n        // Notify capabilities listeners\n        broadcastCapabilitiesReceivedForAllContacts(contact, contactCapabilities);\n        // Notify capabilities listeners for a given contact\n        broadcastCapabilitiesReceivedOnPerContact(contact, contactCapabilities);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/FileUploadEventBroadcaster.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.upload.FileUpload.State;\nimport com.gsma.services.rcs.upload.FileUploadInfo;\nimport com.gsma.services.rcs.upload.IFileUploadListener;\n\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\n/**\n * FileUploadEventBroadcaster maintains the registering and unregistering of IFileUploadListener and\n * also performs broadcast events on these listeners upon the trigger of corresponding callbacks.\n */\npublic class FileUploadEventBroadcaster implements IFileUploadEventBroadcaster {\n\n    private final RemoteCallbackList<IFileUploadListener> mFileUploadListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public FileUploadEventBroadcaster() {\n    }\n\n    public void addEventListener(IFileUploadListener listener) {\n        mFileUploadListeners.register(listener);\n    }\n\n    public void removeEventListener(IFileUploadListener listener) {\n        mFileUploadListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastStateChanged(String uploadId, State state) {\n        int rcsState = state.toInt();\n        final int N = mFileUploadListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mFileUploadListeners.getBroadcastItem(i).onStateChanged(uploadId, rcsState);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mFileUploadListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastProgressUpdate(String uploadId, long currentSize, long totalSize) {\n        final int N = mFileUploadListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mFileUploadListeners.getBroadcastItem(i).onProgressUpdate(uploadId, currentSize,\n                        totalSize);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mFileUploadListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastUploaded(String uploadId, FileUploadInfo info) {\n        final int N = mFileUploadListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mFileUploadListeners.getBroadcastItem(i).onUploaded(uploadId, info);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mFileUploadListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/GeolocSharingEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingIntent;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharingListener;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * GeolocSharingEventBroadcaster maintains the registering and unregistering of\n * IGeolocSharingListener and also performs broadcast events on these listeners upon the trigger of\n * corresponding callbacks.\n */\npublic class GeolocSharingEventBroadcaster implements IGeolocSharingEventBroadcaster {\n\n    private final RemoteCallbackList<IGeolocSharingListener> mGeolocSharingListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public GeolocSharingEventBroadcaster() {\n    }\n\n    public void addEventListener(IGeolocSharingListener listener) {\n        mGeolocSharingListeners.register(listener);\n    }\n\n    public void removeEventListener(IGeolocSharingListener listener) {\n        mGeolocSharingListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode) {\n        final int N = mGeolocSharingListeners.beginBroadcast();\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGeolocSharingListeners.getBroadcastItem(i).onStateChanged(contact, sharingId,\n                        rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGeolocSharingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize) {\n        final int N = mGeolocSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGeolocSharingListeners.getBroadcastItem(i).onProgressUpdate(contact, sharingId,\n                        currentSize, totalSize);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGeolocSharingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String sharingId) {\n        Intent invitation = new Intent(GeolocSharingIntent.ACTION_NEW_INVITATION);\n        invitation.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(invitation);\n        invitation.putExtra(GeolocSharingIntent.EXTRA_SHARING_ID, sharingId);\n        AndroidFactory.getApplicationContext().sendBroadcast(invitation);\n    }\n\n    @Override\n    public void broadcastDeleted(ContactId contact, Set<String> sharingIds) {\n        List<String> ids = new ArrayList<>(sharingIds);\n        final int N = mGeolocSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGeolocSharingListeners.getBroadcastItem(i).onDeleted(contact, ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGeolocSharingListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/GroupChatEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.chat.GroupChatIntent;\nimport com.gsma.services.rcs.chat.IGroupChatListener;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * GroupChatEventBroadcaster maintains the registering and unregistering of IGroupChatListener and\n * also performs broadcast events on these listeners upon the trigger of corresponding callbacks.\n */\npublic class GroupChatEventBroadcaster implements IGroupChatEventBroadcaster {\n\n    private final RemoteCallbackList<IGroupChatListener> mGroupChatListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public GroupChatEventBroadcaster() {\n    }\n\n    public void addGroupChatEventListener(IGroupChatListener listener) {\n        mGroupChatListeners.register(listener);\n    }\n\n    public void removeGroupChatEventListener(IGroupChatListener listener) {\n        mGroupChatListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastMessageStatusChanged(String chatId, String mimeType, String msgId,\n            Status status, Content.ReasonCode reasonCode) {\n        int rcsStatus = status.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        final int N = mGroupChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onMessageStatusChanged(chatId, mimeType,\n                        msgId, rcsStatus, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener.\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastMessageGroupDeliveryInfoChanged(String chatId, ContactId contact,\n            String apiMimeType, String msgId, GroupDeliveryInfo.Status status,\n            GroupDeliveryInfo.ReasonCode reasonCode) {\n        final int N = mGroupChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onMessageGroupDeliveryInfoChanged(chatId,\n                        contact, apiMimeType, msgId, status.toInt(), reasonCode.toInt());\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener.\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastParticipantStatusChanged(String chatId, ContactId contact,\n            ParticipantStatus status) {\n        final int N = mGroupChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onParticipantStatusChanged(chatId, contact,\n                        status.toInt());\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastStateChanged(String chatId, State state, ReasonCode reasonCode) {\n        final int N = mGroupChatListeners.beginBroadcast();\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onStateChanged(chatId, rcsState,\n                        rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastComposingEvent(String chatId, ContactId contact, boolean status) {\n        final int N = mGroupChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onComposingEvent(chatId, contact, status);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String chatId) {\n        Intent invitation = new Intent(GroupChatIntent.ACTION_NEW_INVITATION);\n        invitation.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(invitation);\n        invitation.putExtra(GroupChatIntent.EXTRA_CHAT_ID, chatId);\n        AndroidFactory.getApplicationContext().sendBroadcast(invitation);\n    }\n\n    @Override\n    public void broadcastMessageReceived(String apiMimeType, String msgId) {\n        Intent newGroupChatMessage = new Intent(GroupChatIntent.ACTION_NEW_GROUP_CHAT_MESSAGE);\n        newGroupChatMessage.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(newGroupChatMessage);\n        newGroupChatMessage.putExtra(GroupChatIntent.EXTRA_MIME_TYPE, apiMimeType);\n        newGroupChatMessage.putExtra(GroupChatIntent.EXTRA_MESSAGE_ID, msgId);\n        AndroidFactory.getApplicationContext().sendBroadcast(newGroupChatMessage);\n    }\n\n    @Override\n    public void broadcastMessagesDeleted(String chatId, Set<String> msgIds) {\n        List<String> msgIds2 = new ArrayList<>(msgIds);\n        final int N = mGroupChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onMessagesDeleted(chatId, msgIds2);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener.\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastGroupChatsDeleted(Set<String> chatIds) {\n        List<String> ids = new ArrayList<>(chatIds);\n        final int N = mGroupChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupChatListeners.getBroadcastItem(i).onDeleted(ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener.\", e);\n                }\n            }\n        }\n        mGroupChatListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/GroupFileTransferBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.IGroupFileTransferListener;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * GroupFileTransferBroadcaster maintains the registering and unregistering of\n * IGroupFileTransferListener and also performs broadcast events on these listeners upon the trigger\n * of corresponding callbacks.\n */\npublic class GroupFileTransferBroadcaster implements IGroupFileTransferBroadcaster {\n\n    private final RemoteCallbackList<IGroupFileTransferListener> mGroupFileTransferListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public GroupFileTransferBroadcaster() {\n    }\n\n    public void addGroupFileTransferListener(IGroupFileTransferListener listener) {\n        mGroupFileTransferListeners.register(listener);\n    }\n\n    public void removeGroupFileTransferListener(IGroupFileTransferListener listener) {\n        mGroupFileTransferListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastStateChanged(String chatId, String transferId, State state,\n            ReasonCode reasonCode) {\n        final int N = mGroupFileTransferListeners.beginBroadcast();\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupFileTransferListeners.getBroadcastItem(i).onStateChanged(chatId, transferId,\n                        rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGroupFileTransferListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastProgressUpdate(String chatId, String transferId, long currentSize,\n            long totalSize) {\n        final int N = mGroupFileTransferListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupFileTransferListeners.getBroadcastItem(i).onProgressUpdate(chatId,\n                        transferId, currentSize, totalSize);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mGroupFileTransferListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n            GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode) {\n        int rcsStatus = status.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        final int N = mGroupFileTransferListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupFileTransferListeners.getBroadcastItem(i).onDeliveryInfoChanged(chatId,\n                        contact, transferId, rcsStatus, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener per contact\", e);\n                }\n            }\n        }\n        mGroupFileTransferListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String fileTransferId) {\n        Intent invitation = new Intent(FileTransferIntent.ACTION_NEW_INVITATION);\n        invitation.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(invitation);\n        invitation.putExtra(FileTransferIntent.EXTRA_TRANSFER_ID, fileTransferId);\n        AndroidFactory.getApplicationContext().sendBroadcast(invitation);\n    }\n\n    @Override\n    public void broadcastFileTransfersDeleted(String chatId, Set<String> transferIds) {\n        List<String> ids = new ArrayList<>(transferIds);\n        final int N = mGroupFileTransferListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mGroupFileTransferListeners.getBroadcastItem(i).onDeleted(chatId, ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener per contact\", e);\n                }\n            }\n        }\n        mGroupFileTransferListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IFileUploadEventBroadcaster.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.upload.FileUpload.State;\nimport com.gsma.services.rcs.upload.FileUploadInfo;\n\n/**\n * Interface to perform broadcast events on FileUploadListeners\n */\npublic interface IFileUploadEventBroadcaster {\n\n    void broadcastStateChanged(String uploadId, State state);\n\n    void broadcastProgressUpdate(String uploadId, long currentSize, long totalSize);\n\n    void broadcastUploaded(String uploadId, FileUploadInfo info);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IGeolocSharingEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on GeolocSharingListeners\n */\npublic interface IGeolocSharingEventBroadcaster {\n\n    void broadcastStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode);\n\n    void broadcastProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize);\n\n    void broadcastInvitation(String sharingId);\n\n    void broadcastDeleted(ContactId contact, Set<String> sharingIds);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IGroupChatEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on GroupChatListener\n */\npublic interface IGroupChatEventBroadcaster {\n\n    void broadcastMessageStatusChanged(String chatId, String mimeType, String msgId, Status status,\n            ReasonCode reasonCode);\n\n    void broadcastMessageGroupDeliveryInfoChanged(String chatId, ContactId contact,\n            String mimeType, String msgId, GroupDeliveryInfo.Status status,\n            GroupDeliveryInfo.ReasonCode reasonCode);\n\n    void broadcastParticipantStatusChanged(String chatId, ContactId contact,\n            ParticipantStatus status);\n\n    void broadcastStateChanged(String chatId, State state, GroupChat.ReasonCode reasonCode);\n\n    void broadcastComposingEvent(String chatId, ContactId contact, boolean status);\n\n    void broadcastInvitation(String chatId);\n\n    void broadcastMessageReceived(String mimeType, String msgId);\n\n    void broadcastMessagesDeleted(String chatId, Set<String> msgIds);\n\n    void broadcastGroupChatsDeleted(Set<String> chatIds);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IGroupFileTransferBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on GroupFileTransferListeners\n */\npublic interface IGroupFileTransferBroadcaster {\n\n    void broadcastStateChanged(String chatId, String transferId, State status, ReasonCode reasonCode);\n\n    void broadcastProgressUpdate(String chatId, String transferId, long currentSize, long totalSize);\n\n    void broadcastDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n            GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode);\n\n    void broadcastInvitation(String fileTransferId);\n\n    void broadcastFileTransfersDeleted(String chatId, Set<String> transferIds);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IImageSharingEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on ImageSharingListeners\n */\npublic interface IImageSharingEventBroadcaster {\n\n    void broadcastStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode);\n\n    void broadcastProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize);\n\n    void broadcastInvitation(String sharingId);\n\n    void broadcastDeleted(ContactId contact, Set<String> sharingIds);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IMultimediaMessagingSessionEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\n\n/**\n * Interface to perform broadcast events on MultimediaMessagingSessionListeners\n */\npublic interface IMultimediaMessagingSessionEventBroadcaster {\n\n    void broadcastMessageReceived(ContactId contact, String sessionId, byte[] message,\n            String contentType);\n\n    void broadcastStateChanged(ContactId contact, String sessionId, State state,\n            ReasonCode reasonCode);\n\n    void broadcastInvitation(String sessionId, Intent msrpSessionInvite);\n\n    void broadcastMessagesFlushed(ContactId contact, String sessionId);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IMultimediaStreamingSessionEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\n\n/**\n * Interface to perform broadcast events on MultimediaStreamingSessionListeners\n */\npublic interface IMultimediaStreamingSessionEventBroadcaster {\n\n    void broadcastPayloadReceived(ContactId contact, String sessionId, byte[] content);\n\n    void broadcastStateChanged(ContactId contact, String sessionId, State state,\n            ReasonCode reasonCode);\n\n    void broadcastInvitation(String sessionId, Intent rtpSessionInvite);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IOneToOneChatEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on ChatListeners\n */\npublic interface IOneToOneChatEventBroadcaster {\n\n    void broadcastMessageStatusChanged(ContactId contact, String mimeType, String msgId,\n            Status status, ReasonCode reasonCode);\n\n    void broadcastComposingEvent(ContactId contact, boolean status);\n\n    void broadcastMessageReceived(String mimeType, String msgId);\n\n    void broadcastMessagesDeleted(ContactId contact, Set<String> msgIds);\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IOneToOneFileTransferBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on FileTransferListeners\n */\npublic interface IOneToOneFileTransferBroadcaster {\n\n    void broadcastStateChanged(ContactId contact, String transferId, State status,\n            ReasonCode reasonCode);\n\n    void broadcastProgressUpdate(ContactId contact, String transferId, long currentSize,\n            long totalSize);\n\n    void broadcastInvitation(String fileTransferId);\n\n    void broadcastFileTransferDeleted(ContactId contact, Set<String> filetransferIds);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IRcsServiceRegistrationEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.RcsServiceRegistration.ReasonCode;\n\n/**\n * Interface to perform broadcast events on RcsServiceRegistrationListeners\n */\npublic interface IRcsServiceRegistrationEventBroadcaster {\n\n    void broadcastServiceRegistered();\n\n    void broadcastServiceUnRegistered(ReasonCode reasonCode);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/IVideoSharingEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport java.util.Set;\n\n/**\n * Interface to perform broadcast events on VideoSharingListeners\n */\npublic interface IVideoSharingEventBroadcaster {\n\n    void broadcastStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode);\n\n    void broadcastInvitation(String sharingId);\n\n    void broadcastDeleted(ContactId contact, Set<String> sharingIds);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/ImageSharingEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.IImageSharingListener;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\nimport com.gsma.services.rcs.sharing.image.ImageSharingIntent;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * ImageSharingEventBroadcaster maintains the registering and unregistering of IImageSharingListener\n * and also performs broadcast events on these listeners upon the trigger of corresponding\n * callbacks.\n */\npublic class ImageSharingEventBroadcaster implements IImageSharingEventBroadcaster {\n\n    private final RemoteCallbackList<IImageSharingListener> mImageSharingListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public ImageSharingEventBroadcaster() {\n    }\n\n    public void addEventListener(IImageSharingListener listener) {\n        mImageSharingListeners.register(listener);\n    }\n\n    public void removeEventListener(IImageSharingListener listener) {\n        mImageSharingListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode) {\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        final int N = mImageSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mImageSharingListeners.getBroadcastItem(i).onStateChanged(contact, sharingId,\n                        rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mImageSharingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize) {\n        final int N = mImageSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mImageSharingListeners.getBroadcastItem(i).onProgressUpdate(contact, sharingId,\n                        currentSize, totalSize);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mImageSharingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String sharingId) {\n        Intent invitation = new Intent(ImageSharingIntent.ACTION_NEW_INVITATION);\n        invitation.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(invitation);\n        invitation.putExtra(ImageSharingIntent.EXTRA_SHARING_ID, sharingId);\n        AndroidFactory.getApplicationContext().sendBroadcast(invitation);\n    }\n\n    @Override\n    public void broadcastDeleted(ContactId contact, Set<String> sharingIds) {\n        List<String> ids = new ArrayList<>(sharingIds);\n        final int N = mImageSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mImageSharingListeners.getBroadcastItem(i).onDeleted(contact, ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mImageSharingListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/MultimediaMessagingSessionEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.IMultimediaMessagingSessionListener;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSessionIntent;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\n/**\n * MultimediaMessagingSessionEventBroadcaster maintains the registering and unregistering of\n * IMultimediaMessagingSessionListener and also performs broadcast events on these listeners upon\n * the trigger of corresponding callbacks.\n */\npublic class MultimediaMessagingSessionEventBroadcaster implements\n        IMultimediaMessagingSessionEventBroadcaster {\n\n    private final RemoteCallbackList<IMultimediaMessagingSessionListener> mMultimediaMessagingListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public MultimediaMessagingSessionEventBroadcaster() {\n    }\n\n    public void addMultimediaMessagingEventListener(IMultimediaMessagingSessionListener listener) {\n        mMultimediaMessagingListeners.register(listener);\n    }\n\n    public void removeMultimediaMessagingEventListener(IMultimediaMessagingSessionListener listener) {\n        mMultimediaMessagingListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastMessageReceived(ContactId contact, String sessionId, byte[] message, String contentType) {\n        final int N = mMultimediaMessagingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mMultimediaMessagingListeners.getBroadcastItem(i).onMessageReceived(contact,\n                        sessionId, message);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n            try {\n                mMultimediaMessagingListeners.getBroadcastItem(i).onMessageReceived2(contact,\n                        sessionId, message, contentType);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mMultimediaMessagingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastStateChanged(ContactId contact, String sessionId, State state,\n            ReasonCode reasonCode) {\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        final int N = mMultimediaMessagingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mMultimediaMessagingListeners.getBroadcastItem(i).onStateChanged(contact,\n                        sessionId, rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mMultimediaMessagingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String sessionId, Intent msrpSessionInvite) {\n        msrpSessionInvite.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(msrpSessionInvite);\n        msrpSessionInvite.putExtra(MultimediaMessagingSessionIntent.EXTRA_SESSION_ID, sessionId);\n\n        AndroidFactory.getApplicationContext().sendBroadcast(msrpSessionInvite);\n    }\n\n    @Override\n    public void broadcastMessagesFlushed(ContactId contact, String sessionId) {\n        final int N = mMultimediaMessagingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mMultimediaMessagingListeners.getBroadcastItem(i).onMessagesFlushed(contact, sessionId);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mMultimediaMessagingListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/MultimediaStreamingSessionEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.IMultimediaStreamingSessionListener;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSessionIntent;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\n/**\n * MultimediaStreamingSessionEventBroadcaster maintains the registering and unregistering of\n * IMultimediaStreamingSessionListener and also performs broadcast events on these listeners upon\n * the trigger of corresponding callbacks.\n */\npublic class MultimediaStreamingSessionEventBroadcaster implements\n        IMultimediaStreamingSessionEventBroadcaster {\n\n    private final RemoteCallbackList<IMultimediaStreamingSessionListener> mMultimediaStreamingListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public MultimediaStreamingSessionEventBroadcaster() {\n    }\n\n    public void addMultimediaStreamingEventListener(IMultimediaStreamingSessionListener listener) {\n        mMultimediaStreamingListeners.register(listener);\n    }\n\n    public void removeMultimediaStreamingEventListener(IMultimediaStreamingSessionListener listener) {\n        mMultimediaStreamingListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastPayloadReceived(ContactId contact, String sessionId, byte[] content) {\n        final int N = mMultimediaStreamingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mMultimediaStreamingListeners.getBroadcastItem(i).onPayloadReceived(contact,\n                        sessionId, content);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mMultimediaStreamingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastStateChanged(ContactId contact, String sessionId, State state,\n            ReasonCode reasonCode) {\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        final int N = mMultimediaStreamingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mMultimediaStreamingListeners.getBroadcastItem(i).onStateChanged(contact,\n                        sessionId, rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mMultimediaStreamingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String sessionId, Intent rtpSessionInvite) {\n        rtpSessionInvite.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(rtpSessionInvite);\n        rtpSessionInvite.putExtra(MultimediaMessagingSessionIntent.EXTRA_SESSION_ID, sessionId);\n\n        AndroidFactory.getApplicationContext().sendBroadcast(rtpSessionInvite);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/OneToOneChatEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.IOneToOneChatListener;\nimport com.gsma.services.rcs.chat.OneToOneChatIntent;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * OneToOneChatEventBroadcaster maintains the registering and unregistering of\n * IOneToOneChatListeners and also performs broadcast events on these listeners upon the trigger of\n * corresponding callbacks.\n */\npublic class OneToOneChatEventBroadcaster implements IOneToOneChatEventBroadcaster {\n\n    private final RemoteCallbackList<IOneToOneChatListener> mOneToOneChatListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public OneToOneChatEventBroadcaster() {\n    }\n\n    public void addOneToOneChatEventListener(IOneToOneChatListener listener) {\n        mOneToOneChatListeners.register(listener);\n    }\n\n    public void removeOneToOneChatEventListener(IOneToOneChatListener listener) {\n        mOneToOneChatListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastMessageStatusChanged(ContactId contact, String mimeType, String msgId,\n            Status status, ReasonCode reasonCode) {\n        final int N = mOneToOneChatListeners.beginBroadcast();\n        int rcsStatus = status.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        for (int i = 0; i < N; i++) {\n            try {\n                mOneToOneChatListeners.getBroadcastItem(i).onMessageStatusChanged(contact,\n                        mimeType, msgId, rcsStatus, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener.\", e);\n                }\n            }\n        }\n        mOneToOneChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastComposingEvent(ContactId contact, boolean status) {\n        final int N = mOneToOneChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mOneToOneChatListeners.getBroadcastItem(i).onComposingEvent(contact, status);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mOneToOneChatListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastMessageReceived(String mimeType, String msgId) {\n        Intent newOneToOneMessage = new Intent(\n                OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE);\n        newOneToOneMessage.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(newOneToOneMessage);\n        newOneToOneMessage.putExtra(OneToOneChatIntent.EXTRA_MIME_TYPE, mimeType);\n        newOneToOneMessage.putExtra(OneToOneChatIntent.EXTRA_MESSAGE_ID, msgId);\n        AndroidFactory.getApplicationContext().sendBroadcast(newOneToOneMessage);\n    }\n\n    @Override\n    public void broadcastMessagesDeleted(ContactId contact, Set<String> msgIds) {\n        List<String> ids = new ArrayList<>(msgIds);\n        final int N = mOneToOneChatListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mOneToOneChatListeners.getBroadcastItem(i).onMessagesDeleted(contact, ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener.\", e);\n                }\n            }\n        }\n        mOneToOneChatListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/OneToOneFileTransferBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.filetransfer.FileTransferIntent;\nimport com.gsma.services.rcs.filetransfer.IOneToOneFileTransferListener;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * OneToOneFileTransferBroadcaster maintains the registering and unregistering of\n * IFileTransferListener and also performs broadcast events on these listeners upon the trigger of\n * corresponding callbacks.\n */\npublic class OneToOneFileTransferBroadcaster implements IOneToOneFileTransferBroadcaster {\n\n    private final RemoteCallbackList<IOneToOneFileTransferListener> mOneToOneFileTransferListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public OneToOneFileTransferBroadcaster() {\n    }\n\n    public void addOneToOneFileTransferListener(IOneToOneFileTransferListener listener) {\n        mOneToOneFileTransferListeners.register(listener);\n    }\n\n    public void removeOneToOneFileTransferListener(IOneToOneFileTransferListener listener) {\n        mOneToOneFileTransferListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastStateChanged(ContactId contact, String transferId, State state,\n            ReasonCode reasonCode) {\n        final int N = mOneToOneFileTransferListeners.beginBroadcast();\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        for (int i = 0; i < N; i++) {\n            try {\n                mOneToOneFileTransferListeners.getBroadcastItem(i).onStateChanged(contact,\n                        transferId, rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mOneToOneFileTransferListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastProgressUpdate(ContactId contact, String transferId, long currentSize,\n            long totalSize) {\n        final int N = mOneToOneFileTransferListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mOneToOneFileTransferListeners.getBroadcastItem(i).onProgressUpdate(contact,\n                        transferId, currentSize, totalSize);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mOneToOneFileTransferListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String fileTransferId) {\n        Intent invitation = new Intent(FileTransferIntent.ACTION_NEW_INVITATION);\n        invitation.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(invitation);\n        invitation.putExtra(FileTransferIntent.EXTRA_TRANSFER_ID, fileTransferId);\n        AndroidFactory.getApplicationContext().sendBroadcast(invitation);\n    }\n\n\n    @Override\n    public void broadcastFileTransferDeleted(ContactId contact, Set<String> filetransferIds) {\n        List<String> ids = new ArrayList<>(filetransferIds);\n        final int N = mOneToOneFileTransferListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mOneToOneFileTransferListeners.getBroadcastItem(i).onDeleted(contact, ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mOneToOneFileTransferListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/RcsServiceRegistrationEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * RcsServiceRegistrationEventBroadcaster maintains the registering and unregistering of\n * IRcsServiceRegistrationListener and also performs broadcast events on these listeners upon the\n * trigger of corresponding callbacks.\n */\npublic class RcsServiceRegistrationEventBroadcaster implements\n        IRcsServiceRegistrationEventBroadcaster {\n\n    private final RemoteCallbackList<IRcsServiceRegistrationListener> mServiceRegistrationListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public RcsServiceRegistrationEventBroadcaster() {\n    }\n\n    public void addEventListener(IRcsServiceRegistrationListener listener) {\n        mServiceRegistrationListeners.register(listener);\n    }\n\n    public void removeEventListener(IRcsServiceRegistrationListener listener) {\n        mServiceRegistrationListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastServiceRegistered() {\n        final int N = mServiceRegistrationListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mServiceRegistrationListeners.getBroadcastItem(i).onServiceRegistered();\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mServiceRegistrationListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastServiceUnRegistered(RcsServiceRegistration.ReasonCode reason) {\n        final int N = mServiceRegistrationListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mServiceRegistrationListeners.getBroadcastItem(i).onServiceUnregistered(\n                        reason.toInt());\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mServiceRegistrationListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/broadcaster/VideoSharingEventBroadcaster.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.service.broadcaster;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.IntentUtils;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingListener;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\nimport com.gsma.services.rcs.sharing.video.VideoSharingIntent;\n\nimport android.content.Intent;\nimport android.os.RemoteCallbackList;\nimport android.os.RemoteException;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * VideoSharingEventBroadcaster maintains the registering and unregistering of IVideoSharingListener\n * and also performs broadcast events on these listeners upon the trigger of corresponding\n * callbacks.\n */\npublic class VideoSharingEventBroadcaster implements IVideoSharingEventBroadcaster {\n\n    private final RemoteCallbackList<IVideoSharingListener> mVideoSharingListeners = new RemoteCallbackList<>();\n\n    private final Logger logger = Logger.getLogger(getClass().getName());\n\n    public VideoSharingEventBroadcaster() {\n    }\n\n    public void addEventListener(IVideoSharingListener listener) {\n        mVideoSharingListeners.register(listener);\n    }\n\n    public void removeEventListener(IVideoSharingListener listener) {\n        mVideoSharingListeners.unregister(listener);\n    }\n\n    @Override\n    public void broadcastStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode) {\n        int rcsState = state.toInt();\n        int rcsReasonCode = reasonCode.toInt();\n        final int N = mVideoSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mVideoSharingListeners.getBroadcastItem(i).onStateChanged(contact, sharingId,\n                        rcsState, rcsReasonCode);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mVideoSharingListeners.finishBroadcast();\n    }\n\n    @Override\n    public void broadcastInvitation(String sharingId) {\n        Intent newInvitation = new Intent(VideoSharingIntent.ACTION_NEW_INVITATION);\n        newInvitation.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        IntentUtils.tryToSetReceiverForegroundFlag(newInvitation);\n        newInvitation.putExtra(VideoSharingIntent.EXTRA_SHARING_ID, sharingId);\n        AndroidFactory.getApplicationContext().sendBroadcast(newInvitation);\n    }\n\n    @Override\n    public void broadcastDeleted(ContactId contact, Set<String> sharingIds) {\n        List<String> ids = new ArrayList<>(sharingIds);\n        final int N = mVideoSharingListeners.beginBroadcast();\n        for (int i = 0; i < N; i++) {\n            try {\n                mVideoSharingListeners.getBroadcastItem(i).onDeleted(contact, ids);\n            } catch (RemoteException e) {\n                if (logger.isActivated()) {\n                    logger.error(\"Can't notify listener\", e);\n                }\n            }\n        }\n        mVideoSharingListeners.finishBroadcast();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/permissions/PermissionsAlertDialog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.rcs.service.permissions;\n\nimport com.gsma.rcs.R;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.support.annotation.NonNull;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class PermissionsAlertDialog extends Activity {\n\n    /**\n     * List of permissions needed for service Just need to ask one permission per dangerous group\n     */\n    private static final Set<String> sAllPermissionsList = new HashSet<>(Arrays.asList(\n            Manifest.permission.READ_CONTACTS, Manifest.permission.READ_SMS,\n            Manifest.permission.CAMERA, Manifest.permission.CALL_PHONE,\n            Manifest.permission.WRITE_EXTERNAL_STORAGE));\n\n    private static final int MY_PERMISSION_REQUEST_ALL = 5428;\n    private Set<String> mPermissionsToAsk;\n\n    private static final Logger sLogger = Logger.getLogger(PermissionsAlertDialog.class\n            .getSimpleName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_permissions_alert_dialog);\n        askPermissions();\n    }\n\n    /**\n     * Main function to ask permissions\n     */\n    public void askPermissions() {\n        mPermissionsToAsk = getNotGrantedPermissions();\n        if (mPermissionsToAsk.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            requestPermissions(mPermissionsToAsk.toArray(new String[mPermissionsToAsk.size()]),\n                    MY_PERMISSION_REQUEST_ALL);\n        } else {\n            sendResponse(true);\n        }\n    }\n\n    /**\n     * Check all permissions's status\n     *\n     * @return Set of permissions that are not granted\n     */\n    private Set<String> getNotGrantedPermissions() {\n        Set<String> permissionsToAsk = new HashSet<>();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            for (String permission : PermissionsAlertDialog.sAllPermissionsList) {\n                if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(permission)) {\n                    permissionsToAsk.add(permission);\n                }\n            }\n        }\n        return permissionsToAsk;\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,\n            @NonNull int[] grantResults) {\n        switch (requestCode) {\n            case MY_PERMISSION_REQUEST_ALL:\n                Set<String> grantedPermissions = new HashSet<>();\n                for (int i = 0; i < permissions.length; i++) {\n                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {\n                        grantedPermissions.add(permissions[i]);\n\n                    } else {\n                        if (sLogger.isActivated()) {\n                            sLogger.warn(\"Permission Denied: \" + permissions[i]);\n                        }\n                    }\n                }\n                sendResponse(grantedPermissions.equals(mPermissionsToAsk));\n                break;\n        }\n    }\n\n    public void sendResponse(boolean allPermissionGranted) {\n        PermissionsManager.getInstance().responseReceived(allPermissionGranted);\n        finish();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/service/permissions/PermissionsManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.rcs.service.permissions;\n\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * Author Romain Caron (Orange)\n */\npublic class PermissionsManager {\n\n    /**\n     * Need for asking permissions\n     */\n    private static volatile PermissionsManager sInstance;\n    private boolean mHasPermissions = false;\n\n    /**\n     * Private constructor to avoid creating object in external class\n     */\n    private PermissionsManager() {\n    }\n\n    /**\n     * Returns the Instance of StartService\n     *\n     * @return Instance of StartService\n     */\n    public static PermissionsManager getInstance() {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (PermissionsManager.class) {\n            if (sInstance == null) {\n                sInstance = new PermissionsManager();\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Display the Permissions popup\n     *\n     * @param context to start the Intent\n     * @return boolean, true if all permissions are granted, false if not\n     */\n    public boolean requestForPermissionsAndWaitResponse(Context context) {\n        Intent intent = new Intent(context, PermissionsAlertDialog.class);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(intent);\n        try {\n            synchronized (sInstance) {\n                super.wait();\n            }\n        } catch (InterruptedException e) {\n            // nothing to do\n        }\n        return mHasPermissions;\n    }\n\n    /**\n     * Callback of the Permissions\n     *\n     * @param hasPermissions boolean, true if all permissions are granted, false if not\n     */\n    public void responseReceived(boolean hasPermissions) {\n        synchronized (sInstance) {\n            mHasPermissions = hasPermissions;\n            super.notify();\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/Base64.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\n/**\n * Provides Base64 encoding and decoding as defined by RFC 2045.\n * <p>\n * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045\n * <cite>Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message\n * Bodies</cite> by Freed and Borenstein.\n * </p>\n * \n * @see <a href=\"http://www.ietf.org/rfc/rfc2045.txt\">RFC 2045</a>\n * @author Apache Software Foundation\n * @since 1.0-dev\n * @version $Id: Base64.java,v 1.20 2004/05/24 00:21:24 ggregory Exp $\n */\npublic class Base64 {\n\n    /**\n     * Chunk size per RFC 2045 section 6.8.\n     * <p>\n     * The {@value} character limit does not count the trailing CRLF, but counts all other\n     * characters, including any equal signs.\n     * </p>\n     * \n     * @see <a href=\"http://www.ietf.org/rfc/rfc2045.txt\">RFC 2045 section 6.8</a>\n     */\n    static final int CHUNK_SIZE = 76;\n\n    /**\n     * Chunk separator per RFC 2045 section 2.1.\n     * \n     * @see <a href=\"http://www.ietf.org/rfc/rfc2045.txt\">RFC 2045 section 2.1</a>\n     */\n    static final byte[] CHUNK_SEPARATOR = \"\\r\\n\".getBytes(UTF8);\n\n    /**\n     * The base length.\n     */\n    static final int BASELENGTH = 255;\n\n    /**\n     * Lookup length.\n     */\n    static final int LOOKUPLENGTH = 64;\n\n    /**\n     * Used to calculate the number of bits in a byte.\n     */\n    static final int EIGHTBIT = 8;\n\n    /**\n     * Used when encoding something which has fewer than 24 bits.\n     */\n    static final int SIXTEENBIT = 16;\n\n    /**\n     * Used to determine how many bits data contains.\n     */\n    static final int TWENTYFOURBITGROUP = 24;\n\n    /**\n     * Used to get the number of Quadruples.\n     */\n    static final int FOURBYTE = 4;\n\n    /**\n     * Used to test the sign of a byte.\n     */\n    static final int SIGN = -128;\n\n    /**\n     * Byte used to pad output.\n     */\n    static final byte PAD = (byte) '=';\n\n    // Create arrays to hold the base64 characters and a\n    // lookup for base64 chars\n    private static byte[] base64Alphabet = new byte[BASELENGTH];\n    private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];\n\n    // Populating the lookup and character arrays\n    static {\n        for (int i = 0; i < BASELENGTH; i++) {\n            base64Alphabet[i] = (byte) -1;\n        }\n        for (int i = 'Z'; i >= 'A'; i--) {\n            base64Alphabet[i] = (byte) (i - 'A');\n        }\n        for (int i = 'z'; i >= 'a'; i--) {\n            base64Alphabet[i] = (byte) (i - 'a' + 26);\n        }\n        for (int i = '9'; i >= '0'; i--) {\n            base64Alphabet[i] = (byte) (i - '0' + 52);\n        }\n\n        base64Alphabet['+'] = 62;\n        base64Alphabet['/'] = 63;\n\n        for (int i = 0; i <= 25; i++) {\n            lookUpBase64Alphabet[i] = (byte) ('A' + i);\n        }\n\n        for (int i = 26, j = 0; i <= 51; i++, j++) {\n            lookUpBase64Alphabet[i] = (byte) ('a' + j);\n        }\n\n        for (int i = 52, j = 0; i <= 61; i++, j++) {\n            lookUpBase64Alphabet[i] = (byte) ('0' + j);\n        }\n\n        lookUpBase64Alphabet[62] = (byte) '+';\n        lookUpBase64Alphabet[63] = (byte) '/';\n    }\n\n    private static boolean isBase64(byte octect) {\n        if (octect == PAD) {\n            return true;\n        } else if (base64Alphabet[octect] == -1) {\n            return false;\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * Encodes binary data using the base64 algorithm but does not chunk the output.\n     * \n     * @param binaryData binary data to encode\n     * @return Base64 characters\n     */\n    public static byte[] encodeBase64(byte[] binaryData) {\n        return encodeBase64(binaryData, false);\n    }\n\n    /**\n     * Encodes binary data using the base64 algorithm, optionally chunking the output into 76\n     * character blocks.\n     * \n     * @param binaryData Array containing binary data to encode.\n     * @param isChunked if isChunked is true this encoder will chunk the base64 output into 76\n     *            character blocks\n     * @return Base64-encoded data.\n     */\n    private static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {\n        int lengthDataBits = binaryData.length * EIGHTBIT;\n        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;\n        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;\n        byte encodedData[] = null;\n        int encodedDataLength = 0;\n        int nbrChunks = 0;\n\n        if (fewerThan24bits != 0) {\n            // data not divisible by 24 bit\n            encodedDataLength = (numberTriplets + 1) * 4;\n        } else {\n            // 16 or 8 bit\n            encodedDataLength = numberTriplets * 4;\n        }\n\n        // If the output is to be \"chunked\" into 76 character sections,\n        // for compliance with RFC 2045 MIME, then it is important to\n        // allow for extra length to account for the separator(s)\n        if (isChunked) {\n\n            nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math\n                    .ceil((float) encodedDataLength / CHUNK_SIZE));\n            encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;\n        }\n\n        encodedData = new byte[encodedDataLength];\n\n        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;\n\n        int encodedIndex = 0;\n        int dataIndex = 0;\n        int i = 0;\n        int nextSeparatorIndex = CHUNK_SIZE;\n        int chunksSoFar = 0;\n\n        // log.debug(\"number of triplets = \" + numberTriplets);\n        for (i = 0; i < numberTriplets; i++) {\n            dataIndex = i * 3;\n            b1 = binaryData[dataIndex];\n            b2 = binaryData[dataIndex + 1];\n            b3 = binaryData[dataIndex + 2];\n\n            // log.debug(\"b1= \" + b1 +\", b2= \" + b2 + \", b3= \" + b3);\n\n            l = (byte) (b2 & 0x0f);\n            k = (byte) (b1 & 0x03);\n\n            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);\n            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);\n            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);\n\n            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];\n            // log.debug( \"val2 = \" + val2 );\n            // log.debug( \"k4   = \" + (k<<4) );\n            // log.debug( \"vak  = \" + (val2 | (k<<4)) );\n            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)];\n            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2) | val3];\n            encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];\n\n            encodedIndex += 4;\n\n            // If we are chunking, let's put a chunk separator down.\n            if (isChunked) {\n                // this assumes that CHUNK_SIZE % 4 == 0\n                if (encodedIndex == nextSeparatorIndex) {\n                    System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedIndex,\n                            CHUNK_SEPARATOR.length);\n                    chunksSoFar++;\n                    nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1))\n                            + (chunksSoFar * CHUNK_SEPARATOR.length);\n                    encodedIndex += CHUNK_SEPARATOR.length;\n                }\n            }\n        }\n\n        // form integral number of 6-bit groups\n        dataIndex = i * 3;\n\n        if (fewerThan24bits == EIGHTBIT) {\n            b1 = binaryData[dataIndex];\n            k = (byte) (b1 & 0x03);\n            // log.debug(\"b1=\" + b1);\n            // log.debug(\"b1<<2 = \" + (b1>>2) );\n            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);\n            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];\n            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];\n            encodedData[encodedIndex + 2] = PAD;\n            encodedData[encodedIndex + 3] = PAD;\n        } else if (fewerThan24bits == SIXTEENBIT) {\n\n            b1 = binaryData[dataIndex];\n            b2 = binaryData[dataIndex + 1];\n            l = (byte) (b2 & 0x0f);\n            k = (byte) (b1 & 0x03);\n\n            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);\n            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);\n\n            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];\n            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2 | (k << 4)];\n            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];\n            encodedData[encodedIndex + 3] = PAD;\n        }\n\n        if (isChunked) {\n            // we also add a separator to the end of the final chunk.\n            if (chunksSoFar < nbrChunks) {\n                System.arraycopy(CHUNK_SEPARATOR, 0, encodedData, encodedDataLength\n                        - CHUNK_SEPARATOR.length, CHUNK_SEPARATOR.length);\n            }\n        }\n\n        return encodedData;\n    }\n\n    /**\n     * Decodes Base64 data into octects\n     * \n     * @param base64Data Byte array containing Base64 data\n     * @return Array containing decoded data.\n     */\n    public static byte[] decodeBase64(byte[] base64Data) {\n        // RFC 2045 requires that we discard ALL non-Base64 characters\n        base64Data = discardNonBase64(base64Data);\n\n        // handle the edge case, so we don't have to worry about it later\n        if (base64Data.length == 0) {\n            return new byte[0];\n        }\n\n        int numberQuadruple = base64Data.length / FOURBYTE;\n        byte decodedData[] = null;\n        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;\n\n        // Throw away anything not in base64Data\n\n        int encodedIndex = 0;\n        int dataIndex = 0;\n        {\n            // this sizes the output array properly - rlw\n            int lastData = base64Data.length;\n            // ignore the '=' padding\n            while (base64Data[lastData - 1] == PAD) {\n                if (--lastData == 0) {\n                    return new byte[0];\n                }\n            }\n            decodedData = new byte[lastData - numberQuadruple];\n        }\n\n        for (int i = 0; i < numberQuadruple; i++) {\n            dataIndex = i * 4;\n            marker0 = base64Data[dataIndex + 2];\n            marker1 = base64Data[dataIndex + 3];\n\n            b1 = base64Alphabet[base64Data[dataIndex]];\n            b2 = base64Alphabet[base64Data[dataIndex + 1]];\n\n            if (marker0 != PAD && marker1 != PAD) {\n                // No PAD e.g 3cQl\n                b3 = base64Alphabet[marker0];\n                b4 = base64Alphabet[marker1];\n\n                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);\n                decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));\n                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);\n            } else if (marker0 == PAD) {\n                // Two PAD e.g. 3c[Pad][Pad]\n                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);\n            } else if (marker1 == PAD) {\n                // One PAD e.g. 3cQ[Pad]\n                b3 = base64Alphabet[marker0];\n\n                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);\n                decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));\n            }\n            encodedIndex += 3;\n        }\n        return decodedData;\n    }\n\n    /**\n     * Discards any characters outside of the base64 alphabet, per the requirements on page 25 of\n     * RFC 2045 - \"Any characters outside of the base64 alphabet are to be ignored in base64 encoded\n     * data.\"\n     * \n     * @param data The base-64 encoded data to groom\n     * @return The data, less non-base64 characters (see RFC 2045).\n     */\n    private static byte[] discardNonBase64(byte[] data) {\n        byte groomedData[] = new byte[data.length];\n        int bytesCopied = 0;\n\n        for (int i = 0; i < data.length; i++) {\n            if (isBase64(data[i])) {\n                groomedData[bytesCopied++] = data[i];\n            }\n        }\n\n        byte packedData[] = new byte[bytesCopied];\n\n        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);\n\n        return packedData;\n    }\n\n    /**\n     * Encode the input data in base-64 format to a string\n     * \n     * @return String\n     */\n    public static String encodeBase64ToString(byte[] data) {\n        byte[] encoded = encodeBase64(data);\n        StringBuffer encodedBuff = new StringBuffer();\n        for (int i = 0; i < encoded.length; i++) {\n            encodedBuff.append((char) encoded[i]);\n        }\n        return encodedBuff.toString();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/CloseableUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\npublic class CloseableUtils {\n\n    private static final Logger sLogger = Logger.getLogger(CloseableUtils.class.getName());\n\n    /**\n     * Try to close properly objects implementing Closeable (input stream, output stream...). In\n     * case it fails to close them properly, it logs the failure as warning and do nothing more.\n     * This is a special case as we do not want to crash while attempting to close a closeable.\n     * \n     * @param c object to close or null\n     * @return IOException or null\n     *         <p>\n     *         <b>Be Careful:</b><br />\n     *         In Android SDK 15 and earlier Cursor does not implement Closeable. So do not use with\n     *         cursor.\n     *         </p>\n     */\n    public static IOException tryToClose(Closeable c) {\n        if (c != null) {\n            try {\n                c.close();\n            } catch (IOException e) {\n                if (sLogger.isActivated()) {\n                    sLogger.debug(new StringBuilder(\"Failed to close the stream, Message=\").append(\n                            e.getMessage()).toString());\n                }\n                return e;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/ContactUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Contact utility functions\n */\npublic class ContactUtil {\n\n    private static volatile com.gsma.services.rcs.contact.ContactUtil mContactUtil;\n\n    private static final Logger sLogger = Logger.getLogger(ContactUtil.class.getSimpleName());\n\n    /**\n     * A class to hold a valid phone number\n     */\n    public final static class PhoneNumber {\n        private final String mNumber;\n\n        /**\n         * Constructor\n         * \n         * @param number a valid phone number\n         */\n        /* package private */PhoneNumber(String number) {\n            mNumber = number;\n        }\n\n        /**\n         * Gets the valid phone number\n         * \n         * @return the valid phone number\n         */\n        public String getNumber() {\n            return mNumber;\n        }\n    }\n\n    /**\n     * Gets a valid phone number from a URI\n     * \n     * @param uri phone number\n     * @return the phone number without URI formating or null if not valid\n     */\n    public static PhoneNumber getValidPhoneNumberFromUri(String uri) {\n        String number = PhoneUtils.extractNumberFromUriWithoutFormatting(uri);\n        synchronized (ContactUtil.class) {\n            if (mContactUtil == null) {\n                mContactUtil = com.gsma.services.rcs.contact.ContactUtil.getInstance(AndroidFactory\n                        .getApplicationContext());\n            }\n        }\n        try {\n            if (mContactUtil.isValidContact(number)) {\n                return new PhoneNumber(number);\n            }\n        } catch (RcsPermissionDeniedException e) {\n            if (sLogger.isActivated()) {\n                sLogger.error(\"Failed to validate phone number from URI '\" + uri + (\"'!\"), e);\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Gets a valid phone number from a contact got from Android system.<br>\n     * (By Android system, we mean telephony manager, address book, etc)\n     * \n     * @param contact from Android system\n     * @return the phone number or null if not valid\n     */\n    public static PhoneNumber getValidPhoneNumberFromAndroid(String contact) {\n        synchronized (ContactUtil.class) {\n            if (mContactUtil == null) {\n                mContactUtil = com.gsma.services.rcs.contact.ContactUtil.getInstance(AndroidFactory\n                        .getApplicationContext());\n            }\n        }\n        try {\n            if (mContactUtil.isValidContact(contact)) {\n                return new PhoneNumber(contact);\n            }\n        } catch (RcsPermissionDeniedException e) {\n            sLogger.error(\"Failed to validate phone number from Android '\" + contact + (\"'!\"), e);\n        }\n        return null;\n    }\n\n    /**\n     * Creates a ContactId from a validated phone number\n     * \n     * @param phoneNumber the validated phone number\n     * @return the Contact Identifier\n     */\n    public static ContactId createContactIdFromValidatedData(PhoneNumber phoneNumber) {\n        synchronized (ContactUtil.class) {\n            if (mContactUtil == null) {\n                mContactUtil = com.gsma.services.rcs.contact.ContactUtil.getInstance(AndroidFactory\n                        .getApplicationContext());\n            }\n        }\n        try {\n            return mContactUtil.formatContact(phoneNumber.getNumber());\n\n        } catch (RcsPermissionDeniedException e) {\n            /*\n             * This exception cannot occur since PhoneNumber can only be instantiated for valid\n             * numbers.\n             */\n            String errorMessage = \"Phone number '\" + phoneNumber\n                    + \"' cannot be converted into contactId!\";\n            throw new IllegalStateException(errorMessage, e);\n        }\n    }\n\n    /**\n     * Creates a ContactId from a trusted data<br>\n     * (By trusted data, we mean RCS providers)\n     * \n     * @param phoneNumber from a trusted data\n     * @return the Contact Identifier\n     */\n    public static ContactId createContactIdFromTrustedData(String phoneNumber) {\n        synchronized (ContactUtil.class) {\n            if (mContactUtil == null) {\n                mContactUtil = com.gsma.services.rcs.contact.ContactUtil.getInstance(AndroidFactory\n                        .getApplicationContext());\n            }\n        }\n        try {\n            return mContactUtil.formatContact(phoneNumber);\n\n        } catch (RcsPermissionDeniedException e) {\n            /*\n             * This exception should not occur since core stack cannot be started if country code\n             * cannot be resolved.\n             */\n            String errorMessage = \"Failed to convert phone number '\" + phoneNumber\n                    + \"' into contactId!\";\n            throw new IllegalStateException(errorMessage, e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/DatabaseUtils.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.utils;\n\nimport android.os.ParcelFileDescriptor;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class DatabaseUtils {\n\n    private static final Map<String, Integer> sModeBits = new HashMap<>();\n\n    static {\n        sModeBits.put(\"r\", ParcelFileDescriptor.MODE_READ_ONLY);\n        sModeBits.put(\"w\", ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE\n                | ParcelFileDescriptor.MODE_TRUNCATE);\n        sModeBits.put(\"wt\", ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE\n                | ParcelFileDescriptor.MODE_TRUNCATE);\n        sModeBits.put(\"wa\", ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE\n                | ParcelFileDescriptor.MODE_APPEND);\n        sModeBits\n                .put(\"rw\", ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE);\n        sModeBits.put(\"rwt\", ParcelFileDescriptor.MODE_READ_WRITE\n                | ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE);\n    }\n\n    public static String[] appendIdWithSelectionArgs(String id, String[] selectionArgs) {\n        String[] idSelectionArg = new String[] {\n            id\n        };\n        if (selectionArgs == null) {\n            return idSelectionArg;\n        }\n        return DatabaseUtils.appendSelectionArgs(idSelectionArg, selectionArgs);\n    }\n\n    private static String[] appendSelectionArgs(String[] selectionArgs,\n            String[] selectionArgsToAppend) {\n        String[] resultingSelectionArgs = new String[selectionArgs.length\n                + selectionArgsToAppend.length];\n        System.arraycopy(selectionArgs, 0, resultingSelectionArgs, 0, selectionArgs.length);\n        System.arraycopy(selectionArgsToAppend, 0, resultingSelectionArgs, selectionArgs.length,\n                selectionArgsToAppend.length);\n        return resultingSelectionArgs;\n    }\n\n    public static int parseMode(String mode) {\n        Integer modeBits = sModeBits.get(mode);\n        if (modeBits == null) {\n            throw new IllegalArgumentException(\"Bad mode '\" + mode + \"!\");\n        }\n        return modeBits.intValue();\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/DateUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.TimeZone;\n\nimport android.text.format.Time;\n\n/**\n * Date utility functions\n * \n * @author jexa7410\n * @author Deutsche Telekom\n */\npublic class DateUtils {\n    /**\n     * UTC time zone\n     */\n    private static TimeZone UTC = TimeZone.getTimeZone(\"UTC\");\n\n    /**\n     * ISO 8601 date formats\n     */\n    private static SimpleDateFormat ISO8601DATEFORMAT[] = {\n            new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssZ\"),\n            new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mmZ\")\n    };\n\n    /**\n     * Encode a long date to string value in Z format (see RFC 3339)\n     * \n     * @param date Date in milliseconds\n     * @return String\n     */\n    public static String encodeDate(long date) {\n        Time t = new Time(UTC.getID());\n        t.set(date);\n        return t.format3339(false);\n    }\n\n    /**\n     * Decode a string date to long value (see ISO8601 and RFC 3339)\n     * \n     * @param date Date as string\n     * @return Milliseconds\n     */\n    public static long decodeDate(String date) {\n        long millis = -1;\n\n        // Try to use ISO8601\n        String normalizedDate = date.replaceAll(\"Z$\", \"+0000\");\n        for (int i = 0; millis == -1 && i < ISO8601DATEFORMAT.length; i++) {\n            try {\n                Date iso8601 = ISO8601DATEFORMAT[i].parse(normalizedDate);\n                millis = iso8601.getTime();\n            } catch (ParseException ex) {\n                // Try next format\n            }\n        }\n\n        // If still not valid format is found let's try RFC3339\n        if (millis == -1) {\n            Time t = new Time(UTC.getID());\n            t.parse3339(date);\n            millis = t.toMillis(false);\n        }\n\n        return millis;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/DeviceUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.telephony.TelephonyManager;\n\nimport java.util.UUID;\n\n/***\n * Device utility functions\n * \n * @author jexa7410\n */\npublic class DeviceUtils {\n\n    private static final String URN_IMEI = \"\\\"<urn:gsma:imei:\";\n\n    private static final String URN_UUID = \"\\\"<urn:uuid:\";\n\n    private static final String GREATER_THAN = \">\\\"\";\n\n    private static final char HYPHEN = '-';\n\n    private static final int START_INDEX = 0;\n\n    private static final int LAST_INDEX = 1;\n\n    private static final int LAST_SEVENTH_INDEX = 7;\n\n    private static UUID sUuid;\n\n    private static String sImei;\n\n    /**\n     * Returns unique UUID of the device\n     * \n     * @param ctx Context\n     * @return UUID\n     */\n    public static UUID getDeviceUUID(Context ctx) {\n        if (sUuid == null) {\n            String imei = getImei(ctx);\n            if (imei == null) {\n                // For compatibility with device without telephony\n                sUuid = generateUUID();\n            } else {\n                sUuid = UUID.nameUUIDFromBytes(imei.getBytes(UTF8));\n            }\n        }\n        return sUuid;\n    }\n\n    /**\n     * Generate the UUID from system using serial\n     * \n     * @return generated UUID\n     */\n    public static UUID generateUUID() {\n        return UUID.nameUUIDFromBytes(Build.SERIAL.getBytes(UTF8));\n    }\n\n    /**\n     * Returns the IMEI of the device\n     * \n     * @param ctx application context\n     * @return IMEI of the device\n     */\n    private static String getImei(Context ctx) {\n        if (sImei == null) {\n            final TelephonyManager telephonyManager = (TelephonyManager) ctx\n                    .getSystemService(Context.TELEPHONY_SERVICE);\n            sImei = telephonyManager.getDeviceId();\n            if (sImei == null) {\n                return null;\n            }\n            /**\n             * As per 3GPP TS 24.299, IMEI should be in format tac\"-\"snr\"-\"spare\" where: tac=8\n             * digits, snr=6 digits and spare=1 digit\n             */\n            final String tac = sImei.substring(START_INDEX, sImei.length() - LAST_SEVENTH_INDEX);\n            final String snr = sImei.substring(tac.length(), sImei.length() - LAST_INDEX);\n            final char spare = sImei.charAt(sImei.length() - LAST_INDEX);\n\n            sImei = tac + HYPHEN + snr + HYPHEN + spare;\n        }\n        return sImei;\n    }\n\n    /**\n     * Get instance ID for populating SIP Instance\n     * \n     * @param ctx application context\n     * @param rcsSettings the RCS settings accessor\n     * @return instance Id\n     */\n    public static String getInstanceId(Context ctx, RcsSettings rcsSettings) {\n        /**\n         * In accordance to RCS implementation guidelines v3.5, ID_4_33, embedded clients should use\n         * IMEI as SIP instance if it's available and should no longer be dependent on deviceID\n         * param. In case IMEI is not available, they should use uuid_Value, provided in\n         * configurations or else generate it as per RFC4122, section 4.2\n         */\n        final String imei = getImei(ctx);\n        if (imei != null) {\n            return URN_IMEI + imei + GREATER_THAN;\n        }\n        return URN_UUID + rcsSettings.getUUID() + GREATER_THAN;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/FifoBuffer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport java.util.Vector;\n\n/**\n * FIFO buffer\n * \n * @author JM. Auffret\n */\npublic class FifoBuffer {\n    /**\n     * Number of objects in the buffer\n     */\n    private int nbObjects = 0;\n\n    /**\n     * Buffer of objects\n     */\n    private Vector<Object> fifo = new Vector<>();\n\n    /**\n     * Add an object in the buffer\n     * \n     * @param obj Message\n     */\n    public synchronized void addObject(Object obj) {\n        fifo.addElement(obj);\n        nbObjects++;\n        notifyAll();\n    }\n\n    /**\n     * Read an object in the buffer. This is a blocking method until an object is read.\n     * \n     * @return Object\n     */\n    public synchronized Object getObject() {\n        Object obj = null;\n        if (nbObjects == 0) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n                // Nothing to do\n            }\n        }\n        if (nbObjects != 0) {\n            obj = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            nbObjects--;\n            notifyAll();\n        }\n        return obj;\n    }\n\n    /**\n     * Read an object in the buffer. This is a blocking method until a timeout occurs or an object\n     * is read.\n     * \n     * @param timeout Timeout\n     * @return Message\n     */\n    public synchronized Object getObject(int timeout) {\n        Object obj = null;\n        if (nbObjects == 0) {\n            try {\n                wait(timeout);\n            } catch (InterruptedException e) {\n                // Nothing to do\n            }\n        }\n        if (nbObjects != 0) {\n            obj = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            nbObjects--;\n            notifyAll();\n        }\n        return obj;\n    }\n\n    /**\n     * Close the buffer\n     */\n    public synchronized void close() {\n        // Free the semaphore\n        this.notifyAll();\n    }\n\n    /**\n     * Get FIFO size\n     * \n     * @return size of the FIFO\n     */\n    public int size() {\n        return fifo.size();\n    }\n\n    /**\n     * clean FIFO\n     */\n    public void clean(int size) {\n        if (fifo.size() > size) {\n            while (size > 0) {\n                fifo.removeElementAt(0);\n                nbObjects--;\n                size--;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/FileUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.core.content.ContentManager;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.database.Cursor;\nimport android.media.MediaMetadataRetriever;\nimport android.net.Uri;\nimport android.os.Process;\nimport android.provider.OpenableColumns;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * File utilities\n *\n * @author Philippe LEMORDANT\n */\npublic class FileUtils {\n\n    private static final Logger sLogger = Logger.getLogger(FileUtils.class.getSimpleName());\n\n    /**\n     * Copy a file to a directory\n     *\n     * @param srcFile the source file (may not be null)\n     * @param destDir the destination directory (may not be null)\n     * @param preserveFileDate whether to preserve the file date\n     * @throws IOException\n     * @throws IllegalArgumentException\n     */\n    public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate)\n            throws IOException, IllegalArgumentException {\n        if (srcFile == null) {\n            throw new IllegalArgumentException(\"Source is null\");\n        }\n        if (!srcFile.exists()) {\n            throw new FileNotFoundException(\"Source '\" + srcFile + \"' does not exist\");\n        }\n        if (srcFile.isDirectory()) {\n            throw new IOException(\"Source '\" + srcFile + \"' is a directory\");\n        }\n        if (destDir == null) {\n            throw new IllegalArgumentException(\"Destination is null\");\n        }\n        if (!destDir.exists()) {\n            // Create directory if it does not exist\n            if (!destDir.mkdir()) {\n                throw new IOException(\"Destination '\" + destDir + \"' directory cannot be created\");\n            }\n        } else {\n            if (!destDir.isDirectory()) {\n                throw new IllegalArgumentException(\"Destination '\" + destDir\n                        + \"' is not a directory\");\n            }\n        }\n        File destFile = new File(destDir, srcFile.getName());\n        if (destFile.exists() && !destFile.canWrite()) {\n            throw new IOException(\"Destination '\" + destFile + \"' file exists but is read-only\");\n        }\n        FileInputStream input = new FileInputStream(srcFile);\n        FileOutputStream output = null;\n        try {\n            output = new FileOutputStream(destFile);\n            byte[] buffer = new byte[1024];\n            int length;\n            while ((length = input.read(buffer)) > 0) {\n                output.write(buffer, 0, length);\n            }\n        } finally {\n            CloseableUtils.tryToClose(input);\n            CloseableUtils.tryToClose(output);\n        }\n        // check if full content is copied\n        if (srcFile.length() != destFile.length()) {\n            throw new IOException(\"Failed to copy from '\" + srcFile + \"' to '\" + destFile + \"'\");\n        }\n        // preserve the file date\n        if (preserveFileDate)\n            destFile.setLastModified(srcFile.lastModified());\n    }\n\n    /**\n     * get the oldest file from the list\n     *\n     * @param files list of files\n     * @return the oldest one or null\n     */\n    public static File getOldestFile(final File[] files) {\n        if (files == null || files.length == 0) {\n            return null;\n        }\n        File result = null;\n        for (File file : files) {\n            if (result == null) {\n                result = file;\n            } else {\n                if (file.lastModified() < result.lastModified()) {\n                    result = file;\n                }\n            }\n        }\n        return result;\n    }\n\n    /**\n     * Delete a directory recursively\n     *\n     * @param dir the directory\n     * @throws IOException\n     */\n    public static void deleteDirectory(File dir) throws IOException {\n        if (!dir.isDirectory()) {\n            throw new IllegalArgumentException(dir.getPath() + \" should always be a directory!\");\n        }\n        String[] children = dir.list();\n        for (String childname : children) {\n            File child = new File(dir, childname);\n            if (child.isDirectory()) {\n                deleteDirectory(child);\n                if (!child.delete()) {\n                    throw new IOException(\"Failed to delete file : \" + child.getPath());\n                }\n            } else {\n                if (!child.delete()) {\n                    throw new IOException(\"Failed to delete file : \" + child.getPath());\n                }\n            }\n        }\n        if (!dir.delete()) {\n            throw new IOException(\"Failed to delete directory : \" + dir.getPath());\n        }\n    }\n\n    /**\n     * Fetch the file name from URI\n     *\n     * @param ctx Context\n     * @param file URI\n     * @return fileName String\n     */\n    public static String getFileName(Context ctx, Uri file) {\n        String scheme = file.getScheme();\n        Cursor cursor = null;\n        try {\n            cursor = ctx.getContentResolver().query(file, null, null, null, null);\n            switch (scheme) {\n                case ContentResolver.SCHEME_CONTENT:\n                    if (cursor != null && cursor.moveToFirst()) {\n                        /*\n                         * Warning: OpenableColumns.DISPLAY_NAME does not have to be a filename (eg.\n                         * for audio files)\n                         */\n                        return cursor.getString(cursor\n                                .getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME));\n                    }\n                    throw new IllegalArgumentException(\"Error in retrieving file name from the URI\");\n\n                case ContentResolver.SCHEME_FILE:\n                    return file.getLastPathSegment();\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI scheme '\" + scheme + \"'!\");\n            }\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Fetch the file size from URI\n     *\n     * @param ctx Context\n     * @param file URI\n     * @return fileSize long\n     */\n    public static long getFileSize(Context ctx, Uri file) {\n        String scheme = file.getScheme();\n        Cursor cursor = null;\n        try {\n            cursor = ctx.getContentResolver().query(file, null, null, null, null);\n            switch (scheme) {\n                case ContentResolver.SCHEME_CONTENT:\n                    if (cursor != null && cursor.moveToFirst()) {\n                        return Long.valueOf(cursor.getString(cursor\n                                .getColumnIndexOrThrow(OpenableColumns.SIZE)));\n                    }\n                    throw new IllegalArgumentException(\"Error in retrieving file size form the URI\");\n\n                case ContentResolver.SCHEME_FILE:\n                    return (new File(file.getPath())).length();\n\n                default:\n                    throw new IllegalArgumentException(\"Unsupported URI scheme '\" + scheme + \"'!\");\n            }\n        } finally {\n            CursorUtil.close(cursor);\n        }\n    }\n\n    /**\n     * Test if the stack can read data from this Uri.\n     *\n     * @param ctx The context\n     * @param file The file URI\n     * @return True if URI is readable\n     */\n    public static boolean isReadFromUriPossible(Context ctx, Uri file) {\n        String scheme = file.getScheme();\n        switch (scheme) {\n            case ContentResolver.SCHEME_CONTENT:\n                InputStream stream = null;\n                try {\n                    if (PackageManager.PERMISSION_GRANTED == ctx\n                            .checkUriPermission(file, Process.myPid(), Process.myUid(),\n                                    Intent.FLAG_GRANT_READ_URI_PERMISSION)) {\n                        return true;\n                    }\n                    stream = ctx.getContentResolver().openInputStream(file);\n                    stream.read();\n                    return true;\n\n                } catch (SecurityException e) {\n                    sLogger.error(\"Failed to read from uri :\" + file, e);\n                    return false;\n\n                } catch (IOException e) {\n                    if (sLogger.isActivated()) {\n                        sLogger.debug(\"Failed to read from uri :\" + file + \", Message=\"\n                                + e.getMessage());\n                    }\n                    return false;\n\n                } finally {\n                    CloseableUtils.tryToClose(stream);\n                }\n            case ContentResolver.SCHEME_FILE:\n                String path = file.getPath();\n                if (path == null) {\n                    sLogger.error(\"Failed to read from uri :\".concat(file.toString()));\n                    return false;\n                }\n                try {\n                    return new File(path).canRead();\n\n                } catch (SecurityException e) {\n                    sLogger.error(\"Failed to read from uri :\" + file, e);\n                    return false;\n                }\n            default:\n                throw new IllegalArgumentException(\"Unsupported URI scheme '\" + scheme + \"'!\");\n        }\n    }\n\n    /**\n     * Copies a file. The destination is overwritten if it already exists.\n     *\n     * @param source Uri of the source file\n     * @param destination Uri of the destination file\n     * @throws IOException if the copy operation fails\n     */\n    private static void copyFile(Uri source, Uri destination) throws IOException {\n        FileInputStream sourceStream = null;\n        FileOutputStream destStream = null;\n        try {\n            sourceStream = (FileInputStream) AndroidFactory.getApplicationContext()\n                    .getContentResolver().openInputStream(source);\n            destStream = (FileOutputStream) AndroidFactory.getApplicationContext()\n                    .getContentResolver().openOutputStream(destination);\n            byte buffer[] = new byte[1024];\n            int length;\n            while ((length = sourceStream.read(buffer)) > 0) {\n                destStream.write(buffer, 0, length);\n            }\n        } finally {\n            CloseableUtils.tryToClose(sourceStream);\n            CloseableUtils.tryToClose(destStream);\n        }\n    }\n\n    private static String getMimeTypeFromFile(Context ctx, Uri file) {\n        MediaMetadataRetriever mmr = null;\n        try {\n            mmr = new MediaMetadataRetriever();\n            mmr.setDataSource(ctx, file);\n            return mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE);\n\n        } finally {\n            if (mmr != null) {\n                mmr.release();\n            }\n        }\n    }\n\n    /**\n     * Gets the duration from file Uri\n     * \n     * @param ctx the context\n     * @param file the file Uri\n     * @return the duration in ms or -1 if it cannot be retrieved\n     */\n    public static long getDurationFromFile(Context ctx, Uri file) {\n        MediaMetadataRetriever mmr = null;\n        try {\n            mmr = new MediaMetadataRetriever();\n            mmr.setDataSource(ctx, file);\n            return Long\n                    .parseLong(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));\n\n        } catch (NumberFormatException e) {\n            return -1;\n\n        } finally {\n            if (mmr != null) {\n                mmr.release();\n            }\n        }\n    }\n\n    /**\n     * Create copy of sent file in respective sent directory.\n     *\n     * @param file The file Uri to copy\n     * @param rcsSettings The RcsSettings accessor\n     * @return Uri of copy or created file\n     * @throws IOException\n     */\n    public static Uri createCopyOfSentFile(Uri file, RcsSettings rcsSettings) throws IOException {\n        String mimeType = getMimeType(file);\n        Context ctx = AndroidFactory.getApplicationContext();\n        String fileName = getFileName(ctx, file);\n        String extension = MimeManager.getFileExtension(fileName);\n        /*\n         * Checks if filename contains extension.\n         */\n        if (extension == null) {\n            /*\n             * If extension is not provided by filename then guess extension from MimeType.\n             */\n            extension = MimeManager.getInstance().getExtensionFromMimeType(mimeType);\n            if (extension == null) {\n                throw new RuntimeException(\"Cannot retrieve file extension for Uri='\" + file + \"'!\");\n            }\n            fileName = fileName + \".\" + extension;\n        }\n        Uri destination = ContentManager.generateUriForSentContent(fileName, mimeType, rcsSettings);\n        copyFile(file, destination);\n        return destination;\n    }\n\n    /**\n     * Gets the mime-type from file Uri\n     * \n     * @param file the file Uri\n     * @return the mime-type or null\n     */\n    public static String getMimeType(Uri file) {\n        String scheme = file.getScheme();\n        Context ctx = AndroidFactory.getApplicationContext();\n        if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {\n            return ctx.getContentResolver().getType(file);\n        }\n        if (ContentResolver.SCHEME_FILE.equals(scheme)) {\n            String path = file.getPath();\n            if (path == null) {\n                throw new RuntimeException(\"Invalid file path for Uri='\" + file + \"'!\");\n            }\n            String extension = MimeManager.getFileExtension(path);\n            if (extension == null) {\n                throw new IllegalArgumentException(\"No file extension Uri='\" + file + \"'!\");\n            }\n            String mimeType = MimeManager.getInstance().getMimeType(extension);\n            if (MimeManager.isVideoType(mimeType)) {\n                /*\n                 * Warning: Audio and Video files share the same extensions so we need to retrieve\n                 * mime type directly from file.\n                 */\n                String mimeTypeFromMediaFile = getMimeTypeFromFile(ctx, file);\n                if (mimeTypeFromMediaFile != null) {\n                    mimeType = mimeTypeFromMediaFile;\n                }\n            }\n            return mimeType;\n        }\n        throw new IllegalArgumentException(\"Unsupported URI scheme '\" + scheme + \"'!\");\n    }\n\n    /**\n     * Gets mime type from extesion pparsed from path or filename\n     * \n     * @param pathOrFilename the path or filename\n     * @return the mime type or null if not found\n     */\n\n    public static String getMimeTypeFromExtension(String pathOrFilename) {\n        String ext = MimeManager.getFileExtension(pathOrFilename);\n        return MimeManager.getInstance().getMimeType(ext);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/HexadecimalUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\n/**\n * Hexadecimal utils\n * \n * @author Deutsche Telekom AG\n */\npublic class HexadecimalUtils {\n\n    /**\n     * Decode hex string to a byte array\n     * \n     * @param s hexadecimal encoded string\n     * @return array of bytes\n     */\n    public static byte[] hexStringToByteArray(String s) {\n\n        if (s == null || s.length() == 0) {\n            return null;\n        }\n\n        int len = s.length();\n\n        // '111' is not a valid hex encoding.\n        if (len % 2 != 0) {\n            throw new IllegalArgumentException();\n        }\n\n        byte[] data = new byte[len / 2];\n        for (int i = 0; i < len; i += 2) {\n            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(\n                    s.charAt(i + 1), 16));\n        }\n        return data;\n    }\n\n    /**\n     * Convert byte array into Hexadecimal string\n     * \n     * @param bytes\n     * @return {@link String} if valid byte array, otherwise <code>null</code>\n     */\n    public static String byteArrayToHexString(byte[] bytes) {\n\n        if (bytes == null || bytes.length == 0) {\n            return null;\n        }\n\n        final char[] hexArray = {\n                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\n        };\n        char[] hexChars = new char[bytes.length * 2];\n        int value;\n        for (int j = 0; j < bytes.length; j++) {\n            value = bytes[j] & 0xFF;\n            hexChars[j * 2] = hexArray[value >>> 4];\n            hexChars[j * 2 + 1] = hexArray[value & 0x0F];\n        }\n        return new String(hexChars);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/IdGenerator.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport java.util.UUID;\n\n/**\n * Unique identifier generator\n * \n * @author JF. Jestin\n */\npublic class IdGenerator {\n\n    /**\n     * Every 6 bit are coded using this table (see base64 encoding standard, except '/' which was\n     * replaced by '_')\n     */\n    private final static char[] CODE_TABLE = {\n            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',\n            'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',\n            'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',\n            'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '_'\n    };\n\n    /**\n     * The counter which get a new value for each subsequent call of increment()\n     */\n    private static int cyclicCounter = 0;\n\n    /**\n     * How much digits are used for coding the counter, 3 means 3*6 bits, that are 18 bits resulting\n     * in a max. value of 262144 for the counter which seems to be enough.\n     */\n    private final static int N_COUNTERS_CHARS = 3;\n\n    /**\n     * The number of generated characters for the uniq identifier\n     * <p>\n     * System.currentTimeMillis() returns long, but only 42 bit are taken, which seems to be enough\n     * for more than 100 years after 1970, these 42 bits need 7 chars for their coding, the number\n     * of chars for the counter is added:\n     * \n     * <pre>\n     * maxDigit = 7 + N_COUNTERS_CHARS;\n     * </pre>\n     */\n    private final static int MAX_DIGIT = 7 + N_COUNTERS_CHARS;\n\n    /**\n     * The central method to increment the cyclic counter, synchronized to achieve a unique value\n     * for each subsequent call\n     * <p>\n     * there is no problem if the counter reaches the maximum counter value, defined by\n     * N_COUNTERS_CHARS, only the right number of bits are taken into account for generating the\n     * output\n     * \n     * @return The new counter value\n     */\n    private static synchronized int increment() {\n        return cyclicCounter++;\n    }\n\n    /**\n     * Encode twoumbers into a textual representation using a base64 like coding table.\n     * \n     * @param time This should be System.currentTimeMillis\n     * @param counter The counter value, it is coded into N_COUNTERS_CHARS chars, ie for 3 chars we\n     *            have 18 bit and a max. range of 262144\n     * @result The converted String containing (7 + N_COUNTERS_CHARS) characters\n     */\n    private static String encode64(long time, int counter) {\n        char[] encodedData = new char[MAX_DIGIT];\n        int i, idx;\n\n        for (i = 0; i < 7; i++) {\n            idx = (int) time & 63;\n            time >>= 6;\n            encodedData[i] = CODE_TABLE[idx];\n        }\n\n        for (; i < MAX_DIGIT; i++) {\n            idx = counter & 63;\n            counter >>= 6;\n            encodedData[i] = CODE_TABLE[idx];\n        }\n\n        return new String(encodedData);\n    }\n\n    /**\n     * Get a unique local identifier for each subsequent call\n     * \n     * @return Unique identifier\n     */\n    public static synchronized String getIdentifier() {\n        long time = System.currentTimeMillis();\n\n        int counter = -1;\n        if (N_COUNTERS_CHARS > 0)\n            counter = increment();\n\n        return encode64(time, counter);\n    }\n\n    /**\n     * Generate a new unique and random message ID (eg. for SIP or MSRP)\n     * \n     * @return the messageID\n     *         <p>\n     *         <b>Note:</b><br />\n     *         The message ID is a string of 32 characters in the range [a-f0-9] in compliance with\n     *         RFC 4975\n     *         </p>\n     */\n    public static synchronized String generateMessageID() {\n        UUID id = UUID.randomUUID();\n        return String.format(\"%016x%016x\", id.getMostSignificantBits(),\n                id.getLeastSignificantBits());\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/InetAddressUtils.java",
    "content": "/*\n * ====================================================================\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements.  See the NOTICE file\n * distributed with this work for additional information\n * regarding copyright ownership.  The ASF licenses this file\n * to you under the Apache License, Version 2.0 (the\n * \"License\"); you may not use this file except in compliance\n * with the License.  You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing,\n * software distributed under the License is distributed on an\n * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage com.gsma.rcs.utils;\n\nimport java.util.regex.Pattern;\n\n/**\n * A collection of utilities relating to InetAddresses.\n *\n * @since 4.0\n */\npublic class InetAddressUtils {\n\n    private InetAddressUtils() {\n    }\n\n    private static final Pattern IPV4_PATTERN = Pattern\n            .compile(\"^(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)(\\\\.(25[0-5]|2[0-4]\\\\d|[0-1]?\\\\d?\\\\d)){3}$\");\n\n    private static final Pattern IPV6_STD_PATTERN = Pattern\n            .compile(\"^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$\");\n\n    private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = Pattern\n            .compile(\"^((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)$\");\n\n    public static boolean isIPv4Address(final String input) {\n        return IPV4_PATTERN.matcher(input).matches();\n    }\n\n    public static boolean isIPv6StdAddress(final String input) {\n        return IPV6_STD_PATTERN.matcher(input).matches();\n    }\n\n    public static boolean isIPv6HexCompressedAddress(final String input) {\n        return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();\n    }\n\n    public static boolean isIPv6Address(final String input) {\n        return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/IntentUtils.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\n\n/**\n * IntentUtils class\n */\npublic class IntentUtils {\n\n    /**\n     * Try to allow the recipient to run at foreground priority, with a shorter timeout interval.\n     *\n     * @param intent Intent to set flags\n     */\n    public static void tryToSetReceiverForegroundFlag(Intent intent) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {\n            /*\n             * Since FLAG_RECEIVER_FOREGROUND is introduced only from API level\n             * JELLY_BEAN_VERSION_CODE we need to do nothing if we are running on a version prior\n             * that so we just return then.\n             */\n            return;\n        }\n        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);\n    }\n\n    /**\n     * Sends broadcast event\n     * \n     * @param context the Context\n     * @param action the intent action\n     */\n    public static void sendBroadcastEvent(Context context, String action) {\n        Intent intent = new Intent(action);\n        IntentUtils.tryToSetReceiverForegroundFlag(intent);\n        context.sendBroadcast(intent);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/IpAddressUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\n/**\n * IP address utility functions\n * \n * @author B. JOGUET\n */\npublic class IpAddressUtils {\n\n    /**\n     * Extract host address (see RFC4007 and RFC2373)\n     * \n     * @param host Host address\n     * @return Address\n     */\n    public static String extractHostAddress(String host) {\n        if (host == null) {\n            return null;\n        }\n\n        // Remove prefix from address\n        int index = host.indexOf(\"/\");\n        if (index != -1) {\n            host = host.substring(0, index);\n        }\n\n        // Remove zone id from address\n        /*\n         * RFC4007: <address>%<zone_id> where: <address> is a literal IPv6 address, <zone_id> is a\n         * string identifying the zone of the address, and `%' is a delimiter character to\n         * distinguish between <address> and <zone_id>.\n         */\n        index = host.indexOf(\"%\");\n        if (index != -1) {\n            host = host.substring(0, index);\n        }\n\n        return host;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/MimeManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.text.TextUtils;\nimport android.webkit.MimeTypeMap;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * MIME manager\n * \n * @author jexa7410\n * @author LEMORDANT Philippe\n */\npublic class MimeManager {\n\n    private static final String DEFAULT_FILE_ENCONDING = \"application/octet-stream\";\n    /**\n     * Singleton instance to access Two-way map that maps MIME-types to file extensions and vice\n     * versa.\n     */\n    private static volatile MimeManager sInstance;\n\n    /**\n     * Mime-Type to file extension mapping:\n     */\n    private HashMap<String, String> mimeTypeToExtensionMap;\n\n    /**\n     * File extension to Mime-Type mapping:\n     */\n    private HashMap<String, String> extensionToMimeTypeMap;\n\n    /**\n     * Set of image MIME-type:\n     */\n    private Set<String> imageMimeTypeSet;\n\n    /**\n     * Creates a new MIME-type map.\n     */\n    private MimeManager() {\n        mimeTypeToExtensionMap = new HashMap<>();\n        extensionToMimeTypeMap = new HashMap<>();\n        imageMimeTypeSet = new HashSet<>();\n    }\n\n    /**\n     * @return The singleton instance of the MIME-type map.\n     */\n    public static MimeManager getInstance() {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (MimeManager.class) {\n            if (sInstance == null) {\n                sInstance = new MimeManager();\n\n                // Image type\n                sInstance.loadMap(\"jpg\", \"image/jpeg\");\n                sInstance.loadMap(\"jpeg\", \"image/jpeg\");\n                sInstance.loadMap(\"png\", \"image/png\");\n                sInstance.loadMap(\"bmp\", \"image/bmp\");\n\n                // Audio type\n                sInstance.loadMap(\"3gp\", \"audio/3gpp\");\n                sInstance.loadMap(\"mp4\", \"audio/mp4\");\n\n                // Video type\n                sInstance.loadMap(\"3gp\", \"video/3gpp\");\n                sInstance.loadMap(\"mp4\", \"video/mp4\");\n                sInstance.loadMap(\"mp4a\", \"video/mp4\");\n                sInstance.loadMap(\"mpeg4\", \"video/mp4\");\n                sInstance.loadMap(\"mpeg\", \"video/mpeg\");\n                sInstance.loadMap(\"mpg\", \"video/mpeg\");\n\n                // Visit Card type\n                sInstance.loadMap(\"vcf\", \"text/vcard\");\n\n                // Geoloc type\n                sInstance.loadMap(\"xml\", \"application/vnd.gsma.rcspushlocation+xml\");\n            }\n            return sInstance;\n        }\n    }\n\n    /**\n     * Load an entry into the map.\n     */\n    private void loadMap(String extension, String mimeType) {\n        // Do not override extension if already inserted.\n        // First extension inserted should be the most representative one.\n        if (!mimeTypeToExtensionMap.containsKey(mimeType)) {\n            mimeTypeToExtensionMap.put(mimeType, extension);\n        }\n\n        extensionToMimeTypeMap.put(extension, mimeType);\n\n        // Insert into imageMimeType set if image\n        if (isImageType(mimeType)) {\n            imageMimeTypeSet.add(mimeType);\n        }\n    }\n\n    /**\n     * Is MIME-type supported\n     * \n     * @param mimeType the MIME-Type\n     * @return True if there is a MIME-type entry in the map\n     */\n    public boolean isMimeTypeSupported(String mimeType) {\n        return \"*\".equals(mimeType) || !TextUtils.isEmpty(mimeType)\n                && mimeTypeToExtensionMap.containsKey(mimeType);\n    }\n\n    private String getMimeTypeFromMap(String extension) {\n        return extensionToMimeTypeMap.get(extension.toLowerCase());\n    }\n\n    /**\n     * Returns the MIME-type associated to a given file extension\n     * \n     * @param extension The file extension\n     * @return The MIME-type for the extension or null if there is none.\n     */\n    public String getMimeType(String extension) {\n        if (TextUtils.isEmpty(extension)) {\n            return null;\n        }\n        String mimeType = getMimeTypeFromMap(extension);\n        if (mimeType != null) {\n            return mimeType;\n        }\n        mimeType = (MimeTypeMap.getSingleton()).getMimeTypeFromExtension(extension.toLowerCase());\n        return (mimeType != null) ? mimeType : DEFAULT_FILE_ENCONDING;\n    }\n\n    /**\n     * Returns the supported image MIME types\n     * \n     * @return Set of image MIME-types\n     */\n    public Set<String> getSupportedImageMimeTypes() {\n        return sInstance.imageMimeTypeSet;\n    }\n\n    /**\n     * Get extension having MIME-type\n     * \n     * @param mimeType the MIME-type\n     * @return The extension for the MIME-type or null if there is none.\n     */\n    public String getExtensionFromMimeType(String mimeType) {\n        if (TextUtils.isEmpty(mimeType)) {\n            return null;\n        }\n        String extension = mimeTypeToExtensionMap.get(mimeType);\n        if (extension != null) {\n            return extension;\n        }\n        return (MimeTypeMap.getSingleton()).getExtensionFromMimeType(mimeType);\n    }\n\n    /**\n     * Returns path extension\n     * \n     * @param path The path or filename\n     * @return Extension\n     */\n    public static String getFileExtension(String path) {\n        if (path.indexOf('.') != -1) {\n            return path.substring(path.lastIndexOf('.') + 1);\n        }\n        return null;\n    }\n\n    /**\n     * Is a image type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isImageType(String mime) {\n        return mime.toLowerCase().startsWith(\"image/\");\n    }\n\n    /**\n     * Is a video type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isVideoType(String mime) {\n        return mime.toLowerCase().startsWith(\"video/\");\n    }\n\n    /**\n     * Is an audio type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isAudioType(String mime) {\n        return mime.toLowerCase().startsWith(\"audio/\");\n    }\n\n    /**\n     * Is a VCard type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isVCardType(String mime) {\n        mime = mime.toLowerCase();\n        return \"text/vcard\".equals(mime) || \"text/x-vcard\".equals(mime);\n    }\n\n    /**\n     * Is a geoloc type\n     * \n     * @param mime MIME type\n     * @return Boolean\n     */\n    public static boolean isGeolocType(String mime) {\n        return mime.toLowerCase().equals(\"application/vnd.gsma.rcspushlocation+xml\");\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/NetworkRessourceManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.platform.network.DatagramConnection;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.platform.network.SocketServerConnection;\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport java.io.IOException;\nimport java.util.Random;\n\n/**\n * Network ressource manager\n * \n * @author jexa7410\n */\npublic class NetworkRessourceManager {\n\n    /**\n     * Default SIP port max\n     */\n    private static final int DEFAULT_LOCAL_SIP_PORT_RANGE_MAX = 65000;\n\n    /**\n     * Generate a default free SIP port number <br>\n     * This returns a random port which is free both in UDP and in TCP <br>\n     * Note that it does not bind to those ports, so there still is a chance that something else\n     * binds to it before you do. <br>\n     * Minimize this chance by using those ports as soon as possible\n     * \n     * @param rcsSettings\n     * @return Local SIP port\n     */\n    public static synchronized int generateLocalSipPort(RcsSettings rcsSettings) {\n        int defaultLocalSipPortRangeMin = rcsSettings.getSipListeningPort();\n        int candidatePort = getDefaultNumber(defaultLocalSipPortRangeMin,\n                DEFAULT_LOCAL_SIP_PORT_RANGE_MAX);\n        while (!isLocalUdpPortFree(candidatePort) && !isLocalTcpPortFree(candidatePort)) {\n            // Loop until candidate port is free in UDP and in TCP\n            candidatePort = getDefaultNumber(defaultLocalSipPortRangeMin,\n                    DEFAULT_LOCAL_SIP_PORT_RANGE_MAX);\n        }\n        return candidatePort;\n    }\n\n    /**\n     * Generate a default number from a given range\n     * \n     * @param minRange\n     * @param maxRange\n     * @return number Random number between minRange and maxRange\n     */\n    private static int getDefaultNumber(int minRange, int maxRange) {\n        Random random = new Random();\n        return (random.nextInt(maxRange - minRange + 1) + minRange);\n    }\n\n    /**\n     * Generate a default free RTP port number\n     * \n     * @param rcsSettings\n     * @return Local RTP port\n     */\n    public static synchronized int generateLocalRtpPort(RcsSettings rcsSettings) {\n        return generateLocalUdpPort(rcsSettings.getDefaultRtpPort());\n    }\n\n    /**\n     * Generate a default free MSRP port number\n     * \n     * @param rcsSettings\n     * @return Local MSRP port\n     */\n    public static synchronized int generateLocalMsrpPort(RcsSettings rcsSettings) {\n        return generateLocalTcpPort(rcsSettings.getDefaultMsrpPort());\n    }\n\n    /**\n     * Generate a free UDP port number from a specific port base\n     * \n     * @param portBase UDP port base\n     * @return Local UDP port\n     */\n    private static int generateLocalUdpPort(int portBase) {\n        int resp = -1;\n        int port = portBase;\n        while ((resp == -1) && (port < Integer.MAX_VALUE)) {\n            if (isLocalUdpPortFree(port)) {\n                // Free UDP port found\n                resp = port;\n            } else {\n                // +2 needed for RTCP port\n                port += 2;\n            }\n        }\n        return resp;\n    }\n\n    /**\n     * Test if the given local UDP port is really free (not used by other applications)\n     * \n     * @param port Port to check\n     * @return Boolean\n     */\n    private static boolean isLocalUdpPortFree(int port) {\n        boolean res = false;\n        try {\n            DatagramConnection conn = NetworkFactory.getFactory().createDatagramConnection();\n            conn.open(port);\n            conn.close();\n            res = true;\n        } catch (IOException e) {\n            res = false;\n        }\n        return res;\n    }\n\n    /**\n     * Generate a free TCP port number\n     * \n     * @param portBase TCP port base\n     * @return Local TCP port\n     */\n    private static int generateLocalTcpPort(int portBase) {\n        int resp = -1;\n        int port = portBase;\n        while (resp == -1) {\n            if (isLocalTcpPortFree(port)) {\n                // Free TCP port found\n                resp = port;\n            } else {\n                port++;\n            }\n        }\n        return resp;\n    }\n\n    /**\n     * Test if the given local TCP port is really free (not used by other applications)\n     * \n     * @param port Port to check\n     * @return Boolean\n     */\n    private static boolean isLocalTcpPortFree(int port) {\n        boolean res = false;\n        try {\n            SocketServerConnection conn = NetworkFactory.getFactory()\n                    .createSocketServerConnection();\n            conn.open(port);\n            conn.close();\n            res = true;\n        } catch (IOException e) {\n            res = false;\n        }\n        return res;\n    }\n\n    /**\n     * Is a valid IP address\n     * \n     * @param ipAddress IP address\n     * @return Boolean\n     */\n    public static boolean isValidIpAddress(String ipAddress) {\n        boolean result = false;\n        if ((ipAddress != null) && (!ipAddress.equals(\"127.0.0.1\"))\n                && (!ipAddress.equals(\"localhost\"))) {\n            result = true;\n        }\n        return result;\n    }\n\n    /**\n     * Convert an IP address to its integer representation\n     * \n     * @param addr IP address\n     * @return Integer\n     */\n    public static int ipToInt(String addr) {\n        String[] addrArray = addr.split(\"\\\\.\");\n        int num = 0;\n        for (int i = 0; i < addrArray.length; i++) {\n            int power = 3 - i;\n            num += ((Integer.parseInt(addrArray[i]) % 256 * Math.pow(256, power)));\n        }\n        return num;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/NetworkUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.platform.AndroidFactory;\n\nimport android.content.Context;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkInfo;\nimport android.telephony.TelephonyManager;\n\n/**\n * Network utils\n * \n * @author hlxn7157\n */\npublic class NetworkUtils {\n    /**\n     * Network access type unknown\n     */\n    public static int NETWORK_ACCESS_UNKNOWN = -1;\n\n    /**\n     * Network access type 2G\n     */\n    public static int NETWORK_ACCESS_2G = 0;\n\n    /**\n     * Network access type 3G\n     */\n    public static int NETWORK_ACCESS_3G = 1;\n\n    /**\n     * Network access type 3G+\n     */\n    public static int NETWORK_ACCESS_3GPLUS = 2;\n\n    /**\n     * Network access type Wi-Fi\n     */\n    public static int NETWORK_ACCESS_WIFI = 3;\n\n    /**\n     * Network access type 4G LTE\n     */\n    public static int NETWORK_ACCESS_4G = 4;\n\n    /**\n     * Get network access type\n     * \n     * @return Type\n     */\n    public static int getNetworkAccessType() {\n        ConnectivityManager connectivityMgr = (ConnectivityManager) AndroidFactory\n                .getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);\n        NetworkInfo networkInfo = connectivityMgr.getActiveNetworkInfo();\n        if (networkInfo == null) {\n            return NETWORK_ACCESS_UNKNOWN;\n        }\n        int networkType = networkInfo.getType();\n        switch (networkType) {\n            case ConnectivityManager.TYPE_WIFI:\n                return NETWORK_ACCESS_WIFI;\n\n            case ConnectivityManager.TYPE_MOBILE:\n                return getNetworkSubType(networkInfo.getSubtype());\n\n            default:\n                return NETWORK_ACCESS_UNKNOWN;\n        }\n    }\n\n    /**\n     * Returns network subType\n     */\n    private static int getNetworkSubType(int subType) {\n        switch (subType) {\n            case TelephonyManager.NETWORK_TYPE_GPRS:\n                /* Intentional fall back */\n            case TelephonyManager.NETWORK_TYPE_EDGE:\n                return NETWORK_ACCESS_2G;\n\n                /* ~ 400-7000 kbps */\n            case TelephonyManager.NETWORK_TYPE_UMTS:\n                /* Intentional fall back */\n                /* ~ 700-1700 kbps */\n            case TelephonyManager.NETWORK_TYPE_HSPA:\n                return NETWORK_ACCESS_3G;\n\n                /* ~ 2-14 Mbps */\n            case TelephonyManager.NETWORK_TYPE_HSDPA:\n                /* Intentional fall back */\n                /* ~ 1-23 Mbps */\n            case TelephonyManager.NETWORK_TYPE_HSUPA:\n                /* Intentional fall back */\n                /* ~10-20 Mbps */\n            case TelephonyManager.NETWORK_TYPE_HSPAP:\n                return NETWORK_ACCESS_3GPLUS;\n\n                /* ~10+ Mbps */\n            case TelephonyManager.NETWORK_TYPE_LTE:\n                return NETWORK_ACCESS_4G;\n            default:\n                return NETWORK_ACCESS_UNKNOWN;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/PeriodicRefresher.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.core.Core;\nimport com.gsma.rcs.core.ims.network.NetworkException;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\n\n/**\n * Periodic refresher\n * \n * @author JM. Auffret\n */\npublic abstract class PeriodicRefresher {\n\n    /**\n     * Keep alive manager\n     */\n    private final KeepAlive mAlarmReceiver = new KeepAlive();\n\n    private final PendingIntent mAlarmIntent;\n\n    private final String mAction;\n\n    private boolean mTimerStarted = false;\n\n    private final Context mContext;\n\n    private final AlarmManager mAlarmManager;\n\n    private static final Logger sLogger = Logger.getLogger(PeriodicRefresher.class.getName());\n\n    /**\n     * Constructor\n     */\n    public PeriodicRefresher() {\n        mContext = AndroidFactory.getApplicationContext();\n        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);\n        /* Create a unique pending intent */\n        mAction = getClass().getName() + '_' + System.currentTimeMillis(); /* Unique action ID */\n        mAlarmIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(mAction), 0);\n    }\n\n    /**\n     * Periodic processing\n     * \n     * @throws NetworkException\n     * @throws PayloadException\n     * @throws ContactManagerException\n     */\n    public abstract void periodicProcessing() throws PayloadException, NetworkException,\n            ContactManagerException;\n\n    /**\n     * Start the timer\n     * \n     * @param currentTime Time from when the timer has to be started\n     * @param expirePeriod Expiration period in milliseconds\n     */\n    public void startTimer(long currentTime, long expirePeriod) {\n        startTimer(currentTime, expirePeriod, 1.0);\n    }\n\n    /**\n     * Start the timer\n     * \n     * @param currentTime Time from when the timer has to be started\n     * @param expirePeriod Expiration period in milliseconds\n     * @param delta Delta to apply on the expire period in percentage\n     */\n    public synchronized void startTimer(long currentTime, long expirePeriod, double delta) {\n        /* Check expire period */\n        if (expirePeriod <= 0) {\n            /* Expire period is null */\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Timer is deactivated\");\n            }\n            return;\n        }\n\n        /* Calculate the effective refresh period */\n        long pollingPeriod = (long) (expirePeriod * delta);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Start timer at period=\" + pollingPeriod + \"ms (expiration=\"\n                    + expirePeriod + \"ms)\");\n        }\n        mContext.registerReceiver(mAlarmReceiver, new IntentFilter(mAction));\n        TimerUtils.setExactTimer(mAlarmManager, currentTime + pollingPeriod, mAlarmIntent);\n        mTimerStarted = true;\n    }\n\n    /**\n     * Stop the timer\n     */\n    public synchronized void stopTimer() {\n        if (!mTimerStarted) {\n            return;\n        }\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Stop timer\");\n        }\n        /* The timer is stopped */\n        mTimerStarted = false;\n        mAlarmManager.cancel(mAlarmIntent);\n\n        try {\n            mContext.unregisterReceiver(mAlarmReceiver);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Keep alive manager\n     */\n    private class KeepAlive extends BroadcastReceiver {\n        public void onReceive(Context context, Intent intent) {\n            Core.getInstance().scheduleCoreOperation(new Runnable() {\n                @Override\n                public void run() {\n                    try {\n                        periodicProcessing();\n\n                    } catch (ContactManagerException | PayloadException e) {\n                        sLogger.error(\"IMS re-registration unsuccessful!\", e);\n\n                    } catch (NetworkException e) {\n                        /* Nothing to be handled here */\n                        if (sLogger.isActivated()) {\n                            sLogger.debug(e.getMessage());\n                        }\n                    } catch (RuntimeException e) {\n                        /*\n                         * Normally we are not allowed to catch runtime exceptions as these are\n                         * genuine bugs which should be handled/fixed within the code. However the\n                         * cases when we are executing operations on a thread unhandling such\n                         * exceptions will eventually lead to exit the system and thus can bring the\n                         * whole system down, which is not intended.\n                         */\n                        sLogger.error(\"IMS re-registration unsuccessful!\", e);\n                        stopTimer();\n                    }\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/PhoneUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Phone utility functions\n * \n * @author jexa7410\n */\npublic class PhoneUtils {\n\n    private static RcsSettings sRcsSettings;\n\n    /**\n     * Regular expression of the SIP header\n     */\n    private final static String REGEXP_EXTRACT_URI = \"<(.*)>\";\n\n    /**\n     * Pattern to extract Uri from SIP header\n     */\n    private final static Pattern PATTERN_EXTRACT_URI = Pattern.compile(REGEXP_EXTRACT_URI);\n\n    /**\n     * Header for TEL URI\n     */\n    public static final String TEL_URI_HEADER = \"tel:\";\n\n    /**\n     * header for SIP URI\n     */\n    public static final String SIP_URI_HEADER = \"sip:\";\n\n    /**\n     * Start delimiter for URI\n     */\n    public static final String URI_START_DELIMITER = \"<\";\n\n    /**\n     * End delimiter for URI\n     */\n    public static final String URI_END_DELIMITER = \">\";\n\n    /**\n     * Initializes\n     * \n     * @param rcsSettings the RCS settings accessor\n     */\n    public static synchronized void initialize(RcsSettings rcsSettings) {\n        sRcsSettings = rcsSettings;\n    }\n\n    /**\n     * Format ContactId to tel or sip Uri\n     * \n     * @param contactId the contact identifier\n     * @return the Uri\n     */\n    public static Uri formatContactIdToUri(ContactId contactId) {\n        if (contactId == null) {\n            throw new IllegalArgumentException(\"ContactId is null\");\n        }\n        // @FIXME: Should make use of android.net.sip.SipProfile.Builder for creating SIP URI\n        // instead of doing it with Strings.\n        if (sRcsSettings.isTelUriFormatUsed()) {\n            /* Tel-URI format */\n            return Uri.parse(TEL_URI_HEADER.concat(contactId.toString()));\n        }\n        /* SIP-URI format */\n        return Uri.parse(SIP_URI_HEADER + contactId + \"@\" + sRcsSettings.getUserProfileImsDomain()\n                + \";user=phone\");\n    }\n\n    /**\n     * Extract user part phone number from a SIP-URI or Tel-URI or SIP address\n     * \n     * @param uri SIP or Tel URI\n     * @return Unformatted Number or null in case of error\n     */\n    /* package private */static String extractNumberFromUriWithoutFormatting(String uri) {\n        if (uri == null) {\n            return null;\n        }\n        /* Extract URI from address */\n        int index0 = uri.indexOf(URI_START_DELIMITER);\n        if (index0 != -1) {\n            uri = uri.substring(index0 + URI_START_DELIMITER.length(),\n                    uri.indexOf(URI_END_DELIMITER, index0));\n        }\n        /* Extract a Tel-URI */\n        int index1 = uri.indexOf(TEL_URI_HEADER);\n        if (index1 != -1) {\n            uri = uri.substring(index1 + TEL_URI_HEADER.length());\n        }\n        /* Extract a SIP-URI */\n        index1 = uri.indexOf(SIP_URI_HEADER);\n        if (index1 != -1) {\n            int index2 = uri.indexOf(\"@\", index1);\n            uri = uri.substring(index1 + SIP_URI_HEADER.length(), index2);\n        }\n        /* Remove URI parameters */\n        int index2 = uri.indexOf(\";\");\n        if (index2 != -1) {\n            uri = uri.substring(0, index2);\n        }\n        // @formatter:off\n        /* Remove URI headers.\n            According to RFC 3261, headers are formatted as follows:\n\n            SIP-URI =  \"sip:\" [ userinfo ] hostport uri-parameters [ headers ]\n            headers         =  \"?\" header *( \"&\" header )\n            header          =  hname \"=\" hvalue\n            hname           =  1*( hnv-unreserved / unreserved / escaped )\n            hvalue          =  *( hnv-unreserved / unreserved / escaped )\n            hnv-unreserved  =  \"[\" / \"]\" / \"/\" / \"?\" / \":\" / \"+\" / \"$\"\n        */\n        // @formatter:on\n        index2 = uri.indexOf(\"?\");\n        if (index2 != -1) {\n            uri = uri.substring(0, index2);\n        }\n        /* Returns the extracted number (username part of the URI) */\n        return uri;\n    }\n\n    /**\n     * get URI from SIP identity header\n     * \n     * @param header the SIP header\n     * @return the Uri\n     */\n    public static String extractUriFromSipHeader(String header) {\n        if (header != null) {\n            Matcher matcher = PATTERN_EXTRACT_URI.matcher(header);\n            if (matcher.find()) {\n                return matcher.group(1);\n            }\n        }\n        return header;\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/StorageUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.os.Environment;\nimport android.os.StatFs;\n\n/**\n * Storage utility functions\n * \n * @author Deutsche Telekom AG\n */\npublic class StorageUtils {\n\n    /**\n     * Verify if external storage is available (read or write) using {@link Environment} external\n     * storage state\n     * \n     * @see Environment#MEDIA_MOUNTED\n     * @see Environment#MEDIA_MOUNTED_READ_ONLY\n     * @return <code>true</code> if available, otherwise <code>false</code>\n     */\n    public static boolean hasExternalStorage() {\n        String state = Environment.getExternalStorageState();\n        return Environment.MEDIA_MOUNTED.equals(state)\n                || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state);\n    }\n\n    /**\n     * Get available space in external storage, only if external storage is ready to write\n     * \n     * @return Available space in bytes, otherwise <code>-1</code>\n     */\n    public static long getExternalStorageFreeSpace() {\n        long freeSpace = -1;\n        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {\n            StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());\n            long blockSize = stat.getBlockSize();\n            long availableBlocks = stat.getAvailableBlocks();\n            freeSpace = blockSize * availableBlocks;\n        }\n        return freeSpace;\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/StringUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport java.nio.charset.Charset;\nimport java.text.CharacterIterator;\nimport java.text.StringCharacterIterator;\nimport java.util.Iterator;\n\n/**\n * String utility functions\n */\npublic class StringUtils {\n\n    public static final String UTF8_STR = \"utf-8\";\n\n    public static final Charset UTF8 = Charset.forName(UTF8_STR);\n\n    public static final String UTF16_STR = \"utf-16\";\n\n    public static final Charset UTF16 = Charset.forName(UTF16_STR);\n\n    public static final String PDUS = \"pdus\";\n\n    /**\n     * Truncate a string to a max length\n     * \n     * @param text String to truncate\n     * @param truncatedLength Max length\n     * @return Truncated string\n     */\n    public static String truncate(String text, int truncatedLength) {\n        if (text == null) {\n            return null;\n        }\n\n        if ((truncatedLength < 0) || (truncatedLength > text.length())) {\n            return text;\n        }\n        return text.substring(0, truncatedLength);\n    }\n\n    /**\n     * Escape characters for text appearing as XML data, between tags. The following characters are\n     * replaced : <br>\n     * < <br>\n     * > <br>\n     * & <br>\n     * \" <br>\n     * '\n     * \n     * @param text Input text\n     * @return Encoded string\n     */\n    public static String encodeXML(String text) {\n        if (text == null) {\n            return null;\n        }\n\n        final StringBuilder result = new StringBuilder();\n        final StringCharacterIterator iterator = new StringCharacterIterator(text);\n        char character = iterator.current();\n        while (character != CharacterIterator.DONE) {\n            if (character == '<') {\n                result.append(\"&lt;\");\n            } else if (character == '>') {\n                result.append(\"&gt;\");\n            } else if (character == '\\\"') {\n                result.append(\"&quot;\");\n            } else if (character == '\\'') {\n                result.append(\"&#039;\");\n            } else if (character == '&') {\n                result.append(\"&amp;\");\n            } else {\n                // the char is not a special one\n                // add it to the result as is\n                result.append(character);\n            }\n            character = iterator.next();\n        }\n        return result.toString();\n    }\n\n    /**\n     * Decode XML string\n     * \n     * @param text Input text\n     * @return Decoded string\n     */\n    public static String decodeXML(String text) {\n        if (text == null) {\n            return null;\n        }\n\n        text = text.replaceAll(\"&lt;\", \"<\");\n        text = text.replaceAll(\"&gt;\", \">\");\n        text = text.replaceAll(\"&quot;\", \"\\\"\");\n        text = text.replaceAll(\"&#039;\", \"\\'\");\n        text = text.replaceAll(\"&amp;\", \"&\");\n\n        return text;\n    }\n\n    /**\n     * Remove quotes delimiters\n     * \n     * @param input Input\n     * @return String without quotes\n     */\n    public static String removeQuotes(String input) {\n        if ((input != null) && input.startsWith(\"\\\"\") && input.endsWith(\"\\\"\")) {\n            input = input.substring(1, input.length() - 1);\n        }\n        return input;\n    }\n\n    /**\n     * Is empty string\n     * \n     * @param str String\n     * @return Boolean\n     */\n    public static boolean isEmpty(String str) {\n        return (str == null) || (str.trim().length() == 0);\n    }\n\n    /**\n     * Build a string of delimited items\n     * \n     * @param s an iterator over a CharSequence\n     * @param delimiter a delimiter\n     * @return the string of delimited items\n     */\n    public static String join(Iterable<? extends CharSequence> s, String delimiter) {\n        Iterator<? extends CharSequence> iter = s.iterator();\n        if (!iter.hasNext())\n            return \"\";\n        StringBuilder buffer = new StringBuilder(iter.next());\n        while (iter.hasNext())\n            buffer.append(delimiter).append(iter.next());\n        return buffer.toString();\n    }\n\n    /**\n     * compares two strings null-safe\n     * \n     * @param str1\n     * @param str2\n     * @return true if equals\n     */\n    public static boolean equals(String str1, String str2) {\n        return str1 == null ? str2 == null : str1.equals(str2);\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/TimerUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.os.Build;\n\n/**\n * Utilities for timer management\n */\npublic class TimerUtils {\n\n    /**\n     * Schedule an alarm with exact timer\n     * \n     * @param alarmManager\n     * @param triggerAtMillis time in milliseconds that the alarm should go off. @param operation\n     *            Action to perform when the alarm goes off\n     * @param operation Action to perform when the alarm goes off\n     */\n    public static void setExactTimer(AlarmManager alarmManager, long triggerAtMillis,\n            PendingIntent operation) {\n        /*\n         * Beginning with API 19 (KITKAT), alarm delivery is inexact. The OS will shift alarms in\n         * order to minimize wake ups and battery use. The new API setExact(int, long,\n         * PendingIntent) will support applications which need strict delivery guarantees.\n         * Applications whose targetSdkVersion is earlier than API 19 will continue to see the\n         * previous behavior in which all alarms are delivered exactly when requested.\n         */\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {\n            alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);\n        } else {\n            alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/logger/Appender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils.logger;\n\n/**\n * Appender\n * \n * @author jexa7410\n */\npublic abstract class Appender {\n    /**\n     * Constructor\n     */\n    public Appender() {\n    }\n\n    /**\n     * Print a trace\n     * \n     * @param classname Classname\n     * @param level Trace level\n     * @param trace Trace\n     */\n    public abstract void printTrace(String classname, int level, String trace);\n}\n"
  },
  {
    "path": "core/src/com/gsma/rcs/utils/logger/Logger.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils.logger;\n\nimport com.gsma.rcs.platform.logger.AndroidAppender;\nimport com.gsma.rcs.service.api.ExceptionUtil;\n\n/**\n * Logger\n * \n * @author jexa7410\n */\npublic class Logger {\n    /**\n     * Trace ON\n     */\n    public static final boolean TRACE_ON = true;\n\n    /**\n     * Trace OFF\n     */\n    public static final boolean TRACE_OFF = false;\n\n    /**\n     * DEBUG level\n     */\n    public static final int DEBUG_LEVEL = 0;\n\n    /**\n     * INFO level\n     */\n    public static final int INFO_LEVEL = 1;\n\n    /**\n     * WARN level\n     */\n    public static final int WARN_LEVEL = 2;\n\n    /**\n     * ERROR level\n     */\n    public static final int ERROR_LEVEL = 3;\n\n    /**\n     * FATAL level\n     */\n    public static final int FATAL_LEVEL = 4;\n\n    /**\n     * Trace flag\n     */\n    public static boolean sActivationFlag = TRACE_ON;\n\n    /**\n     * Trace level\n     */\n    public static int traceLevel = DEBUG_LEVEL;\n\n    /**\n     * List of appenders\n     */\n    private static Appender[] sAppenders = new Appender[] {\n        new AndroidAppender()\n    };\n\n    /**\n     * Classname\n     */\n    private String mClassname;\n\n    /**\n     * Constructor\n     * \n     * @param classname Classname\n     */\n    private Logger(String classname) {\n        int index = classname.lastIndexOf('.');\n        if (index != -1) {\n            mClassname = classname.substring(index + 1);\n        } else {\n            mClassname = classname;\n        }\n    }\n\n    /**\n     * Is logger activated\n     * \n     * @return boolean\n     */\n    public boolean isActivated() {\n        return (sActivationFlag == TRACE_ON);\n    }\n\n    /**\n     * Debug trace\n     * \n     * @param trace Trace\n     */\n    public void debug(String trace) {\n        printTrace(trace, DEBUG_LEVEL);\n    }\n\n    /**\n     * Info trace\n     * \n     * @param trace Trace\n     */\n    public void info(String trace) {\n        printTrace(trace, INFO_LEVEL);\n    }\n\n    /**\n     * Warning trace\n     * \n     * @param trace Trace\n     */\n    public void warn(String trace) {\n        printTrace(trace, WARN_LEVEL);\n    }\n\n    /**\n     * Warning trace\n     * \n     * @param trace Trace\n     * @param e Exception\n     */\n    public void warn(String trace, Throwable e) {\n        printTrace(trace, WARN_LEVEL);\n        printTrace(ExceptionUtil.getFullStackTrace(e), WARN_LEVEL);\n    }\n\n    /**\n     * Error trace\n     * \n     * @param trace Trace\n     */\n    public void error(String trace) {\n        printTrace(trace, ERROR_LEVEL);\n    }\n\n    /**\n     * Error trace\n     * \n     * @param trace Trace\n     * @param e Exception\n     */\n    public void error(String trace, Throwable e) {\n        printTrace(trace, ERROR_LEVEL);\n        printTrace(ExceptionUtil.getFullStackTrace(e), ERROR_LEVEL);\n    }\n\n    /**\n     * Fatal trace\n     * \n     * @param trace Trace\n     */\n    public void fatal(String trace) {\n        printTrace(trace, FATAL_LEVEL);\n    }\n\n    /**\n     * Fatal trace\n     * \n     * @param trace Trace\n     * @param e Exception\n     */\n    public void fatal(String trace, Throwable e) {\n        printTrace(trace, FATAL_LEVEL);\n        printTrace(ExceptionUtil.getFullStackTrace(e), FATAL_LEVEL);\n\n    }\n\n    /**\n     * Print a trace\n     * \n     * @param trace Trace\n     * @param level Trace level\n     */\n    private void printTrace(String trace, int level) {\n        if (sAppenders != null && level >= traceLevel) {\n            /*\n             * String having '\\' characters are not printed out in locat console !\n             */\n            trace = trace.replace(\"\\r\", \"\");\n            for (Appender appender : sAppenders) {\n                appender.printTrace(mClassname, level, trace);\n            }\n        }\n    }\n\n    /**\n     * Create a static instance\n     * \n     * @param classname Classname\n     * @return Instance\n     */\n    public static synchronized Logger getLogger(String classname) {\n        return new Logger(classname);\n    }\n\n}\n"
  },
  {
    "path": "core/src/com/telekom/bouncycastle/wrapper/SimpleContentSignerBuilder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.telekom.bouncycastle.wrapper;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.operator.ContentSigner;\nimport local.org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;\nimport local.org.bouncycastle.operator.OperatorCreationException;\nimport local.org.bouncycastle.operator.OperatorStreamException;\nimport local.org.bouncycastle.operator.RuntimeOperatorException;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.security.GeneralSecurityException;\nimport java.security.PrivateKey;\nimport java.security.Signature;\nimport java.security.SignatureException;\n\n/**\n * Simplified class derived from org.bouncycastle.operator.jcajce.JcaContentSignerBuilder to avoid\n * implementing a complete security provider just for creating and signing certificates.\n */\npublic class SimpleContentSignerBuilder {\n\n    private String mAlgorithm = \"SHA1withRSA\";\n    private AlgorithmIdentifier sigAlgId;\n\n    public SimpleContentSignerBuilder() {\n        this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(mAlgorithm);\n    }\n\n    public ContentSigner build(PrivateKey privateKey) throws OperatorCreationException {\n        try {\n            final Signature sig = Signature.getInstance(mAlgorithm);\n\n            sig.initSign(privateKey);\n\n            return new ContentSigner() {\n                private SignatureOutputStream stream = new SignatureOutputStream(sig);\n\n                public AlgorithmIdentifier getAlgorithmIdentifier() {\n                    return sigAlgId;\n                }\n\n                public OutputStream getOutputStream() {\n                    return stream;\n                }\n\n                public byte[] getSignature() {\n                    try {\n                        return stream.getSignature();\n                    } catch (SignatureException e) {\n                        throw new RuntimeOperatorException(\"exception obtaining signature: \"\n                                + e.getMessage(), e);\n                    }\n                }\n            };\n        } catch (GeneralSecurityException e) {\n            throw new OperatorCreationException(\"cannot create signer: \" + e.getMessage(), e);\n        }\n    }\n\n    private class SignatureOutputStream extends OutputStream {\n        private Signature sig;\n\n        SignatureOutputStream(Signature sig) {\n            this.sig = sig;\n        }\n\n        public void write(byte[] bytes, int off, int len) throws IOException {\n            try {\n                sig.update(bytes, off, len);\n            } catch (SignatureException e) {\n                throw new OperatorStreamException(\"exception in content signer: \" + e.getMessage(),\n                        e);\n            }\n        }\n\n        public void write(byte[] bytes) throws IOException {\n            try {\n                sig.update(bytes);\n            } catch (SignatureException e) {\n                throw new OperatorStreamException(\"exception in content signer: \" + e.getMessage(),\n                        e);\n            }\n        }\n\n        public void write(int b) throws IOException {\n            try {\n                sig.update((byte) b);\n            } catch (SignatureException e) {\n                throw new OperatorStreamException(\"exception in content signer: \" + e.getMessage(),\n                        e);\n            }\n        }\n\n        byte[] getSignature() throws SignatureException {\n            return sig.sign();\n        }\n    }\n}\n"
  },
  {
    "path": "core/tests/.gitignore",
    "content": "/gen\r\n/bin\r\n"
  },
  {
    "path": "core/tests/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!-- package name must be unique so suffix with \"tests\" so package loader doesn't ignore us -->\n<manifest package=\"com.gsma.rcs.tests\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <!--\n      We add an application tag here just so that we can indicate that\n         this package needs to link against the android.test library,\n         which is needed when building test cases.\n    -->\n    <application>\n        <uses-library android:name=\"android.test.runner\"/>\n    </application>\n\n</manifest>"
  },
  {
    "path": "core/tests/ant.properties",
    "content": "test.runner=com.zutubi.android.junitreport.JUnitReportTestRunner\ntested.project.dir=../\n"
  },
  {
    "path": "core/tests/default.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system use,\n# \"build.properties\", and override values to adapt the script to your\n# project structure.\n\n# Project target.\ntarget=android-7\n"
  },
  {
    "path": "core/tests/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-23\n"
  },
  {
    "path": "core/tests/res/.gitignore",
    "content": "/drawable-xhdpi\r\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/InitTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs;\n\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.test.AndroidTestCase;\n\n/**\n * Caution: this class is set at the top of the class naming hierarchy in order to be first\n * executed.\n */\npublic class InitTest extends AndroidTestCase {\n\n    private static final Logger sLogger = Logger.getLogger(InitTest.class.getName());\n\n    private ContactUtil mContactUtils;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Context ctx = getContext();\n        mContactUtils = ContactUtil.getInstance(new ContactUtilMockContext(ctx));\n        if (sLogger.isActivated()) {\n            Configuration config = ctx.getResources().getConfiguration();\n            sLogger.warn(\"mcc='\" + config.mcc + \"'\");\n            sLogger.debug(\"Country Code='\" + mContactUtils.getMyCountryCode()\n                    + \"' Country Area Code='\" + mContactUtils.getMyCountryAreaCode() + \"'\");\n        }\n    }\n\n    public void testGetMyCountryAreaCode() throws RcsPermissionDeniedException {\n        assertEquals(\"Country Code='\" + mContactUtils.getMyCountryCode() + \"' Country Area Code='\"\n                + mContactUtils.getMyCountryAreaCode() + \"'\",\n                ContactUtilMockContext.COUNTRY_AREA_CODE, mContactUtils.getMyCountryAreaCode());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/RcsSettingsMock.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs;\n\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\nimport com.gsma.rcs.utils.PhoneUtils;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.Context;\n\npublic class RcsSettingsMock {\n\n    private static ContactId mOriContact;\n    private static RcsSettings sSettings;\n\n    public static RcsSettings getMockSettings(Context context) throws RcsPermissionDeniedException {\n        sSettings = RcsSettings.getInstance(new LocalContentResolver(context));\n        AndroidFactory.setApplicationContext(context, sSettings);\n        mOriContact = sSettings.getUserProfileImsUserName();\n        sSettings.setUserProfileImsUserName(ContactUtil\n                .createContactIdFromTrustedData(\"+33601020304\"));\n        PhoneUtils.initialize(sSettings);\n        return sSettings;\n    }\n\n    public static void restoreSettings() {\n        sSettings.setUserProfileImsUserName(mOriContact);\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/chat/ChatSdpUtilsTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010 France Telecom S.A.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.chat;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\n\nimport android.test.AndroidTestCase;\n\nimport java.util.Vector;\n\npublic class ChatSdpUtilsTest extends AndroidTestCase {\n\n    public void testbuildChatSDP() {\n\n        /***\n         * v=0 o=- 3667904944 3667904944 IN IP4 192.168.1.50 s=- c=IN IP4 192.168.1.50 t=0 0\n         * m=message 20000 TCP/MSRP * a=accept-types:message/cpim application/im-iscomposing+xml\n         * a=accept-wrapped-types:text/plain message/imdn+xml\n         * application/vnd.gsma.rcspushlocation+xml application/vnd.gsma.rcs-ft-http+xml\n         * a=setup:actpass a=path:msrp://192.168.1.50:20000/1458916144436;tcp a=sendrecv\n         */\n        // Parse the remote SDP part\n        String ntpTime = \"3667904944 3667904944\";\n        String ipAddress = \"192.168.1.50\";\n        int localMsrpPort = 20000;\n        String localSocketProtocol = \"TCP/MSRP\";\n        String localMsrpPath = \"msrp://10.29.67.37:20000/1391503972255;tcp\";\n        String localSetup = \"actpass\";\n        String acceptedTypes = \"message/cpim application/im-iscomposing+xml\";\n        String wrappedTypes = \"text/plain message/imdn+xml application/vnd.gsma.rcspushlocation+xml application/vnd.gsma.rcs-ft-http+xml\";\n\n        //@formatter:off\n        String sdp = \"v=0\" + SipUtils.CRLF\n                + \"o=- \" + ntpTime + \" \" + ntpTime + \" \" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF\n                + \"s=-\" + SipUtils.CRLF\n                + \"c=\" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF\n                + \"t=0 0\" + SipUtils.CRLF\n                + \"m=message \" + localMsrpPort + \" \" + localSocketProtocol + \" *\" + SipUtils.CRLF\n                + \"a=path:\" + localMsrpPath + SipUtils.CRLF\n                + \"a=setup:\" + localSetup + SipUtils.CRLF\n                + \"a=accept-types:\" + acceptedTypes + SipUtils.CRLF\n                + \"a=accept-wrapped-types:\" + wrappedTypes + SipUtils.CRLF\n                + \"a=sendrecv\" + SipUtils.CRLF;\n\n        //@formatter:on\n        SdpParser parser = new SdpParser(sdp.getBytes());\n        Vector<MediaDescription> media = parser.getMediaDescriptions();\n        MediaDescription mediaDesc = media.elementAt(0);\n        assertEquals(mediaDesc.getMediaAttribute(\"setup\").getValue(), localSetup);\n        assertEquals(mediaDesc.getMediaAttribute(\"accept-types\").getValue(), acceptedTypes);\n        assertEquals(mediaDesc.getMediaAttribute(\"accept-wrapped-types\").getValue(),\n                wrappedTypes);\n        assertEquals(mediaDesc.getMediaAttribute(\"path\").getValue(), localMsrpPath);\n        assertEquals(mediaDesc.mPort, localMsrpPort);\n        assertEquals(mediaDesc.mProtocol, localSocketProtocol);\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/chat/ConferenceInfoParserTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.chat;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.chat.event.ConferenceInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.event.ConferenceInfoParser;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.test.AndroidTestCase;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\npublic class ConferenceInfoParserTest extends AndroidTestCase {\n    private static Logger sLogger = Logger.getLogger(ConferenceInfoParserTest.class.getName());\n\n    private static final String sXmlContentToParse1 = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n            + \"<conference-info entity=\\\"sips:conf233@example.com\\\" state=\\\"full\\\" version=\\\"1\\\" xmlns=\\\"urn:ietf:params:xml:ns:conference-info\\\">\\n\"\n            + \"\\t<!-- CONFERENCE INFO -->\\n\"\n            + \"\\t<conference-description>\\n\"\n            + \"\\t\\t<subject>Agenda: This month's\\n\"\n            + \"     goals</subject>\\n\"\n            + \"\\t\\t<service-uris>\\n\"\n            + \"\\t\\t\\t<entry>\\n\"\n            + \"\\t\\t\\t\\t<uri>http://sharepoint/salesgroup/</uri>\\n\"\n            + \"\\t\\t\\t\\t<purpose>web-page</purpose>\\n\"\n            + \"\\t\\t\\t</entry>\\n\"\n            + \"\\t\\t</service-uris>\\n\"\n            + \"\\t\\t<maximum-user-count>50</maximum-user-count>\\n\"\n            + \"\\t</conference-description>\\n\"\n            + \"\\t<!-- CONFERENCE STATE-->\\n\"\n            + \"\\t<conference-state>\\n\"\n            + \"\\t\\t<user-count>33</user-count>\\n\"\n            + \"\\t</conference-state>\\n\"\n            + \"\\t<!-- USERS -->\\n\"\n            + \"\\t<users>\\n\"\n            + \"\\t\\t<!-- USER 1 -->\\n\"\n            + \"\\t\\t<user entity=\\\"sip:bob@example.com\\\" state=\\\"full\\\">\\n\"\n            + \"\\t\\t\\t<display-text>Bob Hoskins</display-text>\\n\"\n            + \"\\t\\t\\t<!-- ENDPOINTS -->\\n\"\n            + \"\\t\\t\\t<endpoint entity=\\\"sip:bob@pc33.example.com\\\">\\n\"\n            + \"\\t\\t\\t\\t<display-text>Bob's Laptop</display-text>\\n\"\n            + \"\\t\\t\\t\\t<status>disconnected</status>\\n\"\n            + \"\\t\\t\\t\\t<disconnection-method>departed</disconnection-method>\\n\"\n            + \"\\t\\t\\t\\t<disconnection-info>\\n\"\n            + \"\\t\\t\\t\\t\\t<when>2005-03-04T20:00:00Z</when>\\n\"\n            + \"\\t\\t\\t\\t\\t<reason>bad voice quality</reason>\\n\"\n            + \"\\t\\t\\t\\t\\t<by>sip:mike@example.com</by>\\n\"\n            + \"\\t\\t\\t\\t</disconnection-info>\\n\"\n            + \"\\t\\t\\t\\t<!-- MEDIA -->\\n\"\n            + \"\\t\\t\\t\\t<media id=\\\"1\\\">\\n\"\n            + \"\\t\\t\\t\\t\\t<display-text>main audio</display-text>\\n\"\n            + \"\\t\\t\\t\\t\\t<type>audio</type>\\n\"\n            + \"\\t\\t\\t\\t\\t<label>34567</label>\\n\"\n            + \"\\t\\t\\t\\t\\t<src-id>432424</src-id>\\n\"\n            + \"\\t\\t\\t\\t\\t<status>sendrecv</status>\\n\"\n            + \"\\t\\t\\t\\t</media>\\n\"\n            + \"\\t\\t\\t</endpoint>\\n\"\n            + \"\\t\\t</user>\\n\"\n            + \"\\t\\t<!-- USER 2-->\\n\"\n            + \"\\t\\t<user entity=\\\"sip:alice@example.com\\\" state=\\\"full\\\">\\n\"\n            + \"\\t\\t\\t<display-text>Alice</display-text>\\n\"\n            + \"\\t\\t\\t<!-- ENDPOINTS -->\\n\"\n            + \"\\t\\t\\t<endpoint entity=\\\"sip:4kfk4j392jsu@example.com;grid=433kj4j3u\\\">\\n\"\n            + \"\\t\\t\\t\\t<status>connected</status>\\n\"\n            + \"\\t\\t\\t\\t<joining-method>dialed-out</joining-method>\\n\"\n            + \"\\t\\t\\t\\t<joining-info>\\n\"\n            + \"\\t\\t\\t\\t\\t<when>2005-03-04T20:00:00Z</when>\\n\"\n            + \"\\t\\t\\t\\t\\t<by>sip:mike@example.com</by>\\n\"\n            + \"\\t\\t\\t\\t</joining-info>\\n\"\n            + \"\\t\\t\\t\\t<!-- MEDIA-->\\n\"\n            + \"\\t\\t\\t\\t<media id=\\\"1\\\">\\n\"\n            + \"\\t\\t\\t\\t\\t<display-text>main audio</display-text>\\n\"\n            + \"\\t\\t\\t\\t\\t<type>audio</type>\\n\"\n            + \"\\t\\t\\t\\t\\t<label>34567</label>\\n\"\n            + \"\\t\\t\\t\\t\\t<src-id>534232</src-id>\\n\"\n            + \"\\t\\t\\t\\t\\t<status>sendrecv</status>\\n\"\n            + \"\\t\\t\\t\\t</media>\\n\"\n            + \"\\t\\t\\t</endpoint>\\n\"\n            + \"\\t\\t</user>\\n\"\n            + \"\\t</users>\\n\"\n            + \"</conference-info>\";\n\n\n    public void testGetConferenceInfo() throws ParserConfigurationException, SAXException,\n            IOException, ParseFailureException {\n\n        ConferenceInfoParser parser = new ConferenceInfoParser(new InputSource(\n                new ByteArrayInputStream(sXmlContentToParse1.getBytes())));\n        parser.parse();\n        ConferenceInfoDocument confInfoDoc = parser.getConferenceInfo();\n\n        if (sLogger.isActivated()) {\n            sLogger.info(\"conference info URI = \" + confInfoDoc.getEntity());\n            sLogger.info(\"conference info state = \" + confInfoDoc.getState());\n            sLogger.info(\"conference info users = \" + confInfoDoc.getUserCount());\n        }\n        assertEquals(confInfoDoc.getEntity(), \"sips:conf233@example.com\");\n        assertEquals(confInfoDoc.getState(), \"full\");\n        assertEquals(confInfoDoc.getMaxUserCount(), 50);\n        assertEquals(confInfoDoc.getUserCount(), 33);\n\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/chat/ImdnParserTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010 France Telecom S.A.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.chat;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnParser;\nimport com.gsma.rcs.utils.DateUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.test.AndroidTestCase;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\npublic class ImdnParserTest extends AndroidTestCase {\n    private static Logger sLogger = Logger.getLogger(ImdnParserTest.class.getName());\n\n    private static final String sXmlContentToParse = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n            + \"<imdn xmlns=\\\"urn:ietf:params:xml:ns:imdn\\\">\\n\"\n            + \"\\t<message-id>34jk324j</message-id>\\n\"\n            + \"\\t<datetime>2008-04-04T12:16:49-05:00</datetime>\\n\" + \"\\t<display-notification>\\n\"\n            + \"\\t\\t<status>\\n\" + \"\\t\\t\\t<displayed/>\\n\" + \"\\t\\t</status>\\n\"\n            + \"\\t</display-notification>\\n\" + \"</imdn>\";\n\n    public void testGetImdnDocument() throws SAXException, ParserConfigurationException,\n            IOException, ParseFailureException {\n        ImdnParser parser = new ImdnParser(new InputSource(new ByteArrayInputStream(\n                sXmlContentToParse.getBytes())));\n        parser.parse();\n        ImdnDocument imdnDoc = parser.getImdnDocument();\n        if (sLogger.isActivated()) {\n            sLogger.info(\"MsgId=\" + imdnDoc.getMsgId() + \"  status=\" + imdnDoc.getStatus());\n        }\n        assertEquals(\"34jk324j\", imdnDoc.getMsgId());\n        assertEquals(\"displayed\", imdnDoc.getStatus().toString());\n        assertEquals(\"display-notification\", imdnDoc.getNotificationType());\n        assertEquals(DateUtils.decodeDate(\"2008-04-04T12:16:49-05:00\"), imdnDoc.getDateTime());\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/chat/IsComposingParserTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n **\n /**\n * Created by yplo6403 on 24/02/2016.\n */\npackage com.gsma.rcs.chat;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.chat.iscomposing.IsComposingInfo;\nimport com.gsma.rcs.core.ims.service.im.chat.iscomposing.IsComposingParser;\nimport com.gsma.rcs.utils.DateUtils;\n\nimport android.test.AndroidTestCase;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\npublic class IsComposingParserTest extends AndroidTestCase {\n\n    private static final String sXmlContentToParse1 = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n            + \"        <isComposing xmlns=\\\"urn:ietf:params:xml:ns:im-iscomposing\\\"\"\n            + \"        xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"\"\n            + \"        xsi:schemaLocation=\\\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\\\">\"\n            + \"            <state>active</state>\"\n            + \"            <contenttype>text/plain</contenttype>\"\n            + \"            <lastactive>2012-02-22T17:53:49.000Z</lastactive>\"\n            + \"            <refresh>60</refresh>\" + \"    </isComposing>\";\n\n    private static final String sXmlContentToParse2 = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n            + \"        <isComposing xmlns=\\\"urn:ietf:params:xml:ns:im-iscomposing\\\"\"\n            + \"        xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"\"\n            + \"        xsi:schemaLocation=\\\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\\\">\"\n            + \"            <state>idle</state>\"\n            + \"            <contenttype>text/plain</contenttype>\"\n            + \"            <lastactive>2012-02-22T17:53:49.000Z</lastactive>\"\n            + \"            <refresh>60</refresh>\" + \"    </isComposing>\";\n\n    public void testIsComposingParserActive() throws ParseFailureException, SAXException,\n            ParserConfigurationException {\n        IsComposingParser parser = new IsComposingParser(new InputSource(new ByteArrayInputStream(\n                sXmlContentToParse1.getBytes())));\n        parser.parse();\n        IsComposingInfo info = parser.getIsComposingInfo();\n        assertEquals(\"text/plain\", info.getContentType());\n        assertEquals(60000, info.getRefreshTime());\n        assertEquals(true, info.isStateActive());\n        assertEquals(DateUtils.decodeDate(\"2012-02-22T17:53:49.000Z\"), info.getLastActiveDate());\n    }\n\n    public void testIsComposingParserIdle() throws ParseFailureException, SAXException,\n            ParserConfigurationException {\n        IsComposingParser parser = new IsComposingParser(new InputSource(new ByteArrayInputStream(\n                sXmlContentToParse2.getBytes())));\n        parser.parse();\n        IsComposingInfo info = parser.getIsComposingInfo();\n        assertEquals(\"text/plain\", info.getContentType());\n        assertEquals(60000, info.getRefreshTime());\n        assertEquals(false, info.isStateActive());\n        assertEquals(DateUtils.decodeDate(\"2012-02-22T17:53:49.000Z\"), info.getLastActiveDate());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/chat/ResourceListParserTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.chat;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.chat.resourcelist.ResourceListDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.resourcelist.ResourceListParser;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.test.AndroidTestCase;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\npublic class ResourceListParserTest extends AndroidTestCase {\n    private static final String sXmlContentToParse1 = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n            + \"<resource-lists xmlns=\\\"urn:ietf:params:xml:ns:resource-lists\\\" xmlns:cp=\\\"urn:ietf:params:xml:ns:copycontrol\\\">\\n\"\n            + \"\\t<list>\\n\"\n            + \"\\t\\t<entry cp:copyControl=\\\"to\\\" uri=\\\"sip:bill@example.com\\\"/>\\n\"\n            + \"\\t\\t<entry cp:copyControl=\\\"cc\\\" uri=\\\"sip:joe@example.org\\\"/>\\n\"\n            + \"\\t\\t<entry cp:copyControl=\\\"bcc\\\" uri=\\\"sip:ted@example.net\\\"/>\\n\"\n            + \"\\t</list>\\n\"\n            + \"</resource-lists>\";\n\n    private Logger logger = Logger.getLogger(this.getClass().getName());\n\n    public void testGetResourceListDocument() throws ParserConfigurationException, SAXException,\n            IOException, ParseFailureException {\n\n        ResourceListParser parser = new ResourceListParser(new InputSource(\n                new ByteArrayInputStream(sXmlContentToParse1.getBytes())));\n        parser.parse();\n        ResourceListDocument rlistDoc = parser.getResourceList();\n        if (logger.isActivated()) {\n            if (rlistDoc.getEntries() != null) {\n                logger.info(\"resources number = \" + rlistDoc.getEntries().size());\n            } else {\n                logger.info(\"resources list is null\");\n            }\n        }\n        assertTrue(rlistDoc.getEntries().contains(\"sip:bill@example.com\"));\n        assertTrue(rlistDoc.getEntries().contains(\"sip:joe@example.org\"));\n        assertTrue(rlistDoc.getEntries().contains(\"sip:ted@example.net\"));\n\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/contact/ContactManagerTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.contact;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.core.FileAccessException;\nimport com.gsma.rcs.core.ims.service.ContactInfo;\nimport com.gsma.rcs.core.ims.service.ContactInfo.BlockingState;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RcsStatus;\nimport com.gsma.rcs.core.ims.service.ContactInfo.RegistrationState;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities;\nimport com.gsma.rcs.core.ims.service.capability.Capabilities.CapabilitiesBuilder;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactManager;\nimport com.gsma.rcs.provider.contact.ContactManagerException;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.test.AndroidTestCase;\n\nimport java.util.Arrays;\nimport java.util.Random;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class ContactManagerTest extends AndroidTestCase {\n\n    private static final Logger sLogger = Logger.getLogger(ContactManagerTest.class.getName());\n    private ContactManager mContactManager;\n    private ContactId mContact;\n    private Random mRandom;\n    private RcsSettings mRcsSettings;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Context context = getContext();\n        ContentResolver contentResolver = context.getContentResolver();\n        LocalContentResolver localContentResolver = new LocalContentResolver(contentResolver);\n        mRcsSettings = RcsSettingsMock.getMockSettings(context);\n        mContactManager = ContactManager.getInstance(context, contentResolver,\n                localContentResolver, mRcsSettings);\n        ContactUtil contactUtils = ContactUtil.getInstance(new ContactUtilMockContext(context));\n        mContact = contactUtils.formatContact(\"+33633139785\");\n        mRandom = new Random();\n    }\n\n    protected void tearDown() throws Exception {\n        mContactManager.cleanRCSEntries();\n        RcsSettingsMock.restoreSettings();\n        super.tearDown();\n    }\n\n    public void testCreateMyContact() throws ContactManagerException {\n        long myraw = mContactManager.createMyContact();\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"my rawId = \".concat(Long.toString(myraw)));\n        }\n        if (mRcsSettings.isSocialPresenceSupported()) {\n            assertTrue(ContactManager.INVALID_ID != myraw);\n        }\n    }\n\n    public void testGetRcsContactInfo() throws ContactManagerException, FileAccessException {\n        CapabilitiesBuilder expectedCapa = createRcsContact();\n        ContactInfo getInfo = mContactManager.getContactInfo(mContact);\n        assertNotNull(getInfo);\n        /* Compare getContactInfo informations and initial informations */\n        Capabilities getCapa = getInfo.getCapabilities();\n        assertNotNull(getCapa);\n        assertEquals(expectedCapa.isCsVideoSupported(), getCapa.isCsVideoSupported());\n        assertEquals(expectedCapa.isFileTransferMsrpSupported(),\n                getCapa.isFileTransferMsrpSupported());\n        assertEquals(expectedCapa.isFileTransferHttpSupported(),\n                getCapa.isFileTransferHttpSupported());\n        assertEquals(expectedCapa.isImageSharingSupported(), getCapa.isImageSharingSupported());\n        assertEquals(expectedCapa.isImSessionSupported(), getCapa.isImSessionSupported());\n        assertEquals(expectedCapa.isPresenceDiscovery(), getCapa.isPresenceDiscoverySupported());\n        assertEquals(expectedCapa.isSocialPresence(), getCapa.isSocialPresenceSupported());\n        assertEquals(expectedCapa.isVideoSharingSupported(), getCapa.isVideoSharingSupported());\n        assertEquals(expectedCapa.isSipAutomata(), getCapa.isSipAutomata());\n        assertEquals(expectedCapa.getTimestampOfLastRequest(), getCapa.getTimestampOfLastResponse());\n        assertEquals(expectedCapa.getTimestampOfLastRequest(), getCapa.getTimestampOfLastRequest());\n        Set<String> extensions = getCapa.getSupportedExtensions();\n        assertNotNull(extensions);\n        assertTrue(extensions.contains(\"MyRcsExtensionTag1\"));\n        assertTrue(extensions.contains(\"MyRcsExtensionTag2\"));\n        assertEquals(RcsStatus.RCS_CAPABLE, getInfo.getRcsStatus());\n        assertEquals(RegistrationState.ONLINE, getInfo.getRegistrationState());\n    }\n\n    public void testGetContactCapabilities() throws ContactManagerException, FileAccessException {\n        CapabilitiesBuilder expectedCapa = createRcsContact();\n        Capabilities getCapa = mContactManager.getContactCapabilities(mContact);\n        assertNotNull(getCapa);\n        assertEquals(expectedCapa.isCsVideoSupported(), getCapa.isCsVideoSupported());\n        assertEquals(expectedCapa.isFileTransferMsrpSupported(),\n                getCapa.isFileTransferMsrpSupported());\n        assertEquals(expectedCapa.isFileTransferHttpSupported(),\n                getCapa.isFileTransferHttpSupported());\n        assertEquals(expectedCapa.isImageSharingSupported(), getCapa.isImageSharingSupported());\n        assertEquals(expectedCapa.isImSessionSupported(), getCapa.isImSessionSupported());\n        assertEquals(expectedCapa.isPresenceDiscovery(), getCapa.isPresenceDiscoverySupported());\n        assertEquals(expectedCapa.isSocialPresence(), getCapa.isSocialPresenceSupported());\n        assertEquals(expectedCapa.isVideoSharingSupported(), getCapa.isVideoSharingSupported());\n        assertEquals(expectedCapa.isSipAutomata(), getCapa.isSipAutomata());\n        assertEquals(expectedCapa.getTimestampOfLastRequest(), getCapa.getTimestampOfLastResponse());\n        assertEquals(expectedCapa.getTimestampOfLastRequest(), getCapa.getTimestampOfLastRequest());\n        Set<String> extensions = getCapa.getSupportedExtensions();\n        assertNotNull(extensions);\n        assertTrue(extensions.contains(\"MyRcsExtensionTag1\"));\n        assertTrue(extensions.contains(\"MyRcsExtensionTag2\"));\n    }\n\n    public void testDisplayName() throws ContactManagerException, FileAccessException {\n        createRcsContact();\n        String displayName = UUID.randomUUID().toString();\n        mContactManager.setContactDisplayName(mContact, displayName);\n        assertEquals(displayName, mContactManager.getContactDisplayName(mContact));\n    }\n\n    public void testUpdateCapabilitiesTimeLastRequest() throws InterruptedException,\n            ContactManagerException, FileAccessException {\n        createRcsContact();\n        Capabilities oldCapa = mContactManager.getContactCapabilities(mContact);\n        /*\n         * A timer greater than 1 second is set because some emulator have only an accuracy of 1\n         * second.\n         */\n        Thread.sleep(1010);\n        mContactManager.updateCapabilitiesTimeLastRequest(mContact);\n        Capabilities newCapa = mContactManager.getContactCapabilities(mContact);\n        assertNotNull(newCapa);\n        assertNotNull(oldCapa);\n        assertTrue(newCapa.getTimestampOfLastRequest() > oldCapa.getTimestampOfLastRequest());\n    }\n\n    public void testUpdateCapabilitiesTimeLastResponse() throws InterruptedException,\n            ContactManagerException, FileAccessException {\n        createRcsContact();\n        Capabilities oldCapa = mContactManager.getContactCapabilities(mContact);\n        /*\n         * A timer greater than 1 second is set because some emulator have only an accuracy of 1\n         * second.\n         */\n        Thread.sleep(1010);\n        mContactManager.updateCapabilitiesTimeLastResponse(mContact, System.currentTimeMillis());\n        Capabilities newCapa = mContactManager.getContactCapabilities(mContact);\n        assertNotNull(newCapa);\n        assertNotNull(oldCapa);\n        assertTrue(newCapa.getTimestampOfLastResponse() > oldCapa.getTimestampOfLastResponse());\n    }\n\n    public void testBlockedContact() throws ContactManagerException, FileAccessException {\n        createRcsContact();\n        mContactManager.setBlockingState(mContact, BlockingState.BLOCKED);\n        assertTrue(mContactManager.isBlockedForContact(mContact));\n    }\n\n    public CapabilitiesBuilder createRcsContact() throws ContactManagerException,\n            FileAccessException {\n        long now = System.currentTimeMillis();\n        CapabilitiesBuilder capaBuilder = new CapabilitiesBuilder();\n        /*\n         * For capabilities which do not depend on provisioning, support is chosen randomly.\n         */\n        capaBuilder.setCsVideo(false);\n        capaBuilder.setGeolocationPush(mRandom.nextBoolean());\n        capaBuilder.setGeolocationPush(mRandom.nextBoolean());\n        capaBuilder.setIpVideoCall(mRandom.nextBoolean());\n        capaBuilder.setIpVoiceCall(mRandom.nextBoolean());\n        capaBuilder.setGroupChatStoreForward(mRandom.nextBoolean());\n        capaBuilder.setFileTransferThumbnail(true);\n        capaBuilder.setFileTransferHttp(true);\n        capaBuilder.setFileTransferMsrp(true);\n        capaBuilder.setImageSharing(mRandom.nextBoolean());\n        capaBuilder.setImSession(true);\n        capaBuilder.setPresenceDiscovery(mRandom.nextBoolean());\n        capaBuilder.setSocialPresence(mRandom.nextBoolean());\n        capaBuilder.setVideoSharing(mRandom.nextBoolean());\n        capaBuilder.setTimestampOfLastRequest(now);\n        capaBuilder.addExtension(\"MyRcsExtensionTag1\");\n        capaBuilder.addExtension(\"MyRcsExtensionTag2\");\n        capaBuilder.setSipAutomata(mRandom.nextBoolean());\n        capaBuilder.setTimestampOfLastResponse(now);\n        /* This will create a RCS contact with default presence information */\n        mContactManager.setContactCapabilities(mContact, capaBuilder.build(),\n                RcsStatus.RCS_CAPABLE, RegistrationState.ONLINE);\n        return capaBuilder;\n    }\n\n    public void testDeleteRCSEntries() throws ContactManagerException, FileAccessException {\n        createRcsContact();\n        Set<ContactId> contacts = mContactManager.getAllContactsFromRcsContactProvider();\n        assertTrue(!contacts.isEmpty());\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"All contacts=\".concat(Arrays.toString(contacts.toArray())));\n        }\n        mContactManager.deleteRCSEntries();\n        assertTrue(mContactManager.getAllContactsFromRcsContactProvider().isEmpty());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/cpim/CpimIdentityTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.cpim;\n\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimIdentity;\n\nimport android.test.InstrumentationTestCase;\n\npublic class CpimIdentityTest extends InstrumentationTestCase {\n\n    public void testInvalidUri() {\n        String uri = \"im:pooh@100akerwood.com\";\n        try {\n            new CpimIdentity(uri);\n            fail(\"Failed to detect unknown URI (\" + uri + \")\");\n\n        } catch (Exception e) {\n            assertTrue(e instanceof IllegalArgumentException);\n        }\n    }\n\n    public void testSipUri() {\n        String uri = \"sip:user@domain.com\";\n        CpimIdentity id = new CpimIdentity(\"<\" + uri + \">\");\n        assertNull(id.getDisplayName());\n        assertEquals(uri, id.getUri());\n    }\n\n    public void testTelUriWithDisplayName() {\n        String displayName = \"\\\"Winnie the Pooh\\\"\";\n        String uri = \"tel:+33674538159\";\n        CpimIdentity id = new CpimIdentity(displayName + \" <\" + uri + \">\");\n        assertEquals(\"Winnie the Pooh\", id.getDisplayName());\n        assertEquals(uri, id.getUri());\n    }\n\n    public void testTelUriWithDisplayNameBis() {\n        String displayName = \"Winnie the Pooh\";\n        String uri = \"tel:+33674538159\";\n        CpimIdentity id = new CpimIdentity(displayName + \" <\" + uri + \">\");\n        assertEquals(displayName, id.getDisplayName());\n        assertEquals(uri, id.getUri());\n    }\n\n    public void testTelUriWithAcceptContact() {\n        String displayName = \"Winnie the Pooh\";\n        String uri = \"tel:+33674538159\";\n        String acceptContact = \"%2Bsip.instance%3D%22%3Curn%3Agsma%3Aimei%3A35824005-944763-1%3E%22\";\n        CpimIdentity id = new CpimIdentity(displayName + \" <\" + uri + \"?Accept-Contact=\"\n                + acceptContact + \">\");\n        assertEquals(\"Winnie the Pooh\", id.getDisplayName());\n        assertEquals(\"tel:+33674538159?Accept-Contact=\" + acceptContact, id.getUri());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/cpim/CpimParserTest.java",
    "content": "\npackage com.gsma.rcs.cpim;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.core.ims.network.sip.Multipart;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.cpim.CpimParser;\nimport com.gsma.rcs.core.ims.service.im.chat.imdn.ImdnUtils;\n\nimport android.test.AndroidTestCase;\n\n/*******************************************************************************\n * Software Name : RCS IMS Stack Copyright (C) 2010-2016 Orange. Licensed under the Apache License,\n * Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You\n * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by\n * applicable law or agreed to in writing, software distributed under the License is distributed on\n * an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See\n * the License for the specific language governing permissions and limitations under the License.\n ******************************************************************************/\npublic class CpimParserTest extends AndroidTestCase {\n    // @formatter:off\n    private static final String sCpimToTest =\n            \"From: <sip:anonymous@anonymous.invalid>\" + SipUtils.CRLF +\n                    \"To: <sip:anonymous@anonymous.invalid>\" + SipUtils.CRLF +\n                    \"NS: imdn <urn:ietf:params:imdn>\" + SipUtils.CRLF +\n                    \"imdn.Message-ID: ae6926cfcffa40a89e44252ce9e970a2\" + SipUtils.CRLF +\n                    \"DateTime: 2016-03-24T08:51:42+01:00\"+SipUtils.CRLF+\n                    \"imdn.Disposition-Notification: positive-delivery\"+SipUtils.CRLF +\n                    SipUtils.CRLF+\n                    \"Content-type: text/plain;charset=utf-8\"+SipUtils.CRLF+\n                    \"Content-length: 7\"+SipUtils.CRLF+\n                    SipUtils.CRLF+\n                    \"Bonjour\";\n\n    private static final String sCpimToTestWithBlankContent =\n            \"From: <sip:anonymous@anonymous.invalid>\" + SipUtils.CRLF +\n                    \"To: <sip:anonymous@anonymous.invalid>\" + SipUtils.CRLF +\n                    \"NS: imdn <urn:ietf:params:imdn>\" + SipUtils.CRLF +\n                    \"imdn.Message-ID: ae6926cfcffa40a89e44252ce9e970a2\" + SipUtils.CRLF +\n                    \"DateTime: 2016-03-24T08:51:42+01:00\"+SipUtils.CRLF+\n                    \"imdn.Disposition-Notification: positive-delivery\"+SipUtils.CRLF +\n                    SipUtils.CRLF+\n                    \"Content-type: text/plain;charset=utf-8\"+SipUtils.CRLF+\n                    \"Content-length: 2\"+SipUtils.CRLF+\n                    SipUtils.CRLF+\n                    \"  \";\n\n    private static final String sMultipartsBoundary = \"----=_Part_3144_497651830.1459426876307\";\n    private static final String sMultiparts =\n            \"------=_Part_3144_497651830.1459426876307\" + SipUtils.CRLF +\n                    \"Content-Type: application/sdp\" + SipUtils.CRLF +\n                    \"Content-Length: 325\" + SipUtils.CRLF +\n                    SipUtils.CRLF +\n                    \"v=0\" + SipUtils.CRLF +\n                    \"o=- 0 0 IN IP4 sip.imsnsn.fr\" + SipUtils.CRLF +\n                    \"s= \" + SipUtils.CRLF +\n                    \"c=IN IP4 80.12.197.204\" + SipUtils.CRLF +\n                    \"t=0 0\" + SipUtils.CRLF +\n                    \"m=message 53358 TCP/MSRP *\" + SipUtils.CRLF +\n                    \"a=accept-types:message/cpim application/im-iscomposing+xml\" + SipUtils.CRLF +\n                    \"a=accept-wrapped-types:text/plain message/imdn+xml application/vnd.gsma.rcs-ft-http+xml\" + SipUtils.CRLF +\n                    \"a=setup:actpass\" + SipUtils.CRLF +\n                    \"a=path:msrp://80.12.197.204:53358/b29w5mku;tcp\" + SipUtils.CRLF +\n                    \"a=sendrecv\" + SipUtils.CRLF +\n                    SipUtils.CRLF +\n                    \"------=_Part_3144_497651830.1459426876307\" + SipUtils.CRLF +\n                    \"Content-Type: message/cpim\" + SipUtils.CRLF +\n                    SipUtils.CRLF +\n                    \"From: <sip:anonymous@anonymous.invalid>\" + SipUtils.CRLF +\n                    \"To: <sip:anonymous@anonymous.invalid>\" + SipUtils.CRLF +\n                    \"NS: imdn <urn:ietf:params:imdn>\" + SipUtils.CRLF +\n                    \"imdn.Message-ID: dd4167b82b864c6ea9def42deada1b54\" + SipUtils.CRLF +\n                    \"DateTime: 2016-03-31T14:21:16+02:00\" + SipUtils.CRLF +\n                    \"imdn.Disposition-Notification: positive-delivery, display\" + SipUtils.CRLF +\n                    SipUtils.CRLF +\n                    \"Content-type: text/plain;charset=utf-8\" + SipUtils.CRLF +\n                    \"Content-length: 3\" + SipUtils.CRLF +\n                    SipUtils.CRLF +\n                    \"   \"+SipUtils.CRLF +\n                    \"------=_Part_3144_497651830.1459426876307--\" + SipUtils.CRLF;\n    // @formatter:on\n\n    public final void testCpimParserString() {\n        CpimMessage msg = (new CpimParser(sCpimToTest)).getCpimMessage();\n        assertEquals(\"<sip:anonymous@anonymous.invalid>\", msg.getHeader(\"From\"));\n        assertEquals(\"<sip:anonymous@anonymous.invalid>\", msg.getHeader(\"To\"));\n        assertEquals(\"imdn <urn:ietf:params:imdn>\", msg.getHeader(CpimMessage.HEADER_NS));\n        assertEquals(\"2016-03-24T08:51:42+01:00\", msg.getHeader(\"DateTime\"));\n        assertEquals(\"text/plain;charset=utf-8\", msg.getContentType());\n        assertEquals(\"positive-delivery\", msg.getHeader(ImdnUtils.HEADER_IMDN_DISPO_NOTIF));\n        assertEquals(\"ae6926cfcffa40a89e44252ce9e970a2\",\n                msg.getHeader(ImdnUtils.HEADER_IMDN_MSG_ID));\n        assertEquals(\"Bonjour\", msg.getMessageContent());\n        assertEquals(\"7\", msg.getContentHeader(CpimMessage.HEADER_CONTENT_LENGTH));\n        assertEquals(\"text/plain;charset=utf-8\",\n                msg.getContentHeader(CpimMessage.HEADER_CONTENT_TYPE));\n    }\n\n    public final void testCpimParserStringWithBlankContent() {\n        CpimMessage msg = (new CpimParser(sCpimToTestWithBlankContent)).getCpimMessage();\n        assertEquals(\"<sip:anonymous@anonymous.invalid>\", msg.getHeader(\"From\"));\n        assertEquals(\"<sip:anonymous@anonymous.invalid>\", msg.getHeader(\"To\"));\n        assertEquals(\"imdn <urn:ietf:params:imdn>\", msg.getHeader(CpimMessage.HEADER_NS));\n        assertEquals(\"2016-03-24T08:51:42+01:00\", msg.getHeader(\"DateTime\"));\n        assertEquals(\"text/plain;charset=utf-8\", msg.getContentType());\n        assertEquals(\"positive-delivery\", msg.getHeader(ImdnUtils.HEADER_IMDN_DISPO_NOTIF));\n        assertEquals(\"ae6926cfcffa40a89e44252ce9e970a2\",\n                msg.getHeader(ImdnUtils.HEADER_IMDN_MSG_ID));\n        assertEquals(\"  \", msg.getMessageContent());\n        assertEquals(\"2\", msg.getContentHeader(CpimMessage.HEADER_CONTENT_LENGTH));\n        assertEquals(\"text/plain;charset=utf-8\",\n                msg.getContentHeader(CpimMessage.HEADER_CONTENT_TYPE));\n    }\n\n    public final void testMultipart() {\n        Multipart multipart = new Multipart(sMultiparts, sMultipartsBoundary);\n        assertTrue(multipart.isMultipart());\n        String cpimPart = multipart.getPart(CpimMessage.MIME_TYPE);\n        CpimParser parser = new CpimParser(cpimPart.getBytes(UTF8));\n        CpimMessage cpim = parser.getCpimMessage();\n        assertEquals(\"   \", cpim.getMessageContent());\n        assertEquals(\"text/plain;charset=utf-8\", cpim.getContentType());\n        assertEquals(\"3\", cpim.getContentHeader(\"Content-length\"));\n        assertEquals(\"positive-delivery, display\", cpim.getHeader(\"imdn.Disposition-Notification\"));\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/dns/DnsTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.dns;\n\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.test.AndroidTestCase;\n\nimport org.xbill.DNS.Lookup;\nimport org.xbill.DNS.NAPTRRecord;\nimport org.xbill.DNS.Record;\nimport org.xbill.DNS.SRVRecord;\nimport org.xbill.DNS.TextParseException;\nimport org.xbill.DNS.Type;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport javax2.sip.ListeningPoint;\n\npublic class DnsTest extends AndroidTestCase {\n\n    private static Logger sLogger = Logger.getLogger(DnsTest.class.getName());\n\n    public void testDnsLib() {\n        String domain = \"rcs.lannion.com\";\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"DNS NAPTR lookup for \" + domain);\n            }\n            Lookup lookup = new Lookup(domain, Type.NAPTR);\n            lookup.setCache(null);\n            lookup.run();\n            int code = lookup.getResult();\n            if (code != Lookup.SUCCESSFUL) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Lookup error: \" + code + \"/\" + lookup.getErrorString());\n                }\n            }\n        } catch (TextParseException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not a valid DNS name\");\n            }\n        } catch (IllegalArgumentException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not a valid DNS type\");\n            }\n        }\n    }\n\n    public void testDnsResolution() {\n        resolveImsProxyConfiguration(\"rcs.lannion.com\", ListeningPoint.TCP);\n    }\n\n    private void resolveImsProxyConfiguration(String imsProxyAddr, String imsProxyProtocol) {\n        int imsProxyPort = -1;\n\n        // First try to resolve via a NAPTR query, then a SRV\n        // query and finally via A query\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Resolve IMS proxy address...\");\n        }\n        String ipAddress = null;\n\n        // DNS NAPTR lookup\n        String service = null;\n        if (imsProxyProtocol.equalsIgnoreCase(ListeningPoint.UDP)) {\n            service = \"SIP+D2U\";\n        } else if (imsProxyProtocol.equalsIgnoreCase(ListeningPoint.TCP)) {\n            service = \"SIP+D2T\";\n        } else if (imsProxyProtocol.equalsIgnoreCase(ListeningPoint.TLS)) {\n            service = \"SIPS+D2T\";\n        }\n        Record[] naptrRecords = getDnsNAPTR(imsProxyAddr);\n        if ((naptrRecords != null) && (naptrRecords.length > 0)) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"NAPTR records found: \" + naptrRecords.length);\n            }\n            for (Record naptrRecord : naptrRecords) {\n                NAPTRRecord naptr = (NAPTRRecord) naptrRecord;\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"NAPTR record: \" + naptr.toString());\n                }\n                if ((naptr != null) && naptr.getService().equalsIgnoreCase(service)) {\n                    // DNS SRV lookup\n                    Record[] srvRecords = getDnsSRV(naptr.getReplacement().toString());\n                    if ((srvRecords != null) && (srvRecords.length > 0)) {\n                        SRVRecord srvRecord = getBestDnsSRV(srvRecords);\n                        ipAddress = getDnsA(srvRecord.getTarget().toString());\n                        imsProxyPort = srvRecord.getPort();\n                    } else {\n                        // Direct DNS A lookup\n                        ipAddress = getDnsA(imsProxyAddr);\n                    }\n                }\n            }\n        } else {\n            // Direct DNS SRV lookup\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"No NAPTR record found: use DNS SRV instead\");\n            }\n            String query;\n            if (imsProxyAddr.startsWith(\"_sip.\")) {\n                query = imsProxyAddr;\n            } else {\n                query = \"_sip._\" + imsProxyProtocol.toLowerCase() + \".\" + imsProxyAddr;\n            }\n            Record[] srvRecords = getDnsSRV(query);\n            if ((srvRecords != null) && (srvRecords.length > 0)) {\n                SRVRecord srvRecord = getBestDnsSRV(srvRecords);\n                ipAddress = getDnsA(srvRecord.getTarget().toString());\n                imsProxyPort = srvRecord.getPort();\n            } else {\n                // Direct DNS A lookup\n                if (sLogger.isActivated()) {\n                    sLogger.debug(\"No SRV record found: use DNS A instead\");\n                }\n                ipAddress = getDnsA(imsProxyAddr);\n            }\n        }\n\n        imsProxyAddr = ipAddress;\n\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"SIP outbound proxy configuration: \" + imsProxyAddr + \":\" + imsProxyPort\n                    + \";\" + imsProxyProtocol);\n        }\n    }\n\n    private Record[] getDnsNAPTR(String domain) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"DNS NAPTR lookup for \" + domain);\n            }\n            Lookup lookup = new Lookup(domain, Type.NAPTR);\n            lookup.setCache(null);\n            Record[] result = lookup.run();\n            int code = lookup.getResult();\n            if (code != Lookup.SUCCESSFUL) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Lookup error: \" + code + \"/\" + lookup.getErrorString());\n                }\n            }\n            return result;\n        } catch (TextParseException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not a valid DNS name\");\n            }\n            return null;\n        } catch (IllegalArgumentException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not a valid DNS type\");\n            }\n            return null;\n        }\n    }\n\n    private Record[] getDnsSRV(String domain) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"DNS SRV lookup for \" + domain);\n            }\n            Lookup lookup = new Lookup(domain, Type.SRV);\n            lookup.setCache(null);\n            Record[] result = lookup.run();\n            int code = lookup.getResult();\n            if (code != Lookup.SUCCESSFUL) {\n                if (sLogger.isActivated()) {\n                    sLogger.warn(\"Lookup error: \" + code + \"/\" + lookup.getErrorString());\n                }\n            }\n            return result;\n        } catch (TextParseException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not a valid DNS name\");\n            }\n            return null;\n        } catch (IllegalArgumentException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Not a valid DNS type\");\n            }\n            return null;\n        }\n    }\n\n    private String getDnsA(String domain) {\n        try {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"DNS A lookup for \" + domain);\n            }\n            return InetAddress.getByName(domain).getHostAddress();\n        } catch (UnknownHostException e) {\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"Unknown host for \" + domain);\n            }\n            return null;\n        }\n    }\n\n    private SRVRecord getBestDnsSRV(Record[] records) {\n        SRVRecord result = null;\n        for (Record record : records) {\n            SRVRecord srv = (SRVRecord) record;\n            if (sLogger.isActivated()) {\n                sLogger.debug(\"SRV record: \" + srv.toString());\n            }\n            if (result == null) {\n                // First record\n                result = srv;\n            } else {\n                // Next record\n                if (srv.getPriority() < result.getPriority()) {\n                    // Lowest priority\n                    result = srv;\n                } else if (srv.getPriority() == result.getPriority()) {\n                    // Highest weight\n                    if (srv.getWeight() > result.getWeight()) {\n                        result = srv;\n                    }\n                }\n            }\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/chat/ChatLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.chat;\n\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.Context;\nimport android.test.AndroidTestCase;\n\nimport java.util.AbstractMap;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ChatLogTest extends AndroidTestCase {\n\n    private Context mContext;\n\n    private ContactUtil mContactUtils;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        mContext = getContext();\n        mContactUtils = ContactUtil.getInstance(new ContactUtilMockContext(mContext));\n    }\n\n\n    public void testGetParticipants() throws RcsPermissionDeniedException {\n        Map<ContactId, ParticipantStatus> participants;\n        participants = ChatLog.GroupChat.getParticipants(mContext, \"+330123=3,+330124=5\");\n        assertNotNull(participants);\n        assertEquals(2, participants.size());\n\n        ContactId contact1 = mContactUtils.formatContact(\"+330123\");\n        AbstractMap.SimpleEntry<ContactId, ParticipantStatus> formatContactParticipant1 = new HashMap.SimpleEntry<>(\n                contact1, ParticipantStatus.CONNECTED);\n        AbstractMap.SimpleEntry<ContactId, ParticipantStatus> participantsParticipant1 = new HashMap.SimpleEntry<>(\n                contact1, participants.get(contact1));\n\n        assertTrue(formatContactParticipant1.equals(participantsParticipant1));\n\n        ContactId contact2 = mContactUtils.formatContact(\"+330124\");\n        AbstractMap.SimpleEntry<ContactId, ParticipantStatus> formatContactParticipant2 = new HashMap.SimpleEntry<>(\n                contact2, ParticipantStatus.DEPARTED);\n        AbstractMap.SimpleEntry<ContactId, ParticipantStatus> participantsParticipant2 = new HashMap.SimpleEntry<>(\n                contact2, participants.get(contact2));\n\n        assertTrue(formatContactParticipant2.equals(participantsParticipant2));\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/chat/ChatMessageTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.chat;\n\nimport static com.gsma.rcs.utils.PhoneUtils.SIP_URI_HEADER;\nimport static com.gsma.rcs.utils.PhoneUtils.initialize;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.core.ims.ImsModule;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatUtils;\nimport com.gsma.rcs.core.ims.userprofile.UserProfile;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.test.AndroidTestCase;\n\nimport java.io.IOException;\nimport java.sql.SQLDataException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Random;\n\npublic class ChatMessageTest extends AndroidTestCase {\n    private ContactId mContact;\n    private ContentResolver mContentResolver;\n    private Random mRandom = new Random();\n    private long mTimestamp;\n    private long mTimestampSent;\n    private String mText;\n    private MessagingLog mMessagingLog;\n    private LocalContentResolver mLocalContentResolver;\n\n    private static final String[] SELECTION = new String[] {\n            Message.DIRECTION, Message.CONTACT, Message.CONTENT, Message.MIME_TYPE,\n            Message.MESSAGE_ID, Message.TIMESTAMP, Message.TIMESTAMP_SENT\n    };\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Context context = getContext();\n        mContentResolver = context.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(mContentResolver);\n        RcsSettings rcsSettings = RcsSettingsMock.getMockSettings(context);\n        initialize(rcsSettings);\n        mMessagingLog = MessagingLog.getInstance(mLocalContentResolver, rcsSettings);\n        ContactUtil contactUtils = ContactUtil.getInstance(new ContactUtilMockContext(context));\n        mContact = contactUtils.formatContact(\"+339000000\");\n        ImsModule.setImsUserProfile(new UserProfile(mContact, \"homeDomain\", \"privateID\",\n                \"password\", \"realm\", Uri.parse(\"xdmServerAddr\"), \"xdmServerLogin\",\n                \"xdmServerPassword\", formatSipUri(\"imConferenceUri\"), rcsSettings));\n        mTimestamp = mRandom.nextLong();\n        mTimestampSent = mRandom.nextLong();\n        mText = Long.toString(mRandom.nextLong());\n    }\n\n    @Override\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testTextMessage() throws PayloadException, IOException, SQLDataException {\n        String msgId = Long.toString(System.currentTimeMillis());\n        ChatMessage msg = new ChatMessage(msgId, mContact, mText, MimeType.TEXT_MESSAGE,\n                mTimestamp, mTimestampSent, \"display\");\n\n        mMessagingLog.addOutgoingOneToOneChatMessage(msg, Message.Content.Status.SENT,\n                Message.Content.ReasonCode.UNSPECIFIED, 0);\n\n        String where = Message.MESSAGE_ID + \"=?\";\n        String[] whereArgs = new String[] {\n            msgId\n        };\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(Message.CONTENT_URI, SELECTION, where, whereArgs,\n                    Message.TIMESTAMP + \" ASC\");\n            if (cursor == null) {\n                throw new SQLDataException(\"Cannot query uri:\" + Message.CONTENT_URI);\n            }\n            assertEquals(cursor.getCount(), 1);\n            assertTrue(cursor.moveToNext());\n            Direction direction = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndex(Message.DIRECTION)));\n            String contact = cursor.getString(cursor.getColumnIndex(Message.CONTACT));\n            String content = cursor.getString(cursor.getColumnIndex(Message.CONTENT));\n            assertNotNull(content);\n            String mimeType = cursor.getString(cursor.getColumnIndex(Message.MIME_TYPE));\n            String id = cursor.getString(cursor.getColumnIndex(Message.MESSAGE_ID));\n            long readTimestamp = cursor.getLong(cursor.getColumnIndex(Message.TIMESTAMP));\n            long readTimestampSent = cursor.getLong(cursor.getColumnIndex(Message.TIMESTAMP_SENT));\n\n            assertEquals(Direction.OUTGOING, direction);\n            assertEquals(mContact.toString(), contact);\n            assertEquals(mText, content);\n            assertEquals(Message.MimeType.TEXT_MESSAGE, mimeType);\n            assertEquals(msgId, id);\n            assertEquals(mTimestamp, readTimestamp);\n            assertEquals(mTimestampSent, readTimestampSent);\n            mLocalContentResolver.delete(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                    null, null);\n            assertFalse(mMessagingLog.isMessagePersisted(msgId));\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGeolocMessage() throws PayloadException, IOException, SQLDataException {\n        Geoloc geoloc = new Geoloc(mText, 10.0, 11.0, 2000, 2);\n        ChatMessage chatMsg = ChatUtils.createGeolocMessage(mContact, geoloc, mTimestamp,\n                mTimestampSent);\n        String msgId = chatMsg.getMessageId();\n        // Add entry\n        mMessagingLog.addOutgoingOneToOneChatMessage(chatMsg, Message.Content.Status.SENT,\n                Message.Content.ReasonCode.UNSPECIFIED, 0);\n\n        // Read entry\n        Uri uri = Uri.withAppendedPath(Message.CONTENT_URI, msgId);\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(uri, SELECTION, null, null, Message.TIMESTAMP + \" ASC\");\n            if (cursor == null) {\n                throw new SQLDataException(\"Cannot query Selection:\" + Arrays.toString(SELECTION));\n            }\n\n            assertEquals(cursor.getCount(), 1);\n            assertTrue(cursor.moveToNext());\n            Direction direction = Direction.valueOf(cursor.getInt(cursor\n                    .getColumnIndex(Message.DIRECTION)));\n            String contact = cursor.getString(cursor.getColumnIndex(Message.CONTACT));\n            String content = cursor.getString(cursor.getColumnIndex(Message.CONTENT));\n            assertNotNull(content);\n            Geoloc readGeoloc = new Geoloc(content);\n            assertNotNull(readGeoloc);\n            String contentType = cursor.getString(cursor.getColumnIndex(Message.MIME_TYPE));\n            String id = cursor.getString(cursor.getColumnIndex(Message.MESSAGE_ID));\n            long readTimestamp = cursor.getLong(cursor.getColumnIndex(Message.TIMESTAMP));\n            long readTimestampSent = cursor.getLong(cursor.getColumnIndex(Message.TIMESTAMP_SENT));\n\n            assertEquals(Direction.OUTGOING, direction);\n            assertEquals(mContact.toString(), contact);\n            assertEquals(readGeoloc.getLabel(), geoloc.getLabel());\n            assertEquals(readGeoloc.getLatitude(), geoloc.getLatitude());\n            assertEquals(readGeoloc.getLongitude(), geoloc.getLongitude());\n            assertEquals(readGeoloc.getExpiration(), geoloc.getExpiration());\n            assertEquals(readGeoloc.getAccuracy(), geoloc.getAccuracy());\n            assertEquals(Message.MimeType.GEOLOC_MESSAGE, contentType);\n            assertEquals(msgId, id);\n            assertEquals(mTimestamp, readTimestamp);\n            assertEquals(mTimestampSent, readTimestampSent);\n            mLocalContentResolver.delete(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId),\n                    null, null);\n            assertFalse(mMessagingLog.isMessagePersisted(msgId));\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    /**\n     * Format to SIP-URI\n     * \n     * @param path Sip Uri path\n     * @return SIP-URI\n     */\n    private Uri formatSipUri(String path) {\n        return path.startsWith(SIP_URI_HEADER) ? Uri.parse(path) : Uri.parse(SIP_URI_HEADER + path);\n    }\n\n    public void testChatMessageDeliveryExpiration() throws PayloadException {\n        String msgId = Long.toString(mRandom.nextLong());\n        ChatMessage msg = new ChatMessage(msgId, mContact, mText, MimeType.TEXT_MESSAGE,\n                mTimestamp, mTimestampSent, \"display\");\n        mMessagingLog.addOutgoingOneToOneChatMessage(msg, Status.SENDING, ReasonCode.UNSPECIFIED,\n                System.currentTimeMillis() + 30000L);\n        assertFalse(mMessagingLog.isChatMessageExpiredDelivery(msgId));\n        mMessagingLog.setChatMessageDeliveryExpired(msgId);\n        assertTrue(mMessagingLog.isChatMessageExpiredDelivery(msgId));\n    }\n\n    private void verifyMessageLogEntries(Cursor cursor, List<String> msgIds) {\n        if (!cursor.moveToFirst()) {\n            fail(\"Cursor should not be empty!\");\n        }\n        int msgIdIdx = cursor.getColumnIndexOrThrow(Message.MESSAGE_ID);\n        while (cursor.moveToNext()) {\n            String msgId = cursor.getString(msgIdIdx);\n            assertTrue(msgIds.contains(msgId));\n        }\n    }\n\n    public void testClearChatMessageDeliveryExpiration() throws PayloadException {\n        List<String> msgIds = new ArrayList<>();\n        for (int i = 0; i < 4; i++) {\n            msgIds.add(Long.toString(mRandom.nextLong()));\n        }\n        for (String msgId : msgIds) {\n            ChatMessage msg = new ChatMessage(msgId, mContact, mText, MimeType.TEXT_MESSAGE,\n                    mTimestamp, mTimestampSent, \"display\");\n            mMessagingLog.addOutgoingOneToOneChatMessage(msg, Status.SENDING,\n                    ReasonCode.UNSPECIFIED, System.currentTimeMillis() + 30000L);\n        }\n        Cursor cursor = mMessagingLog.getUndeliveredOneToOneChatMessages();\n        assertEquals(4, cursor.getCount());\n        verifyMessageLogEntries(cursor, msgIds);\n        CursorUtil.close(cursor);\n        mMessagingLog.clearMessageDeliveryExpiration(msgIds);\n        cursor = mMessagingLog.getUndeliveredOneToOneChatMessages();\n        assertEquals(0, cursor.getCount());\n        CursorUtil.close(cursor);\n    }\n\n    public void testMarkMessageAsRead() {\n        long now = System.currentTimeMillis();\n        String msgId = Long.toString(now);\n        assertEquals(null, mMessagingLog.isMessageRead(msgId));\n        assertEquals(0, mMessagingLog.markMessageAsRead(msgId, now));\n        ChatMessage msg = new ChatMessage(msgId, mContact, mText, MimeType.TEXT_MESSAGE,\n                mTimestamp, mTimestampSent, \"display\");\n        mMessagingLog.addIncomingOneToOneChatMessage(msg, true);\n        assertFalse(mMessagingLog.isMessageRead(msgId));\n        int count = mMessagingLog.markMessageAsRead(msgId, now);\n        assertEquals(1, count);\n        assertTrue(mMessagingLog.isMessageRead(msgId));\n        count = mMessagingLog.markMessageAsRead(msgId, now);\n        assertEquals(0, count);\n        mLocalContentResolver.delete(Uri.withAppendedPath(MessageData.CONTENT_URI, msgId), null,\n                null);\n        assertFalse(mMessagingLog.isMessagePersisted(msgId));\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/chat/GeolocInfoXmlParserTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 ORANGE.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.chat;\n\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.chat.geoloc.GeolocInfoParser;\nimport com.gsma.rcs.utils.DateUtils;\n\nimport android.test.AndroidTestCase;\n\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport java.io.ByteArrayInputStream;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\n\npublic class GeolocInfoXmlParserTest extends AndroidTestCase {\n\n    private static final String sXmlContentToParse = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n            + \"<rcsenvelope entity=\\\"tel:+12345678901\\\" xmlns=\\\"urn:gsma:params:xml:ns:rcs:rcs:geolocation\\\" xmlns:gml=\\\"http://www.opengis.net/gml\\\" xmlns:gp=\\\"urn:ietf:params:xml:ns:pidf:geopriv10\\\" xmlns:gs=\\\"http://www.opengis.net/pidflo/1.0\\\" xmlns:rpid=\\\"urn:ietf:params:xml:ns:pidf:rpid\\\">\\n\"\n            + \"     <rcspushlocation id=\\\"a123\\\" label=\\\"meeting location\\\">\\n\"\n            + \"          <rpid:place-type rpid:until=\\\"2012-03-15T21:00:00-05:00\\\"/>\\n\"\n            + \"          <rpid:time-offset rpid:until=\\\"2012-03-15T21:00:00-05:00\\\"/>\\n\"\n            + \"          <gp:geopriv>\\n\"\n            + \"               <gp:location-info>\\n\"\n            + \"                    <gs:Circle srsName=\\\"urn:ogc:def:crs:EPSG::4326\\\">\\n\"\n            + \"                         <gml:pos>48.731964 -3.45829</gml:pos>\\n\"\n            + \"                         <gs:radius uom=\\\"urn:ogc:def:uom:EPSG::9001\\\">10</gs:radius>\\n\"\n            + \"                    </gs:Circle>\\n\"\n            + \"               </gp:location-info>\\n\"\n            + \"               <gp:usage-rules>\\n\"\n            + \"                    <gp:retention-expiry>2012-03-15T21:00:00-05:00</gp:retention-expiry>\\n\"\n            + \"               </gp:usage-rules>\\n\" + \"          </gp:geopriv>\\n\"\n            + \"          <timestamp>2012-03-15T16:09:44-05:00</timestamp>\\n\"\n            + \"     </rcspushlocation>\\n\" + \"</rcsenvelope>\";\n\n    public void testGeolocXmlParser() throws ParseFailureException, SAXException,\n            ParserConfigurationException {\n        GeolocInfoParser parser = new GeolocInfoParser(new InputSource(new ByteArrayInputStream(\n                sXmlContentToParse.getBytes())));\n        parser.parse();\n        GeolocInfoDocument info = parser.getGeoLocInfo();\n        assertEquals(48.731964, info.getLatitude());\n        assertEquals(-3.45829, info.getLongitude());\n        assertEquals(10.0f, info.getRadius());\n        assertEquals(\"tel:+12345678901\", info.getEntity());\n        assertEquals(DateUtils.decodeDate(\"2012-03-15T21:00:00-05:00\"), info.getExpiration());\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/chat/MessageLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.chat;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatLog.Message;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.test.AndroidTestCase;\n\nimport java.util.Map;\nimport java.util.Random;\n\npublic class MessageLogTest extends AndroidTestCase {\n\n    private ContactId mContact1;\n    private ContactId mContact2;\n    private ContentResolver mContentResolver;\n    private LocalContentResolver mLocalContentResolver;\n    private MessagingLog mMessagingLog;\n    private String mChatId;\n    private long mTimestamp;\n    private Random mRandom = new Random();\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Context context = getContext();\n        mContentResolver = context.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(mContentResolver);\n        RcsSettings rcsSettings = RcsSettingsMock.getMockSettings(context);\n        mMessagingLog = MessagingLog.getInstance(mLocalContentResolver, rcsSettings);\n        ContactUtil contactUtils = ContactUtil.getInstance(new ContactUtilMockContext(mContext));\n        mContact1 = contactUtils.formatContact(\"+339000000\");\n        mContact2 = contactUtils.formatContact(\"+339000001\");\n        mChatId = String.valueOf(mRandom.nextLong());\n        mTimestamp = Math.abs(mRandom.nextLong());\n    }\n\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        mMessagingLog.deleteAllEntries();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testAddGroupChatEvent() {\n        // Add entry\n        String messageId = mMessagingLog.addGroupChatEvent(mChatId, mContact1,\n                GroupChatEvent.Status.DEPARTED, mTimestamp);\n        // Read entry\n        Uri uri = Uri.withAppendedPath(MessageData.CONTENT_URI, messageId);\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(uri, null, null, null, null);\n            // Check entry\n            if (cursor == null) {\n                throw new SQLException(\"Can not query uri\" + uri);\n            }\n            assertEquals(cursor.getCount(), 1);\n            assertTrue(cursor.moveToFirst());\n            String id = cursor.getString(cursor.getColumnIndexOrThrow(ChatLog.Message.MESSAGE_ID));\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(ChatLog.Message.CHAT_ID));\n            String contact = cursor\n                    .getString(cursor.getColumnIndexOrThrow(ChatLog.Message.CONTACT));\n            String mimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.MIME_TYPE));\n            int direction = cursor.getInt(cursor.getColumnIndexOrThrow(ChatLog.Message.DIRECTION));\n            int status = cursor.getInt(cursor.getColumnIndexOrThrow(ChatLog.Message.STATUS));\n            int reason = cursor.getInt(cursor.getColumnIndexOrThrow(ChatLog.Message.REASON_CODE));\n            long timestamp = cursor\n                    .getLong(cursor.getColumnIndexOrThrow(ChatLog.Message.TIMESTAMP));\n            long timestampSent = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(ChatLog.Message.TIMESTAMP_SENT));\n\n            assertEquals(messageId, id);\n            assertEquals(mContact1.toString(), contact);\n            assertEquals(mChatId, chatId);\n            assertEquals(Message.MimeType.GROUPCHAT_EVENT, mimeType);\n            assertEquals(Direction.IRRELEVANT.toInt(), direction);\n            assertEquals(Message.GroupChatEvent.Status.DEPARTED.toInt(), status);\n            assertEquals(ReasonCode.UNSPECIFIED.toInt(), reason);\n            assertEquals(mTimestamp, timestamp);\n            assertEquals(mTimestamp, timestampSent);\n\n            mLocalContentResolver.delete(uri, null, null);\n            assertEquals(false, mMessagingLog.isMessagePersisted(messageId));\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n\n    }\n\n    public void testGetGroupChatEventsSimpleCase() {\n        String id1 = mMessagingLog.addGroupChatEvent(mChatId, mContact1,\n                GroupChatEvent.Status.DEPARTED, mTimestamp);\n        String id2 = mMessagingLog.addGroupChatEvent(mChatId, mContact2,\n                GroupChatEvent.Status.JOINED, mTimestamp);\n        Map<ContactId, GroupChatEvent.Status> groupChatEvents = mMessagingLog\n                .getGroupChatEvents(mChatId);\n        assertNotNull(groupChatEvents);\n        assertTrue(!groupChatEvents.isEmpty());\n        assertTrue(groupChatEvents.containsKey(mContact1));\n        assertTrue(groupChatEvents.containsKey(mContact2));\n        assertEquals(GroupChatEvent.Status.DEPARTED, groupChatEvents.get(mContact1));\n        assertEquals(GroupChatEvent.Status.JOINED, groupChatEvents.get(mContact2));\n\n        Uri uri = Uri.withAppendedPath(MessageData.CONTENT_URI, id1);\n        mLocalContentResolver.delete(uri, null, null);\n        assertEquals(false, mMessagingLog.isMessagePersisted(id1));\n        uri = Uri.withAppendedPath(MessageData.CONTENT_URI, id2);\n        mLocalContentResolver.delete(uri, null, null);\n        assertEquals(false, mMessagingLog.isMessagePersisted(id2));\n    }\n\n    public void testGetGroupChatEventsMultipleEntriesForSameContact() {\n        mMessagingLog.addGroupChatEvent(mChatId, mContact1, GroupChatEvent.Status.DEPARTED,\n                mTimestamp);\n        mMessagingLog.addGroupChatEvent(mChatId, mContact2, GroupChatEvent.Status.JOINED,\n                mTimestamp);\n        mMessagingLog.addGroupChatEvent(mChatId, mContact1, GroupChatEvent.Status.JOINED,\n                mTimestamp + 1);\n        mMessagingLog.addGroupChatEvent(mChatId, mContact2, GroupChatEvent.Status.DEPARTED,\n                mTimestamp + 1);\n        Map<ContactId, GroupChatEvent.Status> groupChatEvents = mMessagingLog\n                .getGroupChatEvents(mChatId);\n        assertNotNull(groupChatEvents);\n        assertTrue(!groupChatEvents.isEmpty());\n        assertTrue(groupChatEvents.containsKey(mContact1));\n        assertTrue(groupChatEvents.containsKey(mContact2));\n        assertEquals(GroupChatEvent.Status.JOINED, groupChatEvents.get(mContact1));\n        assertEquals(GroupChatEvent.Status.DEPARTED, groupChatEvents.get(mContact2));\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/filetransfer/FileTransferLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.filetransfer;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.core.content.FileContent;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.provider.CursorUtil;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.rcs.utils.MimeManager;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsService.ReadStatus;\nimport com.gsma.services.rcs.chat.GroupChat;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.test.AndroidTestCase;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.Set;\n\npublic class FileTransferLogTest extends AndroidTestCase {\n\n    private ContactId mContact;\n    private ContentResolver mContentResolver;\n    private LocalContentResolver mLocalContentResolver;\n    private MessagingLog mMessagingLog;\n    private String mChatId;\n    private String mFileTransferId;\n    private long mTimestamp;\n    private long mTimestampSent;\n    private long mFileExpiration;\n    private Random mRandom = new Random();\n\n    private static final String IMAGE_FILENAME = \"image1.jpg\";\n    private static final String IMAGE_URI = \"content://file/image1.jpg\";\n    private static final long IMAGE_FILESIZE = 1234567;\n    private final MmContent mContent = new FileContent(Uri.parse(IMAGE_URI), IMAGE_FILESIZE,\n            IMAGE_FILENAME);\n\n    private static final String IMAGE_ICON_FILENAME = \"icon1.jpg\";\n    private static final String IMAGE_ICON_URI = \"content://file/icon1.jpg\";\n    private static final long IMAGE_ICON_FILESIZE = 123;\n    private static final MmContent ICON_CONTENT = new FileContent(Uri.parse(IMAGE_ICON_URI),\n            IMAGE_ICON_FILESIZE, IMAGE_ICON_FILENAME);\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Context context = getContext();\n        mContentResolver = context.getContentResolver();\n        mLocalContentResolver = new LocalContentResolver(mContentResolver);\n        RcsSettings rcsSettings = RcsSettingsMock.getMockSettings(context);\n        mMessagingLog = MessagingLog.getInstance(mLocalContentResolver, rcsSettings);\n        ContactUtil contactUtils = ContactUtil.getInstance(new ContactUtilMockContext(mContext));\n        mContact = contactUtils.formatContact(\"+339000000\");\n        mFileTransferId = Long.toString(mRandom.nextLong());\n        mChatId = String.valueOf(mRandom.nextLong());\n        mTimestamp = mRandom.nextLong();\n        mTimestampSent = mRandom.nextLong();\n        mFileExpiration = mRandom.nextLong();\n    }\n\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        mMessagingLog.deleteAllEntries();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testAddFileTransfer() {\n        // Add entry\n        mMessagingLog.addOneToOneFileTransfer(mFileTransferId, mContact, Direction.OUTGOING,\n                mContent, null, State.INITIATING, ReasonCode.UNSPECIFIED, mTimestamp,\n                mTimestampSent, mFileExpiration, FileTransferLog.UNKNOWN_EXPIRATION);\n        // Read entry\n        Uri uri = Uri.withAppendedPath(FileTransferLog.CONTENT_URI, mFileTransferId);\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(uri, null, null, null, null);\n            // Check entry\n            if (cursor == null) {\n                throw new SQLException(\"Can not query uri \" + uri);\n\n            }\n            assertEquals(1, cursor.getCount());\n            assertTrue(cursor.moveToFirst());\n            String id = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FT_ID));\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.CHAT_ID));\n            String contact = cursor\n                    .getString(cursor.getColumnIndexOrThrow(FileTransferLog.CONTACT));\n            String fileUri = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FILE));\n            String filename = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILENAME));\n            String fileMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.MIME_TYPE));\n            int direction = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.DIRECTION));\n            long transferred = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TRANSFERRED));\n            long size = cursor.getLong(cursor.getColumnIndexOrThrow(FileTransferLog.FILESIZE));\n            String icon = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FILEICON));\n            String iconMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_MIME_TYPE));\n            long iconExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_EXPIRATION));\n            int readStatus = cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.READ_STATUS));\n            int state = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.STATE));\n            int reason = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.REASON_CODE));\n            long fileExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILE_EXPIRATION));\n            long timestampDelivered = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DELIVERED));\n            long timestampDisplayed = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DISPLAYED));\n\n            assertEquals(mFileTransferId, id);\n            assertEquals(mContact.toString(), chatId);\n            assertEquals(mContact.toString(), contact);\n            assertEquals(IMAGE_URI, fileUri);\n            assertEquals(IMAGE_FILENAME, filename);\n            assertEquals(MimeManager.getInstance().getMimeType(IMAGE_FILENAME), fileMimeType);\n            assertEquals(Direction.OUTGOING.toInt(), direction);\n            assertEquals(0, transferred);\n            assertEquals(IMAGE_FILESIZE, size);\n            assertEquals(null, icon);\n            assertEquals(null, iconMimeType);\n            assertEquals(FileTransferLog.UNKNOWN_EXPIRATION, iconExpiration);\n            assertEquals(ReadStatus.UNREAD.toInt(), readStatus);\n            assertEquals(FileTransfer.State.INITIATING.toInt(), state);\n            assertEquals(FileTransfer.ReasonCode.UNSPECIFIED.toInt(), reason);\n            assertEquals(mFileExpiration, fileExpiration);\n            assertEquals(0L, timestampDelivered);\n            assertEquals(0L, timestampDisplayed);\n\n            assertEquals(true, mMessagingLog.isFileTransfer(mFileTransferId));\n            assertEquals(false, mMessagingLog.isGroupFileTransfer(mFileTransferId));\n            assertEquals(FileTransfer.State.INITIATING,\n                    mMessagingLog.getFileTransferState(mFileTransferId));\n            assertEquals(FileTransfer.ReasonCode.UNSPECIFIED,\n                    mMessagingLog.getFileTransferReasonCode(mFileTransferId));\n\n            mLocalContentResolver\n                    .delete(Uri.withAppendedPath(FileTransferData.CONTENT_URI, mFileTransferId),\n                            null, null);\n            assertEquals(false, mMessagingLog.isFileTransfer(mFileTransferId));\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n\n        }\n    }\n\n    public void testAddOutgoingGroupFileTransfer() {\n        // Add entry\n        Map<ContactId, GroupChat.ParticipantStatus> participants = new HashMap<>();\n        participants.put(mContact, GroupChat.ParticipantStatus.INVITING);\n        Set<ContactId> recipients = new HashSet<>();\n        recipients.add(mContact);\n        mMessagingLog.addGroupChat(mChatId, null, null, participants, GroupChat.State.INITIATING,\n                GroupChat.ReasonCode.UNSPECIFIED, Direction.OUTGOING, mTimestamp);\n        mMessagingLog.addOutgoingGroupFileTransfer(mFileTransferId, mChatId, mContent,\n                ICON_CONTENT, recipients, State.INITIATING, ReasonCode.UNSPECIFIED, mTimestamp,\n                mTimestampSent);\n        // Read entry\n        Uri uri = Uri.withAppendedPath(FileTransferLog.CONTENT_URI, mFileTransferId);\n        Cursor cursor = null;\n        // Check entry\n        try {\n\n            cursor = mContentResolver.query(uri, null, null, null, null);\n            // Check entry\n            if (cursor == null) {\n                throw new SQLException(\"Can not query uri \" + uri);\n\n            }\n            assertEquals(1, cursor.getCount());\n            assertTrue(cursor.moveToFirst());\n            String id = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FT_ID));\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.CHAT_ID));\n            String contact = cursor\n                    .getString(cursor.getColumnIndexOrThrow(FileTransferLog.CONTACT));\n            String fileUri = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FILE));\n            String filename = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILENAME));\n            String fileMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.MIME_TYPE));\n            int direction = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.DIRECTION));\n            long transferred = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TRANSFERRED));\n            long size = cursor.getLong(cursor.getColumnIndexOrThrow(FileTransferLog.FILESIZE));\n            String icon = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FILEICON));\n            String iconMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_MIME_TYPE));\n            long iconExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_EXPIRATION));\n            int readStatus = cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.READ_STATUS));\n            int state = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.STATE));\n            int reason = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.REASON_CODE));\n            long fileExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILE_EXPIRATION));\n            long timestampDelivered = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DELIVERED));\n            long timestampDisplayed = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DISPLAYED));\n\n            assertEquals(mFileTransferId, id);\n            assertEquals(mChatId, chatId);\n            assertEquals(null, contact);\n            assertEquals(IMAGE_URI, fileUri);\n            assertEquals(IMAGE_FILENAME, filename);\n            assertEquals(MimeManager.getInstance().getMimeType(IMAGE_FILENAME), fileMimeType);\n            assertEquals(Direction.OUTGOING.toInt(), direction);\n            assertEquals(0, transferred);\n            assertEquals(IMAGE_FILESIZE, size);\n            assertEquals(IMAGE_ICON_URI, icon);\n            assertEquals(MimeManager.getInstance().getMimeType(IMAGE_ICON_FILENAME), iconMimeType);\n            assertEquals(FileTransferLog.UNKNOWN_EXPIRATION, iconExpiration);\n            assertEquals(ReadStatus.UNREAD.toInt(), readStatus);\n            assertEquals(FileTransfer.State.INITIATING.toInt(), state);\n            assertEquals(FileTransfer.ReasonCode.UNSPECIFIED.toInt(), reason);\n            assertEquals(FileTransferLog.UNKNOWN_EXPIRATION, fileExpiration);\n            assertEquals(0L, timestampDelivered);\n            assertEquals(0L, timestampDisplayed);\n\n            assertEquals(true, mMessagingLog.isFileTransfer(mFileTransferId));\n            assertEquals(true, mMessagingLog.isGroupFileTransfer(mFileTransferId));\n            assertEquals(FileTransfer.State.INITIATING,\n                    mMessagingLog.getFileTransferState(mFileTransferId));\n            assertEquals(FileTransfer.ReasonCode.UNSPECIFIED,\n                    mMessagingLog.getFileTransferReasonCode(mFileTransferId));\n            mLocalContentResolver\n                    .delete(Uri.withAppendedPath(FileTransferData.CONTENT_URI, mFileTransferId),\n                            null, null);\n            assertEquals(false, mMessagingLog.isFileTransfer(mFileTransferId));\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testAddIncomingGroupFileTransfer() {\n        long fileIconExpiration = mRandom.nextLong();\n        // Add entry\n        mMessagingLog.addIncomingGroupFileTransfer(mFileTransferId, mChatId, mContact, mContent,\n                ICON_CONTENT, State.ACCEPTING, ReasonCode.UNSPECIFIED, mTimestamp, mTimestampSent,\n                mFileExpiration, fileIconExpiration);\n        // Read entry\n\n        Uri uri = Uri.withAppendedPath(FileTransferLog.CONTENT_URI, mFileTransferId);\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(uri, null, null, null, null);\n            // Check entry\n            if (cursor == null) {\n                throw new SQLException(\"Can not query uri \" + uri);\n            }\n            assertEquals(1, cursor.getCount());\n            assertTrue(cursor.moveToFirst());\n            String id = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FT_ID));\n            String chatId = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.CHAT_ID));\n            String contact = cursor\n                    .getString(cursor.getColumnIndexOrThrow(FileTransferLog.CONTACT));\n            String fileUri = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FILE));\n            String filename = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILENAME));\n            String fileMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.MIME_TYPE));\n            int direction = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.DIRECTION));\n            long transferred = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TRANSFERRED));\n            long size = cursor.getLong(cursor.getColumnIndexOrThrow(FileTransferLog.FILESIZE));\n            String icon = cursor.getString(cursor.getColumnIndexOrThrow(FileTransferLog.FILEICON));\n            String iconMimeType = cursor.getString(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_MIME_TYPE));\n            long _fileIconExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILEICON_EXPIRATION));\n            int readStatus = cursor.getInt(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.READ_STATUS));\n            int state = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.STATE));\n            int reason = cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.REASON_CODE));\n            long _fileExpiration = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.FILE_EXPIRATION));\n            long timestampDelivered = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DELIVERED));\n            long timestampDisplayed = cursor.getLong(cursor\n                    .getColumnIndexOrThrow(FileTransferLog.TIMESTAMP_DISPLAYED));\n\n            assertEquals(mFileTransferId, id);\n            assertEquals(mChatId, chatId);\n            assertEquals(mContact.toString(), contact);\n            assertEquals(IMAGE_URI, fileUri);\n            assertEquals(IMAGE_FILENAME, filename);\n            assertEquals(MimeManager.getInstance().getMimeType(IMAGE_FILENAME), fileMimeType);\n            assertEquals(Direction.INCOMING.toInt(), direction);\n            assertEquals(0, transferred);\n            assertEquals(IMAGE_FILESIZE, size);\n            assertEquals(IMAGE_ICON_URI, icon);\n            assertEquals(MimeManager.getInstance().getMimeType(IMAGE_ICON_FILENAME), iconMimeType);\n            assertEquals(fileIconExpiration, _fileIconExpiration);\n            assertEquals(ReadStatus.UNREAD.toInt(), readStatus);\n            assertEquals(FileTransfer.State.ACCEPTING.toInt(), state);\n            assertEquals(FileTransfer.ReasonCode.UNSPECIFIED.toInt(), reason);\n            assertEquals(mFileExpiration, _fileExpiration);\n            assertEquals(0L, timestampDelivered);\n            assertEquals(0L, timestampDisplayed);\n\n            assertEquals(true, mMessagingLog.isFileTransfer(mFileTransferId));\n            assertEquals(true, mMessagingLog.isGroupFileTransfer(mFileTransferId));\n            assertEquals(FileTransfer.State.ACCEPTING,\n                    mMessagingLog.getFileTransferState(mFileTransferId));\n            assertEquals(FileTransfer.ReasonCode.UNSPECIFIED,\n                    mMessagingLog.getFileTransferReasonCode(mFileTransferId));\n            mLocalContentResolver\n                    .delete(Uri.withAppendedPath(FileTransferData.CONTENT_URI, mFileTransferId),\n                            null, null);\n            assertEquals(false, mMessagingLog.isFileTransfer(mFileTransferId));\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n\n    }\n\n    public void testFileTransferDeliveryExpiration() {\n        mMessagingLog.addOneToOneFileTransfer(mFileTransferId, mContact, Direction.OUTGOING,\n                mContent, null, State.INITIATING, ReasonCode.UNSPECIFIED, mTimestamp,\n                mTimestampSent, mFileExpiration, FileTransferLog.UNKNOWN_EXPIRATION);\n        assertFalse(mMessagingLog.isFileTransferExpiredDelivery(mFileTransferId));\n        mMessagingLog.setFileTransferDeliveryExpired(mFileTransferId);\n        assertTrue(mMessagingLog.isFileTransferExpiredDelivery(mFileTransferId));\n    }\n\n    private void verifyFileTransferLogEntries(Cursor cursor, List<String> fileTransferIds) {\n        if (!cursor.moveToFirst()) {\n            fail(\"Cursor should not be empty!\");\n        }\n        int ftIdIdx = cursor.getColumnIndexOrThrow(FileTransferLog.FT_ID);\n        do {\n            String filetransferId = cursor.getString(ftIdIdx);\n            assertTrue(fileTransferIds.contains(filetransferId));\n        } while (cursor.moveToNext());\n    }\n\n    public void testClearFileTransferDeliveryExpiration() {\n        List<String> fileTransferIds = new ArrayList<>();\n        for (int i = 0; i < 4; i++) {\n            fileTransferIds.add(Long.toString(mRandom.nextLong()));\n        }\n        for (String fileTransferId : fileTransferIds) {\n            mMessagingLog.addOneToOneFileTransfer(fileTransferId, mContact, Direction.OUTGOING,\n                    mContent, null, State.INITIATING, ReasonCode.UNSPECIFIED, mTimestamp,\n                    mTimestampSent, mFileExpiration, FileTransferLog.UNKNOWN_EXPIRATION);\n            mMessagingLog.setFileInfoDequeued(fileTransferId, System.currentTimeMillis());\n        }\n        Cursor cursor = mMessagingLog.getUnDeliveredOneToOneFileTransfers();\n        assertEquals(4, cursor.getCount());\n        verifyFileTransferLogEntries(cursor, fileTransferIds);\n        CursorUtil.close(cursor);\n        mMessagingLog.clearFileTransferDeliveryExpiration(fileTransferIds);\n        cursor = mMessagingLog.getUnDeliveredOneToOneFileTransfers();\n        assertEquals(0, cursor.getCount());\n        CursorUtil.close(cursor);\n    }\n\n    public Boolean isFileTransferRead(String msgId) {\n        Uri uri = Uri.withAppendedPath(FileTransferLog.CONTENT_URI, msgId);\n        Cursor cursor = null;\n        try {\n            cursor = mContentResolver.query(uri, new String[] {\n                FileTransferLog.READ_STATUS\n            }, null, null, null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query file transfer read status\");\n            }\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            return (cursor.getInt(cursor.getColumnIndexOrThrow(FileTransferLog.READ_STATUS)) == ReadStatus.READ\n                    .toInt());\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testMarkFileTransferAsRead() {\n        long now = System.currentTimeMillis();\n        long fileIconExpiration = mRandom.nextLong();\n        assertEquals(0, mMessagingLog.markFileTransferAsRead(mFileTransferId, now));\n        // Add entry\n        mMessagingLog.addIncomingGroupFileTransfer(mFileTransferId, mChatId, mContact, mContent,\n                ICON_CONTENT, State.ACCEPTING, ReasonCode.UNSPECIFIED, mTimestamp, mTimestampSent,\n                mFileExpiration, fileIconExpiration);\n        assertFalse(isFileTransferRead(mFileTransferId));\n        int count = mMessagingLog.markFileTransferAsRead(mFileTransferId, now);\n        assertEquals(1, count);\n        assertTrue(isFileTransferRead(mFileTransferId));\n        count = mMessagingLog.markFileTransferAsRead(mFileTransferId, now);\n        assertEquals(0, count);\n        mLocalContentResolver.delete(\n                Uri.withAppendedPath(FileTransferData.CONTENT_URI, mFileTransferId), null, null);\n        assertEquals(false, mMessagingLog.isFileTransfer(mFileTransferId));\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/filetransfer/FileTransferSdpUtilsTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.filetransfer;\n\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaAttribute;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport junit.framework.TestCase;\n\nimport java.util.Vector;\n\npublic class FileTransferSdpUtilsTest extends TestCase {\n\n    private static Logger sLogger = Logger.getLogger(FileTransferSdpUtilsTest.class.getName());\n\n    public void testbuildFtSDP() {\n\n        /*\n         * v=0 o=- 3600507138 3600507138 IN IP4 10.29.67.37 s=- c=IN IP4 10.29.67.37 t=0 0 m=message\n         * 20000 TCP/MSRP * a=accept-types:image/jpeg a=file-transfer-id:1391518338244\n         * a=file-disposition:attachment a=file-selector:name:\"phototmp_3_1_1_1.jpg\" type:image/jpeg\n         * size:195490 a=setup:actpass a=path:msrp://10.29.67.37:20000/1391518338240;tcp a=sendonly\n         * a=max-size:15728640\n         */\n        // @formatter:on\n\n        String ntpTime = \"3600507138 3600507138\";\n        String ipAddress = \"10.29.67.37\";\n        int localMsrpPort = 20000;\n        String localSocketProtocol = \"TCP/MSRP\";\n        String localMsrpPath = \"msrp://10.29.67.37:20000/1391503972255;tcp\";\n        String localSetup = \"actpass\";\n        String acceptedTypes = \"image/jpeg\";\n        String fileTransferID = \"1391518338244\";\n        int maxSize = 15728640;\n        String fileSelector = \"name:\\\"phototmp_3_1_1_1.jpg\\\" type:image/jpeg size:195490\";\n        // / @formatter:off\n        String sdp = \"v=0\" + SipUtils.CRLF\n                + \"o=- \" + ntpTime + \" \" + ntpTime + \" \"\n                + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF\n                + \"s=-\" + SipUtils.CRLF\n                + \"c=\" + SdpUtils.formatAddressType(ipAddress) + SipUtils.CRLF\n                + \"t=0 0\" + SipUtils.CRLF\n                + \"m=message \" + localMsrpPort + \" \" + localSocketProtocol + \" *\" + SipUtils.CRLF\n                + \"a=path:\" + localMsrpPath + SipUtils.CRLF\n                + \"a=setup:\" + localSetup + SipUtils.CRLF\n                + \"a=accept-types: \" + acceptedTypes + SipUtils.CRLF\n                + \"a=file-transfer-id:\" + fileTransferID + SipUtils.CRLF\n                + \"a=file-disposition:attachment\" + SipUtils.CRLF\n                + \"a=sendonly\" + SipUtils.CRLF\n                + \"a=max-size:\" + maxSize + SipUtils.CRLF\n                + \"a=file-selector:\" + fileSelector + SipUtils.CRLF;\n        // @formatter:on\n        sLogger.info(\"SDP \" + sdp);\n        // Parse the remote SDP part\n        SdpParser parser = new SdpParser(sdp.getBytes());\n        Vector<MediaDescription> media = parser.getMediaDescriptions();\n        MediaDescription mediaDesc = media.elementAt(0);\n        for (MediaDescription mediaDescription : media) {\n            sLogger.info(media.toString());\n            for (MediaAttribute attribute : mediaDescription.mMediaAttributes) {\n                sLogger.info(\"attribute: (name=\" + attribute.getName() + \") (value=\"\n                        + attribute.getValue() + \")\");\n            }\n        }\n        assertEquals(mediaDesc.getMediaAttribute(\"setup\").getValue().trim(), localSetup);\n        assertEquals(mediaDesc.getMediaAttribute(\"file-transfer-id\").getValue().trim(),\n                fileTransferID);\n        assertEquals(mediaDesc.getMediaAttribute(\"file-disposition\").getValue().trim(),\n                \"attachment\");\n\n        assertEquals(mediaDesc.getMediaAttribute(\"max-size\").getValue().trim(), \"\" + maxSize);\n        assertEquals(mediaDesc.getMediaAttribute(\"accept-types\").getValue().trim(), acceptedTypes);\n        assertEquals(mediaDesc.getMediaAttribute(\"path\").getValue().trim(), localMsrpPath);\n        assertEquals(mediaDesc.getMediaAttribute(\"file-selector\").getValue().trim(), fileSelector);\n\n        assertEquals(mediaDesc.mPort, localMsrpPort);\n        assertEquals(mediaDesc.mProtocol, localSocketProtocol);\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/im/filetransfer/FileTransferXmlParserTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *      @Author : Created by yplo6403 on 24/02/2016.\n *\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.im.filetransfer;\n\nimport static com.gsma.rcs.utils.StringUtils.UTF8;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.core.ParseFailureException;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.FileTransferUtils;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpInfoDocument;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferHttpThumbnail;\nimport com.gsma.rcs.core.ims.service.im.filetransfer.http.FileTransferXmlParser;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\n\nimport android.net.Uri;\nimport android.test.AndroidTestCase;\n\nimport org.xml.sax.SAXException;\n\nimport javax.xml.parsers.ParserConfigurationException;\n\npublic class FileTransferXmlParserTest extends AndroidTestCase {\n\n    private static final Logger sLogger = Logger.getLogger(FileTransferXmlParserTest.class\n            .getName());\n\n    private static Uri sUri = Uri.parse(\"https://host/path/download?id=12345\");\n    private static Uri sUriThumbnail = Uri.parse(\"https://host/path/download?id=6789\");\n\n    private static final String sXmlContentToParse1 = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n            + \"<file>\" + \"<file-info type=\\\"file\\\" file-disposition=\\\"render\\\">\"\n            + \"  <file-size>1234567890</file-size>\" + \"  <file-name>audio.mp4</file-name>\"\n            + \"  <content-type>audio/mp4</content-type>\"\n            + \"  <am:playing-length>1000</am:playing-length>\" + \"  <data url = \\\"\" + sUri\n            + \"\\\" until = \\\"2016-04-29T16:02:23.000Z\\\"/>\" + \"</file-info>\" + \"</file>\";\n\n    private static final String sXmlContentToParse2 = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n            + \"<file>\" + \"<file-info type=\\\"file\\\" file-disposition=\\\"attach\\\">\"\n            + \"  <file-size>1234567890</file-size>\" + \"  <file-name>image.jpg</file-name>\"\n            + \"  <content-type>image/jpeg</content-type>\" + \"  <data url = \\\"\" + sUri\n            + \"\\\" until = \\\"2016-04-29T16:02:23.000Z\\\"/>\" + \"</file-info>\" + \"</file>\";\n\n    private static final String sXmlContentToParse3 = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n            + \"<file>\" + \"<file-info type=\\\"thumbnail\\\">\" + \"  <file-size>12345</file-size>\"\n            + \"  <content-type>image/png</content-type>\" + \"  <data url = \\\"\" + sUriThumbnail\n            + \"\\\" until = \\\"2016-04-29T16:02:23.000Z\\\"/>\" + \"</file-info>\" + \"</file>\" + \"<file>\"\n            + \"<file-info type=\\\"file\\\" file-disposition=\\\"attach\\\">\"\n            + \"  <file-size>1234567890</file-size>\" + \"  <file-name>image.jpg</file-name>\"\n            + \"  <content-type>image/jpeg</content-type>\" + \"  <data url = \\\"\" + sUri\n            + \"\\\" until = \\\"2016-04-29T16:02:23.000Z\\\"/>\" + \"</file-info>\" + \"</file>\";\n\n    private RcsSettings mRcsSettings;\n\n    private static final String sXmlContentToEncoded = \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\"\n            + \"<file><file-info type=\\\"file\\\" file-disposition=\\\"attachment\\\"><file-size>100000</file-size>\"\n            + \"<file-name>gsma.jpg</file-name><content-type>image/jpeg</content-type>\"\n            + \"<data url = \\\"https://host/path/download?id=12345\\\"  until=\\\"2016-04-29T16:02:23.000Z\\\"/>\"\n            + \"</file-info></file>\";\n\n    private final static String sFilename = \"gsma.jpg\";\n    private final static int sSize = 100000;\n    private final static String sMimeType = \"image/jpeg\";\n    private final static long sExpiration = 1461945743000L;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        mRcsSettings = RcsSettingsMock.getMockSettings(getContext());\n    }\n\n    @Override\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testFileTransferXmlParserAudioMessage() throws ParseFailureException, SAXException,\n            ParserConfigurationException {\n        FileTransferXmlParser parser = new FileTransferXmlParser(\n                sXmlContentToParse1.getBytes(UTF8), mRcsSettings);\n        sLogger.debug(sXmlContentToParse1);\n        parser.parse();\n        FileTransferHttpInfoDocument info = parser.getFileTransferInfo();\n        assertEquals(1234567890, info.getSize());\n        assertEquals(\"audio.mp4\", info.getFilename());\n        assertEquals(\"audio/mp4\", info.getMimeType());\n        assertEquals(FileTransfer.Disposition.RENDER, info.getFileDisposition());\n        assertEquals(1461945743000L, info.getExpiration());\n        assertNull(info.getFileThumbnail());\n        assertEquals(1000, info.getPlayingLength());\n        assertEquals(sUri, info.getUri());\n    }\n\n    public void testFileTransferXmlParserFileImageWithoutIcon() throws ParseFailureException,\n            SAXException, ParserConfigurationException {\n        FileTransferXmlParser parser = new FileTransferXmlParser(\n                sXmlContentToParse2.getBytes(UTF8), mRcsSettings);\n        sLogger.debug(sXmlContentToParse1);\n        parser.parse();\n        FileTransferHttpInfoDocument info = parser.getFileTransferInfo();\n        assertEquals(1234567890, info.getSize());\n        assertEquals(\"image.jpg\", info.getFilename());\n        assertEquals(\"image/jpeg\", info.getMimeType());\n        assertEquals(FileTransfer.Disposition.ATTACH, info.getFileDisposition());\n        assertEquals(1461945743000L, info.getExpiration());\n        assertNull(info.getFileThumbnail());\n        assertEquals(-1, info.getPlayingLength());\n        assertEquals(sUri, info.getUri());\n    }\n\n    public void testFileTransferXmlParserFileImageWithIcon() throws ParseFailureException,\n            SAXException, ParserConfigurationException {\n        FileTransferXmlParser parser = new FileTransferXmlParser(\n                sXmlContentToParse3.getBytes(UTF8), mRcsSettings);\n        sLogger.debug(sXmlContentToParse1);\n        parser.parse();\n        FileTransferHttpInfoDocument info = parser.getFileTransferInfo();\n        assertEquals(1234567890, info.getSize());\n        assertEquals(\"image.jpg\", info.getFilename());\n        assertEquals(\"image/jpeg\", info.getMimeType());\n        assertEquals(FileTransfer.Disposition.ATTACH, info.getFileDisposition());\n        assertEquals(1461945743000L, info.getExpiration());\n        FileTransferHttpThumbnail icon = info.getFileThumbnail();\n        assertNotNull(icon);\n        assertEquals(1461945743000L, icon.getExpiration());\n        assertEquals(\"image/png\", icon.getMimeType());\n        assertEquals(sUriThumbnail, icon.getUri());\n        assertEquals(12345, icon.getSize());\n        assertEquals(-1, info.getPlayingLength());\n        assertEquals(sUri, info.getUri());\n    }\n\n    public void testCreateHttpFileTransferXml() {\n        FileTransferHttpInfoDocument doc1 = new FileTransferHttpInfoDocument(mRcsSettings, sUri,\n                sFilename, sSize, sMimeType, sExpiration, null);\n        String xml = FileTransferUtils.createHttpFileTransferXml(doc1);\n        assertEquals(sXmlContentToEncoded, xml);\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/provider/UserProfilePersistedStorageUtilTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.provider;\n\nimport com.gsma.rcs.addressbook.RcsAccountException;\nimport com.gsma.rcs.utils.FileUtils;\nimport com.gsma.rcs.utils.logger.Logger;\n\nimport android.os.Environment;\nimport android.test.AndroidTestCase;\nimport android.text.TextUtils;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.io.IOException;\nimport java.util.regex.Pattern;\n\npublic class UserProfilePersistedStorageUtilTest extends AndroidTestCase {\n\n    private static final int MAX_SAVED_ACCOUNT = 3;\n\n    private static final Logger sLogger = Logger\n            .getLogger(UserProfilePersistedStorageUtilTest.class.getSimpleName());\n\n    private static final String DB_PATH = Environment.getDataDirectory().toString()\n            + UserProfilePersistedStorageUtil.DATABASE_LOCATION;\n\n    private File mSrcdir = new File(DB_PATH);\n\n    File[] mSavedAccounts;\n\n    /**\n     * Pattern to check if rcs account have atleast 3 characters.\n     */\n    private static final Pattern RCS_ACCOUNT_MATCH_PATTERN = Pattern.compile(\"^\\\\d{3,}$\");\n\n    private static File[] listOfSavedAccounts(final File databasesDir) {\n        if (!databasesDir.exists() || !databasesDir.isDirectory()) {\n            /*\n             * As the database itself doesn't exist , So there won't be any accounts related to user\n             * profile saved, So return from here. This is a special case where we don't throw\n             * exception as backup and restore files and not always needed to be present and reading\n             * information from persisted cache is always optional\n             */\n            return null;\n        }\n        FileFilter directoryFilter = new FileFilter() {\n            public boolean accept(File file) {\n                return file.isDirectory()\n                        && RCS_ACCOUNT_MATCH_PATTERN.matcher(file.getName()).matches();\n            }\n        };\n        return databasesDir.listFiles(directoryFilter);\n    }\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        if (!mSrcdir.exists()) {\n            if (!mSrcdir.mkdir()) {\n                throw new RuntimeException(\"Impossible to create directory\");\n\n            }\n\n        }\n        // Clean up all saved configurations\n        mSavedAccounts = listOfSavedAccounts(mSrcdir);\n        if (mSavedAccounts == null) {\n            return;\n        }\n        for (File savedAccount : mSavedAccounts) {\n            FileUtils.deleteDirectory(savedAccount);\n        }\n    }\n\n    protected void tearDown() throws Exception {\n        super.tearDown();\n    }\n\n    public void testBackupAccount() throws InterruptedException, IOException, RcsAccountException {\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"1111\");\n        /*\n         * A timer greater than 1 second is set because some emulator have only an accuracy of 1\n         * second.\n         */\n        Thread.sleep(1010);\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"2222\");\n        Thread.sleep(1010);\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"3333\");\n        Thread.sleep(1010);\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"4444\");\n\n        mSavedAccounts = listOfSavedAccounts(mSrcdir);\n        if (mSavedAccounts == null) {\n            throw new RcsAccountException(\"No Saved account found\");\n        }\n        for (File file : mSavedAccounts) {\n            sLogger.info(\"Account \" + file.getName() + \" last modified=\" + file.lastModified());\n        }\n        assertTrue(\"listOfSavedAccounts failed\", mSavedAccounts.length == 4);\n\n        String oldestFile = FileUtils.getOldestFile(mSavedAccounts).getName();\n        if (TextUtils.isEmpty(oldestFile)) {\n            fail(\"testBackupAccount failed : oldestFile is null or empty\");\n        } else if (!oldestFile.equals(\"1111\")) {\n            fail(\"testBackupAccount failed: oldestFile is \".concat(oldestFile));\n        }\n    }\n\n    public void testCleanBackups() throws InterruptedException, IOException, RcsAccountException {\n        /* This cleanBackups removes the oldest directory (if MAX_SAVED_ACCOUNT is reached) */\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"1111\");\n        /*\n         * A timer greater than 1 second is set because some emulator have only an accuracy of 1\n         * second.\n         */\n        Thread.sleep(1010);\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"2222\");\n        Thread.sleep(1010);\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"3333\");\n        Thread.sleep(1010);\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"4444\");\n        UserProfilePersistedStorageUtil.normalizeFileBackup(\"3333\");\n\n        mSavedAccounts = listOfSavedAccounts(mSrcdir);\n        if (mSavedAccounts == null) {\n            throw new RcsAccountException(\"No Saved account found\");\n\n        }\n\n        for (File file : mSavedAccounts) {\n            sLogger.info(\"Account \" + file.getName() + \" last modified=\" + file.lastModified());\n        }\n\n        assertTrue(\"listOfSavedAccounts MAX_SAVED_ACCOUNT failed\",\n                mSavedAccounts.length == MAX_SAVED_ACCOUNT);\n\n        String oldestFile = FileUtils.getOldestFile(mSavedAccounts).getName();\n        if (TextUtils.isEmpty(oldestFile)) {\n            fail(\"testCleanBackups failed: oldestFile is null or empty\");\n        } else if (!oldestFile.equals(\"2222\")) {\n            fail(\"testCleanBackups failed: oldestFile is \".concat(oldestFile));\n        }\n    }\n\n    public void testRestoreDb() throws IOException, RcsAccountException {\n        UserProfilePersistedStorageUtil.tryToBackupAccount(\"2222\");\n        UserProfilePersistedStorageUtil.tryToRestoreAccount(\"2222\");\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/richcall/VideoSdpTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010 France Telecom S.A.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * <p/>\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.richcall;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.core.ims.network.sip.SipUtils;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264Profile1_2;\nimport com.gsma.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264Profile1b;\nimport com.gsma.rcs.core.ims.protocol.sdp.MediaDescription;\nimport com.gsma.rcs.core.ims.protocol.sdp.SdpParser;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoCodecManager;\nimport com.gsma.rcs.core.ims.service.richcall.video.VideoSdpBuilder;\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\n\nimport android.test.AndroidTestCase;\n\nimport java.util.Vector;\n\npublic class VideoSdpTest extends AndroidTestCase {\n    private static int RTP_PORT = 12345;\n    private VideoCodec[] mCodecs;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        RcsSettingsMock.getMockSettings(getContext());\n        // Create list of codecs\n        mCodecs = new VideoCodec[4];\n        int payload_count = 95;\n        mCodecs[3] = new VideoCodec(H264Config.CODEC_NAME, ++payload_count, H264Config.CLOCK_RATE,\n                10, 96000, H264Config.QCIF_WIDTH, H264Config.QCIF_HEIGHT,\n                H264Config.CODEC_PARAM_PROFILEID + \"=\" + H264Profile1b.BASELINE_PROFILE_ID + \";\"\n                        + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1\");\n        mCodecs[2] = new VideoCodec(H264Config.CODEC_NAME, ++payload_count, H264Config.CLOCK_RATE,\n                12, 256, H264Config.QVGA_WIDTH, H264Config.QVGA_HEIGHT,\n                H264Config.CODEC_PARAM_PROFILEID + \"=\" + H264Profile1_2.BASELINE_PROFILE_ID + \";\"\n                        + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1\");\n        mCodecs[1] = new VideoCodec(H264Config.CODEC_NAME, ++payload_count, H264Config.CLOCK_RATE,\n                12, 256, H264Config.CIF_WIDTH, H264Config.CIF_HEIGHT,\n                H264Config.CODEC_PARAM_PROFILEID + \"=\" + H264Profile1_2.BASELINE_PROFILE_ID + \";\"\n                        + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1\");\n        mCodecs[0] = new VideoCodec(H264Config.CODEC_NAME, ++payload_count, H264Config.CLOCK_RATE,\n                15, 396, H264Config.CIF_WIDTH, H264Config.CIF_HEIGHT,\n                H264Config.CODEC_PARAM_PROFILEID + \"=\" + H264Profile1_2.BASELINE_PROFILE_ID + \";\"\n                        + H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1\");\n    }\n\n    @Override\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testCreateSdp() {\n        // Create SDP\n        String createdSdp = \"v=tester\\r\\n\"\n                + VideoSdpBuilder.buildSdpOfferWithoutOrientation(mCodecs, RTP_PORT);\n        // TEST SDP\n        // @formatter:off\n        String videoSdp = \"v=tester\" + SipUtils.CRLF +\n                \"m=video 12345 RTP/AVP 99 98 97 96\" + SipUtils.CRLF +\n                \"a=framerate:15\" + SipUtils.CRLF +\n                \"a=rtpmap:99 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:99 352-288\" + SipUtils.CRLF +\n                \"a=fmtp:99 profile-level-id=42800c;packetization-mode=1\" + SipUtils.CRLF +\n                \"a=rtpmap:98 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:98 352-288\" + SipUtils.CRLF +\n                \"a=fmtp:98 profile-level-id=42800c;packetization-mode=1\" + SipUtils.CRLF +\n                \"a=rtpmap:97 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:97 320-240\" + SipUtils.CRLF +\n                \"a=fmtp:97 profile-level-id=42800c;packetization-mode=1\" + SipUtils.CRLF +\n                \"a=rtpmap:96 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:96 176-144\" + SipUtils.CRLF +\n                \"a=fmtp:96 profile-level-id=42900b;packetization-mode=1\" + SipUtils.CRLF;\n        // @formatter:on\n        assertEquals(videoSdp, createdSdp);\n    }\n\n    public void testParseSdp() {\n        // Parse the remote SDP part\n        // @formatter:off\n        String videoSdp2 = \"v=tester\" + SipUtils.CRLF +\n                \"m=video 12345 RTP/AVP 99 98 97 96\" + SipUtils.CRLF +\n                \"b=AS:128\" + SipUtils.CRLF +\n                \"b=RS:256\" + SipUtils.CRLF +\n                \"b=RR:1024\" + SipUtils.CRLF +\n                \"a=rtpmap:99 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:99 352-288\" + SipUtils.CRLF +\n                \"a=framerate:99 15\" + SipUtils.CRLF +\n                \"a=fmtp:99 profile-level-id=42800c;packetization-mode=1\" + SipUtils.CRLF +\n                \"a=rtpmap:98 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:98 352-288\" + SipUtils.CRLF +\n                \"a=framerate:98 12\" + SipUtils.CRLF +\n                \"a=fmtp:98 profile-level-id=42800c;packetization-mode=1\" + SipUtils.CRLF +\n                \"a=rtpmap:97 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:97 320-240\" + SipUtils.CRLF +\n                \"a=framerate:97 12\" + SipUtils.CRLF +\n                \"a=fmtp:97 profile-level-id=42800c;packetization-mode=1\" + SipUtils.CRLF +\n                \"a=rtpmap:96 H264/90000\" + SipUtils.CRLF +\n                \"a=framesize:96 176-144\" + SipUtils.CRLF +\n                \"a=framerate:96 10\" + SipUtils.CRLF +\n                \"a=fmtp:96 profile-level-id=42900b;packetization-mode=1\" + SipUtils.CRLF;\n        // @formatter:on\n        SdpParser parser = new SdpParser(videoSdp2.getBytes());\n        // Test port\n        MediaDescription mediaVideo = parser.getMediaDescription(\"video\");\n        int port = mediaVideo.mPort;\n        assertEquals(port, RTP_PORT);\n\n        // Test codecs\n        Vector<MediaDescription> medias = parser.getMediaDescriptions(\"video\");\n        Vector<VideoCodec> proposedCodecs = VideoCodecManager.extractVideoCodecsFromSdp(medias);\n        assertEquals(proposedCodecs.size(), mCodecs.length);\n        for (int i = 0; i < proposedCodecs.size(); i++) {\n            VideoCodec codec = mCodecs[i];\n            assertEquals(proposedCodecs.elementAt(i).getEncoding(), codec.getEncoding());\n            assertEquals(proposedCodecs.elementAt(i).getPayloadType(), codec.getPayloadType());\n            assertEquals(proposedCodecs.elementAt(i).getParameters(), codec.getParameters());\n            assertEquals(proposedCodecs.elementAt(i).getFrameRate(), codec.getFrameRate());\n            assertEquals(proposedCodecs.elementAt(i).getWidth(), codec.getWidth());\n            assertEquals(proposedCodecs.elementAt(i).getHeight(), codec.getHeight());\n            // Bitrate and order pref not tested because not in SDP\n        }\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/utils/Base64Test.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010 France Telecom S.A.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.test.AndroidTestCase;\n\npublic class Base64Test extends AndroidTestCase {\n\n    public final void testBase64() {\n        String ss = \"2 + 2 = quatre, non 5?\";\n        assertEquals(Base64.encodeBase64ToString(ss.getBytes()), \"MiArIDIgPSBxdWF0cmUsIG5vbiA1Pw==\");\n        assertEquals(new String(Base64.encodeBase64(ss.getBytes())),\n                \"MiArIDIgPSBxdWF0cmUsIG5vbiA1Pw==\");\n        assertEquals(Base64.encodeBase64ToString(Base64\n                .decodeBase64((\"MiArIDIgPSBxdWF0cmUsIG5vbiA1Pw==\").getBytes())),\n                \"MiArIDIgPSBxdWF0cmUsIG5vbiA1Pw==\");\n        assertEquals(\n                new String(Base64.decodeBase64((\"MiArIDIgPSBxdWF0cmUsIG5vbiA1Pw==\").getBytes())),\n                ss);\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/utils/ContactUtilMockContext.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.content.res.Resources;\nimport android.test.mock.MockContext;\nimport android.test.mock.MockResources;\n\n/**\n * A class to mock up a Context object for create singleton for ContactUtil.<br>\n * All ContactUtil.getInstance(...) calls MUST an instance of this class as input parameter.\n * \n * @author YPLO6403\n */\npublic class ContactUtilMockContext extends MockContext {\n\n    private final static int MCC_COUNTRY_CODE = 240; // Sweden\n    public final static String COUNTRY_CODE = \"+46\";\n    public final static String COUNTRY_AREA_CODE = \"0\";\n\n    private final Context mDelegatedContext;\n\n    public ContactUtilMockContext(Context context) {\n        mDelegatedContext = context;\n    }\n\n    @Override\n    public Resources getResources() {\n        mDelegatedContext.getResources();\n        return new MockResources() {\n\n            @Override\n            public Configuration getConfiguration() {\n                Configuration config = mDelegatedContext.getResources().getConfiguration();\n                config.mcc = MCC_COUNTRY_CODE;\n                return config;\n            }\n\n        };\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/utils/DateUtilsTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010 France Telecom S.A.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.test.AndroidTestCase;\n\nimport java.util.Date;\n\npublic class DateUtilsTest extends AndroidTestCase {\n\n    @SuppressWarnings(\"deprecation\")\n    public void testEncodeDecode() {\n        long t = System.currentTimeMillis();\n        String encoded = DateUtils.encodeDate(t);\n        long decoded = DateUtils.decodeDate(encoded);\n\n        assertEquals(new Date(t).getYear(), new Date(decoded).getYear());\n        assertEquals(new Date(t).getMonth(), new Date(decoded).getMonth());\n        assertEquals(new Date(t).getDay(), new Date(decoded).getDay());\n        assertEquals(new Date(t).getHours(), new Date(decoded).getHours());\n        assertEquals(new Date(t).getMinutes(), new Date(decoded).getMinutes());\n        assertEquals(new Date(t).getSeconds(), new Date(decoded).getSeconds());\n        assertEquals(new Date(t).getTimezoneOffset(), new Date(decoded).getTimezoneOffset());\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/utils/IpAddressUtilsTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010 France Telecom S.A.\n * Copyright (C) 2016 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport android.test.AndroidTestCase;\n\n/**\n * @author jexa7410\n */\npublic class IpAddressUtilsTest extends AndroidTestCase {\n\n    public void testExtractHostAddress() {\n        assertEquals(IpAddressUtils.extractHostAddress(\"127.0.0.1\"), \"127.0.0.1\");\n        assertEquals(IpAddressUtils.extractHostAddress(\"domain.com\"), \"domain.com\");\n        assertEquals(IpAddressUtils.extractHostAddress(\"127.0.0.1%2\"), \"127.0.0.1\");\n        assertEquals(IpAddressUtils.extractHostAddress(\"fe80::1234%1\"), \"fe80::1234\");\n        assertEquals(IpAddressUtils.extractHostAddress(\"ff02::5678%pvc1.3\"), \"ff02::5678\");\n        assertEquals(IpAddressUtils.extractHostAddress(\"169.254.0.0/16\"), \"169.254.0.0\");\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/rcs/utils/NetworkRessourceMangerTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.utils;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.platform.network.NetworkFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\n\nimport android.test.AndroidTestCase;\n\nimport java.io.IOException;\nimport java.net.DatagramSocket;\nimport java.net.ServerSocket;\nimport java.net.SocketException;\n\npublic class NetworkRessourceMangerTest extends AndroidTestCase {\n\n    private RcsSettings mRcsSettings;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        mRcsSettings = RcsSettingsMock.getMockSettings(getContext());\n        NetworkFactory.loadFactory(\"com.gsma.rcs.platform.network.AndroidNetworkFactory\",\n                mRcsSettings);\n    }\n\n    @Override\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testPortSelection() {\n        int updPort = NetworkRessourceManager.generateLocalSipPort(mRcsSettings);\n        DatagramSocket udpSocket1 = null;\n        try {\n            udpSocket1 = new DatagramSocket(updPort);\n        } catch (SocketException e) {\n            assertNull(\"Error \" + e, e);\n        }\n        assertNotNull(\"No UPD socket created at \" + updPort, udpSocket1);\n\n        int tcpPort = NetworkRessourceManager.generateLocalSipPort(mRcsSettings);\n        ServerSocket tcpSocket1 = null;\n        try {\n            tcpSocket1 = new ServerSocket(tcpPort);\n        } catch (IOException e) {\n            assertNull(\"Error \" + e, e);\n        }\n        assertNotNull(\"No TCP socket created at \" + tcpPort, tcpSocket1);\n\n        int udpTcpPort = NetworkRessourceManager.generateLocalSipPort(mRcsSettings);\n        DatagramSocket udpSocket2 = null;\n        try {\n            udpSocket2 = new DatagramSocket(udpTcpPort);\n        } catch (SocketException e) {\n            assertNull(\"Error \" + e, e);\n        }\n        assertNotNull(\"No UPD socket created at \" + udpTcpPort, udpSocket2);\n\n        ServerSocket tcpSocket2 = null;\n        try {\n            tcpSocket2 = new ServerSocket(udpTcpPort);\n        } catch (IOException e) {\n            assertNull(\"Error \" + e, e);\n        }\n        assertNotNull(\"No TCP socket created at \" + udpTcpPort, tcpSocket2);\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/GeolocTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs;\n\nimport com.gsma.services.rcs.Geoloc;\n\nimport android.test.AndroidTestCase;\n\nimport java.util.NoSuchElementException;\n\npublic class GeolocTest extends AndroidTestCase {\n\n    public void testgetGeolocInvalidData() {\n        try {\n            new Geoloc(\"abcd,2,3,4.0\");\n            fail(\"Exception is expected\");\n        } catch (Exception e) {\n            assertTrue(e instanceof NumberFormatException);\n        }\n    }\n\n    public void testgetGeolocMissingData() {\n        try {\n            new Geoloc(\"0,1,2\");\n        } catch (Exception e) {\n            assertTrue(e instanceof NoSuchElementException);\n        }\n    }\n\n    public void testgetGeoloc() {\n        Geoloc geoloc = new Geoloc(\"label,1,2,3,4.0\");\n        assertNotNull(geoloc);\n        assertEquals(\"label\", geoloc.getLabel());\n        assertEquals(1.0d, geoloc.getLatitude());\n        assertEquals(2.0d, geoloc.getLongitude());\n        assertEquals(3L, geoloc.getExpiration());\n        assertEquals(4.0f, geoloc.getAccuracy());\n    }\n\n    public void testgetGeolocNoLabel() {\n        Geoloc geoloc = new Geoloc(\"1,2,3,4.0\");\n        assertNotNull(geoloc);\n        assertEquals(null, geoloc.getLabel());\n        assertEquals(1.0d, geoloc.getLatitude());\n        assertEquals(2.0d, geoloc.getLongitude());\n        assertEquals(3L, geoloc.getExpiration());\n        assertEquals(4.0f, geoloc.getAccuracy());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/capabilities/CapabilitiesTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010 France Telecom S.A.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs.capabilities;\n\nimport com.gsma.services.rcs.capability.Capabilities;\n\nimport android.os.Parcel;\nimport android.test.AndroidTestCase;\n\nimport java.util.HashSet;\nimport java.util.Random;\nimport java.util.Set;\n\npublic class CapabilitiesTest extends AndroidTestCase {\n\n    private boolean mBimageSharing;\n\n    private boolean mBvideoSharing;\n\n    private boolean mBimSession;\n\n    private boolean fileTransfer;\n\n    private boolean mBgeolocPush;\n\n    private Set<String> mExtensions = new HashSet<>();\n\n    private boolean mBautomata;\n\n    private long mTimestamp;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Random random = new Random();\n        mBimageSharing = random.nextBoolean();\n        mBvideoSharing = random.nextBoolean();\n        mBimSession = random.nextBoolean();\n        fileTransfer = random.nextBoolean();\n        mBgeolocPush = random.nextBoolean();\n        mBautomata = random.nextBoolean();\n        mExtensions.add(String.valueOf(random.nextInt(96) + 32));\n        mExtensions.add(String.valueOf(random.nextInt(96) + 32));\n        mTimestamp = random.nextLong();\n    }\n\n\n    public void testCapabilitiesNullSet() {\n        Capabilities capabilities = new Capabilities(mBimageSharing, mBvideoSharing, mBimSession,\n                fileTransfer, mBgeolocPush, null, mBautomata, mTimestamp);\n        Parcel parcel = Parcel.obtain();\n        capabilities.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        Capabilities createFromParcel = Capabilities.CREATOR.createFromParcel(parcel);\n        assertTrue(capabilitiesIsEqual(createFromParcel, capabilities));\n    }\n\n    public void testCapabilities() {\n        Capabilities capabilities = new Capabilities(mBimageSharing, mBvideoSharing, mBimSession,\n                fileTransfer, mBgeolocPush, mExtensions, mBautomata, mTimestamp);\n        Parcel parcel = Parcel.obtain();\n        capabilities.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        Capabilities createFromParcel = Capabilities.CREATOR.createFromParcel(parcel);\n        assertTrue(capabilitiesIsEqual(createFromParcel, capabilities));\n    }\n\n    public static boolean capabilitiesIsEqual(Capabilities cap1, Capabilities cap2) {\n        if (cap1.isImageSharingSupported() != cap2.isImageSharingSupported()) {\n            return false;\n        }\n        if (cap1.isVideoSharingSupported() != cap2.isVideoSharingSupported()) {\n            return false;\n        }\n        if (cap1.isImSessionSupported() != cap2.isImSessionSupported()) {\n            return false;\n        }\n        if (cap1.isFileTransferSupported() != cap2.isFileTransferSupported()) {\n            return false;\n        }\n        if (cap1.isGeolocPushSupported() != cap2.isGeolocPushSupported()) {\n            return false;\n        }\n        if (cap1.isAutomata() != cap2.isAutomata()) {\n            return false;\n        }\n        if (cap1.getSupportedExtensions() != null) {\n            if (!cap1.getSupportedExtensions().equals(cap2.getSupportedExtensions()))\n                return false;\n        } else {\n            if (cap2.getSupportedExtensions() != null) {\n                return false;\n            }\n        }\n        return cap1.getTimestamp() == cap2.getTimestamp();\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/capabilities/ServiceExtensionManagerTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs.capabilities;\n\nimport com.gsma.rcs.core.ims.service.extension.ServiceExtensionManager;\n\nimport android.test.AndroidTestCase;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.UUID;\n\npublic class ServiceExtensionManagerTest extends AndroidTestCase {\n\n    private Set<String> extensions;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        extensions = new HashSet<>();\n        extensions.add(UUID.randomUUID().toString());\n        extensions.add(UUID.randomUUID().toString());\n    }\n\n    public void testGetExtensions() {\n        String concatenatedExtensions = ServiceExtensionManager.getExtensions(extensions);\n        Log.d(\"RCS\", \"testGetExtensions concatenatedExtensions=\" + concatenatedExtensions);\n        Set<String> newExtensions = ServiceExtensionManager.getExtensions(concatenatedExtensions);\n        assertEquals(newExtensions, extensions);\n    }\n\n    public void testGetExtensionsEmptyTokens() {\n        Set<String> newExtensions = ServiceExtensionManager.getExtensions(\"; ;\");\n        assertTrue(newExtensions.isEmpty());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/contacts/ContactUtilTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs.contacts;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.platform.AndroidFactory;\nimport com.gsma.rcs.provider.settings.RcsSettings;\nimport com.gsma.rcs.utils.ContactUtil;\n\nimport android.content.Context;\nimport android.test.AndroidTestCase;\n\npublic class ContactUtilTest extends AndroidTestCase {\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Context context = getContext();\n        RcsSettings settings = RcsSettingsMock.getMockSettings(context);\n        AndroidFactory.setApplicationContext(context, settings);\n    }\n\n    @Override\n    public void tearDown() throws Exception {\n        super.tearDown();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    public void testGetValidPhoneNumberFromUri() {\n        String telUri = \"<tel:+33640519308?Accept-Contact=%2Bsip.instance%3D%22%3Curn%3Agsma%3Aimei%3A35824005-944763-1%3E%22>\";\n        ContactUtil.PhoneNumber number = ContactUtil.getValidPhoneNumberFromUri(telUri);\n        assertNotNull(number);\n        assertEquals(\"+33640519308\", number.getNumber());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/contacts/ContactUtilsTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs.contacts;\n\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.rcs.utils.logger.Logger;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.test.AndroidTestCase;\nimport android.text.TextUtils;\n\npublic class ContactUtilsTest extends AndroidTestCase {\n\n    private static final Logger sLogger = Logger.getLogger(ContactUtilsTest.class.getName());\n\n    private ContactUtil mContactUtils;\n    private String mNextCountryAreaCode;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        mContactUtils = ContactUtil.getInstance(new ContactUtilMockContext(getContext()));\n        mNextCountryAreaCode = String.valueOf(Integer\n                .valueOf(ContactUtilMockContext.COUNTRY_AREA_CODE) + 1);\n        if (sLogger.isActivated()) {\n            sLogger.debug(\"Country Code='\" + mContactUtils.getMyCountryCode()\n                    + \"' Country Area Code='\" + mContactUtils.getMyCountryAreaCode() + \"'\");\n        }\n    }\n\n    public void testIsValidContactNull() {\n        try {\n            assertFalse(mContactUtils.isValidContact(null));\n        } catch (RcsPermissionDeniedException e) {\n            fail(e.getMessage());\n        }\n    }\n\n    public void testIsValidContactInvalidLength() throws RcsPermissionDeniedException {\n        assertFalse(mContactUtils.isValidContact(\"+\"));\n    }\n\n    public void testIsValidContactInvalidLength_min() throws RcsPermissionDeniedException {\n        assertFalse(mContactUtils.isValidContact(\"\"));\n    }\n\n    public void testIsValidContactInvalidLength_max() throws RcsPermissionDeniedException {\n        assertFalse(mContactUtils.isValidContact(\"0123456789012345\"));\n    }\n\n    public void testIsValidContactInvalidCharacter() throws RcsPermissionDeniedException {\n        assertFalse(mContactUtils.isValidContact(\"012345a\"));\n    }\n\n    public void testIsValidContactWrongAreaCode() throws RcsPermissionDeniedException {\n        assertFalse(mContactUtils.isValidContact(mNextCountryAreaCode.concat(\"123456789\")));\n    }\n\n    public void testIsValidContactNormalCase_1() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(ContactUtilMockContext.COUNTRY_AREA_CODE\n                .concat(\"123456789\")));\n    }\n\n    public void testIsValidContactNormalCase_2() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(\"+123456789\"));\n    }\n\n    public void testIsValidContactNormalCase_3() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(\"+012345678901234\"));\n    }\n\n    public void testIsValidContactNormalCase_4() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(ContactUtilMockContext.COUNTRY_AREA_CODE\n                .concat(\"12345678901234\")));\n    }\n\n    public void testIsValidContactNormalCase_5() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(ContactUtilMockContext.COUNTRY_AREA_CODE\n                .concat(\"1 2 3 4 5 6 7 8 9 0 1 2 3 4\")));\n    }\n\n    public void testIsValidContactNormalCase_6() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(ContactUtilMockContext.COUNTRY_AREA_CODE\n                .concat(\"-1-2-3-4-5-6-7-8-9-0-1-2-3-4\")));\n    }\n\n    public void testIsValidContactNormalCase_7() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(\" \" + ContactUtilMockContext.COUNTRY_AREA_CODE\n                + \"-1 2-3 4-5 6-7 8-9 0-1 2-3 4 \"));\n    }\n\n    public void testIsValidContactNormalCase_8() throws RcsPermissionDeniedException {\n        assertTrue(mContactUtils.isValidContact(ContactUtilMockContext.COUNTRY_AREA_CODE\n                .concat(\"    1--------2-3 4-5 6-7 8-9 0-1 2-3 4 \")));\n    }\n\n    public void testFormatContactIdNull() throws RcsPermissionDeniedException {\n        try {\n            mContactUtils.formatContact(null);\n            fail(\"Expected IllegalArgumentException to be thrown\");\n        } catch (IllegalArgumentException ignore) {\n        }\n    }\n\n    public void testFormatContactIdWithInternationalNumbering() throws RcsPermissionDeniedException {\n        ContactId cid = mContactUtils.formatContact(\"+33612345678\");\n        assertEquals(\"+33612345678\", cid.toString());\n        cid = mContactUtils.formatContact(\"+34612345678\");\n        assertEquals(\"+34612345678\", cid.toString());\n    }\n\n    public void testFormatContactIdWithLocalNumbering() throws RcsPermissionDeniedException {\n        String cac = mContactUtils.getMyCountryAreaCode();\n        if (TextUtils.isEmpty(cac))\n            return;\n        String cc = mContactUtils.getMyCountryCode();\n        ContactId cid = mContactUtils.formatContact(cac + \"612345678\");\n        assertEquals(cc + \"612345678\", cid.toString());\n    }\n\n    public void testFormatContactIdWithLocalNumberingButDifferentCountryAreaCode()\n            throws RcsPermissionDeniedException {\n        String cac = mContactUtils.getMyCountryAreaCode();\n        if (TextUtils.isEmpty(cac))\n            return;\n        try {\n            int cacInteger = Integer.parseInt(cac);\n            mContactUtils.formatContact((++cacInteger) + \"612345678\");\n            fail(\"IllegalArgumentException expected\");\n        } catch (Exception e) {\n            assertTrue(e instanceof IllegalArgumentException);\n        }\n    }\n\n    public void testFormatContactIdWithPrefixedInternationalNumbering()\n            throws RcsPermissionDeniedException {\n        String cc = mContactUtils.getMyCountryCode();\n        ContactId cid = mContactUtils.formatContact(\"00\" + cc.substring(1) + \"612345678\");\n        assertEquals(cc + \"612345678\", cid.toString());\n        int ccInteger = Integer.parseInt(cc.substring(1)) + 1;\n        cid = mContactUtils.formatContact(\"00\" + ccInteger + \"612345678\");\n        assertEquals(\"+\" + ccInteger + \"612345678\", cid.toString());\n    }\n\n    public void testGetMyCountryAreaCode() throws RcsPermissionDeniedException {\n        assertEquals(\"Country Code='\" + mContactUtils.getMyCountryCode() + \"' Country Area Code='\"\n                + mContactUtils.getMyCountryAreaCode() + \"'\",\n                ContactUtilMockContext.COUNTRY_AREA_CODE, mContactUtils.getMyCountryAreaCode());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/contacts/RcsContactTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010 France Telecom S.A.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs.contacts;\n\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.service.rcs.capabilities.CapabilitiesTest;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.os.Parcel;\nimport android.test.AndroidTestCase;\n\nimport java.util.HashSet;\nimport java.util.Random;\n\npublic class RcsContactTest extends AndroidTestCase {\n\n    private Capabilities mCapabilities;\n\n    private boolean mRegistered;\n\n    private ContactId mContactId;\n\n    private String mDisplayName;\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        Random random = new Random();\n        boolean mBimageSharing = random.nextBoolean();\n        boolean videoSharing = random.nextBoolean();\n        boolean imSession = random.nextBoolean();\n        boolean fileTransfer = random.nextBoolean();\n        boolean geolocPush = random.nextBoolean();\n        boolean automata = random.nextBoolean();\n        HashSet<String> extensions = new HashSet<>();\n        extensions.add(String.valueOf(random.nextInt(96) + 32));\n        extensions.add(String.valueOf(random.nextInt(96) + 32));\n        long timestamp = random.nextLong();\n\n        mCapabilities = new Capabilities(mBimageSharing, videoSharing, imSession, fileTransfer,\n                geolocPush, extensions, automata, timestamp);\n        mRegistered = random.nextBoolean();\n        ContactUtil contactUtils = ContactUtil\n                .getInstance(new ContactUtilMockContext(getContext()));\n        mContactId = contactUtils.formatContact(\"+33123456789\");\n        mDisplayName = \"displayName\";\n    }\n\n    public void testRcsContactContactNull() {\n        RcsContact rcsContact = new RcsContact(null, mRegistered, mCapabilities, mDisplayName, false,\n                -1L);\n        Parcel parcel = Parcel.obtain();\n        rcsContact.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        RcsContact createFromParcel = RcsContact.CREATOR.createFromParcel(parcel);\n        assertTrue(rcsContactIsEqual(createFromParcel, rcsContact));\n    }\n\n    public void testRcsContactCapabilitiesNull() {\n        RcsContact rcsContact = new RcsContact(mContactId, mRegistered, null, mDisplayName, false, -1L);\n        Parcel parcel = Parcel.obtain();\n        rcsContact.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        RcsContact createFromParcel = RcsContact.CREATOR.createFromParcel(parcel);\n        assertTrue(rcsContactIsEqual(createFromParcel, rcsContact));\n    }\n\n    public void testRcsContactDisplayNameNull() {\n        RcsContact rcsContact = new RcsContact(mContactId, mRegistered, mCapabilities, null, false,\n                -1L);\n        Parcel parcel = Parcel.obtain();\n        rcsContact.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        RcsContact createFromParcel = RcsContact.CREATOR.createFromParcel(parcel);\n        assertTrue(rcsContactIsEqual(createFromParcel, rcsContact));\n    }\n\n    public void testRcsContact() {\n        RcsContact rcsContact = new RcsContact(mContactId, mRegistered, mCapabilities, mDisplayName,\n                false, -1L);\n        Parcel parcel = Parcel.obtain();\n        rcsContact.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        RcsContact createFromParcel = RcsContact.CREATOR.createFromParcel(parcel);\n        assertTrue(rcsContactIsEqual(createFromParcel, rcsContact));\n    }\n\n    private boolean rcsContactIsEqual(RcsContact rcs1, RcsContact rcs2) {\n        if (rcs1.isOnline() != rcs2.isOnline()) {\n            return false;\n        }\n\n        if (rcs1.getContactId() != null) {\n            if (!rcs1.getContactId().equals(rcs2.getContactId())) {\n                return false;\n            }\n        } else {\n            if (rcs2.getContactId() != null) {\n                return false;\n            }\n        }\n\n        if (rcs1.getCapabilities() != null) {\n            if (!CapabilitiesTest.capabilitiesIsEqual(rcs1.getCapabilities(),\n                    rcs2.getCapabilities())) {\n                return false;\n            }\n        } else {\n            if (rcs2.getCapabilities() != null) {\n                return false;\n            }\n        }\n\n        if (rcs1.getDisplayName() != null) {\n            if (!rcs1.getDisplayName().equals(rcs2.getDisplayName())) {\n                return false;\n            }\n\n        } else {\n            if (rcs2.getDisplayName() != null) {\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/history/HistoryLogTest.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * All rights, including trade secret rights, reserved.\n */\n\npackage com.gsma.service.rcs.history;\n\nimport com.gsma.rcs.RcsSettingsMock;\nimport com.gsma.rcs.core.content.FileContent;\nimport com.gsma.rcs.core.content.MmContent;\nimport com.gsma.rcs.core.content.VideoContent;\nimport com.gsma.rcs.core.ims.protocol.PayloadException;\nimport com.gsma.rcs.core.ims.service.im.chat.ChatMessage;\nimport com.gsma.rcs.provider.LocalContentResolver;\nimport com.gsma.rcs.provider.contact.ContactProvider;\nimport com.gsma.rcs.provider.history.HistoryLogData;\nimport com.gsma.rcs.provider.history.HistoryProvider;\nimport com.gsma.rcs.provider.messaging.FileTransferData;\nimport com.gsma.rcs.provider.messaging.FileTransferProvider;\nimport com.gsma.rcs.provider.messaging.MessageData;\nimport com.gsma.rcs.provider.messaging.MessagingLog;\nimport com.gsma.rcs.provider.settings.RcsSettingsProvider;\nimport com.gsma.rcs.provider.sharing.GeolocSharingData;\nimport com.gsma.rcs.provider.sharing.ImageSharingData;\nimport com.gsma.rcs.provider.sharing.RichCallHistory;\nimport com.gsma.rcs.provider.sharing.VideoSharingData;\nimport com.gsma.rcs.service.api.HistoryServiceImpl;\nimport com.gsma.rcs.utils.ContactUtilMockContext;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.ChatLog.Message;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\nimport com.gsma.services.rcs.history.IHistoryService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport android.content.ContentProvider;\nimport android.content.ContentProviderClient;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.database.sqlite.SQLiteDatabase;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.provider.BaseColumns;\nimport android.support.annotation.NonNull;\nimport android.test.AndroidTestCase;\nimport android.test.IsolatedContext;\nimport android.test.mock.MockContentResolver;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Random;\n\npublic class HistoryLogTest extends AndroidTestCase {\n\n    private static final String REMOTE_CONTACT_NUMBER = \"+46123456789\";\n\n    private static final String SELECTION_EMPTY = \"\";\n\n    private static final String SELECTION_NOT_EMPTY = HistoryLog.CONTACT + \"='\"\n            + REMOTE_CONTACT_NUMBER + \"'\";\n\n    private static final String FILE_TRANSFER_ID = \"FtId\" + System.currentTimeMillis();\n\n    private static final String MESSAGE_ID = \"MsgId\" + System.currentTimeMillis();\n\n    private static final String IMAGE_SHARING_ID = \"ImageSharingId\" + System.currentTimeMillis();\n\n    private static final String VIDEO_SHARING_ID = \"VideoSharingId\" + System.currentTimeMillis();\n\n    private static final String GEOLOC_SHARING_ID = \"GeolocSharingId\" + System.currentTimeMillis();\n\n    private static final String IMAGE_FILE_NAME = \"image1.jpg\";\n\n    private static final String VIDEO_FILE_NAME = \"video1.mpg\";\n\n    private static final String IMAGE_URI = \"content://file/image1.jpg\";\n\n    private static final String VIDEO_URI = \"content://file/video1.mpg\";\n\n    private static final long IMAGE_FILE_SIZE = 123456;\n\n    private static final long VIDEO_FILE_SIZE = 1234567;\n\n    private static final String THUMBNAIL_FILE_NAME = \"thumbnail1.jpg\";\n\n    private static final String THUMBNAIL_URI = \"content://file/thumbnail1.jpg\";\n\n    private static final long THUMBNAIL_FILE_SIZE = 1234;\n\n    private static final String VIDEO_ENCODING = \"video/\";\n\n    private static MyContentProvider sMyContentProvider = new MyContentProvider();\n\n    private static final MmContent CONTENT = new FileContent(Uri.parse(IMAGE_URI), IMAGE_FILE_SIZE,\n            IMAGE_FILE_NAME);\n\n    private static final MmContent THUMBNAIL = new FileContent(Uri.parse(THUMBNAIL_URI),\n            THUMBNAIL_FILE_SIZE, THUMBNAIL_FILE_NAME);\n\n    private static final VideoContent VIDEO_CONTENT = new VideoContent(Uri.parse(VIDEO_URI),\n            VIDEO_ENCODING, VIDEO_FILE_SIZE, VIDEO_FILE_NAME);\n\n    private static final String TXT = \"Hello\";\n\n    private static final String DISPLAY_NAME = \"display\";\n\n    private static final int EXTERNAL_PROVIDER_ID = 10;\n\n    private static final int INVALID_EXTERNAL_PROVIDER_ID = 1;\n\n    public static final String EXTERNAL_AUTHORITY = \"com.gsma.services.rcs.provider.externaltest\";\n\n    public static final Uri EXTERNAL_URI = Uri.parse(\"content://\" + EXTERNAL_AUTHORITY);\n\n    public static final String EXTERNAL_TABLE = \"mytable\";\n\n    public static final String EXTERNAL_TABLE_CREATE = \"create table if not exists \"\n            + EXTERNAL_TABLE + \" ( _id integer, myid text, mycontent text, mytimestamp integer )\";\n\n    public static final String EXTERNAL_DATABASE_NAME = \"my.db\";\n\n    private static final String[] PROJECTION = new String[] {\n            HistoryLog.PROVIDER_ID, HistoryLog.BASECOLUMN_ID, HistoryLog.ID\n    };\n\n    private static final String SELECTION_WITH_MESSAGE_ID = HistoryLog.ID + \"='\" + MESSAGE_ID + \"'\";\n\n    private static final String SELECTION_ID = HistoryLog.ID + \"=?\";\n\n    private static final String[] SELECTION_ARGS = new String[] {\n        MESSAGE_ID\n    };\n\n    private static final String SORT_TIMESTAMP_ASC = HistoryLog.TIMESTAMP + \" ASC\";\n\n    private static final String SORT_TIMESTAMP_DESC = HistoryLog.TIMESTAMP + \" DESC\";\n\n    private static IHistoryService mHistoryService;\n\n    private MessagingLog mMessagingLog;\n\n    private static LocalContentResolver sLocalContentResolver;\n\n    private RichCallHistory mRichCallHistory;\n\n    private Random mRandom = new Random();\n\n    private long mTimestamp;\n\n    private long mTimestampSent;\n\n    private ContactUtil mContactUtil;\n\n    static class MyContentProvider extends ContentProvider {\n\n        @Override\n        public boolean onCreate() {\n            return true;\n        }\n\n        @Override\n        public Cursor query(@NonNull Uri uri, String[] projection, String selection,\n                String[] selectionArgs, String sortOrder) {\n            Log.i(\"HISTORY\", \"query external\");\n\n            SQLiteDatabase db = getContext().openOrCreateDatabase(EXTERNAL_DATABASE_NAME,\n                    Context.MODE_PRIVATE, null);\n            Cursor c = db.query(EXTERNAL_TABLE, projection, null, null, null, null, null);\n            assertNotNull(c);\n\n            return c;\n        }\n\n        @Override\n        public String getType(@NonNull Uri uri) {\n            return \"vnd.android.cursor.item/test\";\n        }\n\n        @Override\n        public Uri insert(@NonNull Uri uri, ContentValues values) {\n            return null;\n        }\n\n        @Override\n        public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {\n            return 0;\n        }\n\n        @Override\n        public int update(@NonNull Uri uri, ContentValues values, String selection,\n                String[] selectionArgs) {\n            return 0;\n        }\n    }\n\n    ContentProvider getContentProvider(ContentResolver resolver, Uri uri) {\n        if (resolver == null) {\n            throw new IllegalArgumentException(\"resolver is null!\");\n        }\n        ContentProviderClient contentProviderClient = resolver.acquireContentProviderClient(uri);\n        if (contentProviderClient == null) {\n            throw new SQLException(\"Cannot revolve ContentProviderClient\");\n        }\n        ContentProvider provider = contentProviderClient.getLocalContentProvider();\n        if (provider == null) {\n            throw new SQLException(\"Cannot revolve ContentProvider\");\n        }\n        return provider;\n    }\n\n    protected void setUp() throws Exception {\n        super.setUp();\n\n        ContentResolver realResolver = getContext().getContentResolver();\n        MockContentResolver mockResolver = new MockContentResolver();\n        IsolatedContext iContext = new IsolatedContext(mockResolver, super.getContext());\n\n        ContentProvider provider = getContentProvider(realResolver, ChatLog.Message.CONTENT_URI);\n        mockResolver.addProvider(ChatLog.Message.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, FileTransferLog.CONTENT_URI);\n        mockResolver.addProvider(ChatLog.Message.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, ImageSharingLog.CONTENT_URI);\n        mockResolver.addProvider(ChatLog.Message.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, VideoSharingLog.CONTENT_URI);\n        mockResolver.addProvider(ChatLog.Message.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, GeolocSharingLog.CONTENT_URI);\n        mockResolver.addProvider(GeolocSharingLog.CONTENT_URI.getAuthority(), provider);\n\n        HistoryProvider historyProvider = (HistoryProvider) getContentProvider(realResolver,\n                HistoryLog.CONTENT_URI);\n\n        mockResolver.addProvider(HistoryLog.CONTENT_URI.getAuthority(), historyProvider);\n        mockResolver.addProvider(EXTERNAL_AUTHORITY, sMyContentProvider);\n\n        historyProvider.registerInternalProviders();\n\n        sMyContentProvider.attachInfo(iContext, null);\n\n        setContext(iContext);\n\n        if (sLocalContentResolver == null) {\n            sLocalContentResolver = new LocalContentResolver(mockResolver);\n        }\n        mMessagingLog = MessagingLog.getInstance(sLocalContentResolver,\n                RcsSettingsMock.getMockSettings(iContext));\n        RichCallHistory.getInstance(sLocalContentResolver);\n        mRichCallHistory = RichCallHistory.getInstance();\n        mContactUtil = ContactUtil.getInstance(new ContactUtilMockContext(\n                new ContactUtilMockContext(getContext())));\n\n        provider = getContentProvider(realResolver, (MessageData.CONTENT_URI));\n        mockResolver.addProvider(MessageData.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, (FileTransferData.CONTENT_URI));\n        mockResolver.addProvider(FileTransferData.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, (ImageSharingData.CONTENT_URI));\n        mockResolver.addProvider(ImageSharingData.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, (VideoSharingData.CONTENT_URI));\n        mockResolver.addProvider(VideoSharingData.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, (GeolocSharingData.CONTENT_URI));\n        mockResolver.addProvider(GeolocSharingData.CONTENT_URI.getAuthority(), provider);\n\n        provider = getContentProvider(realResolver, (HistoryLogData.CONTENT_URI));\n        mockResolver.addProvider(HistoryLogData.CONTENT_URI.getAuthority(), provider);\n\n        sLocalContentResolver.delete(MessageData.CONTENT_URI, null, null);\n        sLocalContentResolver.delete(ImageSharingData.CONTENT_URI, null, null);\n        sLocalContentResolver.delete(VideoSharingData.CONTENT_URI, null, null);\n        sLocalContentResolver.delete(GeolocSharingData.CONTENT_URI, null, null);\n\n        SQLiteDatabase dbft = getContext().openOrCreateDatabase(FileTransferProvider.DATABASE_NAME,\n                Context.MODE_PRIVATE, null);\n        dbft.delete(FileTransferProvider.TABLE, null, null);\n        dbft.close();\n\n        mHistoryService = new HistoryServiceImpl(getContext());\n\n        getContext().deleteDatabase(EXTERNAL_DATABASE_NAME);\n        SQLiteDatabase db = getContext().openOrCreateDatabase(EXTERNAL_DATABASE_NAME,\n                Context.MODE_PRIVATE, null);\n        db.execSQL(EXTERNAL_TABLE_CREATE);\n        db.delete(EXTERNAL_TABLE, null, null);\n        db.close();\n        mTimestamp = mRandom.nextLong();\n        mTimestampSent = mRandom.nextLong();\n    }\n\n    public Context getContext() {\n        return super.getContext();\n    }\n\n    protected void tearDown() throws Exception {\n        super.tearDown();\n        RcsSettingsMock.restoreSettings();\n    }\n\n    private ContactId getRemoteContact() throws RcsPermissionDeniedException {\n        return mContactUtil.formatContact(REMOTE_CONTACT_NUMBER);\n    }\n\n    private void addOutgoingFileTransferSharing() throws RcsPermissionDeniedException {\n        mMessagingLog.addOneToOneFileTransfer(FILE_TRANSFER_ID, getRemoteContact(),\n                Direction.INCOMING, CONTENT, THUMBNAIL, FileTransfer.State.INVITED,\n                FileTransfer.ReasonCode.UNSPECIFIED, mTimestamp++, mTimestampSent++,\n                FileTransferLog.UNKNOWN_EXPIRATION, FileTransferLog.UNKNOWN_EXPIRATION);\n    }\n\n    private void addOutgoingOneToOneChatMessages(String... ids)\n            throws RcsPermissionDeniedException, PayloadException, IOException {\n        if (ids.length == 0) {\n            ChatMessage msg = new ChatMessage(MESSAGE_ID, getRemoteContact(), TXT,\n                    MimeType.TEXT_MESSAGE, mTimestamp++, mTimestampSent++, DISPLAY_NAME);\n            mMessagingLog.addOutgoingOneToOneChatMessage(msg, Message.Content.Status.SENT,\n                    Message.Content.ReasonCode.UNSPECIFIED, 0);\n        }\n        for (String id : ids) {\n            ChatMessage msg = new ChatMessage(id, getRemoteContact(), TXT, MimeType.TEXT_MESSAGE,\n                    mTimestamp++, mTimestampSent++, DISPLAY_NAME);\n            mMessagingLog.addOutgoingOneToOneChatMessage(msg, Message.Content.Status.SENT,\n                    Message.Content.ReasonCode.UNSPECIFIED, 0);\n        }\n    }\n\n    private void addOutgoingImageSharing() throws RcsPermissionDeniedException {\n        mRichCallHistory.addImageSharing(IMAGE_SHARING_ID, getRemoteContact(), Direction.INCOMING,\n                CONTENT, ImageSharing.State.ACCEPTING, ImageSharing.ReasonCode.UNSPECIFIED,\n                mTimestamp++);\n    }\n\n    private void addOutgoingVideoSharing() throws RcsPermissionDeniedException {\n        mRichCallHistory.addVideoSharing(VIDEO_SHARING_ID, getRemoteContact(), Direction.INCOMING,\n                VIDEO_CONTENT, VideoSharing.State.ACCEPTING, VideoSharing.ReasonCode.UNSPECIFIED,\n                mTimestamp++);\n    }\n\n    private void addOutgoingGeolocSharing() throws RcsPermissionDeniedException {\n        mRichCallHistory.addOutgoingGeolocSharing(getRemoteContact(), GEOLOC_SHARING_ID,\n                new Geoloc(\"test\", 0, 0, 0, 0), GeolocSharing.State.TRANSFERRED,\n                GeolocSharing.ReasonCode.UNSPECIFIED, mTimestamp++);\n    }\n\n    private void addItems() throws RcsPermissionDeniedException, PayloadException, IOException {\n        addOutgoingOneToOneChatMessages();\n        addOutgoingFileTransferSharing();\n        addOutgoingImageSharing();\n        addOutgoingVideoSharing();\n        addOutgoingGeolocSharing();\n    }\n\n    private Uri getUriWithAllInternalProviders() {\n        return createHistoryUri(ChatLog.Message.HISTORYLOG_MEMBER_ID,\n                FileTransferData.HISTORYLOG_MEMBER_ID, ImageSharingData.HISTORYLOG_MEMBER_ID,\n                VideoSharingData.HISTORYLOG_MEMBER_ID, GeolocSharingData.HISTORYLOG_MEMBER_ID);\n    }\n\n    private void verifyHistoryLogEntries(Cursor cursor) {\n        boolean messageEncountered = false;\n        boolean fileTransferEncountered = false;\n        boolean imageSharingEncountered = false;\n        boolean videoSharingEncountered = false;\n        boolean geolocSharingEncountered = false;\n\n        while (cursor.moveToNext()) {\n            int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n            String readUniqueId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n\n            if (ChatLog.Message.HISTORYLOG_MEMBER_ID == providerId) {\n                assertEquals(MESSAGE_ID, readUniqueId);\n                messageEncountered = true;\n\n            } else if (FileTransferData.HISTORYLOG_MEMBER_ID == providerId) {\n                assertEquals(FILE_TRANSFER_ID, readUniqueId);\n                fileTransferEncountered = true;\n\n            } else if (ImageSharingData.HISTORYLOG_MEMBER_ID == providerId) {\n                assertEquals(IMAGE_SHARING_ID, readUniqueId);\n                imageSharingEncountered = true;\n\n            } else if (GeolocSharingData.HISTORYLOG_MEMBER_ID == providerId) {\n                assertEquals(GEOLOC_SHARING_ID, readUniqueId);\n                geolocSharingEncountered = true;\n\n            } else {\n                assertEquals(VideoSharingData.HISTORYLOG_MEMBER_ID, providerId);\n                assertEquals(VIDEO_SHARING_ID, readUniqueId);\n                videoSharingEncountered = true;\n            }\n        }\n        assertTrue(messageEncountered);\n        assertTrue(fileTransferEncountered);\n        assertTrue(imageSharingEncountered);\n        assertTrue(videoSharingEncountered);\n        assertTrue(geolocSharingEncountered);\n    }\n\n    private void verifyChatLogEntry(Cursor cursor) {\n        while (cursor.moveToNext()) {\n            int providerId = cursor.getInt(cursor.getColumnIndexOrThrow(HistoryLog.PROVIDER_ID));\n            String readUniqueId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n\n            assertEquals(ChatLog.Message.HISTORYLOG_MEMBER_ID, providerId);\n            assertEquals(MESSAGE_ID, readUniqueId);\n        }\n    }\n\n    private static Uri createHistoryUri(int... providerIds) {\n        HistoryUriBuilder uriBuilder = new HistoryUriBuilder(HistoryLog.CONTENT_URI);\n\n        for (int providerId : providerIds) {\n            uriBuilder.appendProvider(providerId);\n        }\n\n        return uriBuilder.build();\n    }\n\n    private static Map<String, String> getExternalColumnMapping() {\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLog.PROVIDER_ID, String.valueOf(EXTERNAL_PROVIDER_ID));\n        columnMapping.put(HistoryLog.BASECOLUMN_ID, BaseColumns._ID);\n        columnMapping.put(HistoryLog.ID, \"myid\");\n        columnMapping.put(HistoryLog.CONTENT, \"mycontent\");\n        columnMapping.put(HistoryLog.TIMESTAMP, \"mytimestamp\");\n        return columnMapping;\n    }\n\n    public void testQueryHistoryLogProviderWithoutProjection() throws RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, null, null, null, null);\n        assertNotNull(cursor);\n        assertEquals(5, cursor.getCount());\n        verifyHistoryLogEntries(cursor);\n        cursor.close();\n    }\n\n    public void testQueryHistoryLogProviderWithProjection() throws RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, PROJECTION, null, null,\n                null);\n        assertNotNull(cursor);\n        assertEquals(5, cursor.getCount());\n        verifyHistoryLogEntries(cursor);\n        cursor.close();\n    }\n\n    public void testQueryHistoryLogProviderWithSelection() throws RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, null,\n                SELECTION_WITH_MESSAGE_ID, null, null);\n        assertNotNull(cursor);\n        assertEquals(1, cursor.getCount());\n        verifyChatLogEntry(cursor);\n        cursor.close();\n    }\n\n    public void testQueryHistoryLogProviderWithSelectionArgs() throws RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, null, SELECTION_ID,\n                SELECTION_ARGS, null);\n        assertNotNull(cursor);\n        assertEquals(1, cursor.getCount());\n        verifyChatLogEntry(cursor);\n        cursor.close();\n    }\n\n    public void testQueryHistoryLogProviderWithSelectionEmpty()\n            throws RcsPermissionDeniedException, PayloadException, IOException {\n        addItems();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, null, SELECTION_EMPTY,\n                null, null);\n        assertNotNull(cursor);\n        assertEquals(5, cursor.getCount());\n        verifyHistoryLogEntries(cursor);\n        cursor.close();\n    }\n\n    public void testQueryHistoryLogProviderWithSelectionNotEmpty()\n            throws RcsPermissionDeniedException, PayloadException, IOException {\n        addItems();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, null,\n                SELECTION_NOT_EMPTY, null, null);\n        assertNotNull(cursor);\n        assertEquals(5, cursor.getCount());\n        verifyHistoryLogEntries(cursor);\n        cursor.close();\n    }\n\n    public void testQueryHistoryLogProviderWithSort() throws RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addOutgoingOneToOneChatMessages();\n        addOutgoingFileTransferSharing();\n        Uri historyUri = getUriWithAllInternalProviders();\n        Cursor cursor = getContext().getContentResolver().query(historyUri, null, null, null,\n                SORT_TIMESTAMP_ASC);\n        assertEquals(2, cursor.getCount());\n        cursor.moveToNext();\n        String firstAscId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        cursor.moveToNext();\n        String secondAscId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        cursor = getContext().getContentResolver().query(historyUri, null, null, null,\n                SORT_TIMESTAMP_DESC);\n        assertNotNull(cursor);\n        assertEquals(2, cursor.getCount());\n        cursor.moveToNext();\n        String firstDescId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        cursor.moveToNext();\n        String secondDescId = cursor.getString(cursor.getColumnIndexOrThrow(HistoryLog.ID));\n        assertEquals(firstAscId, secondDescId);\n        assertEquals(secondAscId, firstDescId);\n        assertTrue(!firstAscId.equals(secondAscId));\n        cursor.close();\n    }\n\n    public void testRegisterInvalidExtraHistoryLogMember_badproviderid()\n            throws RcsPermissionDeniedException, PayloadException, IOException {\n        addItems();\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLog.PROVIDER_ID, String.valueOf(INVALID_EXTERNAL_PROVIDER_ID));\n\n        Uri database = Uri.fromFile(getContext().getDatabasePath(EXTERNAL_DATABASE_NAME));\n        try {\n            mHistoryService.registerExtraHistoryLogMember(INVALID_EXTERNAL_PROVIDER_ID,\n                    EXTERNAL_URI, database, EXTERNAL_TABLE, columnMapping);\n            fail();\n        } catch (Exception ignore) {\n        }\n    }\n\n    public void testRegisterExtraHistoryLogMemberWithForbiddenDatabases()\n            throws RcsPermissionDeniedException, PayloadException, IOException {\n        addItems();\n        Map<String, String> columnMapping = new HashMap<>();\n        columnMapping.put(HistoryLog.PROVIDER_ID, String.valueOf(EXTERNAL_PROVIDER_ID));\n\n        try {\n            mHistoryService.registerExtraHistoryLogMember(EXTERNAL_PROVIDER_ID, EXTERNAL_URI,\n                    Uri.fromFile(getContext().getDatabasePath(RcsSettingsProvider.DATABASE_NAME)),\n                    EXTERNAL_TABLE, columnMapping);\n            fail();\n        } catch (Exception ignore) {\n        }\n\n        try {\n            mHistoryService.registerExtraHistoryLogMember(EXTERNAL_PROVIDER_ID, EXTERNAL_URI,\n                    Uri.fromFile(getContext().getDatabasePath(ContactProvider.DATABASE_NAME)),\n                    EXTERNAL_TABLE, columnMapping);\n            fail();\n        } catch (Exception ignore) {\n        }\n    }\n\n    public void testRegisterExtraHistoryLogMemberWithMappingNull()\n            throws RcsPermissionDeniedException, PayloadException, IOException {\n        addItems();\n        Map<String, String> columnMapping = null;\n\n        Uri database = Uri.fromFile(getContext().getDatabasePath(EXTERNAL_DATABASE_NAME));\n        try {\n            mHistoryService.registerExtraHistoryLogMember(EXTERNAL_PROVIDER_ID, EXTERNAL_URI,\n                    database, EXTERNAL_TABLE, columnMapping);\n            fail();\n        } catch (Exception ignore) {\n        }\n    }\n\n    public void testUnregisterInvalidExtraHistoryLogMember() {\n        try {\n            mHistoryService.unregisterExtraHistoryLogMember(INVALID_EXTERNAL_PROVIDER_ID);\n            fail();\n        } catch (Exception ignore) {\n        }\n    }\n\n    public void testSQLInjection_selection() throws RemoteException, RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems(); // 5\n\n        assertEquals(\n                5,\n                getContext().getContentResolver()\n                        .query(getUriWithAllInternalProviders(), null, null, null, null).getCount());\n\n        try {\n            getContext().getContentResolver()\n                    .query(createHistoryUri(1), null, \"_id = 1;DROP TABLE MESSAGE;\", null, null)\n                    .close();\n            fail();\n        } catch (Exception e) {\n            addOutgoingOneToOneChatMessages(\"AnotherOne\"); // 1\n            assertEquals(\n                    6,\n                    getContext().getContentResolver()\n                            .query(getUriWithAllInternalProviders(), null, null, null, null)\n                            .getCount());\n        }\n    }\n\n    public void testSQLInjection_sort() throws RemoteException, RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems(); // 5\n\n        getContext().getContentResolver()\n                .query(createHistoryUri(1), null, null, null, \"_id;DROP TABLE MESSAGE;\").close();\n        addOutgoingOneToOneChatMessages(\"AnotherOne\"); // 1\n        assertEquals(\n                6,\n                getContext().getContentResolver()\n                        .query(getUriWithAllInternalProviders(), null, null, null, null).getCount());\n    }\n\n    public void testSQLInjection_tablename() throws RemoteException, RcsPermissionDeniedException,\n            PayloadException, IOException {\n        addItems(); // 5\n\n        assertEquals(\n                5,\n                getContext().getContentResolver()\n                        .query(getUriWithAllInternalProviders(), null, null, null, null).getCount());\n\n        Uri database = Uri.fromFile(getContext().getDatabasePath(EXTERNAL_DATABASE_NAME));\n        mHistoryService.registerExtraHistoryLogMember(EXTERNAL_PROVIDER_ID, EXTERNAL_URI, database,\n                EXTERNAL_TABLE + \";DROP TABLE MESSAGE;\", getExternalColumnMapping());\n\n        addOutgoingOneToOneChatMessages(\"YetAnotherOne\"); // 1\n        assertEquals(\n                6,\n                getContext().getContentResolver()\n                        .query(getUriWithAllInternalProviders(), null, null, null, null).getCount());\n    }\n\n}\n"
  },
  {
    "path": "core/tests/src/com/gsma/service/rcs/upload/FileUploadInfoTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.service.rcs.upload;\n\nimport java.io.File;\nimport java.util.Random;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.test.AndroidTestCase;\n\nimport com.gsma.services.rcs.upload.FileUploadInfo;\n\n/**\n * @author Danielle Rouquier\n */\npublic class FileUploadInfoTest extends AndroidTestCase {\n    File tFilef = new File(\"tFileName\");\n\n    File tIconFileName = new File(\"tIconFileName\");\n\n    Uri tFile;\n\n    long tValidity;\n\n    long tSize;\n\n    String tFileName;\n\n    String tMimeType;\n\n    Uri tFileIcon;\n\n    String tIconMimeType;\n\n    long tFileIconVal;\n\n    long tFileIconSize;\n\n    protected void setUp() throws Exception {\n        Random random = new Random();\n        tValidity = random.nextLong();\n        tFileIconVal = random.nextLong();\n        tSize = random.nextLong();\n        tFileName = String.valueOf(random.nextInt(96) + 32);\n        tMimeType = String.valueOf(random.nextInt(96) + 32);\n        tIconMimeType = String.valueOf(random.nextInt(96) + 32);\n        tFileIconSize = random.nextLong();\n        tFile = Uri.fromFile(tFilef);\n        tFileIcon = Uri.fromFile(tIconFileName);\n    }\n\n    public void testFileUploadInfoNull() {\n        Exception ex = null;\n        FileUploadInfo tfileUploadInfo = new FileUploadInfo(null, tValidity, tFileName, tSize,\n                tMimeType, tFileIcon, tFileIconVal, tFileIconSize, tIconMimeType);\n        // the constructor here issues no exception\n        try {\n            Parcel parcel = Parcel.obtain();\n            tfileUploadInfo.writeToParcel(parcel, 0);\n            // done writing, now reset parcel for reading\n            parcel.setDataPosition(0);\n            // finish round trip\n            FileUploadInfo.CREATOR.createFromParcel(parcel);\n        } catch (Exception e) {\n            ex = e;\n        }\n        assertTrue(\"File to upload URI should be not null\", (ex != null));\n    }\n\n    public void testFileUploadInfo() {\n        FileUploadInfo tfileUploadInfo = new FileUploadInfo(tFile, tValidity, tFileName, tSize,\n                tMimeType, tFileIcon, tFileIconVal, tFileIconSize, tIconMimeType);\n        Parcel parcel = Parcel.obtain();\n        tfileUploadInfo.writeToParcel(parcel, 0);\n        // done writing, now reset parcel for reading\n        parcel.setDataPosition(0);\n        // finish round trip\n        FileUploadInfo createFromParcel = FileUploadInfo.CREATOR.createFromParcel(parcel);\n        assertEquals(createFromParcel.getFile(), tfileUploadInfo.getFile());\n        assertEquals(createFromParcel.getFileExpiration(), tfileUploadInfo.getFileExpiration());\n        assertEquals(createFromParcel.getFileName(), tfileUploadInfo.getFileName());\n        assertEquals(createFromParcel.getSize(), tfileUploadInfo.getSize());\n        assertEquals(createFromParcel.getMimeType(), tfileUploadInfo.getMimeType());\n        assertEquals(createFromParcel.getFileIcon(), tfileUploadInfo.getFileIcon());\n        assertEquals(createFromParcel.getFileIconExpiration(),\n                tfileUploadInfo.getFileIconExpiration());\n        assertEquals(createFromParcel.getFileIconMimeType(), tfileUploadInfo.getFileIconMimeType());\n        assertEquals(createFromParcel.getFileIconSize(), tfileUploadInfo.getFileIconSize());\n    }\n\n    /**\n     * @throws java.lang.Exception\n     */\n    protected void tearDown() throws Exception {\n        super.tearDown();\n    }\n\n}\n"
  },
  {
    "path": "docs/SUPPORTED-STANDARDS.txt",
    "content": "-----------------------------------\n Supported standards at 07/09/2012\n-----------------------------------\n\n\n\n\nIETF:\n-----\n\nRFC 1321 - The MD5 Message-Digest Algorithm\nRFC 2327 - SDP: Session Description Protocol\nRFC 2373 - IP Version 6 Addressing Architecture\nRFC 2392 - Content-ID and Message-ID Uniform Resource Locators\nRFC 2617 - HTTP Authentication: Basic and Digest Access Authentication\nRFC 3261 - SIP: Session Initiation Protocol\nRFC 3263 - Session Initiation Protocol (SIP): Locating SIP Servers\nRFC 3264 - An Offer/Answer Model with the Session Description Protocol (SDP)\nRFC 3265 - Session Initiation Protocol (SIP) Specific Event Notification\nRFC 3325 - Private Extensions to the Session Initiation Protocol (SIP) forAsserted Identity within Trusted Networks\nRFC 3339 - Date and Time on the Internet\nRFC 3455 - Private Header (P-Header) Extensions to the Session Initiation Protocol (SIP) for the 3rd-Generation Partnership Project (3GPP)\nRFC 3515 - The Session Initiation Protocol (SIP) Refer Method\nRFC 3550 - RTP: A Transport Protocol for Real-Time Applications\nRFC 3608 - Session Initiation Protocol (SIP) Extension Header Field for Service Route Discovery During Registration\nRFC 3840 - Indicating User Agent Capabilities in the Session Initiation Protocol (SIP)\nRFC 3856 - A Presence Event Package for the Session Initiation Protocol (SIP)\nRFC 3857 - A Watcher Information Event Template-Package for the Session Initiation Protocol (SIP)\nRFC 3858 - An Extensible Markup Language (XML) Based Format for Watcher Information\nRFC 3862 - Common Presence and Instant Messaging (CPIM): Message Format\nRFC 3863 - Presence Information Data Format (PIDF)\nRFC 3891 - The Session Initiation Protocol (SIP) \"Replaces\" Header\nRFC 3903 - Session Initiation Protocol (SIP) Extension for Event State Publication\nRFC 3966 - The tel URI for Telephone Numbers\nRFC 3994 - Indication of Message Composition for Instant Messaging\nRFC 4007 - IPv6 Scoped Address Architecture\nRFC 4028 - The Session Timers in the Session Initiation Protocol (SIP)\nRFC 4145 - TCP-Based Media Transport in the Session Description Protocol (SDP)\nRFC 4566 - SDP: Session Description Protocol\nRFC 4662 - A Session Initiation Protocol (SIP) Event Notification Extension for Resource Lists\nRFC 4480 - RPID: Rich Presence Extensions to the Presence Information Data Format (PIDF)\nRFC 4481 - Timed Presence Extensions to the Presence Information Data Format (PIDF) to Indicate Status Information for Past and Future Time Intervals\nRFC 4961 - Symmetric RTP / RTP Control Protocol (RTCP)\nRFC 4975 - The Message Session Relay Protocol (MSRP)\nRFC 5262 - Presence Information Data Format (PIDF) Extension for Partial Presence\nRFC 5438 - Instant Message Disposition Notification (IMDN)\nRFC 5547 - A Session Description Protocol (SDP) Offer/Answer Mechanism to Enable File Transfer\nRFC 5626 - Managing Client-Initiated Connection in the Session Initiation Protocol\nRFC 5627 - Obtaining and Using Globally Routable User Agent URIs (GRUUs) in the Session Initiation Protocol (SIP)\nRFC 5839 - An Extension to Session Initiation Protocol (SIP) Events for Conditional Event Notification\"\nRFC 6135 - An Alternative Connection Model for the Message Session Relay Protocol (MSRP)\nRFC 6223 - Indication of Support for Keep-Alive\n\ndraft-ietf-sip-uri-list-conferencing-01\t - Conference Establishment Using Request-Contained Lists in the Session Initiation Protocol (SIP)\ndraft-ietf-sip-multiple-refer-01\t - Referring to Multiple Resources in the Session Initiation Protocol (SIP)\ndraft-ietf-simple-imdn-04\t\t - Instant Message Disposition Notification\ndraft-ietf-mmusic-file-transfer-mech-03\t - A Session Description Protocol (SDP) Offer/Answer Mechanism to Enable File Transfer\ndraft-ietf-simple-msrp-sessmatch-10\t - Session Matching Update for the Message Session Relay Protocol (MSRP)\ndraft-kaplan-dispatch-session-id-03\t - A Session Identifier for the Session Initiation Protocol (SIP)\n\n\n3GPP:\n-----\nTS 24.229 - IP multimedia call control protocol based on Session Initiation Protocol (SIP) and Session Description Protocol (SDP), Stage 3\nTS 24.279 - Combining Circuit Switched (CS) and IP Multimedia Subsystem (IMS) services, Stage 3\n\n\nOMA:\n----\n\nInstant Messaging using SIMPLE Architecture, v1.0\nInstant Messaging Requirements, v1.0\nInstant Messaging using SIMPLE, v1.0\nPresence SIMPLE Architecture, v2.0\nResource List Server (RLS) XDM Specification, v2.0\n\n\nGSMA:\n-----\n\nRCS Release 1 - Functional Description\nRCS Release 1 - Technical Realization\nRCS Release 2 - Functional Description\nRCS Release 2 - Technical Realization\nRCS Release 2 - Endorsement of OMA SIP/SIMPLE IM 1.0\nRCS Release 2 - Management Objects\nRCS-e Version 1.1 - Services and Client Specification\nRCS-e Version 1.2.1 - Services and Client Specification\nRCS-e GSMA RCS IOT RCS-e Implementation Guidelines 2.1\nRCS-e GSMA RCS IOT RCS-e Implementation Guidelines 3.1\n\nIR74 - Video Share Interoper ability Specification\nIR79 - Image Share Interoperability Specification\n\n"
  },
  {
    "path": "eclipse/README.txt",
    "content": "Instructions to format source files according to android rules:\n\nThe formatting guidelines are in the file called android-formatting-rules.xml in the eclipse directory.\nThere are also as set of rules of how to order the imports in the file called android.importorder.\n\n1- Import it with Eclipse\nMenu bar -> Window -> Preferences -> Java -> Code Style -> Formatter -> Import\nPoint it to the eclipse folder and select the android-eclipse-formatting.xml\n\nMenu bar -> Window -> Preferences -> Java -> Code Style -> Organize Imports -> Import\nPoint it to the eclipse folder and select the android.importorder\n\n2- Format source files\nFrom the Eclipse GUI, right click on the source folder then select \"Source -> Format\"\n\nOnce formatted, a source file should not be changed if you reformat it manually using the <CTRL>+A (Select all) then <CTRL>+F (Format) sequences.\n\nEnsure that XML, AIDL and java files are converted to UNIX text file format (Line delimiter: LF)\nfind <source directory> -name \"*.java\" -exec dos2unix {} \\;\nfind <source directory> -name \"*.aidl\" -exec dos2unix {} \\;\nfind <resource directory> -name \"*.xml\" -exec dos2unix {} \\;\n\nAll committed files MUST be formatted according to above rules.\n"
  },
  {
    "path": "eclipse/android-eclipse-formatting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<profiles version=\"12\">\n<profile kind=\"CodeFormatterProfile\" name=\"Android\" version=\"12\">\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.disabling_tag\" value=\"@formatter:off\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_field\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_on_off_tags\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_ellipsis\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiple_fields\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_binary_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_array_initializer\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_binary_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_package\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.source\" value=\"1.8\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_line_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.join_wrapped_lines\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_member_type\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_type_members_on_columns\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_parameter_description\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"100\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.enabling_tag\" value=\"@formatter:on\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.problem.assertIdentifier\" value=\"error\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_body\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_method\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_method_declaration\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_switch\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.problem.enumIdentifier\" value=\"error\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_ellipsis\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_method_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.compact_else_if\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_root_tags\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_constant\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block_in_case\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.compliance\" value=\"1.8\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_lambda_body\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_binary_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"enabled\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_label\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"100\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_import_groups\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_binary_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_block\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.join_lines_in_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_if\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_html\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_source_code\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.8\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_resources_in_try\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_header\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_block_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line\" value=\"false\"/>\n</profile>\n</profiles>\n"
  },
  {
    "path": "eclipse/android.importorder",
    "content": "10=javax\n9=java\n8=org\n7=net\n6=libcore\n5=junit\n4=gov\n3=dalvik\n2=android\n1=com\n0=com.gsma\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Thu Dec 15 09:18:52 CET 2016\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.14.1-all.zip\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "libs/api/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "libs/api/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n\tlintOptions {\n\t\tabortOnError false\n\t}\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\t\n\tdefaultConfig {\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n    }\n}\n\nconfigurations {\n    jaxDoclet\n    classpaths\n}\n\ndependencies {\n    jaxDoclet(\"com.google.doclava:doclava:1.0.6\")\n    classpaths files(new File(System.getenv('ANDROID_HOME') + '/platforms/rootProject.targetSdkVersion/android.jar'))\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    exclude {\n        it.file.path.contains('aidl')\n    }\n    title = null\n    options.docletpath = configurations.jaxDoclet.files.asType(List)\n    options.classpath = configurations.classpaths.files.asType(List)\n    options {\n        doclet \"com.google.doclava.Doclava\"\n        bootClasspath new File(System.getenv('JAVA_HOME') + \"/jre/lib/rt.jar\")\n\t\taddStringOption \"d\", \"./build/docs/javadoc\"\n        addStringOption \"hdf project.name\", \"RCS API\"\n        addStringOption \"hdf sdk.version\", \"1.6\"\n        addStringOption \"title\", \"TAPI 1.6.1\"\n        addStringOption \"federate android\", \"http://developer.android.com/reference/\"\n        addStringOption \"federationxml android\", \"http://doclava.googlecode.com/svn/static/api/android-10.xml\"\n        addStringOption \"since ./version/blackbird_1_5_1.xml\", \"1.5\"\n\t\taddStringOption \"since ./version/crane_1_6_1.xml\", \"1.6\"\n    }\n}"
  },
  {
    "path": "libs/api/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:/adt-bundle-windows-x86_64/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "libs/api/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.services.rcs\">\n</manifest>\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/Geoloc.aidl",
    "content": "package com.gsma.services.rcs;\n\n/**\n * Geoloc object\n */\nparcelable Geoloc;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/ICommonServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Common service configuration interface\n */\n\ninterface ICommonServiceConfiguration {\n\n\tint getDefaultMessagingMethod();\n\t\n\tint getMessagingUX();\n\t\n\tContactId getMyContactId();\n\t\n\tString getMyDisplayName();\n\t \n\tboolean isConfigValid();\n\t\n\tvoid setDefaultMessagingMethod(in int method);\n\t\n\tvoid setMyDisplayName(in String name);\n\t\n\tint getMinimumBatteryLevel();\n\t\n\tvoid setMinimumBatteryLevel( in int level);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/IRcsServiceRegistrationListener.aidl",
    "content": "package com.gsma.services.rcs;\n\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * RCS service registration events listener\n */\ninterface IRcsServiceRegistrationListener {\n\n\tvoid onServiceRegistered();\n\n\tvoid onServiceUnregistered(in int reasonCode);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/RcsServiceRegistration.aidl",
    "content": "package com.gsma.services.rcs;\n\n/**\n * ReasonCode object\n */\nparcelable RcsServiceRegistration.ReasonCode;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/capability/Capabilities.aidl",
    "content": "package com.gsma.services.rcs.capability;\n\n/**\n * Capabilities object\n */\nparcelable Capabilities;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/capability/ICapabilitiesListener.aidl",
    "content": "package com.gsma.services.rcs.capability;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport com.gsma.services.rcs.capability.Capabilities;\n\n/**\n * Callback method for new capabilities\n */\ninterface ICapabilitiesListener {\n\tvoid onCapabilitiesReceived(in ContactId contact, in Capabilities capabilities);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/capability/ICapabilityService.aidl",
    "content": "package com.gsma.services.rcs.capability;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.capability.ICapabilitiesListener;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Capability service API\n */\ninterface ICapabilityService {\n\n\tboolean isServiceRegistered();\n\t\n\tint getServiceRegistrationReasonCode();\n\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tCapabilities getMyCapabilities();\n\n\tCapabilities getContactCapabilities(in ContactId contact);\n\n\tvoid requestContactCapabilities(in ContactId contact);\n\n    void requestAllContactsCapabilities();\n\n\tvoid requestContactCapabilities2(in List<ContactId> contacts);\n\n\tvoid addCapabilitiesListener(in ICapabilitiesListener listener);\n\n\tvoid removeCapabilitiesListener(in ICapabilitiesListener listener);\n\n\tvoid addCapabilitiesListener2(in ContactId contact, in ICapabilitiesListener listener);\n\n\tvoid removeCapabilitiesListener2(in ContactId contact, in ICapabilitiesListener listener);\n\t\n\tint getServiceVersion();\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IChatMessage.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\ninterface IChatMessage {\n\n\tContactId getContact();\n\n\tString getId();\n\n\tString getContent();\n\n\tString getMimeType();\n\n\tint getDirection();\n\n\tlong getTimestamp();\n\n\tlong getTimestampSent();\n\n\tlong getTimestampDelivered();\n\n\tlong getTimestampDisplayed();\n\n\tint getStatus();\n\n\tint getReasonCode();\n\n\tString getChatId();\n\n\tboolean isRead();\n\n\tboolean isExpiredDelivery();\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IChatService.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.chat.IOneToOneChatListener;\nimport com.gsma.services.rcs.chat.IOneToOneChat;\nimport com.gsma.services.rcs.chat.IGroupChatListener;\nimport com.gsma.services.rcs.chat.IGroupChat;\nimport com.gsma.services.rcs.chat.IChatServiceConfiguration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Chat service API\n */\ninterface IChatService {\n\n\tboolean isServiceRegistered();\n\t\n\tint getServiceRegistrationReasonCode();\n    \n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tIChatServiceConfiguration getConfiguration();\n    \n\tIGroupChat initiateGroupChat(in List<ContactId> contacts, in String subject);\n\n\tIOneToOneChat getOneToOneChat(in ContactId contact);\n\n\tIGroupChat getGroupChat(in String chatId);\n\t\n\tvoid markMessageAsRead(in String msgId);\n\n\tvoid addEventListener3(in IGroupChatListener listener);\n\n\tvoid removeEventListener3(in IGroupChatListener listener);\n\n\tvoid addEventListener2(in IOneToOneChatListener listener);\n\n\tvoid removeEventListener2(in IOneToOneChatListener listener);\n\n\tint getServiceVersion();\n\n\tIChatMessage getChatMessage(in String msgId);\n\n\tICommonServiceConfiguration getCommonConfiguration();\n\n\tboolean isAllowedToInitiateGroupChat();\n\n\tboolean isAllowedToInitiateGroupChat2(in ContactId contact);\n\n\tvoid deleteOneToOneChats();\n\n\tvoid deleteGroupChats();\n\n\tvoid deleteOneToOneChat(in ContactId contact);\n\n\tvoid deleteGroupChat(in String chatId);\n\n\tvoid deleteMessage(in String msgId);\n\n\tvoid clearMessageDeliveryExpiration(in List<String> msgIds);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IChatServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\n/**\n * Chat service configuration interface\n */\ninterface IChatServiceConfiguration {\n\n\tlong getIsComposingTimeout();\n\n\tlong getGeolocExpirationTime();\n\t\n\tint getGeolocLabelMaxLength();\n\t\n\tint getGroupChatMaxParticipants();\n\t\n\tint getGroupChatMessageMaxLength();\n\t\n\tint getGroupChatMinParticipants();\n\t\n\tint getGroupChatSubjectMaxLength();\n\t\n\tint getOneToOneChatMessageMaxLength();\n\n\tboolean isChatWarnSF();\n\t\n\tboolean isGroupChatSupported();\n\t\n\tboolean isRespondToDisplayReportsEnabled();\n\t\n\tboolean isSmsFallback();\n\t\n\tvoid setRespondToDisplayReports(in boolean enable);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IGroupChat.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.chat.IGroupChatListener;\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.filetransfer.IFileTransfer;\nimport com.gsma.services.rcs.filetransfer.IOneToOneFileTransferListener;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Group chat interface\n */\ninterface IGroupChat {\n\n\tString getChatId();\n\n\tint getDirection();\n\t\n\tint getState();\t\n\n\tint getReasonCode();\n\n\tContactId getRemoteContact();\n\n\tString getSubject();\t\n\n\tMap getParticipants();\n\n\tlong getTimestamp();\n\n\tIChatMessage sendMessage(in String text);\n\n\tvoid setComposingStatus(in boolean ongoing);\n\n\tvoid inviteParticipants(in List<ContactId> participants);\n\t\n\tint getMaxParticipants();\n\t\n\tvoid leave();\n\n\tIChatMessage sendMessage2(in Geoloc geoloc);\n\n\tvoid openChat();\n\n\tboolean isAllowedToSendMessage();\n\n\tboolean isAllowedToInviteParticipants();\n\n\tboolean isAllowedToInviteParticipant(in ContactId participant);\n\n\tboolean isAllowedToLeave();\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IGroupChatListener.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Group chat event listener\n */\ninterface IGroupChatListener {\n\n\tvoid onStateChanged(in String chatId, in int state, in int reasonCode);\n\n\tvoid onComposingEvent(String chatId, in ContactId contact, in boolean status);\n\n\tvoid onMessageStatusChanged(in String chatId, in String mimeType, in String msgId, in int status,\n\t\t\t in int reasonCode);\n\n\tvoid onMessageGroupDeliveryInfoChanged(in String chatId, in ContactId contact, in String mimeType,\n\t\t\tin String msgId, in int status, in int reasonCode);\n\n\tvoid onParticipantStatusChanged(in String chatId, in ContactId contact, in int status);\n\n\tvoid onDeleted(in List<String> chatIds);\n\n\tvoid onMessagesDeleted(in String chatId, in List<String> msgIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IOneToOneChat.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.chat.IChatMessage;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * One-to-One Chat interface\n */\ninterface IOneToOneChat {\n\n\tContactId getRemoteContact();\n\n\tIChatMessage sendMessage(in String message);\n\n\tvoid setComposingStatus(in boolean ongoing);\n\n\tIChatMessage sendMessage2(in Geoloc geoloc);\n\n\tvoid openChat();\n\n\tvoid resendMessage(in String msgId);\n\n\tboolean isAllowedToSendMessage();\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/chat/IOneToOneChatListener.aidl",
    "content": "package com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * One-to-One Chat event listener\n */\ninterface IOneToOneChatListener {\n\n\tvoid onMessageStatusChanged(in ContactId contact, in String mimeType, in String msgId,\n\t\t\tin int status, in int reasonCode);\n\n\tvoid onComposingEvent(in ContactId contact, in boolean status);\n\n\tvoid onMessagesDeleted(in ContactId contact, in List<String> msgIds);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/contact/ContactId.aidl",
    "content": "package com.gsma.services.rcs.contact;\n\n/**\n * contactId object\n */\nparcelable ContactId;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/contact/IContactService.aidl",
    "content": "package com.gsma.services.rcs.contact;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.contact.RcsContact;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\n\n/**\n * Contacts service API\n */\ninterface IContactService {\n\n\tboolean isServiceRegistered();\n\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tRcsContact getRcsContact(in ContactId contact);\n\n\tList<RcsContact> getRcsContacts();\n\n\tList<RcsContact> getRcsContactsOnline();\n\n\tList<RcsContact> getRcsContactsSupporting(in String tag);\n\t\n\tint getServiceVersion();\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n\t\n\tvoid blockContact(in ContactId contact);\n\n\tvoid unblockContact(in ContactId contact);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/contact/RcsContact.aidl",
    "content": "package com.gsma.services.rcs.contact;\n\n/**\n * Rcs contact object\n */\nparcelable RcsContact;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/extension/IMultimediaMessagingSession.aidl",
    "content": "package com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Multimedia messaging session interface\n */\ninterface IMultimediaMessagingSession {\n\n\tString getSessionId();\n\t\n\tContactId getRemoteContact();\n\t\n\tString getServiceId();\n\t\n\tint getState();\n\t\n\tint getReasonCode();\n\t\n\tint getDirection();\n\t\n\tvoid acceptInvitation();\n\t\n\tvoid rejectInvitation();\n\t\n\tvoid abortSession();\n\n\tvoid sendMessage(in byte[] content);\n\n\tvoid sendMessage2(in byte[] content, in String contentType);\n\n\tvoid flushMessages();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/extension/IMultimediaMessagingSessionListener.aidl",
    "content": "package com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for multimedia messaging session events\n */\ninterface IMultimediaMessagingSessionListener {\n\n\tvoid onStateChanged(in ContactId contact, in String sessionId, in int state, in int reasonCode);\n\n\tvoid onMessageReceived(in ContactId contact, in String sessionId, in byte[] content);\n\n\tvoid onMessageReceived2(in ContactId contact, in String sessionId, in byte[] content, in String contentType);\n\n\tvoid onMessagesFlushed(in ContactId contact, in String sessionId);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/extension/IMultimediaSessionService.aidl",
    "content": "package com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.extension.IMultimediaMessagingSession;\nimport com.gsma.services.rcs.extension.IMultimediaMessagingSessionListener;\nimport com.gsma.services.rcs.extension.IMultimediaStreamingSession;\nimport com.gsma.services.rcs.extension.IMultimediaStreamingSessionListener;\nimport com.gsma.services.rcs.extension.IMultimediaSessionServiceConfiguration;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Multimedia session service API for extended services\n */\ninterface IMultimediaSessionService {\n\n\tboolean isServiceRegistered();\n\t\n\tint getServiceRegistrationReasonCode();\n\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tIMultimediaSessionServiceConfiguration getConfiguration();\n\n\tList<IBinder> getMessagingSessions(in String serviceId);\n\t\n\tIMultimediaMessagingSession getMessagingSession(in String sessionId);\n\t\n\tIMultimediaMessagingSession initiateMessagingSession(in String serviceId, in ContactId contact);\n\t\n\tIMultimediaMessagingSession initiateMessagingSession2(in String serviceId, in ContactId contact, in String[] acceptTypes, in String[] acceptWrappedTypes);\n\n\tList<IBinder> getStreamingSessions(in String serviceId);\n\t\n\tIMultimediaStreamingSession getStreamingSession(in String sessionId);\n\t\n\tIMultimediaStreamingSession initiateStreamingSession(in String serviceId, in ContactId contact);\n\n\tIMultimediaStreamingSession initiateStreamingSession2(in String serviceId, in ContactId contact, in String encoding);\n\n\tvoid sendInstantMultimediaMessage(in String serviceId, in ContactId contact, in byte[] content, String contentType);\n\n\tint getServiceVersion();\n\n\tvoid addEventListener2(in IMultimediaMessagingSessionListener listener);\n\n\tvoid removeEventListener2(in IMultimediaMessagingSessionListener listener);\n\n\tvoid addEventListener3(in IMultimediaStreamingSessionListener listener);\n\n\tvoid removeEventListener3(in IMultimediaStreamingSessionListener listener);\n\n\tICommonServiceConfiguration getCommonConfiguration();\n}\n\n\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/extension/IMultimediaSessionServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs.extension;\n\n/**\n * Multimedia session service configuration interface\n */\ninterface IMultimediaSessionServiceConfiguration {\n\n\tint getMessageMaxLength();\n\n\tlong getMessagingSessionInactivityTimeout(in String serviceId);\n\n\tboolean isServiceActivated(in String serviceId);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/extension/IMultimediaStreamingSession.aidl",
    "content": "package com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Multimedia streaming session interface\n */\ninterface IMultimediaStreamingSession {\n\n\tString getSessionId();\n\t\n\tContactId getRemoteContact();\n\t\n\tString getServiceId();\n\t\n\tint getState();\n\t\n\tint getReasonCode();\n\t\n\tint getDirection();\n\t\n\tvoid acceptInvitation();\n\t\n\tvoid rejectInvitation();\n\t\n\tvoid abortSession();\n\n\tvoid sendPayload(in byte[] content);\n}\n\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/extension/IMultimediaStreamingSessionListener.aidl",
    "content": "package com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for multimedia streaming session events\n */\ninterface IMultimediaStreamingSessionListener {\n\n\tvoid onStateChanged(in ContactId contact, in String sessionId, in int state, in int reasonCode);\n\n\tvoid onPayloadReceived(in ContactId contact, in String sessionId, in byte[] content);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/filetransfer/IFileTransfer.aidl",
    "content": "package com.gsma.services.rcs.filetransfer;\n\nimport android.net.Uri;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * File transfer interface\n */\ninterface IFileTransfer {\n\n\tString getChatId();\n\n\tString getTransferId();\n\n\tContactId getRemoteContact();\n\n\tString getFileName();\n\n\tlong getFileSize();\n\n\tString getMimeType();\n\n\tUri getFileIcon();\n\n\tString getFileIconMimeType();\n\n\tUri getFile();\n\n\tint getState();\n\n\tint getReasonCode();\n\t\n\tint getDirection();\n\n\tlong getTimestamp();\n\n\tlong getTimestampSent();\n\n\tlong getTimestampDelivered();\n\n\tlong getTimestampDisplayed();\n\t\t\n\tvoid acceptInvitation();\n\n\tvoid rejectInvitation();\n\n\tvoid abortTransfer();\n\t\n\tvoid pauseTransfer();\n\t\n\tvoid resumeTransfer();\n\n\tboolean isRead();\n\n\tboolean isAllowedToResendTransfer();\n\n\tvoid resendTransfer();\n\n\tboolean isAllowedToPauseTransfer();\n\n\tboolean isAllowedToResumeTransfer();\n\t\n\tlong getFileExpiration();\n\t\n\tlong getFileIconExpiration();\n\n\tboolean isExpiredDelivery();\n\n\tint getDisposition();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/filetransfer/IFileTransferService.aidl",
    "content": "package com.gsma.services.rcs.filetransfer;\n\nimport android.net.Uri;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.filetransfer.IFileTransfer;\nimport com.gsma.services.rcs.filetransfer.IOneToOneFileTransferListener;\nimport com.gsma.services.rcs.filetransfer.IGroupFileTransferListener;\nimport com.gsma.services.rcs.filetransfer.IFileTransferServiceConfiguration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\n\n/**\n * File transfer service API\n */\ninterface IFileTransferService {\n\n\tboolean isServiceRegistered();\n\t\n\tint getServiceRegistrationReasonCode();\n\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tIFileTransferServiceConfiguration getConfiguration();\n\n\tIFileTransfer getFileTransfer(in String transferId);\n\n\tIFileTransfer transferFile(in ContactId contact, in Uri file, in boolean attachFileicon);\n\n\tIFileTransfer transferFileToGroupChat(in String chatId, in Uri file, in boolean attachFileicon);\n\n\tvoid markFileTransferAsRead(in String transferId);\n\t\n\tvoid addEventListener2(in IOneToOneFileTransferListener listener);\n\n\tvoid removeEventListener2(in IOneToOneFileTransferListener listener);\n\n\tvoid addEventListener3(in IGroupFileTransferListener listener);\n\n\tvoid removeEventListener3(in IGroupFileTransferListener listener);\n\t\n\tint getServiceVersion();\n\n\tboolean isAllowedToTransferFile(in ContactId contact);\n\n\tboolean isAllowedToTransferFileToGroupChat(in String chatId);\n\n\tvoid deleteOneToOneFileTransfers();\n\n\tvoid deleteGroupFileTransfers();\n\n\tvoid deleteOneToOneFileTransfers2(in ContactId contact);\n\n\tvoid deleteGroupFileTransfers2(in String chatId);\n\n\tvoid deleteFileTransfer(in String transferId);\n\n\tvoid clearFileTransferDeliveryExpiration(in List<String> transferIds);\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n\n\tIFileTransfer transferFile2(in ContactId contact, in Uri file, in int disposition, in boolean attachFileicon);\n\n\tIFileTransfer transferFileToGroupChat2(in String chatId, in Uri file, in int disposition, in boolean attachFileicon);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/filetransfer/IFileTransferServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs.filetransfer;\n\n/**\n * File transfer service configuration interface\n */\ninterface IFileTransferServiceConfiguration {\n\n\tlong getWarnSize();\n\n\tlong getMaxSize();\n\n    long getMaxAudioMessageDuration();\n\n\tboolean isAutoAcceptEnabled();\n\t\n\tvoid setAutoAccept(in boolean enable);\n\n\tboolean isAutoAcceptInRoamingEnabled();\n\t\n\tvoid setAutoAcceptInRoaming(in boolean enable);\n\n\tboolean isAutoAcceptModeChangeable();\n\t\n\tint getMaxFileTransfers();\n\t\n\tint getImageResizeOption();\n\t\n\tvoid setImageResizeOption(in int option);\n\t\n\tboolean isGroupFileTransferSupported();\n\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/filetransfer/IGroupFileTransferListener.aidl",
    "content": "package com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for group file transfer events\n */\ninterface IGroupFileTransferListener {\n\n\tvoid onStateChanged(in String chatId, in String transferId, in int state, in int reasonCode);\n\n\tvoid onDeliveryInfoChanged(in String chatId, in ContactId contact, in String transferId, in int state, in int reasonCode);\n\n\tvoid onProgressUpdate(in String chatId, in String transferId, in long currentSize, in long totalSize);\n\n\tvoid onDeleted(in String chatId, in List<String> transferIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/filetransfer/IOneToOneFileTransferListener.aidl",
    "content": "package com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for one-to-one file transfer events\n */\ninterface IOneToOneFileTransferListener {\n\n\tvoid onStateChanged(in ContactId contact, in String transferId, in int state, in int reasonCode);\n\n\tvoid onProgressUpdate(in ContactId contact, in String transferId, in long currentSize, in long totalSize);\n\n\tvoid onDeleted(in ContactId contact, in List<String> transferIds);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/history/IHistoryService.aidl",
    "content": "package com.gsma.services.rcs.history;\n\nimport android.net.Uri;\n\n/**\n * History service API\n */\ninterface IHistoryService {\n\n    void registerExtraHistoryLogMember(in int providerId, in Uri providerUri, in Uri databaseUri, in String table, in Map columnMapping);\n\n    void unregisterExtraHistoryLogMember(in int providerId);\n\n    long createUniqueId(in int providerId);\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/geoloc/IGeolocSharing.aidl",
    "content": "package com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Geoloc sharing interface\n */\ninterface IGeolocSharing {\n\n\tString getSharingId();\n\n\tContactId getRemoteContact();\n\n\tGeoloc getGeoloc();\n\n\tint getState();\n\n\tint getReasonCode();\n\t\n\tint getDirection();\n\t\t\n\tvoid acceptInvitation();\n\n\tvoid rejectInvitation();\n\n\tvoid abortSharing();\n\n\tlong getTimestamp();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/geoloc/IGeolocSharingListener.aidl",
    "content": "package com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for geoloc sharing events\n */\ninterface IGeolocSharingListener {\n\n\tvoid onStateChanged(in ContactId contact, in String sharingId, in int state, in int reasonCode);\n\n\tvoid onProgressUpdate(in ContactId contact, in String sharingId, in long currentSize, in long totalSize);\n\n\tvoid onDeleted(in ContactId contact, in List<String> sharingIds);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/geoloc/IGeolocSharingService.aidl",
    "content": "package com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.IGeolocSharingListener;\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Geoloc sharing service API\n */\ninterface IGeolocSharingService {\n\n\tboolean isServiceRegistered();\n\t\n\tint getServiceRegistrationReasonCode();\n\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tIGeolocSharing getGeolocSharing(in String sharingId);\n\n\tIGeolocSharing shareGeoloc(in ContactId contact, in Geoloc geoloc);\n\n\tvoid addEventListener2(in IGeolocSharingListener listener);\n\n\tvoid removeEventListener2(in IGeolocSharingListener listener);\n\n\tint getServiceVersion();\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n\n\tvoid deleteGeolocSharings();\n\n\tvoid deleteGeolocSharings2(in ContactId contact);\n\n\tvoid deleteGeolocSharing(in String sharingId);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/image/IImageSharing.aidl",
    "content": "package com.gsma.services.rcs.sharing.image;\n\nimport android.net.Uri;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Image sharing interface\n */\ninterface IImageSharing {\n\n\tString getSharingId();\n\n\tContactId getRemoteContact();\n\n\tUri getFile();\n\n\tString getFileName();\n\n\tlong getFileSize();\n\n\tString getMimeType();\n\n\tint getState();\n\n\tint getReasonCode();\n\t\n\tint getDirection();\n\n\tlong getTimestamp();\n\t\t\n\tvoid acceptInvitation();\n\n\tvoid rejectInvitation();\n\n\tvoid abortSharing();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/image/IImageSharingListener.aidl",
    "content": "package com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for image sharing events\n */\ninterface IImageSharingListener {\n\n\tvoid onStateChanged(in ContactId contact, in String sharingId, in int state, in int reasonCode);\n\n\tvoid onProgressUpdate(in ContactId contact, in String sharingId, in long currentSize, in long totalSize);\n\n\tvoid onDeleted(in ContactId contact, in List<String> sharingIds);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/image/IImageSharingService.aidl",
    "content": "package com.gsma.services.rcs.sharing.image;\n\nimport android.net.Uri;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.sharing.image.IImageSharing;\nimport com.gsma.services.rcs.sharing.image.IImageSharingListener;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.sharing.image.IImageSharingServiceConfiguration;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Image sharing service API\n */\ninterface IImageSharingService {\n\n\tboolean isServiceRegistered();\n\n\tint getServiceRegistrationReasonCode();\n\t\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tIImageSharingServiceConfiguration getConfiguration();\n\n\tIImageSharing getImageSharing(in String sharingId);\n\n\tIImageSharing shareImage(in ContactId contact, in Uri file);\n\n\tvoid addEventListener2(in IImageSharingListener listener);\n\n\tvoid removeEventListener2(in IImageSharingListener listener);\n\n\tint getServiceVersion();\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n\n\tvoid deleteImageSharings();\n\n\tvoid deleteImageSharings2(in ContactId contact);\n\n\tvoid deleteImageSharing(in String sharingId);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/image/IImageSharingServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs.sharing.image;\n\n/**\n * Image sharing service configuration interface\n */\ninterface IImageSharingServiceConfiguration {\n\n\tlong getMaxSize();\n\t\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/IVideoPlayer.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.sharing.video.VideoCodec;\n\n/**\n * Video player interface\n */\ninterface IVideoPlayer {\n\tvoid setRemoteInfo(in VideoCodec codec, in String remoteHost, in int remotePort, in int orientation);\n\t\n\tint getLocalRtpPort();\n\n\tVideoCodec[] getSupportedCodecs();\n\n\tVideoCodec getCodec();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/IVideoSharing.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoDescriptor;\n\n/**\n * Video sharing interface\n */\ninterface IVideoSharing {\n\n\tString getSharingId();\n\n\tContactId getRemoteContact();\n\n\tint getState();\n\n\tint getReasonCode();\n\n\tint getDirection();\n\t\n\tvoid acceptInvitation(IVideoPlayer player);\n\n\tvoid rejectInvitation();\n\n\tvoid abortSharing();\n\t\n\tString getVideoEncoding();\n\n\tlong getTimestamp();\n\n\tlong getDuration();\n\t\n\tVideoDescriptor getVideoDescriptor();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/IVideoSharingListener.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Callback methods for video sharing events\n */\ninterface IVideoSharingListener {\n\n\tvoid onStateChanged(in ContactId contact, in String sharingId, in int state, in int reasonCode);\n\n\tvoid onDeleted(in ContactId contact, in List<String> sharingIds);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/IVideoSharingService.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.IRcsServiceRegistrationListener;\nimport com.gsma.services.rcs.sharing.video.IVideoSharing;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingListener;\nimport com.gsma.services.rcs.sharing.video.IVideoPlayer;\nimport com.gsma.services.rcs.sharing.video.IVideoSharingServiceConfiguration;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\nimport com.gsma.services.rcs.RcsServiceRegistration;\n\n/**\n * Video sharing service API\n */\ninterface IVideoSharingService {\n\n\tboolean isServiceRegistered();\n\t\n\tint getServiceRegistrationReasonCode();\n\n\tvoid addEventListener(IRcsServiceRegistrationListener listener);\n\n\tvoid removeEventListener(IRcsServiceRegistrationListener listener);\n\n\tIVideoSharingServiceConfiguration getConfiguration();\n\n\tIVideoSharing getVideoSharing(in String sharingId);\n\n\tIVideoSharing shareVideo(in ContactId contact, in IVideoPlayer player);\n\n\tvoid addEventListener2(in IVideoSharingListener listener);\n\n\tvoid removeEventListener2(in IVideoSharingListener listener);\n\n\tint getServiceVersion();\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n\n\tvoid deleteVideoSharings();\n\n\tvoid deleteVideoSharings2(in ContactId contact);\n\n\tvoid deleteVideoSharing(in String sharingId);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/IVideoSharingServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\n/**\n * Video sharing service configuration interface\n */\ninterface IVideoSharingServiceConfiguration {\n\n\tlong getMaxTime();\n\t\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/VideoCodec.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\n/**\n * Video codec object\n */\nparcelable VideoCodec;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/sharing/video/VideoDescriptor.aidl",
    "content": "package com.gsma.services.rcs.sharing.video;\n\n/**\n * Video descriptor object\n */\nparcelable VideoDescriptor;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/upload/FileUploadInfo.aidl",
    "content": "package com.gsma.services.rcs.upload;\n\n/**\n * File Upload info object\n */\nparcelable FileUploadInfo;"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/upload/IFileUpload.aidl",
    "content": "package com.gsma.services.rcs.upload;\n\nimport android.net.Uri;\n\nimport com.gsma.services.rcs.upload.FileUploadInfo;\n\n/**\n * File upload interface\n */\ninterface IFileUpload {\n\n\tString getUploadId();\n\n\tUri getFile();\n\n\tFileUploadInfo getUploadInfo();\n\n\tint getState();\n\t\n\tvoid abortUpload();\n}\n"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/upload/IFileUploadListener.aidl",
    "content": "package com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.upload.FileUploadInfo;\n\n/**\n * Callback methods for file upload events\n */\ninterface IFileUploadListener {\n\n\tvoid onStateChanged(in String uploadId, in int state);\n\n\tvoid onProgressUpdate(in String uploadId, in long currentSize, in long totalSize);\n\n\tvoid onUploaded(in String uploadId, in FileUploadInfo info);\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/upload/IFileUploadService.aidl",
    "content": "package com.gsma.services.rcs.upload;\n\nimport android.net.Uri;\n\nimport com.gsma.services.rcs.upload.IFileUpload;\nimport com.gsma.services.rcs.upload.IFileUploadListener;\nimport com.gsma.services.rcs.upload.IFileUploadServiceConfiguration;\nimport com.gsma.services.rcs.ICommonServiceConfiguration;\n\n/**\n * File uploadservice API\n */\ninterface IFileUploadService {\n\n\tIFileUploadServiceConfiguration getConfiguration();\n\n\tboolean canUploadFile();\n\n\tList<IBinder> getFileUploads();\n\t\n\tIFileUpload getFileUpload(in String uploadId);\n\n\tIFileUpload uploadFile(in Uri file, in boolean fileIcon);\n\n\tvoid addEventListener(in IFileUploadListener listener);\n\n\tvoid removeEventListener(in IFileUploadListener listener);\n\n\tint getServiceVersion();\n\t\n\tICommonServiceConfiguration getCommonConfiguration();\n}"
  },
  {
    "path": "libs/api/src/main/aidl/com/gsma/services/rcs/upload/IFileUploadServiceConfiguration.aidl",
    "content": "package com.gsma.services.rcs.upload;\n\n/**\n * File upload service configuration interface\n */\ninterface IFileUploadServiceConfiguration {\n\n\tlong getMaxSize();\n\t\n}"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/CommonServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.SparseArray;\n\n/**\n * This class represents the common configuration of RCS Services\n * \n * @author Philippe LEMORDANT\n */\npublic class CommonServiceConfiguration {\n\n    private final ICommonServiceConfiguration mIConfig;\n\n    /**\n     * The messaging client mode\n     */\n    public enum MessagingMode {\n        /**\n         * Messaging mode not defined\n         */\n        NONE(0),\n        /**\n         * Messaging mode integrated\n         */\n        INTEGRATED(1),\n        /**\n         * Messaging mode converged\n         */\n        CONVERGED(2),\n        /**\n         * Messaging mode seamless\n         */\n        SEAMLESS(3);\n\n        private int mValue;\n\n        private static SparseArray<MessagingMode> mValueToEnum = new SparseArray<>();\n        static {\n            for (MessagingMode entry : MessagingMode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        MessagingMode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to MessagingMode instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a MessagingMode instance for the specified integer value.\n         * \n         * @param value the value associated to the MessagingMode\n         * @return instance\n         */\n        public static MessagingMode valueOf(int value) {\n            MessagingMode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + MessagingMode.class.getName() + \"\" + value);\n\n        }\n\n    }\n\n    /**\n     * The messaging method\n     */\n    public enum MessagingMethod {\n        /**\n         * Messaging method automatic\n         */\n        AUTOMATIC(0),\n        /**\n         * Messaging method RCS\n         */\n        RCS(1),\n        /**\n         * Messaging method non RCS\n         */\n        NON_RCS(2);\n\n        private int mValue;\n\n        private static SparseArray<MessagingMethod> mValueToEnum = new SparseArray<>();\n        static {\n            for (MessagingMethod entry : MessagingMethod.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        MessagingMethod(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to MessagingMethod instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a MessagingMethod instance for the specified integer value.\n         * \n         * @param value the value associated to the MessagingMethod\n         * @return instance\n         */\n        public static MessagingMethod valueOf(int value) {\n            MessagingMethod entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + MessagingMethod.class.getName() + \"\" + value);\n        }\n\n    }\n\n    /**\n     * The minimum battery level\n     */\n    public enum MinimumBatteryLevel {\n        /**\n         * Discard minimum battery level\n         */\n        NEVER_STOP(0),\n        /**\n         * 5% is the minimum battery level\n         */\n        PERCENT_5(5),\n        /**\n         * 10% is the minimum battery level\n         */\n        PERCENT_10(10),\n        /**\n         * 20% is the minimum battery level\n         */\n        PERCENT_20(20);\n\n        private int mValue;\n\n        private static SparseArray<MinimumBatteryLevel> mValueToEnum = new SparseArray<>();\n        static {\n            for (MinimumBatteryLevel entry : MinimumBatteryLevel.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        MinimumBatteryLevel(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to MinimumBatteryLevel instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a MinimumBatteryLevel instance for the specified integer value.\n         * \n         * @param value the value associated to the MinimumBatteryLevel\n         * @return instance\n         */\n        public static MinimumBatteryLevel valueOf(int value) {\n            MinimumBatteryLevel entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + MinimumBatteryLevel.class.getName() + \"\" + value);\n        }\n\n    }\n\n    /**\n     * Constructor\n     * \n     * @param iConfig ICommonServiceConfiguration instance\n     * @hide\n     */\n    /* package private */CommonServiceConfiguration(ICommonServiceConfiguration iConfig) {\n        mIConfig = iConfig;\n    }\n\n    /**\n     * Returns True if RCS configuration is valid.\n     * \n     * @return boolean True if RCS configuration is valid.\n     * @throws RcsGenericException\n     */\n    public boolean isConfigValid() throws RcsGenericException {\n        try {\n            return mIConfig.isConfigValid();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the display name associated to the RCS user account.<br>\n     * The display name may be updated by the end user via the RCS settings application.\n     * \n     * @return String Display name\n     * @throws RcsGenericException\n     */\n    public String getMyDisplayName() throws RcsGenericException {\n        try {\n            return mIConfig.getMyDisplayName();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the display name associated to the RCS user account.\n     * \n     * @param name the new display name\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void setMyDisplayName(String name) throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            mIConfig.setMyDisplayName(name);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the user contact Identifier (i.e. username part of the IMPU).\n     * \n     * @return ContactId the contact ID\n     * @throws RcsGenericException\n     */\n    public ContactId getMyContactId() throws RcsGenericException {\n        try {\n            return mIConfig.getMyContactId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the messaging client mode which can be INTEGRATED, CONVERGED, SEAMLESS or NONE.\n     * \n     * @return MessagingMode the messaging client mode\n     * @throws RcsGenericException\n     */\n    public MessagingMode getMessagingUX() throws RcsGenericException {\n        try {\n            return MessagingMode.valueOf(mIConfig.getMessagingUX());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the minimum battery level which can be NEVER_STOP, PERCENT_5, PERCENT_10 or\n     * PERCENT_20.\n     * \n     * @return MinimumBatteryLevel the minimum battery level\n     * @throws RcsGenericException\n     */\n    public MinimumBatteryLevel getMinimumBatteryLevel() throws RcsGenericException {\n        try {\n            return MinimumBatteryLevel.valueOf(mIConfig.getMinimumBatteryLevel());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the minimum battery level.\n     * \n     * @param level the minimum battery level which can be NEVER_STOP, PERCENT_5, PERCENT_10 or\n     *            PERCENT_20.\n     * @throws RcsGenericException\n     */\n    public void setMinimumBatteryLevel(MinimumBatteryLevel level) throws RcsGenericException {\n        try {\n            mIConfig.setMinimumBatteryLevel(level.toInt());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the default messaging method which can be AUTOMATIC, RCS or NON_RCS.\n     * \n     * @return MessagingMethod the default messaging method\n     * @throws RcsGenericException\n     */\n    public MessagingMethod getDefaultMessagingMethod() throws RcsGenericException {\n        try {\n            return MessagingMethod.valueOf(mIConfig.getDefaultMessagingMethod());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the default messaging method.\n     * \n     * @param method the default messaging method which can be AUTOMATIC, RCS or NON_RCS.\n     * @throws RcsGenericException\n     */\n    public void setDefaultMessagingMethod(MessagingMethod method) throws RcsGenericException {\n        try {\n            mIConfig.setDefaultMessagingMethod(method.toInt());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/Geoloc.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.io.Serializable;\nimport java.util.StringTokenizer;\n\n/**\n * Geolocation class\n */\npublic class Geoloc implements Parcelable, Serializable {\n\n    private static final long serialVersionUID = 0L;\n\n    private final String mLabel;\n\n    private final double mLatitude;\n\n    private final double mLongitude;\n\n    private final long mExpiration;\n\n    /**\n     * Accuracy (in meters)\n     */\n    private final float mAccuracy;\n\n    /**\n     * Constructor\n     * \n     * @param label Label\n     * @param latitude Latitude\n     * @param longitude Longitude\n     * @param expiration Expiration date\n     * @param accuracy Accuracy\n     */\n    public Geoloc(String label, double latitude, double longitude, long expiration, float accuracy) {\n        mLabel = label;\n        mLatitude = latitude;\n        mLongitude = longitude;\n        mExpiration = expiration;\n        mAccuracy = accuracy;\n    }\n\n    /**\n     * Constructor: returns a Geoloc instance as parsed from the GEOLOC field in the\n     * GeolocSharingLog provider or the CONTENT field of a GelocMessage in the ChatLog.Message\n     * provider.\n     * \n     * @param geoloc Provider geoloc format\n     */\n    public Geoloc(String geoloc) {\n        StringTokenizer items = new StringTokenizer(geoloc, \",\");\n        if (items.countTokens() > 4) {\n            mLabel = items.nextToken();\n        } else {\n            mLabel = null;\n        }\n        mLatitude = Double.valueOf(items.nextToken());\n        mLongitude = Double.valueOf(items.nextToken());\n        mExpiration = Long.valueOf(items.nextToken());\n        mAccuracy = Float.valueOf(items.nextToken());\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     * @hide\n     */\n    public Geoloc(Parcel source) {\n        mLabel = source.readString();\n        mLatitude = source.readDouble();\n        mLongitude = source.readDouble();\n        mExpiration = source.readLong();\n        mAccuracy = source.readFloat();\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation.\n     * \n     * @return Integer\n     * @hide\n     */\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object.\n     * \n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mLabel);\n        dest.writeDouble(mLatitude);\n        dest.writeDouble(mLongitude);\n        dest.writeLong(mExpiration);\n        dest.writeFloat(mAccuracy);\n    }\n\n    /**\n     * Parcelable creator.\n     * \n     * @hide\n     */\n    public static final Parcelable.Creator<Geoloc> CREATOR = new Parcelable.Creator<Geoloc>() {\n        public Geoloc createFromParcel(Parcel source) {\n            return new Geoloc(source);\n        }\n\n        public Geoloc[] newArray(int size) {\n            return new Geoloc[size];\n        }\n    };\n\n    /**\n     * Returns the label.\n     * \n     * @return Label\n     */\n    public String getLabel() {\n        return mLabel;\n    }\n\n    /**\n     * Returns the latitude.\n     * \n     * @return Latitude\n     */\n    public double getLatitude() {\n        return mLatitude;\n    }\n\n    /**\n     * Returns the longitude.\n     * \n     * @return Longitude\n     */\n    public double getLongitude() {\n        return mLongitude;\n    }\n\n    /**\n     * Returns the expiration date of the geoloc.\n     * \n     * @return Expiration date. 0 means no expiration date has been defined.\n     */\n    public long getExpiration() {\n        return mExpiration;\n    }\n\n    /**\n     * Returns the accuracy\n     * \n     * @return Accuracy in meters. 0 means no accuracy has been defined.\n     */\n    public float getAccuracy() {\n        return mAccuracy;\n    }\n\n    /**\n     * Returns the geoloc in provider format.\n     * \n     * @return String\n     */\n    @Override\n    public String toString() {\n        StringBuilder providerContent;\n        if (mLabel == null) {\n            providerContent = new StringBuilder();\n        } else {\n            providerContent = new StringBuilder(mLabel);\n        }\n        return providerContent.append(\",\").append(mLatitude).append(\",\").append(mLongitude)\n                .append(\",\").append(mExpiration).append(\",\").append(mAccuracy).toString();\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/Intents.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\n/**\n * Intents related to rcs service activities\n * \n * @author Jean-Marc AUFFRET\n */\npublic class Intents {\n    /**\n     * Intents for RCS service\n     */\n    public static class Service {\n        /**\n         * Intent to check if stack deactivation/activation is allowed by the client\n         */\n        public static final String ACTION_GET_ACTIVATION_MODE_CHANGEABLE = \"com.gsma.services.rcs.action.GET_ACTIVATION_MODE_CHANGEABLE\";\n\n        /**\n         * Used as an boolean extra field in ACTION_GET_ACTIVATION_MODE_CHANGEABLE intent to request\n         * the activation mode changeable.\n         */\n        public static final String EXTRA_GET_ACTIVATION_MODE_CHANGEABLE = \"get_activation_mode_changeable\";\n\n        /**\n         * Intent to check if RCS stack is activated\n         */\n        public static final String ACTION_GET_ACTIVATION_MODE = \"com.gsma.services.rcs.action.GET_ACTIVATION_MODE\";\n\n        /**\n         * Used as an boolean extra field in ACTION_GET_ACTIVATION_MODE intent to request the\n         * activation mode.\n         */\n        public static final String EXTRA_GET_ACTIVATION_MODE = \"get_activation_mode\";\n\n        /**\n         * Intent to set the activation mode of the RCS stack\n         */\n        public static final String ACTION_SET_ACTIVATION_MODE = \"com.gsma.services.rcs.action.SET_ACTIVATION_MODE\";\n\n        /**\n         * Used as an boolean extra field in ACTION_SET_ACTIVATION_MODE intent to set the activation\n         * mode.\n         */\n        public static final String EXTRA_SET_ACTIVATION_MODE = \"set_activation_mode\";\n\n        /**\n         * Intent to check if RCS stack is compatible with RCS API\n         */\n        public static final String ACTION_GET_COMPATIBILITY = \"com.gsma.services.rcs.action.GET_COMPATIBILITY\";\n\n        /**\n         * Used as a string extra field in ACTION_GET_COMPATIBILITY intent to convey the codename\n         */\n        public static final String EXTRA_GET_COMPATIBILITY_CODENAME = \"get_compatibility_codename\";\n\n        /**\n         * Used as an integer extra field in ACTION_GET_COMPATIBILITY intent to convey the version\n         */\n        public static final String EXTRA_GET_COMPATIBILITY_VERSION = \"get_compatibility_version\";\n\n        /**\n         * Used as an integer extra field in ACTION_GET_COMPATIBILITY intent to convey the increment\n         */\n        public static final String EXTRA_GET_COMPATIBILITY_INCREMENT = \"get_compatibility_increment\";\n\n        /**\n         * Used as an boolean extra field in ACTION_GET_COMPATIBILITY intent to convey the response\n         */\n        public static final String EXTRA_GET_COMPATIBILITY_RESPONSE = \"get_compatibility_response\";\n\n        /**\n         * Used as an string extra field in ACTION_GET_COMPATIBILITY intent to convey the service\n         * class name\n         */\n        public static final String EXTRA_GET_COMPATIBILITY_SERVICE = \"get_compatibility_service\";\n\n        /**\n         * Intent to get the RCS service starting state.\n         */\n        public static final String ACTION_GET_SERVICE_STARTING_STATE = \"com.gsma.services.rcs.action.GET_SERVICE_STARTING_STATE\";\n\n        /**\n         * Used as a boolean extra field in ACTION_GET_SERVICE_STARTING_STATE intent to convey the\n         * response.\n         */\n        public static final String EXTRA_GET_SERVICE_STARTING_STATE = \"get_service_starting_state\";\n\n        private Service() {\n        }\n    }\n\n    /**\n     * Intents for chat service\n     */\n    public static class Chat {\n        /**\n         * Load the chat application to view a chat conversation. This Intent takes into parameter\n         * an URI on the chat conversation (i.e. content://chats/chat_ID). If no parameter found the\n         * main entry of the chat application is displayed.\n         */\n        public static final String ACTION_VIEW_ONE_TO_ONE_CHAT = \"com.gsma.services.rcs.action.VIEW_ONE_TO_ONE_CHAT\";\n\n        /**\n         * Load the chat application to send a new chat message to a given contact. This Intent\n         * takes into parameter a contact URI (i.e. content://contacts/people/contact_ID). If no\n         * parameter the main entry of the chat application is displayed.\n         */\n        public static final String ACTION_SEND_ONE_TO_ONE_CHAT_MESSAGE = \"com.gsma.services.rcs.action.SEND_ONE_TO_ONE_CHAT_MESSAGE\";\n\n        /**\n         * Load the group chat application. This Intent takes into parameter an URI on the group\n         * chat conversation (i.e. content://chats/chat_ID). If no parameter found the main entry of\n         * the group chat application is displayed.\n         */\n        public static final String ACTION_VIEW_GROUP_CHAT = \"com.gsma.services.rcs.action.VIEW_GROUP_CHAT\";\n\n        /**\n         * Load the group chat application to start a new conversation with a group of contacts.\n         * This Intent takes into parameter a list of contact URIs. If no parameter the main entry\n         * of the group chat application is displayed.\n         */\n        public static final String ACTION_INITIATE_GROUP_CHAT = \"com.gsma.services.rcs.action.INITIATE_GROUP_CHAT\";\n\n        private Chat() {\n        }\n    }\n\n    /**\n     * Intents for file transfer service\n     */\n    public static class FileTransfer {\n        /**\n         * Load the file transfer application to view a file transfer. This Intent takes into\n         * parameter an URI on the file transfer (i.e. content://filetransfers/ft_ID). If no\n         * parameter found the main entry of the file transfer application is displayed.\n         */\n        public static final String ACTION_VIEW_FILE_TRANSFER = \"com.gsma.services.rcs.action.VIEW_FILE_TRANSFER\";\n\n        /**\n         * Load the file transfer application to start a new file transfer to a given contact. This\n         * Intent takes into parameter a contact URI (i.e. content://contacts/people/contact_ID). If\n         * no parameter the main entry of the file transfer application is displayed.\n         */\n        public static final String ACTION_INITIATE_ONE_TO_ONE_FILE_TRANSFER = \"com.gsma.services.rcs.action.INITIATE_ONE_TO_ONE_FILE_TRANSFER\";\n\n        /**\n         * Load the group chat application to start a new conversation with a group of contacts and\n         * send a file to them. This Intent takes into parameter a list of contact URIs (i.e.\n         * content://contacts/people/contact_ID). If no parameter, the main entry of the group chat\n         * application is displayed.\n         */\n        public static final String ACTION_INITIATE_GROUP_FILE_TRANSFER = \"com.gsma.services.rcs.action.ACTION_INITIATE_GROUP_FILE_TRANSFER\";\n\n        private FileTransfer() {\n        }\n    }\n\n    private Intents() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsGenericException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs;\n\n/**\n * Rcs Generic Exception\n * <p>\n * A Generic exception that must be thrown from a service API when the requested operation failed to\n * fully complete its scope of responsibility and none of the more specified exceptions can be\n * thrown. The client must be able to trust that in case of any failure what so ever and its not\n * possible to throw a more specific exception this exception will be thrown as a kind of default\n * exception to signify that some error occurred that not necessarily need to be more specific than\n * that.\n * </p>\n */\npublic class RcsGenericException extends RcsServiceException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsGenericException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructs a new Exception with the current stack trace and the specified cause.\n     * \n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsGenericException(Throwable cause) {\n        super(cause);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsGenericException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsGenericException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsGenericException\n     */\n    public static void assertException(Exception e) throws RcsGenericException {\n        if (isIntendedException(e, RcsGenericException.class)) {\n            throw new RcsGenericException(extractServerException(e), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsIllegalArgumentException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs;\n\nimport android.text.TextUtils;\n\n/**\n * Rcs Illegal Argument Exception.\n * <p>\n * Thrown when a method of the service API is called with one or multiple illegal input parameter.\n * Such as a calling a method and passing null as a parameter in the case that null is not valid for\n * that parameter.\n * </p>\n */\npublic class RcsIllegalArgumentException extends IllegalArgumentException {\n\n    /**\n     * Special Delimiter that will be appended while trasmitting server exceptions over AIDL layer.\n     */\n    private static final char DELIMITER_PIPE = '|';\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsIllegalArgumentException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsIllegalArgumentException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsIllegalArgumentException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsIllegalArgumentException\n     */\n    public static void assertException(Exception e) throws RcsIllegalArgumentException {\n        if (isIntendedException(e, RcsIllegalArgumentException.class)) {\n            throw new RcsIllegalArgumentException(extractServerException(e), e);\n        }\n    }\n\n    /**\n     * Checks if the exception is one of the intended server side exception that has been thrown\n     * over the AIDL layer.\n     * \n     * @param e Exception\n     * @param clazz Class\n     * @return true if exception getMessage() starts with clazz getName()\n     */\n    private static boolean isIntendedException(Exception e, Class<?> clazz) {\n        final String message = e.getMessage();\n        return (!TextUtils.isEmpty(message) && message.startsWith(clazz.getName()));\n    }\n\n    /**\n     * Extracts server side exception message thrown over the AIDL layer after parsing it based on\n     * {@link DELIMITER_PIPE}\n     * \n     * @param e Exception\n     * @return Server exception message\n     */\n    private static String extractServerException(Exception e) {\n        final String message = e.getMessage();\n        final int delimiterIndex = message.indexOf(DELIMITER_PIPE);\n        if (delimiterIndex > 0 && delimiterIndex < message.length() - 1) {\n            return message.substring(delimiterIndex + 1);\n        }\n        return message;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsMaxAllowedSessionLimitReachedException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs;\n\n/**\n * Rcs Max Allowed Session Limit Reached Exception.\n * <p>\n * Thrown if the SERVICE TYPE (message/filetransfer/imageshare/geolocationshare etc) cannot be\n * sent/transfered/resent or a new groupchat invitation cannot be sent right now since the limit of\n * allowed ongoing sessions has already been reached and the client needs to wait for at least one\n * session to be released back to the stack first.\n * </p>\n */\npublic class RcsMaxAllowedSessionLimitReachedException extends RcsServiceException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsMaxAllowedSessionLimitReachedException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsMaxAllowedSessionLimitReachedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsMaxAllowedSessionLimitReachedException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsMaxAllowedSessionLimitReachedException\n     */\n    public static void assertException(Exception e)\n            throws RcsMaxAllowedSessionLimitReachedException {\n        if (isIntendedException(e, RcsMaxAllowedSessionLimitReachedException.class)) {\n            throw new RcsMaxAllowedSessionLimitReachedException(extractServerException(e), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsPermissionDeniedException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\n/**\n * RCS permission denied exception\n * <p>\n * Thrown when a method of the service API is called that not allowed right now. This can be for\n * multiple reasons like it is not possible to call accept() on a file transfer invitation that has\n * previously already been rejected, the file trying to be sent is not allowed to be read back due\n * to security aspects or any other operation that fails because the operation is not allowed or has\n * been blocked for some other reason.\n * </p>\n */\npublic class RcsPermissionDeniedException extends RcsServiceException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsPermissionDeniedException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsPermissionDeniedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsPermissionDeniedException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsPermissionDeniedException\n     */\n    public static void assertException(Exception e) throws RcsPermissionDeniedException {\n        if (isIntendedException(e, RcsPermissionDeniedException.class)) {\n            throw new RcsPermissionDeniedException(extractServerException(e), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsPersistentStorageException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs;\n\n/**\n * Rcs Persistent Storage Exception\n * <p>\n * Thrown when a method of the service API is called to persist data or read back persisted data\n * failed. This can be because the underlying persistent storage database (or possibly further on a\n * CPM cloud) reported an error such as no more entries can be added perhaps because disk is full,\n * or just that a SQL operation failed or even a unsuccessful read operation from persistent\n * storage.\n * </p>\n */\npublic class RcsPersistentStorageException extends RcsServiceException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsPersistentStorageException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsPersistentStorageException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsPersistentStorageException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsPersistentStorageException\n     */\n    public static void assertException(Exception e) throws RcsPersistentStorageException {\n        if (isIntendedException(e, RcsPersistentStorageException.class)) {\n            throw new RcsPersistentStorageException(extractServerException(e), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.content.Context;\nimport android.os.IInterface;\nimport android.util.SparseArray;\n\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Method;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\n/**\n * Abstract RCS service\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class RcsService {\n    /**\n     * Action broadcasted when RCS service is up.\n     */\n    public static final String ACTION_SERVICE_UP = \"com.gsma.services.rcs.action.SERVICE_UP\";\n\n    /**\n     * Action to broadcast when RCS service is provisioned.\n     */\n    public static final String ACTION_SERVICE_PROVISIONING_DATA_CHANGED = \"com.gsma.services.rcs.action.SERVICE_PROVISIONING_DATA_CHANGED\";\n\n    /**\n     * @hide\n     */\n    protected final RcsServiceControl mRcsServiceControl;\n\n    private final Map<RcsServiceRegistrationListener, WeakReference<IRcsServiceRegistrationListener>> mRegistrationListeners = new WeakHashMap<>();\n\n    /**\n     * Information about the current build\n     */\n    public static class Build {\n        /**\n         * List of version codes\n         */\n        public static class VERSION_CODES {\n            /**\n             * The original first version of RCS API\n             */\n            public final static int BASE = 0;\n\n            /**\n             * Blackbird version of RCS API\n             */\n            public final static int BLACKBIRD = 1;\n\n            /**\n             * Crane Priority Release version of RCS API\n             */\n            public final static int CPR = 2;\n\n            private VERSION_CODES() {\n            }\n        }\n\n        /**\n         * API release implementor name\n         */\n        public static final String API_CODENAME = \"GSMA\";\n\n        /**\n         * API version number\n         * \n         * @see VERSION_CODES\n         */\n        public static final int API_VERSION = VERSION_CODES.CPR;\n\n        /**\n         * Internal number used by the underlying source control to represent this build\n         */\n        public static final int API_INCREMENTAL = 0;\n\n        private Build() {\n        }\n    }\n\n    /**\n     * Direction of the communication for Chat message, Geolocation, Filetransfer, Imageshare,\n     * Videoshare etc.\n     */\n    public enum Direction {\n\n        /**\n         * Incoming communication\n         */\n        INCOMING(0),\n\n        /**\n         * Outgoing communication\n         */\n        OUTGOING(1),\n\n        /**\n         * Irrelevant or not applicable (e.g. for group chat event message)\n         */\n        IRRELEVANT(2);\n\n        private final int mValue;\n\n        private static SparseArray<Direction> mValueToEnum = new SparseArray<>();\n        static {\n            for (Direction entry : Direction.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        Direction(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to Direction instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a Direction instance for the specified integer value.\n         * \n         * @param value the value associated to the Direction\n         * @return instance\n         */\n        public static Direction valueOf(int value) {\n            Direction entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + Direction.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Read status of the message\n     */\n    public enum ReadStatus {\n        /**\n         * The message has not yet been displayed in the UI.\n         */\n        UNREAD(0),\n        /**\n         * The message has been displayed in the UI.\n         */\n        READ(1);\n\n        private final int mValue;\n\n        private static SparseArray<ReadStatus> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReadStatus entry : ReadStatus.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReadStatus(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to ReadStatus instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a ReadStatus instance for the specified integer value.\n         * \n         * @param value the value associated to the ReadStatus\n         * @return instance\n         */\n        public static ReadStatus valueOf(int value) {\n            ReadStatus entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReadStatus.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Application context\n     * @hide\n     */\n    protected Context mCtx;\n\n    /**\n     * Service listener\n     * @hide\n     */\n    protected RcsServiceListener mListener;\n\n    /**\n     * API interface\n     */\n    private IInterface mApi;\n\n    /**\n     * Service version\n     */\n    private Integer mVersion;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     * @hide\n     */\n    public RcsService(Context ctx, RcsServiceListener listener) {\n        mCtx = ctx;\n        mListener = listener;\n        mRcsServiceControl = RcsServiceControl.getInstance(ctx);\n    }\n\n    /**\n     * Call specific method on the API interface\n     * \n     * @param method Method to be called\n     * @param param Parameters of the method\n     * @param paramClass Class of the parameter passed\n     * @return Object\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    private Object callApiMethod(String method, Object param,\n            Class<IRcsServiceRegistrationListener> paramClass)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        Class<? extends IInterface> c = mApi.getClass();\n        try {\n            if (param != null) {\n                Method m = c.getDeclaredMethod(method, paramClass);\n                return m.invoke(mApi, param);\n            }\n            Method m = c.getDeclaredMethod(method, (Class[]) null);\n            return m.invoke(mApi);\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        mApi = api;\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public abstract void connect() throws RcsPermissionDeniedException;\n\n    /**\n     * Disconnects from the API\n     */\n    public abstract void disconnect();\n\n    /**\n     * Returns true if the service is connected, else returns false\n     * \n     * @return Returns true if connected else returns false\n     */\n    public boolean isServiceConnected() {\n        return (mApi != null);\n    }\n\n    /**\n     * Returns service version\n     * \n     * @return int Version\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     * @see Build.VERSION_CODES\n     */\n    public int getServiceVersion() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        if (mVersion != null) {\n            return mVersion;\n        }\n        try {\n            mVersion = (Integer) callApiMethod(\"getServiceVersion\", null, null);\n            return mVersion;\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if the service is registered to the platform, else returns false\n     * \n     * @return boolean true if registered else returns false\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public boolean isServiceRegistered() throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return (Boolean) callApiMethod(\"isServiceRegistered\", null, null);\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code for the service registration\n     * \n     * @return RcsServiceRegistration.ReasonCode\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public RcsServiceRegistration.ReasonCode getServiceRegistrationReasonCode()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            int reasonCode = (Integer) callApiMethod(\"getServiceRegistrationReasonCode\", null, null);\n            return RcsServiceRegistration.ReasonCode.valueOf(reasonCode);\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on service registration events\n     * \n     * @param listener Service registration listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(RcsServiceRegistrationListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IRcsServiceRegistrationListener rcsListener = new RcsServiceRegistrationListenerImpl(\n                    listener);\n            mRegistrationListeners.put(listener, new WeakReference<>(rcsListener));\n            callApiMethod(\"addEventListener\", rcsListener, IRcsServiceRegistrationListener.class);\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on service registration events\n     * \n     * @param listener Service registration listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(RcsServiceRegistrationListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IRcsServiceRegistrationListener> weakRef = mRegistrationListeners\n                    .remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IRcsServiceRegistrationListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                callApiMethod(\"removeEventListener\", rcsListener,\n                        IRcsServiceRegistrationListener.class);\n            }\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the configuration that is common for all the service APIs\n     * \n     * @return CommonServiceConfiguration instance\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public CommonServiceConfiguration getCommonConfiguration()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            ICommonServiceConfiguration configuration = (ICommonServiceConfiguration) callApiMethod(\n                    \"getCommonConfiguration\", null, null);\n            return new CommonServiceConfiguration(configuration);\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceControl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.app.Activity;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager.NameNotFoundException;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.util.Log;\n\n/**\n * A utility class to control the activation of the RCS service.\n * \n * @author Philippe LEMORDANT\n */\npublic class RcsServiceControl {\n\n    private static final boolean sAccurateLog = false;\n\n    /**\n     * RCS stack package name\n     */\n    public final static String RCS_STACK_PACKAGENAME = \"com.gsma.rcs\";\n\n    private static final String TIME_SPENT = \"dur\";\n\n    /**\n     * Singleton of RcsServiceControl\n     */\n    private static volatile RcsServiceControl sInstance;\n\n    private final Handler mHandler;\n    private final Context mContext;\n\n    private static final long INTENT_RESPONSE_TIMEOUT = 2000;\n\n    private final static String LOG_TAG = \"[RCS][\" + RcsServiceControl.class.getSimpleName() + \"]\";\n\n    private RcsServiceControl(Context ctx) {\n        HandlerThread handlerThread = new HandlerThread(getClass().getSimpleName());\n        handlerThread.start();\n        mHandler = new Handler(handlerThread.getLooper());\n        mContext = ctx;\n    }\n\n    /**\n     * Gets an instance of RcsServiceControl\n     *\n     * @param ctx the context.\n     * @return RcsServiceControl the singleton instance.\n     */\n    public static RcsServiceControl getInstance(Context ctx) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (RcsServiceControl.class) {\n            if (sInstance == null) {\n                if (ctx == null) {\n                    throw new IllegalArgumentException(\"Context is null\");\n\n                }\n                sInstance = new RcsServiceControl(ctx.getApplicationContext());\n            }\n        }\n        return sInstance;\n    }\n\n    /**\n     * IntentUtils class sets appropriate flags to an intent using reflection\n     */\n    private static class IntentUtils {\n\n        /**\n         * Using reflection to add FLAG_EXCLUDE_STOPPED_PACKAGES support backward compatibility.\n         *\n         * @param intent Intent to set flags\n         */\n        private static void tryToSetExcludeStoppedPackagesFlag(Intent intent) {\n            intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);\n        }\n\n        /**\n         * Using reflection to add FLAG_RECEIVER_FOREGROUND support backward compatibility.\n         *\n         * @param intent Intent to set flags\n         */\n        private static void tryToSetReceiverForegroundFlag(Intent intent) {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {\n                /*\n                 * Since FLAG_RECEIVER_FOREGROUND is introduced only from API level\n                 * JELLY_BEAN_VERSION_CODE we need to do nothing if we are running on a version\n                 * prior that so we just return then.\n                 */\n                return;\n            }\n            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);\n        }\n    }\n\n    private Intent generateIsCompatibeIntent(String service) {\n        Intent intent = new Intent(Intents.Service.ACTION_GET_COMPATIBILITY);\n        intent.putExtra(Intents.Service.EXTRA_GET_COMPATIBILITY_SERVICE, service);\n        intent.putExtra(Intents.Service.EXTRA_GET_COMPATIBILITY_CODENAME,\n                RcsService.Build.API_CODENAME);\n        intent.putExtra(Intents.Service.EXTRA_GET_COMPATIBILITY_VERSION,\n                RcsService.Build.API_VERSION);\n        intent.putExtra(Intents.Service.EXTRA_GET_COMPATIBILITY_INCREMENT,\n                RcsService.Build.API_INCREMENTAL);\n        return intent;\n    }\n\n    private Intent generateSetActivationModeIntent(boolean active) {\n        Intent intent = new Intent(Intents.Service.ACTION_SET_ACTIVATION_MODE);\n        intent.putExtra(Intents.Service.EXTRA_SET_ACTIVATION_MODE, active);\n        return intent;\n    }\n\n    private class SyncBroadcastReceiver extends BroadcastReceiver {\n        public volatile boolean mHaveResult = false;\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            synchronized (this) {\n                mHaveResult = true;\n                notify();\n            }\n        }\n    }\n\n    /**\n     * Query RCS stack by sending broadcast intent.\n     *\n     * @param intent Intent\n     * @return the result extra data bundle or null if no response is received due to timeout\n     * @throws RcsGenericException raised if timeout\n     */\n    private Bundle queryRcsStackByIntent(Intent intent) throws RcsGenericException {\n        final String action = intent.getAction();\n        final SyncBroadcastReceiver broadcastReceiver = new SyncBroadcastReceiver();\n        intent.setPackage(RCS_STACK_PACKAGENAME);\n        trySetIntentForActivePackageAndReceiverInForeground(intent);\n        synchronized (sInstance) {\n            synchronized (broadcastReceiver) {\n                mContext.sendOrderedBroadcast(intent, null, broadcastReceiver, mHandler,\n                        Activity.RESULT_OK, null, null);\n                long endTime = System.currentTimeMillis() + INTENT_RESPONSE_TIMEOUT;\n                while (!broadcastReceiver.mHaveResult) {\n                    long delay = endTime - System.currentTimeMillis();\n                    if (delay <= 0) {\n                        Log.w(LOG_TAG, \"Waiting for result for \" + action\n                                + \" has reached deadline!\");\n                        break;\n                    }\n                    try {\n                        if (sAccurateLog) {\n                            Log.d(LOG_TAG, \"Waiting for result for \" + action + \" during max \"\n                                    + delay + \"ms\");\n                        }\n                        broadcastReceiver.wait(delay);\n\n                    } catch (InterruptedException e) {\n                        Log.w(LOG_TAG, \"Waiting for result for \" + action + \" was interrupted!\");\n                    }\n                }\n                Bundle result = broadcastReceiver.getResultExtras(false);\n                if (result == null) {\n                    throw new RcsGenericException(\"Failed to get result for \" + action + \"!\");\n                }\n                result.putLong(TIME_SPENT, System.currentTimeMillis() - endTime\n                        + INTENT_RESPONSE_TIMEOUT);\n                return result;\n            }\n        }\n    }\n\n    /**\n     * Update flags of the broadcast intent to increase performance\n     *\n     * @param intent the intent\n     */\n    private void trySetIntentForActivePackageAndReceiverInForeground(Intent intent) {\n        IntentUtils.tryToSetExcludeStoppedPackagesFlag(intent);\n        IntentUtils.tryToSetReceiverForegroundFlag(intent);\n    }\n\n    /**\n     * Returns true if the RCS stack is installed and not disabled on the device.\n     *\n     * @return boolean true if the RCS stack is installed and not disabled on the device.\n     */\n    public boolean isAvailable() {\n        try {\n            ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(\n                    RCS_STACK_PACKAGENAME, 0);\n            return (appInfo.flags & ApplicationInfo.FLAG_STOPPED) == 0;\n        } catch (NameNotFoundException e) {\n            return false;\n        }\n    }\n\n    /**\n     * Returns true if the RCS stack de-activation/activation is allowed by the client.\n     *\n     * @return boolean true if the RCS stack de-activation/activation is allowed by the client.\n     * @throws RcsGenericException\n     */\n    public boolean isActivationModeChangeable() throws RcsGenericException {\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"isActivationModeChangeable: Request()\");\n        }\n        Bundle result = queryRcsStackByIntent(new Intent(\n                Intents.Service.ACTION_GET_ACTIVATION_MODE_CHANGEABLE));\n        boolean activationModeChangeable = result.getBoolean(\n                Intents.Service.EXTRA_GET_ACTIVATION_MODE_CHANGEABLE, false);\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"isActivationModeChangeable: Response() = \" + activationModeChangeable\n                    + \" (in \" + result.getLong(TIME_SPENT, -1) + \"ms)\");\n        }\n        return activationModeChangeable;\n    }\n\n    /**\n     * Returns true if the RCS stack is marked as active on the device.\n     *\n     * @return boolean true if the RCS stack is marked as active on the device.\n     * @throws RcsGenericException\n     */\n    public boolean isActivated() throws RcsGenericException {\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"isActivated: Request()\");\n        }\n        Bundle result = queryRcsStackByIntent(new Intent(Intents.Service.ACTION_GET_ACTIVATION_MODE));\n        boolean activated = result.getBoolean(Intents.Service.EXTRA_GET_ACTIVATION_MODE, false);\n        if (sAccurateLog) {\n            Log.d(LOG_TAG,\n                    \"isActivated: Response() -> \" + activated + \" (in \"\n                            + result.getLong(TIME_SPENT, -1) + \"ms)\");\n        }\n        return activated;\n    }\n\n    /**\n     * Deactive/Activate the RCS stack in case these operations are allowed (see\n     * isStackActivationStatusChangeable) or else throws an RcsPermissionDeniedException.\n     *\n     * @param active True is activation is enabled.\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void setActivationMode(boolean active) throws RcsPermissionDeniedException,\n            RcsGenericException {\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"setActivationMode: Request(\" + active + \")\");\n        }\n        Bundle result = queryRcsStackByIntent(generateSetActivationModeIntent(active));\n        boolean activationMode = result\n                .getBoolean(Intents.Service.EXTRA_SET_ACTIVATION_MODE, false);\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"setActivationMode: Response(\" + active + \") -> \" + activationMode\n                    + \" (in \" + result.getLong(TIME_SPENT, -1) + \"ms)\");\n        }\n        if (active != activationMode) {\n            throw new RcsPermissionDeniedException(\"Stack activation mode is not changeable!\");\n        }\n    }\n\n    /**\n     * Returns true if the client RCS API and core RCS stack are compatible for the given service.\n     *\n     * @param service the RCS service\n     * @return boolean true if the client RCS stack and RCS API are compatible for the given\n     *         service.\n     * @throws RcsGenericException\n     * @hide\n     */\n    public boolean isCompatible(RcsService service) throws RcsGenericException {\n        String serviceName = service.getClass().getSimpleName();\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"isCompatible: Request(\" + serviceName + \")\");\n        }\n        Bundle result = queryRcsStackByIntent(generateIsCompatibeIntent(serviceName));\n        boolean compatible = result.getBoolean(Intents.Service.EXTRA_GET_COMPATIBILITY_RESPONSE,\n                false);\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"isCompatible: Response(\" + serviceName + \") -> \" + compatible + \" (in \"\n                    + result.getLong(TIME_SPENT, -1) + \"ms)\");\n        }\n        return compatible;\n    }\n\n    /**\n     * Returns true if the RCS stack is started.\n     *\n     * @return boolean true if the RCS stack is started.\n     * @throws RcsGenericException\n     */\n    public boolean isServiceStarted() throws RcsGenericException {\n        if (sAccurateLog) {\n            Log.d(LOG_TAG, \"isServiceStarted: Request()\");\n        }\n        Bundle result = queryRcsStackByIntent(new Intent(\n                Intents.Service.ACTION_GET_SERVICE_STARTING_STATE));\n        boolean started = result\n                .getBoolean(Intents.Service.EXTRA_GET_SERVICE_STARTING_STATE, false);\n        if (sAccurateLog) {\n            Log.d(LOG_TAG,\n                    \"isServiceStarted: Response() -> \" + started + \" (in \"\n                            + result.getLong(TIME_SPENT, -1) + \"ms)\");\n        }\n        return started;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.text.TextUtils;\n\n/**\n * Rcs service exception\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RcsServiceException extends Exception {\n\n    /**\n     * Special Delimiter that will be appended while trasmitting server exceptions over AIDL layer.\n     */\n    static final char DELIMITER_PIPE = '|';\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsServiceException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructs a new Exception with the current stack trace and the specified cause.\n     * \n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsServiceException(Throwable cause) {\n        super(cause);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsServiceException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Checks if the exception is one of the intended server side exception that has been thrown\n     * over the AIDL layer.\n     * \n     * @param e Exception\n     * @param clazz Class\n     * @return true if exception getMessage() starts with clazz getName()\n     */\n    protected static boolean isIntendedException(Exception e, Class<?> clazz) {\n        final String message = e.getMessage();\n        return (!TextUtils.isEmpty(message) && message.startsWith(clazz.getName()));\n    }\n\n    /**\n     * Extracts server side exception message thrown over the AIDL layer after parsing it based on\n     *\n     * @param e Exception\n     * @return Server exception message\n     */\n    protected static String extractServerException(Exception e) {\n        final String message = e.getMessage();\n        final int delimiterIndex = message.indexOf(DELIMITER_PIPE);\n        if (delimiterIndex > 0 && delimiterIndex < message.length() - 1) {\n            return message.substring(delimiterIndex + 1);\n        }\n        return message;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.util.SparseArray;\n\n/**\n * RCS service event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface RcsServiceListener {\n    /**\n     * ReasonCode\n     */\n    enum ReasonCode {\n\n        /**\n         * Internal error\n         */\n        INTERNAL_ERROR(0),\n\n        /**\n         * Service has been disabled\n         */\n        SERVICE_DISABLED(1),\n\n        /**\n         * Service connection has been lost\n         */\n        CONNECTION_LOST(2);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to ReasonCode instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a ReasonCode instance for the specified integer value.\n         * \n         * @param value the value associated with the ReasonCode\n         * @return instance\n         */\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value + \"!\");\n        }\n\n    }\n\n    /**\n     * Callback called when service is connected. This method is called when the service is well\n     * connected to the RCS service (binding procedure successful): this means the methods of the\n     * API may be used.\n     */\n    void onServiceConnected();\n\n    /**\n     * Callback called when service has been disconnected. This method is called when the service is\n     * disconnected from the RCS service (e.g. service deactivated).\n     * \n     * @param reasonCode the reason code\n     * @see ReasonCode\n     */\n    void onServiceDisconnected(ReasonCode reasonCode);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceNotAvailableException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\n/**\n * RCS service not available exception\n * <p>\n * Thrown when a method of the service API is called and the service API is not bound to the RCS\n * service (e.g. RCS service not yet started or API not yet connected).\n * </p>\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RcsServiceNotAvailableException extends RcsServiceException {\n\n    static final long serialVersionUID = 1L;\n\n    private static final String ERROR_CNX = \"Service not connected\";\n\n    /**\n     * No Argument Constructor\n     * <p>\n     * This is a special case and reason for providing such constructor is due to the fact that we\n     * will either have all or none of the services available at any given instance. So we can keep\n     * the error message centralized here itself.\n     * </p>\n     */\n    public RcsServiceNotAvailableException() {\n        super(ERROR_CNX);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsServiceNotAvailableException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceNotRegisteredException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\n/**\n * Rcs service not registered exception\n * <p>\n * Thrown when a method of the service API using the RCS service platform is called and the terminal\n * which requires that the RcsCoreService is registered and connected to the IMS server is not\n * registered to the RCS service platform (e.g. not yet registered)\n * </p>\n * <p>\n * Should not be thrown when a service API method is called that fully could perform its scope of\n * responsibility without having to be connected to the IMS.\n * </p>\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RcsServiceNotRegisteredException extends RcsServiceException {\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsServiceNotRegisteredException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsServiceNotRegisteredException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsServiceNotRegisteredException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsServiceNotRegisteredException\n     */\n    public static void assertException(Exception e) throws RcsServiceNotRegisteredException {\n        if (isIntendedException(e, RcsServiceNotRegisteredException.class)) {\n            throw new RcsServiceNotRegisteredException(extractServerException(e), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceRegistration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.util.SparseArray;\n\n/**\n * A class to hold the reason code for IMS registration\n * \n * @author Philippe LEMORDANT\n */\npublic class RcsServiceRegistration {\n    /**\n     * ReasonCode for IMS registration\n     */\n    public enum ReasonCode {\n        /**\n         * No specific reason code specified\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * IMS connection has been lost\n         */\n        CONNECTION_LOST(1),\n\n        /**\n         * Disconnected from RCS platform (Battery low)\n         */\n        BATTERY_LOW(2);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to ReasonCode instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a ReasonCode instance for the specified integer value.\n         * \n         * @param value the value associated with the ReasonCode\n         * @return instance\n         */\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + RcsServiceRegistration.class.getName() + \"\" + value + \"!\");\n        }\n\n    }\n\n    private RcsServiceRegistration() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceRegistrationListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\n/**\n * Service registration events listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class RcsServiceRegistrationListener {\n\n    /**\n     * Callback called when service is registered to the network platform\n     */\n    public abstract void onServiceRegistered();\n\n    /**\n     * Callback called when service is unregistered from the network platform\n     * \n     * @param reasonCode the reason code\n     */\n    public abstract void onServiceUnregistered(RcsServiceRegistration.ReasonCode reasonCode);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsServiceRegistrationListenerImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs;\n\nimport android.util.Log;\n\n/**\n * RCS service registration listener implementation\n * \n * @hide\n */\npublic class RcsServiceRegistrationListenerImpl extends IRcsServiceRegistrationListener.Stub {\n\n    private final RcsServiceRegistrationListener mListener;\n\n    private final static String LOG_TAG = RcsServiceRegistrationListenerImpl.class.getName();\n\n    RcsServiceRegistrationListenerImpl(RcsServiceRegistrationListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onServiceRegistered() {\n        mListener.onServiceRegistered();\n    }\n\n    @Override\n    public void onServiceUnregistered(int reasonCode) {\n        RcsServiceRegistration.ReasonCode rcsReasonCode;\n        try {\n            rcsReasonCode = RcsServiceRegistration.ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n\n        mListener.onServiceUnregistered(rcsReasonCode);\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/RcsUnsupportedOperationException.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs;\n\nimport android.text.TextUtils;\n\n/**\n * Rcs unsupported operation exception.\n * <p>\n * Thrown when a method of the service API is called that is not supported (ie does not make sense\n * within the scope of the use case) like trying to call pauseTransfer() on a non pausable file\n * transfer that does not support that etc.\n * </p>\n */\npublic class RcsUnsupportedOperationException extends UnsupportedOperationException {\n\n    /**\n     * Special Delimiter that will be appended while trasmitting server exceptions over AIDL layer.\n     */\n    private static final char DELIMITER_PIPE = '|';\n\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     */\n    public RcsUnsupportedOperationException(String message) {\n        super(message);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param message Error message obtained either from a constant string or through e.getMessage()\n     * @param cause the cause (which is saved for later retrieval by the Throwable.getCause()\n     *            method). (A null value is permitted, and indicates that the cause is nonexistent\n     *            or unknown.)\n     */\n    public RcsUnsupportedOperationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Asserts {@link RcsUnsupportedOperationException}\n     * <p>\n     * An utility method that will translate the Server side exception to client specific exception\n     * by parsing exception message which will have a special formatted exception message with a\n     * pre-defined delimiter.\n     * </p>\n     * \n     * @param e Exception\n     * @throws RcsUnsupportedOperationException\n     */\n    public static void assertException(Exception e) throws RcsUnsupportedOperationException {\n        if (isIntendedException(e, RcsUnsupportedOperationException.class)) {\n            throw new RcsUnsupportedOperationException(extractServerException(e), e);\n        }\n    }\n\n    /**\n     * Checks if the exception is one of the intended server side exception that has been thrown\n     * over the AIDL layer.\n     * \n     * @param e Exception\n     * @param clazz Class\n     * @return true if exception getMessage() starts with clazz getName()\n     */\n    private static boolean isIntendedException(Exception e, Class<?> clazz) {\n        final String message = e.getMessage();\n        return (!TextUtils.isEmpty(message) && message.startsWith(clazz.getName()));\n    }\n\n    /**\n     * Extracts server side exception message thrown over the AIDL layer after parsing it based on\n     * {@link DELIMITER_PIPE}\n     * \n     * @param e Exception\n     * @return Server exception message\n     */\n    private static String extractServerException(Exception e) {\n        final String message = e.getMessage();\n        final int delimiterIndex = message.indexOf(DELIMITER_PIPE);\n        if (delimiterIndex > 0 && delimiterIndex < message.length() - 1) {\n            return message.substring(delimiterIndex + 1);\n        }\n        return message;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/capability/Capabilities.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.capability;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Capabilities of a contact. This class encapsulates the different capabilities which may be\n * supported by the local user or a remote contact.\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class Capabilities implements Parcelable {\n    /**\n     * Image sharing support\n     */\n    private boolean mImageSharing = false;\n\n    /**\n     * Video sharing support\n     */\n    private boolean mVideoSharing = false;\n\n    /**\n     * IM session support\n     */\n    private boolean mImSession = false;\n\n    /**\n     * File transfer support\n     */\n    private boolean mFileTransfer = false;\n\n    /**\n     * Geolocation push support\n     */\n    private boolean mGeolocPush = false;\n\n    /**\n     * List of supported extensions\n     */\n    private Set<String> mExtensions = new HashSet<>();\n\n    /**\n     * Automata flag\n     */\n    private boolean mAutomata = false;\n\n    /**\n     * The timestamp of the last capability response\n     */\n    private long mTimestamp;\n\n    /**\n     * Indicates the file transfer capability is supported.\n     */\n    public static final int CAPABILITY_FILE_TRANSFER = 0x00000001;\n\n    /**\n     * Indicates the IM capability is supported.\n     */\n    public static final int CAPABILITY_IM = 0x00000002;\n\n    /**\n     * Indicates the geoloc push capability is supported.\n     */\n    public static final int CAPABILITY_GEOLOC_PUSH = 0x00000004;\n\n    /**\n     * Indicates the image sharing capability is supported.\n     */\n    public static final int CAPABILITY_IMAGE_SHARING = 0x00000008;\n\n    /**\n     * Indicates the video sharing capability is supported.\n     */\n    public static final int CAPABILITY_VIDEO_SHARING = 0x00000010;\n\n    /**\n     * Constructor\n     *\n     * @param imageSharing Image sharing support\n     * @param videoSharing Video sharing support\n     * @param imSession IM/Chat support\n     * @param fileTransfer File transfer support\n     * @param geolocPush Geolocation push support\n     * @param extensions Set of supported extensions\n     * @param automata Automata flag\n     * @param timestamp timestamp of last capability response\n     * @hide\n     */\n    public Capabilities(boolean imageSharing, boolean videoSharing, boolean imSession,\n            boolean fileTransfer, boolean geolocPush, Set<String> extensions, boolean automata,\n            long timestamp) {\n        mImageSharing = imageSharing;\n        mVideoSharing = videoSharing;\n        mImSession = imSession;\n        mFileTransfer = fileTransfer;\n        mGeolocPush = geolocPush;\n        mExtensions = extensions;\n        mAutomata = automata;\n        mTimestamp = timestamp;\n    }\n\n    /**\n     * Constructor\n     *\n     * @param source Parcelable source\n     * @hide\n     */\n    public Capabilities(Parcel source) {\n        mImageSharing = source.readInt() != 0;\n        mVideoSharing = source.readInt() != 0;\n        mImSession = source.readInt() != 0;\n        mFileTransfer = source.readInt() != 0;\n\n        boolean containsExtension = source.readInt() != 0;\n        if (containsExtension) {\n            List<String> exts = new ArrayList<>();\n            source.readStringList(exts);\n            mExtensions = new HashSet<>(exts);\n        } else {\n            mExtensions = null;\n        }\n        mGeolocPush = source.readInt() != 0;\n        mAutomata = source.readInt() != 0;\n        mTimestamp = source.readLong();\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation\n     *\n     * @return Integer\n     * @hide\n     */\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object\n     *\n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(mImageSharing ? 1 : 0);\n        dest.writeInt(mVideoSharing ? 1 : 0);\n        dest.writeInt(mImSession ? 1 : 0);\n        dest.writeInt(mFileTransfer ? 1 : 0);\n        if (mExtensions != null) {\n            dest.writeInt(1);\n            List<String> exts = new ArrayList<String>(mExtensions);\n            dest.writeStringList(exts);\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeInt(mGeolocPush ? 1 : 0);\n        dest.writeInt(mAutomata ? 1 : 0);\n        dest.writeLong(mTimestamp);\n    }\n\n    /**\n     * Parcelable creator\n     *\n     * @hide\n     */\n    public static final Parcelable.Creator<Capabilities> CREATOR = new Parcelable.Creator<Capabilities>() {\n        public Capabilities createFromParcel(Parcel source) {\n            return new Capabilities(source);\n        }\n\n        public Capabilities[] newArray(int size) {\n            return new Capabilities[size];\n        }\n    };\n\n    /**\n     * Is image sharing supported\n     *\n     * @deprecated Use {@link #hasCapabilities(int capabilities)} instead.\n     * @return true if supported else returns false\n     */\n    @Deprecated\n    public boolean isImageSharingSupported() {\n        return mImageSharing;\n    }\n\n    /**\n     * Is video sharing supported\n     *\n     * @deprecated Use {@link #hasCapabilities(int capabilities)} instead.\n     * @return true if supported else returns false\n     */\n    @Deprecated\n    public boolean isVideoSharingSupported() {\n        return mVideoSharing;\n    }\n\n    /**\n     * Is IM session supported\n     *\n     * @deprecated Use {@link #hasCapabilities(int capabilities)} instead.\n     * @return true if supported else returns false\n     */\n    @Deprecated\n    public boolean isImSessionSupported() {\n        return mImSession;\n    }\n\n    /**\n     * Is file transfer supported\n     *\n     * @deprecated Use {@link #hasCapabilities(int capabilities)} instead.\n     * @return true if supported else returns false\n     */\n    @Deprecated\n    public boolean isFileTransferSupported() {\n        return mFileTransfer;\n    }\n\n    /**\n     * Is geolocation push supported\n     *\n     * @deprecated Use {@link #hasCapabilities(int capabilities)} instead.\n     * @return true if supported else returns false\n     */\n    @Deprecated\n    public boolean isGeolocPushSupported() {\n        return mGeolocPush;\n    }\n\n    /**\n     * Is extension supported\n     *\n     * @param tag Feature tag\n     * @return true if supported else returns false\n     */\n    public boolean isExtensionSupported(String tag) {\n        return mExtensions.contains(tag);\n    }\n\n    /**\n     * Gets the set of supported extensions\n     *\n     * @return Set of feature tags\n     */\n    public Set<String> getSupportedExtensions() {\n        return mExtensions;\n    }\n\n    /**\n     * Is automata\n     *\n     * @return true if it's an automata else returns false\n     */\n    public boolean isAutomata() {\n        return mAutomata;\n    }\n\n    /**\n     * Timestamp of the last capability response (in milliseconds)\n     *\n     * @return the timestamp of the last capability response\n     */\n    public long getTimestamp() {\n        return mTimestamp;\n    }\n\n    private int isCapabilitySupported(boolean supported, int capabilityFlag) {\n        return (supported) ? capabilityFlag : 0;\n    }\n\n    /**\n     * Gets the combination of supported capabilities.\n     * \n     * @return the combination of supported capabilities\n     */\n    private int getSupportedCapabilities() {\n        int result = isCapabilitySupported(mFileTransfer, CAPABILITY_FILE_TRANSFER);\n        result |= isCapabilitySupported(mImSession, CAPABILITY_IM);\n        result |= isCapabilitySupported(mGeolocPush, CAPABILITY_GEOLOC_PUSH);\n        result |= isCapabilitySupported(mImageSharing, CAPABILITY_IMAGE_SHARING);\n        result |= isCapabilitySupported(mVideoSharing, CAPABILITY_VIDEO_SHARING);\n        return result;\n    }\n\n    /**\n     * Tests for the support of capabilities on this instance.\n     * \n     * @return True if the capabilities are supported.\n     */\n    public boolean hasCapabilities(int capabilities) {\n        return (getSupportedCapabilities() & capabilities) == capabilities;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/capability/CapabilitiesListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.capability;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * New capabilities event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class CapabilitiesListener {\n    /**\n     * Callback called when new capabilities are received for a given contact\n     * \n     * @param contact Contact Identifier\n     * @param capabilities Received capabilities\n     */\n    public abstract void onCapabilitiesReceived(ContactId contact, Capabilities capabilities);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/capability/CapabilitiesListenerImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.capability;\n\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteException;\n\n/**\n * Capabilitues event listener implementation\n * \n * @author Philippe LEMORDANT\n * @hide\n */\npublic class CapabilitiesListenerImpl extends ICapabilitiesListener.Stub {\n\n    private final CapabilitiesListener mListener;\n\n    /**\n     * Constructor\n     * \n     * @param listener Capabilities listener\n     */\n    public CapabilitiesListenerImpl(CapabilitiesListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onCapabilitiesReceived(ContactId contact, Capabilities capabilities)\n            throws RemoteException {\n        mListener.onCapabilitiesReceived(contact, capabilities);\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/capability/CapabilitiesLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.capability;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Content provider for last received capabilities\n * \n * @author Jean-Marc AUFFRET\n */\npublic class CapabilitiesLog {\n    /**\n     * Content provider URI\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.capability/capability\");\n\n    /**\n     * Capability is not supported\n     */\n    public static final int NOT_SUPPORTED = 0;\n\n    /**\n     * Capability is supported\n     */\n    public static final int SUPPORTED = 1;\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the MSISDN of the remote contact associated to the\n     * capabilities.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the image share capability.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String CAPABILITY_IMAGE_SHARE = \"capability_image_share\";\n\n    /**\n     * The name of the column containing the video share capability.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String CAPABILITY_VIDEO_SHARE = \"capability_video_share\";\n\n    /**\n     * The name of the column containing the file transfer capability.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String CAPABILITY_FILE_TRANSFER = \"capability_file_transfer\";\n\n    /**\n     * The name of the column containing the chat/IM session capability.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String CAPABILITY_IM_SESSION = \"capability_im_session\";\n\n    /**\n     * The name of the column containing the geoloc push capability.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String CAPABILITY_GEOLOC_PUSH = \"capability_geoloc_push\";\n\n    /**\n     * The name of the column containing the RCS extensions. List of features tags semicolon\n     * separated (e.g. <TAG1>;<TAG2>;...;TAGn).\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CAPABILITY_EXTENSIONS = \"capability_extensions\";\n\n    /**\n     * The name of the column containing the automata information.\n     */\n    public static final String AUTOMATA = \"automata\";\n\n    /**\n     * The name of the column containing the time of the last capability update from network.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP = \"timestamp\";\n\n    private CapabilitiesLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/capability/CapabilityService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.capability;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * Capability service offers the main entry point to read capabilities of remote contacts, to\n * initiate capability discovery and to receive capabilities updates. Several applications may\n * connect/disconnect to the API. The parameter contact in the API supports the following formats:\n * MSISDN in national or international format, SIP address, SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic final class CapabilityService extends RcsService {\n    /**\n     * Intent broadcasted to discover extensions\n     */\n    public final static String INTENT_EXTENSIONS = \"com.gsma.services.rcs.capability.EXTENSION\";\n\n    /**\n     * Extension MIME type\n     */\n    public final static String EXTENSION_MIME_TYPE = \"com.gsma.services.rcs\";\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * API\n     */\n    private ICapabilityService mApi;\n    private final Map<CapabilitiesListener, WeakReference<ICapabilitiesListener>> mCapabilitiesListeners = new WeakHashMap<>();\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public CapabilityService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the capability service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the capability service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(ICapabilityService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (ICapabilityService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(ICapabilityService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Returns the capabilities supported by the local end user. The supported capabilities are\n     * fixed by the MNO and read during the provisioning.\n     * \n     * @return Capabilities\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public Capabilities getMyCapabilities() throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.getMyCapabilities();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the capabilities of a given contact from the local database. This method doesn't\n     * request any network update to the remote contact. The parameter contact supports the\n     * following formats: MSISDN in national or international format, SIP address, SIP-URI or\n     * Tel-URI. If the format of the contact is not supported an exception is thrown.\n     * \n     * @param contact Contact Identifier\n     * @return Capabilities\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public Capabilities getContactCapabilities(ContactId contact)\n            throws RcsPersistentStorageException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.getContactCapabilities(contact);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Requests capabilities to a remote contact. This method initiates in background a new\n     * capability request to the remote contact by sending a SIP OPTIONS. The result of the\n     * capability request is sent asynchronously via callback method of the capabilities listener.\n     * The parameter contact supports the following formats: MSISDN in national or international\n     * format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an\n     * exception is thrown. The result of the capability refresh request is provided to all the\n     * clients that have registered the listener for this event.\n     *\n     * @deprecated Use {@link #requestContactCapabilities(Set of ContactIds )} instead.\n     * @param contact Contact Identifier\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    @Deprecated\n    public void requestContactCapabilities(ContactId contact)\n            throws RcsServiceNotRegisteredException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            List<ContactId> listOfContacts = new ArrayList<>();\n            listOfContacts.add(contact);\n            mApi.requestContactCapabilities2(listOfContacts);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Requests capabilities for a group of remote contacts. This method initiates in background new\n     * capability requests to the remote contact by sending a SIP OPTIONS. The result of the\n     * capability request is sent asynchronously via callback method of the capabilities listener.\n     * The parameter contacts supports the following formats: MSISDN in national or international\n     * format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an\n     * exception is thrown. The result of the capability refresh request is provided to all the\n     * clients that have registered the listener for this event.\n     * \n     * @param contacts Set of contact identifiers\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void requestContactCapabilities(Set<ContactId> contacts)\n            throws RcsServiceNotRegisteredException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        if (contacts == null || contacts.isEmpty()) {\n            throw new RcsIllegalArgumentException(\"contacts must not be null or empty!\");\n        }\n        try {\n            mApi.requestContactCapabilities2(new ArrayList<>(contacts));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Requests capabilities for all contacts existing in the local address book. This method\n     * initiates in background new capability requests for each contact of the address book by\n     * sending SIP OPTIONS. The result of a capability request is sent asynchronously via callback\n     * method of the capabilities listener. The result of the capability refresh request is provided\n     * to all the clients that have registered the listener for this event.\n     * \n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void requestAllContactsCapabilities() throws RcsServiceNotRegisteredException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        try {\n            mApi.requestAllContactsCapabilities();\n        } catch (Exception e) {\n            RcsServiceNotRegisteredException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Registers a capabilities listener on any contact\n     * \n     * @param listener Capabilities listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addCapabilitiesListener(CapabilitiesListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            ICapabilitiesListener rcsListener = new CapabilitiesListenerImpl(listener);\n            mCapabilitiesListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addCapabilitiesListener(rcsListener);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Unregisters a capabilities listener\n     * \n     * @param listener Capabilities listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeCapabilitiesListener(CapabilitiesListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<ICapabilitiesListener> weakRef = mCapabilitiesListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            ICapabilitiesListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeCapabilitiesListener(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Registers a capabilities listener on a list of contacts\n     * \n     * @param contacts Set of contact Identifiers\n     * @param listener Capabilities listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addCapabilitiesListener(Set<ContactId> contacts, CapabilitiesListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        if (contacts == null || contacts.isEmpty()) {\n            throw new RcsIllegalArgumentException(\"contacts must not be null or empty!\");\n        }\n        try {\n            ICapabilitiesListener rcsListener = new CapabilitiesListenerImpl(listener);\n            mCapabilitiesListeners.put(listener, new WeakReference<>(rcsListener));\n            for (ContactId contact : contacts) {\n                mApi.addCapabilitiesListener2(contact, rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Unregisters a capabilities listener on a list of contacts\n     * \n     * @param contacts Set of contact identifiers\n     * @param listener Capabilities listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeCapabilitiesListener(Set<ContactId> contacts, CapabilitiesListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        if (contacts == null || contacts.isEmpty()) {\n            throw new RcsIllegalArgumentException(\"contacts must not be null or empty!\");\n        }\n        try {\n            WeakReference<ICapabilitiesListener> weakRef = mCapabilitiesListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            ICapabilitiesListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                for (ContactId contact : contacts) {\n                    mApi.removeCapabilitiesListener2(contact, rcsListener);\n                }\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/capability/package-info.java",
    "content": "/**\n * This API permits to discover capabilities supported by remote contacts.\n * <p>\n * This API allows for querying the capabilities of a user or users and checking\n * for changes in their capabilities:<br>\n * - Read the supported capabilities locally by the user on its device.<br>\n * - Retrieve all capabilities of a user.<br>\n * - Checking a specific capability of a user.<br>\n * - Registering for changes to a user/users's capabilities.<br>\n * - Unregistering for changes to a user/users's capabilities.<br>\n * - Define scheme for registering new service capabilities based on manifest defined\n *  feature tags. This API may be accessible by any application (third party, MNO, OEM).\n *  The RCS extensions are controlled internally by the RCS service.\n * <p>\n * For example, this API may be used:<br>\n * - To request capability update for a user when opening its contact card in the address book.<br>\n * - To synchronize capabilities of all the contacts from the RCS account management menu.<br>\n * - To receive supported capabilities when a CS call is established.<br>\n */\n\npackage com.gsma.services.rcs.capability;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/ChatLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.provider.BaseColumns;\nimport android.util.SparseArray;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Content provider for chat history\n * \n * @author Jean-Marc AUFFRET\n * @author YPLO6403\n */\npublic class ChatLog {\n    /**\n     * Group chat\n     */\n    public static class GroupChat {\n        /**\n         * Content provider URI for chat conversations\n         */\n        public static final Uri CONTENT_URI = Uri\n                .parse(\"content://com.gsma.services.rcs.provider.chat/groupchat\");\n\n        /**\n         * History log member id\n         */\n        public static final int HISTORYLOG_MEMBER_ID = 0;\n\n        /**\n         * The name of the column containing the unique id across provider tables.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n        /**\n         * The name of the column containing the unique ID of the group chat.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String CHAT_ID = \"chat_id\";\n\n        /**\n         * The name of the column containing the state of the group chat.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         * \n         * @see State\n         */\n        public static final String STATE = \"state\";\n\n        /**\n         * The name of the column containing the reason code of the state of the group chat.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         * \n         * @see ReasonCode\n         */\n        public static final String REASON_CODE = \"reason_code\";\n\n        /**\n         * The name of the column containing the subject of the group chat.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String SUBJECT = \"subject\";\n\n        /**\n         * The name of the column containing the direction of the group chat.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         * \n         * @see Direction\n         */\n        public static final String DIRECTION = \"direction\";\n\n        /**\n         * The name of the column containing the time when group chat is created.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String TIMESTAMP = \"timestamp\";\n\n        /**\n         * The name of the column containing the list of participants and associated status.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String PARTICIPANTS = \"participants\";\n\n        /**\n         * ContactId formatted number of the inviter of the group chat or null if this is a group\n         * chat initiated by the local user (ie outgoing group chat).\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String CONTACT = \"contact\";\n\n        /**\n         * Utility method to get participants from its string representation in the ChatLog\n         * provider.\n         * \n         * @param ctx the context\n         * @param participants Participants in string representation\n         * @return Participants\n         * @throws RcsPermissionDeniedException\n         */\n        public static Map<ContactId, ParticipantStatus> getParticipants(Context ctx,\n                String participants) throws RcsPermissionDeniedException {\n            ContactUtil contactUtils = ContactUtil.getInstance(ctx);\n            String[] tokens = participants.split(\",\");\n            Map<ContactId, ParticipantStatus> participantResult = new HashMap<>();\n            for (String participant : tokens) {\n                String[] keyValue = participant.split(\"=\");\n                if (keyValue.length == 2) {\n                    String contact = keyValue[0];\n                    ParticipantStatus status = ParticipantStatus.valueOf(Integer\n                            .parseInt(keyValue[1]));\n                    participantResult.put(contactUtils.formatContact(contact), status);\n                }\n            }\n            return participantResult;\n        }\n\n        private GroupChat() {\n        }\n    }\n\n    /**\n     * Chat message from a single chat or group chat\n     */\n    public static class Message {\n        /**\n         * Content provider URI for chat messages\n         */\n        public static final Uri CONTENT_URI = Uri\n                .parse(\"content://com.gsma.services.rcs.provider.chat/chatmessage\");\n\n        /**\n         * History log member id\n         */\n        public static final int HISTORYLOG_MEMBER_ID = 1;\n\n        /**\n         * The name of the column containing the unique id across provider tables.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n        /**\n         * The name of the column containing the chat ID.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String CHAT_ID = \"chat_id\";\n\n        /**\n         * The name of the column containing the message ID.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String MESSAGE_ID = \"msg_id\";\n\n        /**\n         * The name of the column containing the message status.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String STATUS = \"status\";\n\n        /**\n         * The name of the column containing the message status reason code.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         * \n         * @see ReasonCode\n         */\n        public static final String REASON_CODE = \"reason_code\";\n\n        /**\n         * The name of the column containing the message read status.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String READ_STATUS = \"read_status\";\n\n        /**\n         * The name of the column containing the message direction.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         * \n         * @see Direction\n         */\n        public static final String DIRECTION = \"direction\";\n\n        /**\n         * The name of the column containing the MSISDN of the remote contact.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String CONTACT = \"contact\";\n\n        /**\n         * The name of the column containing the message content.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String CONTENT = \"content\";\n\n        /**\n         * The name of the column containing the time when message is created.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String TIMESTAMP = \"timestamp\";\n\n        /**\n         * The name of the column containing the time when message is sent. If 0 means not sent.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String TIMESTAMP_SENT = \"timestamp_sent\";\n\n        /**\n         * The name of the column containing the time when message is delivered. If 0 means not\n         * delivered.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String TIMESTAMP_DELIVERED = \"timestamp_delivered\";\n\n        /**\n         * The name of the column containing the time when message is displayed. If 0 means not\n         * displayed.\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String TIMESTAMP_DISPLAYED = \"timestamp_displayed\";\n\n        /**\n         * If delivery has expired for this message. Values: 1 (true), 0 (false)\n         * <P>\n         * Type: INTEGER\n         * </P>\n         */\n        public static final String EXPIRED_DELIVERY = \"expired_delivery\";\n\n        /**\n         * The name of the column containing the MIME-TYPE of the message body.\n         * <P>\n         * Type: TEXT\n         * </P>\n         */\n        public static final String MIME_TYPE = \"mime_type\";\n\n        /**\n         * Message MIME-types\n         */\n        public static class MimeType {\n\n            /**\n             * MIME-type of text messages\n             */\n            public static final String TEXT_MESSAGE = \"text/plain\";\n\n            /**\n             * MIME-type of geoloc messages\n             */\n            public static final String GEOLOC_MESSAGE = \"application/geoloc\";\n\n            /**\n             * MIME-type of group chat events\n             */\n            public static final String GROUPCHAT_EVENT = \"rcs/groupchat-event\";\n\n            private MimeType() {\n            }\n        }\n\n        public static class Content {\n            /**\n             * Status of the message\n             */\n            public enum Status {\n\n                /**\n                 * The message has been rejected\n                 */\n                REJECTED(0),\n\n                /**\n                 * The message is queued to be sent by rcs service when possible\n                 */\n                QUEUED(1),\n\n                /**\n                 * The message is in progress of sending\n                 */\n                SENDING(2),\n\n                /**\n                 * The message has been sent\n                 */\n                SENT(3),\n\n                /**\n                 * The message sending has been failed\n                 */\n                FAILED(4),\n\n                /**\n                 * The message has been delivered to the remote.\n                 */\n                DELIVERED(5),\n\n                /**\n                 * The message has been received and a displayed delivery report is requested\n                 */\n                DISPLAY_REPORT_REQUESTED(6),\n\n                /**\n                 * The message is delivered and no display delivery report is requested.\n                 */\n                RECEIVED(7),\n\n                /**\n                 * The message has been displayed\n                 */\n                DISPLAYED(8);\n\n                private final int mValue;\n\n                private static SparseArray<Status> mValueToEnum = new SparseArray<>();\n                static {\n                    for (Status entry : Status.values()) {\n                        mValueToEnum.put(entry.toInt(), entry);\n                    }\n                }\n\n                Status(int value) {\n                    mValue = value;\n                }\n\n                public final int toInt() {\n                    return mValue;\n                }\n\n                public static Status valueOf(int value) {\n                    Status entry = mValueToEnum.get(value);\n                    if (entry != null) {\n                        return entry;\n                    }\n                    throw new IllegalArgumentException(\"No enum const class \"\n                            + Status.class.getName() + \"\" + value + \"!\");\n                }\n            }\n\n            /**\n             * Reason code of the message status\n             */\n            public enum ReasonCode {\n\n                /**\n                 * No specific reason code specified.\n                 */\n                UNSPECIFIED(0),\n\n                /**\n                 * Sending of the message failed.\n                 */\n                FAILED_SEND(1),\n\n                /**\n                 * Delivering of the message failed.\n                 */\n                FAILED_DELIVERY(2),\n\n                /**\n                 * Displaying of the message failed.\n                 */\n                FAILED_DISPLAY(3),\n\n                /**\n                 * Incoming one-to-one message was detected as spam.\n                 */\n                REJECTED_SPAM(4);\n\n                private final int mValue;\n\n                private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n                static {\n                    for (ReasonCode entry : ReasonCode.values()) {\n                        mValueToEnum.put(entry.toInt(), entry);\n                    }\n                }\n\n                ReasonCode(int value) {\n                    mValue = value;\n                }\n\n                public final int toInt() {\n                    return mValue;\n                }\n\n                public static ReasonCode valueOf(int value) {\n                    ReasonCode entry = mValueToEnum.get(value);\n                    if (entry != null) {\n                        return entry;\n                    }\n                    throw new IllegalArgumentException(\"No enum const class \"\n                            + ReasonCode.class.getName() + \"\" + value + \"!\");\n                }\n            }\n\n            private Content() {\n            }\n        }\n\n        public static class GroupChatEvent {\n            /**\n             * Status of group chat event message\n             */\n            public enum Status {\n\n                /**\n                 * JOINED.\n                 */\n                JOINED(0),\n\n                /**\n                 * DEPARTED.\n                 */\n                DEPARTED(1);\n\n                private final int mValue;\n\n                private static SparseArray<Status> mValueToEnum = new SparseArray<>();\n                static {\n                    for (Status entry : Status.values()) {\n                        mValueToEnum.put(entry.toInt(), entry);\n                    }\n                }\n\n                Status(int value) {\n                    mValue = value;\n                }\n\n                public final int toInt() {\n                    return mValue;\n                }\n\n                public static Status valueOf(int value) {\n                    Status entry = mValueToEnum.get(value);\n                    if (entry != null) {\n                        return entry;\n                    }\n                    throw new IllegalArgumentException(\"No enum const class \"\n                            + Status.class.getName() + \"\" + value + \"!\");\n                }\n            }\n\n            private GroupChatEvent() {\n            }\n        }\n\n        private Message() {\n        }\n    }\n\n    private ChatLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/ChatMessage.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * Chat message\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class ChatMessage {\n\n    private final IChatMessage mChatMessageInf;\n\n    /**\n     * Constructor\n     * \n     * @param chatMessageInf IChatMessage\n     */\n    /* package private */ChatMessage(IChatMessage chatMessageInf) {\n        mChatMessageInf = chatMessageInf;\n    }\n\n    /**\n     * Returns the message ID\n     * \n     * @return String\n     * @throws RcsGenericException\n     */\n    public String getId() throws RcsGenericException {\n        try {\n            return mChatMessageInf.getId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the contact\n     * \n     * @return ContactId\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getContact();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the message content\n     * \n     * @return String\n     * @throws RcsPersistentStorageException\n     */\n    public String getContent() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getContent();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the mime type of the chat message.\n     * \n     * @return String\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getMimeType() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getMimeType();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of message\n     * \n     * @return Direction\n     * @see Direction\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Direction getDirection() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Direction.valueOf(mChatMessageInf.getDirection());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local time-stamp of when the chat message was sent and/or queued for outgoing\n     * messages or the local time-stamp of when the chat message was received for incoming messages.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestamp() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getTimestamp();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local time-stamp of when the chat message was sent and/or queued for outgoing\n     * messages or the remote time-stamp of when the chat message was sent for incoming messages.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestampSent() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getTimestampSent();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the chat message was delivered for outgoing messages or 0\n     * for incoming messages or it was not yet delivered.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestampDelivered() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getTimestampDelivered();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the chat message was displayed for outgoing messages or 0\n     * for incoming messages or it was not yes displayed.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestampDisplayed() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getTimestampDisplayed();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the status of the chat message.\n     * \n     * @return Status\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Status getStatus() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Status.valueOf(mChatMessageInf.getStatus());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the chat message.\n     * \n     * @return ReasonCode\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ReasonCode getReasonCode() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mChatMessageInf.getReasonCode());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the chat ID of this chat message.\n     * \n     * @return String\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getChatId() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.getChatId();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true is this chat message has been marked as read.\n     * \n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isRead() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.isRead();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if delivery for this chat message has expired or false otherwise. Note: false\n     * means either that delivery for this chat message has not yet expired, delivery has been\n     * successful, delivery expiration has been cleared (see clearMessageDeliveryExpiration) or that\n     * this particular chat message is not eligible for delivery expiration in the first place.\n     * \n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isExpiredDelivery() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mChatMessageInf.isExpiredDelivery();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/ChatService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * Chat service offers the main entry point to initiate chat 1-1 and group conversations with\n * contacts. Several applications may connect/disconnect to the API. The parameter contact in the\n * API supports the following formats: MSISDN in national or international format, SIP address,\n * SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class ChatService extends RcsService {\n    /**\n     * API\n     */\n    private IChatService mApi;\n\n    private final Map<OneToOneChatListener, WeakReference<IOneToOneChatListener>> mOneToOneChatListeners = new WeakHashMap<>();\n    private final Map<GroupChatListener, WeakReference<IGroupChatListener>> mGroupChatListeners = new WeakHashMap<>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public ChatService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the chat service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the chat service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IChatService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IChatService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IChatService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Returns the configuration of the chat service\n     * \n     * @return ChatServiceConfiguration\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public ChatServiceConfiguration getConfiguration() throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new ChatServiceConfiguration(mApi.getConfiguration());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a group chat with a group of contact and returns a GroupChat instance. The subject\n     * is optional and may be null.\n     * \n     * @param contacts Set of contact identifiers\n     * @param subject The subject is optional and may be null\n     * @return GroupChat instance\n     * @throws RcsPermissionDeniedException\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsMaxAllowedSessionLimitReachedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public GroupChat initiateGroupChat(Set<ContactId> contacts, String subject)\n            throws RcsPermissionDeniedException, RcsServiceNotRegisteredException,\n            RcsMaxAllowedSessionLimitReachedException, RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IGroupChat chatIntf = mApi.initiateGroupChat(new ArrayList<>(contacts), subject);\n            return new GroupChat(chatIntf);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsMaxAllowedSessionLimitReachedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a chat with a given contact\n     * \n     * @param contact ContactId\n     * @return OneToOneChat\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public OneToOneChat getOneToOneChat(ContactId contact) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new OneToOneChat(mApi.getOneToOneChat(contact));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a group chat from its unique ID. An exception is thrown if the chat ID does not exist\n     * \n     * @param chatId Chat ID\n     * @return GroupChat\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public GroupChat getGroupChat(String chatId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new GroupChat(mApi.getGroupChat(chatId));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to initiate a new group chat now else returns false.\n     * \n     * @return boolean\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToInitiateGroupChat() throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.isAllowedToInitiateGroupChat();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it's possible to initiate a new group chat with the specified contactId right\n     * now, else returns false.\n     * \n     * @param contact the remote contact\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToInitiateGroupChat(ContactId contact)\n            throws RcsPersistentStorageException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.isAllowedToInitiateGroupChat2(contact);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all one to one chat from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteOneToOneChats() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteOneToOneChats();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all group chat from history and abort/reject any associated ongoing session if such\n     * exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGroupChats() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGroupChats();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes a one to one chat with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteOneToOneChat(ContactId contact) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteOneToOneChat(contact);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Delete a group chat by its chat id from history and abort/reject any associated ongoing\n     * session if such exists.\n     * \n     * @param chatId the chat ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGroupChat(String chatId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGroupChat(chatId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Delete a message from its message id from history.\n     * \n     * @param msgId the message ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteMessage(String msgId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteMessage(msgId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Disables and clears any delivery expiration for a set of chat messages regardless if the\n     * delivery of them has expired already or not.\n     * \n     * @param msgIds the message IDs\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void clearMessageDeliveryExpiration(Set<String> msgIds)\n            throws RcsServiceNotAvailableException, RcsPersistentStorageException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.clearMessageDeliveryExpiration(new ArrayList<>(msgIds));\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Mark a received message as read (ie. displayed in the UI)\n     * \n     * @param msgId Message id\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void markMessageAsRead(String msgId) throws RcsServiceNotAvailableException,\n            RcsPersistentStorageException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.markMessageAsRead(msgId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on group chat events\n     * \n     * @param listener Group chat listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(GroupChatListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IGroupChatListener rcsListener = new GroupChatListenerImpl(listener);\n            mGroupChatListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener3(rcsListener);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on group chat events\n     * \n     * @param listener Group chat event listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(GroupChatListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IGroupChatListener> weakRef = mGroupChatListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IGroupChatListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener3(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener for one-to-one chat events\n     * \n     * @param listener One-to-one chat listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(OneToOneChatListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IOneToOneChatListener rcsListener = new OneToOneChatListenerImpl(listener);\n            mOneToOneChatListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener2(rcsListener);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener for one-to-one chat events\n     * \n     * @param listener One-to-one chat listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(OneToOneChatListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IOneToOneChatListener> weakRef = mOneToOneChatListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IOneToOneChatListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener2(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a chat message from its unique ID\n     * \n     * @param msgId Message id\n     * @return ChatMessage\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public ChatMessage getChatMessage(String msgId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new ChatMessage(mApi.getChatMessage(msgId));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/ChatServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\n/**\n * Chat service configuration\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class ChatServiceConfiguration {\n\n    private final IChatServiceConfiguration mIConfig;\n\n    /**\n     * Constructor\n     * \n     * @param iConfig IChatServiceConfiguration instance\n     * @hide\n     */\n    /* package private */ChatServiceConfiguration(IChatServiceConfiguration iConfig) {\n        mIConfig = iConfig;\n    }\n\n    /**\n     * Does the UX should alert the user that messages are handled differently when the Store and\n     * Forward functionality is involved. It returns True if user should be informed when sending\n     * message to offline user.\n     * \n     * @return boolean\n     * @throws RcsGenericException\n     */\n    public boolean isChatWarnSF() throws RcsGenericException {\n        try {\n            return mIConfig.isChatWarnSF();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the time after inactive chat could be closed\n     * \n     * @return long Timeout in milliseconds\n     * @throws RcsGenericException\n     */\n    public long getIsComposingTimeout() throws RcsGenericException {\n        try {\n            return mIConfig.getIsComposingTimeout();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the maximum number of participants in a group chat\n     * \n     * @return int Number\n     * @throws RcsGenericException\n     */\n    public int getGroupChatMaxParticipants() throws RcsGenericException {\n        try {\n            return mIConfig.getGroupChatMaxParticipants();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the minimum number of participants in a group chat\n     * \n     * @return int number\n     * @throws RcsGenericException\n     */\n    public int getGroupChatMinParticipants() throws RcsGenericException {\n        try {\n            return mIConfig.getGroupChatMinParticipants();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the maximum one-to-one chat message s length can have.\n     * <p>\n     * The length is the number of bytes of the message encoded in UTF-8.\n     * \n     * @return int Number of bytes\n     * @throws RcsGenericException\n     */\n    public int getOneToOneChatMessageMaxLength() throws RcsGenericException {\n        try {\n            return mIConfig.getOneToOneChatMessageMaxLength();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Return maximum length of a group chat message.\n     * <p>\n     * The length is the number of bytes of the message encoded in UTF-8.\n     * \n     * @return int Number of bytes\n     * @throws RcsGenericException\n     */\n    public int getGroupChatMessageMaxLength() throws RcsGenericException {\n        try {\n            return mIConfig.getGroupChatMessageMaxLength();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * The maximum group chat subject's length can have.\n     * <p>\n     * The length is the number of bytes of the message encoded in UTF-8.\n     * \n     * @return int The maximum group chat subject's length can have.\n     * @throws RcsGenericException\n     */\n    public int getGroupChatSubjectMaxLength() throws RcsGenericException {\n        try {\n            return mIConfig.getGroupChatSubjectMaxLength();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns True if group chat is supported, else returns False.\n     * \n     * @return boolean True if group chat is supported, else returns False.\n     * @throws RcsGenericException\n     */\n    public boolean isGroupChatSupported() throws RcsGenericException {\n        try {\n            return mIConfig.isGroupChatSupported();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Does the UX proposes automatically a SMS fallback in case of chat failure. It returns True if\n     * SMS fallback procedure is activated, else returns False.\n     * \n     * @return boolean\n     * @throws RcsGenericException\n     */\n    public boolean isSmsFallback() throws RcsGenericException {\n        try {\n            return mIConfig.isSmsFallback();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Does displayed delivery report activated on received chat messages.\n     * <p>\n     * Only applicable to one to one chat message.\n     * \n     * @return boolean\n     * @throws RcsGenericException\n     */\n    public boolean isRespondToDisplayReportsEnabled() throws RcsGenericException {\n        try {\n            return mIConfig.isRespondToDisplayReportsEnabled();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Return maximum length of a geoloc label\n     * \n     * @return int Number of bytes\n     * @throws RcsGenericException\n     */\n    public int getGeolocLabelMaxLength() throws RcsGenericException {\n        try {\n            return mIConfig.getGeolocLabelMaxLength();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Get geoloc expiration time\n     * \n     * @return int Time in milliseconds\n     * @throws RcsGenericException\n     */\n    public long getGeolocExpirationTime() throws RcsGenericException {\n        try {\n            return mIConfig.getGeolocExpirationTime();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the parameter that controls whether to respond or not to display reports when requested\n     * by the remote.<br>\n     * Applicable to one to one chat messages.\n     * \n     * @param enable true to set respond to display reports\n     * @throws RcsGenericException\n     */\n    public void setRespondToDisplayReports(boolean enable) throws RcsGenericException {\n        try {\n            mIConfig.setRespondToDisplayReports(enable);\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/GroupChat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsUnsupportedOperationException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.SparseArray;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Group chat\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GroupChat {\n    /**\n     * Group chat state\n     */\n    public enum State {\n\n        /**\n         * Chat invitation received\n         */\n        INVITED(0),\n\n        /**\n         * Chat invitation sent\n         */\n        INITIATING(1),\n\n        /**\n         * Chat is started\n         */\n        STARTED(2),\n\n        /**\n         * Chat has been aborted\n         */\n        ABORTED(3),\n\n        /**\n         * Chat has failed\n         */\n        FAILED(4),\n\n        /**\n         * Chat has been accepted and is in the process of becoming started.\n         */\n        ACCEPTING(5),\n\n        /**\n         * Chat invitation was rejected.\n         */\n        REJECTED(6);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State state : State.values()) {\n                mValueToEnum.put(state.toInt(), state);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to State instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a State instance for the specified integer value.\n         * \n         * @param value the value associated to the state\n         * @return instance\n         */\n        public static State valueOf(int value) {\n            State state = mValueToEnum.get(value);\n            if (state != null) {\n                return state;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n    }\n\n    /**\n     * Group chat participant status\n     */\n    public enum ParticipantStatus {\n        /**\n         * Invite can not be sent, instead it has been queued\n         */\n        INVITE_QUEUED(0),\n        /**\n         * Participant is about to be invited\n         */\n        INVITING(1),\n        /**\n         * Participant is invited\n         */\n        INVITED(2),\n        /**\n         * Participant is connected\n         */\n        CONNECTED(3),\n        /**\n         * Participant disconnected\n         */\n        DISCONNECTED(4),\n        /**\n         * Participant has departed\n         */\n        DEPARTED(5),\n        /**\n         * Participant status is failed\n         */\n        FAILED(6),\n        /**\n         * Participant declined invitation\n         */\n        DECLINED(7),\n        /**\n         * Participant invitation has timed-out\n         */\n        TIMEOUT(8);\n\n        private final int mValue;\n\n        private static SparseArray<ParticipantStatus> mValueToEnum = new SparseArray<>();\n        static {\n            for (ParticipantStatus status : ParticipantStatus.values()) {\n                mValueToEnum.put(status.toInt(), status);\n            }\n        }\n\n        ParticipantStatus(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static ParticipantStatus valueOf(int value) {\n            ParticipantStatus status = mValueToEnum.get(value);\n            if (status != null) {\n                return status;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + ParticipantStatus.class.getName() + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Group chat state reason code\n     */\n    public enum ReasonCode {\n\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * Group chat is aborted by local user.\n         */\n        ABORTED_BY_USER(1),\n\n        /**\n         * Group chat is aborted by remote user.\n         */\n        ABORTED_BY_REMOTE(2),\n\n        /**\n         * Group chat is aborted by inactivity.\n         */\n        ABORTED_BY_INACTIVITY(3),\n\n        /**\n         * Group chat is rejected because already taken by the secondary device.\n         */\n        REJECTED_BY_SECONDARY_DEVICE(4),\n\n        /**\n         * Group chat invitation was rejected as it was detected as spam.\n         */\n        REJECTED_SPAM(5),\n\n        /**\n         * Group chat invitation was rejected due to max number of chats open already.\n         */\n        REJECTED_MAX_CHATS(6),\n\n        /**\n         * Group chat invitation was rejected by remote.\n         */\n        REJECTED_BY_REMOTE(7),\n\n        /**\n         * Group chat invitation was rejected by timeout.\n         */\n        REJECTED_BY_TIMEOUT(8),\n\n        /**\n         * Group chat invitation was rejected by system.\n         */\n        REJECTED_BY_SYSTEM(9),\n\n        /**\n         * Group chat initiation failed.\n         */\n        FAILED_INITIATION(10);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode reasonCode : ReasonCode.values()) {\n                mValueToEnum.put(reasonCode.toInt(), reasonCode);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Gets integer value associated to ReasonCode instance\n         * \n         * @return value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a ReasonCode instance for the specified integer value.\n         * \n         * @param value the value associated to the reason code\n         * @return instance\n         */\n        public static ReasonCode valueOf(int value) {\n            ReasonCode reasonCode = mValueToEnum.get(value);\n            if (reasonCode != null) {\n                return reasonCode;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Group chat interface\n     */\n    private final IGroupChat mGroupChatInf;\n\n    /**\n     * Constructor\n     * \n     * @param chatIntf Group chat interface\n     */\n    /* package private */GroupChat(IGroupChat chatIntf) {\n        mGroupChatInf = chatIntf;\n    }\n\n    /**\n     * @throws RcsGenericException Returns the chat ID\n     * @return chat Id\n     */\n    public String getChatId() throws RcsGenericException {\n        try {\n            return mGroupChatInf.getChatId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the group chat\n     * \n     * @return Direction\n     * @see Direction\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Direction getDirection() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Direction.valueOf(mGroupChatInf.getDirection());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the group chat\n     * \n     * @return State\n     * @see State\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public State getState() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return State.valueOf(mGroupChatInf.getState());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the group chat\n     * \n     * @return ReasonCode\n     * @see ReasonCode\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ReasonCode getReasonCode() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mGroupChatInf.getReasonCode());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact\n     * \n     * @return ContactId\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mGroupChatInf.getRemoteContact();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the subject of the group chat\n     * \n     * @return String\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getSubject() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mGroupChatInf.getSubject();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the map of participants and associated status .\n     * \n     * @return Map&lt;ContactId, ParticipantStatus&gt;\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    /*\n     * Unchecked cast must be suppressed since AIDL provides a raw Map type that must be cast.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Map<ContactId, ParticipantStatus> getParticipants()\n            throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            Map<ContactId, Integer> apiParticipants = mGroupChatInf.getParticipants();\n            Map<ContactId, ParticipantStatus> participants = new HashMap<>();\n\n            for (Map.Entry<ContactId, Integer> apiParticipant : apiParticipants.entrySet()) {\n                participants.put(apiParticipant.getKey(),\n                        ParticipantStatus.valueOf(apiParticipant.getValue()));\n            }\n\n            return participants;\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the group chat invitation was initiated for outgoing\n     * group chats or the local timestamp of when the group chat invitation was received for\n     * incoming group chat invitations.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestamp() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mGroupChatInf.getTimestamp();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to send messages in the group chat right now, else returns\n     * false.\n     * \n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToSendMessage() throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return mGroupChatInf.isAllowedToSendMessage();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a text message to the group\n     * \n     * @param text Message\n     * @return ChatMessage\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ChatMessage sendMessage(String text) throws RcsPermissionDeniedException,\n            RcsPersistentStorageException, RcsGenericException {\n        try {\n            return new ChatMessage(mGroupChatInf.sendMessage(text));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a geoloc message\n     * \n     * @param geoloc Geoloc info\n     * @return ChatMessage\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ChatMessage sendMessage(Geoloc geoloc) throws RcsPermissionDeniedException,\n            RcsPersistentStorageException, RcsGenericException {\n        try {\n            return new ChatMessage(mGroupChatInf.sendMessage2(geoloc));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * This method should be called to notify the stack of if there is ongoing composing or not in\n     * this GroupChat. If there is an ongoing chat session established with the remote side\n     * corresponding to this GroupChat this means that a call to this method will send the\n     * 'is-composing' event or the 'is-not-composing' event to the remote side. However since this\n     * method can be called at any time even when there is no chat session established with the\n     * remote side or when the stack is not even connected to the IMS server then the stack\n     * implementation needs to hold the last given information (i.e. composing or not composing) in\n     * memory and then send it later when there is an established session available to relay this\n     * information on. Note: if this GroupChat corresponds to an incoming pending chat session and\n     * the parameter IM SESSION START is 1 then the session is accepted before sending the\n     * 'is-composing' event.\n     * \n     * @param ongoing True is client application is composing\n     * @throws RcsGenericException\n     */\n    public void setComposingStatus(boolean ongoing) throws RcsGenericException {\n        try {\n            mGroupChatInf.setComposingStatus(ongoing);\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to invite additional participants to the group chat right now,\n     * else returns false.\n     * \n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToInviteParticipants() throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return mGroupChatInf.isAllowedToInviteParticipants();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to invite the specified participant to the group chat right\n     * now, else returns false.\n     * \n     * @param participant the contact ID\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToInviteParticipant(ContactId participant)\n            throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mGroupChatInf.isAllowedToInviteParticipant(participant);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Invite additional participants to this group chat.\n     * \n     * @param participants List of participants\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void inviteParticipants(Set<ContactId> participants)\n            throws RcsPermissionDeniedException, RcsPersistentStorageException, RcsGenericException {\n        try {\n            mGroupChatInf.inviteParticipants(new ArrayList<>(participants));\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsUnsupportedOperationException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the max number of participants in the group chat. This limit is read during the\n     * conference event subscription and overrides the provisioning parameter.\n     * \n     * @return int\n     * @throws RcsGenericException\n     */\n    public int getMaxParticipants() throws RcsGenericException {\n        try {\n            return mGroupChatInf.getMaxParticipants();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to leave this group chat.\n     * \n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToLeave() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mGroupChatInf.isAllowedToLeave();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Leaves a group chat willingly and permanently. The group chat will continue between other\n     * participants if there are enough participants.\n     * \n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void leave() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            mGroupChatInf.leave();\n        } catch (Exception e) {\n            RcsUnsupportedOperationException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * open the chat conversation.<br>\n     * Note: if it is an incoming pending chat session and the parameter IM SESSION START is 0 then\n     * the session is accepted now.\n     * \n     * @throws RcsGenericException\n     */\n    public void openChat() throws RcsGenericException {\n        try {\n            mGroupChatInf.openChat();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/GroupChatIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\n/**\n * Intent for group chat conversation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GroupChatIntent {\n    /**\n     * Broadcast action: a new group chat invitation has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_CHAT_ID} containing the unique ID of the chat conversation.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT\";\n\n    /**\n     * Broadcast action: a new group chat message has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_MESSAGE_ID} containing the message ID of chat message.\n     * </ul>\n     */\n    public final static String ACTION_NEW_GROUP_CHAT_MESSAGE = \"com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT_MESSAGE\";\n\n    /**\n     * Unique ID of the chat conversation\n     */\n    public final static String EXTRA_CHAT_ID = \"chatId\";\n\n    /**\n     * MIME-type of received message\n     */\n    public final static String EXTRA_MIME_TYPE = \"mimeType\";\n\n    /**\n     * Message ID of received message\n     */\n    public final static String EXTRA_MESSAGE_ID = \"messageId\";\n\n    private GroupChatIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/GroupChatListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.chat.GroupChat.State;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport java.util.Set;\n\n/**\n * Group chat event listener\n *\n * @author Jean-Marc AUFFRET\n */\npublic abstract class GroupChatListener {\n    /**\n     * Callback called when the group chat state is changed\n     *\n     * @param chatId chat id\n     * @param state group chat state\n     * @param reasonCode reason code\n     */\n    public abstract void onStateChanged(String chatId, State state, GroupChat.ReasonCode reasonCode);\n\n    /**\n     * Callback called when an Is-composing event has been received. If the remote is typing a\n     * message the status is set to true, else it is false.\n     *\n     * @param chatId the chat ID\n     * @param contact the contact ID\n     * @param status Is-composing status\n     */\n    public abstract void onComposingEvent(String chatId, ContactId contact, boolean status);\n\n    /**\n     * Callback called when a message status/reasonCode is changed.\n     *\n     * @param chatId chat id\n     * @param mimeType MIME-type\n     * @param msgId message id\n     * @param status message status\n     * @param reasonCode reason code\n     */\n    public abstract void onMessageStatusChanged(String chatId, String mimeType, String msgId,\n            Status status, ReasonCode reasonCode);\n\n    /**\n     * Callback called when a group delivery info status/reasonCode was changed for a single\n     * recipient to a group message.\n     *\n     * @param chatId chat id\n     * @param contact contact\n     * @param mimeType MIME-type\n     * @param msgId message id\n     * @param status message status\n     * @param reasonCode status reason code\n     */\n    public abstract void onMessageGroupDeliveryInfoChanged(String chatId, ContactId contact,\n            String mimeType, String msgId, GroupDeliveryInfo.Status status,\n            GroupDeliveryInfo.ReasonCode reasonCode);\n\n    /**\n     * Callback called when a participant status has been changed in a group chat.\n     *\n     * @param chatId chat id\n     * @param contact contact id\n     * @param status participant status\n     */\n    public abstract void onParticipantStatusChanged(String chatId, ContactId contact,\n            ParticipantStatus status);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several group\n     * chats was deleted specified by the chatIds parameter.\n     *\n     * @param chatIds chat ids of those deleted chats\n     */\n    public abstract void onDeleted(Set<String> chatIds);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several group\n     * chat messages was deleted specified by the msgIds parameter corresponding to a specific group\n     * chat.\n     *\n     * @param chatId chat id of those deleted messages\n     * @param msgIds message ids of those deleted messages\n     */\n    public abstract void onMessagesDeleted(String chatId, Set<String> msgIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/GroupChatListenerImpl.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.chat.GroupChat.ParticipantStatus;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Group chat event listener implementation\n *\n * @hide\n */\npublic class GroupChatListenerImpl extends IGroupChatListener.Stub {\n\n    private final GroupChatListener mListener;\n\n    private final static String LOG_TAG = GroupChatListenerImpl.class.getName();\n\n    GroupChatListenerImpl(GroupChatListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onStateChanged(String chatId, int state, int reasonCode) {\n        GroupChat.State rcsState;\n        GroupChat.ReasonCode rcsReasonCode;\n        try {\n            rcsState = GroupChat.State.valueOf(state);\n            rcsReasonCode = GroupChat.ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(chatId, rcsState, rcsReasonCode);\n    }\n\n    @Override\n    public void onComposingEvent(String chatId, ContactId contact, boolean status)\n            throws RemoteException {\n        mListener.onComposingEvent(chatId, contact, status);\n    }\n\n    @Override\n    public void onMessageStatusChanged(String chatId, String mimeType, String msgId, int status,\n            int reasonCode) {\n        Status rcsStatus;\n        Content.ReasonCode rcsReasonCode;\n        try {\n            rcsStatus = Status.valueOf(status);\n            rcsReasonCode = Content.ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onMessageStatusChanged(chatId, mimeType, msgId, rcsStatus, rcsReasonCode);\n    }\n\n    @Override\n    public void onMessageGroupDeliveryInfoChanged(String chatId, ContactId contact,\n            String mimeType, String msgId, int status, int reasonCode) {\n        GroupDeliveryInfo.Status rcsStatus;\n        GroupDeliveryInfo.ReasonCode rcsReasonCode;\n        try {\n            rcsStatus = GroupDeliveryInfo.Status.valueOf(status);\n            rcsReasonCode = GroupDeliveryInfo.ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onMessageGroupDeliveryInfoChanged(chatId, contact, mimeType, msgId, rcsStatus,\n                rcsReasonCode);\n    }\n\n    @Override\n    public void onParticipantStatusChanged(String chatId, ContactId contact, int status) {\n        try {\n            mListener\n                    .onParticipantStatusChanged(chatId, contact, ParticipantStatus.valueOf(status));\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown status not part of standard coming from stack which a client\n             * application can not handle since it is built only to handle the possible enum values\n             * documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n        }\n    }\n\n    /**\n     * This feature to be implemented in CR005\n     */\n    @Override\n    public void onDeleted(List<String> chatIds) throws RemoteException {\n        mListener.onDeleted(new HashSet<>(chatIds));\n    }\n\n    /**\n     * This feature to be implemented in CR005\n     */\n    @Override\n    public void onMessagesDeleted(String chatId, List<String> msgIds) throws RemoteException {\n        mListener.onMessagesDeleted(chatId, new HashSet<>(msgIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/OneToOneChat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * One-to-One Chat\n * \n * @author Jean-Marc AUFFRET\n */\npublic class OneToOneChat {\n\n    /**\n     * Chat interface\n     */\n    private final IOneToOneChat mOneToOneChatInf;\n\n    /**\n     * Constructor\n     * \n     * @param chatIntf Chat interface\n     */\n    /* package private */OneToOneChat(IOneToOneChat chatIntf) {\n        mOneToOneChatInf = chatIntf;\n    }\n\n    /**\n     * Returns the remote contact\n     * \n     * @return ContactId\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsGenericException {\n        try {\n            return mOneToOneChatInf.getRemoteContact();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to send messages in this one to one chat right now, else\n     * return false.\n     * \n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToSendMessage() throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return mOneToOneChatInf.isAllowedToSendMessage();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a chat message\n     * \n     * @param message Message\n     * @return ChatMessage\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ChatMessage sendMessage(String message) throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return new ChatMessage(mOneToOneChatInf.sendMessage(message));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a geoloc message\n     * \n     * @param geoloc Geoloc info\n     * @return ChatMessage\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ChatMessage sendMessage(Geoloc geoloc) throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return new ChatMessage(mOneToOneChatInf.sendMessage2(geoloc));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * This method should be called to notify the stack of if there is ongoing composing or not in\n     * this OneToOneChat. If there is an ongoing chat session established with the remote side\n     * corresponding to this OneToOneChat this means that a call to this method will send the\n     * 'is-composing' event or the 'is-not-composing' event to the remote side. However since this\n     * method can be called at any time even when there is no chat session established with the\n     * remote side or when the stack is not even connected to the IMS server then the stack\n     * implementation needs to hold the last given information (i.e. composing or not composing) in\n     * memory and then send it later when there is an established session available to relay this\n     * information on. Note: if this OneToOneChat corresponds to an incoming pending chat session\n     * and the parameter IM SESSION START is 1 then the session is accepted before sending the\n     * 'is-composing' event.\n     * \n     * @param ongoing True is client application is composing\n     * @throws RcsGenericException\n     */\n    public void setComposingStatus(boolean ongoing) throws RcsGenericException {\n        try {\n            mOneToOneChatInf.setComposingStatus(ongoing);\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * open the chat conversation.<br>\n     * Note: if it is an incoming pending chat session and the parameter IM SESSION START is 0 then\n     * the session is accepted now.\n     * \n     * @throws RcsGenericException\n     */\n    public void openChat() throws RcsGenericException {\n        try {\n            mOneToOneChatInf.openChat();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Resend a message which previously failed.\n     * \n     * @param msgId the message ID\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void resendMessage(String msgId) throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            mOneToOneChatInf.resendMessage(msgId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/OneToOneChatIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\n/**\n * Intent for one-to-one chat conversation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class OneToOneChatIntent {\n\n    /**\n     * Broadcast action: a new chat message has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_MESSAGE_ID} containing the message ID of chat message.\n     * <li> {@link #EXTRA_MIME_TYPE} containing the MIME-type of chat message.\n     * </ul>\n     */\n    public final static String ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE = \"com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE\";\n\n    /**\n     * MIME-type of received message\n     */\n    public final static String EXTRA_MIME_TYPE = \"mimeType\";\n\n    /**\n     * Message ID of received message\n     */\n    public final static String EXTRA_MESSAGE_ID = \"messageId\";\n\n    /**\n     * Broadcast action: message delivery expired.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_CONTACT} containing the contact ID of remote contact.\n     * <li> {@link #EXTRA_MESSAGE_ID} containing the message ID of the chat message that triggered\n     * the timeout.\n     * </ul>\n     */\n    public final static String ACTION_MESSAGE_DELIVERY_EXPIRED = \"com.gsma.services.rcs.chat.action.MESSAGE_DELIVERY_EXPIRED\";\n\n    /**\n     * ContactId of remote contact\n     */\n    public final static String EXTRA_CONTACT = \"contact\";\n\n    private OneToOneChatIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/OneToOneChatListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport java.util.Set;\n\n/**\n * One-to-One Chat event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class OneToOneChatListener {\n\n    /**\n     * Callback called when a message status/reasonCode is changed.\n     * \n     * @param contact Contact ID\n     * @param mimeType MIME-type of message\n     * @param msgId Message Id\n     * @param status Status\n     * @param reasonCode Reason code\n     */\n    public abstract void onMessageStatusChanged(ContactId contact, String mimeType, String msgId,\n            Status status, ReasonCode reasonCode);\n\n    /**\n     * Callback called when an Is-composing event has been received. If the remote is typing a\n     * message the status is set to true, else it is false.\n     * \n     * @param contact Contact ID\n     * @param status Is-composing status\n     */\n    public abstract void onComposingEvent(ContactId contact, boolean status);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several one to\n     * one chat messages was deleted specified by the msgIds parameter corresponding to a specific\n     * contact.\n     *\n     * @param contact contact id of those deleted messages\n     * @param msgIds message ids of those deleted messages\n     */\n    public abstract void onMessagesDeleted(ContactId contact, Set<String> msgIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/OneToOneChatListenerImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.chat;\n\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode;\nimport com.gsma.services.rcs.chat.ChatLog.Message.Content.Status;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Chat event listener implementation\n * \n * @hide\n */\npublic class OneToOneChatListenerImpl extends IOneToOneChatListener.Stub {\n\n    private final OneToOneChatListener mListener;\n\n    private final static String LOG_TAG = OneToOneChatListenerImpl.class.getSimpleName();\n\n    OneToOneChatListenerImpl(OneToOneChatListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onMessageStatusChanged(ContactId contact, String mimeType, String msgId,\n            int status, int reasonCode) {\n        Status rcsStatus;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsStatus = Status.valueOf(status);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onMessageStatusChanged(contact, mimeType, msgId, rcsStatus, rcsReasonCode);\n    }\n\n    @Override\n    public void onComposingEvent(ContactId contact, boolean status) throws RemoteException {\n        mListener.onComposingEvent(contact, status);\n    }\n\n    /**\n     * This feature to be implemented in CR005\n     */\n    @Override\n    public void onMessagesDeleted(ContactId contact, List<String> msgIds) throws RemoteException {\n        mListener.onMessagesDeleted(contact, new HashSet<>(msgIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/chat/package-info.java",
    "content": "/**\n * This API exposes all functionality for single chat and group chat services.\n * <p>\n */\n\npackage com.gsma.services.rcs.chat;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/contact/ContactId.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.contact;\n\nimport java.io.Serializable;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * ContactId class is defined to handle phone numbers instead of string.\n * \n * @author YPLO6403\n */\npublic class ContactId implements Parcelable, Serializable {\n\n    /**\n     * \n     */\n    private static final long serialVersionUID = 1L;\n\n    /**\n     * The ContactId formatted in the international representation of the phone number\n     * \"<CC><NDCCS><SN>\" <br>\n     * with:\n     * <ul>\n     * <li>- CC : the country code with a leading '+' character\n     * <li>- NCSDC : the national destination code\n     * <li>- SN: the subscriber number\n     * </ul>\n     * All these codes CC, NDCS, SN are digits.\n     * <p>\n     * If this number needs to be displayed in the UI with some particular UI formatting, it is in\n     * the scope of UI code to format that. This class will never hold specific UI formatted numbers\n     * since they need to be unique.\n     */\n    private String mContactId;\n\n    /**\n     * Constructor\n     * \n     * @param contact the contact number (valid characters are digits, space, '-', leading '+')\n     */\n    /* package private */ContactId(String contact) {\n        mContactId = contact;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     * @hide\n     */\n    public ContactId(Parcel source) {\n        mContactId = source.readString();\n    }\n\n    @Override\n    public String toString() {\n        return mContactId;\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation\n     * \n     * @return Integer\n     * @hide\n     */\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object\n     * \n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mContactId);\n    }\n\n    /**\n     * Parcelable creator\n     * \n     * @hide\n     */\n    public static final Parcelable.Creator<ContactId> CREATOR = new Parcelable.Creator<ContactId>() {\n        public ContactId createFromParcel(Parcel source) {\n            return new ContactId(source);\n        }\n\n        public ContactId[] newArray(int size) {\n            return new ContactId[size];\n        }\n    };\n\n    /**\n     * hashCode\n     * \n     * @hide\n     */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((mContactId == null) ? 0 : mContactId.hashCode());\n        return result;\n    }\n\n    /**\n     * equals\n     * \n     * @hide\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ContactId other = (ContactId) obj;\n        if (mContactId == null) {\n            if (other.mContactId != null) {\n                return false;\n            }\n        } else if (!mContactId.equals(other.mContactId)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/contact/ContactProvider.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.contact;\n\n/**\n * Contact provider for RCS info integrated in the native address book\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ContactProvider {\n    /**\n     * RCS phone number\n     */\n    public final static String MIME_TYPE_PHONE_NUMBER = \"vnd.android.cursor.item/com.gsma.services.rcs.number\";\n\n    /**\n     * Registration state\n     */\n    public final static String MIME_TYPE_REGISTRATION_STATE = \"vnd.android.cursor.item/com.gsma.services.rcs.registration-state\";\n\n    /**\n     * Blocking contact\n     */\n    public final static String MIME_TYPE_BLOCKING_STATE = \"vnd.android.cursor.item/com.gsma.services.rcs.blocking-state\";\n\n    /**\n     * Image sharing capability support\n     */\n    public final static String MIME_TYPE_IMAGE_SHARE = \"vnd.android.cursor.item/com.gsma.services.rcs.image-share\";\n\n    /**\n     * Video sharing capability support\n     */\n    public final static String MIME_TYPE_VIDEO_SHARE = \"vnd.android.cursor.item/com.gsma.services.rcs.video-share\";\n\n    /**\n     * IM/Chat capability support\n     */\n    public final static String MIME_TYPE_IM_SESSION = \"vnd.android.cursor.item/com.gsma.services.rcs.im-session\";\n\n    /**\n     * File transfer capability support\n     */\n    public final static String MIME_TYPE_FILE_TRANSFER = \"vnd.android.cursor.item/com.gsma.services.rcs.file-transfer\";\n\n    /**\n     * Geolocation push capability support\n     */\n    public final static String MIME_TYPE_GEOLOC_PUSH = \"vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push\";\n\n    /**\n     * Mime type for the time stamp when the blocking was activated\n     */\n    public final static String MIME_TYPE_BLOCKING_TIMESTAMP = \"vnd.android.cursor.item/com.gsma.services.rcs.blocking-timestamp\";\n\n    /**\n     * IP voice call capability support\n     */\n    // public final static String MIME_TYPE_IP_VOICE_CALL =\n    // \"vnd.android.cursor.item/com.gsma.services.rcs.ip-voice-call\";\n\n    /**\n     * IP video call capability support\n     */\n    // public final static String MIME_TYPE_IP_VIDEO_CALL =\n    // \"vnd.android.cursor.item/com.gsma.services.rcs.ip-video-call\";\n\n    /**\n     * RCS extensions supported\n     */\n    public final static String MIME_TYPE_EXTENSIONS = \"vnd.android.cursor.item/com.gsma.services.rcs.extensions\";\n\n    private ContactProvider() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/contact/ContactService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.contact;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Contact service offers additional methods to manage RCS info in the local address book. The\n * parameter contact in the API supports the following formats: MSISDN in national or international\n * format, SIP address, SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class ContactService extends RcsService {\n    /**\n     * API\n     */\n    private IContactService mApi;\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public ContactService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the contact service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the contact service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IContactService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IContactService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IContactService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Returns the rcs contact infos from its contact ID (i.e. MSISDN)\n     * \n     * @param contact Contact ID\n     * @return RcsContact\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     * @see RcsContact\n     */\n    public RcsContact getRcsContact(ContactId contact) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.getRcsContact(contact);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of RCS contacts\n     * \n     * @return Set&lt;RcsContact&gt; List of contacts\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     * @see RcsContact\n     */\n    public Set<RcsContact> getRcsContacts() throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new HashSet<>(mApi.getRcsContacts());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of online contacts (i.e. registered)\n     *\n     * @deprecated Use {@link #getRcsContacts()} instead.\n     *\n     * @return Set&lt;RcsContact&gt; List of contacts\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     * @see RcsContact\n     */\n    @Deprecated\n    public Set<RcsContact> getRcsContactsOnline() throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new HashSet<>(mApi.getRcsContactsOnline());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of contacts supporting a given extension or service ID\n     *\n     *  @deprecated Use {@link #getRcsContacts()} instead.\n     *\n     * @param serviceId Service ID\n     * @return Set&lt;RcsContact&gt; List of contacts\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     * @see RcsContact\n     */\n    @Deprecated\n    public Set<RcsContact> getRcsContactsSupporting(String serviceId)\n            throws RcsPersistentStorageException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new HashSet<>(mApi.getRcsContactsSupporting(serviceId));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Block a contact. Any communication from the given contact will be blocked and redirected to\n     * the corresponding spambox.\n     * \n     * @param contact Contact ID\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void blockContact(ContactId contact) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.blockContact(contact);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Unblock a contact\n     * \n     * @param contact Contact ID\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void unblockContact(ContactId contact) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.unblockContact(contact);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/contact/ContactUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * \n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.contact;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\n\nimport android.content.Context;\nimport android.content.res.AssetFileDescriptor;\nimport android.content.res.Configuration;\nimport android.database.Cursor;\nimport android.database.SQLException;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.provider.ContactsContract;\nimport android.text.TextUtils;\nimport android.util.SparseArray;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Utility class for validation and unique formatting of phone numbers\n * \n * @author YPLO6403\n */\npublic class ContactUtil {\n\n    /**\n     * Singleton of ContactUtil\n     */\n    private static volatile ContactUtil sInstance;\n\n    /**\n     * The country code of the device\n     */\n    private String mCountryCode;\n\n    /**\n     * The country area code\n     */\n    private String mCountryAreaCode;\n\n    /**\n     * Application context\n     */\n    private final Context mCtx;\n\n    /**\n     * Regular expression to validate phone numbers\n     */\n    private final static String REGEXP_CONTACT = \"^00\\\\d{1,15}$|^[+]?\\\\d{1,15}$|^\\\\d{1,15}$\";\n\n    /**\n     * Pattern to check contact\n     */\n    private final static Pattern PATTERN_CONTACT = Pattern.compile(REGEXP_CONTACT);\n\n    private final static String MSISDN_PREFIX_INTERNATIONAL = \"00\";\n\n    private final static String COUNTRY_CODE_PREFIX = \"+\";\n\n    /**\n     * Index of Country Code in the array\n     */\n    private static final int COUNTRY_CODE_IDX = 0;\n    /**\n     * Index of Country Area Code in the array\n     */\n    private static final int COUNTRY_AREA_CODE_IDX = 1;\n\n    private static final int MCC_UNDEFINED = 0;\n\n    /**\n     * A map between the ISO country code and an array of String containing first the County Code\n     * and secondly the Area Code.<br>\n     * Note 1 : the Area Code is optional (if it does not exist then it is null).<br>\n     * Note 2 : the Country Code is optional (if it does not exist then the string array is null).\n     */\n    // @formatter:off\n      \n    private static final SparseArray<String[]> sCountryCodes = new SparseArray<String[]> () {\n\n        {\n            {\n                put( 202 , new String[] {\"30\" }); // Greece\n                put( 204 , new String[] {\"31\" , \"0\" }); // Netherlands (Kingdom of the)\n                put( 206 , new String[] {\"32\" , \"0\" }); // Belgium\n                put( 208 , new String[] {\"33\" , \"0\" }); // France\n                put( 212 , new String[] {\"377\" }); // Monaco (Principality of)\n                put( 213 , new String[] {\"376\" }); // Andorra (Principality of)\n                put( 214 , new String[] {\"34\" }); // Spain\n                put( 216 , new String[] {\"36\" , \"06\" }); // Hungary (Republic of)\n                put( 218 , new String[] {\"387\" , \"0\" }); // Bosnia and Herzegovina\n                put( 219 , new String[] {\"385\" , \"0\" }); // Croatia (Republic of)\n                put( 220 , new String[] {\"381\" , \"0\" }); // Serbia and Montenegro\n                put( 222 , new String[] {\"39\" }); // Italy\n                put( 225 , new String[] {\"379\" }); // Vatican City State\n                put( 226 , new String[] {\"40\" , \"0\" }); // Romania\n                put( 228 , new String[] {\"41\" , \"0\" }); // Switzerland (Confederation of)\n                put( 230 , new String[] {\"420\" , \"0\" }); // Czech Republic\n                put( 231 , new String[] {\"421\" , \"0\" }); // Slovak Republic\n                put( 232 , new String[] {\"43\" , \"0\" }); // Austria\n                put( 234 , new String[] {\"44\" , \"0\" }); // United Kingdom of Great Britain and Northern Ireland\n                put( 235 , new String[] {\"44\" , \"0\" }); // United Kingdom of Great Britain and Northern Ireland\n                put( 238 , new String[] {\"45\" }); // Denmark\n                put( 240 , new String[] {\"46\" , \"0\" }); // Sweden\n                put( 242 , new String[] {\"47\" }); // Norway\n                put( 244 , new String[] {\"358\" , \"0\" }); // Finland\n                put( 246 , new String[] {\"370\" , \"8\" }); // Lithuania (Republic of)\n                put( 247 , new String[] {\"371\" }); // Latvia (Republic of)\n                put( 248 , new String[] {\"372\" }); // Estonia (Republic of)\n                put( 250 , new String[] {\"7\" , \"8\" }); // Russian Federation\n                put( 255 , new String[] {\"380\" , \"0\" }); // Ukraine\n                put( 257 , new String[] {\"375\" , \"8\" }); // Belarus (Republic of)\n                put( 259 , new String[] {\"373\" , \"0\" }); // Moldova (Republic of)\n                put( 260 , new String[] {\"48\" }); // Poland (Republic of)\n                put( 262 , new String[] {\"49\" , \"0\" }); // Germany (Federal Republic of)\n                put( 266 , new String[] {\"350\" }); // Gibraltar\n                put( 268 , new String[] {\"351\" }); // Portugal\n                put( 270 , new String[] {\"352\" }); // Luxembourg\n                put( 272 , new String[] {\"353\" , \"0\" }); // Ireland\n                put( 274 , new String[] {\"354\" }); // Iceland\n                put( 276 , new String[] {\"355\" , \"0\" }); // Albania (Republic of)\n                put( 278 , new String[] {\"356\" }); // Malta\n                put( 280 , new String[] {\"357\" }); // Cyprus (Republic of)\n                put( 282 , new String[] {\"955\" , \"8\" }); // Georgia\n                put( 283 , new String[] {\"374\" , \"0\" }); // Armenia (Republic of)\n                put( 284 , new String[] {\"359\" , \"0\" }); // Bulgaria (Republic of)\n                put( 286 , new String[] {\"90\" , \"0\" }); // Turkey\n                put( 288 , new String[] {\"298\" }); // Faroe Islands\n                put( 289 , new String[] {\"955\" , \"8\" }); // Abkhazia (Georgia)\n                put( 290 , new String[] {\"299\" }); // Greenland (Denmark)\n                put( 292 , new String[] {\"378\" }); // San Marino (Republic of)\n                put( 293 , new String[] {\"386\" }); // Slovenia (Republic of)\n                put( 294 , new String[] {\"389\" , \"0\" }); // The Former Yugoslav Republic of Macedonia\n                put( 295 , new String[] {\"423\" }); // Liechtenstein (Principality of)\n                put( 297 , new String[] {\"382\" , \"0\" }); // Montenegro (Republic of)\n                put( 302 , new String[] {\"1\" , \"1\" }); // Canada\n                put( 308 , new String[] {\"508\" }); // Saint Pierre and Miquelon (Collectivite territoriale de la Republique francaise)\n                put( 310 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 311 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 312 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 313 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 314 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 315 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 316 , new String[] {\"1\" , \"1\" }); // United States of America\n                put( 330 , new String[] {\"1-787\" , \"1\" }); // Puerto Rico\n                put( 332 , new String[] {\"1-340\" , \"1\" }); // United States Virgin Islands\n                put( 334 , new String[] {\"52\" , \"01\" }); // Mexico\n                put( 338 , new String[] {\"1-876\" , \"1\" }); // Jamaica\n                put( 340 , new String[] {\"590\" , \"0\" }); // Guadeloupe (French Department of)\n                put( 342 , new String[] {\"1-246\" , \"1\" }); // Barbados\n                put( 344 , new String[] {\"1-268\" , \"1\" }); // Antigua and Barbuda\n                put( 346 , new String[] {\"1-345\" , \"1\" }); // Cayman Islands\n                put( 348 , new String[] {\"1-284\" , \"1\" }); // British Virgin Islands\n                put( 350 , new String[] {\"1-441\" , \"1\" }); // Bermuda\n                put( 352 , new String[] {\"1-473\" , \"1\" }); // Grenada\n                put( 354 , new String[] {\"1-664\" , \"1\" }); // Montserrat\n                put( 356 , new String[] {\"1-869\" , \"1\" }); // Saint Kitts and Nevis\n                put( 358 , new String[] {\"1-758\" , \"1\" }); // Saint Lucia\n                put( 360 , new String[] {\"1-784\" , \"1\" }); // Saint Vincent and the Grenadines\n                put( 362 , new String[] {\"1-264\" , \"1\" }); // Netherlands Antilles\n                put( 363 , new String[] {\"297\" }); // Aruba\n                put( 364 , new String[] {\"1-242\" , \"1\" }); // Bahamas (Commonwealth of the)\n                put( 365 , new String[] {\"1-264\" , \"1\" }); // Anguilla\n                put( 366 , new String[] {\"1-767\" , \"1\" }); // Dominica (Commonwealth of)\n                put( 368 , new String[] {\"53\" , \"0\" }); // Cuba\n                put( 370 , new String[] {\"1-809\" , \"1\" }); // Dominican Republic\n                put( 372 , new String[] {\"509\" }); // Haiti (Republic of)\n                put( 374 , new String[] {\"1-868\" , \"1\" }); // Trinidad and Tobago\n                put( 376 , new String[] {\"1-649\" , \"1\" }); // Turks and Caicos Islands\n                put( 400 , new String[] {\"994\" , \"0\" }); // Azerbaijani Republic\n                put( 401 , new String[] {\"7-7\" , \"8\" }); // Kazakhstan (Republic of)\n                put( 402 , new String[] {\"975\" }); // Bhutan (Kingdom of)\n                put( 404 , new String[] {\"91\" , \"0\" }); // India (Republic of)\n                put( 405 , new String[] {\"91\" , \"0\" }); // India (Republic of)\n                put( 410 , new String[] {\"92\" , \"0\" }); // Pakistan (Islamic Republic of)\n                put( 412 , new String[] {\"93\" , \"0\" }); // Afghanistan\n                put( 413 , new String[] {\"94\" , \"0\" }); // Sri Lanka (Democratic Socialist Republic of)\n                put( 414 , new String[] {\"95\" }); // Myanmar (Union of)\n                put( 415 , new String[] {\"961\" , \"0\" }); // Lebanon\n                put( 416 , new String[] {\"962\" , \"0\" }); // Jordan (Hashemite Kingdom of)\n                put( 417 , new String[] {\"963\" , \"0\" }); // Syrian Arab Republic\n                put( 418 , new String[] {\"964\" }); // Iraq (Republic of)\n                put( 419 , new String[] {\"965\" }); // Kuwait (State of)\n                put( 420 , new String[] {\"966\" , \"0\" }); // Saudi Arabia (Kingdom of)\n                put( 421 , new String[] {\"967\" , \"0\" }); // Yemen (Republic of)\n                put( 422 , new String[] {\"968\" }); // Oman (Sultanate of)\n                put( 424 , new String[] {\"971\" , \"0\" }); // United Arab Emirates\n                put( 425 , new String[] {\"972\" , \"0\" }); // Israel (State of)\n                put( 426 , new String[] {\"973\" }); // Bahrain (Kingdom of)\n                put( 427 , new String[] {\"974\" }); // Qatar (State of)\n                put( 428 , new String[] {\"976\" , \"0\" }); // Mongolia\n                put( 429 , new String[] {\"977\" , \"0\" }); // Nepal\n                put( 430 , new String[] {\"971\" , \"0\" }); // United Arab Emirates\n                put( 431 , new String[] {\"971\" , \"0\" }); // United Arab Emirates\n                put( 432 , new String[] {\"98\" , \"0\" }); // Iran (Islamic Republic of)\n                put( 434 , new String[] {\"998\" , \"8\" }); // Uzbekistan (Republic of)\n                put( 436 , new String[] {\"992\" , \"8\" }); // Tajikistan (Republic of)\n                put( 437 , new String[] {\"996\" , \"0\" }); // Kyrgyz Republic\n                put( 438 , new String[] {\"993\" , \"8\" }); // Turkmenistan\n                put( 440 , new String[] {\"81\" , \"0\" }); // Japan\n                put( 441 , new String[] {\"81\" , \"0\" }); // Japan\n                put( 450 , new String[] {\"82\" , \"0\" }); // Korea (Republic of)\n                put( 452 , new String[] {\"84\" , \"0\" }); // Viet Nam (Socialist Republic of)\n                put( 454 , new String[] {\"852\" }); // \"Hong Kong, China\"\n                put( 455 , new String[] {\"853\" }); // \"Macao, China\"\n                put( 456 , new String[] {\"855\" , \"0\" }); // Cambodia (Kingdom of)\n                put( 457 , new String[] {\"856\" }); // Lao People's Democratic Republic\n                put( 460 , new String[] {\"86\" , \"0\" }); // China (People's Republic of)\n                put( 461 , new String[] {\"86\" , \"0\" }); // China (People's Republic of)\n                put( 466 , new String[] {\"886\" , \"0\" }); // \"Taiwan, China\"\n                put( 467 , new String[] {\"850\" }); // Democratic People's Republic of Korea\n                put( 470 , new String[] {\"880\" , \"0\" }); // Bangladesh (People's Republic of)\n                put( 472 , new String[] {\"960\" }); // Maldives (Republic of)\n                put( 502 , new String[] {\"60\" , \"0\" }); // Malaysia\n                put( 505 , new String[] {\"61\" , \"0\" }); // Australia\n                put( 510 , new String[] {\"62\" , \"0\" }); // Indonesia (Republic of)\n                put( 514 , new String[] {\"670\" }); // Democratic Republic of Timor-Leste\n                put( 515 , new String[] {\"63\" , \"0\" }); // Philippines (Republic of the)\n                put( 520 , new String[] {\"66\" , \"0\" }); // Thailand\n                put( 525 , new String[] {\"65\" }); // Singapore (Republic of)\n                put( 528 , new String[] {\"673\" }); // Brunei Darussalam\n                put( 530 , new String[] {\"64\" , \"0\" }); // New Zealand\n                put( 534 , new String[] {\"1-670\" , \"1\" }); // Northern Mariana Islands (Commonwealth of the)\n                put( 535 , new String[] {\"1-671\" , \"1\" }); // Guam\n                put( 536 , new String[] {\"674\" }); // Nauru (Republic of)\n                put( 537 , new String[] {\"675\" }); // Papua New Guinea\n                put( 539 , new String[] {\"676\" }); // Tonga (Kingdom of)\n                put( 540 , new String[] {\"677\" }); // Solomon Islands\n                put( 541 , new String[] {\"678\" }); // Vanuatu (Republic of)\n                put( 542 , new String[] {\"679\" }); // Fiji (Republic of)\n                put( 543 , new String[] {\"681\" }); // Wallis and Futuna (Territoire franais d'outre-mer)\n                put( 544 , new String[] {\"1-684\" , \"1\" }); // American Samoa\n                put( 545 , new String[] {\"686\" }); // Kiribati (Republic of)\n                put( 546 , new String[] {\"687\" }); // New Caledonia (Territoire franais d'outre-mer)\n                put( 547 , new String[] {\"689\" }); // French Polynesia (Territoire franais d'outre-mer)\n                put( 548 , new String[] {\"682\" }); // Cook Islands\n                put( 549 , new String[] {\"685\" }); // Samoa (Independent State of)\n                put( 550 , new String[] {\"691\" , \"1\" }); // Micronesia (Federated States of)\n                put( 551 , new String[] {\"692\" , \"1\" }); // Marshall Islands (Republic of the)\n                put( 552 , new String[] {\"680\" }); // Palau (Republic of)\n                put( 602 , new String[] {\"20\" , \"0\" }); // Egypt (Arab Republic of)\n                put( 603 , new String[] {\"213\" , \"0\" }); // Algeria (People's Democratic Republic of)\n                put( 604 , new String[] {\"212\" , \"0\" }); // Morocco (Kingdom of)\n                put( 605 , new String[] {\"216\" }); // Tunisia\n                put( 606 , new String[] {\"281\" , \"0\" }); // Libya (Socialist People's Libyan Arab Jamahiriya)\n                put( 607 , new String[] {\"220\" }); // Gambia (Republic of the)\n                put( 608 , new String[] {\"221\" }); // Senegal (Republic of)\n                put( 609 , new String[] {\"222\" }); // Mauritania (Islamic Republic of)\n                put( 610 , new String[] {\"223\" }); // Mali (Republic of)\n                put( 611 , new String[] {\"224\" }); // Guinea (Republic of)\n                put( 612 , new String[] {\"225\" }); // Cte d'Ivoire (Republic of)\n                put( 613 , new String[] {\"226\" }); // Burkina Faso\n                put( 614 , new String[] {\"227\" }); // Niger (Republic of the)\n                put( 615 , new String[] {\"228\" }); // Togolese Republic\n                put( 616 , new String[] {\"229\" }); // Benin (Republic of)\n                put( 617 , new String[] {\"230\" }); // Mauritius (Republic of)\n                put( 618 , new String[] {\"231\" }); // Liberia (Republic of)\n                put( 619 , new String[] {\"232\" , \"0\" }); // Sierra Leone\n                put( 620 , new String[] {\"233\" , \"0\" }); // Ghana\n                put( 621 , new String[] {\"234\" , \"0\" }); // Nigeria (Federal Republic of)\n                put( 622 , new String[] {\"235\" }); // Chad (Republic of)\n                put( 623 , new String[] {\"236\" }); // Central African Republic\n                put( 624 , new String[] {\"237\" }); // Cameroon (Republic of)\n                put( 625 , new String[] {\"238\" }); // Cape Verde (Republic of)\n                put( 626 , new String[] {\"239\" }); // Sao Tome and Principe (Democratic Republic of)\n                put( 627 , new String[] {\"240\" }); // Equatorial Guinea (Republic of)\n                put( 628 , new String[] {\"241\" }); // Gabonese Republic\n                put( 629 , new String[] {\"242\" }); // Congo (Republic of the)\n                put( 630 , new String[] {\"242\" }); // Democratic Republic of the Congo\n                put( 631 , new String[] {\"244\" , \"0\" }); // Angola (Republic of)\n                put( 632 , new String[] {\"245\" }); // Guinea-Bissau (Republic of)\n                put( 633 , new String[] {\"248\" }); // Seychelles (Republic of)\n                put( 634 , new String[] {\"249\" , \"0\" }); // Sudan (Republic of the)\n                put( 635 , new String[] {\"250\" }); // Rwanda (Republic of)\n                put( 636 , new String[] {\"251\" , \"0\" }); // Ethiopia (Federal Democratic Republic of)\n                put( 637 , new String[] {\"252\" }); // Somali Democratic Republic\n                put( 638 , new String[] {\"253\" }); // Djibouti (Republic of)\n                put( 639 , new String[] {\"254\" , \"0\" }); // Kenya (Republic of)\n                put( 640 , new String[] {\"255\" , \"0\" }); // Tanzania (United Republic of)\n                put( 641 , new String[] {\"256\" , \"0\" }); // Uganda (Republic of)\n                put( 642 , new String[] {\"257\" }); // Burundi (Republic of)\n                put( 643 , new String[] {\"258\" }); // Mozambique (Republic of)\n                put( 645 , new String[] {\"260\" , \"0\" }); // Zambia (Republic of)\n                put( 646 , new String[] {\"261\" }); // Madagascar (Republic of)\n                put( 647 , new String[] {\"262\" , \"0\" }); // Reunion (French Department of)\n                put( 648 , new String[] {\"263\" , \"0\" }); // Zimbabwe (Republic of)\n                put( 649 , new String[] {\"264\" , \"0\" }); // Namibia (Republic of)\n                put( 650 , new String[] {\"265\" }); // Malawi\n                put( 651 , new String[] {\"266\" }); // Lesotho (Kingdom of)\n                put( 652 , new String[] {\"267\" }); // Botswana (Republic of)\n                put( 653 , new String[] {\"268\" }); // Swaziland (Kingdom of)\n                put( 654 , new String[] {\"269\" }); // Comoros (Union of the)\n                put( 655 , new String[] {\"27\" , \"0\" }); // South Africa (Republic of)\n                put( 657 , new String[] {\"291\" , \"0\" }); // Eritrea\n                put( 702 , new String[] {\"501\" }); // Belize\n                put( 704 , new String[] {\"502\" }); // Guatemala (Republic of)\n                put( 706 , new String[] {\"503\" }); // El Salvador (Republic of)\n                put( 708 , new String[] {\"504\" }); // Honduras (Republic of)\n                put( 710 , new String[] {\"505\" }); // Nicaragua\n                put( 712 , new String[] {\"506\" }); // Costa Rica\n                put( 714 , new String[] {\"507\" }); // Panama (Republic of)\n                put( 716 , new String[] {\"51\" , \"0\" }); // Peru\n                put( 722 , new String[] {\"54\" , \"0\" }); // Argentine Republic\n                put( 724 , new String[] {\"55\" , \"0\" }); // Brazil (Federative Republic of)\n                put( 730 , new String[] {\"56\" , \"0\" }); // Chile\n                put( 732 , new String[] {\"57\" , \"09\" }); // Colombia (Republic of)\n                put( 734 , new String[] {\"58\" , \"0\" }); // Venezuela (Bolivarian Republic of)\n                put( 736 , new String[] {\"591\" , \"0\" }); // Bolivia (Republic of)\n                put( 738 , new String[] {\"592\" }); // Guyana\n                put( 742 , new String[] {\"594\" , \"0\" }); // French Guiana (French Department of)\n                put( 744 , new String[] {\"595\" , \"0\" }); // Paraguay (Republic of)\n                put( 746 , new String[] {\"597\" , \"0\" }); // Suriname (Republic of)\n                put( 748 , new String[] {\"598\" , \"0\" }); // Uruguay (Eastern Republic of)\n                put( 750 , new String[] {\"500\" }); // Falkland Islands (Malvinas)\n            }\n        }\n    };\n\n    // @formatter:on\n\n    /**\n     * Constructor\n     * \n     * @param ctx the context\n     */\n    private ContactUtil(Context ctx) {\n        mCtx = ctx;\n    }\n\n    /**\n     * Gets a singleton instance of ContactUtil.\n     * \n     * @param context the context.\n     * @return the singleton instance.\n     */\n    public static ContactUtil getInstance(Context context) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (ContactUtil.class) {\n            if (sInstance == null) {\n                if (context == null) {\n                    throw new IllegalArgumentException(\"Context is null\");\n                }\n                sInstance = new ContactUtil(context);\n            }\n        }\n        return sInstance;\n    }\n\n    /**\n     * Removes blank and minus characters from contact\n     * \n     * @param contact the phone number\n     * @return phone string stripped of separators.\n     */\n    private String stripSeparators(String contact) {\n        contact = contact.replaceAll(\"[ -]\", \"\");\n        Matcher matcher = PATTERN_CONTACT.matcher(contact);\n        if (matcher.find()) {\n            return matcher.group();\n        }\n        return null;\n    }\n\n    /**\n     * Checks the validity of a contact number.\n     * \n     * @param contact the contact number.\n     * @return Returns true if the given contactId have the syntax of valid RCS contactId. If the\n     *         string is too short (1 digit at least), too long (more than 15 digits) or contains\n     *         illegal characters (valid characters are digits, space, '-', leading '+') then it\n     *         returns false.\n     * @throws RcsPermissionDeniedException if the mobile country code failed to be read and is\n     *             required to validate the contact.\n     */\n    public boolean isValidContact(String contact) throws RcsPermissionDeniedException {\n        if (TextUtils.isEmpty(contact)) {\n            return false;\n        }\n        String strippedContact = stripSeparators(contact);\n        if (TextUtils.isEmpty(strippedContact)) {\n            return false;\n        }\n        if (strippedContact.startsWith(COUNTRY_CODE_PREFIX)) {\n            return true;\n        }\n        if (strippedContact.startsWith(MSISDN_PREFIX_INTERNATIONAL)) {\n            return true;\n        }\n        /*\n         * At this point, the contact is using a local area formatting so the mobile country code is\n         * required to validate its format.\n         */\n        if (mCountryCode == null) {\n            tryToDetermineAndCacheCountryAndAreaCodes();\n        }\n        /* At this point, the mobile country and area codes are resolved */\n        return TextUtils.isEmpty(mCountryAreaCode) || strippedContact.startsWith(mCountryAreaCode);\n    }\n\n    /**\n     * Formats the given contact to uniquely represent a RCS contact phone number.\n     * \n     * @param contact the contact phone number to format.\n     * @return the ContactId.\n     * @throws RcsPermissionDeniedException if the mobile country code failed to be read and is\n     *             required to format the contact.\n     */\n    public ContactId formatContact(String contact) throws RcsPermissionDeniedException {\n        if (TextUtils.isEmpty(contact)) {\n            throw new IllegalArgumentException(\"Input parameter is null or empty!\");\n        }\n        String strippedContact = stripSeparators(contact);\n        if (TextUtils.isEmpty(strippedContact)) {\n            throw new IllegalArgumentException(\"Contact '\" + contact + \"' has invalid characters or is too long!\");\n        }\n        /* Is Country Code provided ? */\n        if (strippedContact.startsWith(COUNTRY_CODE_PREFIX)) {\n            return new ContactId(strippedContact);\n        }\n        /* International numbering with prefix ? */\n        if (strippedContact.startsWith(MSISDN_PREFIX_INTERNATIONAL)) {\n            return new ContactId(new StringBuilder(COUNTRY_CODE_PREFIX).append(strippedContact,\n                    MSISDN_PREFIX_INTERNATIONAL.length(), strippedContact.length()).toString());\n        }\n        /*\n         * The contact is using a local area formatting so the mobile country code is required to\n         * validate its format.\n         */\n        if (mCountryCode == null) {\n            tryToDetermineAndCacheCountryAndAreaCodes();\n        }\n        /* Local numbering ? */\n        if (TextUtils.isEmpty(mCountryAreaCode)) {\n            /* No Country Area Code, add Country code to local number */\n            return new ContactId(mCountryCode.concat(strippedContact));\n        }\n        // Local number must start with Country Area Code\n        if (strippedContact.startsWith(mCountryAreaCode)) {\n            /* Remove Country Area Code and add Country Code */\n            return new ContactId(new StringBuilder(mCountryCode).append(strippedContact,\n                    mCountryAreaCode.length(), strippedContact.length()).toString());\n        }\n        throw new IllegalArgumentException(\"Local phone number '\" + strippedContact + \"' should be prefixed with Country Area Code (\" + mCountryAreaCode + \")\");\n    }\n\n    private void tryToDetermineAndCacheCountryAndAreaCodes() throws RcsPermissionDeniedException {\n        synchronized (ContactUtil.class) {\n            if (mCountryCode != null) {\n                return;\n            }\n            Configuration config = mCtx.getResources().getConfiguration();\n            /* Get the country code information associated to the mobile country code */\n            String[] countryCodeInfo = sCountryCodes.get(config.mcc);\n            if (countryCodeInfo == null) {\n                throw new RcsPermissionDeniedException(\"Failed to get mobile country code (\" + config.mcc + \")!\");\n            }\n            /* Get the country code from map */\n            String ccWithoutHeader = countryCodeInfo[COUNTRY_CODE_IDX];\n            mCountryCode = COUNTRY_CODE_PREFIX.concat(ccWithoutHeader);\n            mCountryAreaCode = null;\n            if (countryCodeInfo.length == 2) {\n                /* Get the country area code from map */\n                mCountryAreaCode = countryCodeInfo[COUNTRY_AREA_CODE_IDX];\n            }\n        }\n    }\n\n    /**\n     * Gets the user country code.\n     * \n     * @return the user country code.\n     * @throws RcsPermissionDeniedException if the mobile country code failed to be read.\n     */\n    public String getMyCountryCode() throws RcsPermissionDeniedException {\n        if (mCountryCode == null) {\n            tryToDetermineAndCacheCountryAndAreaCodes();\n        }\n        return mCountryCode;\n    }\n\n    /**\n     * Checks if my country code is defined.\n     * \n     * @return True if my country code is defined.\n     */\n    public boolean isMyCountryCodeDefined() {\n        /*\n         * The 'mcc' is read from the Android configuration but it reflects the information of the\n         * SIM card. If undefined then the SIM card is either not inserted or not readable (pin code\n         * is not yet entered). 'mcc' information may be persisted by the Android kernel. So it can\n         * be defined in Android configuration even if the SIM card is not inserted. In this case\n         * 'mcc' reflects the information read from the last inserted SIM card.\n         */\n        return mCtx.getResources().getConfiguration().mcc != MCC_UNDEFINED;\n    }\n\n    /**\n     * Gets the user country area code.\n     * \n     * @return the country area code or null if it does not exist.\n     * @throws RcsPermissionDeniedException thrown if the mobile country code failed to be read.\n     */\n    public String getMyCountryAreaCode() throws RcsPermissionDeniedException {\n        if (mCountryCode == null) {\n            tryToDetermineAndCacheCountryAndAreaCodes();\n        }\n        return mCountryAreaCode;\n    }\n\n    /**\n     * Returns the vCard of a contact. The contact parameter contains the database URI of the\n     * contact in the address book. The method returns a Uri to the visit card. The visit card\n     * filename has the file extension .vcf and is generated from the address book vCard URI (see\n     * Android SDK attribute ContactsContract.Contacts.CONTENT_VCARD_URI which returns the\n     * referenced contact formatted as a vCard when opened through openAssetFileDescriptor(Uri,\n     * String)).\n     * \n     * @param contactUri Contact URI of the contact in the address book\n     * @return Uri of vCard or null if not found\n     * @throws RcsGenericException\n     */\n    public Uri getVCard(Uri contactUri) throws RcsGenericException {\n        Cursor cursor = null;\n        try {\n            cursor = mCtx.getContentResolver().query(contactUri, null, null, null, null);\n            if (cursor == null) {\n                throw new SQLException(\"Cannot query VCard for URI='\"+contactUri+\"'\");\n            }\n            int displayNameColIdx = cursor\n                    .getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);\n            int lookupKeyColIdx = cursor\n                    .getColumnIndexOrThrow(ContactsContract.Contacts.LOOKUP_KEY);\n            if (!cursor.moveToFirst()) {\n                return null;\n            }\n            String lookupKey = cursor.getString(lookupKeyColIdx);\n            Uri vCardUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI,\n                    lookupKey);\n            AssetFileDescriptor fd = mCtx.getContentResolver().openAssetFileDescriptor(vCardUri,\n                    \"r\");\n            if (fd == null) {\n                return null;\n            }\n            FileInputStream fis = fd.createInputStream();\n            byte[] vCardData = new byte[(int) fd.getDeclaredLength()];\n            fis.read(vCardData);\n\n            String name = cursor.getString(displayNameColIdx);\n            String fileName = Environment.getExternalStorageDirectory()\n                    .toString() + File.separator + name + \".vcf\";\n            File vCardFile = new File(fileName);\n            if (vCardFile.exists()) {\n                vCardFile.delete();\n            }\n            FileOutputStream fos = new FileOutputStream(vCardFile, true);\n            fos.write(vCardData);\n            fos.close();\n            return Uri.fromFile(vCardFile);\n\n        } catch (IOException e) {\n            throw new RcsGenericException(e);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/contact/RcsContact.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.contact;\n\nimport com.gsma.services.rcs.capability.Capabilities;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * RCS contact\n * \n * @author Jean-Marc AUFFRET\n * @author YPLO6403\n */\npublic class RcsContact implements Parcelable {\n    /**\n     * Capabilities\n     */\n    private Capabilities mCapabilities;\n\n    /**\n     * Contact ID\n     */\n    private ContactId mContact;\n\n    /**\n     * Display name\n     */\n    private String mDisplayName;\n\n    /**\n     * Online state\n     */\n    private boolean mOnline;\n\n    /**\n     * Blocking state\n     */\n    private boolean mBlocked;\n\n    /**\n     * Blocking timestamp\n     */\n    private long mBlockingTimestamp;\n\n    /**\n     * Constructor\n     * \n     * @param contact Contact ID\n     * @param online Online state\n     * @param capabilities Capabilities\n     * @param displayName Display name\n     * @param blocked Blocking state\n     * @param blockingTs Blocking timestamp\n     * @hide\n     */\n    public RcsContact(ContactId contact, boolean online, Capabilities capabilities,\n            String displayName, boolean blocked, long blockingTs) {\n        mContact = contact;\n        mOnline = online;\n        mCapabilities = capabilities;\n        mDisplayName = displayName;\n        mBlocked = blocked;\n        mBlockingTimestamp = blockingTs;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     * @hide\n     */\n    public RcsContact(Parcel source) {\n        boolean containsContact = source.readInt() != 0;\n        if (containsContact) {\n            mContact = ContactId.CREATOR.createFromParcel(source);\n        } else {\n            mContact = null;\n        }\n        mOnline = source.readInt() != 0;\n        boolean containsCapabilities = source.readInt() != 0;\n        if (containsCapabilities) {\n            mCapabilities = Capabilities.CREATOR.createFromParcel(source);\n        } else {\n            mCapabilities = null;\n        }\n        mDisplayName = source.readString();\n        mBlocked = source.readInt() != 0;\n        mBlockingTimestamp = source.readLong();\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation\n     * \n     * @return Integer\n     * @hide\n     */\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object\n     * \n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    public void writeToParcel(Parcel dest, int flags) {\n        if (mContact != null) {\n            dest.writeInt(1);\n            mContact.writeToParcel(dest, flags);\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeInt(mOnline ? 1 : 0);\n        if (mCapabilities != null) {\n            dest.writeInt(1);\n            mCapabilities.writeToParcel(dest, flags);\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeString(mDisplayName);\n        dest.writeInt(mBlocked ? 1 : 0);\n        dest.writeLong(mBlockingTimestamp);\n    }\n\n    /**\n     * Parcelable creator\n     * \n     * @hide\n     */\n    public static final Parcelable.Creator<RcsContact> CREATOR = new Parcelable.Creator<RcsContact>() {\n        public RcsContact createFromParcel(Parcel source) {\n            return new RcsContact(source);\n        }\n\n        public RcsContact[] newArray(int size) {\n            return new RcsContact[size];\n        }\n    };\n\n    /**\n     * Returns the canonical contact ID (i.e. MSISDN)\n     * \n     * @return Contact ID\n     */\n    public ContactId getContactId() {\n        return mContact;\n    }\n\n    /**\n     * Is contact online (i.e. registered to the service platform)\n     * \n     * @return Returns true if online else returns false\n     */\n    public boolean isOnline() {\n        return mOnline;\n    }\n\n    /**\n     * Returns the capabilities associated to the contact\n     * \n     * @return Capabilities\n     */\n    public Capabilities getCapabilities() {\n        return mCapabilities;\n    }\n\n    /**\n     * Returns the display name associated to the contact\n     * \n     * @return displayName\n     */\n    public String getDisplayName() {\n        return mDisplayName;\n    }\n\n    /**\n     * Is contact blocked\n     * \n     * @return Returns true if blocked else returns false\n     */\n    public boolean isBlocked() {\n        return mBlocked;\n    }\n\n    /**\n     * Returns the timestamp when the blocking was activated or -1 if contact is not blocked.\n     * \n     * @return Timestamp\n     */\n    public long getBlockingTimestamp() {\n        return mBlockingTimestamp;\n    }\n\n    /**\n     @hide\n     */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + ((mContact == null) ? 0 : mContact.hashCode());\n        return result;\n    }\n\n    /**\n        @hide\n     */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj)\n            return true;\n        if (obj == null)\n            return false;\n        if (getClass() != obj.getClass())\n            return false;\n        RcsContact other = (RcsContact) obj;\n        if (mContact == null) {\n            if (other.mContact != null)\n                return false;\n        } else if (!mContact.equals(other.mContact))\n            return false;\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/contact/package-info.java",
    "content": "/**\n * This API exposes all infos related to RCS contacts.\n * <p>\n */\n\npackage com.gsma.services.rcs.contact;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/InstantMultimediaMessageIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\n/**\n * Intent for instant multimedia message\n *\n * @author Jean-Marc AUFFRET\n */\npublic class InstantMultimediaMessageIntent {\n    /**\n     * Broadcast action: a new multimedia instant message has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_CONTACT} containing the contact ID of remote contact.\n     * <li> {@link #EXTRA_SERVICE_ID} containing the service ID related to the multimedia message.\n     * <li>The service ID is read from the method Intent.getType() which returns the MIME type\n     * included in the intent and corresponding to the invoked service.\n     * <li> {@link #EXTRA_CONTENT} containing the content of the multimedia message.\n     * <li> {@link #EXTRA_CONTENT_TYPE} containing the content type of the multimedia message.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INSTANT_MESSAGE = \"com.gsma.services.rcs.extension.action.NEW_INSTANT_MESSAGE\";\n\n    /**\n     * ContactId of remote contact\n     */\n    public final static String EXTRA_CONTACT = \"contact\";\n\n    /**\n     * Unique service ID\n     */\n    public final static String EXTRA_SERVICE_ID = \"serviceId\";\n\n    /**\n     * Content of the multimedia message (byte[])\n     */\n    public final static String EXTRA_CONTENT = \"content\";\n\n    /**\n     * Content type of the multimedia message\n     */\n    public final static String EXTRA_CONTENT_TYPE = \"contentType\";\n\n    private InstantMultimediaMessageIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaMessagingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * This class maintains the information related to a multimedia session for a real time messaging\n * service.\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaMessagingSession extends MultimediaSession {\n    /**\n     * Messaging session interface\n     */\n    private IMultimediaMessagingSession mSessionIntf;\n\n    /**\n     * Constructor\n     * \n     * @param sessionIntf Multimedia session interface\n     */\n    /* package private */MultimediaMessagingSession(IMultimediaMessagingSession sessionIntf) {\n        super();\n        mSessionIntf = sessionIntf;\n    }\n\n    /**\n     * Returns the session ID of the multimedia session\n     * \n     * @return String Session ID\n     * @throws RcsGenericException\n     */\n    public String getSessionId() throws RcsGenericException {\n        try {\n            return mSessionIntf.getSessionId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsGenericException {\n        try {\n            return mSessionIntf.getRemoteContact();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the service ID\n     * \n     * @return String Service ID\n     * @throws RcsGenericException\n     */\n    public String getServiceId() throws RcsGenericException {\n        try {\n            return mSessionIntf.getServiceId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the session\n     * \n     * @return State\n     * @see MultimediaSession.State\n     * @throws RcsGenericException\n     */\n    public State getState() throws RcsGenericException {\n        try {\n            return State.valueOf(mSessionIntf.getState());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code state of the session\n     * \n     * @return ReasonCode\n     * @see MultimediaSession.ReasonCode\n     * @throws RcsGenericException\n     */\n    public ReasonCode getReasonCode() throws RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mSessionIntf.getReasonCode());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the session\n     * \n     * @return Direction\n     * @see Direction\n     * @throws RcsGenericException\n     */\n    public Direction getDirection() throws RcsGenericException {\n        try {\n            return Direction.valueOf(mSessionIntf.getDirection());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts session invitation.\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void acceptInvitation() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.acceptInvitation();\n\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Rejects session invitation\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void rejectInvitation() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.rejectInvitation();\n\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the session\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void abortSession() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.abortSession();\n\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a message in real time\n     * \n     * @deprecated Use {@link #sendMessage(byte[] content, String contentType)} instead.\n     * @param content Message content\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    @Deprecated\n    public void sendMessage(byte[] content) throws RcsPermissionDeniedException,\n            RcsGenericException {\n        try {\n            mSessionIntf.sendMessage(content);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a message in real time\n     *\n     * @param content Message content\n     * @param contentType Message content type\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void sendMessage(byte[] content, String contentType)\n            throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.sendMessage2(content, contentType);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Flush all messages of the session\n     *\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void flushMessages() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.flushMessages();\n\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaMessagingSessionIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\n/**\n * Intent for multimedia messaging session invitations\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaMessagingSessionIntent {\n    /**\n     * Broadcast action: a new messaging session invitation has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_SESSION_ID} containing the unique ID of the multimedia session.\n     * <li>The service ID is read from the method Intent.getType() which returns the MIME type\n     * included in the intent and corresponding to the invoked service.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.extension.action.NEW_MESSAGING_SESSION\";\n\n    /**\n     * Unique ID of the multimedia session\n     */\n    public final static String EXTRA_SESSION_ID = \"sessionId\";\n\n    private MultimediaMessagingSessionIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaMessagingSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\n/**\n * This class offers callback methods on multimedia messaging session events\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class MultimediaMessagingSessionListener {\n    /**\n     * Callback called when the multimedia messaging session state/reasonCode is changed.\n     * \n     * @param contact Contact ID\n     * @param sessionId Session ID\n     * @param state State\n     * @param reasonCode Reason code\n     */\n    public abstract void onStateChanged(ContactId contact, String sessionId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Callback called when a multimedia message or data is received.\n     * \n     * @deprecated Use\n     *             {@link #onMessageReceived(ContactId contact, String sessionId, byte[] content, String contentType)}\n     *             instead.\n     * @param contact Contact ID\n     * @param sessionId Session ID\n     * @param content Message content\n     */\n    @Deprecated\n    public abstract void onMessageReceived(ContactId contact, String sessionId, byte[] content);\n\n    /**\n     * Callback called when a multimedia message or data is received.\n     *\n     * @param contact Contact ID\n     * @param sessionId Session ID\n     * @param content Message content\n     * @param contentType Message content type\n     */\n    public abstract void onMessageReceived(ContactId contact, String sessionId, byte[] content,\n            String contentType);\n\n    /**\n     * Callback called when multimedia messages have been flushed.\n     *\n     * @param contact Contact ID\n     * @param sessionId Session ID\n     */\n    public abstract void onMessagesFlushed(ContactId contact, String sessionId);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaMessagingSessionListenerImpl.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.util.Log;\n\n/**\n * Multimedia Messaging Session Listener Implementation\n * \n * @hide\n */\npublic class MultimediaMessagingSessionListenerImpl extends\n        IMultimediaMessagingSessionListener.Stub {\n\n    private final MultimediaMessagingSessionListener mListener;\n\n    private static final String LOG_TAG = MultimediaMessagingSessionListenerImpl.class.getName();\n\n    MultimediaMessagingSessionListenerImpl(MultimediaMessagingSessionListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(ContactId contact, String sessionId, int state, int reasonCode) {\n        State rcsState;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsState = State.valueOf(state);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(contact, sessionId, rcsState, rcsReasonCode);\n    }\n\n    public void onMessageReceived(ContactId contact, String sessionId, byte[] content) {\n        mListener.onMessageReceived(contact, sessionId, content);\n    }\n\n    public void onMessageReceived2(ContactId contact, String sessionId, byte[] content, String contentType) {\n        mListener.onMessageReceived(contact, sessionId, content, contentType);\n    }\n\n    public void onMessagesFlushed(ContactId contact, String sessionId) {\n        mListener.onMessagesFlushed(contact, sessionId);\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.SparseArray;\n\n/**\n * This class maintains the information related to a multimedia session and offers methods to manage\n * it. This is an abstract class between a messaging session and a streaming session.\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class MultimediaSession {\n    /**\n     * Multimedia session state\n     */\n    public enum State {\n\n        /**\n         * Session invitation received\n         */\n        INVITED(0),\n\n        /**\n         * Session invitation sent\n         */\n        INITIATING(1),\n\n        /**\n         * Session is started\n         */\n        STARTED(2),\n\n        /**\n         * Session has been aborted\n         */\n        ABORTED(3),\n\n        /**\n         * Session has failed\n         */\n        FAILED(4),\n\n        /**\n         * Session has been rejected.\n         */\n        REJECTED(5),\n\n        /**\n         * Call ringing\n         */\n        RINGING(6),\n\n        /**\n         * Session has been accepted and is in the process of becoming started\n         */\n        ACCEPTING(7);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State entry : State.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static State valueOf(int value) {\n            State entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value);\n        }\n    }\n\n    /**\n     * Multimedia session reason code\n     */\n    public enum ReasonCode {\n\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * Session is aborted by local user.\n         */\n        ABORTED_BY_USER(1),\n\n        /**\n         * Session is aborted by remote user.\n         */\n        ABORTED_BY_REMOTE(2),\n\n        /**\n         * Session is aborted by system.\n         */\n        ABORTED_BY_SYSTEM(3),\n\n        /**\n         * Session is aborted by inactivity.\n         */\n        ABORTED_BY_INACTIVITY(4),\n\n        /**\n         * Session invitation was rejected by local user.\n         */\n        REJECTED_BY_USER(5),\n\n        /**\n         * Session invitation was rejected by remote.\n         */\n        REJECTED_BY_REMOTE(6),\n\n        /**\n         * Session invitation was rejected by timeout.\n         */\n        REJECTED_BY_TIMEOUT(7),\n\n        /**\n         * Session invitation was rejected by system.\n         */\n        REJECTED_BY_SYSTEM(8),\n\n        /**\n         * Initiation failed.\n         */\n        FAILED_INITIATION(9),\n\n        /**\n         * Session failed.\n         */\n        FAILED_SESSION(10),\n\n        /**\n         * Media failed.\n         */\n        FAILED_MEDIA(11);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value);\n        }\n    }\n\n    /**\n     * Constructor\n     */\n    MultimediaSession() {\n    }\n\n    /**\n     * Returns the session ID of the multimedia session\n     * \n     * @return String Session ID\n     * @throws RcsGenericException\n     */\n    public abstract String getSessionId() throws RcsGenericException;\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RcsGenericException\n     */\n    public abstract ContactId getRemoteContact() throws RcsGenericException;\n\n    /**\n     * Returns the service ID\n     * \n     * @return String Service ID\n     * @throws RcsGenericException\n     */\n    public abstract String getServiceId() throws RcsGenericException;\n\n    /**\n     * Returns the state of the session\n     * \n     * @return State\n     * @see MultimediaSession.State\n     * @throws RcsGenericException\n     */\n    public abstract State getState() throws RcsGenericException;\n\n    /**\n     * Returns the direction of the session\n     * \n     * @return Direction\n     * @see Direction\n     * @throws RcsGenericException\n     */\n    public abstract Direction getDirection() throws RcsGenericException;\n\n    /**\n     * Returns the reason code of the session.\n     * \n     * @return ReasonCode\n     * @see MultimediaSession.ReasonCode\n     * @throws RcsGenericException\n     */\n    public abstract ReasonCode getReasonCode() throws RcsGenericException;\n\n    /**\n     * Accepts session invitation.\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public abstract void acceptInvitation() throws RcsPermissionDeniedException,\n            RcsGenericException;\n\n    /**\n     * Rejects session invitation\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public abstract void rejectInvitation() throws RcsPermissionDeniedException,\n            RcsGenericException;\n\n    /**\n     * Aborts the session\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public abstract void abortSession() throws RcsPermissionDeniedException, RcsGenericException;\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaSessionService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * This class offers the main entry point to initiate and to manage multimedia sessions. Several\n * applications may connect/disconnect to the API.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class MultimediaSessionService extends RcsService {\n    /**\n     * API\n     */\n    private IMultimediaSessionService mApi;\n\n    private final Map<MultimediaMessagingSessionListener, WeakReference<IMultimediaMessagingSessionListener>> mMultimediaMessagingSessionListeners = new WeakHashMap<>();\n\n    private final Map<MultimediaStreamingSessionListener, WeakReference<IMultimediaStreamingSessionListener>> mMultimediaStreamingSessionListeners = new WeakHashMap<>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public MultimediaSessionService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the multimedia service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the multimedia service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IMultimediaSessionService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IMultimediaSessionService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IMultimediaSessionService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Returns the configuration of the multimedia session service\n     * \n     * @return MultimediaSessionServiceConfiguration\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public MultimediaSessionServiceConfiguration getConfiguration()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new MultimediaSessionServiceConfiguration(mApi.getConfiguration());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a new session for real time messaging with a remote contact and for a given service\n     * extension. The messages are exchanged in real time during the session may be from any type.\n     * The parameter contact supports the following formats: MSISDN in national or international\n     * format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an\n     * exception is thrown.\n     * \n     * @param serviceId Service ID\n     * @param contact Contact identifier\n     * @return MultimediaMessagingSession\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPermissionDeniedException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public MultimediaMessagingSession initiateMessagingSession(String serviceId, ContactId contact)\n            throws RcsServiceNotRegisteredException, RcsPermissionDeniedException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaMessagingSession sessionIntf = mApi.initiateMessagingSession(serviceId,\n                    contact);\n            if (sessionIntf != null) {\n                return new MultimediaMessagingSession(sessionIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a new session for real time messaging with a remote contact and for a given service\n     * extension. The messages exchanged in real time during the session are specified by parameters\n     * accept-types and accept-wrapped-types. The parameter contact supports the following formats:\n     * MSISDN in national or international format, SIP address, SIP-URI or Tel-URI. If the format of\n     * the contact is not supported an exception is thrown.\n     *\n     * @param serviceId Service ID\n     * @param contact Contact identifier\n     * @param acceptTypes Accept-types related to exchanged messages (may be null or empty)\n     * @param acceptWrappedTypes Accept-wrapped-types related to exchanged messages (may be null or\n     *            empty)\n     * @return MultimediaMessagingSession\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPermissionDeniedException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public MultimediaMessagingSession initiateMessagingSession(String serviceId, ContactId contact,\n            String[] acceptTypes, String[] acceptWrappedTypes)\n            throws RcsServiceNotRegisteredException, RcsPermissionDeniedException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaMessagingSession sessionIntf = mApi.initiateMessagingSession2(serviceId,\n                    contact, acceptTypes, acceptWrappedTypes);\n            if (sessionIntf != null) {\n                return new MultimediaMessagingSession(sessionIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of messaging sessions associated to a given service ID\n     * \n     * @param serviceId Service ID\n     * @return Set&lt;MultimediaMessagingSession&gt; List of messaging sessions\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public Set<MultimediaMessagingSession> getMessagingSessions(String serviceId)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            Set<MultimediaMessagingSession> result = new HashSet<>();\n            List<IBinder> mmsList = mApi.getMessagingSessions(serviceId);\n            for (IBinder binder : mmsList) {\n                MultimediaMessagingSession session = new MultimediaMessagingSession(\n                        IMultimediaMessagingSession.Stub.asInterface(binder));\n                result.add(session);\n            }\n            return result;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current messaging session from its unique session ID\n     * \n     * @param sessionId the session ID\n     * @return MultimediaMessagingSession Multimedia messaging session or null if not found\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public MultimediaMessagingSession getMessagingSession(String sessionId)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaMessagingSession sessionIntf = mApi.getMessagingSession(sessionId);\n            if (sessionIntf != null) {\n                return new MultimediaMessagingSession(sessionIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a new session for real time streaming with a remote contact and for a given service\n     * extension. The payload are exchanged in real time during the session and may be from any\n     * type. The parameter contact supports the following formats: MSISDN in national or\n     * international format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not\n     * supported an exception is thrown.\n     * \n     * @deprecated Use\n     *             {@link #initiateStreamingSession(String serviceId, ContactId contact, String encoding)}\n     *             instead.\n     * @param serviceId Service ID\n     * @param contact Contact ID\n     * @return MultimediaStreamingSession\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPermissionDeniedException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    @Deprecated\n    public MultimediaStreamingSession initiateStreamingSession(String serviceId, ContactId contact)\n            throws RcsServiceNotRegisteredException, RcsPermissionDeniedException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaStreamingSession sessionIntf = mApi.initiateStreamingSession(serviceId,\n                    contact);\n            if (sessionIntf != null) {\n                return new MultimediaStreamingSession(sessionIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Initiates a new session for real time streaming with a remote contact for a given service\n     * extension and encoding (ie. rtpmap format containing <encoding name>/<clock rate> and\n     * optional parameters if needed. The payload are exchanged in real time during the session and\n     * may be from any type. The parameter contact supports the following formats: MSISDN in\n     * national or international format, SIP address, SIP-URI or Tel-URI. If the format of the\n     * contact is not supported an exception is thrown.\n     *\n     * @param serviceId Service ID\n     * @param contact Contact ID\n     * @param encoding Encoding payload format\n     * @return MultimediaStreamingSession\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPermissionDeniedException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public MultimediaStreamingSession initiateStreamingSession(String serviceId, ContactId contact,\n            String encoding) throws RcsServiceNotRegisteredException, RcsPermissionDeniedException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaStreamingSession sessionIntf = mApi.initiateStreamingSession2(serviceId,\n                    contact, encoding);\n            if (sessionIntf != null) {\n                return new MultimediaStreamingSession(sessionIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of streaming sessions associated to a given service ID\n     * \n     * @param serviceId Service ID\n     * @return Set&lt;MultimediaStreamingSession&gt; List of streaming sessions\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public Set<MultimediaStreamingSession> getStreamingSessions(String serviceId)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            Set<MultimediaStreamingSession> result = new HashSet<>();\n            List<IBinder> mmsList = mApi.getStreamingSessions(serviceId);\n            for (IBinder binder : mmsList) {\n                MultimediaStreamingSession session = new MultimediaStreamingSession(\n                        IMultimediaStreamingSession.Stub.asInterface(binder));\n                result.add(session);\n            }\n            return result;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current streaming session from its unique session ID\n     * \n     * @param sessionId the session ID\n     * @return MultimediaStreamingSession Multimedia streaming session or null if not found\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public MultimediaStreamingSession getStreamingSession(String sessionId)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaStreamingSession sessionIntf = mApi.getStreamingSession(sessionId);\n            if (sessionIntf != null) {\n                return new MultimediaStreamingSession(sessionIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on multimedia messaging session events\n     * \n     * @param listener Session event listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(MultimediaMessagingSessionListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaMessagingSessionListener multimediaMessagingSessionListener = new MultimediaMessagingSessionListenerImpl(\n                    listener);\n            mMultimediaMessagingSessionListeners.put(listener, new WeakReference<>(\n                    multimediaMessagingSessionListener));\n            mApi.addEventListener2(multimediaMessagingSessionListener);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on multimedia messaging session events\n     * \n     * @param listener Session event listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(MultimediaMessagingSessionListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IMultimediaMessagingSessionListener> weakRef = mMultimediaMessagingSessionListeners\n                    .remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IMultimediaMessagingSessionListener multimediaMessagingSessionListener = weakRef.get();\n            if (multimediaMessagingSessionListener != null) {\n                mApi.removeEventListener2(multimediaMessagingSessionListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on multimedia streaming session events\n     * \n     * @param listener Session event listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(MultimediaStreamingSessionListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IMultimediaStreamingSessionListener multimediaStreamingSessionListener = new MultimediaStreamingSessionListenerImpl(\n                    listener);\n            mMultimediaStreamingSessionListeners.put(listener, new WeakReference<>(\n                    multimediaStreamingSessionListener));\n            mApi.addEventListener3(multimediaStreamingSessionListener);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on multimedia streaming session events\n     * \n     * @param listener Session event listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(MultimediaStreamingSessionListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IMultimediaStreamingSessionListener> weakRef = mMultimediaStreamingSessionListeners\n                    .remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IMultimediaStreamingSessionListener multimediaStreamingSessionListener = weakRef.get();\n            if (multimediaStreamingSessionListener != null) {\n                mApi.removeEventListener3(multimediaStreamingSessionListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends an instant multimedia message to a remote contact and for a given service extension.\n     * The content takes part of the message, so any multimedia session is needed to exchange\n     * content here. The parameter contact supports the following formats: MSISDN in national or\n     * international format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not\n     * supported an exception is thrown.\n     *\n     * @param serviceId Service ID\n     * @param contact Contact identifier\n     * @param content Content of the message\n     * @param contentType Content type of the the message\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPermissionDeniedException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void sendInstantMultimediaMessage(String serviceId, ContactId contact, byte[] content,\n            String contentType) throws RcsServiceNotRegisteredException,\n            RcsPermissionDeniedException, RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.sendInstantMultimediaMessage(serviceId, contact, content, contentType);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaSessionServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications AB.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications AB.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\n/**\n * Multimedia session configuration\n * \n * @author Jean-Marc AUFFRET\n * @author yplo6403\n */\npublic class MultimediaSessionServiceConfiguration {\n\n    private final IMultimediaSessionServiceConfiguration mIConfig;\n\n    /**\n     * Constructor\n     * \n     * @param iConfig IMultimediaSessionServiceConfiguration instance\n     */\n    /* package private */MultimediaSessionServiceConfiguration(\n            IMultimediaSessionServiceConfiguration iConfig) {\n        mIConfig = iConfig;\n    }\n\n    /**\n     * Return maximum length of a multimedia message\n     * \n     * @return int Number of bytes\n     * @throws RcsGenericException\n     */\n    public int getMessageMaxLength() throws RcsGenericException {\n        try {\n            return mIConfig.getMessageMaxLength();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the inactivity timeout of a multimedia messaging session.\n     *\n     * @param serviceId Service ID\n     * @return long Timeout in milliseconds\n     * @throws RcsGenericException\n     */\n    public long getMessagingSessionInactivityTimeout(String serviceId) throws RcsGenericException {\n        try {\n            return mIConfig.getMessagingSessionInactivityTimeout(serviceId);\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns True if the given service ID is activated, else returns False.\n     *\n     * @param serviceId Service ID\n     * @return boolean\n     * @throws RcsGenericException\n     */\n    public boolean isServiceActivated(String serviceId) throws RcsGenericException {\n        try {\n            return mIConfig.isServiceActivated(serviceId);\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaStreamingSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\n/**\n * This class maintains the information related to a multimedia session for a real time streaming\n * service.\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaStreamingSession extends MultimediaSession {\n    /**\n     * Streaming session interface\n     */\n    private IMultimediaStreamingSession mSessionIntf;\n\n    /**\n     * Constructor\n     * \n     * @param sessionIntf Multimedia session interface\n     */\n    /* package private */MultimediaStreamingSession(IMultimediaStreamingSession sessionIntf) {\n        super();\n        mSessionIntf = sessionIntf;\n    }\n\n    /**\n     * Returns the session ID of the multimedia session\n     * \n     * @return String Session ID\n     * @throws RcsGenericException\n     */\n    public String getSessionId() throws RcsGenericException {\n        try {\n            return mSessionIntf.getSessionId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsGenericException {\n        try {\n            return mSessionIntf.getRemoteContact();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the service ID\n     * \n     * @return String Service ID\n     * @throws RcsGenericException\n     */\n    public String getServiceId() throws RcsGenericException {\n        try {\n            return mSessionIntf.getServiceId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the session\n     * \n     * @return State\n     * @see MultimediaSession.State\n     * @throws RcsGenericException\n     */\n    public State getState() throws RcsGenericException {\n        try {\n            return State.valueOf(mSessionIntf.getState());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the session\n     * \n     * @return ReasonCode\n     * @see MultimediaSession.ReasonCode\n     * @throws RcsGenericException\n     */\n    public ReasonCode getReasonCode() throws RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mSessionIntf.getReasonCode());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the session\n     * \n     * @return Direction\n     * @see Direction\n     * @throws RcsGenericException\n     */\n    public Direction getDirection() throws RcsGenericException {\n        try {\n            return Direction.valueOf(mSessionIntf.getDirection());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts session invitation.\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void acceptInvitation() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.acceptInvitation();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Rejects session invitation\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void rejectInvitation() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.rejectInvitation();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the session\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void abortSession() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSessionIntf.abortSession();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sends a payload in real time\n     *\n     * @param content Payload content\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void sendPayload(byte[] content) throws RcsPermissionDeniedException,\n            RcsGenericException {\n        try {\n            mSessionIntf.sendPayload(content);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaStreamingSessionIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\n/**\n * Intent for multimedia streaming session invitations\n * \n * @author Jean-Marc AUFFRET\n */\npublic class MultimediaStreamingSessionIntent {\n    /**\n     * Broadcast action: a new messaging session invitation has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_SESSION_ID} containing the unique ID of the multimedia session.\n     * <li>The service ID is read from the method Intent.getType() which returns the MIME type\n     * included in the intent and corresponding to the invoked service.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.extension.action.NEW_STREAMING_SESSION\";\n\n    /**\n     * Unique ID of the multimedia session\n     */\n    public final static String EXTRA_SESSION_ID = \"sessionId\";\n\n    private MultimediaStreamingSessionIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaStreamingSessionListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\n/**\n * This class offers callback methods on multimedia streaming session events\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class MultimediaStreamingSessionListener {\n    /**\n     * Callback called when the multimedia messaging session state/reasoncode is changed.\n     * \n     * @param contact Contact ID\n     * @param sessionId Session ID\n     * @param state State\n     * @param reasonCode Reason code\n     */\n    public abstract void onStateChanged(ContactId contact, String sessionId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Callback called when a multimedia message or data is received.\n     *\n     * @param contact Contact ID\n     * @param sessionId Session ID\n     * @param content Payload content\n     */\n    public abstract void onPayloadReceived(ContactId contact, String sessionId, byte[] content);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/MultimediaStreamingSessionListenerImpl.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.extension;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.extension.MultimediaSession.ReasonCode;\nimport com.gsma.services.rcs.extension.MultimediaSession.State;\n\nimport android.util.Log;\n\n/**\n * Multimedia Streaming Session Listener Implementation\n * \n * @hide\n */\npublic class MultimediaStreamingSessionListenerImpl extends\n        IMultimediaStreamingSessionListener.Stub {\n\n    private final MultimediaStreamingSessionListener mListener;\n\n    private static final String LOG_TAG = MultimediaStreamingSessionListenerImpl.class.getName();\n\n    MultimediaStreamingSessionListenerImpl(MultimediaStreamingSessionListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(ContactId contact, String sessionId, int state, int reasonCode) {\n        State rcsState;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsState = State.valueOf(state);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(contact, sessionId, rcsState, rcsReasonCode);\n    }\n\n    public void onPayloadReceived(ContactId contact, String sessionId, byte[] content) {\n        mListener.onPayloadReceived(contact, sessionId, content);\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/extension/package-info.java",
    "content": "/**\n * This API exposes all functionality to initiate multimedia sessions between two end points based on a dedicated service ID (or extension).<p>\n */\n\npackage com.gsma.services.rcs.extension;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/FileTransfer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.RcsUnsupportedOperationException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.util.SparseArray;\n\n/**\n * File transfer\n *\n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class FileTransfer {\n\n    /**\n     * File disposition\n     */\n    public enum Disposition {\n        /**\n         * Attachment\n         */\n        ATTACH(0),\n\n        /**\n         * Render\n         */\n        RENDER(1);\n\n        private final int mValue;\n\n        private static SparseArray<Disposition> mValueToEnum = new SparseArray<>();\n        static {\n            for (Disposition entry : Disposition.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        Disposition(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Returns the value of this Disposition as an integer.\n         *\n         * @return integer value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a Disposition instance representing the specified integer value.\n         *\n         * @param value the integer value\n         * @return State instance\n         */\n        public static Disposition valueOf(int value) {\n            Disposition entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n    }\n\n    /**\n     * File transfer state\n     */\n    public enum State {\n        /**\n         * File transfer invitation received\n         */\n        INVITED(0),\n\n        /**\n         * File transfer has been accepted and is in the process of becoming started\n         */\n        ACCEPTING(1),\n\n        /**\n         * File transfer is rejected\n         */\n        REJECTED(2),\n\n        /**\n         * File transfer has been queued\n         */\n        QUEUED(3),\n\n        /**\n         * File transfer initiating\n         */\n        INITIATING(4),\n\n        /**\n         * File transfer is started\n         */\n        STARTED(5),\n\n        /**\n         * File transfer is paused\n         */\n        PAUSED(6),\n\n        /**\n         * File transfer has been aborted\n         */\n        ABORTED(7),\n\n        /**\n         * File transfer has been transferred with success\n         */\n        TRANSFERRED(8),\n\n        /**\n         * File transfer has failed\n         */\n        FAILED(9),\n\n        /**\n         * File transfer has been delivered\n         */\n        DELIVERED(10),\n\n        /**\n         * File transfer has been displayed or opened\n         */\n        DISPLAYED(11);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State entry : State.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Returns the value of this State as an integer.\n         *\n         * @return integer value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a State instance representing the specified integer value.\n         *\n         * @param value the integer value\n         * @return State instance\n         */\n        public static State valueOf(int value) {\n            State entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n\n    }\n\n    /**\n     * File transfer reason code\n     */\n    public enum ReasonCode {\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * File transfer is aborted by local user.\n         */\n        ABORTED_BY_USER(1),\n\n        /**\n         * File transfer is aborted by remote user..\n         */\n        ABORTED_BY_REMOTE(2),\n\n        /**\n         * File transfer is aborted by system.\n         */\n        ABORTED_BY_SYSTEM(3),\n\n        /**\n         * file transfer is rejected because already taken by the secondary device.\n         */\n        REJECTED_BY_SECONDARY_DEVICE(4),\n\n        /**\n         * File transfer has been rejected by timeout.\n         */\n        REJECTED_BY_TIMEOUT(5),\n\n        /**\n         * Incoming file transfer was rejected as it was detected as spam.\n         */\n        REJECTED_SPAM(6),\n\n        /**\n         * Incoming file transfer was rejected as is cannot be received due to lack of local storage\n         * space.\n         */\n        REJECTED_LOW_SPACE(7),\n\n        /**\n         * Incoming transfer was rejected as it was too big to be received.\n         */\n        REJECTED_MAX_SIZE(8),\n\n        /**\n         * Incoming file transfer was rejected as there was too many file transfers ongoing.\n         */\n        REJECTED_MAX_FILE_TRANSFERS(9),\n\n        /**\n         * File transfer invitation was rejected by local user.\n         */\n        REJECTED_BY_USER(10),\n\n        /**\n         * File transfer invitation was rejected by remote.\n         */\n        REJECTED_BY_REMOTE(11),\n\n        /**\n         * File transfer invitation was rejected because of media failure\n         */\n        REJECTED_MEDIA_FAILED(12),\n\n        /**\n         * File transfer invitation was rejected by system.\n         */\n        REJECTED_BY_SYSTEM(13),\n\n        /**\n         * File transfer was paused by system.\n         */\n        PAUSED_BY_SYSTEM(14),\n\n        /**\n         * File transfer was paused by user.\n         */\n        PAUSED_BY_USER(15),\n\n        /**\n         * File transfer initiation failed.\n         */\n        FAILED_INITIATION(16),\n\n        /**\n         * The transferring of the file contents (data) from/to remote side failed.\n         */\n        FAILED_DATA_TRANSFER(17),\n\n        /**\n         * Saving of the incoming file transfer failed.\n         */\n        FAILED_SAVING(18),\n\n        /**\n         * Delivering of the file transfer invitation failed.\n         */\n        FAILED_DELIVERY(19),\n\n        /**\n         * Displaying of the file transfer invitation failed.\n         */\n        FAILED_DISPLAY(20),\n\n        /**\n         * File transfer not allowed to be sent.\n         */\n        FAILED_NOT_ALLOWED_TO_SEND(21);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Returns the value of this ReasonCode as an integer.\n         *\n         * @return integer value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a ReasonCode instance representing the specified integer value.\n         *\n         * @param value the integer value\n         * @return ReasonCode instance\n         */\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * File transfer interface\n     */\n    private final IFileTransfer mTransferInf;\n\n    /**\n     * Constructor\n     *\n     * @param transferIntf File transfer interface\n     */\n    /* package private */FileTransfer(IFileTransfer transferIntf) {\n        mTransferInf = transferIntf;\n    }\n\n    /**\n     * Returns the chat ID if this file transfer is a group file transfer\n     *\n     * @return String Chat ID\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getChatId() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getChatId();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the file transfer ID of the file transfer\n     *\n     * @return String Transfer ID\n     * @throws RcsGenericException\n     */\n    public String getTransferId() throws RcsGenericException {\n        try {\n            return mTransferInf.getTransferId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     *\n     * @return ContactId\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getRemoteContact();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the complete filename including the path of the file to be transferred\n     *\n     * @return String Filename\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getFileName() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFileName();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the size of the file to be transferred\n     *\n     * @return long Size in bytes\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getFileSize() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFileSize();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the MIME type of the file to be transferred\n     *\n     * @return String Type\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getMimeType() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getMimeType();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the Uri of the file icon\n     *\n     * @return Uri the Uri of the file icon or thumbnail\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Uri getFileIcon() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFileIcon();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the MIME type of the file icon to be transfered\n     *\n     * @return String MIME Type\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getFileIconMimeType() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFileIconMimeType();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the Uri of the file\n     *\n     * @return Uri of file\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Uri getFile() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFile();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the file transfer\n     *\n     * @return State\n     * @see FileTransfer.State\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public State getState() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return State.valueOf(mTransferInf.getState());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the sharing\n     *\n     * @return ReasonCode\n     * @see ReasonCode\n     * @see FileTransfer.ReasonCode\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ReasonCode getReasonCode() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mTransferInf.getReasonCode());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the transfer\n     *\n     * @return Direction\n     * @see Direction\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Direction getDirection() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Direction.valueOf(mTransferInf.getDirection());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the file transfer was initiated and/or queued for\n     * outgoing file transfers or the local timestamp of when the file transfer invitation was\n     * received for incoming file transfers\n     *\n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestamp() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getTimestamp();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the file transfer was initiated and /or queued for\n     * outgoing file transfers or the remote timestamp of when the file transfer was initiated for\n     * incoming file transfers\n     *\n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestampSent() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getTimestampSent();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the file transfer was delivered for outgoing file\n     * transfers or 0 for incoming file transfers or it was not yet displayed\n     *\n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestampDelivered() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getTimestampDelivered();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the file transfer was displayed for outgoing file\n     * transfers or 0 for incoming file transfers or it was not yet displayed\n     *\n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestampDisplayed() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getTimestampDisplayed();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts file transfer invitation\n     *\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void acceptInvitation() throws RcsPermissionDeniedException,\n            RcsPersistentStorageException, RcsGenericException {\n        try {\n            mTransferInf.acceptInvitation();\n        } catch (Exception e) {\n            RcsUnsupportedOperationException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Rejects file transfer invitation\n     *\n     * @throws RcsPersistentStorageException\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void rejectInvitation() throws RcsPersistentStorageException,\n            RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mTransferInf.rejectInvitation();\n        } catch (Exception e) {\n            RcsUnsupportedOperationException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the file transfer\n     *\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void abortTransfer() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mTransferInf.abortTransfer();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to pause this file transfer right now, else returns false. If\n     * this filetransfer corresponds to a file transfer that is no longer present in the persistent\n     * storage false will be returned (this is no error)\n     *\n     * @return boolean\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToPauseTransfer() throws RcsGenericException {\n        try {\n            return mTransferInf.isAllowedToPauseTransfer();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Pauses the file transfer\n     *\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void pauseTransfer() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mTransferInf.pauseTransfer();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            RcsUnsupportedOperationException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to resume this file transfer right now, else return false. If\n     * this filetransfer corresponds to a file transfer that is no longer present in the persistent\n     * storage false will be returned.\n     *\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToResumeTransfer() throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return mTransferInf.isAllowedToResumeTransfer();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Resumes the file transfer\n     *\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void resumeTransfer() throws RcsPermissionDeniedException,\n            RcsPersistentStorageException, RcsGenericException {\n        try {\n            mTransferInf.resumeTransfer();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns whether you can resend the transfer.\n     *\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToResendTransfer() throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return mTransferInf.isAllowedToResendTransfer();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Resend a file transfer which was previously failed. This only for 1-1 file transfer, an\n     * exception is thrown in case of a file transfer to group.\n     *\n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void resendTransfer() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mTransferInf.resendTransfer();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            RcsUnsupportedOperationException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if file transfer has been marked as read\n     *\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isRead() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.isRead();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the time for when file on the content server is no longer valid to download.\n     *\n     * @return long time in milliseconds or 0 if not applicable or -1 if unknown\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getFileExpiration() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFileExpiration();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the time for when file icon on the content server is no longer valid to download.\n     *\n     * @return long time in milliseconds or 0 if not applicable or -1 if unknown\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getFileIconExpiration() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.getFileIconExpiration();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if delivery for this file has expired or false otherwise. Note: false means\n     * either that delivery for this file has not yet expired, delivery has been successful,\n     * delivery expiration has been cleared (see clearFileTransferDeliveryExpiration) or that this\n     * particular file is not eligible for delivery expiration in the first place.\n     *\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public boolean isExpiredDelivery() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mTransferInf.isExpiredDelivery();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the file disposition\n     * {@link com.gsma.services.rcs.filetransfer.FileTransfer.Disposition}.\n     *\n     * @return disposition\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Disposition getDisposition() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Disposition.valueOf(mTransferInf.getDisposition());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/FileTransferIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.filetransfer;\n\n/**\n * Intent for file transfer invitation\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileTransferIntent {\n    /**\n     * Broadcast action: a new file transfer has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_TRANSFER_ID} containing the unique ID of the file transfer.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.filetransfer.action.NEW_FILE_TRANSFER\";\n\n    /**\n     * Broadcast action: a file transfer is resuming.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_TRANSFER_ID} containing the unique ID of the file transfer.\n     * </ul>\n     */\n    public final static String ACTION_RESUME = \"com.gsma.services.rcs.filetransfer.action.RESUME_FILE_TRANSFER\";\n\n    /**\n     * Unique ID of the file transfer\n     */\n    public final static String EXTRA_TRANSFER_ID = \"transferId\";\n\n    /**\n     * Broadcast action: file transfer delivery expired\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_CONTACT} containing the contact ID of remote contact.\n     * <li> {@link #EXTRA_TRANSFER_ID} containing the unique ID of the file transfer.\n     * </ul>\n     */\n    public final static String ACTION_FILE_TRANSFER_DELIVERY_EXPIRED = \"com.gsma.services.rcs.filetransfer.action.FILE_TRANSFER_DELIVERY_EXPIRED\";\n\n    /**\n     * ContactId of remote contact\n     */\n    public final static String EXTRA_CONTACT = \"contact\";\n\n    private FileTransferIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/FileTransferLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.RcsService.Direction;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Content provider for file transfer history\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileTransferLog {\n    /**\n     * Content provider URI\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.filetransfer/filetransfer\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = 2;\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the unique ID of the file transfer.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FT_ID = \"ft_id\";\n\n    /**\n     * The name of the column containing the identity of the remote contact.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the URI of the file.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILE = \"file\";\n\n    /**\n     * The name of the column containing the filename (absolute path).\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILENAME = \"filename\";\n\n    /**\n     * The name of the column containing the file size to be transferred (in bytes).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String FILESIZE = \"filesize\";\n\n    /**\n     * The name of the column containing the MIME-type of the file.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String MIME_TYPE = \"mime_type\";\n\n    /**\n     * The name of the column containing the file disposition.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     *\n     * @see Direction\n     */\n    public static final String DISPOSITION = \"disposition\";\n\n    /**\n     * The name of the column containing the direction of the transfer.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see Direction\n     */\n    public static final String DIRECTION = \"direction\";\n\n    /**\n     * The name of the column containing the amount of data transferred (in bytes).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TRANSFERRED = \"transferred\";\n\n    /**\n     * The name of the column containing the time when transfer is initiated.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP = \"timestamp\";\n\n    /**\n     * The name of the column containing the time when file is sent. If 0 means not sent.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_SENT = \"timestamp_sent\";\n\n    /**\n     * The name of the column containing the time when file is delivered. If 0 means not delivered.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_DELIVERED = \"timestamp_delivered\";\n\n    /**\n     * The name of the column containing the time when file is displayed. If 0 means not displayed.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_DISPLAYED = \"timestamp_displayed\";\n\n    /**\n     * If delivery has expired for this file. Values: 1 (true), 0 (false)\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String EXPIRED_DELIVERY = \"expired_delivery\";\n\n    /**\n     * The name of the column containing the state of the transfer.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see FileTransfer.State\n     */\n    public static final String STATE = \"state\";\n\n    /**\n     * The name of the column containing the reason code of the state.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * com.gsma.services.rcs.RcsCommon.ReasonCode\n     */\n    public static final String REASON_CODE = \"reason_code\";\n\n    /**\n     * The name of the column containing the read status for the transfer.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * FileTransfer.ReadStatus\n     */\n    public static final String READ_STATUS = \"read_status\";\n\n    /**\n     * The name of the column containing the file icon (absolute path).\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILEICON = \"fileicon\";\n\n    /**\n     * The name of the column containing the chat ID used for the file transfer in group chat.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CHAT_ID = \"chat_id\";\n\n    /**\n     * The name of the column containing the MIME-type of the file icon.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILEICON_MIME_TYPE = \"fileicon_mime_type\";\n\n    /**\n     * The name of the column containing the timestamp when the file on the content server is no\n     * longer valid to download.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String FILE_EXPIRATION = \"file_expiration\";\n\n    /**\n     * The name of the column containing the timestamp when the file icon on the content server is\n     * no longer valid to download.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String FILEICON_EXPIRATION = \"fileicon_expiration\";\n\n    /**\n     * The value assigned if file or icon expiration is unknown\n     */\n    public static final long UNKNOWN_EXPIRATION = 0L;\n\n    private FileTransferLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/FileTransferService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.Disposition;\n\nimport android.content.ComponentName;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * This class offers the main entry point to transfer files and to receive files. Several\n * applications may connect/disconnect to the API. The parameter contact in the API supports the\n * following formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class FileTransferService extends RcsService {\n\n    /**\n     * API\n     */\n    private IFileTransferService mApi;\n\n    private final Map<OneToOneFileTransferListener, WeakReference<IOneToOneFileTransferListener>> mOneToOneFileTransferListeners = new WeakHashMap<>();\n\n    private final Map<GroupFileTransferListener, WeakReference<IGroupFileTransferListener>> mGroupFileTransferListeners = new WeakHashMap<>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public FileTransferService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the file transfer service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the file transfer service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IFileTransferService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IFileTransferService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IFileTransferService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Granting temporary read Uri permission from client to stack service if it is a content URI\n     * \n     * @param file Uri of file to grant permission\n     */\n    private void tryToGrantUriPermissionToStackServices(Uri file) {\n        if (!ContentResolver.SCHEME_CONTENT.equals(file.getScheme())) {\n            return;\n        }\n        Intent fileTransferServiceIntent = new Intent(IFileTransferService.class.getName());\n        List<ResolveInfo> stackServices = mCtx.getPackageManager().queryIntentServices(\n                fileTransferServiceIntent, 0);\n        for (ResolveInfo stackService : stackServices) {\n            mCtx.grantUriPermission(stackService.serviceInfo.packageName, file,\n                    Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        }\n    }\n\n    /**\n     * Returns the configuration of the file transfer service\n     * \n     * @return FileTransferServiceConfiguration\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileTransferServiceConfiguration getConfiguration()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new FileTransferServiceConfiguration(mApi.getConfiguration());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to initiate file transfer to the contact specified by the\n     * contact parameter, else returns false.\n     * \n     * @param contact the remote contact\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToTransferFile(ContactId contact) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.isAllowedToTransferFile(contact);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Transfers a file to a contact. The parameter file contains the URI of the file to be\n     * transferred (for a local or a remote file). The parameter contact supports the following\n     * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI. If the\n     * format of the contact is not supported an exception is thrown.\n     * \n     * @deprecated Use\n     *             {@link #transferFile(ContactId contact, Uri file, Disposition disposition, boolean attachFileIcon)}\n     *             instead.\n     * @param contact the remote contact Identifier\n     * @param file Uri of file to transfer\n     * @param attachFileIcon File icon option. If true, the stack tries to attach fileicon. Fileicon\n     *            may not be attached if file is not an image or if local or remote contact does not\n     *            support fileicon.\n     * @return FileTransfer\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    @Deprecated\n    public FileTransfer transferFile(ContactId contact, Uri file, boolean attachFileIcon)\n            throws RcsPersistentStorageException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        return transferFile(contact, file, Disposition.ATTACH, attachFileIcon);\n    }\n\n    /**\n     * Transfers a file to a contact. The parameter file contains the URI of the file to be\n     * transferred (for a local or a remote file). The parameter contact supports the following\n     * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI. If the\n     * format of the contact is not supported an exception is thrown.\n     *\n     * @param contact the remote contact Identifier\n     * @param file Uri of file to transfer\n     * @param disposition File disposition\n     * @param attachFileIcon File icon option. If true, the stack tries to attach fileicon. Fileicon\n     *            may not be attached if file is not an image or if local or remote contact does not\n     *            support fileicon.\n     * @return FileTransfer\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileTransfer transferFile(ContactId contact, Uri file, Disposition disposition,\n            boolean attachFileIcon) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            /* Only grant permission for content Uris */\n            tryToGrantUriPermissionToStackServices(file);\n            IFileTransfer ftIntf = mApi.transferFile2(contact, file, disposition.toInt(),\n                    attachFileIcon);\n            if (ftIntf != null) {\n                return new FileTransfer(ftIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns true if it is possible to initiate file transfer to the group chat specified by the\n     * chatId parameter, else returns false.\n     * \n     * @param chatId the chat ID\n     * @return boolean\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public boolean isAllowedToTransferFileToGroupChat(String chatId)\n            throws RcsPersistentStorageException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.isAllowedToTransferFileToGroupChat(chatId);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Transfers a file to a group chat with an optional file icon.\n     * \n     * @deprecated Use\n     *             {@link #transferFileToGroupChat(String chatId, Uri file, Disposition disposition, boolean attachFileIcon)}\n     *             instead.\n     * @param chatId the chat ID\n     * @param file Uri of file to transfer\n     * @param attachFileIcon Attach file icon option. If true, the stack tries to attach fileIcon.\n     *            FileIcon may not be attached if file is not an image or if local or remote contact\n     *            does not support fileIcon.\n     * @return FileTransfer\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileTransfer transferFileToGroupChat(String chatId, Uri file, boolean attachFileIcon)\n            throws RcsPermissionDeniedException, RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        return transferFileToGroupChat(chatId, file, Disposition.ATTACH, attachFileIcon);\n    }\n\n    /**\n     * Transfers a file to a group chat with an optional file icon.\n     *\n     * @param chatId the chat ID\n     * @param file Uri of file to transfer\n     * @param disposition File disposition\n     * @param attachFileIcon Attach file icon option. If true, the stack tries to attach fileIcon.\n     *            FileIcon may not be attached if file is not an image or if local or remote contact\n     *            does not support fileIcon.\n     * @return FileTransfer\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileTransfer transferFileToGroupChat(String chatId, Uri file, Disposition disposition,\n            boolean attachFileIcon) throws RcsPermissionDeniedException,\n            RcsPersistentStorageException, RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            /* Only grant permission for content Uris */\n            tryToGrantUriPermissionToStackServices(file);\n            IFileTransfer ftIntf = mApi.transferFileToGroupChat2(chatId, file, disposition.toInt(),\n                    attachFileIcon);\n            if (ftIntf != null) {\n                return new FileTransfer(ftIntf);\n\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Mark a received file transfer as read (i.e. the invitation or the file has been displayed in\n     * the UI).\n     * \n     * @param transferId the file transfer ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void markFileTransferAsRead(String transferId) throws RcsServiceNotAvailableException,\n            RcsPersistentStorageException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.markFileTransferAsRead(transferId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current file transfer from its unique ID\n     * \n     * @param transferId the file transfer ID\n     * @return FileTransfer File transfer or null if not found\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileTransfer getFileTransfer(String transferId) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IFileTransfer ftIntf = mApi.getFileTransfer(transferId);\n            if (ftIntf != null) {\n                return new FileTransfer(ftIntf);\n\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on file transfer events\n     * \n     * @param listener One-to-one file transfer listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(OneToOneFileTransferListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IOneToOneFileTransferListener rcsListener = new OneToOneFileTransferListenerImpl(\n                    listener);\n            mOneToOneFileTransferListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener2(rcsListener);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on file transfer events\n     * \n     * @param listener File transfer listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(OneToOneFileTransferListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IOneToOneFileTransferListener> weakRef = mOneToOneFileTransferListeners\n                    .remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IOneToOneFileTransferListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener2(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on group file transfer events\n     * \n     * @param listener Group file transfer listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(GroupFileTransferListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IGroupFileTransferListener rcsListener = new GroupFileTransferListenerImpl(listener);\n            mGroupFileTransferListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener3(rcsListener);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on group file transfer events\n     * \n     * @param listener Group file transfer listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(GroupFileTransferListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IGroupFileTransferListener> weakRef = mGroupFileTransferListeners\n                    .remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IGroupFileTransferListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener3(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all one to one file transfer from history and abort/reject any associated ongoing\n     * session if such exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteOneToOneFileTransfers() throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteOneToOneFileTransfers();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all group file transfer from history and abort/reject any associated ongoing session\n     * if such exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGroupFileTransfers() throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGroupFileTransfers();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes file transfer corresponding to a given one to one chat specified by contact from\n     * history and abort/reject any associated ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteOneToOneFileTransfers(ContactId contact)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteOneToOneFileTransfers2(contact);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes file transfer corresponding to a given group chat specified by chat id from history\n     * and abort/reject any associated ongoing session if such exists.\n     * \n     * @param chatId the chat ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGroupFileTransfers(String chatId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGroupFileTransfers2(chatId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes a file transfer by its unique id from history and abort/reject any associated ongoing\n     * session if such exists.\n     * \n     * @param transferId the file transfer ID\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteFileTransfer(String transferId) throws RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteFileTransfer(transferId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Disables and clears any delivery expiration for a set of file transfers regardless if the\n     * delivery of them has expired already or not.\n     * \n     * @param transferIds the file transfer IDs\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void clearFileTransferDeliveryExpiration(Set<String> transferIds)\n            throws RcsServiceNotAvailableException, RcsPersistentStorageException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.clearFileTransferDeliveryExpiration(new ArrayList<>(transferIds));\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/FileTransferServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsUnsupportedOperationException;\n\nimport android.util.SparseArray;\n\n/**\n * File transfer service configuration\n * \n * @author LEMORDANT Philippe\n */\npublic class FileTransferServiceConfiguration {\n\n    private IFileTransferServiceConfiguration mIFtServiceConfig;\n\n    /**\n     * Enumerated for the Image Resize Option\n     */\n    public enum ImageResizeOption {\n        /**\n         * Always resize\n         */\n        ALWAYS_RESIZE(0),\n        /**\n         * Always ask if resize or not\n         */\n        ALWAYS_ASK(1),\n        /**\n         * Never resize\n         */\n        NEVER_RESIZE(2);\n\n        private int mValue;\n\n        private static SparseArray<ImageResizeOption> mValueToEnum = new SparseArray<>();\n        static {\n            for (ImageResizeOption entry : ImageResizeOption.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ImageResizeOption(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Returns the value of this ImageResizeOption as an int.\n         * \n         * @return int value\n         */\n        public final int toInt() {\n            return mValue;\n            /**\n             * @param value\n             * @return\n             */\n        }\n\n        /**\n         * Returns a ImageResizeOption instance representing the specified int value.\n         * \n         * @param value the int value representing the ImageResizeOption\n         * @return ImageResizeOption instance\n         */\n        public static ImageResizeOption valueOf(int value) {\n            ImageResizeOption entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \"\n                    + ImageResizeOption.class.getName() + \"\" + value);\n\n        }\n\n    }\n\n    /**\n     * Constructor\n     * \n     * @param iFtServiceConfig the file transfer service configuration interface\n     */\n    /* package private */FileTransferServiceConfiguration(\n            IFileTransferServiceConfiguration iFtServiceConfig) {\n        mIFtServiceConfig = iFtServiceConfig;\n    }\n\n    /**\n     * Returns the maximum audio message duration.\n     *\n     * @return long maximum audio message duration\n     * @throws RcsGenericException\n     */\n    public long getMaxAudioMessageDuration() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.getMaxAudioMessageDuration();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the file transfer size threshold when the user should be warned about the potential\n     * charges associated to the transfer of a large file. It returns 0 if there no need to warn.\n     *\n     * @return long Size in bytes\n     * @throws RcsGenericException\n     */\n    public long getWarnSize() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.getWarnSize();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the file transfer size limit. It returns 0 if there is no limitation.\n     * \n     * @return long Size in bytes\n     * @throws RcsGenericException\n     */\n    public long getMaxSize() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.getMaxSize();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Is file transfer invitation automatically accepted\n     * \n     * @return boolean Returns true if File Transfer is automatically accepted else returns false\n     * @throws RcsGenericException\n     */\n    public boolean isAutoAcceptEnabled() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.isAutoAcceptEnabled();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the Auto Accept Mode of a File Transfer configuration.<br>\n     * The Auto Accept Mode can only be modified by client application if isAutoAcceptChangeable is\n     * true.\n     * \n     * @param enable True if file transfer is auto accepted\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void setAutoAccept(boolean enable) throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            mIFtServiceConfig.setAutoAccept(enable);\n        } catch (Exception e) {\n            RcsUnsupportedOperationException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Is file transfer invitation automatically accepted while in roaming.\n     * <p>\n     * This parameter is only applicable if auto accept is active for File Transfer in normal\n     * conditions (see isAutoAcceptEnabled).\n     * \n     * @return boolean Returns true if File Transfer is automatically accepted while in roaming else\n     *         returns false\n     * @throws RcsGenericException\n     */\n    public boolean isAutoAcceptInRoamingEnabled() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.isAutoAcceptInRoamingEnabled();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the Auto Accept Mode of a File Transfer configuration while roaming.<br>\n     * The AutoAcceptInRoaming can only be modified by client application if\n     * isAutoAcceptModeChangeable is true and if the AutoAccept Mode in normal conditions is true.\n     * \n     * @param enable True if file transfer is auto accepted in roaming\n     * @throws RcsPermissionDeniedException\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public void setAutoAcceptInRoaming(boolean enable) throws RcsPermissionDeniedException,\n            RcsPersistentStorageException, RcsGenericException {\n        try {\n            mIFtServiceConfig.setAutoAcceptInRoaming(enable);\n\n        } catch (Exception e) {\n            RcsUnsupportedOperationException.assertException(e);\n            RcsPermissionDeniedException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * is default Auto Accept mode (both in normal or roaming modes) changeable\n     * \n     * @return boolean True if client is allowed to change the default Auto Accept mode (both in\n     *         normal or roaming modes)\n     * @throws RcsGenericException\n     */\n    public boolean isAutoAcceptModeChangeable() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.isAutoAcceptModeChangeable();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the max number of simultaneous file transfers\n     * \n     * @return int the max number of simultaneous file transfers\n     * @throws RcsGenericException\n     */\n    public int getMaxFileTransfers() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.getMaxFileTransfers();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the image resize option for file transfer in the range: ALWAYS_PERFORM,\n     * ONLY_ABOVE_MAX_SIZE, ASK\n     * \n     * @return ImageResizeOption instance\n     * @throws RcsGenericException\n     */\n    public ImageResizeOption getImageResizeOption() throws RcsGenericException {\n        try {\n            return ImageResizeOption.valueOf(mIFtServiceConfig.getImageResizeOption());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Sets the image resize option for file transfer.\n     * \n     * @param option the image resize option for file transfer.\n     * @throws RcsGenericException\n     */\n    public void setImageResizeOption(ImageResizeOption option) throws RcsGenericException {\n        try {\n            mIFtServiceConfig.setImageResizeOption(option.toInt());\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns True if group file transfer is supported, else returns False.\n     * \n     * @return boolean True if group file transfer is supported, else returns False.\n     * @throws RcsGenericException\n     */\n    public boolean isGroupFileTransferSupported() throws RcsGenericException {\n        try {\n            return mIFtServiceConfig.isGroupFileTransferSupported();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/GroupFileTransferListener.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport java.util.Set;\n\n/**\n * Group file transfer event listener\n */\npublic abstract class GroupFileTransferListener {\n\n    /**\n     * Callback called when the group file transfer status/reasonCode is changed.\n     *\n     * @param chatId Id of chat\n     * @param transferId Id of file transfer\n     * @param state State of file transfer after change\n     * @param reasonCode Reason code of file transfer after change\n     */\n    public abstract void onStateChanged(String chatId, String transferId, FileTransfer.State state,\n            FileTransfer.ReasonCode reasonCode);\n\n    /**\n     * Callback called when a group file transfer state/reasonCode is changed for a single recipient\n     * only.\n     *\n     * @param chatId Id of chat\n     * @param contact Contact ID\n     * @param transferId Id of file transfer\n     * @param status state of file transfer after change\n     * @param reasonCode Reason code of state after change\n     */\n    public abstract void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n            GroupDeliveryInfo.Status status, GroupDeliveryInfo.ReasonCode reasonCode);\n\n    /**\n     * Callback called during the transfer progress of group file transfer\n     *\n     * @param chatId Id of chat\n     * @param transferId Id of file transfer\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size to transfer in bytes\n     */\n    public abstract void onProgressUpdate(String chatId, String transferId, long currentSize,\n            long totalSize);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several group\n     * file transfers was deleted specified by the transferIds parameter corresponding to a specific\n     * group chat.\n     *\n     * @param chatId id of the chat\n     * @param transferIds ids of those deleted file transfers\n     */\n    public abstract void onDeleted(String chatId, Set<String> transferIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/GroupFileTransferListenerImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Group file transfer event listener implementation\n *\n * @hide\n */\npublic class GroupFileTransferListenerImpl extends IGroupFileTransferListener.Stub {\n\n    private final GroupFileTransferListener mListener;\n\n    private final static String LOG_TAG = GroupFileTransferListenerImpl.class.getName();\n\n    GroupFileTransferListenerImpl(GroupFileTransferListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(String chatId, String transferId, int state, int reasonCode) {\n        FileTransfer.State rcsState;\n        FileTransfer.ReasonCode rcsReasonCode;\n        try {\n            rcsState = FileTransfer.State.valueOf(state);\n            rcsReasonCode = FileTransfer.ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(chatId, transferId, rcsState, rcsReasonCode);\n    }\n\n    @Override\n    public void onProgressUpdate(String chatId, String transferId, long currentSize, long totalSize) {\n        mListener.onProgressUpdate(chatId, transferId, currentSize, totalSize);\n    }\n\n    public void onDeliveryInfoChanged(String chatId, ContactId contact, String transferId,\n            int status, int reasonCode) {\n        GroupDeliveryInfo.Status rcsStatus;\n        GroupDeliveryInfo.ReasonCode rcsReasonCode;\n        try {\n            rcsStatus = GroupDeliveryInfo.Status.valueOf(status);\n            rcsReasonCode = GroupDeliveryInfo.ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n\n        mListener.onDeliveryInfoChanged(chatId, contact, transferId, rcsStatus, rcsReasonCode);\n    }\n\n    /**\n     * This feature to be implemented in CR005\n     */\n    @Override\n    public void onDeleted(String chatId, List<String> transferIds) throws RemoteException {\n        mListener.onDeleted(chatId, new HashSet<>(transferIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/OneToOneFileTransferListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport java.util.Set;\n\n/**\n * One-To-One File transfer event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class OneToOneFileTransferListener {\n\n    /**\n     * Callback called when the file transfer state/reasonCode is changed.\n     * \n     * @param contact Contact ID\n     * @param transferId Id of file transfer\n     * @param state State of the file transfer\n     * @param reasonCode Reason code\n     */\n    public abstract void onStateChanged(ContactId contact, String transferId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Callback called during the file transfer progress.\n     * \n     * @param contact Contact ID\n     * @param transferId Id of file transfer\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size to transfer in bytes\n     */\n    public abstract void onProgressUpdate(ContactId contact, String transferId, long currentSize,\n            long totalSize);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several one to\n     * one file transfers was deleted specified by the transferIds parameter corresponding to a\n     * specific contact.\n     *\n     * @param contact Contact ID\n     * @param transferIds ids of those deleted file transfers\n     */\n    public abstract void onDeleted(ContactId contact, Set<String> transferIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/OneToOneFileTransferListenerImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.filetransfer;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode;\nimport com.gsma.services.rcs.filetransfer.FileTransfer.State;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * File transfer event listener\n * \n * @hide\n */\npublic class OneToOneFileTransferListenerImpl extends IOneToOneFileTransferListener.Stub {\n\n    private final OneToOneFileTransferListener mListener;\n\n    private final static String LOG_TAG = OneToOneFileTransferListenerImpl.class.getName();\n\n    OneToOneFileTransferListenerImpl(OneToOneFileTransferListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(ContactId contact, String transferId, int state, int reasonCode) {\n        State rcsState;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsState = State.valueOf(state);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(contact, transferId, rcsState, rcsReasonCode);\n    }\n\n    public void onProgressUpdate(ContactId contact, String transferId, long currentSize,\n            long totalSize) {\n        mListener.onProgressUpdate(contact, transferId, currentSize, totalSize);\n    }\n\n    /**\n     * This feature to be implemented in CR005\n     */\n    @Override\n    public void onDeleted(ContactId contact, List<String> transferIds) throws RemoteException {\n        mListener.onDeleted(contact, new HashSet<>(transferIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/filetransfer/package-info.java",
    "content": "/**\n * This API exposes all functionality to transfer files in real time.\n * <p>\n */\n\npackage com.gsma.services.rcs.filetransfer;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/groupdelivery/GroupDeliveryInfo.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.groupdelivery;\n\nimport android.util.SparseArray;\n\n/**\n * Delivery info (delivery information on group messages and group file transfers)\n */\npublic class GroupDeliveryInfo {\n\n    /**\n     * Status of the group delivery info\n     */\n    public enum Status {\n\n        /**\n         * Delivery notifications were unsupported at the time the message or file-transfer was sent\n         * and no delivery notification has been requested.\n         */\n        UNSUPPORTED(0),\n        /**\n         * The message or file-transfer has not received any delivery report for the specified\n         * contact.\n         */\n        NOT_DELIVERED(1),\n\n        /**\n         * The message or file-transfer has received a delivery report for the specified contact\n         */\n        DELIVERED(2),\n\n        /**\n         * The message or file-transfer has received a displayed report for the specified contact.\n         */\n        DISPLAYED(3),\n\n        /**\n         * The message or file-transfer has received a delivery report failure for the specified\n         * contact.\n         */\n        FAILED(4);\n\n        private final int mValue;\n\n        private static SparseArray<Status> mValueToEnum = new SparseArray<>();\n        static {\n            for (Status entry : Status.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        Status(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static Status valueOf(int value) {\n            Status entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + Status.class.getName() + \"\"\n                    + value);\n        }\n    }\n\n    /**\n     * Group chat delivery status reason\n     */\n    public enum ReasonCode {\n\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * A delivered-error delivery report has been received.\n         */\n        FAILED_DELIVERY(1),\n\n        /**\n         * A displayed-error delivery report has been received.\n         */\n        FAILED_DISPLAY(2);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value);\n        }\n    }\n\n    private GroupDeliveryInfo() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/groupdelivery/GroupDeliveryInfoLog.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.groupdelivery;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Delivery info (delivery information on group messages and group file transfers)\n */\npublic class GroupDeliveryInfoLog {\n\n    /**\n     * Content provider URI for Group Delivery Info\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.groupdeliveryinfo/groupdeliveryinfo\");\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the status of a group delivery info.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String STATUS = \"status\";\n\n    /**\n     * The name of the column containing the reason code of a group delivery info.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String REASON_CODE = \"reason_code\";\n\n    /**\n     * The name of the column containing the unique ID of the chat message (\"msg_id\") or file\n     * transfer (\"ft_id\").\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String ID = \"id\";\n\n    /**\n     * The name of the column containing the unique ID of the group chat.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CHAT_ID = \"chat_id\";\n\n    /**\n     * ContactId formatted number of the inviter of the group chat or the group file transfer.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the time when message or file transfer notification is\n     * displayed.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_DELIVERED = \"timestamp_delivered\";\n\n    /**\n     * The name of the column containing the time when message is displayed or file transfer is done\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_DISPLAYED = \"timestamp_displayed\";\n\n    private GroupDeliveryInfoLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/history/HistoryLog.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.history;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Content provider for history log\n */\npublic class HistoryLog {\n\n    /**\n     * Content provider URI for history log\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.history/history\");\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the provider the entry originates from.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String PROVIDER_ID = \"provider_id\";\n\n    /**\n     * The name of the column containing the entry ID.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String ID = \"id\";\n\n    /**\n     * The name of the column containing the MIME-type.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String MIME_TYPE = \"mime_type\";\n\n    /**\n     * The name of the column containing the disposition.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String DISPOSITION = \"disposition\";\n\n    /**\n     * The name of the column containing the direction.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String DIRECTION = \"direction\";\n\n    /**\n     * The name of the column containing the ContactId formatted number.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the time when the entry was inserted.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP = \"timestamp\";\n\n    /**\n     * The name of the column containing the time when the entry was sent. 0 means not sent.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_SENT = \"timestamp_sent\";\n\n    /**\n     * The name of the column containing the time when the entry was delivered. 0 means not\n     * delivered.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_DELIVERED = \"timestamp_delivered\";\n\n    /**\n     * The name of the column containing the time when the entry was displayed. 0 means not\n     * displayed.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP_DISPLAYED = \"timestamp_displayed\";\n\n    /**\n     * The name of the column denoting if delivery has expired for this file. Values: 1 (true), 0\n     * (false)\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String EXPIRED_DELIVERY = \"expired_delivery\";\n\n    /**\n     * The name of the column containing the status (or state).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String STATUS = \"status\";\n\n    /**\n     * The name of the column containing the reason code associated with the entry status.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String REASON_CODE = \"reason_code\";\n\n    /**\n     * The name of the column containing the read status of the event.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String READ_STATUS = \"read_status\";\n\n    /**\n     * The name of the column containing the chat ID.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CHAT_ID = \"chat_id\";\n\n    /**\n     * The name of the column containing the content of the message if this entry corresponds to a\n     * content message or the file URI if this entry is a file transfer, image share, video share\n     * etc.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTENT = \"content\";\n\n    /**\n     * The name of the column containing the file icon URI.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILEICON = \"fileicon\";\n\n    /**\n     * The name of the column containing the file icon MIME-type.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILEICON_MIME_TYPE = \"fileicon_mime_type\";\n\n    /**\n     * The name of the column containing the filename of a file transfer.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILENAME = \"filename\";\n\n    /**\n     * The name of the column containing the file size of a file transfer.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String FILESIZE = \"filesize\";\n\n    /**\n     * The name of the column containing the transferred amount of data (in bytes).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TRANSFERRED = \"transferred\";\n\n    /**\n     * The name of the column containing the duration of a call or sharing (in milliseconds).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String DURATION = \"duration\";\n\n    private HistoryLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/history/HistoryService.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.history;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.net.Uri;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.util.Map;\n\n/**\n * History service offers the entry point to register and unregister extra history log provider\n * members to the API.\n */\npublic final class HistoryService extends RcsService {\n\n    private IHistoryService mService;\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public HistoryService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the history service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the history service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IHistoryService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set service interface\n     * \n     * @param service Service interface\n     * @hide\n     */\n    protected void setApi(IInterface service) {\n        super.setApi(service);\n        mService = (IHistoryService) service;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IHistoryService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Registers an external history log member.\n     * \n     * @param providerId Provider ID of history log member\n     * @param providerUri Provider Uri\n     * @param database URI of database to register\n     * @param table Name of table to register\n     * @param columnMapping Translator of internal field names to history log provider field names\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void registerExtraHistoryLogMember(int providerId, Uri providerUri, Uri database,\n            String table, Map<String, String> columnMapping)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mService == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mService.registerExtraHistoryLogMember(providerId, providerUri, database, table,\n                    columnMapping);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Unregisters an external history log member.\n     * \n     * @param providerId Provider ID of history log member\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void unregisterExtraHistoryLogMember(int providerId)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mService == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mService.unregisterExtraHistoryLogMember(providerId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Creates an id that will be unique across all tables in the base column \"_id\".\n     * \n     * @param providerId of the provider that requires the generated id for its table\n     * @return long the generated id as long\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public long createUniqueId(int providerId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mService == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mService.createUniqueId(providerId);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/history/HistoryUriBuilder.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.history;\n\nimport android.net.Uri;\n\n/**\n * Utility builder class to generate the uri used to query the History provider.\n */\npublic class HistoryUriBuilder {\n\n    private final Uri.Builder mUriBuilder;\n\n    public HistoryUriBuilder(Uri historyLogUri) {\n        mUriBuilder = historyLogUri.buildUpon();\n    }\n\n    /**\n     * Add the provider ids that will be part of the query.\n     * \n     * @param providerId the provider ID\n     * @return the builder\n     */\n    public HistoryUriBuilder appendProvider(int providerId) {\n        mUriBuilder.appendQueryParameter(HistoryLog.PROVIDER_ID, String.valueOf(providerId));\n        return this;\n    }\n\n    /**\n     * Creates and returns the uri that contains the provider id parameters.\n     * \n     * @return the generated uri\n     */\n    public Uri build() {\n        return mUriBuilder.build();\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/package-info.java",
    "content": "/**\n * The RCS service is implemented into an Android background service\n * which offers a high level API: the RCS Terminal API.\n * <p>\n * The RCS API is a client/server interface based on database\n * providers, AIDL API & Intents. Several UI may be connected at a time\n * to manage RCS events and to interact with the single stack instance\n * running in background.\n * <p>\n * The RCS API permits to implement RCS application (e.g. enhanced\n * address book, content sharing app, chat view, widgets) by hiding RCS\n * protocols complexity.\n * <p>\n * The RCS API offers the following service API:<br>\n * - Capability API: contact capabilities discovery.<br>\n * - Chat API: 1-1 chat and group chat.<br>\n * - File Transfer API: transfer a file.<br>\n * - Video Share API: live video sharing during a CS call.<br>\n * - Image Share API: image sharing during a CS call.<br>\n * - UX API: links third party applications with RCS applications.<br>\n * <p>\n * The RCS API uses the following Android concepts:<br>\n * - Intents mechanism to broadcast incoming events (e.g. notification) and\n * incoming invitations to any Android activity or broadcast receiver which are\n * declared in the device.<br>\n * - AIDL interfaces to initiate and to manage session in real time (start,\n * session monitoring, stop). Session events are managed thanks to callback mechanism.<br>\n * <p>\n * Note: Methods of the RCS API throw an exception if the RCS service is not available, not\n * initialized or not registered to the IMS platform.\n * <p>\n * Note: Remote application exceptions are not yet supported by the\n * AIDL SDK, a generic AIDL exception is thrown instead.\n * <p>\n * Note: The supported formats for a contact used as a method parameter are:<br>\n * - Phone number in national or international format (e.g. +33xxx).<br>\n * - SIP address (e.g. \"John\" <sip:+33xxx@domain.com>).<br>\n * - SIP-URI (e.g. sip:+33xxx@domain.com).<br>\n * - Tel-URI (e.g. tel:+33xxx).<br>\n */\n\npackage com.gsma.services.rcs;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/GeolocSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.SparseArray;\n\n/**\n * Geoloc sharing\n * \n * @author Philippe LEMRODANT\n */\npublic class GeolocSharing {\n\n    /**\n     * Geoloc sharing state\n     */\n    public enum State {\n\n        /**\n         * Sharing invitation received\n         */\n        INVITED(0),\n\n        /**\n         * Sharing invitation sent\n         */\n        INITIATING(1),\n\n        /**\n         * Sharing is started\n         */\n        STARTED(2),\n\n        /**\n         * Sharing has been aborted\n         */\n        ABORTED(3),\n\n        /**\n         * Sharing has failed\n         */\n        FAILED(4),\n\n        /**\n         * Sharing has been transferred\n         */\n        TRANSFERRED(5),\n\n        /**\n         * Sharing invitation was rejected\n         */\n        REJECTED(6),\n\n        /**\n         * Call ringing\n         */\n        RINGING(7),\n\n        /**\n         * Sharing has been accepted and is in the process of becoming started\n         */\n        ACCEPTING(8);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State entry : State.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static State valueOf(int value) {\n            State entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n    }\n\n    /**\n     * Reason code\n     */\n    public enum ReasonCode {\n\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * Geolocation share is aborted by local user.\n         */\n        ABORTED_BY_USER(1),\n\n        /**\n         * Geolocation share is aborted by remote user.\n         */\n        ABORTED_BY_REMOTE(2),\n\n        /**\n         * Geolocation share is aborted by system.\n         */\n        ABORTED_BY_SYSTEM(3),\n\n        /**\n         * Geolocation share is rejected because already taken by the secondary device.\n         */\n        REJECTED_BY_SECONDARY_DEVICE(4),\n\n        /**\n         * Geolocation share invitation was rejected because it is spam.\n         */\n        REJECTED_SPAM(5),\n\n        /**\n         * Geolocation share invitation was rejected due to to many open sharing sessions.\n         */\n        REJECTED_MAX_SHARING_SESSIONS(6),\n\n        /**\n         * Geolocation share invitation was rejected by local user.\n         */\n        REJECTED_BY_USER(7),\n\n        /**\n         * Geolocation share invitation was rejected by remote.\n         */\n        REJECTED_BY_REMOTE(8),\n\n        /**\n         * Geolocation share invitation was rejected by timeout.\n         */\n        REJECTED_BY_TIMEOUT(9),\n\n        /**\n         * Geolocation share invitation was rejected by system.\n         */\n        REJECTED_BY_SYSTEM(10),\n\n        /**\n         * Geolocation share initiation failed.\n         */\n        FAILED_INITIATION(11),\n\n        /**\n         * Sharing of the geolocation has failed.\n         */\n        FAILED_SHARING(12);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Geoloc sharing interface\n     */\n    private IGeolocSharing mSharingInf;\n\n    /**\n     * Constructor\n     * \n     * @param sharingInf Geoloc sharing interface\n     */\n    /* package private */GeolocSharing(IGeolocSharing sharingInf) {\n        mSharingInf = sharingInf;\n    }\n\n    /**\n     * Returns the sharing ID of the geoloc sharing\n     * \n     * @return String Sharing ID\n     * @throws RcsGenericException\n     */\n    public String getSharingId() throws RcsGenericException {\n        try {\n            return mSharingInf.getSharingId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getRemoteContact();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the geolocation info\n     * \n     * @return Geoloc object\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see Geoloc\n     */\n    public Geoloc getGeoloc() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getGeoloc();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the sharing\n     * \n     * @return State\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see State\n     */\n    public State getState() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return State.valueOf(mSharingInf.getState());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the sharing\n     * \n     * @return ReasonCode\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see ReasonCode\n     */\n    public ReasonCode getReasonCode() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mSharingInf.getReasonCode());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the sharing\n     * \n     * @return Direction\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see Direction\n     */\n    public Direction getDirection() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Direction.valueOf(mSharingInf.getDirection());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the geoloc sharing was initiated for outgoing geoloc\n     * sharing or the local timestamp of when the geoloc sharing invitation was received for\n     * incoming geoloc sharings.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestamp() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getTimestamp();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts geoloc sharing invitation\n     * \n     * @throws RcsGenericException\n     */\n    public void acceptInvitation() throws RcsGenericException {\n        try {\n            mSharingInf.acceptInvitation();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Rejects geoloc sharing invitation\n     * \n     * @throws RcsGenericException\n     */\n    public void rejectInvitation() throws RcsGenericException {\n        try {\n            mSharingInf.rejectInvitation();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the sharing\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void abortSharing() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSharingInf.abortSharing();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/GeolocSharingIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\n/**\n * Intent for geoloc sharing invitations\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GeolocSharingIntent {\n    /**\n     * Broadcast action: a new geoloc sharing invitation has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_SHARING_ID} containing the unique ID of the geoloc sharing.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.sharing.geoloc.action.NEW_GEOLOC_SHARING\";\n\n    /**\n     * Unique ID of the geoloc sharing\n     */\n    public final static String EXTRA_SHARING_ID = \"sharingId\";\n\n    private GeolocSharingIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/GeolocSharingListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\n\nimport java.util.Set;\n\n/**\n * Geoloc sharing event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class GeolocSharingListener {\n    /**\n     * Callback called when the geoloc sharing state changes\n     * \n     * @param contact Contact ID\n     * @param sharingId ID of geoloc sharing\n     * @param state State of image sharing\n     * @param reasonCode Reason code of geoloc sharing state\n     */\n    public abstract void onStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Callback called during the sharing progress\n     * \n     * @param contact Contact ID\n     * @param sharingId ID of geoloc sharing\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size to transfer in bytes\n     */\n    public abstract void onProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several geoloc\n     * sharings was deleted specified by the sharingIds parameter corresponding to a specific\n     * contact.\n     *\n     * @param contact Contact ID\n     * @param sharingIds ids of those deleted geoloc sharing\n     */\n    public abstract void onDeleted(ContactId contact, Set<String> sharingIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/GeolocSharingListenerImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Geoloc sharing event listener implementation\n * \n * @hide\n */\npublic class GeolocSharingListenerImpl extends IGeolocSharingListener.Stub {\n\n    private final GeolocSharingListener mListener;\n\n    private final static String LOG_TAG = GeolocSharingListenerImpl.class.getName();\n\n    GeolocSharingListenerImpl(GeolocSharingListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(ContactId contact, String chatId, int state, int reasonCode) {\n        State rcsState;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsState = State.valueOf(state);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(contact, chatId, rcsState, rcsReasonCode);\n    }\n\n    @Override\n    public void onProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize) throws RemoteException {\n        mListener.onProgressUpdate(contact, sharingId, currentSize, totalSize);\n    }\n\n    @Override\n    public void onDeleted(ContactId contact, List<String> sharingIds) throws RemoteException {\n        mListener.onDeleted(contact, new HashSet<>(sharingIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/GeolocSharingLog.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Content provider for geoloc sharing history\n */\npublic class GeolocSharingLog {\n\n    /**\n     * Content provider URI for geoloc sharings\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.geolocshare/geolocshare\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = 5;\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the unique sharing ID.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String SHARING_ID = \"sharing_id\";\n\n    /**\n     * The name of the column containing the ContactId formatted number of the remote contact.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the geolocation stored as a String that you can pass as an\n     * argument to the Geoloc constructor.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTENT = \"content\";\n\n    /**\n     * The name of the column containing the MIME-type of the geoloc sharing.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String MIME_TYPE = \"mime_type\";\n\n    /**\n     * The name of the column containing the geoloc sharing direction.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String DIRECTION = \"direction\";\n\n    /**\n     * The name of the column containing the time when geoloc sharing is created.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP = \"timestamp\";\n\n    /**\n     * The name of the column containing the geoloc sharing state.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String STATE = \"state\";\n\n    /**\n     * The name of the column containing the reason code associated with the geoloc sharing state.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String REASON_CODE = \"reason_code\";\n\n    private GeolocSharingLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/GeolocSharingService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\nimport com.gsma.services.rcs.Geoloc;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\n/**\n * This class offers the main entry point to share geolocation info during a CS call. Several\n * applications may connect/disconnect to the API. The parameter contact in the API supports the\n * following formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class GeolocSharingService extends RcsService {\n    /**\n     * API\n     */\n    private IGeolocSharingService mApi;\n\n    private final Map<GeolocSharingListener, WeakReference<IGeolocSharingListener>> mGeolocSharingListeners = new WeakHashMap<GeolocSharingListener, WeakReference<IGeolocSharingListener>>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public GeolocSharingService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the geoloc sharing service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the geoloc sharing service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IGeolocSharingService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IGeolocSharingService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IGeolocSharingService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Shares a geolocation with a contact. An exception if thrown if there is no ongoing CS call.\n     * The parameter contact supports the following formats: MSISDN in national or international\n     * format, SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an\n     * exception is thrown.\n     * \n     * @param contact Contact identifier\n     * @param geoloc Geolocation info\n     * @return GeolocSharing\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     * @see Geoloc\n     */\n    public GeolocSharing shareGeoloc(ContactId contact, Geoloc geoloc)\n            throws RcsServiceNotRegisteredException, RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IGeolocSharing sharingIntf = mApi.shareGeoloc(contact, geoloc);\n            if (sharingIntf != null) {\n                return new GeolocSharing(sharingIntf);\n\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current geoloc sharing from its unique ID\n     * \n     * @param sharingId Sharing ID\n     * @return GeolocSharing Geoloc sharing or null if not found\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public GeolocSharing getGeolocSharing(String sharingId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new GeolocSharing(mApi.getGeolocSharing(sharingId));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all geoloc sharing from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGeolocSharings() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGeolocSharings();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes geoloc sharing with a given contact from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGeolocSharings(ContactId contact) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGeolocSharings2(contact);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes a geoloc sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId the sharing ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteGeolocSharing(String sharingId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteGeolocSharing(sharingId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on geoloc sharing events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(GeolocSharingListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IGeolocSharingListener rcsListener = new GeolocSharingListenerImpl(listener);\n            mGeolocSharingListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener2(rcsListener);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on geoloc sharing events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(GeolocSharingListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IGeolocSharingListener> weakRef = mGeolocSharingListeners\n                    .remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IGeolocSharingListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener2(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/geoloc/package-info.java",
    "content": "/**\n * This API exposes exposes all functionality related to share geolocations during a CS call.\n * <p>\n */\n\npackage com.gsma.services.rcs.sharing.geoloc;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.net.Uri;\nimport android.util.SparseArray;\n\n/**\n * Image sharing\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ImageSharing {\n\n    /**\n     * Image sharing state\n     */\n    public enum State {\n\n        /**\n         * Sharing invitation received\n         */\n        INVITED(0),\n\n        /**\n         * Sharing invitation sent\n         */\n        INITIATING(1),\n\n        /**\n         * Sharing is started\n         */\n        STARTED(2),\n\n        /**\n         * Sharing has been aborted\n         */\n        ABORTED(3),\n\n        /**\n         * Sharing has failed\n         */\n        FAILED(4),\n\n        /**\n         * Image has been transferred with success\n         */\n        TRANSFERRED(5),\n\n        /**\n         * Sharing has been rejected\n         */\n        REJECTED(6),\n\n        /**\n         * Ringing\n         */\n        RINGING(7),\n\n        /**\n         * Sharing has been accepted and is in the process of becoming started\n         */\n        ACCEPTING(8);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State entry : State.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static State valueOf(int value) {\n            State entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n    }\n\n    /**\n     * Reason code associated with the image share state.\n     */\n    public enum ReasonCode {\n\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * Image share is aborted by local user.\n         */\n        ABORTED_BY_USER(1),\n\n        /**\n         * Image share is aborted by remote user.\n         */\n        ABORTED_BY_REMOTE(2),\n\n        /**\n         * Image share is aborted by system.\n         */\n        ABORTED_BY_SYSTEM(3),\n\n        /**\n         * Image share is rejected because already taken by the secondary device.\n         */\n        REJECTED_BY_SECONDARY_DEVICE(4),\n\n        /**\n         * Incoming image was rejected because it is spam.\n         */\n        REJECTED_SPAM(5),\n\n        /**\n         * Incoming image was rejected by timeout.\n         */\n        REJECTED_BY_TIMEOUT(6),\n\n        /**\n         * Incoming image was rejected as is cannot be received due to lack of local storage space.\n         */\n        REJECTED_LOW_SPACE(7),\n\n        /**\n         * Incoming image was rejected as it was too big to be received.\n         */\n        REJECTED_MAX_SIZE(8),\n\n        /**\n         * Incoming image was rejected because max number of sharing sessions is achieved.\n         */\n        REJECTED_MAX_SHARING_SESSIONS(9),\n\n        /**\n         * Incoming image was rejected by local user.\n         */\n        REJECTED_BY_USER(10),\n\n        /**\n         * Incoming image was rejected by remote.\n         */\n        REJECTED_BY_REMOTE(11),\n\n        /**\n         * Incoming image was rejected by system.\n         */\n        REJECTED_BY_SYSTEM(12),\n\n        /**\n         * Image share initiation failed;\n         */\n        FAILED_INITIATION(13),\n\n        /**\n         * Sharing of the image share has failed.\n         */\n        FAILED_SHARING(14),\n\n        /**\n         * Saving of the image share has failed.\n         */\n        FAILED_SAVING(15);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Image sharing interface\n     */\n    private final IImageSharing mSharingInf;\n\n    /**\n     * Constructor\n     * \n     * @param sharingInf Image sharing interface\n     */\n    /* package private */ImageSharing(IImageSharing sharingInf) {\n        mSharingInf = sharingInf;\n    }\n\n    /**\n     * Returns the sharing ID of the image sharing\n     * \n     * @return String Sharing ID\n     * @throws RcsGenericException\n     */\n    public String getSharingId() throws RcsGenericException {\n        try {\n            return mSharingInf.getSharingId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getRemoteContact();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the URI of the file to be shared\n     * \n     * @return Uri\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public Uri getFile() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getFile();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the complete filename including the path of the file to be transferred\n     * \n     * @return String Filename\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getFileName() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getFileName();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the size of the file to be transferred\n     * \n     * @return long Size in bytes\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getFileSize() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getFileSize();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the MIME type of the file to be transferred\n     * \n     * @return String Type\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getMimeType() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getMimeType();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the image sharing was initiated for outgoing image\n     * sharing or the local timestamp of when the image sharing invitation was received for incoming\n     * image sharings.\n     * \n     * @return long\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestamp() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getTimestamp();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the sharing\n     * \n     * @return State\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see ImageSharing.State\n     */\n    public State getState() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return State.valueOf(mSharingInf.getState());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the state of the sharing\n     * \n     * @return ReasonCode\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see ImageSharing.ReasonCode\n     */\n    public ReasonCode getReasonCode() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mSharingInf.getReasonCode());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the sharing\n     * \n     * @return Direction\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see Direction\n     */\n    public Direction getDirection() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Direction.valueOf(mSharingInf.getDirection());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts image sharing invitation\n     * \n     * @throws RcsGenericException\n     */\n    public void acceptInvitation() throws RcsGenericException {\n        try {\n            mSharingInf.acceptInvitation();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Rejects image sharing invitation\n     * \n     * @throws RcsGenericException\n     */\n    public void rejectInvitation() throws RcsGenericException {\n        try {\n            mSharingInf.rejectInvitation();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the sharing\n     * \n     * @throws RcsPermissionDeniedException\n     * @throws RcsGenericException\n     */\n    public void abortSharing() throws RcsPermissionDeniedException, RcsGenericException {\n        try {\n            mSharingInf.abortSharing();\n        } catch (Exception e) {\n            RcsPermissionDeniedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharingIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.image;\n\n/**\n * Intent for image sharing invitations\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ImageSharingIntent {\n    /**\n     * Broadcast action: a new image sharing invitation has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_SHARING_ID} containing the unique ID of the image sharing.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.sharing.image.action.NEW_IMAGE_SHARING\";\n\n    /**\n     * Unique ID of the image sharing\n     */\n    public final static String EXTRA_SHARING_ID = \"sharingId\";\n\n    private ImageSharingIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharingListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport java.util.Set;\n\n/**\n * Image sharing event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class ImageSharingListener {\n    /**\n     * Callback called when the image sharing state/reasonCode has been changed.\n     * \n     * @param contact Contact ID\n     * @param sharingId ID of image sharing\n     * @param state State of image sharing\n     * @param reasonCode Reason code of the image sharing state\n     */\n    public abstract void onStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Callback called during the sharing progress.\n     * \n     * @param contact Contact ID\n     * @param sharingId ID of image sharing\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size to transfer in bytes\n     */\n    public abstract void onProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several image\n     * sharings was deleted specified by the sharingIds parameter corresponding to a specific\n     * contact.\n     *\n     * @param contact Contact ID\n     * @param sharingIds ids of those deleted image sharing\n     */\n    public abstract void onDeleted(ContactId contact, Set<String> sharingIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharingListenerImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.image.ImageSharing.State;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * ImageSharing event listener implementation\n * \n * @hide\n */\npublic class ImageSharingListenerImpl extends IImageSharingListener.Stub {\n\n    private final ImageSharingListener mListener;\n\n    private final static String LOG_TAG = ImageSharingListenerImpl.class.getName();\n\n    ImageSharingListenerImpl(ImageSharingListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(ContactId contact, String sharingId, int state, int reasonCode) {\n        State rcsStatus;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsStatus = State.valueOf(state);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(contact, sharingId, rcsStatus, rcsReasonCode);\n    }\n\n    @Override\n    public void onProgressUpdate(ContactId contact, String sharingId, long currentSize,\n            long totalSize) throws RemoteException {\n        mListener.onProgressUpdate(contact, sharingId, currentSize, totalSize);\n\n    }\n\n    @Override\n    public void onDeleted(ContactId contact, List<String> sharingIds) throws RemoteException {\n        mListener.onDeleted(contact, new HashSet<>(sharingIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharingLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.RcsService.Direction;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Content provider for image sharing history\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ImageSharingLog {\n    /**\n     * Content provider URI\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.imageshare/imageshare\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = 3;\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the unique ID of the image sharing.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String SHARING_ID = \"sharing_id\";\n\n    /**\n     * The name of the column containing the MSISDN of the remote contact.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the URI of the file.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILE = \"file\";\n\n    /**\n     * The name of the column containing the filename (absolute path).\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String FILENAME = \"filename\";\n\n    /**\n     * The name of the column containing the image size to be transferred (in bytes).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String FILESIZE = \"filesize\";\n\n    /**\n     * The name of the column containing the MIME-type of the file.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String MIME_TYPE = \"mime_type\";\n\n    /**\n     * The name of the column containing the direction of the sharing.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see Direction\n     */\n    public static final String DIRECTION = \"direction\";\n\n    /**\n     * The name of the column containing the amount of data transferred (in bytes).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TRANSFERRED = \"transferred\";\n\n    /**\n     * The name of the column containing the date of the sharing (in milliseconds).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP = \"timestamp\";\n\n    /**\n     * The name of the column containing the state of the sharing.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see ImageSharing.State\n     */\n    public static final String STATE = \"state\";\n\n    /**\n     * The name of the column containing the reason code of the state.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see ImageSharing.ReasonCode\n     */\n    public static final String REASON_CODE = \"reason_code\";\n\n    private ImageSharingLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharingService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ComponentName;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\n/**\n * This class offers the main entry point to transfer image during a CS call. Several applications\n * may connect/disconnect to the API. The parameter contact in the API supports the following\n * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class ImageSharingService extends RcsService {\n\n    /**\n     * API\n     */\n    private IImageSharingService mApi;\n\n    private final Map<ImageSharingListener, WeakReference<IImageSharingListener>> mImageSharingListeners = new WeakHashMap<>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public ImageSharingService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the image sharing service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the image sharing service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IImageSharingService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IImageSharingService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IImageSharingService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Granting temporary read Uri permission from client to stack service if it is a content URI\n     * \n     * @param file Uri of file to grant permission\n     */\n    private void tryToGrantUriPermissionToStackServices(Uri file) {\n        if (!ContentResolver.SCHEME_CONTENT.equals(file.getScheme())) {\n            return;\n        }\n        Intent fileTransferServiceIntent = new Intent(IImageSharingService.class.getName());\n        List<ResolveInfo> stackServices = mCtx.getPackageManager().queryIntentServices(\n                fileTransferServiceIntent, 0);\n        for (ResolveInfo stackService : stackServices) {\n            mCtx.grantUriPermission(stackService.serviceInfo.packageName, file,\n                    Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        }\n    }\n\n    /**\n     * Returns the configuration of image sharing service\n     * \n     * @return ImageSharingServiceConfiguration\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public ImageSharingServiceConfiguration getConfiguration()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new ImageSharingServiceConfiguration(mApi.getConfiguration());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Shares an image with a contact. The parameter file contains the URI of the image to be shared\n     * (for a local or a remote image). An exception if thrown if there is no ongoing CS call. The\n     * parameter contact supports the following formats: MSISDN in national or international format,\n     * SIP address, SIP-URI or Tel-URI. If the format of the contact is not supported an exception\n     * is thrown.\n     * \n     * @param contact Contact identifier\n     * @param file Uri of file to share\n     * @return ImageSharing\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public ImageSharing shareImage(ContactId contact, Uri file)\n            throws RcsServiceNotRegisteredException, RcsPersistentStorageException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            /* Only grant permission for content Uris */\n            tryToGrantUriPermissionToStackServices(file);\n            IImageSharing sharingIntf = mApi.shareImage(contact, file);\n            if (sharingIntf != null) {\n                return new ImageSharing(sharingIntf);\n\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current image sharing from its unique ID\n     * \n     * @param sharingId Sharing ID\n     * @return ImageSharing Image sharing or null if not found\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public ImageSharing getImageSharing(String sharingId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new ImageSharing(mApi.getImageSharing(sharingId));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on image sharing events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(ImageSharingListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IImageSharingListener rcsListener = new ImageSharingListenerImpl(listener);\n            mImageSharingListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener2(rcsListener);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on image sharing events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(ImageSharingListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IImageSharingListener> weakRef = mImageSharingListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IImageSharingListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener2(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all image sharing from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteImageSharings() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteImageSharings();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes image sharing with a given contact from history and abort/reject any associated\n     * ongoing session if such exists\n     * \n     * @param contact The remote contact\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteImageSharings(ContactId contact) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteImageSharings2(contact);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * deletes an image sharing by its sharing id from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId the sharing ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteImageSharing(String sharingId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteImageSharing(sharingId);\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/ImageSharingServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.image;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\n/**\n * Image sharing service configuration\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class ImageSharingServiceConfiguration {\n\n    IImageSharingServiceConfiguration mConfiguration;\n\n    /**\n     * Constructor\n     * \n     * @param configuration the Image sharing configuration\n     */\n    /* package private */ImageSharingServiceConfiguration(\n            IImageSharingServiceConfiguration configuration) {\n        mConfiguration = configuration;\n    }\n\n    /**\n     * Returns the maximum authorized size of the image that can be sent. It returns 0 if there is\n     * no limitation.\n     * \n     * @return long Size in bytes\n     * @throws RcsGenericException\n     */\n    public long getMaxSize() throws RcsGenericException {\n        try {\n            return mConfiguration.getMaxSize();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/image/package-info.java",
    "content": "/**\n * This API exposes exposes all functionality related to transfer images during a CS call.\n * <p>\n */\n\npackage com.gsma.services.rcs.sharing.image;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoCodec.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * Video codec\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoCodec implements Parcelable {\n    /**\n     * Video encoding\n     */\n    private final String mEncoding;\n\n    /**\n     * Payload\n     */\n    private final int mPayload;\n\n    /**\n     * Clock rate\n     */\n    private final int mClockRate;\n\n    /**\n     * Frame rate\n     */\n    private final int mFrameRate;\n\n    /**\n     * Bit rate\n     */\n    private final int mBitRate;\n\n    /**\n     * Video frame width\n     */\n    private final int mWidth;\n\n    /**\n     * Video frame height\n     */\n    private final int mHeight;\n\n    /**\n     * Video parameters\n     */\n    private final String mParameters;\n\n    /**\n     * Constructor\n     * \n     * @param encoding Video encoding\n     * @param payload Payload\n     * @param clockRate Clock rate\n     * @param frameRate Frame rate\n     * @param bitRate Bit rate\n     * @param width Video width\n     * @param height Video height\n     * @param parameters Codec parameters\n     * @hide\n     */\n    public VideoCodec(String encoding, int payload, int clockRate, int frameRate, int bitRate,\n            int width, int height, String parameters) {\n        mEncoding = encoding;\n        mPayload = payload;\n        mClockRate = clockRate;\n        mFrameRate = frameRate;\n        mBitRate = bitRate;\n        mWidth = width;\n        mHeight = height;\n        mParameters = parameters;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     * @hide\n     */\n    public VideoCodec(Parcel source) {\n        mEncoding = source.readString();\n        mPayload = source.readInt();\n        mClockRate = source.readInt();\n        mFrameRate = source.readInt();\n        mBitRate = source.readInt();\n        mWidth = source.readInt();\n        mHeight = source.readInt();\n        mParameters = source.readString();\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation\n     * \n     * @return Integer\n     * @hide\n     */\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object\n     * \n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mEncoding);\n        dest.writeInt(mPayload);\n        dest.writeInt(mClockRate);\n        dest.writeInt(mFrameRate);\n        dest.writeInt(mBitRate);\n        dest.writeInt(mWidth);\n        dest.writeInt(mHeight);\n        dest.writeString(mParameters);\n    }\n\n    /**\n     * Parcelable creator\n     * \n     * @hide\n     */\n    public static final Parcelable.Creator<VideoCodec> CREATOR = new Parcelable.Creator<VideoCodec>() {\n        public VideoCodec createFromParcel(Parcel source) {\n            return new VideoCodec(source);\n        }\n\n        public VideoCodec[] newArray(int size) {\n            return new VideoCodec[size];\n        }\n    };\n\n    /**\n     * Returns the encoding name (e.g. H264)\n     * \n     * @return Encoding name\n     */\n    public String getEncoding() {\n        return mEncoding;\n    }\n\n    /**\n     * Returns the codec payload type (e.g. 96)\n     * \n     * @return Payload type\n     */\n    public int getPayloadType() {\n        return mPayload;\n    }\n\n    /**\n     * Returns the codec clock rate (e.g. 90000)\n     * \n     * @return Clock rate\n     */\n    public int getClockRate() {\n        return mClockRate;\n    }\n\n    /**\n     * Returns the codec frame rate (e.g. 10)\n     * \n     * @return Frame rate\n     */\n    public int getFrameRate() {\n        return mFrameRate;\n    }\n\n    /**\n     * Returns the codec bit rate (e.g. 64000)\n     * \n     * @return Bit rate\n     */\n    public int getBitRate() {\n        return mBitRate;\n    }\n\n    /**\n     * Returns the width of video frame (e.g. 176)\n     * \n     * @return Video width in pixels\n     */\n    public int getWidth() {\n        return mWidth;\n    }\n\n    /**\n     * Returns the height of video frame (e.g. 144)\n     * \n     * @return Video height in pixels\n     */\n    public int getHeight() {\n        return mHeight;\n    }\n\n    /**\n     * Returns the list of codec parameters (e.g. profile-level-id, packetization-mode). Parameters\n     * are are semicolon separated.\n     * \n     * @return Parameters\n     */\n    public String getParameters() {\n        return mParameters;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoDescriptor.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * Video descriptor for the default video player\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoDescriptor implements Parcelable {\n    /**\n     * Screen width\n     */\n    private final int mWidth;\n\n    /**\n     * Screen height\n     */\n    private final int mHeight;\n\n    /**\n     * Constructor\n     * \n     * @param width Video width\n     * @param height Video height\n     * @hide\n     */\n    public VideoDescriptor(int width, int height) {\n        mWidth = width;\n        mHeight = height;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     * @hide\n     */\n    public VideoDescriptor(Parcel source) {\n        mWidth = source.readInt();\n        mHeight = source.readInt();\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation\n     * \n     * @return Integer\n     * @hide\n     */\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object\n     * \n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(mWidth);\n        dest.writeInt(mHeight);\n    }\n\n    /**\n     * Parcelable creator\n     * \n     * @hide\n     */\n    public static final Parcelable.Creator<VideoDescriptor> CREATOR = new Parcelable.Creator<VideoDescriptor>() {\n        public VideoDescriptor createFromParcel(Parcel source) {\n            return new VideoDescriptor(source);\n        }\n\n        public VideoDescriptor[] newArray(int size) {\n            return new VideoDescriptor[size];\n        }\n    };\n\n    /**\n     * Returns the video width (e.g. 176)\n     * \n     * @return Video width\n     */\n    public int getWidth() {\n        return mWidth;\n    }\n\n    /**\n     * Returns the video height (e.g. 144)\n     * \n     * @return Video height\n     */\n    public int getHeight() {\n        return mHeight;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoPlayer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\n/**\n * Video player offers an interface to manage the video player instance independently of the RCS\n * service. The video player is implemented in the application side.<br>\n * In the originating side, the video player captures the video from the device camera, encodes the\n * video into the selected format and streams the encoded video frames over the network in RTP.<br>\n * In the terminating side, the video renderer is implemented in the application side. The video\n * renderer receives the video streaming over the network in RTP, decodes the video frames and\n * displays the decoded picture on the device screen.\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class VideoPlayer {\n    /**\n     * Constructor\n     */\n    public VideoPlayer() {\n    }\n\n    /**\n     * Set the remote info\n     * \n     * @param codec Video codec\n     * @param remoteHost Remote RTP host\n     * @param remotePort Remote RTP port\n     * @param orientationHeaderId Orientation header extension ID. The extension ID is a value\n     *            between 1 and 15 arbitrarily chosen by the sender, as defined in RFC5285\n     */\n    public abstract void setRemoteInfo(VideoCodec codec, String remoteHost, int remotePort,\n            int orientationHeaderId);\n\n    /**\n     * Returns the local RTP port used to stream video\n     * \n     * @return Port number\n     */\n    public abstract int getLocalRtpPort();\n\n    /**\n     * Returns the list of codecs supported by the player\n     * \n     * @return List of codecs\n     */\n    public abstract VideoCodec[] getSupportedCodecs();\n\n    /**\n     * Returns the current codec\n     * \n     * @return Codec\n     */\n    public abstract VideoCodec getCodec();\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoPlayerImpl.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport android.os.RemoteException;\n\n/**\n * Implementation of VideoPlayer.\n * \n * @author Philippe LEMORDANT\n * @hide\n */\npublic class VideoPlayerImpl extends IVideoPlayer.Stub {\n\n    private final VideoPlayer mVideoPlayer;\n\n    /**\n     * Constructor\n     */\n    public VideoPlayerImpl(VideoPlayer videoPlayer) {\n        mVideoPlayer = videoPlayer;\n    }\n\n    @Override\n    public void setRemoteInfo(VideoCodec codec, String remoteHost, int remotePort, int orientation)\n            throws RemoteException {\n        mVideoPlayer.setRemoteInfo(codec, remoteHost, remotePort, orientation);\n    }\n\n    @Override\n    public int getLocalRtpPort() {\n        return mVideoPlayer.getLocalRtpPort();\n    }\n\n    @Override\n    public VideoCodec[] getSupportedCodecs() {\n        return mVideoPlayer.getSupportedCodecs();\n    }\n\n    @Override\n    public VideoCodec getCodec() {\n        return mVideoPlayer.getCodec();\n    }\n\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharing.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService.Direction;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.util.SparseArray;\n\n/**\n * Video sharing\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic class VideoSharing {\n\n    /**\n     * Video sharing state\n     */\n    public enum State {\n\n        /**\n         * Sharing invitation received\n         */\n        INVITED(0),\n\n        /**\n         * Sharing invitation sent\n         */\n        INITIATING(1),\n\n        /**\n         * Sharing is started\n         */\n        STARTED(2),\n\n        /**\n         * Sharing has been aborted\n         */\n        ABORTED(3),\n\n        /**\n         * Sharing has failed\n         */\n        FAILED(4),\n\n        /**\n         * Sharing has been rejected\n         */\n        REJECTED(5),\n\n        /**\n         * Ringing\n         */\n        RINGING(6),\n\n        /**\n         * Sharing has been accepted and is in the process of becoming started\n         */\n        ACCEPTING(7);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State entry : State.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static State valueOf(int value) {\n            State entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n    }\n\n    /**\n     * Reason code associated with the video share state.\n     */\n    public enum ReasonCode {\n\n        /**\n         * No specific reason code specified.\n         */\n        UNSPECIFIED(0),\n\n        /**\n         * Video share is aborted by local user.\n         */\n        ABORTED_BY_USER(1),\n\n        /**\n         * Video share is aborted by remote user.\n         */\n        ABORTED_BY_REMOTE(2),\n\n        /**\n         * Video share is aborted by system.\n         */\n        ABORTED_BY_SYSTEM(3),\n\n        /**\n         * Video share is rejected because already taken by the secondary device.\n         */\n        REJECTED_BY_SECONDARY_DEVICE(4),\n\n        /**\n         * Video share invitation was rejected because it is spam.\n         */\n        REJECTED_SPAM(5),\n\n        /**\n         * Video share invitation was rejected due to max number of sharing sessions already are\n         * open.\n         */\n        REJECTED_MAX_SHARING_SESSIONS(6),\n\n        /**\n         * Video share invitation was rejected by local user.\n         */\n        REJECTED_BY_USER(7),\n\n        /**\n         * Video share invitation was rejected by remote.\n         */\n        REJECTED_BY_REMOTE(8),\n\n        /**\n         * Video share been rejected due to timeout.\n         */\n        REJECTED_BY_TIMEOUT(9),\n\n        /**\n         * Video share been rejected due to system.\n         */\n        REJECTED_BY_SYSTEM(10),\n\n        /**\n         * Video share initiation failed.\n         */\n        FAILED_INITIATION(11),\n\n        /**\n         * Sharing of the video share has failed.\n         */\n        FAILED_SHARING(12);\n\n        private final int mValue;\n\n        private static SparseArray<ReasonCode> mValueToEnum = new SparseArray<>();\n        static {\n            for (ReasonCode entry : ReasonCode.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        ReasonCode(int value) {\n            mValue = value;\n        }\n\n        public final int toInt() {\n            return mValue;\n        }\n\n        public static ReasonCode valueOf(int value) {\n            ReasonCode entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + ReasonCode.class.getName()\n                    + \"\" + value + \"!\");\n        }\n    }\n\n    /**\n     * Video encoding\n     */\n    public static class Encoding {\n        /**\n         * H264\n         */\n        public static final String H264 = \"H264\";\n\n        private Encoding() {\n        }\n    }\n\n    /**\n     * Video sharing interface\n     */\n    private final IVideoSharing mSharingInf;\n\n    /**\n     * Constructor\n     * \n     * @param sharingInf Video sharing interface\n     */\n    /* package private */VideoSharing(IVideoSharing sharingInf) {\n        mSharingInf = sharingInf;\n    }\n\n    /**\n     * Returns the sharing ID of the video sharing\n     * \n     * @return String Sharing ID\n     * @throws RcsGenericException\n     */\n    public String getSharingId() throws RcsGenericException {\n        try {\n            return mSharingInf.getSharingId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the remote contact identifier\n     * \n     * @return ContactId\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public ContactId getRemoteContact() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getRemoteContact();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the sharing\n     * \n     * @return State\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see VideoSharing.State\n     */\n    public State getState() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return State.valueOf(mSharingInf.getState());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the reason code of the sharing\n     * \n     * @return ReasonCode\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see VideoSharing.ReasonCode\n     */\n    public ReasonCode getReasonCode() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return ReasonCode.valueOf(mSharingInf.getReasonCode());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the direction of the sharing\n     * \n     * @return Direction\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see Direction\n     */\n    public Direction getDirection() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return Direction.valueOf(mSharingInf.getDirection());\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Accepts video sharing invitation\n     * \n     * @param player Video player\n     * @throws RcsGenericException\n     */\n    public void acceptInvitation(VideoPlayer player) throws RcsGenericException {\n        try {\n            VideoPlayerImpl videoPlayer = new VideoPlayerImpl(player);\n            mSharingInf.acceptInvitation(videoPlayer);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Rejects video sharing invitation\n     * \n     * @throws RcsGenericException\n     */\n    public void rejectInvitation() throws RcsGenericException {\n        try {\n            mSharingInf.rejectInvitation();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the sharing\n     * \n     * @throws RcsGenericException\n     */\n    public void abortSharing() throws RcsGenericException {\n        try {\n            mSharingInf.abortSharing();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Return the video encoding (eg. H.264)\n     * \n     * @return String Encoding\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public String getVideoEncoding() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getVideoEncoding();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the local timestamp of when the video sharing was initiated for outgoing video\n     * sharing or the local timestamp of when the video sharing invitation was received for incoming\n     * video sharings.\n     * \n     * @return long Timestamp in milliseconds\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getTimestamp() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getTimestamp();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the duration of the video sharing\n     * \n     * @return long Duration in milliseconds\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     */\n    public long getDuration() throws RcsPersistentStorageException, RcsGenericException {\n        try {\n            return mSharingInf.getDuration();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the video descriptor\n     * \n     * @return VideoDescriptor\n     * @throws RcsPersistentStorageException\n     * @throws RcsGenericException\n     * @see VideoDescriptor\n     */\n    public VideoDescriptor getVideoDescriptor() throws RcsPersistentStorageException,\n            RcsGenericException {\n        try {\n            return mSharingInf.getVideoDescriptor();\n\n        } catch (Exception e) {\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharingIntent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\n/**\n * Intent for video sharing invitations\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoSharingIntent {\n    /**\n     * Broadcast action: a new video sharing invitation has been received.\n     * <p>\n     * Intent includes the following extras:\n     * <ul>\n     * <li> {@link #EXTRA_SHARING_ID} containing the unique ID of the video sharing.\n     * </ul>\n     */\n    public final static String ACTION_NEW_INVITATION = \"com.gsma.services.rcs.sharing.video.action.NEW_VIDEO_SHARING\";\n\n    /**\n     * Unique ID of the video sharing\n     */\n    public final static String EXTRA_SHARING_ID = \"sharingId\";\n\n    private VideoSharingIntent() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharingListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport java.util.Set;\n\n/**\n * Video sharing event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class VideoSharingListener {\n\n    /**\n     * Callback called when the sharing state/reasonCode is changed.\n     * \n     * @param contact Contact ID\n     * @param sharingId ID of video sharing\n     * @param state State of video sharing\n     * @param reasonCode Reason code of the video sharing state\n     * @see VideoSharing.State\n     * @see VideoSharing.ReasonCode\n     */\n    public abstract void onStateChanged(ContactId contact, String sharingId, State state,\n            ReasonCode reasonCode);\n\n    /**\n     * Callback called when a delete operation completed that resulted in that one or several video\n     * sharings was deleted specified by the sharingIds parameter corresponding to a specific\n     * contact.\n     *\n     * @param contact Contact ID\n     * @param sharingIds ids of those deleted video sharing\n     */\n    public abstract void onDeleted(ContactId contact, Set<String> sharingIds);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharingListenerImpl.java",
    "content": "/*\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode;\nimport com.gsma.services.rcs.sharing.video.VideoSharing.State;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport java.util.HashSet;\nimport java.util.List;\n\n/**\n * Video sharing event listener implementation\n * \n * @hide\n */\npublic class VideoSharingListenerImpl extends IVideoSharingListener.Stub {\n\n    private final VideoSharingListener mListener;\n\n    private final static String LOG_TAG = VideoSharingListenerImpl.class.getName();\n\n    VideoSharingListenerImpl(VideoSharingListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(ContactId contact, String sharingId, int state, int reasonCode) {\n        State rcsStatus;\n        ReasonCode rcsReasonCode;\n        try {\n            rcsStatus = State.valueOf(state);\n            rcsReasonCode = ReasonCode.valueOf(reasonCode);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can of course not handle since it is build only to handle the\n             * possible enum values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(contact, sharingId, rcsStatus, rcsReasonCode);\n    }\n\n    /**\n     * This feature to be implemented in CR005\n     */\n    @Override\n    public void onDeleted(ContactId contact, List<String> sharingIds) throws RemoteException {\n        mListener.onDeleted(contact, new HashSet<>(sharingIds));\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharingLog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.RcsService.Direction;\n\nimport android.net.Uri;\nimport android.provider.BaseColumns;\n\n/**\n * Content provider for video sharing history\n * \n * @author Jean-Marc AUFFRET\n */\npublic class VideoSharingLog {\n    /**\n     * Content provider URI\n     */\n    public static final Uri CONTENT_URI = Uri\n            .parse(\"content://com.gsma.services.rcs.provider.videoshare/videoshare\");\n\n    /**\n     * History log member id\n     */\n    public static final int HISTORYLOG_MEMBER_ID = 4;\n\n    /**\n     * The name of the column containing the unique id across provider tables.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String BASECOLUMN_ID = BaseColumns._ID;\n\n    /**\n     * The name of the column containing the unique ID of the video sharing.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String SHARING_ID = \"sharing_id\";\n\n    /**\n     * The name of the column containing the MSISDN of the remote contact.\n     * <P>\n     * Type: TEXT\n     * </P>\n     */\n    public static final String CONTACT = \"contact\";\n\n    /**\n     * The name of the column containing the direction of the sharing.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see Direction\n     */\n    public static final String DIRECTION = \"direction\";\n\n    /**\n     * The name of the column containing the date of the sharing (in milliseconds).\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String TIMESTAMP = \"timestamp\";\n\n    /**\n     * The name of the column containing the duration of the sharing (in milliseconds). The value is\n     * only set at the end of the call.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String DURATION = \"duration\";\n\n    /**\n     * The name of the column containing the state of the sharing.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see VideoSharing.State\n     */\n    public static final String STATE = \"state\";\n\n    /**\n     * The name of the column containing the reason code of the state.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see VideoSharing.ReasonCode\n     */\n    public static final String REASON_CODE = \"reason_code\";\n\n    /**\n     * The name of the column containing the encoding type of video.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     * \n     * @see VideoSharing.Encoding\n     */\n    public static final String VIDEO_ENCODING = \"video_encoding\";\n\n    /**\n     * The name of the column containing the width of video.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String WIDTH = \"width\";\n\n    /**\n     * The name of the column containing the height of video.\n     * <P>\n     * Type: INTEGER\n     * </P>\n     */\n    public static final String HEIGHT = \"height\";\n\n    private VideoSharingLog() {\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharingService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Map;\nimport java.util.WeakHashMap;\n\n/**\n * This class offers the main entry point to share live video during a CS call. Several applications\n * may connect/disconnect to the API. The parameter contact in the API supports the following\n * formats: MSISDN in national or international format, SIP address, SIP-URI or Tel-URI.\n * \n * @author Jean-Marc AUFFRET\n * @author Philippe LEMORDANT\n */\npublic final class VideoSharingService extends RcsService {\n    /**\n     * API\n     */\n    private IVideoSharingService mApi;\n\n    private final Map<VideoSharingListener, WeakReference<IVideoSharingListener>> mVideoSharingListeners = new WeakHashMap<>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public VideoSharingService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the video sharing service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the video sharing service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IVideoSharingService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IVideoSharingService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IVideoSharingService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Returns the configuration of video sharing service\n     * \n     * @return VideoSharingServiceConfiguration\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public VideoSharingServiceConfiguration getConfiguration()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new VideoSharingServiceConfiguration(mApi.getConfiguration());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Shares a live video with a contact. The parameter renderer contains the video player provided\n     * by the application. An exception if thrown if there is no ongoing CS call. The parameter\n     * contact supports the following formats: MSISDN in national or international format, SIP\n     * address, SIP-URI or Tel-URI. If the format of the contact is not supported an exception is\n     * thrown.\n     * \n     * @param contact Contact identifier\n     * @param player Video player\n     * @return VideoSharing\n     * @throws RcsPersistentStorageException\n     * @throws RcsServiceNotRegisteredException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public VideoSharing shareVideo(ContactId contact, VideoPlayer player)\n            throws RcsPersistentStorageException, RcsServiceNotRegisteredException,\n            RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            VideoPlayerImpl videoPlayer = new VideoPlayerImpl(player);\n            IVideoSharing sharingIntf = mApi.shareVideo(contact, videoPlayer);\n            if (sharingIntf != null) {\n                return new VideoSharing(sharingIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsServiceNotRegisteredException.assertException(e);\n            RcsPersistentStorageException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current video sharing from its unique ID\n     * \n     * @param sharingId Sharing ID\n     * @return VideoSharing Video sharing or null if not found\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public VideoSharing getVideoSharing(String sharingId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new VideoSharing(mApi.getVideoSharing(sharingId));\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on video sharing events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(VideoSharingListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IVideoSharingListener rcsListener = new VideoSharingListenerImpl(listener);\n            mVideoSharingListeners.put(listener, new WeakReference<>(rcsListener));\n            mApi.addEventListener2(rcsListener);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on video sharing events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(VideoSharingListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IVideoSharingListener> weakRef = mVideoSharingListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IVideoSharingListener rcsListener = weakRef.get();\n            if (rcsListener != null) {\n                mApi.removeEventListener2(rcsListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes all video sharing from history and abort/reject any associated ongoing session if\n     * such exists.\n     * \n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteVideoSharings() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteVideoSharings();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Delete video sharing associated with a given contact from history and abort/reject any\n     * associated ongoing session if such exists.\n     * \n     * @param contact the remote contact\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteVideoSharings(ContactId contact) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteVideoSharings2(contact);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Deletes a video sharing by its sharing ID from history and abort/reject any associated\n     * ongoing session if such exists.\n     * \n     * @param sharingId the sharing ID\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void deleteVideoSharing(String sharingId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            mApi.deleteVideoSharing(sharingId);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/VideoSharingServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.sharing.video;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\n/**\n * Video sharing service configuration\n * \n * @author Jean-Marc AUFFRET\n * @author yplo6403\n */\npublic class VideoSharingServiceConfiguration {\n\n    IVideoSharingServiceConfiguration mConfiguration;\n\n    /**\n     * Constructor\n     * \n     * @param configuration the configuration\n     */\n    /* package private */VideoSharingServiceConfiguration(\n            IVideoSharingServiceConfiguration configuration) {\n        mConfiguration = configuration;\n    }\n\n    /**\n     * Returns the maximum authorized duration of the video sharing. It returns 0 if there is no\n     * limitation.\n     * \n     * @return long Duration in milliseconds\n     * @throws RcsGenericException\n     */\n    public long getMaxTime() throws RcsGenericException {\n        try {\n            return mConfiguration.getMaxTime();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/sharing/video/package-info.java",
    "content": "/**\n * This API exposes all functionality related to share live video stream during a CS call.\n * <p>\n */\n\npackage com.gsma.services.rcs.sharing.video;\n\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/FileUpload.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\nimport android.net.Uri;\nimport android.util.SparseArray;\n\n/**\n * File upload\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileUpload {\n\n    /**\n     * File upload state\n     */\n    public enum State {\n\n        /**\n         * Initiating state\n         */\n        INITIATING(0),\n\n        /**\n         * Upload is started\n         */\n        STARTED(1),\n\n        /**\n         * Upload has been aborted\n         */\n        ABORTED(2),\n\n        /**\n         * Upload has failed\n         */\n        FAILED(3),\n\n        /**\n         * File has been transferred with success\n         */\n        TRANSFERRED(4);\n\n        private final int mValue;\n\n        private static SparseArray<State> mValueToEnum = new SparseArray<>();\n        static {\n            for (State entry : State.values()) {\n                mValueToEnum.put(entry.toInt(), entry);\n            }\n        }\n\n        State(int value) {\n            mValue = value;\n        }\n\n        /**\n         * Returns the value of this State as an integer.\n         * \n         * @return integer value\n         */\n        public final int toInt() {\n            return mValue;\n        }\n\n        /**\n         * Returns a State instance representing the specified integer value.\n         * \n         * @param value the integer value\n         * @return State instance\n         */\n        public static State valueOf(int value) {\n            State entry = mValueToEnum.get(value);\n            if (entry != null) {\n                return entry;\n            }\n            throw new IllegalArgumentException(\"No enum const class \" + State.class.getName() + \"\"\n                    + value + \"!\");\n        }\n    }\n\n    /**\n     * File upload interface\n     */\n    private IFileUpload mUploadInf;\n\n    /**\n     * Constructor\n     * \n     * @param uploadInf Upload interface\n     */\n    /* package private */FileUpload(IFileUpload uploadInf) {\n        mUploadInf = uploadInf;\n    }\n\n    /**\n     * Returns the upload ID of the upload\n     * \n     * @return String Upload ID\n     * @throws RcsGenericException\n     */\n    public String getUploadId() throws RcsGenericException {\n        try {\n            return mUploadInf.getUploadId();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the URI of the file to be uploaded\n     * \n     * @return Uri\n     * @throws RcsGenericException\n     */\n    public Uri getFile() throws RcsGenericException {\n        try {\n            return mUploadInf.getFile();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns info related to the uploaded file on the content server\n     * \n     * @return FileUploadInfo info or null if not yet upload or in case of error\n     * @throws RcsGenericException\n     * @see FileUploadInfo\n     */\n    public FileUploadInfo getUploadInfo() throws RcsGenericException {\n        try {\n            return mUploadInf.getUploadInfo();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the state of the upload\n     * \n     * @return State\n     * @throws RcsGenericException\n     * @see FileUpload.State\n     */\n    public State getState() throws RcsGenericException {\n        try {\n            return State.valueOf(mUploadInf.getState());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Aborts the upload\n     * \n     * @throws RcsGenericException\n     */\n    public void abortUpload() throws RcsGenericException {\n        try {\n            mUploadInf.abortUpload();\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/FileUploadInfo.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n/**\n * File upload info\n * \n * @author Jean-Marc AUFFRET\n */\npublic class FileUploadInfo implements Parcelable {\n    /**\n     * URI of the file on the content server\n     */\n    private Uri mFile;\n\n    /**\n     * Time in milliseconds for when file on the content server is no longer valid to download\n     */\n    private long mExpiration;\n\n    /**\n     * Original filename\n     */\n    private String mFileName;\n\n    /**\n     * File size\n     */\n    private long mSize;\n\n    /**\n     * File MIME type\n     */\n    private String mMimeType;\n\n    /**\n     * URI of the file icon on the content server\n     */\n    private final Uri mFileIcon;\n\n    /**\n     * Time in milliseconds for when file icon on the content server is no longer valid to download\n     * or 0 if not applicable\n     */\n    private final long mFileIconExpiration;\n\n    /**\n     * File icon size\n     */\n    private final long mFileIconSize;\n\n    /**\n     * File icon MIME type\n     */\n    private final String mFileIconMimeType;\n\n    /**\n     * Constructor for outgoing message\n     *\n     * @hide\n     */\n    public FileUploadInfo(Uri file, long validity, String filename, long size, String type,\n            Uri fileIcon, long fileIconValidity, long fileIconSize, String fileIconType) {\n        mFile = file;\n        mExpiration = validity;\n        mFileName = filename;\n        mSize = size;\n        mMimeType = type;\n        mFileIcon = fileIcon;\n        mFileIconExpiration = fileIconValidity;\n        mFileIconSize = fileIconSize;\n        mFileIconMimeType = fileIconType;\n    }\n\n    /**\n     * Constructor for outgoing message\n     *\n     * @hide\n     */\n    public FileUploadInfo(Uri file, long validity, String filename, long size, String type) {\n        mFile = file;\n        mExpiration = validity;\n        mFileName = filename;\n        mSize = size;\n        mMimeType = type;\n        mFileIcon = null;\n        mFileIconExpiration = FileTransferLog.UNKNOWN_EXPIRATION;\n        mFileIconSize = 0L;\n        mFileIconMimeType = null;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param source Parcelable source\n     * @hide\n     */\n    public FileUploadInfo(Parcel source) {\n        mFile = Uri.parse(source.readString());\n        mExpiration = source.readLong();\n        mFileName = source.readString();\n        mSize = source.readLong();\n        mMimeType = source.readString();\n        boolean containsFileIcon = source.readInt() != 0;\n        if (containsFileIcon) {\n            mFileIcon = Uri.parse(source.readString());\n        } else {\n            mFileIcon = null;\n        }\n        mFileIconExpiration = source.readLong();\n        mFileIconSize = source.readLong();\n        mFileIconMimeType = source.readString();\n    }\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable's marshalled\n     * representation\n     * \n     * @return Integer\n     * @hide\n     */\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Write parcelable object\n     * \n     * @param dest The Parcel in which the object should be written\n     * @param flags Additional flags about how the object should be written\n     * @hide\n     */\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mFile.toString());\n        dest.writeLong(mExpiration);\n        dest.writeString(mFileName);\n        dest.writeLong(mSize);\n        dest.writeString(mMimeType);\n        if (mFileIcon != null) {\n            dest.writeInt(1);\n            dest.writeString(mFileIcon.toString());\n        } else {\n            dest.writeInt(0);\n        }\n        dest.writeLong(mFileIconExpiration);\n        dest.writeLong(mFileIconSize);\n        dest.writeString(mFileIconMimeType);\n    }\n\n    /**\n     * Parcelable creator\n     * \n     * @hide\n     */\n    public static final Parcelable.Creator<FileUploadInfo> CREATOR = new Parcelable.Creator<FileUploadInfo>() {\n        public FileUploadInfo createFromParcel(Parcel source) {\n            return new FileUploadInfo(source);\n        }\n\n        public FileUploadInfo[] newArray(int size) {\n            return new FileUploadInfo[size];\n        }\n    };\n\n    /**\n     * Returns URI of the file on the content server\n     * \n     * @return Uri\n     */\n    public Uri getFile() {\n        return mFile;\n    }\n\n    /**\n     * Returns the timestamp for when the file on the content server is no longer valid to download.\n     * \n     * @return timestamp in milliseconds\n     */\n    public long getFileExpiration() {\n        return mExpiration;\n    }\n\n    /**\n     * Returns the original filename\n     * \n     * @return String\n     */\n    public String getFileName() {\n        return mFileName;\n    }\n\n    /**\n     * Returns the size of the file\n     * \n     * @return Size\n     */\n    public long getSize() {\n        return mSize;\n    }\n\n    /**\n     * Returns the MIME type of the file\n     * \n     * @return MIME type\n     */\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    /**\n     * Returns URI of the file icon on the content server\n     * \n     * @return Uri or null if no file icon defined\n     */\n    public Uri getFileIcon() {\n        return mFileIcon;\n    }\n\n    /**\n     * Returns the timestamp for when the file icon on the content server is no longer valid to\n     * download.\n     * \n     * @return timestamp in milliseconds of 0 if no file icon defined\n     */\n    public long getFileIconExpiration() {\n        return mFileIconExpiration;\n    }\n\n    /**\n     * Returns the size of the file icon\n     * \n     * @return Size or 0 if no file icon defined\n     */\n    public long getFileIconSize() {\n        return mFileIconSize;\n    }\n\n    /**\n     * Returns the MIME type of the file icon\n     * \n     * @return MIME type or null if no file icon defined\n     */\n    public String getFileIconMimeType() {\n        return mFileIconMimeType;\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/FileUploadListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.upload.FileUpload.State;\n\n/**\n * File upload event listener\n * \n * @author Jean-Marc AUFFRET\n */\npublic abstract class FileUploadListener {\n    /**\n     * Callback called when the file upload state has been changed.\n     * \n     * @param uploadId ID of upload\n     * @param state State of upload\n     */\n    public abstract void onStateChanged(String uploadId, State state);\n\n    /**\n     * Callback called during the upload progress.\n     * \n     * @param uploadId ID of upload\n     * @param currentSize Current transferred size in bytes\n     * @param totalSize Total size to transfer in bytes\n     */\n    public abstract void onProgressUpdate(String uploadId, long currentSize, long totalSize);\n\n    /**\n     * Callback called when the file has been uploaded.\n     * \n     * @param uploadId ID of upload\n     * @param info Info about the file upload\n     */\n    public abstract void onUploaded(String uploadId, FileUploadInfo info);\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/FileUploadListenerImpl.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.upload.FileUpload.State;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\n/**\n * File Upload Listener Implementation\n * \n * @hide\n */\npublic class FileUploadListenerImpl extends IFileUploadListener.Stub {\n\n    private final FileUploadListener mListener;\n\n    private final static String LOG_TAG = FileUploadListenerImpl.class.getName();\n\n    FileUploadListenerImpl(FileUploadListener listener) {\n        mListener = listener;\n    }\n\n    public void onStateChanged(String uploadId, int state) {\n        State rcsState;\n        try {\n            rcsState = State.valueOf(state);\n        } catch (IllegalArgumentException e) {\n            /*\n             * Detected unknown state or reasonCode not part of standard coming from stack which a\n             * client application can not handle since it is built only to handle the possible enum\n             * values documented and specified in the api standard.\n             */\n            Log.e(LOG_TAG, e.getMessage());\n            return;\n        }\n        mListener.onStateChanged(uploadId, rcsState);\n    }\n\n    public void onProgressUpdate(String uploadId, long currentSize, long totalSize)\n            throws RemoteException {\n        mListener.onProgressUpdate(uploadId, currentSize, totalSize);\n    }\n\n    public void onUploaded(String uploadId, FileUploadInfo info) throws RemoteException {\n        mListener.onUploaded(uploadId, info);\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/FileUploadService.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsIllegalArgumentException;\nimport com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\n\nimport android.content.ComponentName;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\nimport java.lang.ref.WeakReference;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.WeakHashMap;\n\n/**\n * This class offers the main entry point to upload a file to the RCS content server. Several\n * applications may connect/disconnect to the API. There is no pause and resume supported here.\n * \n * @author Jean-Marc AUFFRET\n */\npublic final class FileUploadService extends RcsService {\n\n    /**\n     * API\n     */\n    private IFileUploadService mApi;\n\n    private final Map<FileUploadListener, WeakReference<IFileUploadListener>> mFileUploadListeners = new WeakHashMap<>();\n\n    private static boolean sApiCompatible = false;\n\n    /**\n     * Constructor\n     * \n     * @param ctx Application context\n     * @param listener Service listener\n     */\n    public FileUploadService(Context ctx, RcsServiceListener listener) {\n        super(ctx, listener);\n    }\n\n    /**\n     * Connects to the API\n     * \n     * @throws RcsPermissionDeniedException\n     */\n    public final void connect() throws RcsPermissionDeniedException {\n        if (!sApiCompatible) {\n            try {\n                sApiCompatible = mRcsServiceControl.isCompatible(this);\n                if (!sApiCompatible) {\n                    throw new RcsPermissionDeniedException(\n                            \"The TAPI client version of the file upload service is not compatible with the TAPI service implementation version on this device!\");\n                }\n            } catch (RcsServiceException e) {\n                throw new RcsPermissionDeniedException(\n                        \"The compatibility of TAPI client version with the TAPI service implementation version of this device cannot be checked for the file upload service!\",\n                        e);\n            }\n        }\n        Intent serviceIntent = new Intent(IFileUploadService.class.getName());\n        serviceIntent.setPackage(RcsServiceControl.RCS_STACK_PACKAGENAME);\n        mCtx.bindService(serviceIntent, apiConnection, 0);\n    }\n\n    /**\n     * Disconnects from the API\n     */\n    public void disconnect() {\n        try {\n            mCtx.unbindService(apiConnection);\n        } catch (IllegalArgumentException e) {\n            // Nothing to do\n        }\n    }\n\n    /**\n     * Set API interface\n     * \n     * @param api API interface\n     * @hide\n     */\n    protected void setApi(IInterface api) {\n        super.setApi(api);\n        mApi = (IFileUploadService) api;\n    }\n\n    /**\n     * Service connection\n     */\n    private ServiceConnection apiConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName className, IBinder service) {\n            setApi(IFileUploadService.Stub.asInterface(service));\n            if (mListener != null) {\n                mListener.onServiceConnected();\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName className) {\n            setApi(null);\n            if (mListener == null) {\n                return;\n            }\n            ReasonCode reasonCode = ReasonCode.CONNECTION_LOST;\n            try {\n                if (!mRcsServiceControl.isActivated()) {\n                    reasonCode = ReasonCode.SERVICE_DISABLED;\n                }\n            } catch (RcsServiceException e) {\n                // Do nothing\n            }\n            mListener.onServiceDisconnected(reasonCode);\n        }\n    };\n\n    /**\n     * Granting temporary read Uri permission from client to stack service if it is a content URI\n     * \n     * @param file Uri of file to grant permission\n     */\n    private void tryToGrantUriPermissionToStackServices(Uri file) {\n        if (!ContentResolver.SCHEME_CONTENT.equals(file.getScheme())) {\n            return;\n        }\n        Intent fileTransferServiceIntent = new Intent(IFileUploadService.class.getName());\n        List<ResolveInfo> stackServices = mCtx.getPackageManager().queryIntentServices(\n                fileTransferServiceIntent, 0);\n        for (ResolveInfo stackService : stackServices) {\n            mCtx.grantUriPermission(stackService.serviceInfo.packageName, file,\n                    Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        }\n    }\n\n    /**\n     * Can a file be uploaded now\n     * \n     * @return boolean true if a file can be uploaded, else returns false\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public boolean canUploadFile() throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return mApi.canUploadFile();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the configuration of the file upload service\n     * \n     * @return FileUploadServiceConfiguration\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileUploadServiceConfiguration getConfiguration()\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            return new FileUploadServiceConfiguration(mApi.getConfiguration());\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Uploads a file to the RCS content server. The parameter file contains the URI of the file to\n     * be uploaded (for a local or a remote file).\n     * \n     * @param file Uri of file to upload\n     * @param attachFileIcon Attach file icon option. If true and if it's an image, a file icon is\n     *            attached.\n     * @return FileUpload\n     * @throws RcsMaxAllowedSessionLimitReachedException\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileUpload uploadFile(Uri file, boolean attachFileIcon)\n            throws RcsMaxAllowedSessionLimitReachedException, RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            /* Only grant permission for content Uris */\n            tryToGrantUriPermissionToStackServices(file);\n            IFileUpload uploadIntf = mApi.uploadFile(file, attachFileIcon);\n            if (uploadIntf != null) {\n                return new FileUpload(uploadIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            RcsMaxAllowedSessionLimitReachedException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns the list of file uploads in progress\n     * \n     * @return Set&lt;FileUpload&gt; List of file uploads\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public Set<FileUpload> getFileUploads() throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            Set<FileUpload> result = new HashSet<>();\n            List<IBinder> ishList = mApi.getFileUploads();\n            for (IBinder binder : ishList) {\n                FileUpload upload = new FileUpload(IFileUpload.Stub.asInterface(binder));\n                result.add(upload);\n            }\n            return result;\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Returns a current file upload from its unique ID\n     * \n     * @param uploadId Upload ID\n     * @return FileUpload File upload or null if not found\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public FileUpload getFileUpload(String uploadId) throws RcsServiceNotAvailableException,\n            RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IFileUpload uploadIntf = mApi.getFileUpload(uploadId);\n            if (uploadIntf != null) {\n                return new FileUpload(uploadIntf);\n            }\n            return null;\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Adds a listener on file upload events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void addEventListener(FileUploadListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (listener == null) {\n            throw new RcsIllegalArgumentException(\"listener must not be null!\");\n        }\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            IFileUploadListener fileUploadListener = new FileUploadListenerImpl(listener);\n            mFileUploadListeners.put(listener, new WeakReference<>(fileUploadListener));\n            mApi.addEventListener(fileUploadListener);\n\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n\n    /**\n     * Removes a listener on file upload events\n     * \n     * @param listener Listener\n     * @throws RcsServiceNotAvailableException\n     * @throws RcsGenericException\n     */\n    public void removeEventListener(FileUploadListener listener)\n            throws RcsServiceNotAvailableException, RcsGenericException {\n        if (mApi == null) {\n            throw new RcsServiceNotAvailableException();\n        }\n        try {\n            WeakReference<IFileUploadListener> weakRef = mFileUploadListeners.remove(listener);\n            if (weakRef == null) {\n                return;\n            }\n            IFileUploadListener fileUploadListener = weakRef.get();\n            if (fileUploadListener != null) {\n                mApi.removeEventListener(fileUploadListener);\n            }\n        } catch (Exception e) {\n            RcsIllegalArgumentException.assertException(e);\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/FileUploadServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.upload;\n\nimport com.gsma.services.rcs.RcsGenericException;\n\n/**\n * File upload service configuration\n * \n * @author Jean-Marc AUFFRET\n * @author yplo6403\n */\npublic class FileUploadServiceConfiguration {\n\n    IFileUploadServiceConfiguration mConfiguration;\n\n    /**\n     * Constructor\n     * \n     * @param configuration the configuration\n     */\n    /* package private */FileUploadServiceConfiguration(\n            IFileUploadServiceConfiguration configuration) {\n        mConfiguration = configuration;\n    }\n\n    /**\n     * Returns the file upload size limit. It returns 0 if there is no limitation.\n     * \n     * @return long Size in bytes\n     * @throws RcsGenericException\n     */\n    public long getMaxSize() throws RcsGenericException {\n        try {\n            return mConfiguration.getMaxSize();\n\n        } catch (Exception e) {\n            throw new RcsGenericException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api/src/main/java/com/gsma/services/rcs/upload/package-info.java",
    "content": "/**\n * This API exposes exposes all functionality related to upload files to the\n * RCS content server. Then the link to the uploaded file may be shared with\n * any contact.\n * <p>\n */\n\npackage com.gsma.services.rcs.upload;\n\n"
  },
  {
    "path": "libs/api/version/blackbird_1_5_1.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"CommonServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getDefaultMessagingMethod\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMessagingUX\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMinimumBatteryLevel\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isConfigValid\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setDefaultMessagingMethod\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"method\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMinimumBatteryLevel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"level\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMyDisplayName\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMethod\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MinimumBatteryLevel\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Geoloc\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<method name=\"getAccuracy\"\n return=\"float\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLabel\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLatitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLongitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SEND_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SEND_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_ONE_TO_ONE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_ONE_TO_ONE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.ACTION_INITIATE_GROUP_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_ONE_TO_ONE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_ONE_TO_ONE_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Service\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE_CHANGEABLE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_COMPATIBILITY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_COMPATIBILITY&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_SERVICE_STARTING_STATE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode_changeable&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_codename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_INCREMENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_increment&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_RESPONSE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_response&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_SERVICE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_service&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_VERSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_version&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_service_starting_state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;set_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsGenericException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsIllegalArgumentException\"\n extends=\"java.lang.IllegalArgumentException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsIllegalArgumentException\" type=\"com.gsma.services.rcs.RcsIllegalArgumentException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsMaxAllowedSessionLimitReachedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPermissionDeniedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPersistentStorageException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCommonConfiguration\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceRegistrationReasonCode\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceVersion\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<field name=\"ACTION_SERVICE_PROVISIONING_DATA_CHANGED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_PROVISIONING_DATA_CHANGED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SERVICE_UP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_UP&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Direction\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.Direction[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsService.ReadStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceControl\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.RcsServiceControl\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isActivationModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAvailable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceStarted\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setActivationMode\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"active\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"RCS_STACK_PACKAGENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"extractServerException\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n</method>\n<method name=\"isIntendedException\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<parameter name=\"clazz\" type=\"java.lang.Class&lt;?&gt;\">\n</parameter>\n</method>\n</class>\n<interface name=\"RcsServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\">\n</parameter>\n</method>\n</interface>\n<class name=\"RcsServiceListener.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<class name=\"RcsServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsServiceRegistration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"RcsServiceRegistration.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceRegistrationListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"RcsUnsupportedOperationException\"\n extends=\"java.lang.UnsupportedOperationException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsUnsupportedOperationException\" type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutomata\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGeolocPushSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"AUTOMATA\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;automata&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_geoloc_push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<field name=\"EXTENSION_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"participants\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PARTICIPANTS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;participants&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.Content.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.Content.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.MimeType\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"GEOLOC_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;application/geoloc&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GROUPCHAT_EVENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;rcs/groupchat-event&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TEXT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;text/plain&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getContent\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getStatus\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearMessageDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGroupChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getOneToOneChat\"\n return=\"com.gsma.services.rcs.chat.OneToOneChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markMessageAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getGeolocExpirationTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGeolocLabelMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMinParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatSubjectMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getOneToOneChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isChatWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupChatSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isRespondToDisplayReportsEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setRespondToDisplayReports\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"inviteParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipant\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participant\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipants\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToLeave\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"leave\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.ParticipantStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_GROUP_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onMessageGroupDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onParticipantStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.chat.GroupChat.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"resendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"OneToOneChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_MESSAGE_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.MESSAGE_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"OneToOneChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneChatListener\"\n type=\"com.gsma.services.rcs.chat.OneToOneChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contact\"\n>\n<class name=\"ContactId\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n</class>\n<class name=\"ContactProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"MIME_TYPE_BLOCKING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_BLOCKING_TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactService\"\n type=\"com.gsma.services.rcs.contact.ContactService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"blockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getRcsContact\"\n return=\"com.gsma.services.rcs.contact.RcsContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unblockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ContactUtil\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"formatContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.contact.ContactUtil\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"getMyCountryAreaCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getMyCountryCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getVCard\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isMyCountryCodeDefined\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isValidContact\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBlockingTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isBlocked\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isOnline\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.extension\"\n>\n<class name=\"MultimediaMessagingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaMessagingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_MESSAGING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaMessagingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaMessagingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onMessageReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"MultimediaSession\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSession.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSession.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSessionService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionService\"\n type=\"com.gsma.services.rcs.extension.MultimediaSessionService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.extension.MultimediaSessionServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaMessagingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaStreamingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSessionServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendPayload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_STREAMING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaStreamingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaStreamingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPayloadReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.filetransfer\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToPauseTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToResendTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToResumeTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"pauseTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"resendTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"resumeTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_FILE_TRANSFER_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.FILE_TRANSFER_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_RESUME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.RESUME_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN_EXPIRATION\"\n type=\"long\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0L\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.filetransfer.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearFileTransferDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteFileTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFileToGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markFileTransferAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFileToGroupChat\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getImageResizeOption\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxFileTransfers\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptInRoamingEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setAutoAccept\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setAutoAcceptInRoaming\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setImageResizeOption\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"option\" type=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration.ImageResizeOption\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.groupdelivery\"\n>\n<class name=\"GroupDeliveryInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"GroupDeliveryInfo.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfo.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfoLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.history\"\n>\n<class name=\"HistoryLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PROVIDER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;provider_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"HistoryService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryService\"\n type=\"com.gsma.services.rcs.history.HistoryService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"createUniqueId\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"registerExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<parameter name=\"providerUri\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"database\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"table\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"columnMapping\" type=\"java.util.Map&lt;java.lang.String, java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unregisterExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"HistoryUriBuilder\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryUriBuilder\"\n type=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"historyLogUri\" type=\"android.net.Uri\">\n</parameter>\n</constructor>\n<method name=\"appendProvider\"\n return=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n</method>\n<method name=\"build\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.geoloc\"\n>\n<class name=\"GeolocSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.geoloc.action.NEW_GEOLOC_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingListener\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"GeolocSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingService\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocSharing\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.image\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.image.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteImageSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.video\"\n>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoDescriptor\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setRemoteInfo\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.sharing.video.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n<parameter name=\"orientationHeaderId\" type=\"int\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDuration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoDescriptor\"\n return=\"com.gsma.services.rcs.sharing.video.VideoDescriptor\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Encoding\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"H264\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;H264&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.video.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HEIGHT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;height&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"VIDEO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;video_encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"WIDTH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;width&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.upload\"\n>\n<class name=\"FileUpload\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortUpload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadInfo\"\n return=\"com.gsma.services.rcs.upload.FileUploadInfo\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUpload.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadListener\"\n type=\"com.gsma.services.rcs.upload.FileUploadListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.upload.FileUpload.State\">\n</parameter>\n</method>\n<method name=\"onUploaded\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"info\" type=\"com.gsma.services.rcs.upload.FileUploadInfo\">\n</parameter>\n</method>\n</class>\n<class name=\"FileUploadService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadService\"\n type=\"com.gsma.services.rcs.upload.FileUploadService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"canUploadFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.upload.FileUploadServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUpload\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUploads\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.upload.FileUpload&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"uploadFile\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUploadServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n</api>\n"
  },
  {
    "path": "libs/api/version/crane_1_6_1.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"CommonServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getDefaultMessagingMethod\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMessagingUX\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMinimumBatteryLevel\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isConfigValid\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setDefaultMessagingMethod\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"method\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMinimumBatteryLevel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"level\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMyDisplayName\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMethod\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MinimumBatteryLevel\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Geoloc\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<method name=\"getAccuracy\"\n return=\"float\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLabel\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLatitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLongitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SEND_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SEND_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_ONE_TO_ONE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_ONE_TO_ONE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.ACTION_INITIATE_GROUP_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_ONE_TO_ONE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_ONE_TO_ONE_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Service\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE_CHANGEABLE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_COMPATIBILITY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_COMPATIBILITY&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_SERVICE_STARTING_STATE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode_changeable&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_codename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_INCREMENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_increment&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_RESPONSE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_response&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_SERVICE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_service&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_VERSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_version&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_service_starting_state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;set_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsGenericException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsIllegalArgumentException\"\n extends=\"java.lang.IllegalArgumentException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsIllegalArgumentException\" type=\"com.gsma.services.rcs.RcsIllegalArgumentException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsMaxAllowedSessionLimitReachedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPermissionDeniedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPersistentStorageException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCommonConfiguration\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceRegistrationReasonCode\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceVersion\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<field name=\"ACTION_SERVICE_PROVISIONING_DATA_CHANGED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_PROVISIONING_DATA_CHANGED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SERVICE_UP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_UP&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CPR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Direction\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.Direction[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsService.ReadStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceControl\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.RcsServiceControl\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isActivationModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAvailable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceStarted\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setActivationMode\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"active\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"RCS_STACK_PACKAGENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"extractServerException\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n</method>\n<method name=\"isIntendedException\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<parameter name=\"clazz\" type=\"java.lang.Class&lt;?&gt;\">\n</parameter>\n</method>\n</class>\n<interface name=\"RcsServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\">\n</parameter>\n</method>\n</interface>\n<class name=\"RcsServiceListener.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<class name=\"RcsServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsServiceRegistration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"RcsServiceRegistration.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceRegistrationListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"RcsUnsupportedOperationException\"\n extends=\"java.lang.UnsupportedOperationException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsUnsupportedOperationException\" type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"hasCapabilities\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"capabilities\" type=\"int\">\n</parameter>\n</method>\n<method name=\"isAutomata\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGeolocPushSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"8\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"16\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"AUTOMATA\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;automata&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_geoloc_push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<field name=\"EXTENSION_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"participants\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PARTICIPANTS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;participants&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.Content.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.Content.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.MimeType\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"GEOLOC_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;application/geoloc&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GROUPCHAT_EVENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;rcs/groupchat-event&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TEXT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;text/plain&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getContent\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getStatus\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearMessageDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGroupChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getOneToOneChat\"\n return=\"com.gsma.services.rcs.chat.OneToOneChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markMessageAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getGeolocExpirationTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGeolocLabelMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMinParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatSubjectMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getOneToOneChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isChatWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupChatSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isRespondToDisplayReportsEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setRespondToDisplayReports\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"inviteParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipant\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participant\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipants\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToLeave\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"leave\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.ParticipantStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_GROUP_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onMessageGroupDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onParticipantStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.chat.GroupChat.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"resendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"OneToOneChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_MESSAGE_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.MESSAGE_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"OneToOneChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneChatListener\"\n type=\"com.gsma.services.rcs.chat.OneToOneChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contact\"\n>\n<class name=\"ContactId\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n</class>\n<class name=\"ContactProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"MIME_TYPE_BLOCKING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_BLOCKING_TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactService\"\n type=\"com.gsma.services.rcs.contact.ContactService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"blockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getRcsContact\"\n return=\"com.gsma.services.rcs.contact.RcsContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unblockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ContactUtil\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"formatContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.contact.ContactUtil\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"getMyCountryAreaCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getMyCountryCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getVCard\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isMyCountryCodeDefined\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isValidContact\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBlockingTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isBlocked\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isOnline\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.extension\"\n>\n<class name=\"InstantMultimediaMessageIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INSTANT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_INSTANT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTENT_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contentType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SERVICE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;serviceId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaMessagingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"flushMessages\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaMessagingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_MESSAGING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaMessagingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaMessagingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onMessageReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onMessageReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onMessagesFlushed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"MultimediaSession\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSession.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSession.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSessionService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionService\"\n type=\"com.gsma.services.rcs.extension.MultimediaSessionService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.extension.MultimediaSessionServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaMessagingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaStreamingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"acceptTypes\" type=\"java.lang.String[]\">\n</parameter>\n<parameter name=\"acceptWrappedTypes\" type=\"java.lang.String[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"sendInstantMultimediaMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSessionServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMessagingSessionInactivityTimeout\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isServiceActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendPayload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_STREAMING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaStreamingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaStreamingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPayloadReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.filetransfer\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDisposition\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToPauseTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToResendTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToResumeTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"pauseTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"resendTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"resumeTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Disposition\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransfer.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_FILE_TRANSFER_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.FILE_TRANSFER_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_RESUME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.RESUME_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISPOSITION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;disposition&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN_EXPIRATION\"\n type=\"long\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0L\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.filetransfer.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearFileTransferDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteFileTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFileToGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markFileTransferAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"disposition\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFileToGroupChat\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFileToGroupChat\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"disposition\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getImageResizeOption\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxAudioMessageDuration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxFileTransfers\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptInRoamingEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setAutoAccept\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setAutoAcceptInRoaming\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setImageResizeOption\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"option\" type=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration.ImageResizeOption\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.groupdelivery\"\n>\n<class name=\"GroupDeliveryInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"GroupDeliveryInfo.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfo.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfoLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.history\"\n>\n<class name=\"HistoryLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISPOSITION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;disposition&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PROVIDER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;provider_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"HistoryService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryService\"\n type=\"com.gsma.services.rcs.history.HistoryService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"createUniqueId\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"registerExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<parameter name=\"providerUri\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"database\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"table\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"columnMapping\" type=\"java.util.Map&lt;java.lang.String, java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unregisterExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"HistoryUriBuilder\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryUriBuilder\"\n type=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"historyLogUri\" type=\"android.net.Uri\">\n</parameter>\n</constructor>\n<method name=\"appendProvider\"\n return=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n</method>\n<method name=\"build\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.geoloc\"\n>\n<class name=\"GeolocSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.geoloc.action.NEW_GEOLOC_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingListener\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"GeolocSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingService\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocSharing\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.image\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.image.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteImageSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.video\"\n>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoDescriptor\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setRemoteInfo\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.sharing.video.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n<parameter name=\"orientationHeaderId\" type=\"int\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDuration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoDescriptor\"\n return=\"com.gsma.services.rcs.sharing.video.VideoDescriptor\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Encoding\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"H264\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;H264&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.video.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HEIGHT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;height&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"VIDEO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;video_encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"WIDTH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;width&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.upload\"\n>\n<class name=\"FileUpload\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortUpload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadInfo\"\n return=\"com.gsma.services.rcs.upload.FileUploadInfo\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUpload.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadListener\"\n type=\"com.gsma.services.rcs.upload.FileUploadListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.upload.FileUpload.State\">\n</parameter>\n</method>\n<method name=\"onUploaded\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"info\" type=\"com.gsma.services.rcs.upload.FileUploadInfo\">\n</parameter>\n</method>\n</class>\n<class name=\"FileUploadService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadService\"\n type=\"com.gsma.services.rcs.upload.FileUploadService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"canUploadFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.upload.FileUploadServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUpload\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUploads\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.upload.FileUpload&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"uploadFile\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUploadServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n</api>\n"
  },
  {
    "path": "libs/api_cnx/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "libs/api_cnx/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n\tlintOptions {\n\t\tabortOnError false\n\t}\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    defaultConfig {\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n    }\n}\n\ndependencies {\n    compile project(':api')\n\tcompile 'com.android.support:support-v4:25.0.1'\n}"
  },
  {
    "path": "libs/api_cnx/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.rcs.api.connection\">\n\n</manifest>\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/ConnectionManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection;\n\nimport android.app.Activity;\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.util.Log;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceListener.ReasonCode;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.history.HistoryService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\nimport com.gsma.rcs.api.connection.utils.LogUtils;\nimport com.gsma.rcs.api.connection.utils.TimerUtils;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * A class to manage RCS API connections\n *\n * @author Philippe LEMORDANT\n */\npublic class ConnectionManager {\n\n    private static final String LOGTAG = LogUtils.getTag(ConnectionManager.class.getSimpleName());\n\n    private static final long API_DELAY_TO_CONNECT = 5000;\n\n    private static volatile ConnectionManager sInstance;\n    /**\n     * Set of connected services\n     */\n    private final Set<RcsServiceName> mConnectedServices;\n\n    /**\n     * Map of Activity / Client Connection notifier\n     */\n    private final Map<Activity, ClientConnectionNotifier> mClientsToNotify;\n\n    /**\n     * Map of RCS services and listeners\n     */\n    private final Map<RcsServiceName, RcsService> mApis;\n\n    private final Context mCtx;\n\n    private final RcsServiceControl mRcsServiceControl;\n\n    /**\n     * The set of managed services\n     */\n    private final Set<RcsServiceName> mManagedServices;\n\n    private final AlarmManager mAlarmManager;\n\n    private PendingIntent mCnxIntent;\n\n    private int mRetryCount;\n\n    private static final int MAX_RETRY_API_CNX = 4;\n\n    private static final String ACTION_CONNECT = \"com.gsma.rcs.ri.api.ACTION_CONNECT\";\n\n    /**\n     * Constructor\n     *\n     * @param context The context\n     * @param managedServices Set of managed services\n     * @param rcsServiceControl instance of RcsServiceControl\n     */\n    private ConnectionManager(Context context, Set<RcsServiceName> managedServices,\n            RcsServiceControl rcsServiceControl) {\n        mCtx = context;\n        mCnxIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_CONNECT), 0);\n        mAlarmManager = (AlarmManager) mCtx.getSystemService(Context.ALARM_SERVICE);\n\n        mManagedServices = managedServices;\n        mRcsServiceControl = rcsServiceControl;\n        /* Construct list of connected services */\n        mConnectedServices = new HashSet<>();\n        /* Construct list of clients to notify */\n        mClientsToNotify = new HashMap<>();\n        /* Construct list of APIs */\n        mApis = new HashMap<>();\n\n        if (managedServices == null || managedServices.isEmpty()) {\n            throw new RuntimeException(\"Incorrect parameter managedService!\");\n        }\n        /* Instantiate APIs */\n        for (RcsServiceName service : mManagedServices) {\n            switch (service) {\n                case CAPABILITY:\n                    mApis.put(RcsServiceName.CAPABILITY, new CapabilityService(context,\n                            newRcsServiceListener(RcsServiceName.CAPABILITY)));\n                    break;\n                case CHAT:\n                    mApis.put(RcsServiceName.CHAT, new ChatService(context,\n                            newRcsServiceListener(RcsServiceName.CHAT)));\n                    break;\n                case CONTACT:\n                    mApis.put(RcsServiceName.CONTACT, new ContactService(context,\n                            newRcsServiceListener(RcsServiceName.CONTACT)));\n                    break;\n                case FILE_TRANSFER:\n                    mApis.put(RcsServiceName.FILE_TRANSFER, new FileTransferService(context,\n                            newRcsServiceListener(RcsServiceName.FILE_TRANSFER)));\n                    break;\n                case FILE_UPLOAD:\n                    mApis.put(RcsServiceName.FILE_UPLOAD, new FileUploadService(context,\n                            newRcsServiceListener(RcsServiceName.FILE_UPLOAD)));\n                    break;\n                case GEOLOC_SHARING:\n                    mApis.put(RcsServiceName.GEOLOC_SHARING, new GeolocSharingService(context,\n                            newRcsServiceListener(RcsServiceName.GEOLOC_SHARING)));\n                    break;\n                case HISTORY:\n                    mApis.put(RcsServiceName.HISTORY, new HistoryService(context,\n                            newRcsServiceListener(RcsServiceName.HISTORY)));\n                    break;\n                case IMAGE_SHARING:\n                    mApis.put(RcsServiceName.IMAGE_SHARING, new ImageSharingService(context,\n                            newRcsServiceListener(RcsServiceName.IMAGE_SHARING)));\n                    break;\n                case MULTIMEDIA:\n                    mApis.put(RcsServiceName.MULTIMEDIA, new MultimediaSessionService(context,\n                            newRcsServiceListener(RcsServiceName.MULTIMEDIA)));\n                    break;\n                case VIDEO_SHARING:\n                    mApis.put(RcsServiceName.VIDEO_SHARING, new VideoSharingService(context,\n                            newRcsServiceListener(RcsServiceName.VIDEO_SHARING)));\n                    break;\n            }\n        }\n    }\n\n    /**\n     * Create a RCS service listener to monitor API connection\n     *\n     * @param service the service to monitor\n     * @return the listener\n     */\n    private RcsServiceListener newRcsServiceListener(final RcsServiceName service) {\n        return new RcsServiceListener() {\n            @Override\n            public void onServiceConnected() {\n                mConnectedServices.add(service);\n                notifyConnection(service);\n            }\n\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                mConnectedServices.remove(service);\n                notifyDisconnection(service, error);\n            }\n        };\n\n    }\n\n    /**\n     * Notify API disconnection to client\n     *\n     * @param service the disconnected service\n     * @param error the error\n     */\n    private void notifyDisconnection(RcsServiceName service, ReasonCode error) {\n        if (LogUtils.isActive) {\n            Log.w(LOGTAG, service.name() + \" \" + error);\n        }\n        for (ClientConnectionNotifier clientToNotify : mClientsToNotify.values()) {\n            Set<RcsServiceName> monitoredServices = clientToNotify.getMonitoredServices();\n            if (monitoredServices == null || monitoredServices.contains(service)) {\n                clientToNotify.notifyDisconnection(error);\n            }\n        }\n    }\n\n    private void notifyConnection(RcsServiceName service) {\n        if (LogUtils.isActive) {\n            Log.w(LOGTAG, service.name() + \" \" + \" is connected\");\n        }\n        for (ClientConnectionNotifier clienttoNotify : mClientsToNotify.values()) {\n            clienttoNotify.notifyConnection();\n        }\n    }\n\n    /**\n     * Get an instance of ConnectionManager.\n     *\n     * @param context the context\n     * @param rcsServiceControl instance of RcsServiceControl\n     * @param services list of managed services\n     * @return the singleton instance.\n     */\n    public static ConnectionManager createInstance(Context context,\n            RcsServiceControl rcsServiceControl, RcsServiceName... services) {\n        Set<RcsServiceName> managedServices = new HashSet<>();\n        Collections.addAll(managedServices, services);\n        return createInstance(context, rcsServiceControl, managedServices);\n    }\n\n    /**\n     * Get an instance of ConnectionManager.\n     *\n     * @param ctx the context\n     * @param rcsServiceControl instance of RcsServiceControl\n     * @param managedServices Set of managed services\n     * @return the singleton instance.\n     */\n    public static ConnectionManager createInstance(Context ctx,\n            RcsServiceControl rcsServiceControl, Set<RcsServiceName> managedServices) {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        synchronized (ConnectionManager.class) {\n            if (sInstance == null) {\n                if (ctx == null) {\n                    throw new IllegalArgumentException(\"Context is null\");\n                }\n                sInstance = new ConnectionManager(ctx, managedServices, rcsServiceControl);\n            }\n        }\n        return sInstance;\n    }\n\n    /**\n     * Gets the singleton instance of ConnectionManager.\n     *\n     * @return the singleton instance.\n     */\n    public static ConnectionManager getInstance() {\n        return sInstance;\n    }\n\n    /**\n     * Start connection manager\n     */\n    public void start() {\n        /* Register the broadcast receiver to catch ACTION_SERVICE_UP */\n        mCtx.registerReceiver(new RcsServiceReceiver(), new IntentFilter(\n                RcsService.ACTION_SERVICE_UP));\n        /* Register the broadcast receiver to pool periodically the API connections */\n        mCtx.registerReceiver(new ReceiveTimerToReConnectApi(), new IntentFilter(ACTION_CONNECT));\n        mRetryCount = 0;\n        connectApis();\n    }\n\n    /**\n     * Connect APIs\n     */\n    private void connectApis() {\n        try {\n            if (mRcsServiceControl.isServiceStarted()) {\n                /* Connect all APIs */\n                for (RcsServiceName service : mApis.keySet()) {\n                    /* Check if not already connected */\n                    if (!isServiceConnected(service)) {\n                        if (LogUtils.isActive) {\n                            Log.d(LOGTAG, \"Connect service \".concat(service.name()));\n                        }\n                        RcsService rcsService = mApis.get(service);\n                        rcsService.connect();\n                    }\n                }\n            }\n        } catch (RcsServiceException e) {\n            Log.w(LOGTAG, \"Cannot connect service API: \".concat(e.getMessage()));\n            mRetryCount++;\n            if (mRetryCount < MAX_RETRY_API_CNX) {\n                TimerUtils.setExactTimer(mAlarmManager, System.currentTimeMillis()\n                        + API_DELAY_TO_CONNECT, mCnxIntent);\n                if (LogUtils.isActive) {\n                    Log.d(LOGTAG, \"Set timer to retry API connection\");\n                }\n            } else {\n                Log.e(LOGTAG, \"Maximum attempts to connect API is reached\");\n            }\n        }\n    }\n\n    /**\n     * Check if services are connected\n     *\n     * @param services list of services\n     * @return true if all services of the list are connected\n     */\n    public boolean isServiceConnected(RcsServiceName... services) {\n        for (RcsServiceName service : services) {\n            if (!mManagedServices.contains(service)) {\n                throw new IllegalArgumentException(\"Service \" + service\n                        + \" does not belong to set of managed services!\");\n            }\n            if (!mConnectedServices.contains(service)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Start monitoring the API connection by using a callback listener\n     *\n     * @param activity the activity requesting to start monitoring the API connection\n     * @param listener Listener to execute in case of connection event\n     * @param services services to monitor\n     */\n    public void startMonitorApiCnx(Activity activity, RcsServiceListener listener,\n            RcsServiceName... services) {\n        mClientsToNotify.put(activity, new ClientConnectionNotifier(listener, services));\n    }\n\n    /**\n     * Start monitoring the services and finish activities if service is disconnected\n     *\n     * @param activity the activity requesting to start monitoring the services\n     * @param iFinishable the interface to finish activity\n     * @param services the list of services to monitor\n     */\n    public void startMonitorServices(Activity activity, IRcsActivityFinishable iFinishable,\n            RcsServiceName... services) {\n        mClientsToNotify.put(activity, new ClientConnectionNotifier(iFinishable, services));\n    }\n\n    /**\n     * Stop monitoring the services\n     *\n     * @param activity the activity requesting to stop monitoring the services\n     */\n    public void stopMonitorServices(Activity activity) {\n        mClientsToNotify.remove(activity);\n    }\n\n    /**\n     * Stop monitoring the API connection\n     *\n     * @param activity the activity requesting to stop monitoring the API connection\n     */\n    public void stopMonitorApiCnx(Activity activity) {\n        mClientsToNotify.remove(activity);\n    }\n\n    /**\n     * Get the instance of CapabilityService\n     *\n     * @return the instance\n     */\n    public CapabilityService getCapabilityApi() {\n        return (CapabilityService) mApis.get(RcsServiceName.CAPABILITY);\n    }\n\n    /**\n     * Get the instance of ChatService\n     *\n     * @return the instance\n     */\n    public ChatService getChatApi() {\n        return (ChatService) mApis.get(RcsServiceName.CHAT);\n    }\n\n    /**\n     * Get the instance of ContactsService\n     *\n     * @return the instance\n     */\n    public ContactService getContactApi() {\n        return (ContactService) mApis.get(RcsServiceName.CONTACT);\n    }\n\n    /**\n     * Get the instance of FileTransferService\n     *\n     * @return the instance\n     */\n    public FileTransferService getFileTransferApi() {\n        return (FileTransferService) mApis.get(RcsServiceName.FILE_TRANSFER);\n    }\n\n    /**\n     * Get the instance of VideoSharingService\n     *\n     * @return the instance\n     */\n    public VideoSharingService getVideoSharingApi() {\n        return (VideoSharingService) mApis.get(RcsServiceName.VIDEO_SHARING);\n    }\n\n    /**\n     * Get the instance of ImageSharingService\n     *\n     * @return the instance\n     */\n    public ImageSharingService getImageSharingApi() {\n        return (ImageSharingService) mApis.get(RcsServiceName.IMAGE_SHARING);\n    }\n\n    /**\n     * Get the instance of GeolocSharingService\n     *\n     * @return the instance\n     */\n    public GeolocSharingService getGeolocSharingApi() {\n        return (GeolocSharingService) mApis.get(RcsServiceName.GEOLOC_SHARING);\n    }\n\n    /**\n     * Get the instance of FileUploadService\n     *\n     * @return the instance\n     */\n    public FileUploadService getFileUploadApi() {\n        return (FileUploadService) mApis.get(RcsServiceName.FILE_UPLOAD);\n    }\n\n    /**\n     * Get the instance of MultimediaSessionService\n     *\n     * @return the instance\n     */\n    public MultimediaSessionService getMultimediaSessionApi() {\n        return (MultimediaSessionService) mApis.get(RcsServiceName.MULTIMEDIA);\n    }\n\n    /**\n     * Enumerated type for RCS service name\n     */\n    @SuppressWarnings(\"javadoc\")\n    public enum RcsServiceName {\n        CAPABILITY, CONTACT, CHAT, FILE_TRANSFER, IMAGE_SHARING, VIDEO_SHARING, GEOLOC_SHARING, FILE_UPLOAD, MULTIMEDIA, HISTORY\n    }\n\n    /**\n     * Client connection listener\n     */\n    private class ClientConnectionNotifier {\n        /**\n         * The set of monitored services\n         */\n        private final Set<RcsServiceName> mMonitoredServices;\n\n        private RcsServiceListener mListener;\n\n        private IRcsActivityFinishable mIFinishable;\n\n        /**\n         * Constructor\n         *\n         * @param iFinishable Callback called when exception is thrown\n         * @param services the list of services to monitor\n         */\n        public ClientConnectionNotifier(IRcsActivityFinishable iFinishable,\n                RcsServiceName... services) {\n            mIFinishable = iFinishable;\n            mMonitoredServices = new HashSet<>();\n            Collections.addAll(mMonitoredServices, services);\n        }\n\n        /**\n         * Constructor\n         *\n         * @param listener Listener to execute if a connection event occurs\n         * @param services services to notify\n         */\n        public ClientConnectionNotifier(RcsServiceListener listener, RcsServiceName... services) {\n            mListener = listener;\n            mMonitoredServices = new HashSet<>();\n            for (RcsServiceName service : services) {\n                if (!mManagedServices.contains(service)) {\n                    throw new IllegalArgumentException(\"Service \" + service\n                            + \" does not belong to set of managed services!\");\n                }\n                mMonitoredServices.add(service);\n            }\n        }\n\n        public void notifyConnection() {\n            if (mListener == null) {\n                return;\n            }\n            if (mConnectedServices.containsAll(mMonitoredServices)) {\n                /* All monitored services are connected -> notify connection */\n                mListener.onServiceConnected();\n                mRetryCount = 0;\n            }\n        }\n\n        public void notifyDisconnection(ReasonCode error) {\n            if (mIFinishable != null) {\n                String msg;\n                if (ReasonCode.SERVICE_DISABLED == error) {\n                    msg = \"RCS service disabled\";\n                } else {\n                    msg = \"RCS service disconnected\";\n                }\n                mIFinishable.showMessageThenExit(msg);\n                return;\n            }\n            if (mListener != null) {\n                mListener.onServiceDisconnected(error);\n            }\n        }\n\n        public Set<RcsServiceName> getMonitoredServices() {\n            return mMonitoredServices;\n        }\n\n    }\n\n    /**\n     * A broadcast receiver to catch ACTION_SERVICE_UP from the RCS stack\n     */\n    private class RcsServiceReceiver extends BroadcastReceiver {\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (!RcsService.ACTION_SERVICE_UP.equals(intent.getAction())) {\n                return;\n            }\n            if (LogUtils.isActive) {\n                Log.i(LOGTAG, \"RCS service is UP\");\n            }\n            /* Connect all APIs with delay */\n            mRetryCount = 0;\n            TimerUtils.setExactTimer(mAlarmManager, System.currentTimeMillis()\n                    + API_DELAY_TO_CONNECT, mCnxIntent);\n        }\n    }\n\n    private class ReceiveTimerToReConnectApi extends BroadcastReceiver {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            new Thread() {\n                public void run() {\n                    try {\n                        connectApis();\n\n                    } catch (RuntimeException e) {\n                        /*\n                         * Intentionally catch runtime exceptions as else it will abruptly end the\n                         * thread and eventually bring the whole system down, which is not intended.\n                         */\n                        Log.e(LOGTAG, \"Failed to pool connection to RCS service!\", e);\n                    }\n                }\n            }.start();\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/IRcsActivityFinishable.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection;\n\n/**\n * Created by LEMORDANT Philippe on 18/10/2015.\n */\npublic interface IRcsActivityFinishable {\n\n    /*\n     * A method to show a message in alert dialog and finish the RCS activity.\n     */\n    void showMessageThenExit(String msg);\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/DialogUtil.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.DialogInterface;\nimport android.util.Log;\n\nimport com.gsma.rcs.api.connection.R;\n\n/**\n * Dialog utility\n *\n * @author Philippe LEMORDANT\n */\n/* package private */class DialogUtil {\n\n    private static final String LOGTAG = LogUtils.getTag(DialogUtil.class.getSimpleName());\n\n    /**\n     * Show a message then exit activity\n     *\n     * @param activity the activity.\n     * @param msg the message\n     * @param locker the locker\n     */\n    public static void showMessageThenExit(final Activity activity, String msg, LockAccess locker) {\n        showMessageThenExit(activity, msg, locker, null);\n    }\n\n    /**\n     * Show a message then exit activity\n     *\n     * @param activity Activity\n     * @param msg Message to be displayed\n     * @param locker a locker to only execute once\n     * @param e the exception\n     */\n    private static void showMessageThenExit(final Activity activity, String msg, LockAccess locker,\n            Exception e) {\n        /* Do not execute if already executed once */\n        if (locker != null && !locker.tryLock()) {\n            return;\n        }\n        if (e != null) {\n            Log.e(LOGTAG, \"Exception enforces exit of activity!\");\n            Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        } else {\n            if (LogUtils.isActive) {\n                Log.w(LOGTAG,\n                        \"Exit activity \" + activity.getLocalClassName() + \" <\" + msg + \">\");\n            }\n        }\n        /* Do not execute if activity is Finishing */\n        if (activity.isFinishing()) {\n            return;\n        }\n        if (activity instanceof DialogUtil.IRegisterCloseDialog) {\n            ((DialogUtil.IRegisterCloseDialog) activity).closeDialog();\n        }\n        AlertDialog.Builder builder = new AlertDialog.Builder(activity);\n        builder.setMessage(msg);\n        builder.setTitle((e == null) ? R.string.title_msg : R.string.error_exception);\n        builder.setCancelable(false);\n        builder.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener() {\n            public void onClick(DialogInterface dialog, int which) {\n                activity.finish();\n            }\n        });\n        builder.show();\n    }\n\n    /**\n     * Show exception then exit activity\n     *\n     * @param activity Activity\n     * @param e the exception\n     * @param locker a locker to only execute once\n     */\n    public static void showExceptionThenExit(final Activity activity, Exception e, LockAccess locker) {\n        showMessageThenExit(activity, e.getMessage(), locker, e);\n    }\n\n    /**\n     * Show message\n     *\n     * @param activity Activity\n     * @param msg Message to be displayed\n     * @return Dialog\n     */\n    public static AlertDialog showMessage(Activity activity, String msg) {\n        if (LogUtils.isActive) {\n            Log.w(LOGTAG, \"Activity \" + activity.getLocalClassName() + \" message=\" + msg);\n        }\n        AlertDialog.Builder builder = new AlertDialog.Builder(activity);\n        builder.setMessage(msg);\n        builder.setTitle(R.string.title_msg);\n        builder.setCancelable(false);\n        builder.setPositiveButton(R.string.label_ok, null);\n        AlertDialog alert = builder.show();\n        if (activity instanceof DialogUtil.IRegisterCloseDialog) {\n            ((DialogUtil.IRegisterCloseDialog) activity).registerDialog(alert);\n        }\n        return alert;\n    }\n\n    /**\n     * @param activity the activity\n     * @param e exception to show\n     * @return alert dialog\n     */\n    public static AlertDialog showException(Activity activity, Exception e) {\n        Log.e(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n        /* Do not execute if activity is Finishing */\n        if (activity.isFinishing()) {\n            return null;\n        }\n        AlertDialog.Builder builder = new AlertDialog.Builder(activity);\n        String message = e.getMessage();\n        builder.setMessage((message != null) ? activity.getString(R.string.error_exception_message,\n                message) : activity.getString(R.string.error_exception));\n        builder.setTitle(R.string.title_msg);\n        builder.setCancelable(false);\n        builder.setPositiveButton(R.string.label_ok, null);\n        AlertDialog alert = builder.show();\n        if (activity instanceof DialogUtil.IRegisterCloseDialog) {\n            ((DialogUtil.IRegisterCloseDialog) activity).registerDialog(alert);\n        }\n        return alert;\n    }\n\n    /**\n     * Show an exception\n     *\n     * @param activity Activity\n     * @param e Exception to be displayed\n     * @return Dialog\n     */\n\n    /**\n     * Show a progress dialog with the given parameters\n     *\n     * @param activity Activity\n     * @param msg Message to be displayed\n     * @return Dialog\n     */\n    public static ProgressDialog showProgressDialog(Activity activity, String msg) {\n        ProgressDialog dlg = new ProgressDialog(activity);\n        dlg.setMessage(msg);\n        dlg.setIndeterminate(true);\n        dlg.setCancelable(true);\n        dlg.setCanceledOnTouchOutside(false);\n        dlg.show();\n        if (activity instanceof DialogUtil.IRegisterCloseDialog) {\n            ((DialogUtil.IRegisterCloseDialog) activity).registerDialog(dlg);\n        }\n        return dlg;\n    }\n\n    public interface IRegisterCloseDialog {\n\n        /**\n         * Closes dialog (if opened).\n         */\n        void closeDialog();\n\n        /**\n         * Registers the dialog. Activities displaying dialog must register it to enable automatic\n         * closing upon exception.\n         *\n         * @param dialog the dialog instance\n         */\n        void registerDialog(Dialog dialog);\n    }\n\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/ExceptionUtil.java",
    "content": "/*\n * Copyright (C) 2015 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage com.gsma.rcs.api.connection.utils;\n\npublic class ExceptionUtil {\n\n    /**\n     * Special Delimiter that will be appended while propagating server exceptions over AIDL layer.\n     */\n    private static final char DELIMITER_PIPE = '|';\n\n    public static String getFullStackTrace(Throwable t) {\n        StringBuilder sb = new StringBuilder();\n        addTrace(sb, t, true);\n        Throwable cause = t.getCause();\n        while (null != cause) {\n            addTrace(sb, cause, false);\n            cause = cause.getCause();\n        }\n        return sb.toString();\n    }\n\n    private static void addTrace(StringBuilder sb, Throwable t, boolean first) {\n        StackTraceElement[] traces = t.getStackTrace();\n        if (null != traces && traces.length > 0) {\n            if (!first) {\n                sb.append(\"Caused by: \");\n            }\n            sb.append(t.getClass().getName());\n            String msg = t.getMessage();\n            if (msg != null) {\n                sb.append(\": \");\n                if (first) {\n                    final int delimiterIndex = msg.indexOf(DELIMITER_PIPE);\n                    if (delimiterIndex > 0 && delimiterIndex < msg.length() - 1) {\n                        sb.append(msg.substring(delimiterIndex + 1));\n                    } else {\n                        sb.append(msg);\n                    }\n                } else {\n                    sb.append(msg);\n                }\n            }\n            sb.append('\\n');\n            for (StackTraceElement trace : traces) {\n                sb.append(\"\\tat \").append(trace.getClassName()).append('.')\n                        .append(trace.getMethodName()).append('(');\n                int lineNumber = trace.getLineNumber();\n                if (lineNumber > 0) {\n                    sb.append(trace.getFileName()).append(':').append(lineNumber);\n                } else {\n                    sb.append(\"Native Method\");\n                }\n                sb.append(')').append('\\n');\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/IConnectionManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\n\n/**\n * Interface to access the Connection manager\n *\n * @author LEMORDANT Philippe\n */\npublic interface IConnectionManager {\n\n    /**\n     * Start monitoring the API connection\n     */\n    void startMonitorApiCnx(RcsServiceListener listener, RcsServiceName... services);\n\n    /**\n     * Start monitoring the services\n     */\n    void startMonitorServices(RcsServiceName... services);\n\n    /**\n     * Stop monitoring the API connection\n     */\n    void stopMonitorApiCnx();\n\n    /**\n     * Check if activity is on foreground\n     */\n    boolean isOnForeground();\n\n    /**\n     * Check if services are connected\n     *\n     * @param services list of services\n     * @return true if all services of the list are connected\n     */\n    boolean isServiceConnected(RcsServiceName... services);\n\n    /**\n     * Get the instance of CapabilityService\n     *\n     * @return the instance\n     */\n    CapabilityService getCapabilityApi();\n\n    /**\n     * Get the instance of ChatService\n     *\n     * @return the instance\n     */\n    ChatService getChatApi();\n\n    /**\n     * Get the instance of ContactService\n     *\n     * @return the instance\n     */\n    ContactService getContactApi();\n\n    /**\n     * Get the instance of FileTransferService\n     *\n     * @return the instance\n     */\n    FileTransferService getFileTransferApi();\n\n    /**\n     * Get the instance of VideoSharingService\n     *\n     * @return the instance\n     */\n    VideoSharingService getVideoSharingApi();\n\n    /**\n     * Get the instance of ImageSharingService\n     *\n     * @return the instance\n     */\n    ImageSharingService getImageSharingApi();\n\n    /**\n     * Get the instance of GeolocSharingService\n     *\n     * @return the instance\n     */\n    GeolocSharingService getGeolocSharingApi();\n\n    /**\n     * Get the instance of FileUploadService\n     *\n     * @return the instance\n     */\n    FileUploadService getFileUploadApi();\n\n    /**\n     * Get the instance of MultimediaSessionService\n     *\n     * @return the instance\n     */\n    MultimediaSessionService getMultimediaSessionApi();\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/IRcsDialog.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\n\n/**\n * Interface to show an alert dialog to display message or exception and optionally to exit\n * activity.\n *\n * @author LEMORDANT Philippe\n */\npublic interface IRcsDialog {\n\n    /**\n     * Show message in alert dialog then exit activity\n     *\n     * @param msg The message to show\n     */\n    void showMessageThenExit(String msg);\n\n    /**\n     * Show message in alert dialog then exit activity\n     *\n     * @param resId The message to show\n     */\n    void showMessageThenExit(int resId);\n\n    /**\n     * Show exception in alert dialog then exit activity\n     *\n     * @param e The exception to show\n     */\n    void showExceptionThenExit(Exception e);\n\n    /**\n     * Show message in alert dialog\n     *\n     * @param msg The message to show\n     * @return the alert dialog\n     */\n    AlertDialog showMessage(String msg);\n\n    /**\n     * Show message in alert dialog\n     *\n     * @param resId The message to show\n     * @return the alert dialog\n     */\n    AlertDialog showMessage(int resId);\n\n    /**\n     * Show exception in alert dialog\n     *\n     * @param e The exception to show\n     * @return the alert dialog\n     */\n    AlertDialog showException(Exception e);\n\n    /**\n     * Show progress in alert dialog\n     *\n     * @param progress The progress to show\n     * @return the alert dialog\n     */\n    ProgressDialog showProgressDialog(String progress);\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/LockAccess.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * An object to lock access to a resource\n *\n * @author Philippe LEMORDANT\n */\npublic class LockAccess {\n\n    /**\n     * The locker object\n     */\n    AtomicBoolean locker = new AtomicBoolean();\n\n    /**\n     * Acquires the lock only if it is not already locked at the time of invocation\n     *\n     * @return true is resource is unlocked\n     */\n    public boolean tryLock() {\n        return locker.compareAndSet(false, true);\n    }\n\n    /**\n     * Checks if access is locked\n     *\n     * @return True if access is locked\n     */\n    public boolean isLocked() {\n        return locker.get();\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/LogUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\n/**\n * @author Philippe LEMORDANT\n */\npublic class LogUtils {\n\n    /**\n     * Flag {@code isActive} to disable or enable log\n     */\n    public static final boolean isActive = true;\n\n    /**\n     * Utility routine to forge log tag of the RI client application\n     *\n     * @param classname the class name\n     * @return the log tag\n     */\n    public static String getTag(final String classname) {\n        return \"[CNX][\" + classname + \"]\";\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/RcsActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.IRcsActivityFinishable;\nimport com.gsma.rcs.api.connection.R;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\n\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.os.Bundle;\nimport android.util.Log;\n\n/**\n * @author LEMORDANT Philippe\n */\npublic abstract class RcsActivity extends Activity implements DialogUtil.IRegisterCloseDialog,\n        IRcsDialog, IConnectionManager {\n\n    private Dialog mOpenedDialog;\n\n    private LockAccess mLockAcces = new LockAccess();\n\n    private ConnectionManager mCnxManager;\n\n    private IRcsActivityFinishable mIFinishable;\n\n    private boolean onForeground;\n    private static final String LOGTAG = LogUtils.getTag(RcsActivity.class.getSimpleName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mCnxManager = ConnectionManager.getInstance();\n        if (mIFinishable == null) {\n            mIFinishable = new IRcsActivityFinishable() {\n\n                @Override\n                public void showMessageThenExit(String msg) {\n                    if (!RcsActivity.this.isOnForeground()) {\n                        if (LogUtils.isActive) {\n                            Log.w(LOGTAG, \"Exit activity \" + RcsActivity.this.getLocalClassName()\n                                    + \" <\" + msg + \">\");\n                        }\n                        RcsActivity.this.finish();\n                    } else {\n                        DialogUtil.showMessageThenExit(RcsActivity.this, msg, mLockAcces);\n                    }\n                }\n            };\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        onForeground = true;\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        onForeground = false;\n    }\n\n    @Override\n    public boolean isOnForeground() {\n        return onForeground;\n    }\n\n    @Override\n    public void closeDialog() {\n        if (mOpenedDialog != null && mOpenedDialog.isShowing()) {\n            mOpenedDialog.dismiss();\n        }\n    }\n\n    @Override\n    public void registerDialog(Dialog dialog) {\n        mOpenedDialog = dialog;\n    }\n\n    @Override\n    public void showMessageThenExit(String msg) {\n        DialogUtil.showMessageThenExit(this, msg, mLockAcces);\n    }\n\n    @Override\n    public void showMessageThenExit(int resId) {\n        DialogUtil.showMessageThenExit(this, getString(resId), mLockAcces);\n    }\n\n    @Override\n    public void showExceptionThenExit(Exception e) {\n        /*\n         * Non bug exception should not produce log of stack trace.\n         */\n        if (e instanceof RcsServiceNotAvailableException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.label_service_not_available),\n                    mLockAcces);\n\n        } else if (e instanceof RcsServiceNotRegisteredException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.error_not_registered),\n                    mLockAcces);\n\n        } else {\n            DialogUtil.showExceptionThenExit(this, e, mLockAcces);\n        }\n    }\n\n    @Override\n    public AlertDialog showMessage(String msg) {\n        return DialogUtil.showMessage(this, msg);\n    }\n\n    @Override\n    public AlertDialog showMessage(int resId) {\n        return DialogUtil.showMessage(this, getString(resId));\n    }\n\n    @Override\n    public AlertDialog showException(Exception e) {\n        return DialogUtil.showException(this, e);\n    }\n\n    @Override\n    public ProgressDialog showProgressDialog(String msg) {\n        return DialogUtil.showProgressDialog(this, msg);\n    }\n\n    @Override\n    public void startMonitorApiCnx(RcsServiceListener listener, RcsServiceName... services) {\n        mCnxManager.startMonitorApiCnx(this, listener, services);\n    }\n\n    @Override\n    public void startMonitorServices(RcsServiceName... services) {\n        mCnxManager.startMonitorServices(this, mIFinishable, services);\n    }\n\n    @Override\n    public void stopMonitorApiCnx() {\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    public boolean isServiceConnected(RcsServiceName... services) {\n        return mCnxManager.isServiceConnected(services);\n    }\n\n    @Override\n    public CapabilityService getCapabilityApi() {\n        return mCnxManager.getCapabilityApi();\n    }\n\n    @Override\n    public ChatService getChatApi() {\n        return mCnxManager.getChatApi();\n    }\n\n    @Override\n    public ContactService getContactApi() {\n        return mCnxManager.getContactApi();\n    }\n\n    @Override\n    public FileTransferService getFileTransferApi() {\n        return mCnxManager.getFileTransferApi();\n    }\n\n    @Override\n    public VideoSharingService getVideoSharingApi() {\n        return mCnxManager.getVideoSharingApi();\n    }\n\n    @Override\n    public ImageSharingService getImageSharingApi() {\n        return mCnxManager.getImageSharingApi();\n    }\n\n    @Override\n    public GeolocSharingService getGeolocSharingApi() {\n        return mCnxManager.getGeolocSharingApi();\n    }\n\n    @Override\n    public FileUploadService getFileUploadApi() {\n        return mCnxManager.getFileUploadApi();\n    }\n\n    @Override\n    public MultimediaSessionService getMultimediaSessionApi() {\n        return mCnxManager.getMultimediaSessionApi();\n    }\n\n    public boolean isExiting() {\n        return mLockAcces.isLocked();\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/RcsFragmentActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.IRcsActivityFinishable;\nimport com.gsma.rcs.api.connection.R;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.util.Log;\n\n/**\n * @author LEMORDANT Philippe\n */\npublic abstract class RcsFragmentActivity extends FragmentActivity implements\n        DialogUtil.IRegisterCloseDialog, IRcsDialog, IConnectionManager {\n\n    private Dialog mOpenedDialog;\n\n    private LockAccess mLockAcces = new LockAccess();\n\n    private ConnectionManager mCnxManager;\n\n    private IRcsActivityFinishable mIFinishable;\n\n    private boolean onForeground;\n\n    private static final String LOGTAG = LogUtils.getTag(RcsFragmentActivity.class.getSimpleName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mCnxManager = ConnectionManager.getInstance();\n        if (mIFinishable == null) {\n            mIFinishable = new IRcsActivityFinishable() {\n\n                @Override\n                public void showMessageThenExit(String msg) {\n                    if (!RcsFragmentActivity.this.isOnForeground()) {\n                        if (LogUtils.isActive) {\n                            Log.w(LOGTAG,\n                                    \"Exit activity \" + RcsFragmentActivity.this.getLocalClassName()\n                                            + \" <\" + msg + \">\");\n                        }\n                        RcsFragmentActivity.this.finish();\n                    } else {\n                        DialogUtil.showMessageThenExit(RcsFragmentActivity.this, msg, mLockAcces);\n                    }\n                }\n            };\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        onForeground = true;\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        onForeground = false;\n    }\n\n    @Override\n    public boolean isOnForeground() {\n        return onForeground;\n    }\n\n    @Override\n    public void closeDialog() {\n        if (mOpenedDialog != null && mOpenedDialog.isShowing()) {\n            mOpenedDialog.dismiss();\n        }\n    }\n\n    @Override\n    public void registerDialog(Dialog dialog) {\n        mOpenedDialog = dialog;\n    }\n\n    @Override\n    public void showMessageThenExit(String msg) {\n        DialogUtil.showMessageThenExit(this, msg, mLockAcces);\n    }\n\n    @Override\n    public void showMessageThenExit(int resId) {\n        DialogUtil.showMessageThenExit(this, getString(resId), mLockAcces);\n    }\n\n    @Override\n    public void showExceptionThenExit(Exception e) {\n        /*\n         * Non bug exception should not produce log of stack trace.\n         */\n        if (e instanceof RcsServiceNotAvailableException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.label_service_not_available),\n                    mLockAcces);\n\n        } else if (e instanceof RcsServiceNotRegisteredException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.error_not_registered),\n                    mLockAcces);\n\n        } else {\n            DialogUtil.showExceptionThenExit(this, e, mLockAcces);\n        }\n    }\n\n    @Override\n    public AlertDialog showMessage(String msg) {\n        return DialogUtil.showMessage(this, msg);\n    }\n\n    @Override\n    public AlertDialog showMessage(int resId) {\n        return DialogUtil.showMessage(this, getString(resId));\n    }\n\n    @Override\n    public AlertDialog showException(Exception e) {\n        return DialogUtil.showException(this, e);\n    }\n\n    @Override\n    public ProgressDialog showProgressDialog(String msg) {\n        return DialogUtil.showProgressDialog(this, msg);\n    }\n\n    @Override\n    public void startMonitorApiCnx(RcsServiceListener listener, RcsServiceName... services) {\n        mCnxManager.startMonitorApiCnx(this, listener, services);\n    }\n\n    @Override\n    public void startMonitorServices(RcsServiceName... services) {\n        mCnxManager.startMonitorServices(this, mIFinishable, services);\n    }\n\n    @Override\n    public void stopMonitorApiCnx() {\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    public boolean isServiceConnected(RcsServiceName... services) {\n        return mCnxManager.isServiceConnected(services);\n    }\n\n    @Override\n    public CapabilityService getCapabilityApi() {\n        return mCnxManager.getCapabilityApi();\n    }\n\n    @Override\n    public ChatService getChatApi() {\n        return mCnxManager.getChatApi();\n    }\n\n    @Override\n    public ContactService getContactApi() {\n        return mCnxManager.getContactApi();\n    }\n\n    @Override\n    public FileTransferService getFileTransferApi() {\n        return mCnxManager.getFileTransferApi();\n    }\n\n    @Override\n    public VideoSharingService getVideoSharingApi() {\n        return mCnxManager.getVideoSharingApi();\n    }\n\n    @Override\n    public ImageSharingService getImageSharingApi() {\n        return mCnxManager.getImageSharingApi();\n    }\n\n    @Override\n    public GeolocSharingService getGeolocSharingApi() {\n        return mCnxManager.getGeolocSharingApi();\n    }\n\n    @Override\n    public FileUploadService getFileUploadApi() {\n        return mCnxManager.getFileUploadApi();\n    }\n\n    @Override\n    public MultimediaSessionService getMultimediaSessionApi() {\n        return mCnxManager.getMultimediaSessionApi();\n    }\n\n    public boolean isExiting() {\n        return mLockAcces.isLocked();\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/RcsListActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.IRcsActivityFinishable;\nimport com.gsma.rcs.api.connection.R;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ListActivity;\nimport android.app.ProgressDialog;\nimport android.os.Bundle;\nimport android.util.Log;\n\n/**\n * @author LEMORDANT Philippe\n */\npublic abstract class RcsListActivity extends ListActivity implements\n        DialogUtil.IRegisterCloseDialog, IRcsDialog, IConnectionManager {\n\n    private Dialog mOpenedDialog;\n\n    private LockAccess mLockAcces = new LockAccess();\n\n    private ConnectionManager mCnxManager;\n\n    private IRcsActivityFinishable mIFinishable;\n\n    private boolean onForeground;\n\n    private static final String LOGTAG = LogUtils.getTag(RcsListActivity.class.getSimpleName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mCnxManager = ConnectionManager.getInstance();\n        if (mIFinishable == null) {\n            mIFinishable = new IRcsActivityFinishable() {\n\n                @Override\n                public void showMessageThenExit(String msg) {\n                    if (!RcsListActivity.this.isOnForeground()) {\n                        if (LogUtils.isActive) {\n                            Log.w(LOGTAG,\n                                    \"Exit activity \" + RcsListActivity.this.getLocalClassName()\n                                            + \" <\" + msg + \">\");\n                        }\n                        RcsListActivity.this.finish();\n                    } else {\n                        DialogUtil.showMessageThenExit(RcsListActivity.this, msg, mLockAcces);\n                    }\n                }\n            };\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        onForeground = true;\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        onForeground = false;\n    }\n\n    @Override\n    public boolean isOnForeground() {\n        return onForeground;\n    }\n\n    @Override\n    public void closeDialog() {\n        if (mOpenedDialog != null && mOpenedDialog.isShowing()) {\n            mOpenedDialog.dismiss();\n        }\n    }\n\n    @Override\n    public void registerDialog(Dialog dialog) {\n        mOpenedDialog = dialog;\n    }\n\n    @Override\n    public void showMessageThenExit(String msg) {\n        DialogUtil.showMessageThenExit(this, msg, mLockAcces);\n    }\n\n    @Override\n    public void showMessageThenExit(int resId) {\n        DialogUtil.showMessageThenExit(this, getString(resId), mLockAcces);\n    }\n\n    @Override\n    public void showExceptionThenExit(Exception e) {\n        /*\n         * Non bug exception should not produce log of stack trace.\n         */\n        if (e instanceof RcsServiceNotAvailableException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.label_service_not_available),\n                    mLockAcces);\n\n        } else if (e instanceof RcsServiceNotRegisteredException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.error_not_registered),\n                    mLockAcces);\n\n        } else {\n            DialogUtil.showExceptionThenExit(this, e, mLockAcces);\n        }\n    }\n\n    @Override\n    public AlertDialog showMessage(String msg) {\n        return DialogUtil.showMessage(this, msg);\n    }\n\n    @Override\n    public AlertDialog showMessage(int resId) {\n        return DialogUtil.showMessage(this, getString(resId));\n    }\n\n    @Override\n    public AlertDialog showException(Exception e) {\n        return DialogUtil.showException(this, e);\n    }\n\n    @Override\n    public ProgressDialog showProgressDialog(String msg) {\n        return DialogUtil.showProgressDialog(this, msg);\n    }\n\n    @Override\n    public void startMonitorApiCnx(RcsServiceListener listener, RcsServiceName... services) {\n        mCnxManager.startMonitorApiCnx(this, listener, services);\n    }\n\n    @Override\n    public void startMonitorServices(RcsServiceName... services) {\n        mCnxManager.startMonitorServices(this, mIFinishable, services);\n    }\n\n    @Override\n    public void stopMonitorApiCnx() {\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    public boolean isServiceConnected(RcsServiceName... services) {\n        return mCnxManager.isServiceConnected(services);\n    }\n\n    @Override\n    public CapabilityService getCapabilityApi() {\n        return mCnxManager.getCapabilityApi();\n    }\n\n    @Override\n    public ChatService getChatApi() {\n        return mCnxManager.getChatApi();\n    }\n\n    @Override\n    public ContactService getContactApi() {\n        return mCnxManager.getContactApi();\n    }\n\n    @Override\n    public FileTransferService getFileTransferApi() {\n        return mCnxManager.getFileTransferApi();\n    }\n\n    @Override\n    public VideoSharingService getVideoSharingApi() {\n        return mCnxManager.getVideoSharingApi();\n    }\n\n    @Override\n    public ImageSharingService getImageSharingApi() {\n        return mCnxManager.getImageSharingApi();\n    }\n\n    @Override\n    public GeolocSharingService getGeolocSharingApi() {\n        return mCnxManager.getGeolocSharingApi();\n    }\n\n    @Override\n    public FileUploadService getFileUploadApi() {\n        return mCnxManager.getFileUploadApi();\n    }\n\n    @Override\n    public MultimediaSessionService getMultimediaSessionApi() {\n        return mCnxManager.getMultimediaSessionApi();\n    }\n\n    public boolean isExiting() {\n        return mLockAcces.isLocked();\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/RcsPreferenceActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.IRcsActivityFinishable;\nimport com.gsma.rcs.api.connection.R;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingService;\nimport com.gsma.services.rcs.sharing.image.ImageSharingService;\nimport com.gsma.services.rcs.sharing.video.VideoSharingService;\nimport com.gsma.services.rcs.upload.FileUploadService;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.os.Bundle;\nimport android.preference.PreferenceActivity;\nimport android.util.Log;\n\n/**\n * @author LEMORDANT Philippe\n */\npublic abstract class RcsPreferenceActivity extends PreferenceActivity implements\n        DialogUtil.IRegisterCloseDialog, IRcsDialog, IConnectionManager {\n\n    private Dialog mOpenedDialog;\n\n    private LockAccess mLockAcces = new LockAccess();\n\n    private ConnectionManager mCnxManager;\n\n    private IRcsActivityFinishable mIFinishable;\n\n    private boolean onForeground;\n\n    private static final String LOGTAG = LogUtils.getTag(RcsPreferenceActivity.class\n            .getSimpleName());\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mCnxManager = ConnectionManager.getInstance();\n        if (mIFinishable == null) {\n            mIFinishable = new IRcsActivityFinishable() {\n\n                @Override\n                public void showMessageThenExit(String msg) {\n                    if (!RcsPreferenceActivity.this.isOnForeground()) {\n                        if (LogUtils.isActive) {\n                            Log.w(LOGTAG,\n                                    \"Exit activity \"\n                                            + RcsPreferenceActivity.this.getLocalClassName() + \" <\"\n                                            + msg + \">\");\n                        }\n                        RcsPreferenceActivity.this.finish();\n                    } else {\n                        DialogUtil.showMessageThenExit(RcsPreferenceActivity.this, msg, mLockAcces);\n                    }\n                }\n            };\n        }\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        onForeground = true;\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        onForeground = false;\n    }\n\n    @Override\n    public boolean isOnForeground() {\n        return onForeground;\n    }\n\n    @Override\n    public void closeDialog() {\n        if (mOpenedDialog != null && mOpenedDialog.isShowing()) {\n            mOpenedDialog.dismiss();\n        }\n    }\n\n    @Override\n    public void registerDialog(Dialog dialog) {\n        mOpenedDialog = dialog;\n    }\n\n    @Override\n    public void showMessageThenExit(String msg) {\n        DialogUtil.showMessageThenExit(this, msg, mLockAcces);\n    }\n\n    @Override\n    public void showMessageThenExit(int resId) {\n        DialogUtil.showMessageThenExit(this, getString(resId), mLockAcces);\n    }\n\n    @Override\n    public void showExceptionThenExit(Exception e) {\n        /*\n         * Non bug exception should not produce log of stack trace.\n         */\n        if (e instanceof RcsServiceNotAvailableException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.label_service_not_available),\n                    mLockAcces);\n\n        } else if (e instanceof RcsServiceNotRegisteredException) {\n            DialogUtil.showMessageThenExit(this, getString(R.string.error_not_registered),\n                    mLockAcces);\n\n        } else {\n            DialogUtil.showExceptionThenExit(this, e, mLockAcces);\n        }\n    }\n\n    @Override\n    public AlertDialog showMessage(String msg) {\n        return DialogUtil.showMessage(this, msg);\n    }\n\n    @Override\n    public AlertDialog showMessage(int resId) {\n        return DialogUtil.showMessage(this, getString(resId));\n    }\n\n    @Override\n    public AlertDialog showException(Exception e) {\n        return DialogUtil.showException(this, e);\n    }\n\n    @Override\n    public ProgressDialog showProgressDialog(String msg) {\n        return DialogUtil.showProgressDialog(this, msg);\n    }\n\n    @Override\n    public void startMonitorApiCnx(RcsServiceListener listener, RcsServiceName... services) {\n        mCnxManager.startMonitorApiCnx(this, listener, services);\n    }\n\n    @Override\n    public void startMonitorServices(RcsServiceName... services) {\n        mCnxManager.startMonitorServices(this, mIFinishable, services);\n    }\n\n    @Override\n    public void stopMonitorApiCnx() {\n        mCnxManager.stopMonitorServices(this);\n    }\n\n    @Override\n    public boolean isServiceConnected(RcsServiceName... services) {\n        return mCnxManager.isServiceConnected(services);\n    }\n\n    @Override\n    public CapabilityService getCapabilityApi() {\n        return mCnxManager.getCapabilityApi();\n    }\n\n    @Override\n    public ChatService getChatApi() {\n        return mCnxManager.getChatApi();\n    }\n\n    @Override\n    public ContactService getContactApi() {\n        return mCnxManager.getContactApi();\n    }\n\n    @Override\n    public FileTransferService getFileTransferApi() {\n        return mCnxManager.getFileTransferApi();\n    }\n\n    @Override\n    public VideoSharingService getVideoSharingApi() {\n        return mCnxManager.getVideoSharingApi();\n    }\n\n    @Override\n    public ImageSharingService getImageSharingApi() {\n        return mCnxManager.getImageSharingApi();\n    }\n\n    @Override\n    public GeolocSharingService getGeolocSharingApi() {\n        return mCnxManager.getGeolocSharingApi();\n    }\n\n    @Override\n    public FileUploadService getFileUploadApi() {\n        return mCnxManager.getFileUploadApi();\n    }\n\n    @Override\n    public MultimediaSessionService getMultimediaSessionApi() {\n        return mCnxManager.getMultimediaSessionApi();\n    }\n\n    public boolean isExiting() {\n        return mLockAcces.isLocked();\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/java/com/gsma/rcs/api/connection/utils/TimerUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n * Copyright (C) 2014 Sony Mobile Communications Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.api.connection.utils;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.os.Build;\n\npublic class TimerUtils {\n\n    /**\n     * Schedule an alarm with exact timer\n     * \n     * @param alarmManager The alarm manager\n     * @param triggerAtMillis time in milliseconds that the alarm should go off. @param operation\n     *            Action to perform when the alarm goes off\n     */\n    public static void setExactTimer(AlarmManager alarmManager, long triggerAtMillis,\n            PendingIntent operation) {\n        /*\n         * Beginning with API 19 (KITKAT), alarm delivery is inexact. The OS will shift alarms in\n         * order to minimize wake ups and battery use. The new API setExact(int, long,\n         * PendingIntent) will support applications which need strict delivery guarantees.\n         * Applications whose targetSdkVersion is earlier than API 19 will continue to see the\n         * previous behavior in which all alarms are delivered exactly when requested.\n         */\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {\n            alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);\n        } else {\n            alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, operation);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/api_cnx/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"error_not_registered\">Not registered to IMS</string>\n    <string name=\"label_service_not_available\">The service is not available. Please retry later.</string>\n\n    <string name=\"title_msg\">Information</string>\n    <string name=\"label_ok\">OK</string>\n\t\n\t<string name=\"error_exception_message\">%1$s: see Logcat!</string>\n\t<string name=\"error_exception\">\"Exception occurred! See Logcat.\"</string>\n\n</resources>"
  },
  {
    "path": "libs/bouncycastle/AndroidManifestLibrary.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     package=\"local.org.bouncycastle\">\n</manifest>"
  },
  {
    "path": "libs/bouncycastle/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifestLibrary.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\t\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic interface ASN1ApplicationSpecificParser\n    extends ASN1Encodable, InMemoryRepresentable\n{\n    ASN1Encodable readObject()\n        throws IOException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Boolean.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic class ASN1Boolean\n    extends DERBoolean\n{\n    public ASN1Boolean(boolean value)\n    {\n        super(value);\n    }\n\n    ASN1Boolean(byte[] value)\n    {\n        super(value);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Choice.java",
    "content": "package local.org.bouncycastle.asn1;\n\n/**\n * Marker interface for CHOICE objects - if you implement this in a role your\n * own object any attempt to tag the object implicitly will convert the tag to\n * an explicit one as the encoding rules require.\n * <p>\n * If you use this interface your class should also implement the getInstance\n * pattern which takes a tag object and the tagging mode used. \n */\npublic interface ASN1Choice\n{\n    // marker interface\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Encodable.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic interface ASN1Encodable\n{\n    ASN1Primitive toASN1Primitive();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1EncodableVector.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.util.Enumeration;\nimport java.util.Vector;\n\npublic class ASN1EncodableVector\n{\n    Vector v = new Vector();\n\n    public ASN1EncodableVector()\n    {\n    }\n\n    public void add(ASN1Encodable obj)\n    {\n        v.addElement(obj);\n    }\n\n    public void addAll(ASN1EncodableVector other)\n    {\n        for (Enumeration en = other.v.elements(); en.hasMoreElements();)\n        {\n            v.addElement(en.nextElement());\n        }\n    }\n\n    public ASN1Encodable get(int i)\n    {\n        return (ASN1Encodable)v.elementAt(i);\n    }\n\n    public int size()\n    {\n        return v.size();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Encoding.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic interface ASN1Encoding\n{\n    static final String DER = \"DER\";\n    static final String DL = \"DL\";\n    static final String BER = \"BER\";\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Enumerated.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.math.BigInteger;\n\npublic class ASN1Enumerated\n    extends DEREnumerated\n{\n    ASN1Enumerated(byte[] bytes)\n    {\n        super(bytes);\n    }\n\n    public ASN1Enumerated(BigInteger value)\n    {\n        super(value);\n    }\n\n    public ASN1Enumerated(int value)\n    {\n        super(value);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Exception.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class ASN1Exception\n    extends IOException\n{\n    private Throwable cause;\n\n    ASN1Exception(String message)\n    {\n        super(message);\n    }\n\n    ASN1Exception(String message, Throwable cause)\n    {\n        super(message);\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1GeneralizedTime.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.util.Date;\n\npublic class ASN1GeneralizedTime\n    extends DERGeneralizedTime\n{\n    ASN1GeneralizedTime(byte[] bytes)\n    {\n        super(bytes);\n    }\n\n    public ASN1GeneralizedTime(Date time)\n    {\n        super(time);\n    }\n\n    public ASN1GeneralizedTime(String time)\n    {\n        super(time);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Generator.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.OutputStream;\n\npublic abstract class ASN1Generator\n{\n    protected OutputStream _out;\n    \n    public ASN1Generator(OutputStream out)\n    {\n        _out = out;\n    }\n    \n    public abstract OutputStream getRawOutputStream();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1InputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.EOFException;\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport local.org.bouncycastle.util.io.Streams;\n\n\n/**\n * a general purpose ASN.1 decoder - note: this class differs from the\n * others in that it returns null after it has read the last object in\n * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is\n * returned.\n */\npublic class ASN1InputStream\n    extends FilterInputStream\n    implements BERTags\n{\n    private final int limit;\n    private final boolean lazyEvaluate;\n\n    private final byte[][] tmpBuffers;\n\n    public ASN1InputStream(\n        InputStream is)\n    {\n        this(is, StreamUtil.findLimit(is));\n    }\n\n    /**\n     * Create an ASN1InputStream based on the input byte array. The length of DER objects in\n     * the stream is automatically limited to the length of the input array.\n     * \n     * @param input array containing ASN.1 encoded data.\n     */\n    public ASN1InputStream(\n        byte[] input)\n    {\n        this(new ByteArrayInputStream(input), input.length);\n    }\n\n    /**\n     * Create an ASN1InputStream based on the input byte array. The length of DER objects in\n     * the stream is automatically limited to the length of the input array.\n     *\n     * @param input array containing ASN.1 encoded data.\n     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.\n     */\n    public ASN1InputStream(\n        byte[] input,\n        boolean lazyEvaluate)\n    {\n        this(new ByteArrayInputStream(input), input.length, lazyEvaluate);\n    }\n    \n    /**\n     * Create an ASN1InputStream where no DER object will be longer than limit.\n     * \n     * @param input stream containing ASN.1 encoded data.\n     * @param limit maximum size of a DER encoded object.\n     */\n    public ASN1InputStream(\n        InputStream input,\n        int         limit)\n    {\n        this(input, limit, false);\n    }\n\n    /**\n     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed\n     * objects such as sequences will be parsed lazily.\n     *\n     * @param input stream containing ASN.1 encoded data.\n     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.\n     */\n    public ASN1InputStream(\n        InputStream input,\n        boolean     lazyEvaluate)\n    {\n        this(input, StreamUtil.findLimit(input), lazyEvaluate);\n    }\n\n    /**\n     * Create an ASN1InputStream where no DER object will be longer than limit, and constructed\n     * objects such as sequences will be parsed lazily.\n     *\n     * @param input stream containing ASN.1 encoded data.\n     * @param limit maximum size of a DER encoded object.\n     * @param lazyEvaluate true if parsing inside constructed objects can be delayed.\n     */\n    public ASN1InputStream(\n        InputStream input,\n        int         limit,\n        boolean     lazyEvaluate)\n    {\n        super(input);\n        this.limit = limit;\n        this.lazyEvaluate = lazyEvaluate;\n        this.tmpBuffers = new byte[11][];\n    }\n\n    int getLimit()\n    {\n        return limit;\n    }\n\n    protected int readLength()\n        throws IOException\n    {\n        return readLength(this, limit);\n    }\n\n    protected void readFully(\n        byte[]  bytes)\n        throws IOException\n    {\n        if (Streams.readFully(this, bytes) != bytes.length)\n        {\n            throw new EOFException(\"EOF encountered in middle of object\");\n        }\n    }\n\n    /**\n     * build an object given its tag and the number of bytes to construct it from.\n     */\n    protected ASN1Primitive buildObject(\n        int       tag,\n        int       tagNo,\n        int       length)\n        throws IOException\n    {\n        boolean isConstructed = (tag & CONSTRUCTED) != 0;\n\n        DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);\n\n        if ((tag & APPLICATION) != 0)\n        {\n            return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());\n        }\n\n        if ((tag & TAGGED) != 0)\n        {\n            return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);\n        }\n\n        if (isConstructed)\n        {\n            // TODO There are other tags that may be constructed (e.g. BIT_STRING)\n            switch (tagNo)\n            {\n                case OCTET_STRING:\n                    //\n                    // yes, people actually do this...\n                    //\n                    ASN1EncodableVector v = buildDEREncodableVector(defIn);\n                    ASN1OctetString[] strings = new ASN1OctetString[v.size()];\n\n                    for (int i = 0; i != strings.length; i++)\n                    {\n                        strings[i] = (ASN1OctetString)v.get(i);\n                    }\n\n                    return new BEROctetString(strings);\n                case SEQUENCE:\n                    if (lazyEvaluate)\n                    {\n                        return new LazyEncodedSequence(defIn.toByteArray());\n                    }\n                    else\n                    {\n                        return DERFactory.createSequence(buildDEREncodableVector(defIn));   \n                    }\n                case SET:\n                    return DERFactory.createSet(buildDEREncodableVector(defIn));\n                case EXTERNAL:\n                    return new DERExternal(buildDEREncodableVector(defIn));                \n                default:\n                    throw new IOException(\"unknown tag \" + tagNo + \" encountered\");\n            }\n        }\n\n        return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);\n    }\n\n    ASN1EncodableVector buildEncodableVector()\n        throws IOException\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n        ASN1Primitive o;\n\n        while ((o = readObject()) != null)\n        {\n            v.add(o);\n        }\n\n        return v;\n    }\n\n    ASN1EncodableVector buildDEREncodableVector(\n        DefiniteLengthInputStream dIn) throws IOException\n    {\n        return new ASN1InputStream(dIn).buildEncodableVector();\n    }\n\n    public ASN1Primitive readObject()\n        throws IOException\n    {\n        int tag = read();\n        if (tag <= 0)\n        {\n            if (tag == 0)\n            {\n                throw new IOException(\"unexpected end-of-contents marker\");\n            }\n\n            return null;\n        }\n\n        //\n        // calculate tag number\n        //\n        int tagNo = readTagNumber(this, tag);\n\n        boolean isConstructed = (tag & CONSTRUCTED) != 0;\n\n        //\n        // calculate length\n        //\n        int length = readLength();\n\n        if (length < 0) // indefinite length method\n        {\n            if (!isConstructed)\n            {\n                throw new IOException(\"indefinite length primitive encoding encountered\");\n            }\n\n            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);\n            ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);\n\n            if ((tag & APPLICATION) != 0)\n            {\n                return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();\n            }\n\n            if ((tag & TAGGED) != 0)\n            {\n                return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();\n            }\n\n            // TODO There are other tags that may be constructed (e.g. BIT_STRING)\n            switch (tagNo)\n            {\n                case OCTET_STRING:\n                    return new BEROctetStringParser(sp).getLoadedObject();\n                case SEQUENCE:\n                    return new BERSequenceParser(sp).getLoadedObject();\n                case SET:\n                    return new BERSetParser(sp).getLoadedObject();\n                case EXTERNAL:\n                    return new DERExternalParser(sp).getLoadedObject();\n                default:\n                    throw new IOException(\"unknown BER object encountered\");\n            }\n        }\n        else\n        {\n            try\n            {\n                return buildObject(tag, tagNo, length);\n            }\n            catch (IllegalArgumentException e)\n            {\n                throw new ASN1Exception(\"corrupted stream detected\", e);\n            }\n        }\n    }\n\n    static int readTagNumber(InputStream s, int tag) \n        throws IOException\n    {\n        int tagNo = tag & 0x1f;\n\n        //\n        // with tagged object tag number is bottom 5 bits, or stored at the start of the content\n        //\n        if (tagNo == 0x1f)\n        {\n            tagNo = 0;\n\n            int b = s.read();\n\n            // X.690-0207 8.1.2.4.2\n            // \"c) bits 7 to 1 of the first subsequent octet shall not all be zero.\"\n            if ((b & 0x7f) == 0) // Note: -1 will pass\n            {\n                throw new IOException(\"corrupted stream - invalid high tag number found\");\n            }\n\n            while ((b >= 0) && ((b & 0x80) != 0))\n            {\n                tagNo |= (b & 0x7f);\n                tagNo <<= 7;\n                b = s.read();\n            }\n\n            if (b < 0)\n            {\n                throw new EOFException(\"EOF found inside tag value.\");\n            }\n            \n            tagNo |= (b & 0x7f);\n        }\n        \n        return tagNo;\n    }\n\n    static int readLength(InputStream s, int limit)\n        throws IOException\n    {\n        int length = s.read();\n        if (length < 0)\n        {\n            throw new EOFException(\"EOF found when length expected\");\n        }\n\n        if (length == 0x80)\n        {\n            return -1;      // indefinite-length encoding\n        }\n\n        if (length > 127)\n        {\n            int size = length & 0x7f;\n\n            // Note: The invalid long form \"0xff\" (see X.690 8.1.3.5c) will be caught here\n            if (size > 4)\n            {\n                throw new IOException(\"DER length more than 4 bytes: \" + size);\n            }\n\n            length = 0;\n            for (int i = 0; i < size; i++)\n            {\n                int next = s.read();\n\n                if (next < 0)\n                {\n                    throw new EOFException(\"EOF found reading length\");\n                }\n\n                length = (length << 8) + next;\n            }\n\n            if (length < 0)\n            {\n                throw new IOException(\"corrupted stream - negative length found\");\n            }\n\n            if (length >= limit)   // after all we must have read at least 1 byte\n            {\n                throw new IOException(\"corrupted stream - out of bounds length found\");\n            }\n        }\n\n        return length;\n    }\n\n    private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)\n        throws IOException\n    {\n        int len = defIn.getRemaining();\n        if (defIn.getRemaining() < tmpBuffers.length)\n        {\n            byte[] buf = tmpBuffers[len];\n\n            if (buf == null)\n            {\n                buf = tmpBuffers[len] = new byte[len];\n            }\n\n            Streams.readFully(defIn, buf);\n\n            return buf;\n        }\n        else\n        {\n            return defIn.toByteArray();\n        }\n    }\n\n    private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)\n        throws IOException\n    {\n        int len = defIn.getRemaining() / 2;\n        char[] buf = new char[len];\n        int totalRead = 0;\n        while (totalRead < len)\n        {\n            int ch1 = defIn.read();\n            if (ch1 < 0)\n            {\n                break;\n            }\n            int ch2 = defIn.read();\n            if (ch2 < 0)\n            {\n                break;\n            }\n            buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));\n        }\n\n        return buf;\n    }\n\n    static ASN1Primitive createPrimitiveDERObject(\n        int     tagNo,\n        DefiniteLengthInputStream defIn,\n        byte[][] tmpBuffers)\n        throws IOException\n    {\n        switch (tagNo)\n        {\n            case BIT_STRING:\n                return DERBitString.fromInputStream(defIn.getRemaining(), defIn);\n            case BMP_STRING:\n                return new DERBMPString(getBMPCharBuffer(defIn));\n            case BOOLEAN:\n                return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));\n            case ENUMERATED:\n                return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));\n            case GENERALIZED_TIME:\n                return new ASN1GeneralizedTime(defIn.toByteArray());\n            case GENERAL_STRING:\n                return new DERGeneralString(defIn.toByteArray());\n            case IA5_STRING:\n                return new DERIA5String(defIn.toByteArray());\n            case INTEGER:\n                return new ASN1Integer(defIn.toByteArray());\n            case NULL:\n                return DERNull.INSTANCE;   // actual content is ignored (enforce 0 length?)\n            case NUMERIC_STRING:\n                return new DERNumericString(defIn.toByteArray());\n            case OBJECT_IDENTIFIER:\n                return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));\n            case OCTET_STRING:\n                return new DEROctetString(defIn.toByteArray());\n            case PRINTABLE_STRING:\n                return new DERPrintableString(defIn.toByteArray());\n            case T61_STRING:\n                return new DERT61String(defIn.toByteArray());\n            case UNIVERSAL_STRING:\n                return new DERUniversalString(defIn.toByteArray());\n            case UTC_TIME:\n                return new ASN1UTCTime(defIn.toByteArray());\n            case UTF8_STRING:\n                return new DERUTF8String(defIn.toByteArray());\n            case VISIBLE_STRING:\n                return new DERVisibleString(defIn.toByteArray());\n            default:\n                throw new IOException(\"unknown tag \" + tagNo + \" encountered\");\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Integer.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.math.BigInteger;\n\npublic class ASN1Integer\n    extends DERInteger\n{\n    ASN1Integer(byte[] bytes)\n    {\n        super(bytes);\n    }\n\n    public ASN1Integer(BigInteger value)\n    {\n        super(value);\n    }\n\n    public ASN1Integer(long value)\n    {\n        super(value);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Null.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\n/**\n * A NULL object.\n */\npublic abstract class ASN1Null\n    extends ASN1Primitive\n{\n    /**\n     * @deprecated use DERNull.INSTANCE\n     */\n    public ASN1Null()\n    {\n    }\n\n    public static ASN1Null getInstance(Object o)\n    {\n        if (o instanceof ASN1Null)\n        {\n            return (ASN1Null)o;\n        }\n\n        if (o != null)\n        {\n            try\n            {\n                return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"failed to construct NULL from byte[]: \" + e.getMessage());\n            }\n            catch (ClassCastException e)\n            {\n                throw new IllegalArgumentException(\"unknown object in getInstance(): \" + o.getClass().getName());\n            }\n        }\n\n        return null;\n    }\n\n    public int hashCode()\n    {\n        return -1;\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof ASN1Null))\n        {\n            return false;\n        }\n        \n        return true;\n    }\n\n    abstract void encode(ASN1OutputStream out)\n        throws IOException;\n\n    public String toString()\n    {\n         return \"NULL\";\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Object.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\npublic abstract class ASN1Object\n    implements ASN1Encodable\n{\n    /**\n     * Return the default BER or DER encoding for this object.\n     *\n     * @return BER/DER byte encoded object.\n     * @throws java.io.IOException on encoding error.\n     */\n    public byte[] getEncoded()\n        throws IOException\n    {\n        ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n        ASN1OutputStream      aOut = new ASN1OutputStream(bOut);\n\n        aOut.writeObject(this);\n\n        return bOut.toByteArray();\n    }\n\n    /**\n     * Return either the default for \"BER\" or a DER encoding if \"DER\" is specified.\n     *\n     * @param encoding name of encoding to use.\n     * @return byte encoded object.\n     * @throws IOException on encoding error.\n     */\n    public byte[] getEncoded(\n        String encoding)\n        throws IOException\n    {\n        if (encoding.equals(ASN1Encoding.DER))\n        {\n            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();\n            DEROutputStream         dOut = new DEROutputStream(bOut);\n\n            dOut.writeObject(this);\n\n            return bOut.toByteArray();\n        }\n        else if (encoding.equals(ASN1Encoding.DL))\n        {\n            ByteArrayOutputStream   bOut = new ByteArrayOutputStream();\n            DLOutputStream          dOut = new DLOutputStream(bOut);\n\n            dOut.writeObject(this);\n\n            return bOut.toByteArray();\n        }\n\n        return this.getEncoded();\n    }\n\n    public int hashCode()\n    {\n        return this.toASN1Primitive().hashCode();\n    }\n\n    public boolean equals(\n        Object  o)\n    {\n        if (this == o)\n        {\n            return true;\n        }\n\n        if (!(o instanceof ASN1Encodable))\n        {\n            return false;\n        }\n\n        ASN1Encodable other = (ASN1Encodable)o;\n\n        return this.toASN1Primitive().equals(other.toASN1Primitive());\n    }\n\n    /**\n     * @deprecated use toASN1Primitive()\n     * @return the underlying primitive type.\n     */\n    public ASN1Primitive toASN1Object()\n    {\n        return this.toASN1Primitive();\n    }\n\n    protected static boolean hasEncodedTagValue(Object obj, int tagValue)\n    {\n        return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue;\n    }\n\n    public abstract ASN1Primitive toASN1Primitive();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1ObjectIdentifier.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic class ASN1ObjectIdentifier\n    extends DERObjectIdentifier\n{\n    public ASN1ObjectIdentifier(String identifier)\n    {\n        super(identifier);\n    }\n\n    ASN1ObjectIdentifier(byte[] bytes)\n    {\n        super(bytes);\n    }\n\n    ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch)\n    {\n        super(oid, branch);\n    }\n\n    /**\n     * Return an OID that creates a branch under the current one.\n     *\n     * @param branchID node numbers for the new branch.\n     * @return the OID for the new created branch.\n     */\n    public ASN1ObjectIdentifier branch(String branchID)\n    {\n        return new ASN1ObjectIdentifier(this, branchID);\n    }\n\n    /**\n     * Return  true if this oid is an extension of the passed in branch, stem.\n     * @param stem the arc or branch that is a possible parent.\n     * @return  true if the branch is on the passed in stem, false otherwise.\n     */\n    public boolean on(ASN1ObjectIdentifier stem)\n    {\n        String id = getId(), stemId = stem.getId();\n        return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1OctetString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.encoders.Hex;\n\n\npublic abstract class ASN1OctetString\n    extends ASN1Primitive\n    implements ASN1OctetStringParser\n{\n    byte[]  string;\n\n    /**\n     * return an Octet String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want.\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *              be converted.\n     */\n    public static ASN1OctetString getInstance(\n        ASN1TaggedObject    obj,\n        boolean             explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof ASN1OctetString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return BEROctetString.fromSequence(ASN1Sequence.getInstance(o));\n        }\n    }\n    \n    /**\n     * return an Octet String from the given object.\n     *\n     * @param obj the object we want converted.\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1OctetString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1OctetString)\n        {\n            return (ASN1OctetString)obj;\n        }\n        else if (obj instanceof byte[])\n        {\n            try\n            {\n                return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"failed to construct OCTET STRING from byte[]: \" + e.getMessage());\n            }\n        }\n        else if (obj instanceof ASN1Encodable)\n        {\n            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();\n\n            if (primitive instanceof ASN1OctetString)\n            {\n                return (ASN1OctetString)primitive;\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * @param string the octets making up the octet string.\n     */\n    public ASN1OctetString(\n        byte[]  string)\n    {\n        if (string == null)\n        {\n            throw new NullPointerException(\"string cannot be null\");\n        }\n        this.string = string;\n    }\n\n    public InputStream getOctetStream()\n    {\n        return new ByteArrayInputStream(string);\n    }\n\n    public ASN1OctetStringParser parser()\n    {\n        return this;\n    }\n\n    public byte[] getOctets()\n    {\n        return string;\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(this.getOctets());\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof ASN1OctetString))\n        {\n            return false;\n        }\n\n        ASN1OctetString  other = (ASN1OctetString)o;\n\n        return Arrays.areEqual(string, other.string);\n    }\n\n    public ASN1Primitive getLoadedObject()\n    {\n        return this.toASN1Primitive();\n    }\n\n    ASN1Primitive toDERObject()\n    {\n        return new DEROctetString(string);\n    }\n\n    ASN1Primitive toDLObject()\n    {\n        return new DEROctetString(string);\n    }\n\n    abstract void encode(ASN1OutputStream out)\n        throws IOException;\n\n    public String toString()\n    {\n      return \"#\"+new String(Hex.encode(string));\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1OctetStringParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.InputStream;\n\npublic interface ASN1OctetStringParser\n    extends ASN1Encodable, InMemoryRepresentable\n{\n    public InputStream getOctetStream();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1OutputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Stream that produces output based on the default encoding for the passed in objects.\n */\npublic class ASN1OutputStream\n{\n    private OutputStream os;\n\n    public ASN1OutputStream(\n        OutputStream    os)\n    {\n        this.os = os;\n    }\n\n    void writeLength(\n        int length)\n        throws IOException\n    {\n        if (length > 127)\n        {\n            int size = 1;\n            int val = length;\n\n            while ((val >>>= 8) != 0)\n            {\n                size++;\n            }\n\n            write((byte)(size | 0x80));\n\n            for (int i = (size - 1) * 8; i >= 0; i -= 8)\n            {\n                write((byte)(length >> i));\n            }\n        }\n        else\n        {\n            write((byte)length);\n        }\n    }\n\n    void write(int b)\n        throws IOException\n    {\n        os.write(b);\n    }\n\n    void write(byte[] bytes)\n        throws IOException\n    {\n        os.write(bytes);\n    }\n\n    void write(byte[] bytes, int off, int len)\n        throws IOException\n    {\n        os.write(bytes, off, len);\n    }\n\n    void writeEncoded(\n        int     tag,\n        byte[]  bytes)\n        throws IOException\n    {\n        write(tag);\n        writeLength(bytes.length);\n        write(bytes);\n    }\n\n    void writeTag(int flags, int tagNo)\n        throws IOException\n    {\n        if (tagNo < 31)\n        {\n            write(flags | tagNo);\n        }\n        else\n        {\n            write(flags | 0x1f);\n            if (tagNo < 128)\n            {\n                write(tagNo);\n            }\n            else\n            {\n                byte[] stack = new byte[5];\n                int pos = stack.length;\n\n                stack[--pos] = (byte)(tagNo & 0x7F);\n\n                do\n                {\n                    tagNo >>= 7;\n                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);\n                }\n                while (tagNo > 127);\n\n                write(stack, pos, stack.length - pos);\n            }\n        }\n    }\n\n    void writeEncoded(int flags, int tagNo, byte[] bytes)\n        throws IOException\n    {\n        writeTag(flags, tagNo);\n        writeLength(bytes.length);\n        write(bytes);\n    }\n\n    protected void writeNull()\n        throws IOException\n    {\n        os.write(BERTags.NULL);\n        os.write(0x00);\n    }\n\n    public void writeObject(\n        ASN1Encodable obj)\n        throws IOException\n    {\n        if (obj != null)\n        {\n            obj.toASN1Primitive().encode(this);\n        }\n        else\n        {\n            throw new IOException(\"null object detected\");\n        }\n    }\n\n    void writeImplicitObject(ASN1Primitive obj)\n        throws IOException\n    {\n        if (obj != null)\n        {\n            obj.encode(new ImplicitOutputStream(os));\n        }\n        else\n        {\n            throw new IOException(\"null object detected\");\n        }\n    }\n\n    public void close()\n        throws IOException\n    {\n        os.close();\n    }\n\n    public void flush()\n        throws IOException\n    {\n        os.flush();\n    }\n\n    ASN1OutputStream getDERSubStream()\n    {\n        return new DEROutputStream(os);\n    }\n\n    ASN1OutputStream getDLSubStream()\n    {\n        return new DLOutputStream(os);\n    }\n\n    private class ImplicitOutputStream\n        extends ASN1OutputStream\n    {\n        private boolean first = true;\n\n        public ImplicitOutputStream(OutputStream os)\n        {\n            super(os);\n        }\n\n        public void write(int b)\n            throws IOException\n        {\n            if (first)\n            {\n                first = false;\n            }\n            else\n            {\n                super.write(b);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1ParsingException.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic class ASN1ParsingException\n    extends IllegalStateException\n{\n    private Throwable cause;\n\n    public ASN1ParsingException(String message)\n    {\n        super(message);\n    }\n\n    public ASN1ParsingException(String message, Throwable cause)\n    {\n        super(message);\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Primitive.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic abstract class ASN1Primitive\n    extends ASN1Object\n{\n    ASN1Primitive()\n    {\n\n    }\n\n    /**\n     * Create a base ASN.1 object from a byte stream.\n     *\n     * @param data the byte stream to parse.\n     * @return the base ASN.1 object represented by the byte stream.\n     * @exception IOException if there is a problem parsing the data.\n     */\n    public static ASN1Primitive fromByteArray(byte[] data)\n        throws IOException\n    {\n        ASN1InputStream aIn = new ASN1InputStream(data);\n\n        try\n        {\n            return aIn.readObject();\n        }\n        catch (ClassCastException e)\n        {\n            throw new IOException(\"cannot recognise object in stream\");\n        }\n    }\n\n    public final boolean equals(Object o)\n    {\n        if (this == o)\n        {\n            return true;\n        }\n\n        return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive());\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return this;\n    }\n\n    ASN1Primitive toDERObject()\n    {\n        return this;\n    }\n\n    ASN1Primitive toDLObject()\n    {\n        return this;\n    }\n\n    public abstract int hashCode();\n\n    abstract boolean isConstructed();\n\n    abstract int encodedLength() throws IOException;\n\n    abstract void encode(ASN1OutputStream out) throws IOException;\n\n    abstract boolean asn1Equals(ASN1Primitive o);\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Sequence.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.Vector;\n\npublic abstract class ASN1Sequence\n    extends ASN1Primitive\n{\n    protected Vector seq = new Vector();\n\n    /**\n     * return an ASN1Sequence from the given object.\n     *\n     * @param obj the object we want converted.\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1Sequence getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1Sequence)\n        {\n            return (ASN1Sequence)obj;\n        }\n        else if (obj instanceof ASN1SequenceParser)\n        {\n            return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());\n        }\n        else if (obj instanceof byte[])\n        {\n            try\n            {\n                return ASN1Sequence.getInstance(fromByteArray((byte[])obj));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"failed to construct sequence from byte[]: \" + e.getMessage());\n            }\n        }\n        else if (obj instanceof ASN1Encodable)\n        {\n            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();\n\n            if (primitive instanceof ASN1Sequence)\n            {\n                return (ASN1Sequence)primitive;\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * Return an ASN1 sequence from a tagged object. There is a special\n     * case here, if an object appears to have been explicitly tagged on \n     * reading but we were expecting it to be implicitly tagged in the \n     * normal course of events it indicates that we lost the surrounding\n     * sequence - so we need to add it back (this will happen if the tagged\n     * object is a sequence that contains other sequences). If you are\n     * dealing with implicitly tagged sequences you really <b>should</b>\n     * be using this method.\n     *\n     * @param obj the tagged object.\n     * @param explicit true if the object is meant to be explicitly tagged,\n     *          false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *          be converted.\n     */\n    public static ASN1Sequence getInstance(\n        ASN1TaggedObject    obj,\n        boolean             explicit)\n    {\n        if (explicit)\n        {\n            if (!obj.isExplicit())\n            {\n                throw new IllegalArgumentException(\"object implicit - explicit expected.\");\n            }\n\n            return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());\n        }\n        else\n        {\n            //\n            // constructed object which appears to be explicitly tagged\n            // when it should be implicit means we have to add the\n            // surrounding sequence.\n            //\n            if (obj.isExplicit())\n            {\n                if (obj instanceof BERTaggedObject)\n                {\n                    return new BERSequence(obj.getObject());\n                }\n                else\n                {\n                    return new DLSequence(obj.getObject());\n                }\n            }\n            else\n            {\n                if (obj.getObject() instanceof ASN1Sequence)\n                {\n                    return (ASN1Sequence)obj.getObject();\n                }\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * create an empty sequence\n     */\n    protected ASN1Sequence()\n    {\n    }\n\n    /**\n     * create a sequence containing one object\n     */\n    protected ASN1Sequence(\n        ASN1Encodable obj)\n    {\n        seq.addElement(obj);\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    protected ASN1Sequence(\n        ASN1EncodableVector v)\n    {\n        for (int i = 0; i != v.size(); i++)\n        {\n            seq.addElement(v.get(i));\n        }\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    protected ASN1Sequence(\n        ASN1Encodable[]   array)\n    {\n        for (int i = 0; i != array.length; i++)\n        {\n            seq.addElement(array[i]);\n        }\n    }\n\n    public ASN1Encodable[] toArray()\n    {\n        ASN1Encodable[] values = new ASN1Encodable[this.size()];\n\n        for (int i = 0; i != this.size(); i++)\n        {\n            values[i] = this.getObjectAt(i);\n        }\n\n        return values;\n    }\n\n    public Enumeration getObjects()\n    {\n        return seq.elements();\n    }\n\n    public ASN1SequenceParser parser()\n    {\n        final ASN1Sequence outer = this;\n\n        return new ASN1SequenceParser()\n        {\n            private final int max = size();\n\n            private int index;\n\n            public ASN1Encodable readObject() throws IOException\n            {\n                if (index == max)\n                {\n                    return null;\n                }\n                \n                ASN1Encodable obj = getObjectAt(index++);\n                if (obj instanceof ASN1Sequence)\n                {\n                    return ((ASN1Sequence)obj).parser();\n                }\n                if (obj instanceof ASN1Set)\n                {\n                    return ((ASN1Set)obj).parser();\n                }\n\n                return obj;\n            }\n\n            public ASN1Primitive getLoadedObject()\n            {\n                return outer;\n            }\n            \n            public ASN1Primitive toASN1Primitive()\n            {\n                return outer;\n            }\n        };\n    }\n\n    /**\n     * return the object at the sequence position indicated by index.\n     *\n     * @param index the sequence number (starting at zero) of the object\n     * @return the object at the sequence position indicated by index.\n     */\n    public ASN1Encodable getObjectAt(\n        int index)\n    {\n        return (ASN1Encodable)seq.elementAt(index);\n    }\n\n    /**\n     * return the number of objects in this sequence.\n     *\n     * @return the number of objects in this sequence.\n     */\n    public int size()\n    {\n        return seq.size();\n    }\n\n    public int hashCode()\n    {\n        Enumeration             e = this.getObjects();\n        int                     hashCode = size();\n\n        while (e.hasMoreElements())\n        {\n            Object o = getNext(e);\n            hashCode *= 17;\n\n            hashCode ^= o.hashCode();\n        }\n\n        return hashCode;\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof ASN1Sequence))\n        {\n            return false;\n        }\n        \n        ASN1Sequence   other = (ASN1Sequence)o;\n\n        if (this.size() != other.size())\n        {\n            return false;\n        }\n\n        Enumeration s1 = this.getObjects();\n        Enumeration s2 = other.getObjects();\n\n        while (s1.hasMoreElements())\n        {\n            ASN1Encodable obj1 = getNext(s1);\n            ASN1Encodable obj2 = getNext(s2);\n\n            ASN1Primitive o1 = obj1.toASN1Primitive();\n            ASN1Primitive o2 = obj2.toASN1Primitive();\n\n            if (o1 == o2 || o1.equals(o2))\n            {\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n\n    private ASN1Encodable getNext(Enumeration e)\n    {\n        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();\n\n        return encObj;\n    }\n\n    ASN1Primitive toDERObject()\n    {\n        ASN1Sequence derSeq = new DERSequence();\n\n        derSeq.seq = this.seq;\n\n        return derSeq;\n    }\n\n    ASN1Primitive toDLObject()\n    {\n        ASN1Sequence dlSeq = new DLSequence();\n\n        dlSeq.seq = this.seq;\n\n        return dlSeq;\n    }\n\n    boolean isConstructed()\n    {\n        return true;\n    }\n\n    abstract void encode(ASN1OutputStream out)\n        throws IOException;\n\n    public String toString() \n    {\n        return seq.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1SequenceParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic interface ASN1SequenceParser\n    extends ASN1Encodable, InMemoryRepresentable\n{\n    ASN1Encodable readObject()\n        throws IOException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1Set.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.Vector;\n\nabstract public class ASN1Set\n    extends ASN1Primitive\n{\n    private Vector set = new Vector();\n    private boolean isSorted = false;\n\n    /**\n     * return an ASN1Set from the given object.\n     *\n     * @param obj the object we want converted.\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1Set getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1Set)\n        {\n            return (ASN1Set)obj;\n        }\n        else if (obj instanceof ASN1SetParser)\n        {\n            return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive());\n        }\n        else if (obj instanceof byte[])\n        {\n            try\n            {\n                return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"failed to construct set from byte[]: \" + e.getMessage());\n            }\n        }\n        else if (obj instanceof ASN1Encodable)\n        {\n            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();\n\n            if (primitive instanceof ASN1Set)\n            {\n                return (ASN1Set)primitive;\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * Return an ASN1 set from a tagged object. There is a special\n     * case here, if an object appears to have been explicitly tagged on \n     * reading but we were expecting it to be implicitly tagged in the \n     * normal course of events it indicates that we lost the surrounding\n     * set - so we need to add it back (this will happen if the tagged\n     * object is a sequence that contains other sequences). If you are\n     * dealing with implicitly tagged sets you really <b>should</b>\n     * be using this method.\n     *\n     * @param obj the tagged object.\n     * @param explicit true if the object is meant to be explicitly tagged\n     *          false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *          be converted.\n     */\n    public static ASN1Set getInstance(\n        ASN1TaggedObject    obj,\n        boolean             explicit)\n    {\n        if (explicit)\n        {\n            if (!obj.isExplicit())\n            {\n                throw new IllegalArgumentException(\"object implicit - explicit expected.\");\n            }\n\n            return (ASN1Set)obj.getObject();\n        }\n        else\n        {\n            //\n            // constructed object which appears to be explicitly tagged\n            // and it's really implicit means we have to add the\n            // surrounding set.\n            //\n            if (obj.isExplicit())\n            {\n                if (obj instanceof BERTaggedObject)\n                {\n                    return new BERSet(obj.getObject());\n                }\n                else\n                {\n                    return new DLSet(obj.getObject());\n                }\n            }\n            else\n            {\n                if (obj.getObject() instanceof ASN1Set)\n                {\n                    return (ASN1Set)obj.getObject();\n                }\n\n                //\n                // in this case the parser returns a sequence, convert it\n                // into a set.\n                //\n                if (obj.getObject() instanceof ASN1Sequence)\n                {\n                    ASN1Sequence s = (ASN1Sequence)obj.getObject();\n\n                    if (obj instanceof BERTaggedObject)\n                    {\n                        return new BERSet(s.toArray());\n                    }\n                    else\n                    {\n                        return new DLSet(s.toArray());\n                    }\n                }\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    protected ASN1Set()\n    {\n    }\n\n    /**\n     * create a sequence containing one object\n     */\n    protected ASN1Set(\n        ASN1Encodable obj)\n    {\n        set.addElement(obj);\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    protected ASN1Set(\n        ASN1EncodableVector v,\n        boolean                  doSort)\n    {\n        for (int i = 0; i != v.size(); i++)\n        {\n            set.addElement(v.get(i));\n        }\n\n        if (doSort)\n        {\n            this.sort();\n        }\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    protected ASN1Set(\n        ASN1Encodable[]   array,\n        boolean doSort)\n    {\n        for (int i = 0; i != array.length; i++)\n        {\n            set.addElement(array[i]);\n        }\n\n        if (doSort)\n        {\n            this.sort();\n        }\n    }\n\n    public Enumeration getObjects()\n    {\n        return set.elements();\n    }\n\n    /**\n     * return the object at the set position indicated by index.\n     *\n     * @param index the set number (starting at zero) of the object\n     * @return the object at the set position indicated by index.\n     */\n    public ASN1Encodable getObjectAt(\n        int index)\n    {\n        return (ASN1Encodable)set.elementAt(index);\n    }\n\n    /**\n     * return the number of objects in this set.\n     *\n     * @return the number of objects in this set.\n     */\n    public int size()\n    {\n        return set.size();\n    }\n\n    public ASN1Encodable[] toArray()\n    {\n        ASN1Encodable[] values = new ASN1Encodable[this.size()];\n\n        for (int i = 0; i != this.size(); i++)\n        {\n            values[i] = this.getObjectAt(i);\n        }\n\n        return values;\n    }\n\n    public ASN1SetParser parser()\n    {\n        final ASN1Set outer = this;\n\n        return new ASN1SetParser()\n        {\n            private final int max = size();\n\n            private int index;\n\n            public ASN1Encodable readObject() throws IOException\n            {\n                if (index == max)\n                {\n                    return null;\n                }\n\n                ASN1Encodable obj = getObjectAt(index++);\n                if (obj instanceof ASN1Sequence)\n                {\n                    return ((ASN1Sequence)obj).parser();\n                }\n                if (obj instanceof ASN1Set)\n                {\n                    return ((ASN1Set)obj).parser();\n                }\n\n                return obj;\n            }\n\n            public ASN1Primitive getLoadedObject()\n            {\n                return outer;\n            }\n\n            public ASN1Primitive toASN1Primitive()\n            {\n                return outer;\n            }\n        };\n    }\n\n    public int hashCode()\n    {\n        Enumeration             e = this.getObjects();\n        int                     hashCode = size();\n\n        while (e.hasMoreElements())\n        {\n            Object o = getNext(e);\n            hashCode *= 17;\n\n            hashCode ^= o.hashCode();\n        }\n\n        return hashCode;\n    }\n\n    ASN1Primitive toDERObject()\n    {\n        if (isSorted)\n        {\n            ASN1Set derSet = new DERSet();\n\n            derSet.set = this.set;\n\n            return derSet;\n        }\n        else\n        {\n            Vector v = new Vector();\n\n            for (int i = 0; i != set.size(); i++)\n            {\n                v.addElement(set.elementAt(i));\n            }\n\n            ASN1Set derSet = new DERSet();\n\n            derSet.set = v;\n\n            derSet.sort();\n\n            return derSet;\n        }\n    }\n\n    ASN1Primitive toDLObject()\n    {\n        ASN1Set derSet = new DLSet();\n\n        derSet.set = this.set;\n\n        return derSet;\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof ASN1Set))\n        {\n            return false;\n        }\n\n        ASN1Set   other = (ASN1Set)o;\n\n        if (this.size() != other.size())\n        {\n            return false;\n        }\n\n        Enumeration s1 = this.getObjects();\n        Enumeration s2 = other.getObjects();\n\n        while (s1.hasMoreElements())\n        {\n            ASN1Encodable obj1 = getNext(s1);\n            ASN1Encodable obj2 = getNext(s2);\n\n            ASN1Primitive o1 = obj1.toASN1Primitive();\n            ASN1Primitive o2 = obj2.toASN1Primitive();\n\n            if (o1 == o2 || o1.equals(o2))\n            {\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n\n    private ASN1Encodable getNext(Enumeration e)\n    {\n        ASN1Encodable encObj = (ASN1Encodable)e.nextElement();\n\n        // unfortunately null was allowed as a substitute for DER null\n        if (encObj == null)\n        {\n            return DERNull.INSTANCE;\n        }\n\n        return encObj;\n    }\n\n    /**\n     * return true if a <= b (arrays are assumed padded with zeros).\n     */\n    private boolean lessThanOrEqual(\n         byte[] a,\n         byte[] b)\n    {\n        int len = Math.min(a.length, b.length);\n        for (int i = 0; i != len; ++i)\n        {\n            if (a[i] != b[i])\n            {\n                return (a[i] & 0xff) < (b[i] & 0xff);\n            }\n        }\n        return len == a.length;\n    }\n\n    private byte[] getEncoded(\n        ASN1Encodable obj)\n    {\n        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();\n        ASN1OutputStream        aOut = new ASN1OutputStream(bOut);\n\n        try\n        {\n            aOut.writeObject(obj);\n        }\n        catch (IOException e)\n        {\n            throw new IllegalArgumentException(\"cannot encode object added to SET\");\n        }\n\n        return bOut.toByteArray();\n    }\n\n    protected void sort()\n    {\n        if (!isSorted)\n        {\n            isSorted = true;\n            if (set.size() > 1)\n            {\n                boolean    swapped = true;\n                int        lastSwap = set.size() - 1;\n\n                while (swapped)\n                {\n                    int    index = 0;\n                    int    swapIndex = 0;\n                    byte[] a = getEncoded((ASN1Encodable)set.elementAt(0));\n\n                    swapped = false;\n\n                    while (index != lastSwap)\n                    {\n                        byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1));\n\n                        if (lessThanOrEqual(a, b))\n                        {\n                            a = b;\n                        }\n                        else\n                        {\n                            Object  o = set.elementAt(index);\n\n                            set.setElementAt(set.elementAt(index + 1), index);\n                            set.setElementAt(o, index + 1);\n\n                            swapped = true;\n                            swapIndex = index;\n                        }\n\n                        index++;\n                    }\n\n                    lastSwap = swapIndex;\n                }\n            }\n        }\n    }\n\n    boolean isConstructed()\n    {\n        return true;\n    }\n\n    abstract void encode(ASN1OutputStream out)\n            throws IOException;\n\n    public String toString() \n    {\n        return set.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1SetParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic interface ASN1SetParser\n    extends ASN1Encodable, InMemoryRepresentable\n{\n    public ASN1Encodable readObject()\n        throws IOException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1StreamParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic class ASN1StreamParser\n{\n    private final InputStream _in;\n    private final int         _limit;\n    private final byte[][] tmpBuffers;\n\n    public ASN1StreamParser(\n        InputStream in)\n    {\n        this(in, StreamUtil.findLimit(in));\n    }\n\n    public ASN1StreamParser(\n        InputStream in,\n        int         limit)\n    {\n        this._in = in;\n        this._limit = limit;\n\n        this.tmpBuffers = new byte[11][];\n    }\n\n    public ASN1StreamParser(\n        byte[] encoding)\n    {\n        this(new ByteArrayInputStream(encoding), encoding.length);\n    }\n\n    ASN1Encodable readIndef(int tagValue) throws IOException\n    {\n        // Note: INDEF => CONSTRUCTED\n\n        // TODO There are other tags that may be constructed (e.g. BIT_STRING)\n        switch (tagValue)\n        {\n            case BERTags.EXTERNAL:\n                return new DERExternalParser(this);\n            case BERTags.OCTET_STRING:\n                return new BEROctetStringParser(this);\n            case BERTags.SEQUENCE:\n                return new BERSequenceParser(this);\n            case BERTags.SET:\n                return new BERSetParser(this);\n            default:\n                throw new ASN1Exception(\"unknown BER object encountered: 0x\" + Integer.toHexString(tagValue));\n        }\n    }\n\n    ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException\n    {\n        if (_in instanceof IndefiniteLengthInputStream)\n        {\n            if (!constructed)\n            {\n                throw new IOException(\"indefinite length primitive encoding encountered\");\n            }\n            \n            return readIndef(tag);\n        }\n\n        if (constructed)\n        {\n            switch (tag)\n            {\n                case BERTags.SET:\n                    return new DERSetParser(this);\n                case BERTags.SEQUENCE:\n                    return new DERSequenceParser(this);\n                case BERTags.OCTET_STRING:\n                    return new BEROctetStringParser(this);\n            }\n        }\n        else\n        {\n            switch (tag)\n            {\n                case BERTags.SET:\n                    throw new ASN1Exception(\"sequences must use constructed encoding (see X.690 8.9.1/8.10.1)\");\n                case BERTags.SEQUENCE:\n                    throw new ASN1Exception(\"sets must use constructed encoding (see X.690 8.11.1/8.12.1)\");\n                case BERTags.OCTET_STRING:\n                    return new DEROctetStringParser((DefiniteLengthInputStream)_in);\n            }\n        }\n\n        // TODO ASN1Exception\n        throw new RuntimeException(\"implicit tagging not implemented\");\n    }\n\n    ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException\n    {\n        if (!constructed)\n        {\n            // Note: !CONSTRUCTED => IMPLICIT\n            DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;\n            return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray()));\n        }\n\n        ASN1EncodableVector v = readVector();\n\n        if (_in instanceof IndefiniteLengthInputStream)\n        {\n            return v.size() == 1\n                ?   new BERTaggedObject(true, tag, v.get(0))\n                :   new BERTaggedObject(false, tag, BERFactory.createSequence(v));\n        }\n\n        return v.size() == 1\n            ?   new DERTaggedObject(true, tag, v.get(0))\n            :   new DERTaggedObject(false, tag, DERFactory.createSequence(v));\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        int tag = _in.read();\n        if (tag == -1)\n        {\n            return null;\n        }\n\n        //\n        // turn of looking for \"00\" while we resolve the tag\n        //\n        set00Check(false);\n\n        //\n        // calculate tag number\n        //\n        int tagNo = ASN1InputStream.readTagNumber(_in, tag);\n\n        boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;\n\n        //\n        // calculate length\n        //\n        int length = ASN1InputStream.readLength(_in, _limit);\n\n        if (length < 0) // indefinite length method\n        {\n            if (!isConstructed)\n            {\n                throw new IOException(\"indefinite length primitive encoding encountered\");\n            }\n\n            IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);\n            ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);\n\n            if ((tag & BERTags.APPLICATION) != 0)\n            {\n                return new BERApplicationSpecificParser(tagNo, sp);\n            }\n\n            if ((tag & BERTags.TAGGED) != 0)\n            {\n                return new BERTaggedObjectParser(true, tagNo, sp);\n            }\n\n            return sp.readIndef(tagNo);\n        }\n        else\n        {\n            DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);\n\n            if ((tag & BERTags.APPLICATION) != 0)\n            {\n                return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());\n            }\n\n            if ((tag & BERTags.TAGGED) != 0)\n            {\n                return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));\n            }\n\n            if (isConstructed)\n            {\n                // TODO There are other tags that may be constructed (e.g. BIT_STRING)\n                switch (tagNo)\n                {\n                    case BERTags.OCTET_STRING:\n                        //\n                        // yes, people actually do this...\n                        //\n                        return new BEROctetStringParser(new ASN1StreamParser(defIn));\n                    case BERTags.SEQUENCE:\n                        return new DERSequenceParser(new ASN1StreamParser(defIn));\n                    case BERTags.SET:\n                        return new DERSetParser(new ASN1StreamParser(defIn));\n                    case BERTags.EXTERNAL:\n                        return new DERExternalParser(new ASN1StreamParser(defIn));\n                    default:\n                        throw new IOException(\"unknown tag \" + tagNo + \" encountered\");\n                }\n            }\n\n            // Some primitive encodings can be handled by parsers too...\n            switch (tagNo)\n            {\n                case BERTags.OCTET_STRING:\n                    return new DEROctetStringParser(defIn);\n            }\n\n            try\n            {\n                return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);\n            }\n            catch (IllegalArgumentException e)\n            {\n                throw new ASN1Exception(\"corrupted stream detected\", e);\n            }\n        }\n    }\n\n    private void set00Check(boolean enabled)\n    {\n        if (_in instanceof IndefiniteLengthInputStream)\n        {\n            ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);\n        }\n    }\n\n    ASN1EncodableVector readVector() throws IOException\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        ASN1Encodable obj;\n        while ((obj = readObject()) != null)\n        {\n            if (obj instanceof InMemoryRepresentable)\n            {\n                v.add(((InMemoryRepresentable)obj).getLoadedObject());\n            }\n            else\n            {\n                v.add(obj.toASN1Primitive());\n            }\n        }\n\n        return v;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1String.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic interface ASN1String\n{\n    public String getString();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1TaggedObject.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\n/**\n * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by\n * a [n] where n is some number - these are assumed to follow the construction\n * rules (as with sequences).\n */\npublic abstract class ASN1TaggedObject\n    extends ASN1Primitive\n    implements ASN1TaggedObjectParser\n{\n    int             tagNo;\n    boolean         empty = false;\n    boolean         explicit = true;\n    ASN1Encodable obj = null;\n\n    static public ASN1TaggedObject getInstance(\n        ASN1TaggedObject    obj,\n        boolean             explicit)\n    {\n        if (explicit)\n        {\n            return (ASN1TaggedObject)obj.getObject();\n        }\n\n        throw new IllegalArgumentException(\"implicitly tagged tagged object\");\n    }\n\n    static public ASN1TaggedObject getInstance(\n        Object obj) \n    {\n        if (obj == null || obj instanceof ASN1TaggedObject) \n        {\n                return (ASN1TaggedObject)obj;\n        }\n        else if (obj instanceof byte[])\n        {\n            try\n            {\n                return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"failed to construct tagged object from byte[]: \" + e.getMessage());\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * Create a tagged object with the style given by the value of explicit.\n     * <p>\n     * If the object implements ASN1Choice the tag style will always be changed\n     * to explicit in accordance with the ASN.1 encoding rules.\n     * </p>\n     * @param explicit true if the object is explicitly tagged.\n     * @param tagNo the tag number for this object.\n     * @param obj the tagged object.\n     */\n    public ASN1TaggedObject(\n        boolean         explicit,\n        int             tagNo,\n        ASN1Encodable   obj)\n    {\n        if (obj instanceof ASN1Choice)\n        {\n            this.explicit = true;\n        }\n        else\n        {\n            this.explicit = explicit;\n        }\n        \n        this.tagNo = tagNo;\n\n        if (this.explicit)\n        {\n            this.obj = obj;\n        }\n        else\n        {\n            ASN1Primitive prim = obj.toASN1Primitive();\n\n            if (prim instanceof ASN1Set)\n            {\n                ASN1Set s = null;\n            }\n\n            this.obj = obj;\n        }\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof ASN1TaggedObject))\n        {\n            return false;\n        }\n        \n        ASN1TaggedObject other = (ASN1TaggedObject)o;\n        \n        if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)\n        {\n            return false;\n        }\n        \n        if(obj == null)\n        {\n            if (other.obj != null)\n            {\n                return false;\n            }\n        }\n        else\n        {\n            if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive())))\n            {\n                return false;\n            }\n        }\n        \n        return true;\n    }\n    \n    public int hashCode()\n    {\n        int code = tagNo;\n\n        // TODO: actually this is wrong - the problem is that a re-encoded\n        // object may end up with a different hashCode due to implicit\n        // tagging. As implicit tagging is ambiguous if a sequence is involved\n        // it seems the only correct method for both equals and hashCode is to\n        // compare the encodings...\n        if (obj != null)\n        {\n            code ^= obj.hashCode();\n        }\n\n        return code;\n    }\n\n    public int getTagNo()\n    {\n        return tagNo;\n    }\n\n    /**\n     * return whether or not the object may be explicitly tagged. \n     * <p>\n     * Note: if the object has been read from an input stream, the only\n     * time you can be sure if isExplicit is returning the true state of\n     * affairs is if it returns false. An implicitly tagged object may appear\n     * to be explicitly tagged, so you need to understand the context under\n     * which the reading was done as well, see getObject below.\n     */\n    public boolean isExplicit()\n    {\n        return explicit;\n    }\n\n    public boolean isEmpty()\n    {\n        return empty;\n    }\n\n    /**\n     * return whatever was following the tag.\n     * <p>\n     * Note: tagged objects are generally context dependent if you're\n     * trying to extract a tagged object you should be going via the\n     * appropriate getInstance method.\n     */\n    public ASN1Primitive getObject()\n    {\n        if (obj != null)\n        {\n            return obj.toASN1Primitive();\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the object held in this tagged object as a parser assuming it has\n     * the type of the passed in tag. If the object doesn't have a parser\n     * associated with it, the base object is returned.\n     */\n    public ASN1Encodable getObjectParser(\n        int     tag,\n        boolean isExplicit)\n    {\n        switch (tag)\n        {\n        case BERTags.SET:\n            return ASN1Set.getInstance(this, isExplicit).parser();\n        case BERTags.SEQUENCE:\n            return ASN1Sequence.getInstance(this, isExplicit).parser();\n        case BERTags.OCTET_STRING:\n            return ASN1OctetString.getInstance(this, isExplicit).parser();\n        }\n\n        if (isExplicit)\n        {\n            return getObject();\n        }\n\n        throw new RuntimeException(\"implicit tagging not implemented for tag: \" + tag);\n    }\n\n    public ASN1Primitive getLoadedObject()\n    {\n        return this.toASN1Primitive();\n    }\n\n    ASN1Primitive toDERObject()\n    {\n        return new DERTaggedObject(explicit, tagNo, obj);\n    }\n\n    ASN1Primitive toDLObject()\n    {\n        return new DLTaggedObject(explicit, tagNo, obj);\n    }\n\n    abstract void encode(ASN1OutputStream out)\n        throws IOException;\n\n    public String toString()\n    {\n        return \"[\" + tagNo + \"]\" + obj;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1TaggedObjectParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic interface ASN1TaggedObjectParser\n    extends ASN1Encodable, InMemoryRepresentable\n{\n    public int getTagNo();\n    \n    public ASN1Encodable getObjectParser(int tag, boolean isExplicit)\n        throws IOException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ASN1UTCTime.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.util.Date;\n\npublic class ASN1UTCTime\n    extends DERUTCTime\n{\n    ASN1UTCTime(byte[] bytes)\n    {\n        super(bytes);\n    }\n\n    public ASN1UTCTime(Date time)\n    {\n        super(time);\n    }\n\n    public ASN1UTCTime(String time)\n    {\n        super(time);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERApplicationSpecific.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic class BERApplicationSpecific\n    extends DERApplicationSpecific\n{\n    public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)\n    {\n        super(tagNo, vec);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERApplicationSpecificParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class BERApplicationSpecificParser\n    implements ASN1ApplicationSpecificParser\n{\n    private final int tag;\n    private final ASN1StreamParser parser;\n\n    BERApplicationSpecificParser(int tag, ASN1StreamParser parser)\n    {\n        this.tag = tag;\n        this.parser = parser;\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        return parser.readObject();\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n         return new BERApplicationSpecific(tag, parser.readVector());\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(e.getMessage(), e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERConstructedOctetString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.Vector;\n\n/**\n * @deprecated use BEROctetString\n */\npublic class BERConstructedOctetString\n    extends BEROctetString\n{\n    private static final int MAX_LENGTH = 1000;\n\n    /**\n     * convert a vector of octet strings into a single byte string\n     */\n    static private byte[] toBytes(\n        Vector  octs)\n    {\n        ByteArrayOutputStream   bOut = new ByteArrayOutputStream();\n\n        for (int i = 0; i != octs.size(); i++)\n        {\n            try\n            {\n                DEROctetString  o = (DEROctetString)octs.elementAt(i);\n\n                bOut.write(o.getOctets());\n            }\n            catch (ClassCastException e)\n            {\n                throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + \" found in input should only contain DEROctetString\");\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"exception converting octets \" + e.toString());\n            }\n        }\n\n        return bOut.toByteArray();\n    }\n\n    private Vector  octs;\n\n    /**\n     * @param string the octets making up the octet string.\n     */\n    public BERConstructedOctetString(\n        byte[]  string)\n    {\n        super(string);\n    }\n\n    public BERConstructedOctetString(\n        Vector  octs)\n    {\n        super(toBytes(octs));\n\n        this.octs = octs;\n    }\n\n    public BERConstructedOctetString(\n        ASN1Primitive  obj)\n    {\n        super(toByteArray(obj));\n    }\n\n    private static byte[] toByteArray(ASN1Primitive obj)\n    {\n        try\n        {\n            return obj.getEncoded();\n        }\n        catch (IOException e)\n        {\n            throw new IllegalArgumentException(\"Unable to encode object\");\n        }\n    }\n\n    public BERConstructedOctetString(\n        ASN1Encodable  obj)\n    {\n        this(obj.toASN1Primitive());\n    }\n\n    public byte[] getOctets()\n    {\n        return string;\n    }\n\n    /**\n     * return the DER octets that make up this string.\n     */\n    public Enumeration getObjects()\n    {\n        if (octs == null)\n        {\n            return generateOcts().elements();\n        }\n\n        return octs.elements();\n    }\n\n    private Vector generateOcts() \n    { \n        Vector vec = new Vector(); \n        for (int i = 0; i < string.length; i += MAX_LENGTH) \n        { \n            int end; \n\n            if (i + MAX_LENGTH > string.length) \n            { \n                end = string.length; \n            } \n            else \n            { \n                end = i + MAX_LENGTH; \n            } \n\n            byte[] nStr = new byte[end - i]; \n\n            System.arraycopy(string, i, nStr, 0, nStr.length); \n\n            vec.addElement(new DEROctetString(nStr)); \n         } \n        \n         return vec; \n    }\n\n    public static BEROctetString fromSequence(ASN1Sequence seq)\n    {\n        Vector      v = new Vector();\n        Enumeration e = seq.getObjects();\n\n        while (e.hasMoreElements())\n        {\n            v.addElement(e.nextElement());\n        }\n\n        return new BERConstructedOctetString(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERFactory.java",
    "content": "package local.org.bouncycastle.asn1;\n\nclass BERFactory\n{\n    static final BERSequence EMPTY_SEQUENCE = new BERSequence();\n    static final BERSet EMPTY_SET = new BERSet();\n\n    static BERSequence createSequence(ASN1EncodableVector v)\n    {\n        return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v);\n    }\n\n    static BERSet createSet(ASN1EncodableVector v)\n    {\n        return v.size() < 1 ? EMPTY_SET : new BERSet(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERGenerator.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class BERGenerator\n    extends ASN1Generator\n{\n    private boolean      _tagged = false;\n    private boolean      _isExplicit;\n    private int          _tagNo;\n    \n    protected BERGenerator(\n        OutputStream out)\n    {\n        super(out);\n    }\n\n    public BERGenerator(\n        OutputStream out,\n        int tagNo,\n        boolean isExplicit) \n    {\n        super(out);\n        \n        _tagged = true;\n        _isExplicit = isExplicit;\n        _tagNo = tagNo;\n    }\n\n    public OutputStream getRawOutputStream()\n    {\n        return _out;\n    }\n    \n    private void writeHdr(\n        int tag)\n        throws IOException\n    {\n        _out.write(tag);\n        _out.write(0x80);\n    }\n    \n    protected void writeBERHeader(\n        int tag) \n        throws IOException\n    {\n        if (_tagged)\n        {\n            int tagNum = _tagNo | BERTags.TAGGED;\n\n            if (_isExplicit)\n            {\n                writeHdr(tagNum | BERTags.CONSTRUCTED);\n                writeHdr(tag);\n            }\n            else\n            {   \n                if ((tag & BERTags.CONSTRUCTED) != 0)\n                {\n                    writeHdr(tagNum | BERTags.CONSTRUCTED);\n                }\n                else\n                {\n                    writeHdr(tagNum);\n                }\n            }\n        }\n        else\n        {\n            writeHdr(tag);\n        }\n    }\n    \n    protected void writeBERBody(\n        InputStream contentStream)\n        throws IOException\n    {\n        int ch;\n        \n        while ((ch = contentStream.read()) >= 0)\n        {\n            _out.write(ch);\n        }\n    }\n\n    protected void writeBEREnd()\n        throws IOException\n    {\n        _out.write(0x00);\n        _out.write(0x00);\n        \n        if (_tagged && _isExplicit)  // write extra end for tag header\n        {\n            _out.write(0x00);\n            _out.write(0x00);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BEROctetString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.Vector;\n\npublic class BEROctetString\n    extends ASN1OctetString\n{\n    private static final int MAX_LENGTH = 1000;\n\n    private ASN1OctetString[] octs;\n\n    /**\n     * convert a vector of octet strings into a single byte string\n     */\n    static private byte[] toBytes(\n        ASN1OctetString[]  octs)\n    {\n        ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n\n        for (int i = 0; i != octs.length; i++)\n        {\n            try\n            {\n                DEROctetString o = (DEROctetString)octs[i];\n\n                bOut.write(o.getOctets());\n            }\n            catch (ClassCastException e)\n            {\n                throw new IllegalArgumentException(octs[i].getClass().getName() + \" found in input should only contain DEROctetString\");\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"exception converting octets \" + e.toString());\n            }\n        }\n\n        return bOut.toByteArray();\n    }\n\n    /**\n     * @param string the octets making up the octet string.\n     */\n    public BEROctetString(\n        byte[] string)\n    {\n        super(string);\n    }\n\n    public BEROctetString(\n        ASN1OctetString[] octs)\n    {\n        super(toBytes(octs));\n\n        this.octs = octs;\n    }\n\n    public byte[] getOctets()\n    {\n        return string;\n    }\n\n    /**\n     * return the DER octets that make up this string.\n     */\n    public Enumeration getObjects()\n    {\n        if (octs == null)\n        {\n            return generateOcts().elements();\n        }\n\n        return new Enumeration()\n        {\n            int counter = 0;\n\n            public boolean hasMoreElements()\n            {\n                return counter < octs.length;\n            }\n\n            public Object nextElement()\n            {\n                return octs[counter++];\n            }\n        };\n    }\n\n    private Vector generateOcts()\n    { \n        Vector vec = new Vector();\n        for (int i = 0; i < string.length; i += MAX_LENGTH) \n        { \n            int end; \n\n            if (i + MAX_LENGTH > string.length) \n            { \n                end = string.length; \n            } \n            else \n            { \n                end = i + MAX_LENGTH; \n            } \n\n            byte[] nStr = new byte[end - i]; \n\n            System.arraycopy(string, i, nStr, 0, nStr.length);\n\n            vec.addElement(new DEROctetString(nStr));\n         } \n        \n         return vec; \n    }\n\n    boolean isConstructed()\n    {\n        return true;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int length = 0;\n        for (Enumeration e = getObjects(); e.hasMoreElements();)\n        {\n            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();\n        }\n\n        return 2 + length + 2;\n    }\n\n    public void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);\n\n        out.write(0x80);\n\n        //\n        // write out the octet array\n        //\n        for (Enumeration e = getObjects(); e.hasMoreElements();)\n        {\n            out.writeObject((ASN1Encodable)e.nextElement());\n        }\n\n        out.write(0x00);\n        out.write(0x00);\n    }\n\n    static BEROctetString fromSequence(ASN1Sequence seq)\n    {\n        ASN1OctetString[]     v = new ASN1OctetString[seq.size()];\n        Enumeration e = seq.getObjects();\n        int                   index = 0;\n\n        while (e.hasMoreElements())\n        {\n            v[index++] = (ASN1OctetString)e.nextElement();\n        }\n\n        return new BEROctetString(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BEROctetStringGenerator.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class BEROctetStringGenerator\n    extends BERGenerator\n{\n    public BEROctetStringGenerator(OutputStream out) \n        throws IOException\n    {\n        super(out);\n        \n        writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);\n    }\n\n    public BEROctetStringGenerator(\n        OutputStream out,\n        int tagNo,\n        boolean isExplicit) \n        throws IOException\n    {\n        super(out, tagNo, isExplicit);\n        \n        writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);\n    }\n    \n    public OutputStream getOctetOutputStream()\n    {\n        return getOctetOutputStream(new byte[1000]); // limit for CER encoding.\n    }\n\n    public OutputStream getOctetOutputStream(\n        byte[] buf)\n    {\n        return new BufferedBEROctetStream(buf);\n    }\n   \n    private class BufferedBEROctetStream\n        extends OutputStream\n    {\n        private byte[] _buf;\n        private int    _off;\n        private DEROutputStream _derOut;\n\n        BufferedBEROctetStream(\n            byte[] buf)\n        {\n            _buf = buf;\n            _off = 0;\n            _derOut = new DEROutputStream(_out);\n        }\n        \n        public void write(\n            int b)\n            throws IOException\n        {\n            _buf[_off++] = (byte)b;\n\n            if (_off == _buf.length)\n            {\n                DEROctetString.encode(_derOut, _buf);\n                _off = 0;\n            }\n        }\n\n        public void write(byte[] b, int off, int len) throws IOException\n        {\n            while (len > 0)\n            {\n                int numToCopy = Math.min(len, _buf.length - _off);\n                System.arraycopy(b, off, _buf, _off, numToCopy);\n\n                _off += numToCopy;\n                if (_off < _buf.length)\n                {\n                    break;\n                }\n\n                DEROctetString.encode(_derOut, _buf);\n                _off = 0;\n\n                off += numToCopy;\n                len -= numToCopy;\n            }\n        }\n\n        public void close() \n            throws IOException\n        {\n            if (_off != 0)\n            {\n                byte[] bytes = new byte[_off];\n                System.arraycopy(_buf, 0, bytes, 0, _off);\n                \n                DEROctetString.encode(_derOut, bytes);\n            }\n            \n             writeBEREnd();\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BEROctetStringParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport local.org.bouncycastle.util.io.Streams;\n\n\npublic class BEROctetStringParser\n    implements ASN1OctetStringParser\n{\n    private ASN1StreamParser _parser;\n\n    BEROctetStringParser(\n        ASN1StreamParser parser)\n    {\n        _parser = parser;\n    }\n\n    public InputStream getOctetStream()\n    {\n        return new ConstructedOctetStream(_parser);\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        return new BEROctetString(Streams.readAll(getOctetStream()));\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(\"IOException converting stream to byte array: \" + e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BEROutputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class BEROutputStream\n    extends DEROutputStream\n{\n    public BEROutputStream(\n        OutputStream    os)\n    {\n        super(os);\n    }\n\n    public void writeObject(\n        Object    obj)\n        throws IOException\n    {\n        if (obj == null)\n        {\n            writeNull();\n        }\n        else if (obj instanceof ASN1Primitive)\n        {\n            ((ASN1Primitive)obj).encode(this);\n        }\n        else if (obj instanceof ASN1Encodable)\n        {\n            ((ASN1Encodable)obj).toASN1Primitive().encode(this);\n        }\n        else\n        {\n            throw new IOException(\"object not BEREncodable\");\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERSequence.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\npublic class BERSequence\n    extends ASN1Sequence\n{\n    /**\n     * create an empty sequence\n     */\n    public BERSequence()\n    {\n    }\n\n    /**\n     * create a sequence containing one object\n     */\n    public BERSequence(\n        ASN1Encodable obj)\n    {\n        super(obj);\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    public BERSequence(\n        ASN1EncodableVector v)\n    {\n        super(v);\n    }\n\n    /**\n     * create a sequence containing an array of objects.\n     */\n    public BERSequence(\n        ASN1Encodable[]   array)\n    {\n        super(array);\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int length = 0;\n        for (Enumeration e = getObjects(); e.hasMoreElements();)\n        {\n            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();\n        }\n\n        return 2 + length + 2;\n    }\n\n    /*\n     */\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);\n        out.write(0x80);\n\n        Enumeration e = getObjects();\n        while (e.hasMoreElements())\n        {\n            out.writeObject((ASN1Encodable)e.nextElement());\n        }\n\n        out.write(0x00);\n        out.write(0x00);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERSequenceGenerator.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class BERSequenceGenerator\n    extends BERGenerator\n{\n    public BERSequenceGenerator(\n        OutputStream out) \n        throws IOException\n    {\n        super(out);\n\n        writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE);\n    }\n\n    public BERSequenceGenerator(\n        OutputStream out,\n        int tagNo,\n        boolean isExplicit) \n        throws IOException\n    {\n        super(out, tagNo, isExplicit);\n        \n        writeBERHeader(BERTags.CONSTRUCTED | BERTags.SEQUENCE);\n    }\n\n    public void addObject(\n        ASN1Encodable object)\n        throws IOException\n    {\n        object.toASN1Primitive().encode(new BEROutputStream(_out));\n    }\n    \n    public void close() \n        throws IOException\n    {\n        writeBEREnd();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERSequenceParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class BERSequenceParser\n    implements ASN1SequenceParser\n{\n    private ASN1StreamParser _parser;\n\n    BERSequenceParser(ASN1StreamParser parser)\n    {\n        this._parser = parser;\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        return _parser.readObject();\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        return new BERSequence(_parser.readVector());\n    }\n    \n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERSet.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\npublic class BERSet\n    extends ASN1Set\n{\n    /**\n     * create an empty sequence\n     */\n    public BERSet()\n    {\n    }\n\n    /**\n     * @param obj - a single object that makes up the set.\n     */\n    public BERSet(\n        ASN1Encodable obj)\n    {\n        super(obj);\n    }\n\n    /**\n     * @param v - a vector of objects making up the set.\n     */\n    public BERSet(\n        ASN1EncodableVector v)\n    {\n        super(v, false);\n    }\n\n    /**\n     * create a set from an array of objects.\n     */\n    public BERSet(\n        ASN1Encodable[]   a)\n    {\n        super(a, false);\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int length = 0;\n        for (Enumeration e = getObjects(); e.hasMoreElements();)\n        {\n            length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();\n        }\n\n        return 2 + length + 2;\n    }\n\n    /*\n     */\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.write(BERTags.SET | BERTags.CONSTRUCTED);\n        out.write(0x80);\n\n        Enumeration e = getObjects();\n        while (e.hasMoreElements())\n        {\n            out.writeObject((ASN1Encodable)e.nextElement());\n        }\n\n        out.write(0x00);\n        out.write(0x00);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERSetParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class BERSetParser\n    implements ASN1SetParser\n{\n    private ASN1StreamParser _parser;\n\n    BERSetParser(ASN1StreamParser parser)\n    {\n        this._parser = parser;\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        return _parser.readObject();\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        return new BERSet(_parser.readVector());\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERTaggedObject.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\n/**\n * BER TaggedObject - in ASN.1 notation this is any object preceded by\n * a [n] where n is some number - these are assumed to follow the construction\n * rules (as with sequences).\n */\npublic class BERTaggedObject\n    extends ASN1TaggedObject\n{\n    /**\n     * @param tagNo the tag number for this object.\n     * @param obj the tagged object.\n     */\n    public BERTaggedObject(\n        int             tagNo,\n        ASN1Encodable    obj)\n    {\n        super(true, tagNo, obj);\n    }\n\n    /**\n     * @param explicit true if an explicitly tagged object.\n     * @param tagNo the tag number for this object.\n     * @param obj the tagged object.\n     */\n    public BERTaggedObject(\n        boolean         explicit,\n        int             tagNo,\n        ASN1Encodable    obj)\n    {\n        super(explicit, tagNo, obj);\n    }\n\n    /**\n     * create an implicitly tagged object that contains a zero\n     * length sequence.\n     */\n    public BERTaggedObject(\n        int             tagNo)\n    {\n        super(false, tagNo, new BERSequence());\n    }\n\n    boolean isConstructed()\n    {\n        if (!empty)\n        {\n            if (explicit)\n            {\n                return true;\n            }\n            else\n            {\n                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();\n\n                return primitive.isConstructed();\n            }\n        }\n        else\n        {\n            return true;\n        }\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        if (!empty)\n        {\n            ASN1Primitive primitive = obj.toASN1Primitive();\n            int length = primitive.encodedLength();\n\n            if (explicit)\n            {\n                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;\n            }\n            else\n            {\n                // header length already in calculation\n                length = length - 1;\n\n                return StreamUtil.calculateTagLength(tagNo) + length;\n            }\n        }\n        else\n        {\n            return StreamUtil.calculateTagLength(tagNo) + 1;\n        }\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);\n        out.write(0x80);\n\n        if (!empty)\n        {\n            if (!explicit)\n            {\n                Enumeration e;\n                if (obj instanceof ASN1OctetString)\n                {\n                    if (obj instanceof BEROctetString)\n                    {\n                        e = ((BEROctetString)obj).getObjects();\n                    }\n                    else\n                    {\n                        ASN1OctetString             octs = (ASN1OctetString)obj;\n                        BEROctetString berO = new BEROctetString(octs.getOctets());\n                        e = berO.getObjects();\n                    }\n                }\n                else if (obj instanceof ASN1Sequence)\n                {\n                    e = ((ASN1Sequence)obj).getObjects();\n                }\n                else if (obj instanceof ASN1Set)\n                {\n                    e = ((ASN1Set)obj).getObjects();\n                }\n                else\n                {\n                    throw new RuntimeException(\"not implemented: \" + obj.getClass().getName());\n                }\n\n                while (e.hasMoreElements())\n                {\n                    out.writeObject((ASN1Encodable)e.nextElement());\n                }\n            }\n            else\n            {\n                out.writeObject(obj);\n            }\n        }\n\n        out.write(0x00);\n        out.write(0x00);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERTaggedObjectParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class BERTaggedObjectParser\n    implements ASN1TaggedObjectParser\n{\n    private boolean _constructed;\n    private int _tagNumber;\n    private ASN1StreamParser _parser;\n\n    BERTaggedObjectParser(\n        boolean             constructed,\n        int                 tagNumber,\n        ASN1StreamParser    parser)\n    {\n        _constructed = constructed;\n        _tagNumber = tagNumber;\n        _parser = parser;\n    }\n\n    public boolean isConstructed()\n    {\n        return _constructed;\n    }\n\n    public int getTagNo()\n    {\n        return _tagNumber;\n    }\n\n    public ASN1Encodable getObjectParser(\n        int     tag,\n        boolean isExplicit)\n        throws IOException\n    {\n        if (isExplicit)\n        {\n            if (!_constructed)\n            {\n                throw new IOException(\"Explicit tags must be constructed (see X.690 8.14.2)\");\n            }\n            return _parser.readObject();\n        }\n\n        return _parser.readImplicit(_constructed, tag);\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        return _parser.readTaggedObject(_constructed, _tagNumber);\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return this.getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/BERTags.java",
    "content": "package local.org.bouncycastle.asn1;\n\npublic interface BERTags\n{\n    public static final int BOOLEAN             = 0x01;\n    public static final int INTEGER             = 0x02;\n    public static final int BIT_STRING          = 0x03;\n    public static final int OCTET_STRING        = 0x04;\n    public static final int NULL                = 0x05;\n    public static final int OBJECT_IDENTIFIER   = 0x06;\n    public static final int EXTERNAL            = 0x08;\n    public static final int ENUMERATED          = 0x0a;\n    public static final int SEQUENCE            = 0x10;\n    public static final int SEQUENCE_OF         = 0x10; // for completeness\n    public static final int SET                 = 0x11;\n    public static final int SET_OF              = 0x11; // for completeness\n\n\n    public static final int NUMERIC_STRING      = 0x12;\n    public static final int PRINTABLE_STRING    = 0x13;\n    public static final int T61_STRING          = 0x14;\n    public static final int VIDEOTEX_STRING     = 0x15;\n    public static final int IA5_STRING          = 0x16;\n    public static final int UTC_TIME            = 0x17;\n    public static final int GENERALIZED_TIME    = 0x18;\n    public static final int GRAPHIC_STRING      = 0x19;\n    public static final int VISIBLE_STRING      = 0x1a;\n    public static final int GENERAL_STRING      = 0x1b;\n    public static final int UNIVERSAL_STRING    = 0x1c;\n    public static final int BMP_STRING          = 0x1e;\n    public static final int UTF8_STRING         = 0x0c;\n    \n    public static final int CONSTRUCTED         = 0x20;\n    public static final int APPLICATION         = 0x40;\n    public static final int TAGGED              = 0x80;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ConstructedOctetStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nclass ConstructedOctetStream\n    extends InputStream\n{\n    private final ASN1StreamParser _parser;\n\n    private boolean                _first = true;\n    private InputStream            _currentStream;\n\n    ConstructedOctetStream(\n        ASN1StreamParser parser)\n    {\n        _parser = parser;\n    }\n\n    public int read(byte[] b, int off, int len) throws IOException\n    {\n        if (_currentStream == null)\n        {\n            if (!_first)\n            {\n                return -1;\n            }\n\n            ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();\n\n            if (s == null)\n            {\n                return -1;\n            }\n\n            _first = false;\n            _currentStream = s.getOctetStream();\n        }\n\n        int totalRead = 0;\n\n        for (;;)\n        {\n            int numRead = _currentStream.read(b, off + totalRead, len - totalRead);\n\n            if (numRead >= 0)\n            {\n                totalRead += numRead;\n\n                if (totalRead == len)\n                {\n                    return totalRead;\n                }\n            }\n            else\n            {\n                ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject();\n\n                if (aos == null)\n                {\n                    _currentStream = null;\n                    return totalRead < 1 ? -1 : totalRead;\n                }\n\n                _currentStream = aos.getOctetStream();\n            }\n        }\n    }\n\n    public int read()\n        throws IOException\n    {\n        if (_currentStream == null)\n        {\n            if (!_first)\n            {\n                return -1;\n            }\n\n            ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();\n    \n            if (s == null)\n            {\n                return -1;\n            }\n    \n            _first = false;\n            _currentStream = s.getOctetStream();\n        }\n\n        for (;;)\n        {\n            int b = _currentStream.read();\n\n            if (b >= 0)\n            {\n                return b;\n            }\n\n            ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();\n\n            if (s == null)\n            {\n                _currentStream = null;\n                return -1;\n            }\n\n            _currentStream = s.getOctetStream();\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERApplicationSpecific.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\n/**\n * Base class for an application specific object\n */\npublic class DERApplicationSpecific \n    extends ASN1Primitive\n{\n    private final boolean   isConstructed;\n    private final int       tag;\n    private final byte[]    octets;\n\n    DERApplicationSpecific(\n        boolean isConstructed,\n        int     tag,\n        byte[]  octets)\n    {\n        this.isConstructed = isConstructed;\n        this.tag = tag;\n        this.octets = octets;\n    }\n\n    public DERApplicationSpecific(\n        int    tag,\n        byte[] octets)\n    {\n        this(false, tag, octets);\n    }\n\n    public DERApplicationSpecific(\n        int                  tag, \n        ASN1Encodable object)\n        throws IOException \n    {\n        this(true, tag, object);\n    }\n\n    public DERApplicationSpecific(\n        boolean      explicit,\n        int          tag,\n        ASN1Encodable object)\n        throws IOException\n    {\n        ASN1Primitive primitive = object.toASN1Primitive();\n\n        byte[] data = primitive.getEncoded(ASN1Encoding.DER);\n\n        this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence);\n        this.tag = tag;\n\n        if (explicit)\n        {\n            this.octets = data;\n        }\n        else\n        {\n            int lenBytes = getLengthOfHeader(data);\n            byte[] tmp = new byte[data.length - lenBytes];\n            System.arraycopy(data, lenBytes, tmp, 0, tmp.length);\n            this.octets = tmp;\n        }\n    }\n\n    public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec)\n    {\n        this.tag = tagNo;\n        this.isConstructed = true;\n        ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n\n        for (int i = 0; i != vec.size(); i++)\n        {\n            try\n            {\n                bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER));\n            }\n            catch (IOException e)\n            {\n                throw new ASN1ParsingException(\"malformed object: \" + e, e);\n            }\n        }\n        this.octets = bOut.toByteArray();\n    }\n\n    public static DERApplicationSpecific getInstance(Object obj)\n    {\n        if (obj == null || obj instanceof DERApplicationSpecific)\n        {\n            return (DERApplicationSpecific)obj;\n        }\n        else if (obj instanceof byte[])\n        {\n            try\n            {\n                return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"failed to construct object from byte[]: \" + e.getMessage());\n            }\n        }\n        else if (obj instanceof ASN1Encodable)\n        {\n            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();\n\n            if (primitive instanceof ASN1Sequence)\n            {\n                return (DERApplicationSpecific)primitive;\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    private int getLengthOfHeader(byte[] data)\n    {\n        int length = data[1] & 0xff; // TODO: assumes 1 byte tag\n\n        if (length == 0x80)\n        {\n            return 2;      // indefinite-length encoding\n        }\n\n        if (length > 127)\n        {\n            int size = length & 0x7f;\n\n            // Note: The invalid long form \"0xff\" (see X.690 8.1.3.5c) will be caught here\n            if (size > 4)\n            {\n                throw new IllegalStateException(\"DER length more than 4 bytes: \" + size);\n            }\n\n            return size + 2;\n        }\n\n        return 2;\n    }\n\n    public boolean isConstructed()\n    {\n        return isConstructed;\n    }\n    \n    public byte[] getContents()\n    {\n        return octets;\n    }\n    \n    public int getApplicationTag() \n    {\n        return tag;\n    }\n\n    /**\n     * Return the enclosed object assuming explicit tagging.\n     *\n     * @return  the resulting object\n     * @throws IOException if reconstruction fails.\n     */\n    public ASN1Primitive getObject()\n        throws IOException \n    {\n        return new ASN1InputStream(getContents()).readObject();\n    }\n\n    /**\n     * Return the enclosed object assuming implicit tagging.\n     *\n     * @param derTagNo the type tag that should be applied to the object's contents.\n     * @return  the resulting object\n     * @throws IOException if reconstruction fails.\n     */\n    public ASN1Primitive getObject(int derTagNo)\n        throws IOException\n    {\n        if (derTagNo >= 0x1f)\n        {\n            throw new IOException(\"unsupported tag number\");\n        }\n\n        byte[] orig = this.getEncoded();\n        byte[] tmp = replaceTagNumber(derTagNo, orig);\n\n        if ((orig[0] & BERTags.CONSTRUCTED) != 0)\n        {\n            tmp[0] |= BERTags.CONSTRUCTED;\n        }\n\n        return new ASN1InputStream(tmp).readObject();\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length;\n    }\n\n    /* (non-Javadoc)\n     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)\n     */\n    void encode(ASN1OutputStream out) throws IOException\n    {\n        int classBits = BERTags.APPLICATION;\n        if (isConstructed)\n        {\n            classBits |= BERTags.CONSTRUCTED;\n        }\n\n        out.writeEncoded(classBits, tag, octets);\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERApplicationSpecific))\n        {\n            return false;\n        }\n\n        DERApplicationSpecific other = (DERApplicationSpecific)o;\n\n        return isConstructed == other.isConstructed\n            && tag == other.tag\n            && Arrays.areEqual(octets, other.octets);\n    }\n\n    public int hashCode()\n    {\n        return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets);\n    }\n\n    private byte[] replaceTagNumber(int newTag, byte[] input)\n        throws IOException\n    {\n        int tagNo = input[0] & 0x1f;\n        int index = 1;\n        //\n        // with tagged object tag number is bottom 5 bits, or stored at the start of the content\n        //\n        if (tagNo == 0x1f)\n        {\n            tagNo = 0;\n\n            int b = input[index++] & 0xff;\n\n            // X.690-0207 8.1.2.4.2\n            // \"c) bits 7 to 1 of the first subsequent octet shall not all be zero.\"\n            if ((b & 0x7f) == 0) // Note: -1 will pass\n            {\n                throw new ASN1ParsingException(\"corrupted stream - invalid high tag number found\");\n            }\n\n            while ((b >= 0) && ((b & 0x80) != 0))\n            {\n                tagNo |= (b & 0x7f);\n                tagNo <<= 7;\n                b = input[index++] & 0xff;\n            }\n\n            tagNo |= (b & 0x7f);\n        }\n\n        byte[] tmp = new byte[input.length - index + 1];\n\n        System.arraycopy(input, index, tmp, 1, tmp.length - 1);\n\n        tmp[0] = (byte)newTag;\n\n        return tmp;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERBMPString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\n/**\n * DER BMPString object.\n */\npublic class DERBMPString\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private char[]  string;\n\n    /**\n     * return a BMP String from the given object.\n     *\n     * @param obj the object we want converted.\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERBMPString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERBMPString)\n        {\n            return (DERBMPString)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERBMPString)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a BMP String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *              be converted.\n     */\n    public static DERBMPString getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERBMPString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - byte encoded string.\n     */\n    DERBMPString(\n        byte[]   string)\n    {\n        char[]  cs = new char[string.length / 2];\n\n        for (int i = 0; i != cs.length; i++)\n        {\n            cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));\n        }\n\n        this.string = cs;\n    }\n\n    DERBMPString(char[] string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor\n     */\n    public DERBMPString(\n        String   string)\n    {\n        this.string = string.toCharArray();\n    }\n\n    public String getString()\n    {\n        return new String(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n\n    protected boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERBMPString))\n        {\n            return false;\n        }\n\n        DERBMPString  s = (DERBMPString)o;\n\n        return Arrays.areEqual(string, s.string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2);\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.write(BERTags.BMP_STRING);\n        out.writeLength(string.length * 2);\n\n        for (int i = 0; i != string.length; i++)\n        {\n            char c = string[i];\n\n            out.write((byte)(c >> 8));\n            out.write((byte)c);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERBitString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.io.Streams;\n\n\npublic class DERBitString\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n    \n    protected byte[]      data;\n    protected int         padBits;\n\n    /**\n     * return the correct number of pad bits for a bit string defined in\n     * a 32 bit constant\n     */\n    static protected int getPadBits(\n        int bitString)\n    {\n        int val = 0;\n        for (int i = 3; i >= 0; i--) \n        {\n            //\n            // this may look a little odd, but if it isn't done like this pre jdk1.2\n            // JVM's break!\n            //\n            if (i != 0)\n            {\n                if ((bitString >> (i * 8)) != 0) \n                {\n                    val = (bitString >> (i * 8)) & 0xFF;\n                    break;\n                }\n            }\n            else\n            {\n                if (bitString != 0)\n                {\n                    val = bitString & 0xFF;\n                    break;\n                }\n            }\n        }\n \n        if (val == 0)\n        {\n            return 7;\n        }\n\n\n        int bits = 1;\n\n        while (((val <<= 1) & 0xFF) != 0)\n        {\n            bits++;\n        }\n\n        return 8 - bits;\n    }\n\n    /**\n     * return the correct number of bytes for a bit string defined in\n     * a 32 bit constant\n     */\n    static protected byte[] getBytes(int bitString)\n    {\n        int bytes = 4;\n        for (int i = 3; i >= 1; i--)\n        {\n            if ((bitString & (0xFF << (i * 8))) != 0)\n            {\n                break;\n            }\n            bytes--;\n        }\n        \n        byte[] result = new byte[bytes];\n        for (int i = 0; i < bytes; i++)\n        {\n            result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);\n        }\n\n        return result;\n    }\n\n    /**\n     * return a Bit String from the passed in object\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERBitString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERBitString)\n        {\n            return (DERBitString)obj;\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a Bit String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERBitString getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERBitString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return fromOctetString(((ASN1OctetString)o).getOctets());\n        }\n    }\n    \n    protected DERBitString(\n        byte    data,\n        int     padBits)\n    {\n        this.data = new byte[1];\n        this.data[0] = data;\n        this.padBits = padBits;\n    }\n\n    /**\n     * @param data the octets making up the bit string.\n     * @param padBits the number of extra bits at the end of the string.\n     */\n    public DERBitString(\n        byte[]  data,\n        int     padBits)\n    {\n        this.data = data;\n        this.padBits = padBits;\n    }\n\n    public DERBitString(\n        byte[]  data)\n    {\n        this(data, 0);\n    }\n\n    public DERBitString(\n        int value)\n    {\n        this.data = getBytes(value);\n        this.padBits = getPadBits(value);\n    }\n\n    public DERBitString(\n        ASN1Encodable obj)\n        throws IOException\n    {\n        this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);\n        this.padBits = 0;\n    }\n\n    public byte[] getBytes()\n    {\n        return data;\n    }\n\n    public int getPadBits()\n    {\n        return padBits;\n    }\n\n\n    /**\n     * @return the value of the bit string as an int (truncating if necessary)\n     */\n    public int intValue()\n    {\n        int value = 0;\n        \n        for (int i = 0; i != data.length && i != 4; i++)\n        {\n            value |= (data[i] & 0xff) << (8 * i);\n        }\n        \n        return value;\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;\n    }\n\n    void encode(\n        ASN1OutputStream  out)\n        throws IOException\n    {\n        byte[]  bytes = new byte[getBytes().length + 1];\n\n        bytes[0] = (byte)getPadBits();\n        System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);\n\n        out.writeEncoded(BERTags.BIT_STRING, bytes);\n    }\n\n    public int hashCode()\n    {\n        return padBits ^ Arrays.hashCode(data);\n    }\n\n    protected boolean asn1Equals(\n        ASN1Primitive  o)\n    {\n        if (!(o instanceof DERBitString))\n        {\n            return false;\n        }\n\n        DERBitString other = (DERBitString)o;\n\n        return this.padBits == other.padBits\n            && Arrays.areEqual(this.data, other.data);\n    }\n\n    public String getString()\n    {\n        StringBuffer          buf = new StringBuffer(\"#\");\n        ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n        ASN1OutputStream      aOut = new ASN1OutputStream(bOut);\n        \n        try\n        {\n            aOut.writeObject(this);\n        }\n        catch (IOException e)\n        {\n           throw new RuntimeException(\"internal error encoding BitString\");\n        }\n        \n        byte[]    string = bOut.toByteArray();\n        \n        for (int i = 0; i != string.length; i++)\n        {\n            buf.append(table[(string[i] >>> 4) & 0xf]);\n            buf.append(table[string[i] & 0xf]);\n        }\n        \n        return buf.toString();\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    static DERBitString fromOctetString(byte[] bytes)\n    {\n        if (bytes.length < 1)\n        {\n            throw new IllegalArgumentException(\"truncated BIT STRING detected\");\n        }\n\n        int padBits = bytes[0];\n        byte[] data = new byte[bytes.length - 1];\n\n        if (data.length != 0)\n        {\n            System.arraycopy(bytes, 1, data, 0, bytes.length - 1);\n        }\n\n        return new DERBitString(data, padBits);\n    }\n\n    static DERBitString fromInputStream(int length, InputStream stream)\n        throws IOException\n    {\n        if (length < 1)\n        {\n            throw new IllegalArgumentException(\"truncated BIT STRING detected\");\n        }\n\n        int padBits = stream.read();\n        byte[] data = new byte[length - 1];\n\n        if (data.length != 0)\n        {\n            if (Streams.readFully(stream, data) != data.length)\n            {\n                throw new EOFException(\"EOF encountered in middle of BIT STRING\");\n            }\n        }\n\n        return new DERBitString(data, padBits);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERBoolean.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\npublic class DERBoolean\n    extends ASN1Primitive\n{\n    private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff };\n    private static final byte[] FALSE_VALUE = new byte[] { 0 };\n\n    private byte[]         value;\n\n    public static final ASN1Boolean FALSE = new ASN1Boolean(false);\n    public static final ASN1Boolean TRUE  = new ASN1Boolean(true);\n\n\n    /**\n     * return a boolean from the passed in object.\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1Boolean getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1Boolean)\n        {\n            return (ASN1Boolean)obj;\n        }\n\n        if (obj instanceof DERBoolean)\n        {\n            return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE;\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a ASN1Boolean from the passed in boolean.\n     */\n    public static ASN1Boolean getInstance(\n        boolean  value)\n    {\n        return (value ? TRUE : FALSE);\n    }\n\n    /**\n     * return a ASN1Boolean from the passed in boolean.\n     */\n    public static ASN1Boolean getInstance(\n        int value)\n    {\n        return (value != 0 ? TRUE : FALSE);\n    }\n\n    /**\n     * return a Boolean from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static ASN1Boolean getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERBoolean)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets());\n        }\n    }\n    \n    DERBoolean(\n        byte[]       value)\n    {\n        if (value.length != 1)\n        {\n            throw new IllegalArgumentException(\"byte value should have 1 byte in it\");\n        }\n\n        if (value[0] == 0)\n        {\n            this.value = FALSE_VALUE;\n        }\n        else if (value[0] == 0xff)\n        {\n            this.value = TRUE_VALUE;\n        }\n        else\n        {\n            this.value = Arrays.clone(value);\n        }\n    }\n\n    /**\n     * @deprecated use getInstance(boolean) method.\n     * @param value\n     */\n    public DERBoolean(\n        boolean     value)\n    {\n        this.value = (value) ? TRUE_VALUE : FALSE_VALUE;\n    }\n\n    public boolean isTrue()\n    {\n        return (value[0] != 0);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 3;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.BOOLEAN, value);\n    }\n    \n    protected boolean asn1Equals(\n        ASN1Primitive  o)\n    {\n        if ((o == null) || !(o instanceof DERBoolean))\n        {\n            return false;\n        }\n\n        return (value[0] == ((DERBoolean)o).value[0]);\n    }\n    \n    public int hashCode()\n    {\n        return value[0];\n    }\n\n\n    public String toString()\n    {\n      return (value[0] != 0) ? \"TRUE\" : \"FALSE\";\n    }\n\n    static ASN1Boolean fromOctetString(byte[] value)\n    {\n        if (value.length != 1)\n        {\n            throw new IllegalArgumentException(\"byte value should have 1 byte in it\");\n        }\n\n        if (value[0] == 0)\n        {\n            return FALSE;\n        }\n        else if (value[0] == 0xff)\n        {\n            return TRUE;\n        }\n        else\n        {\n            return new ASN1Boolean(value);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DEREncodableVector.java",
    "content": "package local.org.bouncycastle.asn1;\n\n/**\n * a general class for building up a vector of DER encodable objects -\n * this will eventually be superceded by ASN1EncodableVector so you should\n * use that class in preference.\n */\npublic class DEREncodableVector\n    extends ASN1EncodableVector\n{\n    /**\n     * @deprecated use ASN1EncodableVector instead.\n     */\n    public DEREncodableVector()\n    {\n\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DEREnumerated.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\npublic class DEREnumerated\n    extends ASN1Primitive\n{\n    byte[]      bytes;\n\n    /**\n     * return an integer from the passed in object\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1Enumerated getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1Enumerated)\n        {\n            return (ASN1Enumerated)obj;\n        }\n\n        if (obj instanceof DEREnumerated)\n        {\n            return new ASN1Enumerated(((DEREnumerated)obj).getValue());\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (ASN1Enumerated)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an Enumerated from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DEREnumerated getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DEREnumerated)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return fromOctetString(((ASN1OctetString)o).getOctets());\n        }\n    }\n\n    public DEREnumerated(\n        int         value)\n    {\n        bytes = BigInteger.valueOf(value).toByteArray();\n    }\n\n    public DEREnumerated(\n        BigInteger   value)\n    {\n        bytes = value.toByteArray();\n    }\n\n    public DEREnumerated(\n        byte[]   bytes)\n    {\n        this.bytes = bytes;\n    }\n\n    public BigInteger getValue()\n    {\n        return new BigInteger(bytes);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.ENUMERATED, bytes);\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive  o)\n    {\n        if (!(o instanceof DEREnumerated))\n        {\n            return false;\n        }\n\n        DEREnumerated other = (DEREnumerated)o;\n\n        return Arrays.areEqual(this.bytes, other.bytes);\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(bytes);\n    }\n\n    private static ASN1Enumerated[] cache = new ASN1Enumerated[12];\n\n    static ASN1Enumerated fromOctetString(byte[] enc)\n    {\n        if (enc.length > 1)\n        {\n            return new ASN1Enumerated(Arrays.clone(enc));\n        }\n\n        if (enc.length == 0)\n        {\n            throw new IllegalArgumentException(\"ENUMERATED has zero length\");\n        }\n        int value = enc[0] & 0xff;\n\n        if (value >= cache.length)\n        {\n            return new ASN1Enumerated(Arrays.clone(enc));\n        }\n\n        ASN1Enumerated possibleMatch = cache[value];\n\n        if (possibleMatch == null)\n        {\n            possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc));\n        }\n\n        return possibleMatch;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERExternal.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * Class representing the DER-type External\n */\npublic class DERExternal\n    extends ASN1Primitive\n{\n    private ASN1ObjectIdentifier directReference;\n    private ASN1Integer indirectReference;\n    private ASN1Primitive dataValueDescriptor;\n    private int encoding;\n    private ASN1Primitive externalContent;\n    \n    public DERExternal(ASN1EncodableVector vector)\n    {\n        int offset = 0;\n\n        ASN1Primitive enc = getObjFromVector(vector, offset);\n        if (enc instanceof ASN1ObjectIdentifier)\n        {\n            directReference = (ASN1ObjectIdentifier)enc;\n            offset++;\n            enc = getObjFromVector(vector, offset);\n        }\n        if (enc instanceof ASN1Integer)\n        {\n            indirectReference = (ASN1Integer) enc;\n            offset++;\n            enc = getObjFromVector(vector, offset);\n        }\n        if (!(enc instanceof DERTaggedObject))\n        {\n            dataValueDescriptor = (ASN1Primitive) enc;\n            offset++;\n            enc = getObjFromVector(vector, offset);\n        }\n\n        if (vector.size() != offset + 1)\n        {\n            throw new IllegalArgumentException(\"input vector too large\");\n        }\n\n        if (!(enc instanceof DERTaggedObject))\n        {\n            throw new IllegalArgumentException(\"No tagged object found in vector. Structure doesn't seem to be of type External\");\n        }\n        DERTaggedObject obj = (DERTaggedObject)enc;\n        setEncoding(obj.getTagNo());\n        externalContent = obj.getObject();\n    }\n\n    private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)\n    {\n        if (v.size() <= index)\n        {\n            throw new IllegalArgumentException(\"too few objects in input vector\");\n        }\n\n        return v.get(index).toASN1Primitive();\n    }\n    /**\n     * Creates a new instance of DERExternal\n     * See X.690 for more informations about the meaning of these parameters\n     * @param directReference The direct reference or <code>null</code> if not set.\n     * @param indirectReference The indirect reference or <code>null</code> if not set.\n     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.\n     * @param externalData The external data in its encoded form.\n     */\n    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)\n    {\n        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());\n    }\n\n    /**\n     * Creates a new instance of DERExternal.\n     * See X.690 for more informations about the meaning of these parameters\n     * @param directReference The direct reference or <code>null</code> if not set.\n     * @param indirectReference The indirect reference or <code>null</code> if not set.\n     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.\n     * @param encoding The encoding to be used for the external data\n     * @param externalData The external data\n     */\n    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)\n    {\n        setDirectReference(directReference);\n        setIndirectReference(indirectReference);\n        setDataValueDescriptor(dataValueDescriptor);\n        setEncoding(encoding);\n        setExternalContent(externalData.toASN1Primitive());\n    }\n\n    /* (non-Javadoc)\n     * @see java.lang.Object#hashCode()\n     */\n    public int hashCode()\n    {\n        int ret = 0;\n        if (directReference != null)\n        {\n            ret = directReference.hashCode();\n        }\n        if (indirectReference != null)\n        {\n            ret ^= indirectReference.hashCode();\n        }\n        if (dataValueDescriptor != null)\n        {\n            ret ^= dataValueDescriptor.hashCode();\n        }\n        ret ^= externalContent.hashCode();\n        return ret;\n    }\n\n    boolean isConstructed()\n    {\n        return true;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        return this.getEncoded().length;\n    }\n\n    /* (non-Javadoc)\n     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)\n     */\n    void encode(ASN1OutputStream out)\n        throws IOException\n    {\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        if (directReference != null)\n        {\n            baos.write(directReference.getEncoded(ASN1Encoding.DER));\n        }\n        if (indirectReference != null)\n        {\n            baos.write(indirectReference.getEncoded(ASN1Encoding.DER));\n        }\n        if (dataValueDescriptor != null)\n        {\n            baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));\n        }\n        DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);\n        baos.write(obj.getEncoded(ASN1Encoding.DER));\n        out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());\n    }\n\n    /* (non-Javadoc)\n     * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive)\n     */\n    boolean asn1Equals(ASN1Primitive o)\n    {\n        if (!(o instanceof DERExternal))\n        {\n            return false;\n        }\n        if (this == o)\n        {\n            return true;\n        }\n        DERExternal other = (DERExternal)o;\n        if (directReference != null)\n        {\n            if (other.directReference == null || !other.directReference.equals(directReference))  \n            {\n                return false;\n            }\n        }\n        if (indirectReference != null)\n        {\n            if (other.indirectReference == null || !other.indirectReference.equals(indirectReference))\n            {\n                return false;\n            }\n        }\n        if (dataValueDescriptor != null)\n        {\n            if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor))\n            {\n                return false;\n            }\n        }\n        return externalContent.equals(other.externalContent);\n    }\n\n    /**\n     * Returns the data value descriptor\n     * @return The descriptor\n     */\n    public ASN1Primitive getDataValueDescriptor()\n    {\n        return dataValueDescriptor;\n    }\n\n    /**\n     * Returns the direct reference of the external element\n     * @return The reference\n     */\n    public ASN1ObjectIdentifier getDirectReference()\n    {\n        return directReference;\n    }\n\n    /**\n     * Returns the encoding of the content. Valid values are\n     * <ul>\n     * <li><code>0</code> single-ASN1-type</li>\n     * <li><code>1</code> OCTET STRING</li>\n     * <li><code>2</code> BIT STRING</li>\n     * </ul>\n     * @return The encoding\n     */\n    public int getEncoding()\n    {\n        return encoding;\n    }\n    \n    /**\n     * Returns the content of this element\n     * @return The content\n     */\n    public ASN1Primitive getExternalContent()\n    {\n        return externalContent;\n    }\n    \n    /**\n     * Returns the indirect reference of this element\n     * @return The reference\n     */\n    public ASN1Integer getIndirectReference()\n    {\n        return indirectReference;\n    }\n    \n    /**\n     * Sets the data value descriptor\n     * @param dataValueDescriptor The descriptor\n     */\n    private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor)\n    {\n        this.dataValueDescriptor = dataValueDescriptor;\n    }\n\n    /**\n     * Sets the direct reference of the external element\n     * @param directReferemce The reference\n     */\n    private void setDirectReference(ASN1ObjectIdentifier directReferemce)\n    {\n        this.directReference = directReferemce;\n    }\n    \n    /**\n     * Sets the encoding of the content. Valid values are\n     * <ul>\n     * <li><code>0</code> single-ASN1-type</li>\n     * <li><code>1</code> OCTET STRING</li>\n     * <li><code>2</code> BIT STRING</li>\n     * </ul>\n     * @param encoding The encoding\n     */\n    private void setEncoding(int encoding)\n    {\n        if (encoding < 0 || encoding > 2)\n        {\n            throw new IllegalArgumentException(\"invalid encoding value: \" + encoding);\n        }\n        this.encoding = encoding;\n    }\n    \n    /**\n     * Sets the content of this element\n     * @param externalContent The content\n     */\n    private void setExternalContent(ASN1Primitive externalContent)\n    {\n        this.externalContent = externalContent;\n    }\n    \n    /**\n     * Sets the indirect reference of this element\n     * @param indirectReference The reference\n     */\n    private void setIndirectReference(ASN1Integer indirectReference)\n    {\n        this.indirectReference = indirectReference;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERExternalParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class DERExternalParser\n    implements ASN1Encodable, InMemoryRepresentable\n{\n    private ASN1StreamParser _parser;\n\n    /**\n     * \n     */\n    public DERExternalParser(ASN1StreamParser parser)\n    {\n        this._parser = parser;\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        return _parser.readObject();\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        try\n        {\n            return new DERExternal(_parser.readVector());\n        }\n        catch (IllegalArgumentException e)\n        {\n            throw new ASN1Exception(e.getMessage(), e);\n        }\n    }\n    \n    public ASN1Primitive toASN1Primitive()\n    {\n        try \n        {\n            return getLoadedObject();\n        }\n        catch (IOException ioe) \n        {\n            throw new ASN1ParsingException(\"unable to get DER object\", ioe);\n        }\n        catch (IllegalArgumentException ioe) \n        {\n            throw new ASN1ParsingException(\"unable to get DER object\", ioe);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERFactory.java",
    "content": "package local.org.bouncycastle.asn1;\n\nclass DERFactory\n{\n    static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence();\n    static final ASN1Set EMPTY_SET = new DERSet();\n\n    static ASN1Sequence createSequence(ASN1EncodableVector v)\n    {\n        return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v);\n    }\n\n    static ASN1Set createSet(ASN1EncodableVector v)\n    {\n        return v.size() < 1 ? EMPTY_SET : new DLSet(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERGeneralString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\npublic class DERGeneralString \n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[] string;\n\n    public static DERGeneralString getInstance(\n        Object obj) \n    {\n        if (obj == null || obj instanceof DERGeneralString) \n        {\n            return (DERGeneralString) obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERGeneralString)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \"\n                + obj.getClass().getName());\n    }\n\n    public static DERGeneralString getInstance(\n        ASN1TaggedObject obj, \n        boolean explicit) \n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERGeneralString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERGeneralString(((ASN1OctetString)o).getOctets());\n        }\n    }\n\n    DERGeneralString(byte[] string)\n    {\n        this.string = string;\n    }\n\n    public DERGeneralString(String string) \n    {\n        this.string = Strings.toByteArray(string);\n    }\n    \n    public String getString() \n    {\n        return Strings.fromByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public byte[] getOctets() \n    {\n        return Arrays.clone(string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(ASN1OutputStream out)\n        throws IOException \n    {\n        out.writeEncoded(BERTags.GENERAL_STRING, string);\n    }\n    \n    public int hashCode() \n    {\n        return Arrays.hashCode(string);\n    }\n    \n    boolean asn1Equals(ASN1Primitive o)\n    {\n        if (!(o instanceof DERGeneralString)) \n        {\n            return false;\n        }\n        DERGeneralString s = (DERGeneralString)o;\n\n        return Arrays.areEqual(string, s.string);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERGeneralizedTime.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.SimpleTimeZone;\nimport java.util.TimeZone;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * Generalized time object.\n */\npublic class DERGeneralizedTime\n    extends ASN1Primitive\n{\n    private byte[]      time;\n\n    /**\n     * return a generalized time from the passed in object\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1GeneralizedTime getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1GeneralizedTime)\n        {\n            return (ASN1GeneralizedTime)obj;\n        }\n\n        if (obj instanceof DERGeneralizedTime)\n        {\n            return new ASN1GeneralizedTime(((DERGeneralizedTime)obj).time);\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (ASN1GeneralizedTime)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a Generalized Time object from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static ASN1GeneralizedTime getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERGeneralizedTime)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());\n        }\n    }\n    \n    /**\n     * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z\n     * for local time, or Z+-HHMM on the end, for difference between local\n     * time and UTC time. The fractional second amount f must consist of at\n     * least one number with trailing zeroes removed.\n     *\n     * @param time the time string.\n     * @exception IllegalArgumentException if String is an illegal format.\n     */\n    public DERGeneralizedTime(\n        String  time)\n    {\n        this.time = Strings.toByteArray(time);\n        try\n        {\n            this.getDate();\n        }\n        catch (ParseException e)\n        {\n            throw new IllegalArgumentException(\"invalid date string: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * base constructor from a java.util.date object\n     */\n    public DERGeneralizedTime(\n        Date time)\n    {\n        SimpleDateFormat dateF = new SimpleDateFormat(\"yyyyMMddHHmmss'Z'\");\n\n        dateF.setTimeZone(new SimpleTimeZone(0,\"Z\"));\n\n        this.time = Strings.toByteArray(dateF.format(time));\n    }\n\n    DERGeneralizedTime(\n        byte[]  bytes)\n    {\n        this.time = bytes;\n    }\n\n    /**\n     * Return the time.\n     * @return The time string as it appeared in the encoded object.\n     */\n    public String getTimeString()\n    {\n        return Strings.fromByteArray(time);\n    }\n    \n    /**\n     * return the time - always in the form of \n     *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).\n     * <p>\n     * Normally in a certificate we would expect \"Z\" rather than \"GMT\",\n     * however adding the \"GMT\" means we can just use:\n     * <pre>\n     *     dateF = new SimpleDateFormat(\"yyyyMMddHHmmssz\");\n     * </pre>\n     * To read in the time and get a date which is compatible with our local\n     * time zone.\n     */\n    public String getTime()\n    {\n        String stime = Strings.fromByteArray(time);\n\n        //\n        // standardise the format.\n        //             \n        if (stime.charAt(stime.length() - 1) == 'Z')\n        {\n            return stime.substring(0, stime.length() - 1) + \"GMT+00:00\";\n        }\n        else\n        {\n            int signPos = stime.length() - 5;\n            char sign = stime.charAt(signPos);\n            if (sign == '-' || sign == '+')\n            {\n                return stime.substring(0, signPos)\n                    + \"GMT\"\n                    + stime.substring(signPos, signPos + 3)\n                    + \":\"\n                    + stime.substring(signPos + 3);\n            }\n            else\n            {\n                signPos = stime.length() - 3;\n                sign = stime.charAt(signPos);\n                if (sign == '-' || sign == '+')\n                {\n                    return stime.substring(0, signPos)\n                        + \"GMT\"\n                        + stime.substring(signPos)\n                        + \":00\";\n                }\n            }\n        }            \n        return stime + calculateGMTOffset();\n    }\n\n    private String calculateGMTOffset()\n    {\n        String sign = \"+\";\n        TimeZone timeZone = TimeZone.getDefault();\n        int offset = timeZone.getRawOffset();\n        if (offset < 0)\n        {\n            sign = \"-\";\n            offset = -offset;\n        }\n        int hours = offset / (60 * 60 * 1000);\n        int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);\n\n        try\n        {\n            if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))\n            {\n                hours += sign.equals(\"+\") ? 1 : -1;\n            }\n        }\n        catch (ParseException e)\n        {\n            // we'll do our best and ignore daylight savings\n        }\n\n        return \"GMT\" + sign + convert(hours) + \":\" + convert(minutes);\n    }\n\n    private String convert(int time)\n    {\n        if (time < 10)\n        {\n            return \"0\" + time;\n        }\n\n        return Integer.toString(time);\n    }\n\n    public Date getDate()\n        throws ParseException\n    {\n        SimpleDateFormat dateF;\n        String stime = Strings.fromByteArray(time);\n        String d = stime;\n\n        if (stime.endsWith(\"Z\"))\n        {\n            if (hasFractionalSeconds())\n            {\n                dateF = new SimpleDateFormat(\"yyyyMMddHHmmss.SSS'Z'\");\n            }\n            else\n            {\n                dateF = new SimpleDateFormat(\"yyyyMMddHHmmss'Z'\");\n            }\n\n            dateF.setTimeZone(new SimpleTimeZone(0, \"Z\"));\n        }\n        else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)\n        {\n            d = this.getTime();\n            if (hasFractionalSeconds())\n            { \n                dateF = new SimpleDateFormat(\"yyyyMMddHHmmss.SSSz\");\n            }\n            else\n            {\n                dateF = new SimpleDateFormat(\"yyyyMMddHHmmssz\");\n            }\n\n            dateF.setTimeZone(new SimpleTimeZone(0, \"Z\"));\n        }\n        else\n        {\n            if (hasFractionalSeconds())\n            {\n                dateF = new SimpleDateFormat(\"yyyyMMddHHmmss.SSS\");\n            }\n            else\n            {\n                dateF = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n            }\n\n            dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));\n        }\n\n        if (hasFractionalSeconds())\n        {\n            // java misinterprets extra digits as being milliseconds...\n            String frac = d.substring(14);\n            int    index;\n            for (index = 1; index < frac.length(); index++)\n            {\n                char ch = frac.charAt(index);\n                if (!('0' <= ch && ch <= '9'))\n                {\n                    break;        \n                }\n            }\n\n            if (index - 1 > 3)\n            {\n                frac = frac.substring(0, 4) + frac.substring(index);\n                d = d.substring(0, 14) + frac;\n            }\n            else if (index - 1 == 1)\n            {\n                frac = frac.substring(0, index) + \"00\" + frac.substring(index);\n                d = d.substring(0, 14) + frac;\n            }\n            else if (index - 1 == 2)\n            {\n                frac = frac.substring(0, index) + \"0\" + frac.substring(index);\n                d = d.substring(0, 14) + frac;\n            }\n        }\n\n        return dateF.parse(d);\n    }\n\n    private boolean hasFractionalSeconds()\n    {\n        for (int i = 0; i != time.length; i++)\n        {\n            if (time[i] == '.')\n            {\n                if (i == 14)\n                {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        int length = time.length;\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    void encode(\n        ASN1OutputStream  out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.GENERALIZED_TIME, time);\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive  o)\n    {\n        if (!(o instanceof DERGeneralizedTime))\n        {\n            return false;\n        }\n\n        return Arrays.areEqual(time, ((DERGeneralizedTime)o).time);\n    }\n    \n    public int hashCode()\n    {\n        return Arrays.hashCode(time);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERGenerator.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport local.org.bouncycastle.util.io.Streams;\n\n\npublic abstract class DERGenerator\n    extends ASN1Generator\n{       \n    private boolean      _tagged = false;\n    private boolean      _isExplicit;\n    private int          _tagNo;\n    \n    protected DERGenerator(\n        OutputStream out)\n    {\n        super(out);\n    }\n\n    public DERGenerator(\n        OutputStream out,\n        int          tagNo,\n        boolean      isExplicit)\n    { \n        super(out);\n        \n        _tagged = true;\n        _isExplicit = isExplicit;\n        _tagNo = tagNo;\n    }\n\n    private void writeLength(\n        OutputStream out,\n        int          length)\n        throws IOException\n    {\n        if (length > 127)\n        {\n            int size = 1;\n            int val = length;\n\n            while ((val >>>= 8) != 0)\n            {\n                size++;\n            }\n\n            out.write((byte)(size | 0x80));\n\n            for (int i = (size - 1) * 8; i >= 0; i -= 8)\n            {\n                out.write((byte)(length >> i));\n            }\n        }\n        else\n        {\n            out.write((byte)length);\n        }\n    }\n\n    void writeDEREncoded(\n        OutputStream out,\n        int          tag,\n        byte[]       bytes)\n        throws IOException\n    {\n        out.write(tag);\n        writeLength(out, bytes.length);\n        out.write(bytes);\n    }\n\n    void writeDEREncoded(\n        int       tag,\n        byte[]    bytes)\n        throws IOException\n    {\n        if (_tagged)\n        {\n            int tagNum = _tagNo | BERTags.TAGGED;\n            \n            if (_isExplicit)\n            {\n                int newTag = _tagNo | BERTags.CONSTRUCTED | BERTags.TAGGED;\n\n                ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n                \n                writeDEREncoded(bOut, tag, bytes);\n                \n                writeDEREncoded(_out, newTag, bOut.toByteArray());\n            }\n            else\n            {   \n                if ((tag & BERTags.CONSTRUCTED) != 0)\n                {\n                    writeDEREncoded(_out, tagNum | BERTags.CONSTRUCTED, bytes);\n                }\n                else\n                {\n                    writeDEREncoded(_out, tagNum, bytes);\n                }\n            }\n        }\n        else\n        {\n            writeDEREncoded(_out, tag, bytes);\n        }\n    }\n    \n    void writeDEREncoded(\n        OutputStream out,\n        int          tag,\n        InputStream  in)\n        throws IOException\n    {\n        writeDEREncoded(out, tag, Streams.readAll(in));\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERIA5String.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER IA5String object - this is an ascii string.\n */\npublic class DERIA5String\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[]  string;\n\n    /**\n     * return a IA5 string from the passed in object\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERIA5String getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERIA5String)\n        {\n            return (DERIA5String)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERIA5String)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an IA5 String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERIA5String getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERIA5String)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERIA5String(((ASN1OctetString)o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - with bytes.\n     */\n    DERIA5String(\n        byte[]   string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor - without validation.\n     */\n    public DERIA5String(\n        String   string)\n    {\n        this(string, false);\n    }\n\n    /**\n     * Constructor with optional validation.\n     *\n     * @param string the base string to wrap.\n     * @param validate whether or not to check the string.\n     * @throws IllegalArgumentException if validate is true and the string\n     * contains characters that should not be in an IA5String.\n     */\n    public DERIA5String(\n        String   string,\n        boolean  validate)\n    {\n        if (string == null)\n        {\n            throw new NullPointerException(\"string cannot be null\");\n        }\n        if (validate && !isIA5String(string))\n        {\n            throw new IllegalArgumentException(\"string contains illegal characters\");\n        }\n\n        this.string = Strings.toByteArray(string);\n    }\n\n    public String getString()\n    {\n        return Strings.fromByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public byte[] getOctets()\n    {\n        return Arrays.clone(string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.IA5_STRING, string);\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERIA5String))\n        {\n            return false;\n        }\n\n        DERIA5String  s = (DERIA5String)o;\n\n        return Arrays.areEqual(string, s.string);\n    }\n\n    /**\n     * return true if the passed in String can be represented without\n     * loss as an IA5String, false otherwise.\n     *\n     * @return true if in printable set, false otherwise.\n     */\n    public static boolean isIA5String(\n        String  str)\n    {\n        for (int i = str.length() - 1; i >= 0; i--)\n        {\n            char    ch = str.charAt(i);\n\n            if (ch > 0x007f)\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERInteger.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\npublic class DERInteger\n    extends ASN1Primitive\n{\n    byte[]      bytes;\n\n    /**\n     * return an integer from the passed in object\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1Integer getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1Integer)\n        {\n            return (ASN1Integer)obj;\n        }\n        if (obj instanceof DERInteger)\n        {\n            return new ASN1Integer((((DERInteger)obj).getValue()));\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (ASN1Integer)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an Integer from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static ASN1Integer getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERInteger)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets());\n        }\n    }\n\n    public DERInteger(\n        long         value)\n    {\n        bytes = BigInteger.valueOf(value).toByteArray();\n    }\n\n    public DERInteger(\n        BigInteger   value)\n    {\n        bytes = value.toByteArray();\n    }\n\n    public DERInteger(\n        byte[]   bytes)\n    {\n        this.bytes = bytes;\n    }\n\n    public BigInteger getValue()\n    {\n        return new BigInteger(bytes);\n    }\n\n    /**\n     * in some cases positive values get crammed into a space,\n     * that's not quite big enough...\n     */\n    public BigInteger getPositiveValue()\n    {\n        return new BigInteger(1, bytes);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.INTEGER, bytes);\n    }\n    \n    public int hashCode()\n    {\n         int     value = 0;\n \n         for (int i = 0; i != bytes.length; i++)\n         {\n             value ^= (bytes[i] & 0xff) << (i % 4);\n         }\n \n         return value;\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive  o)\n    {\n        if (!(o instanceof DERInteger))\n        {\n            return false;\n        }\n\n        DERInteger other = (DERInteger)o;\n\n        return Arrays.areEqual(bytes, other.bytes);\n    }\n\n    public String toString()\n    {\n      return getValue().toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERNull.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\n/**\n * A NULL object.\n */\npublic class DERNull\n    extends ASN1Null\n{\n    public static final DERNull INSTANCE = new DERNull();\n\n    private static final byte[]  zeroBytes = new byte[0];\n\n    /**\n     * @deprecated use DERNull.INSTANCE\n     */\n    public DERNull()\n    {\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 2;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.NULL, zeroBytes);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERNumericString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.\n */\npublic class DERNumericString\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[]  string;\n\n    /**\n     * return a Numeric string from the passed in object\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERNumericString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERNumericString)\n        {\n            return (DERNumericString)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERNumericString)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an Numeric String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERNumericString getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERNumericString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERNumericString(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - with bytes.\n     */\n    DERNumericString(\n        byte[]   string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor -  without validation..\n     */\n    public DERNumericString(\n        String   string)\n    {\n        this(string, false);\n    }\n\n    /**\n     * Constructor with optional validation.\n     *\n     * @param string the base string to wrap.\n     * @param validate whether or not to check the string.\n     * @throws IllegalArgumentException if validate is true and the string\n     * contains characters that should not be in a NumericString.\n     */\n    public DERNumericString(\n        String   string,\n        boolean  validate)\n    {\n        if (validate && !isNumericString(string))\n        {\n            throw new IllegalArgumentException(\"string contains illegal characters\");\n        }\n\n        this.string = Strings.toByteArray(string);\n    }\n\n    public String getString()\n    {\n        return Strings.fromByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public byte[] getOctets()\n    {\n        return Arrays.clone(string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.NUMERIC_STRING, string);\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERNumericString))\n        {\n            return false;\n        }\n\n        DERNumericString  s = (DERNumericString)o;\n\n        return Arrays.areEqual(string, s.string);\n    }\n\n    /**\n     * Return true if the string can be represented as a NumericString ('0'..'9', ' ')\n     *\n     * @param str string to validate.\n     * @return true if numeric, fale otherwise.\n     */\n    public static boolean isNumericString(\n        String  str)\n    {\n        for (int i = str.length() - 1; i >= 0; i--)\n        {\n            char    ch = str.charAt(i);\n\n            if (ch > 0x007f)\n            {\n                return false;\n            }\n\n            if (('0' <= ch && ch <= '9') || ch == ' ')\n            {\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERObjectIdentifier.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\npublic class DERObjectIdentifier\n    extends ASN1Primitive\n{\n    String identifier;\n\n    private byte[] body;\n\n    /**\n     * return an OID from the passed in object\n     *\n     * @throws IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1ObjectIdentifier getInstance(\n        Object obj)\n    {\n        if (obj == null || obj instanceof ASN1ObjectIdentifier)\n        {\n            return (ASN1ObjectIdentifier)obj;\n        }\n\n        if (obj instanceof DERObjectIdentifier)\n        {\n            return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());\n        }\n\n        if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)\n        {\n            return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();\n        }\n\n        if (obj instanceof byte[])\n        {\n            return ASN1ObjectIdentifier.fromOctetString((byte[])obj);\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an Object Identifier from a tagged object.\n     *\n     * @param obj      the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *                 tagged false otherwise.\n     * @throws IllegalArgumentException if the tagged object cannot\n     * be converted.\n     */\n    public static ASN1ObjectIdentifier getInstance(\n        ASN1TaggedObject obj,\n        boolean explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERObjectIdentifier)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());\n        }\n    }\n\n    private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;\n\n    DERObjectIdentifier(\n        byte[] bytes)\n    {\n        StringBuffer objId = new StringBuffer();\n        long value = 0;\n        BigInteger bigValue = null;\n        boolean first = true;\n\n        for (int i = 0; i != bytes.length; i++)\n        {\n            int b = bytes[i] & 0xff;\n\n            if (value <= LONG_LIMIT)\n            {\n                value += (b & 0x7f);\n                if ((b & 0x80) == 0)             // end of number reached\n                {\n                    if (first)\n                    {\n                        if (value < 40)\n                        {\n                            objId.append('0');\n                        }\n                        else if (value < 80)\n                        {\n                            objId.append('1');\n                            value -= 40;\n                        }\n                        else\n                        {\n                            objId.append('2');\n                            value -= 80;\n                        }\n                        first = false;\n                    }\n\n                    objId.append('.');\n                    objId.append(value);\n                    value = 0;\n                }\n                else\n                {\n                    value <<= 7;\n                }\n            }\n            else\n            {\n                if (bigValue == null)\n                {\n                    bigValue = BigInteger.valueOf(value);\n                }\n                bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));\n                if ((b & 0x80) == 0)\n                {\n                    if (first)\n                    {\n                        objId.append('2');\n                        bigValue = bigValue.subtract(BigInteger.valueOf(80));\n                        first = false;\n                    }\n\n                    objId.append('.');\n                    objId.append(bigValue);\n                    bigValue = null;\n                    value = 0;\n                }\n                else\n                {\n                    bigValue = bigValue.shiftLeft(7);\n                }\n            }\n        }\n\n        this.identifier = objId.toString();\n        this.body = Arrays.clone(bytes);\n    }\n\n    public DERObjectIdentifier(\n        String identifier)\n    {\n        if (identifier == null)\n        {\n            throw new IllegalArgumentException(\"'identifier' cannot be null\");\n        }\n        if (!isValidIdentifier(identifier))\n        {\n            throw new IllegalArgumentException(\"string \" + identifier + \" not an OID\");\n        }\n\n        this.identifier = identifier;\n    }\n\n    DERObjectIdentifier(DERObjectIdentifier oid, String branchID)\n    {\n        if (!isValidBranchID(branchID, 0))\n        {\n            throw new IllegalArgumentException(\"string \" + branchID + \" not a valid OID branch\");\n        }\n\n        this.identifier = oid.getId() + \".\" + branchID;\n    }\n\n    public String getId()\n    {\n        return identifier;\n    }\n\n    private void writeField(\n        ByteArrayOutputStream out,\n        long fieldValue)\n    {\n        byte[] result = new byte[9];\n        int pos = 8;\n        result[pos] = (byte)((int)fieldValue & 0x7f);\n        while (fieldValue >= (1L << 7))\n        {\n            fieldValue >>= 7;\n            result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);\n        }\n        out.write(result, pos, 9 - pos);\n    }\n\n    private void writeField(\n        ByteArrayOutputStream out,\n        BigInteger fieldValue)\n    {\n        int byteCount = (fieldValue.bitLength() + 6) / 7;\n        if (byteCount == 0)\n        {\n            out.write(0);\n        }\n        else\n        {\n            BigInteger tmpValue = fieldValue;\n            byte[] tmp = new byte[byteCount];\n            for (int i = byteCount - 1; i >= 0; i--)\n            {\n                tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80);\n                tmpValue = tmpValue.shiftRight(7);\n            }\n            tmp[byteCount - 1] &= 0x7f;\n            out.write(tmp, 0, tmp.length);\n        }\n    }\n\n    private void doOutput(ByteArrayOutputStream aOut)\n    {\n        OIDTokenizer tok = new OIDTokenizer(identifier);\n        int first = Integer.parseInt(tok.nextToken()) * 40;\n\n        String secondToken = tok.nextToken();\n        if (secondToken.length() <= 18)\n        {\n            writeField(aOut, first + Long.parseLong(secondToken));\n        }\n        else\n        {\n            writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));\n        }\n\n        while (tok.hasMoreTokens())\n        {\n            String token = tok.nextToken();\n            if (token.length() <= 18)\n            {\n                writeField(aOut, Long.parseLong(token));\n            }\n            else\n            {\n                writeField(aOut, new BigInteger(token));\n            }\n        }\n    }\n\n    protected synchronized byte[] getBody()\n    {\n        if (body == null)\n        {\n            ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n\n            doOutput(bOut);\n\n            body = bOut.toByteArray();\n        }\n\n        return body;\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int length = getBody().length;\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        byte[] enc = getBody();\n\n        out.write(BERTags.OBJECT_IDENTIFIER);\n        out.writeLength(enc.length);\n        out.write(enc);\n    }\n\n    public int hashCode()\n    {\n        return identifier.hashCode();\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERObjectIdentifier))\n        {\n            return false;\n        }\n\n        return identifier.equals(((DERObjectIdentifier)o).identifier);\n    }\n\n    public String toString()\n    {\n        return getId();\n    }\n\n    private static boolean isValidBranchID(\n        String branchID, int start)\n    {\n        boolean periodAllowed = false;\n\n        int pos = branchID.length();\n        while (--pos >= start)\n        {\n            char ch = branchID.charAt(pos);\n\n            // TODO Leading zeroes?\n            if ('0' <= ch && ch <= '9')\n            {\n                periodAllowed = true;\n                continue;\n            }\n\n            if (ch == '.')\n            {\n                if (!periodAllowed)\n                {\n                    return false;\n                }\n\n                periodAllowed = false;\n                continue;\n            }\n\n            return false;\n        }\n\n        return periodAllowed;\n    }\n\n    private static boolean isValidIdentifier(\n        String identifier)\n    {\n        if (identifier.length() < 3 || identifier.charAt(1) != '.')\n        {\n            return false;\n        }\n\n        char first = identifier.charAt(0);\n        if (first < '0' || first > '2')\n        {\n            return false;\n        }\n\n        return isValidBranchID(identifier, 2);\n    }\n\n    private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];\n\n    static ASN1ObjectIdentifier fromOctetString(byte[] enc)\n    {\n        if (enc.length < 3)\n        {\n            return new ASN1ObjectIdentifier(enc);\n        }\n\n        int idx1 = enc[enc.length - 2] & 0xff;\n        // in this case top bit is always zero\n        int idx2 = enc[enc.length - 1] & 0x7f;\n\n        ASN1ObjectIdentifier possibleMatch;\n\n        synchronized (cache)\n        {\n            ASN1ObjectIdentifier[] first = cache[idx1];\n            if (first == null)\n            {\n                first = cache[idx1] = new ASN1ObjectIdentifier[128];\n            }\n\n            possibleMatch = first[idx2];\n            if (possibleMatch == null)\n            {\n                return first[idx2] = new ASN1ObjectIdentifier(enc);\n            }\n\n            if (Arrays.areEqual(enc, possibleMatch.getBody()))\n            {\n                return possibleMatch;\n            }\n\n            idx1 = (idx1 + 1) & 0xff;\n            first = cache[idx1];\n            if (first == null)\n            {\n                first = cache[idx1] = new ASN1ObjectIdentifier[128];\n            }\n\n            possibleMatch = first[idx2];\n            if (possibleMatch == null)\n            {\n                return first[idx2] = new ASN1ObjectIdentifier(enc);\n            }\n\n            if (Arrays.areEqual(enc, possibleMatch.getBody()))\n            {\n                return possibleMatch;\n            }\n\n            idx2 = (idx2 + 1) & 0x7f;\n            possibleMatch = first[idx2];\n            if (possibleMatch == null)\n            {\n                return first[idx2] = new ASN1ObjectIdentifier(enc);\n            }\n        }\n\n        if (Arrays.areEqual(enc, possibleMatch.getBody()))\n        {\n            return possibleMatch;\n        }\n\n        return new ASN1ObjectIdentifier(enc);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DEROctetString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class DEROctetString\n    extends ASN1OctetString\n{\n    /**\n     * @param string the octets making up the octet string.\n     */\n    public DEROctetString(\n        byte[]  string)\n    {\n        super(string);\n    }\n\n    public DEROctetString(\n        ASN1Encodable obj)\n        throws IOException\n    {\n        super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER));\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.OCTET_STRING, string);\n    }\n\n    static void encode(\n        DEROutputStream derOut,\n        byte[]          bytes)\n        throws IOException\n    {\n        derOut.writeEncoded(BERTags.OCTET_STRING, bytes);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DEROctetStringParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\npublic class DEROctetStringParser\n    implements ASN1OctetStringParser\n{\n    private DefiniteLengthInputStream stream;\n\n    DEROctetStringParser(\n        DefiniteLengthInputStream stream)\n    {\n        this.stream = stream;\n    }\n\n    public InputStream getOctetStream()\n    {\n        return stream;\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        return new DEROctetString(stream.toByteArray());\n    }\n    \n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(\"IOException converting stream to byte array: \" + e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DEROutputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Stream that outputs encoding based on distinguished encoding rules.\n */\npublic class DEROutputStream\n    extends ASN1OutputStream\n{\n    public DEROutputStream(\n        OutputStream    os)\n    {\n        super(os);\n    }\n\n    public void writeObject(\n        ASN1Encodable obj)\n        throws IOException\n    {\n        if (obj != null)\n        {\n            obj.toASN1Primitive().toDERObject().encode(this);\n        }\n        else\n        {\n            throw new IOException(\"null object detected\");\n        }\n    }\n\n    ASN1OutputStream getDERSubStream()\n    {\n        return this;\n    }\n\n    ASN1OutputStream getDLSubStream()\n    {\n        return this;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERPrintableString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER PrintableString object.\n */\npublic class DERPrintableString\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[]  string;\n\n    /**\n     * return a printable string from the passed in object.\n     * \n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERPrintableString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERPrintableString)\n        {\n            return (DERPrintableString)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERPrintableString)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a Printable String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERPrintableString getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERPrintableString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - byte encoded string.\n     */\n    DERPrintableString(\n        byte[]   string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor - this does not validate the string\n     */\n    public DERPrintableString(\n        String   string)\n    {\n        this(string, false);\n    }\n\n    /**\n     * Constructor with optional validation.\n     *\n     * @param string the base string to wrap.\n     * @param validate whether or not to check the string.\n     * @throws IllegalArgumentException if validate is true and the string\n     * contains characters that should not be in a PrintableString.\n     */\n    public DERPrintableString(\n        String   string,\n        boolean  validate)\n    {\n        if (validate && !isPrintableString(string))\n        {\n            throw new IllegalArgumentException(\"string contains illegal characters\");\n        }\n\n        this.string = Strings.toByteArray(string);\n    }\n\n    public String getString()\n    {\n        return Strings.fromByteArray(string);\n    }\n\n    public byte[] getOctets()\n    {\n        return Arrays.clone(string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.PRINTABLE_STRING, string);\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERPrintableString))\n        {\n            return false;\n        }\n\n        DERPrintableString  s = (DERPrintableString)o;\n\n        return Arrays.areEqual(string, s.string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    /**\n     * return true if the passed in String can be represented without\n     * loss as a PrintableString, false otherwise.\n     *\n     * @return true if in printable set, false otherwise.\n     */\n    public static boolean isPrintableString(\n        String  str)\n    {\n        for (int i = str.length() - 1; i >= 0; i--)\n        {\n            char    ch = str.charAt(i);\n\n            if (ch > 0x007f)\n            {\n                return false;\n            }\n\n            if ('a' <= ch && ch <= 'z')\n            {\n                continue;\n            }\n\n            if ('A' <= ch && ch <= 'Z')\n            {\n                continue;\n            }\n\n            if ('0' <= ch && ch <= '9')\n            {\n                continue;\n            }\n\n            switch (ch)\n            {\n            case ' ':\n            case '\\'':\n            case '(':\n            case ')':\n            case '+':\n            case '-':\n            case '.':\n            case ':':\n            case '=':\n            case '?':\n            case '/':\n            case ',':\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERSequence.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\npublic class DERSequence\n    extends ASN1Sequence\n{\n    private int bodyLength = -1;\n\n    /**\n     * create an empty sequence\n     */\n    public DERSequence()\n    {\n    }\n\n    /**\n     * create a sequence containing one object\n     */\n    public DERSequence(\n        ASN1Encodable obj)\n    {\n        super(obj);\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    public DERSequence(\n        ASN1EncodableVector v)\n    {\n        super(v);\n    }\n\n    /**\n     * create a sequence containing an array of objects.\n     */\n    public DERSequence(\n        ASN1Encodable[]   array)\n    {\n        super(array);\n    }\n\n    private int getBodyLength()\n        throws IOException\n    {\n        if (bodyLength < 0)\n        {\n            int length = 0;\n\n            for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n            {\n                Object    obj = e.nextElement();\n\n                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();\n            }\n\n            bodyLength = length;\n        }\n\n        return bodyLength;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int length = getBodyLength();\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    /*\n     * A note on the implementation:\n     * <p>\n     * As DER requires the constructed, definite-length model to\n     * be used for structured types, this varies slightly from the\n     * ASN.1 descriptions given. Rather than just outputting SEQUENCE,\n     * we also have to specify CONSTRUCTED, and the objects length.\n     */\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        ASN1OutputStream        dOut = out.getDERSubStream();\n        int                     length = getBodyLength();\n\n        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);\n        out.writeLength(length);\n\n        for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n        {\n            Object    obj = e.nextElement();\n\n            dOut.writeObject((ASN1Encodable)obj);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERSequenceGenerator.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class DERSequenceGenerator\n    extends DERGenerator\n{\n    private final ByteArrayOutputStream _bOut = new ByteArrayOutputStream();\n\n    public DERSequenceGenerator(\n        OutputStream out)\n        throws IOException\n    {\n        super(out);\n    }\n\n    public DERSequenceGenerator(\n        OutputStream out,\n        int          tagNo,\n        boolean      isExplicit)\n        throws IOException\n    {\n        super(out, tagNo, isExplicit);\n    }\n\n    public void addObject(\n        ASN1Encodable object)\n        throws IOException\n    {\n        object.toASN1Primitive().encode(new DEROutputStream(_bOut));\n    }\n    \n    public OutputStream getRawOutputStream()\n    {\n        return _bOut;\n    }\n    \n    public void close() \n        throws IOException\n    {\n        writeDEREncoded(BERTags.CONSTRUCTED | BERTags.SEQUENCE, _bOut.toByteArray());\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERSequenceParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class DERSequenceParser\n    implements ASN1SequenceParser\n{\n    private ASN1StreamParser _parser;\n\n    DERSequenceParser(ASN1StreamParser parser)\n    {\n        this._parser = parser;\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        return _parser.readObject();\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n         return new DERSequence(_parser.readVector());\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(e.getMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERSet.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\n/**\n * A DER encoded set object\n */\npublic class DERSet\n    extends ASN1Set\n{\n    private int bodyLength = -1;\n\n    /**\n     * create an empty set\n     */\n    public DERSet()\n    {\n    }\n\n    /**\n     * @param obj - a single object that makes up the set.\n     */\n    public DERSet(\n        ASN1Encodable obj)\n    {\n        super(obj);\n    }\n\n    /**\n     * @param v - a vector of objects making up the set.\n     */\n    public DERSet(\n        ASN1EncodableVector v)\n    {\n        super(v, true);\n    }\n    \n    /**\n     * create a set from an array of objects.\n     */\n    public DERSet(\n        ASN1Encodable[]   a)\n    {\n        super(a, true);\n    }\n\n    DERSet(\n        ASN1EncodableVector v,\n        boolean                  doSort)\n    {\n        super(v, doSort);\n    }\n\n    private int getBodyLength()\n        throws IOException\n    {\n        if (bodyLength < 0)\n        {\n            int length = 0;\n\n            for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n            {\n                Object    obj = e.nextElement();\n\n                length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();\n            }\n\n            bodyLength = length;\n        }\n\n        return bodyLength;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int length = getBodyLength();\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    /*\n     * A note on the implementation:\n     * <p>\n     * As DER requires the constructed, definite-length model to\n     * be used for structured types, this varies slightly from the\n     * ASN.1 descriptions given. Rather than just outputting SET,\n     * we also have to specify CONSTRUCTED, and the objects length.\n     */\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        ASN1OutputStream        dOut = out.getDERSubStream();\n        int                     length = getBodyLength();\n\n        out.write(BERTags.SET | BERTags.CONSTRUCTED);\n        out.writeLength(length);\n\n        for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n        {\n            Object    obj = e.nextElement();\n\n            dOut.writeObject((ASN1Encodable)obj);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERSetParser.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic class DERSetParser\n    implements ASN1SetParser\n{\n    private ASN1StreamParser _parser;\n\n    DERSetParser(ASN1StreamParser parser)\n    {\n        this._parser = parser;\n    }\n\n    public ASN1Encodable readObject()\n        throws IOException\n    {\n        return _parser.readObject();\n    }\n\n    public ASN1Primitive getLoadedObject()\n        throws IOException\n    {\n        return new DERSet(_parser.readVector(), false);\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        try\n        {\n            return getLoadedObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(e.getMessage(), e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERT61String.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER T61String (also the teletex string), try not to use this if you don't need to. The standard support the encoding for\n * this has been withdrawn.\n */\npublic class DERT61String\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[] string;\n\n    /**\n     * return a T61 string from the passed in object.\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERT61String getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERT61String)\n        {\n            return (DERT61String)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERT61String)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an T61 String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERT61String getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERT61String)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERT61String(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - string encoded as a sequence of bytes.\n     */\n    public DERT61String(\n        byte[]   string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor - with string 8 bit assumed.\n     */\n    public DERT61String(\n        String   string)\n    {\n        this(Strings.toByteArray(string));\n    }\n\n    /**\n     * Decode the encoded string and return it, 8 bit encoding assumed.\n     * @return the decoded String\n     */\n    public String getString()\n    {\n        return Strings.fromByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.T61_STRING, string);\n    }\n\n    /**\n     * Return the encoded string as a byte array.\n     * @return the actual bytes making up the encoded body of the T61 string.\n     */\n    public byte[] getOctets()\n    {\n        return Arrays.clone(string);\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERT61String))\n        {\n            return false;\n        }\n\n        return Arrays.areEqual(string, ((DERT61String)o).string);\n    }\n    \n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERT61UTF8String.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER T61String (also the teletex string) - a \"modern\" encapsulation that uses UTF-8. If at all possible, avoid this one! It's only for emergencies.\n * Use UTF8String instead.\n */\npublic class DERT61UTF8String\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[] string;\n\n    /**\n     * return a T61 string from the passed in object. UTF-8 Encoding is assumed in this case.\n     *\n     * @throws IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERT61UTF8String getInstance(\n        Object obj)\n    {\n        if (obj instanceof DERT61String)\n        {\n            return new DERT61UTF8String(((DERT61String)obj).getOctets());\n        }\n\n        if (obj == null || obj instanceof DERT61UTF8String)\n        {\n            return (DERT61UTF8String)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return new DERT61UTF8String(((DERT61String)fromByteArray((byte[])obj)).getOctets());\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an T61 String from a tagged object. UTF-8 encoding is assumed in this case.\n     *\n     * @param obj      the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *                 tagged false otherwise.\n     * @throws IllegalArgumentException if the tagged object cannot\n     * be converted.\n     */\n    public static DERT61UTF8String getInstance(\n        ASN1TaggedObject obj,\n        boolean explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERT61String || o instanceof DERT61UTF8String)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERT61UTF8String(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - string encoded as a sequence of bytes.\n     */\n    public DERT61UTF8String(\n        byte[] string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor - with string UTF8 conversion assumed.\n     */\n    public DERT61UTF8String(\n        String string)\n    {\n        this(Strings.toUTF8ByteArray(string));\n    }\n\n    /**\n     * Decode the encoded string and return it, UTF8 assumed.\n     *\n     * @return the decoded String\n     */\n    public String getString()\n    {\n        return Strings.fromUTF8ByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.T61_STRING, string);\n    }\n\n    /**\n     * Return the encoded string as a byte array.\n     *\n     * @return the actual bytes making up the encoded body of the T61 string.\n     */\n    public byte[] getOctets()\n    {\n        return Arrays.clone(string);\n    }\n\n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERT61UTF8String))\n        {\n            return false;\n        }\n\n        return Arrays.areEqual(string, ((DERT61UTF8String)o).string);\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERTaggedObject.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\n/**\n * DER TaggedObject - in ASN.1 notation this is any object preceded by\n * a [n] where n is some number - these are assumed to follow the construction\n * rules (as with sequences).\n */\npublic class DERTaggedObject\n    extends ASN1TaggedObject\n{\n    private static final byte[] ZERO_BYTES = new byte[0];\n\n    /**\n     * @param explicit true if an explicitly tagged object.\n     * @param tagNo the tag number for this object.\n     * @param obj the tagged object.\n     */\n    public DERTaggedObject(\n        boolean       explicit,\n        int           tagNo,\n        ASN1Encodable obj)\n    {\n        super(explicit, tagNo, obj);\n    }\n\n    public DERTaggedObject(int tagNo, ASN1Encodable encodable)\n    {\n        super(true, tagNo, encodable);\n    }\n\n    boolean isConstructed()\n    {\n        if (!empty)\n        {\n            if (explicit)\n            {\n                return true;\n            }\n            else\n            {\n                ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();\n\n                return primitive.isConstructed();\n            }\n        }\n        else\n        {\n            return true;\n        }\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        if (!empty)\n        {\n            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();\n            int length = primitive.encodedLength();\n\n            if (explicit)\n            {\n                return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;\n            }\n            else\n            {\n                // header length already in calculation\n                length = length - 1;\n\n                return StreamUtil.calculateTagLength(tagNo) + length;\n            }\n        }\n        else\n        {\n            return StreamUtil.calculateTagLength(tagNo) + 1;\n        }\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        if (!empty)\n        {\n            ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();\n\n            if (explicit)\n            {\n                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);\n                out.writeLength(primitive.encodedLength());\n                out.writeObject(primitive);\n            }\n            else\n            {\n                //\n                // need to mark constructed types...\n                //\n                int flags;\n                if (primitive.isConstructed())\n                {\n                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;\n                }\n                else\n                {\n                    flags = BERTags.TAGGED;\n                }\n\n                out.writeTag(flags, tagNo);\n                out.writeImplicitObject(primitive);\n            }\n        }\n        else\n        {\n            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERTags.java",
    "content": "package local.org.bouncycastle.asn1;\n\n/**\n * @deprecated use BERTags\n */\npublic interface DERTags\n    extends BERTags\n{\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERUTCTime.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.SimpleTimeZone;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * UTC time object.\n */\npublic class DERUTCTime\n    extends ASN1Primitive\n{\n    private byte[]      time;\n\n    /**\n     * return an UTC Time from the passed in object.\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static ASN1UTCTime getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof ASN1UTCTime)\n        {\n            return (ASN1UTCTime)obj;\n        }\n\n        if (obj instanceof DERUTCTime)\n        {\n            return new ASN1UTCTime(((DERUTCTime)obj).time);\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (ASN1UTCTime)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return an UTC Time from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static ASN1UTCTime getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Object o = obj.getObject();\n\n        if (explicit || o instanceof ASN1UTCTime)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new ASN1UTCTime(((ASN1OctetString)o).getOctets());\n        }\n    }\n    \n    /**\n     * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were\n     * never encoded. When you're creating one of these objects from scratch, that's\n     * what you want to use, otherwise we'll try to deal with whatever gets read from\n     * the input stream... (this is why the input format is different from the getTime()\n     * method output).\n     * <p>\n     *\n     * @param time the time string.\n     */\n    public DERUTCTime(\n        String  time)\n    {\n        this.time = Strings.toByteArray(time);\n        try\n        {\n            this.getDate();\n        }\n        catch (ParseException e)\n        {\n            throw new IllegalArgumentException(\"invalid date string: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * base constructer from a java.util.date object\n     */\n    public DERUTCTime(\n        Date time)\n    {\n        SimpleDateFormat dateF = new SimpleDateFormat(\"yyMMddHHmmss'Z'\");\n\n        dateF.setTimeZone(new SimpleTimeZone(0,\"Z\"));\n\n        this.time = Strings.toByteArray(dateF.format(time));\n    }\n\n    DERUTCTime(\n        byte[]  time)\n    {\n        this.time = time;\n    }\n\n    /**\n     * return the time as a date based on whatever a 2 digit year will return. For\n     * standardised processing use getAdjustedDate().\n     *\n     * @return the resulting date\n     * @exception ParseException if the date string cannot be parsed.\n     */\n    public Date getDate()\n        throws ParseException\n    {\n        SimpleDateFormat dateF = new SimpleDateFormat(\"yyMMddHHmmssz\");\n\n        return dateF.parse(getTime());\n    }\n\n    /**\n     * return the time as an adjusted date\n     * in the range of 1950 - 2049.\n     *\n     * @return a date in the range of 1950 to 2049.\n     * @exception ParseException if the date string cannot be parsed.\n     */\n    public Date getAdjustedDate()\n        throws ParseException\n    {\n        SimpleDateFormat dateF = new SimpleDateFormat(\"yyyyMMddHHmmssz\");\n\n        dateF.setTimeZone(new SimpleTimeZone(0, \"Z\"));\n\n        return dateF.parse(getAdjustedTime());\n    }\n\n    /**\n     * return the time - always in the form of \n     *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).\n     * <p>\n     * Normally in a certificate we would expect \"Z\" rather than \"GMT\",\n     * however adding the \"GMT\" means we can just use:\n     * <pre>\n     *     dateF = new SimpleDateFormat(\"yyMMddHHmmssz\");\n     * </pre>\n     * To read in the time and get a date which is compatible with our local\n     * time zone.\n     * <p>\n     * <b>Note:</b> In some cases, due to the local date processing, this\n     * may lead to unexpected results. If you want to stick the normal\n     * convention of 1950 to 2049 use the getAdjustedTime() method.\n     */\n    public String getTime()\n    {\n        String stime = Strings.fromByteArray(time);\n\n        //\n        // standardise the format.\n        //\n        if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)\n        {\n            if (stime.length() == 11)\n            {\n                return stime.substring(0, 10) + \"00GMT+00:00\";\n            }\n            else\n            {\n                return stime.substring(0, 12) + \"GMT+00:00\";\n            }\n        }\n        else\n        {\n            int index = stime.indexOf('-');\n            if (index < 0)\n            {\n                index = stime.indexOf('+');\n            }\n            String d = stime;\n\n            if (index == stime.length() - 3)\n            {\n                d += \"00\";\n            }\n\n            if (index == 10)\n            {\n                return d.substring(0, 10) + \"00GMT\" + d.substring(10, 13) + \":\" + d.substring(13, 15);\n            }\n            else\n            {\n                return d.substring(0, 12) + \"GMT\" + d.substring(12, 15) + \":\" +  d.substring(15, 17);\n            }\n        }\n    }\n\n    /**\n     * return a time string as an adjusted date with a 4 digit year. This goes\n     * in the range of 1950 - 2049.\n     */\n    public String getAdjustedTime()\n    {\n        String   d = this.getTime();\n\n        if (d.charAt(0) < '5')\n        {\n            return \"20\" + d;\n        }\n        else\n        {\n            return \"19\" + d;\n        }\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        int length = time.length;\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    void encode(\n        ASN1OutputStream  out)\n        throws IOException\n    {\n        out.write(BERTags.UTC_TIME);\n\n        int length = time.length;\n\n        out.writeLength(length);\n\n        for (int i = 0; i != length; i++)\n        {\n            out.write((byte)time[i]);\n        }\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERUTCTime))\n        {\n            return false;\n        }\n\n        return Arrays.areEqual(time, ((DERUTCTime)o).time);\n    }\n    \n    public int hashCode()\n    {\n        return Arrays.hashCode(time);\n    }\n\n    public String toString() \n    {\n      return Strings.fromByteArray(time);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERUTF8String.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER UTF8String object.\n */\npublic class DERUTF8String\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[]  string;\n\n    /**\n     * return an UTF8 string from the passed in object.\n     * \n     * @exception IllegalArgumentException\n     *                if the object cannot be converted.\n     */\n    public static DERUTF8String getInstance(Object obj)\n    {\n        if (obj == null || obj instanceof DERUTF8String)\n        {\n            return (DERUTF8String)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERUTF8String)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \"\n                + obj.getClass().getName());\n    }\n\n    /**\n     * return an UTF8 String from a tagged object.\n     * \n     * @param obj\n     *            the tagged object holding the object we want\n     * @param explicit\n     *            true if the object is meant to be explicitly tagged false\n     *            otherwise.\n     * @exception IllegalArgumentException\n     *                if the tagged object cannot be converted.\n     */\n    public static DERUTF8String getInstance(\n        ASN1TaggedObject obj,\n        boolean explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERUTF8String)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERUTF8String(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - byte encoded string.\n     */\n    DERUTF8String(byte[] string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor\n     */\n    public DERUTF8String(String string)\n    {\n        this.string = Strings.toUTF8ByteArray(string);\n    }\n\n    public String getString()\n    {\n        return Strings.fromUTF8ByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n\n    boolean asn1Equals(ASN1Primitive o)\n    {\n        if (!(o instanceof DERUTF8String))\n        {\n            return false;\n        }\n\n        DERUTF8String s = (DERUTF8String)o;\n\n        return Arrays.areEqual(string, s.string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.UTF8_STRING, string);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERUniversalString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\n\n\n/**\n * DER UniversalString object.\n */\npublic class DERUniversalString\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private static final char[]  table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n    private byte[] string;\n    \n    /**\n     * return a Universal String from the passed in object.\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERUniversalString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERUniversalString)\n        {\n            return (DERUniversalString)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERUniversalString)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a Universal String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERUniversalString getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERUniversalString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERUniversalString(((ASN1OctetString)o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - byte encoded string.\n     */\n    public DERUniversalString(\n        byte[]   string)\n    {\n        this.string = string;\n    }\n\n    public String getString()\n    {\n        StringBuffer    buf = new StringBuffer(\"#\");\n        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();\n        ASN1OutputStream            aOut = new ASN1OutputStream(bOut);\n        \n        try\n        {\n            aOut.writeObject(this);\n        }\n        catch (IOException e)\n        {\n           throw new RuntimeException(\"internal error encoding BitString\");\n        }\n        \n        byte[]    string = bOut.toByteArray();\n        \n        for (int i = 0; i != string.length; i++)\n        {\n            buf.append(table[(string[i] >>> 4) & 0xf]);\n            buf.append(table[string[i] & 0xf]);\n        }\n        \n        return buf.toString();\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public byte[] getOctets()\n    {\n        return string;\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets());\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERUniversalString))\n        {\n            return false;\n        }\n\n        return Arrays.areEqual(string, ((DERUniversalString)o).string);\n    }\n    \n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DERVisibleString.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * DER VisibleString object.\n */\npublic class DERVisibleString\n    extends ASN1Primitive\n    implements ASN1String\n{\n    private byte[]  string;\n\n    /**\n     * return a Visible String from the passed in object.\n     *\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static DERVisibleString getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DERVisibleString)\n        {\n            return (DERVisibleString)obj;\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return (DERVisibleString)fromByteArray((byte[])obj);\n            }\n            catch (Exception e)\n            {\n                throw new IllegalArgumentException(\"encoding error in getInstance: \" + e.toString());\n            }\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * return a Visible String from a tagged object.\n     *\n     * @param obj the tagged object holding the object we want\n     * @param explicit true if the object is meant to be explicitly\n     *              tagged false otherwise.\n     * @exception IllegalArgumentException if the tagged object cannot\n     *               be converted.\n     */\n    public static DERVisibleString getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        ASN1Primitive o = obj.getObject();\n\n        if (explicit || o instanceof DERVisibleString)\n        {\n            return getInstance(o);\n        }\n        else\n        {\n            return new DERVisibleString(ASN1OctetString.getInstance(o).getOctets());\n        }\n    }\n\n    /**\n     * basic constructor - byte encoded string.\n     */\n    DERVisibleString(\n        byte[]   string)\n    {\n        this.string = string;\n    }\n\n    /**\n     * basic constructor\n     */\n    public DERVisibleString(\n        String   string)\n    {\n        this.string = Strings.toByteArray(string);\n    }\n\n    public String getString()\n    {\n        return Strings.fromByteArray(string);\n    }\n\n    public String toString()\n    {\n        return getString();\n    }\n\n    public byte[] getOctets()\n    {\n        return Arrays.clone(string);\n    }\n\n    boolean isConstructed()\n    {\n        return false;\n    }\n\n    int encodedLength()\n    {\n        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        out.writeEncoded(BERTags.VISIBLE_STRING, this.string);\n    }\n    \n    boolean asn1Equals(\n        ASN1Primitive o)\n    {\n        if (!(o instanceof DERVisibleString))\n        {\n            return false;\n        }\n\n        return Arrays.areEqual(string, ((DERVisibleString)o).string);\n    }\n    \n    public int hashCode()\n    {\n        return Arrays.hashCode(string);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DLOutputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Stream that outputs encoding based on definite length.\n */\npublic class DLOutputStream\n    extends ASN1OutputStream\n{\n    public DLOutputStream(\n        OutputStream os)\n    {\n        super(os);\n    }\n\n    public void writeObject(\n        ASN1Encodable obj)\n        throws IOException\n    {\n        if (obj != null)\n        {\n            obj.toASN1Primitive().toDLObject().encode(this);\n        }\n        else\n        {\n            throw new IOException(\"null object detected\");\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DLSequence.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\npublic class DLSequence\n    extends ASN1Sequence\n{\n    private int bodyLength = -1;\n\n    /**\n     * create an empty sequence\n     */\n    public DLSequence()\n    {\n    }\n\n    /**\n     * create a sequence containing one object\n     */\n    public DLSequence(\n        ASN1Encodable obj)\n    {\n        super(obj);\n    }\n\n    /**\n     * create a sequence containing a vector of objects.\n     */\n    public DLSequence(\n        ASN1EncodableVector v)\n    {\n        super(v);\n    }\n\n    /**\n     * create a sequence containing an array of objects.\n     */\n    public DLSequence(\n        ASN1Encodable[] array)\n    {\n        super(array);\n    }\n\n    private int getBodyLength()\n        throws IOException\n    {\n        if (bodyLength < 0)\n        {\n            int length = 0;\n\n            for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n            {\n                Object    obj = e.nextElement();\n\n                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();\n            }\n\n            bodyLength = length;\n        }\n\n        return bodyLength;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int    length = getBodyLength();\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    /*\n     * A note on the implementation:\n     * <p>\n     * As DL requires the constructed, definite-length model to\n     * be used for structured types, this varies slightly from the\n     * ASN.1 descriptions given. Rather than just outputting SEQUENCE,\n     * we also have to specify CONSTRUCTED, and the objects length.\n     */\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        ASN1OutputStream       dOut = out.getDLSubStream();\n        int                    length = getBodyLength();\n\n        out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);\n        out.writeLength(length);\n\n        for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n        {\n            Object    obj = e.nextElement();\n\n            dOut.writeObject((ASN1Encodable)obj);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DLSet.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\n/**\n * A DER encoded set object\n */\npublic class DLSet\n    extends ASN1Set\n{\n    private int bodyLength = -1;\n\n    /**\n     * create an empty set\n     */\n    public DLSet()\n    {\n    }\n\n    /**\n     * @param obj - a single object that makes up the set.\n     */\n    public DLSet(\n        ASN1Encodable obj)\n    {\n        super(obj);\n    }\n\n    /**\n     * @param v - a vector of objects making up the set.\n     */\n    public DLSet(\n        ASN1EncodableVector v)\n    {\n        super(v, false);\n    }\n\n    /**\n     * create a set from an array of objects.\n     */\n    public DLSet(\n        ASN1Encodable[] a)\n    {\n        super(a, false);\n    }\n\n    private int getBodyLength()\n        throws IOException\n    {\n        if (bodyLength < 0)\n        {\n            int length = 0;\n\n            for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n            {\n                Object    obj = e.nextElement();\n\n                length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();\n            }\n\n            bodyLength = length;\n        }\n\n        return bodyLength;\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        int                     length = getBodyLength();\n\n        return 1 + StreamUtil.calculateBodyLength(length) + length;\n    }\n\n    /*\n     * A note on the implementation:\n     * <p>\n     * As DL requires the constructed, definite-length model to\n     * be used for structured types, this varies slightly from the\n     * ASN.1 descriptions given. Rather than just outputting SET,\n     * we also have to specify CONSTRUCTED, and the objects length.\n     */\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        ASN1OutputStream        dOut = out.getDLSubStream();\n        int                     length = getBodyLength();\n\n        out.write(BERTags.SET | BERTags.CONSTRUCTED);\n        out.writeLength(length);\n\n        for (Enumeration e = this.getObjects(); e.hasMoreElements();)\n        {\n            Object    obj = e.nextElement();\n\n            dOut.writeObject((ASN1Encodable)obj);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DLTaggedObject.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\n/**\n * Definite Length TaggedObject - in ASN.1 notation this is any object preceded by\n * a [n] where n is some number - these are assumed to follow the construction\n * rules (as with sequences).\n */\npublic class DLTaggedObject\n    extends ASN1TaggedObject\n{\n    private static final byte[] ZERO_BYTES = new byte[0];\n\n    /**\n     * @param explicit true if an explicitly tagged object.\n     * @param tagNo the tag number for this object.\n     * @param obj the tagged object.\n     */\n    public DLTaggedObject(\n        boolean explicit,\n        int tagNo,\n        ASN1Encodable obj)\n    {\n        super(explicit, tagNo, obj);\n    }\n\n    boolean isConstructed()\n    {\n        if (!empty)\n        {\n            if (explicit)\n            {\n                return true;\n            }\n            else\n            {\n                ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();\n\n                return primitive.isConstructed();\n            }\n        }\n        else\n        {\n            return true;\n        }\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        if (!empty)\n        {\n            int length = obj.toASN1Primitive().toDLObject().encodedLength();\n\n            if (explicit)\n            {\n                return  StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;\n            }\n            else\n            {\n                // header length already in calculation\n                length = length - 1;\n\n                return StreamUtil.calculateTagLength(tagNo) + length;\n            }\n        }\n        else\n        {\n            return StreamUtil.calculateTagLength(tagNo) + 1;\n        }\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        if (!empty)\n        {\n            ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();\n\n            if (explicit)\n            {\n                out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);\n                out.writeLength(primitive.encodedLength());\n                out.writeObject(primitive);\n            }\n            else\n            {\n                //\n                // need to mark constructed types...\n                //\n                int flags;\n                if (primitive.isConstructed())\n                {\n                    flags = BERTags.CONSTRUCTED | BERTags.TAGGED;\n                }\n                else\n                {\n                    flags = BERTags.TAGGED;\n                }\n\n                out.writeTag(flags, tagNo);\n                out.writeImplicitObject(primitive);\n            }\n        }\n        else\n        {\n            out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/DefiniteLengthInputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport local.org.bouncycastle.util.io.Streams;\n\n\nclass DefiniteLengthInputStream\n        extends LimitedInputStream\n{\n    private static final byte[] EMPTY_BYTES = new byte[0];\n\n    private final int _originalLength;\n    private int _remaining;\n\n    DefiniteLengthInputStream(\n        InputStream in,\n        int         length)\n    {\n        super(in, length);\n\n        if (length < 0)\n        {\n            throw new IllegalArgumentException(\"negative lengths not allowed\");\n        }\n\n        this._originalLength = length;\n        this._remaining = length;\n\n        if (length == 0)\n        {\n            setParentEofDetect(true);\n        }\n    }\n\n    int getRemaining()\n    {\n        return _remaining;\n    }\n\n    public int read()\n        throws IOException\n    {\n        if (_remaining == 0)\n        {\n            return -1;\n        }\n\n        int b = _in.read();\n\n        if (b < 0)\n        {\n            throw new EOFException(\"DEF length \" + _originalLength + \" object truncated by \" + _remaining);\n        }\n\n        if (--_remaining == 0)\n        {\n            setParentEofDetect(true);\n        }\n\n        return b;\n    }\n\n    public int read(byte[] buf, int off, int len)\n        throws IOException\n    {\n        if (_remaining == 0)\n        {\n            return -1;\n        }\n\n        int toRead = Math.min(len, _remaining);\n        int numRead = _in.read(buf, off, toRead);\n\n        if (numRead < 0)\n        {\n            throw new EOFException(\"DEF length \" + _originalLength + \" object truncated by \" + _remaining);\n        }\n\n        if ((_remaining -= numRead) == 0)\n        {\n            setParentEofDetect(true);\n        }\n\n        return numRead;\n    }\n\n    byte[] toByteArray()\n        throws IOException\n    {\n        if (_remaining == 0)\n        {\n            return EMPTY_BYTES;\n        }\n\n        byte[] bytes = new byte[_remaining];\n        if ((_remaining -= Streams.readFully(_in, bytes)) != 0)\n        {\n            throw new EOFException(\"DEF length \" + _originalLength + \" object truncated by \" + _remaining);\n        }\n        setParentEofDetect(true);\n        return bytes;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/InMemoryRepresentable.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\n\npublic interface InMemoryRepresentable\n{\n    ASN1Primitive getLoadedObject()\n        throws IOException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/IndefiniteLengthInputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nclass IndefiniteLengthInputStream\n    extends LimitedInputStream\n{\n    private int _b1;\n    private int _b2;\n    private boolean _eofReached = false;\n    private boolean _eofOn00 = true;\n\n    IndefiniteLengthInputStream(\n        InputStream in,\n        int         limit)\n        throws IOException\n    {\n        super(in, limit);\n\n        _b1 = in.read();\n        _b2 = in.read();\n\n        if (_b2 < 0)\n        {\n            // Corrupted stream\n            throw new EOFException();\n        }\n\n        checkForEof();\n    }\n\n    void setEofOn00(\n        boolean eofOn00)\n    {\n        _eofOn00 = eofOn00;\n        checkForEof();\n    }\n\n    private boolean checkForEof()\n    {\n        if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00))\n        {\n            _eofReached = true;\n            setParentEofDetect(true);\n        }\n        return _eofReached;\n    }\n\n    public int read(byte[] b, int off, int len)\n        throws IOException\n    {\n        // Only use this optimisation if we aren't checking for 00\n        if (_eofOn00 || len < 3)\n        {\n            return super.read(b, off, len);\n        }\n\n        if (_eofReached)\n        {\n            return -1;\n        }\n\n        int numRead = _in.read(b, off + 2, len - 2);\n\n        if (numRead < 0)\n        {\n            // Corrupted stream\n            throw new EOFException();\n        }\n\n        b[off] = (byte)_b1;\n        b[off + 1] = (byte)_b2;\n\n        _b1 = _in.read();\n        _b2 = _in.read();\n\n        if (_b2 < 0)\n        {\n            // Corrupted stream\n            throw new EOFException();\n        }\n\n        return numRead + 2;\n    }\n\n    public int read()\n        throws IOException\n    {\n        if (checkForEof())\n        {\n            return -1;\n        }\n\n        int b = _in.read();\n\n        if (b < 0)\n        {\n            // Corrupted stream\n            throw new EOFException();\n        }\n\n        int v = _b1;\n\n        _b1 = _b2;\n        _b2 = b;\n\n        return v;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/LazyConstructionEnumeration.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\nclass LazyConstructionEnumeration\n    implements Enumeration\n{\n    private ASN1InputStream aIn;\n    private Object          nextObj;\n\n    public LazyConstructionEnumeration(byte[] encoded)\n    {\n        aIn = new ASN1InputStream(encoded, true);\n        nextObj = readObject();\n    }\n\n    public boolean hasMoreElements()\n    {\n        return nextObj != null;\n    }\n\n    public Object nextElement()\n    {\n        Object o = nextObj;\n\n        nextObj = readObject();\n\n        return o;\n    }\n\n    private Object readObject()\n    {\n        try\n        {\n            return aIn.readObject();\n        }\n        catch (IOException e)\n        {\n            throw new ASN1ParsingException(\"malformed DER construction: \" + e, e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/LazyEncodedSequence.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\n/**\n * Note: this class is for processing DER/DL encoded sequences only.\n */\nclass LazyEncodedSequence\n    extends ASN1Sequence\n{\n    private byte[] encoded;\n\n    LazyEncodedSequence(\n        byte[] encoded)\n        throws IOException\n    {\n        this.encoded = encoded;\n    }\n\n    private void parse()\n    {\n        Enumeration en = new LazyConstructionEnumeration(encoded);\n\n        while (en.hasMoreElements())\n        {\n            seq.addElement(en.nextElement());\n        }\n\n        encoded = null;\n    }\n\n    public synchronized ASN1Encodable getObjectAt(int index)\n    {\n        if (encoded != null)\n        {\n            parse();\n        }\n\n        return super.getObjectAt(index);\n    }\n\n    public synchronized Enumeration getObjects()\n    {\n        if (encoded == null)\n        {\n            return super.getObjects();\n        }\n\n        return new LazyConstructionEnumeration(encoded);\n    }\n\n    public synchronized int size()\n    {\n        if (encoded != null)\n        {\n            parse();\n        }\n\n        return super.size();\n    }\n\n    ASN1Primitive toDERObject()\n    {\n        if (encoded != null)\n        {\n            parse();\n        }\n\n        return super.toDERObject();\n    }\n\n    ASN1Primitive toDLObject()\n    {\n        if (encoded != null)\n        {\n            parse();\n        }\n\n        return super.toDLObject();\n    }\n\n    int encodedLength()\n        throws IOException\n    {\n        if (encoded != null)\n        {\n            return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length;\n        }\n        else\n        {\n            return super.toDLObject().encodedLength();\n        }\n    }\n\n    void encode(\n        ASN1OutputStream out)\n        throws IOException\n    {\n        if (encoded != null)\n        {\n            out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded);\n        }\n        else\n        {\n            super.toDLObject().encode(out);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/LimitedInputStream.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.InputStream;\n\nabstract class LimitedInputStream\n        extends InputStream\n{\n    protected final InputStream _in;\n    private int _limit;\n\n    LimitedInputStream(\n        InputStream in,\n        int         limit)\n    {\n        this._in = in;\n        this._limit = limit;\n    }\n\n    int getRemaining()\n    {\n        // TODO: maybe one day this can become more accurate\n        return _limit;\n    }\n    \n    protected void setParentEofDetect(boolean on)\n    {\n        if (_in instanceof IndefiniteLengthInputStream)\n        {\n            ((IndefiniteLengthInputStream)_in).setEofOn00(on);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/OIDTokenizer.java",
    "content": "package local.org.bouncycastle.asn1;\n\n/**\n * class for breaking up an OID into it's component tokens, ala\n * java.util.StringTokenizer. We need this class as some of the\n * lightweight Java environment don't support classes like\n * StringTokenizer.\n */\npublic class OIDTokenizer\n{\n    private String  oid;\n    private int     index;\n\n    public OIDTokenizer(\n        String oid)\n    {\n        this.oid = oid;\n        this.index = 0;\n    }\n\n    public boolean hasMoreTokens()\n    {\n        return (index != -1);\n    }\n\n    public String nextToken()\n    {\n        if (index == -1)\n        {\n            return null;\n        }\n\n        String  token;\n        int     end = oid.indexOf('.', index);\n\n        if (end == -1)\n        {\n            token = oid.substring(index);\n            index = -1;\n            return token;\n        }\n\n        token = oid.substring(index, end);\n\n        index = end + 1;\n        return token;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/StreamUtil.java",
    "content": "package local.org.bouncycastle.asn1;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.channels.FileChannel;\n\nclass StreamUtil\n{\n    private static final long  MAX_MEMORY = Runtime.getRuntime().maxMemory();\n\n    /**\n     * Find out possible longest length...\n     *\n     * @param in input stream of interest\n     * @return length calculation or MAX_VALUE.\n     */\n    static int findLimit(InputStream in)\n    {\n        if (in instanceof LimitedInputStream)\n        {\n            return ((LimitedInputStream)in).getRemaining();\n        }\n        else if (in instanceof ASN1InputStream)\n        {\n            return ((ASN1InputStream)in).getLimit();\n        }\n        else if (in instanceof ByteArrayInputStream)\n        {\n            return ((ByteArrayInputStream)in).available();\n        }\n        else if (in instanceof FileInputStream)\n        {\n            try\n            {\n                FileChannel channel = ((FileInputStream)in).getChannel();\n                long  size = (channel != null) ? channel.size() : Integer.MAX_VALUE;\n\n                if (size < Integer.MAX_VALUE)\n                {\n                    return (int)size;\n                }\n            }\n            catch (IOException e)\n            {\n                // ignore - they'll find out soon enough!\n            }\n        }\n\n        if (MAX_MEMORY > Integer.MAX_VALUE)\n        {\n            return Integer.MAX_VALUE;\n        }\n\n        return (int)MAX_MEMORY;\n    }\n\n    static int calculateBodyLength(\n        int length)\n    {\n        int count = 1;\n\n        if (length > 127)\n        {\n            int size = 1;\n            int val = length;\n\n            while ((val >>>= 8) != 0)\n            {\n                size++;\n            }\n\n            for (int i = (size - 1) * 8; i >= 0; i -= 8)\n            {\n                count++;\n            }\n        }\n\n        return count;\n    }\n\n    static int calculateTagLength(int tagNo)\n        throws IOException\n    {\n        int length = 1;\n\n        if (tagNo >= 31)\n        {\n            if (tagNo < 128)\n            {\n                length++;\n            }\n            else\n            {\n                byte[] stack = new byte[5];\n                int pos = stack.length;\n\n                stack[--pos] = (byte)(tagNo & 0x7F);\n\n                do\n                {\n                    tagNo >>= 7;\n                    stack[--pos] = (byte)(tagNo & 0x7F | 0x80);\n                }\n                while (tagNo > 127);\n\n                length += stack.length - pos;\n            }\n        }\n\n        return length;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/cryptopro/CryptoProObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.cryptopro;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface CryptoProObjectIdentifiers\n{\n    // GOST Algorithms OBJECT IDENTIFIERS :\n    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)}\n    static final ASN1ObjectIdentifier    GOST_id              = new ASN1ObjectIdentifier(\"1.2.643.2.2\");\n\n    static final ASN1ObjectIdentifier    gostR3411          = GOST_id.branch(\"9\");\n    static final ASN1ObjectIdentifier    gostR3411Hmac      = GOST_id.branch(\"10\");\n\n    static final ASN1ObjectIdentifier    gostR28147_cbc     = new ASN1ObjectIdentifier(GOST_id+\".21\");\n\n    static final ASN1ObjectIdentifier    id_Gost28147_89_CryptoPro_A_ParamSet = GOST_id.branch(\"31.1\");\n\n    static final ASN1ObjectIdentifier    gostR3410_94       = new ASN1ObjectIdentifier(GOST_id+\".20\");\n    static final ASN1ObjectIdentifier    gostR3410_2001     = new ASN1ObjectIdentifier(GOST_id+\".19\");\n    static final ASN1ObjectIdentifier    gostR3411_94_with_gostR3410_94   = new ASN1ObjectIdentifier(GOST_id+\".4\");\n    static final ASN1ObjectIdentifier    gostR3411_94_with_gostR3410_2001 = new ASN1ObjectIdentifier(GOST_id+\".3\");\n\n    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) }\n    static final ASN1ObjectIdentifier    gostR3411_94_CryptoProParamSet = new ASN1ObjectIdentifier(GOST_id+\".30.1\");\n\n    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) }\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_A     = new ASN1ObjectIdentifier(GOST_id+\".32.2\");\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_B     = new ASN1ObjectIdentifier(GOST_id+\".32.3\");\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_C     = new ASN1ObjectIdentifier(GOST_id+\".32.4\");\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_D     = new ASN1ObjectIdentifier(GOST_id+\".32.5\");\n\n    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) }\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_XchA  = new ASN1ObjectIdentifier(GOST_id+\".33.1\");\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_XchB  = new ASN1ObjectIdentifier(GOST_id+\".33.2\");\n    static final ASN1ObjectIdentifier    gostR3410_94_CryptoPro_XchC  = new ASN1ObjectIdentifier(GOST_id+\".33.3\");\n\n    //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) }\n    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_A = new ASN1ObjectIdentifier(GOST_id+\".35.1\");\n    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_B = new ASN1ObjectIdentifier(GOST_id+\".35.2\");\n    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_C = new ASN1ObjectIdentifier(GOST_id+\".35.3\");\n\n    // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) }\n    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_XchA  = new ASN1ObjectIdentifier(GOST_id+\".36.0\");\n    static final ASN1ObjectIdentifier    gostR3410_2001_CryptoPro_XchB  = new ASN1ObjectIdentifier(GOST_id+\".36.1\");\n    \n    static final ASN1ObjectIdentifier    gost_ElSgDH3410_default    = new ASN1ObjectIdentifier(GOST_id+\".36.0\");\n    static final ASN1ObjectIdentifier    gost_ElSgDH3410_1          = new ASN1ObjectIdentifier(GOST_id+\".36.1\");\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java",
    "content": "package local.org.bouncycastle.asn1.cryptopro;\n\nimport java.math.BigInteger;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.crypto.params.ECDomainParameters;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.math.ec.ECFieldElement;\nimport local.org.bouncycastle.math.ec.ECPoint;\n\n\n/**\n * table of the available named parameters for GOST 3410-2001.\n */\npublic class ECGOST3410NamedCurves\n{\n    static final Hashtable objIds = new Hashtable();\n    static final Hashtable params = new Hashtable();\n    static final Hashtable names = new Hashtable();\n\n    static\n    {\n        BigInteger mod_p = new BigInteger(\"115792089237316195423570985008687907853269984665640564039457584007913129639319\");\n        BigInteger mod_q = new BigInteger(\"115792089237316195423570985008687907853073762908499243225378155805079068850323\");\n        \n        ECCurve.Fp curve = new ECCurve.Fp(\n            mod_p, // p\n            new BigInteger(\"115792089237316195423570985008687907853269984665640564039457584007913129639316\"), // a\n            new BigInteger(\"166\")); // b\n\n        ECDomainParameters ecParams = new ECDomainParameters(\n            curve,\n            new ECPoint.Fp(curve,\n                    new ECFieldElement.Fp(curve.getQ(),new BigInteger(\"1\")), // x\n                    new ECFieldElement.Fp(curve.getQ(),new BigInteger(\"64033881142927202683649881450433473985931760268884941288852745803908878638612\"))), // y\n            mod_q);\n        \n        params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, ecParams);  \n        \n        mod_p = new BigInteger(\"115792089237316195423570985008687907853269984665640564039457584007913129639319\");\n        mod_q = new BigInteger(\"115792089237316195423570985008687907853073762908499243225378155805079068850323\");\n        \n        curve = new ECCurve.Fp(\n                mod_p, // p\n                new BigInteger(\"115792089237316195423570985008687907853269984665640564039457584007913129639316\"),\n                new BigInteger(\"166\"));\n\n        ecParams = new ECDomainParameters(\n                curve,\n                new ECPoint.Fp(curve,\n                        new ECFieldElement.Fp(curve.getQ(),new BigInteger(\"1\")), // x\n                        new ECFieldElement.Fp(curve.getQ(),new BigInteger(\"64033881142927202683649881450433473985931760268884941288852745803908878638612\"))), // y\n                mod_q);\n\n        params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, ecParams); \n        \n        mod_p = new BigInteger(\"57896044618658097711785492504343953926634992332820282019728792003956564823193\"); //p\n        mod_q = new BigInteger(\"57896044618658097711785492504343953927102133160255826820068844496087732066703\"); //q\n        \n        curve = new ECCurve.Fp(\n            mod_p, // p\n            new BigInteger(\"57896044618658097711785492504343953926634992332820282019728792003956564823190\"), // a\n            new BigInteger(\"28091019353058090096996979000309560759124368558014865957655842872397301267595\")); // b\n\n        ecParams = new ECDomainParameters(\n            curve,\n            new ECPoint.Fp(curve,\n                           new ECFieldElement.Fp(mod_p,new BigInteger(\"1\")), // x\n                           new ECFieldElement.Fp(mod_p,new BigInteger(\"28792665814854611296992347458380284135028636778229113005756334730996303888124\"))), // y\n            mod_q); // q\n\n        params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, ecParams);  \n        \n        mod_p = new BigInteger(\"70390085352083305199547718019018437841079516630045180471284346843705633502619\");\n        mod_q = new BigInteger(\"70390085352083305199547718019018437840920882647164081035322601458352298396601\");\n        \n        curve = new ECCurve.Fp(\n                mod_p, // p\n                new BigInteger(\"70390085352083305199547718019018437841079516630045180471284346843705633502616\"),\n                new BigInteger(\"32858\"));\n\n        ecParams = new ECDomainParameters(\n                curve,\n                new ECPoint.Fp(curve,\n                               new ECFieldElement.Fp(mod_p,new BigInteger(\"0\")),\n                               new ECFieldElement.Fp(mod_p,new BigInteger(\"29818893917731240733471273240314769927240550812383695689146495261604565990247\"))),\n            mod_q);\n        \n        params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, ecParams);  \n                                \n        mod_p = new BigInteger(\"70390085352083305199547718019018437841079516630045180471284346843705633502619\"); //p\n        mod_q = new BigInteger(\"70390085352083305199547718019018437840920882647164081035322601458352298396601\"); //q\n        curve = new ECCurve.Fp(\n            mod_p, // p\n            new BigInteger(\"70390085352083305199547718019018437841079516630045180471284346843705633502616\"), // a\n            new BigInteger(\"32858\")); // b\n\n        ecParams = new ECDomainParameters(\n            curve,\n            new ECPoint.Fp(curve,\n                           new ECFieldElement.Fp(mod_p,new BigInteger(\"0\")), // x\n                           new ECFieldElement.Fp(mod_p,new BigInteger(\"29818893917731240733471273240314769927240550812383695689146495261604565990247\"))), // y\n            mod_q); // q\n\n        params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, ecParams); \n            \n        objIds.put(\"GostR3410-2001-CryptoPro-A\", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A);\n        objIds.put(\"GostR3410-2001-CryptoPro-B\", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B);\n        objIds.put(\"GostR3410-2001-CryptoPro-C\", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C);\n        objIds.put(\"GostR3410-2001-CryptoPro-XchA\", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA);\n        objIds.put(\"GostR3410-2001-CryptoPro-XchB\", CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB);\n        \n        names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, \"GostR3410-2001-CryptoPro-A\");\n        names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, \"GostR3410-2001-CryptoPro-B\");\n        names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, \"GostR3410-2001-CryptoPro-C\");\n        names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, \"GostR3410-2001-CryptoPro-XchA\");\n        names.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, \"GostR3410-2001-CryptoPro-XchB\");\n    }\n\n    /**\n     * return the ECDomainParameters object for the given OID, null if it \n     * isn't present.\n     *\n     * @param oid an object identifier representing a named parameters, if present.\n     */\n    public static ECDomainParameters getByOID(\n        ASN1ObjectIdentifier  oid)\n    {\n        return (ECDomainParameters)params.get(oid);\n    }\n\n    /**\n     * returns an enumeration containing the name strings for parameters\n     * contained in this structure.\n     */\n    public static Enumeration getNames()\n    {\n        return objIds.keys();\n    }\n\n    public static ECDomainParameters getByName(\n        String  name)\n    {\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(name);\n\n        if (oid != null)\n        {\n            return (ECDomainParameters)params.get(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * return the named curve name represented by the given object identifier.\n     */\n    public static String getName(\n        ASN1ObjectIdentifier  oid)\n    {\n        return (String)names.get(oid);\n    }\n    \n    public static ASN1ObjectIdentifier getOID(String name)\n    {\n        return (ASN1ObjectIdentifier)objIds.get(name);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.kisa;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface KISAObjectIdentifiers\n{\n    public static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier(\"1.2.410.200004.1.4\");\n    public static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier(\"1.2.410.200004.7.1.1.1\");\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/nist/NISTNamedCurves.java",
    "content": "package local.org.bouncycastle.asn1.nist;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.sec.SECNamedCurves;\nimport local.org.bouncycastle.asn1.sec.SECObjectIdentifiers;\nimport local.org.bouncycastle.asn1.x9.X9ECParameters;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-3\n */\npublic class NISTNamedCurves\n{\n    static final Hashtable objIds = new Hashtable();\n    static final Hashtable names = new Hashtable();\n\n    static void defineCurve(String name, ASN1ObjectIdentifier oid)\n    {\n        objIds.put(name, oid);\n        names.put(oid, name);\n    }\n\n    static\n    {\n        defineCurve(\"B-571\", SECObjectIdentifiers.sect571r1);\n        defineCurve(\"B-409\", SECObjectIdentifiers.sect409r1);\n        defineCurve(\"B-283\", SECObjectIdentifiers.sect283r1);\n        defineCurve(\"B-233\", SECObjectIdentifiers.sect233r1);\n        defineCurve(\"B-163\", SECObjectIdentifiers.sect163r2);\n        defineCurve(\"K-571\", SECObjectIdentifiers.sect571k1);\n        defineCurve(\"K-409\", SECObjectIdentifiers.sect409k1);\n        defineCurve(\"K-283\", SECObjectIdentifiers.sect283k1);\n        defineCurve(\"K-233\", SECObjectIdentifiers.sect233k1);\n        defineCurve(\"K-163\", SECObjectIdentifiers.sect163k1);\n        defineCurve(\"P-521\", SECObjectIdentifiers.secp521r1);\n        defineCurve(\"P-384\", SECObjectIdentifiers.secp384r1);\n        defineCurve(\"P-256\", SECObjectIdentifiers.secp256r1);\n        defineCurve(\"P-224\", SECObjectIdentifiers.secp224r1);\n        defineCurve(\"P-192\", SECObjectIdentifiers.secp192r1);\n    }\n\n    public static X9ECParameters getByName(\n        String  name)\n    {\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));\n\n        if (oid != null)\n        {\n            return getByOID(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * return the X9ECParameters object for the named curve represented by\n     * the passed in object identifier. Null if the curve isn't present.\n     *\n     * @param oid an object identifier representing a named curve, if present.\n     */\n    public static X9ECParameters getByOID(\n        ASN1ObjectIdentifier  oid)\n    {\n        return SECNamedCurves.getByOID(oid);\n    }\n\n    /**\n     * return the object identifier signified by the passed in name. Null\n     * if there is no object identifier associated with name.\n     *\n     * @return the object identifier associated with name, if present.\n     */\n    public static ASN1ObjectIdentifier getOID(\n        String  name)\n    {\n        return (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));\n    }\n\n    /**\n     * return the named curve name represented by the given object identifier.\n     */\n    public static String getName(\n        ASN1ObjectIdentifier  oid)\n    {\n        return (String)names.get(oid);\n    }\n\n    /**\n     * returns an enumeration containing the name strings for curves\n     * contained in this structure.\n     */\n    public static Enumeration getNames()\n    {\n        return objIds.keys();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.nist;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface NISTObjectIdentifiers\n{\n    //\n    // NIST\n    //     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3) \n\n    //\n    // nistalgorithms(4)\n    //\n    static final ASN1ObjectIdentifier    nistAlgorithm           = new ASN1ObjectIdentifier(\"2.16.840.1.101.3.4\");\n\n    static final ASN1ObjectIdentifier    hashAlgs                = nistAlgorithm.branch(\"2\");\n\n    static final ASN1ObjectIdentifier    id_sha256               = hashAlgs.branch(\"1\");\n    static final ASN1ObjectIdentifier    id_sha384               = hashAlgs.branch(\"2\");\n    static final ASN1ObjectIdentifier    id_sha512               = hashAlgs.branch(\"3\");\n    static final ASN1ObjectIdentifier    id_sha224               = hashAlgs.branch(\"4\");\n    static final ASN1ObjectIdentifier    id_sha512_224           = hashAlgs.branch(\"5\");\n    static final ASN1ObjectIdentifier    id_sha512_256           = hashAlgs.branch(\"6\");\n\n    static final ASN1ObjectIdentifier    aes                     =  nistAlgorithm.branch(\"1\");\n    \n    static final ASN1ObjectIdentifier    id_aes128_ECB           = aes.branch(\"1\"); \n    static final ASN1ObjectIdentifier    id_aes128_CBC           = aes.branch(\"2\");\n    static final ASN1ObjectIdentifier    id_aes128_OFB           = aes.branch(\"3\"); \n    static final ASN1ObjectIdentifier    id_aes128_CFB           = aes.branch(\"4\"); \n    static final ASN1ObjectIdentifier    id_aes128_wrap          = aes.branch(\"5\");\n    static final ASN1ObjectIdentifier    id_aes128_GCM           = aes.branch(\"6\");\n    static final ASN1ObjectIdentifier    id_aes128_CCM           = aes.branch(\"7\");\n    \n    static final ASN1ObjectIdentifier    id_aes192_ECB           = aes.branch(\"21\"); \n    static final ASN1ObjectIdentifier    id_aes192_CBC           = aes.branch(\"22\"); \n    static final ASN1ObjectIdentifier    id_aes192_OFB           = aes.branch(\"23\"); \n    static final ASN1ObjectIdentifier    id_aes192_CFB           = aes.branch(\"24\"); \n    static final ASN1ObjectIdentifier    id_aes192_wrap          = aes.branch(\"25\");\n    static final ASN1ObjectIdentifier    id_aes192_GCM           = aes.branch(\"26\");\n    static final ASN1ObjectIdentifier    id_aes192_CCM           = aes.branch(\"27\");\n    \n    static final ASN1ObjectIdentifier    id_aes256_ECB           = aes.branch(\"41\"); \n    static final ASN1ObjectIdentifier    id_aes256_CBC           = aes.branch(\"42\");\n    static final ASN1ObjectIdentifier    id_aes256_OFB           = aes.branch(\"43\"); \n    static final ASN1ObjectIdentifier    id_aes256_CFB           = aes.branch(\"44\"); \n    static final ASN1ObjectIdentifier    id_aes256_wrap          = aes.branch(\"45\"); \n    static final ASN1ObjectIdentifier    id_aes256_GCM           = aes.branch(\"46\");\n    static final ASN1ObjectIdentifier    id_aes256_CCM           = aes.branch(\"47\");\n\n    //\n    // signatures\n    //\n    static final ASN1ObjectIdentifier    id_dsa_with_sha2        = nistAlgorithm.branch(\"3\");\n\n    static final ASN1ObjectIdentifier    dsa_with_sha224         = id_dsa_with_sha2.branch(\"1\");\n    static final ASN1ObjectIdentifier    dsa_with_sha256         = id_dsa_with_sha2.branch(\"2\");\n    static final ASN1ObjectIdentifier    dsa_with_sha384         = id_dsa_with_sha2.branch(\"3\");\n    static final ASN1ObjectIdentifier    dsa_with_sha512         = id_dsa_with_sha2.branch(\"4\");\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.ntt;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\n/**\n * From RFC 3657\n */\npublic interface NTTObjectIdentifiers\n{\n    public static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier(\"1.2.392.200011.61.1.1.1.2\");\n    public static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier(\"1.2.392.200011.61.1.1.1.3\");\n    public static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier(\"1.2.392.200011.61.1.1.1.4\");\n\n    public static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier(\"1.2.392.200011.61.1.1.3.2\");\n    public static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier(\"1.2.392.200011.61.1.1.3.3\");\n    public static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier(\"1.2.392.200011.61.1.1.3.4\");\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.oiw;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface OIWObjectIdentifiers\n{\n    // id-SHA1 OBJECT IDENTIFIER ::=    \n    //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //\n    static final ASN1ObjectIdentifier    md4WithRSA              = new ASN1ObjectIdentifier(\"1.3.14.3.2.2\");\n    static final ASN1ObjectIdentifier    md5WithRSA              = new ASN1ObjectIdentifier(\"1.3.14.3.2.3\");\n    static final ASN1ObjectIdentifier    md4WithRSAEncryption    = new ASN1ObjectIdentifier(\"1.3.14.3.2.4\");\n    \n    static final ASN1ObjectIdentifier    desECB                  = new ASN1ObjectIdentifier(\"1.3.14.3.2.6\");\n    static final ASN1ObjectIdentifier    desCBC                  = new ASN1ObjectIdentifier(\"1.3.14.3.2.7\");\n    static final ASN1ObjectIdentifier    desOFB                  = new ASN1ObjectIdentifier(\"1.3.14.3.2.8\");\n    static final ASN1ObjectIdentifier    desCFB                  = new ASN1ObjectIdentifier(\"1.3.14.3.2.9\");\n\n    static final ASN1ObjectIdentifier    desEDE                  = new ASN1ObjectIdentifier(\"1.3.14.3.2.17\");\n    \n    static final ASN1ObjectIdentifier    idSHA1                  = new ASN1ObjectIdentifier(\"1.3.14.3.2.26\");\n\n    static final ASN1ObjectIdentifier    dsaWithSHA1             = new ASN1ObjectIdentifier(\"1.3.14.3.2.27\");\n\n    static final ASN1ObjectIdentifier    sha1WithRSA             = new ASN1ObjectIdentifier(\"1.3.14.3.2.29\");\n    \n    // ElGamal Algorithm OBJECT IDENTIFIER ::=    \n    // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }\n    //\n    static final ASN1ObjectIdentifier    elGamalAlgorithm        = new ASN1ObjectIdentifier(\"1.3.14.7.2.1.1\");\n\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.pkcs;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface PKCSObjectIdentifiers\n{\n    //\n    // pkcs-1 OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }\n    //\n    static final ASN1ObjectIdentifier    pkcs_1                    = new ASN1ObjectIdentifier(\"1.2.840.113549.1.1\");\n    static final ASN1ObjectIdentifier    rsaEncryption             = pkcs_1.branch(\"1\");\n    static final ASN1ObjectIdentifier    md2WithRSAEncryption      = pkcs_1.branch(\"2\");\n    static final ASN1ObjectIdentifier    md4WithRSAEncryption      = pkcs_1.branch(\"3\");\n    static final ASN1ObjectIdentifier    md5WithRSAEncryption      = pkcs_1.branch(\"4\");\n    static final ASN1ObjectIdentifier    sha1WithRSAEncryption     = pkcs_1.branch(\"5\");\n    static final ASN1ObjectIdentifier    srsaOAEPEncryptionSET     = pkcs_1.branch(\"6\");\n    static final ASN1ObjectIdentifier    id_RSAES_OAEP             = pkcs_1.branch(\"7\");\n    static final ASN1ObjectIdentifier    id_mgf1                   = pkcs_1.branch(\"8\");\n    static final ASN1ObjectIdentifier    id_pSpecified             = pkcs_1.branch(\"9\");\n    static final ASN1ObjectIdentifier    id_RSASSA_PSS             = pkcs_1.branch(\"10\");\n    static final ASN1ObjectIdentifier    sha256WithRSAEncryption   = pkcs_1.branch(\"11\");\n    static final ASN1ObjectIdentifier    sha384WithRSAEncryption   = pkcs_1.branch(\"12\");\n    static final ASN1ObjectIdentifier    sha512WithRSAEncryption   = pkcs_1.branch(\"13\");\n    static final ASN1ObjectIdentifier    sha224WithRSAEncryption   = pkcs_1.branch(\"14\");\n\n    //\n    // pkcs-3 OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }\n    //\n    static final ASN1ObjectIdentifier    pkcs_3                  = new ASN1ObjectIdentifier(\"1.2.840.113549.1.3\");\n    static final ASN1ObjectIdentifier    dhKeyAgreement          = pkcs_3.branch(\"1\");\n\n    //\n    // pkcs-5 OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }\n    //\n    static final ASN1ObjectIdentifier    pkcs_5                  = new ASN1ObjectIdentifier(\"1.2.840.113549.1.5\");\n\n    static final ASN1ObjectIdentifier    pbeWithMD2AndDES_CBC    = pkcs_5.branch(\"1\");\n    static final ASN1ObjectIdentifier    pbeWithMD2AndRC2_CBC    = pkcs_5.branch(\"4\");\n    static final ASN1ObjectIdentifier    pbeWithMD5AndDES_CBC    = pkcs_5.branch(\"3\");\n    static final ASN1ObjectIdentifier    pbeWithMD5AndRC2_CBC    = pkcs_5.branch(\"6\");\n    static final ASN1ObjectIdentifier    pbeWithSHA1AndDES_CBC   = pkcs_5.branch(\"10\");\n    static final ASN1ObjectIdentifier    pbeWithSHA1AndRC2_CBC   = pkcs_5.branch(\"11\");\n\n    static final ASN1ObjectIdentifier    id_PBES2                = pkcs_5.branch(\"13\");\n\n    static final ASN1ObjectIdentifier    id_PBKDF2               = pkcs_5.branch(\"12\");\n\n    //\n    // encryptionAlgorithm OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }\n    //\n    static final ASN1ObjectIdentifier    encryptionAlgorithm     = new ASN1ObjectIdentifier(\"1.2.840.113549.3\");\n\n    static final ASN1ObjectIdentifier    des_EDE3_CBC            = encryptionAlgorithm.branch(\"7\");\n    static final ASN1ObjectIdentifier    RC2_CBC                 = encryptionAlgorithm.branch(\"2\");\n    static final ASN1ObjectIdentifier    rc4                     = encryptionAlgorithm.branch(\"4\");\n\n    //\n    // object identifiers for digests\n    //\n    static final ASN1ObjectIdentifier    digestAlgorithm        = new ASN1ObjectIdentifier(\"1.2.840.113549.2\");\n    //\n    // md2 OBJECT IDENTIFIER ::=\n    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}\n    //\n    static final ASN1ObjectIdentifier    md2                    = digestAlgorithm.branch(\"2\");\n\n    //\n    // md4 OBJECT IDENTIFIER ::=\n    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}\n    //\n    static final ASN1ObjectIdentifier    md4 = digestAlgorithm.branch(\"4\");\n\n    //\n    // md5 OBJECT IDENTIFIER ::=\n    //      {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}\n    //\n    static final ASN1ObjectIdentifier    md5                     = digestAlgorithm.branch(\"5\");\n\n    static final ASN1ObjectIdentifier    id_hmacWithSHA1         = digestAlgorithm.branch(\"7\");\n    static final ASN1ObjectIdentifier    id_hmacWithSHA224       = digestAlgorithm.branch(\"8\");\n    static final ASN1ObjectIdentifier    id_hmacWithSHA256       = digestAlgorithm.branch(\"9\");\n    static final ASN1ObjectIdentifier    id_hmacWithSHA384       = digestAlgorithm.branch(\"10\");\n    static final ASN1ObjectIdentifier    id_hmacWithSHA512       = digestAlgorithm.branch(\"11\");\n\n    //\n    // pkcs-7 OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }\n    //\n    static final String                 pkcs_7                  = \"1.2.840.113549.1.7\";\n    static final ASN1ObjectIdentifier    data                    = new ASN1ObjectIdentifier(pkcs_7 + \".1\");\n    static final ASN1ObjectIdentifier    signedData              = new ASN1ObjectIdentifier(pkcs_7 + \".2\");\n    static final ASN1ObjectIdentifier    envelopedData           = new ASN1ObjectIdentifier(pkcs_7 + \".3\");\n    static final ASN1ObjectIdentifier    signedAndEnvelopedData  = new ASN1ObjectIdentifier(pkcs_7 + \".4\");\n    static final ASN1ObjectIdentifier    digestedData            = new ASN1ObjectIdentifier(pkcs_7 + \".5\");\n    static final ASN1ObjectIdentifier    encryptedData           = new ASN1ObjectIdentifier(pkcs_7 + \".6\");\n\n    //\n    // pkcs-9 OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }\n    //\n    static final ASN1ObjectIdentifier    pkcs_9                  = new ASN1ObjectIdentifier(\"1.2.840.113549.1.9\");\n\n    static final ASN1ObjectIdentifier    pkcs_9_at_emailAddress  = pkcs_9.branch(\"1\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredName = pkcs_9.branch(\"2\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_contentType = pkcs_9.branch(\"3\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_messageDigest = pkcs_9.branch(\"4\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_signingTime = pkcs_9.branch(\"5\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_counterSignature = pkcs_9.branch(\"6\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_challengePassword = pkcs_9.branch(\"7\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredAddress = pkcs_9.branch(\"8\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch(\"9\");\n\n    static final ASN1ObjectIdentifier    pkcs_9_at_signingDescription = pkcs_9.branch(\"13\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_extensionRequest = pkcs_9.branch(\"14\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_smimeCapabilities = pkcs_9.branch(\"15\");\n\n    static final ASN1ObjectIdentifier    pkcs_9_at_friendlyName  = pkcs_9.branch(\"20\");\n    static final ASN1ObjectIdentifier    pkcs_9_at_localKeyId    = pkcs_9.branch(\"21\");\n\n    /** @deprecated use x509Certificate instead */\n    static final ASN1ObjectIdentifier    x509certType            = pkcs_9.branch(\"22.1\");\n\n    static final ASN1ObjectIdentifier    certTypes               = pkcs_9.branch(\"22\");\n    static final ASN1ObjectIdentifier    x509Certificate         = certTypes.branch(\"1\");\n    static final ASN1ObjectIdentifier    sdsiCertificate         = certTypes.branch(\"2\");\n\n    static final ASN1ObjectIdentifier    crlTypes                = pkcs_9.branch(\"23\");\n    static final ASN1ObjectIdentifier    x509Crl                 = crlTypes.branch(\"1\");\n\n    static final ASN1ObjectIdentifier    id_alg_PWRI_KEK    = pkcs_9.branch(\"16.3.9\");\n\n    //\n    // SMIME capability sub oids.\n    //\n    static final ASN1ObjectIdentifier    preferSignedData        = pkcs_9.branch(\"15.1\");\n    static final ASN1ObjectIdentifier    canNotDecryptAny        = pkcs_9.branch(\"15.2\");\n    static final ASN1ObjectIdentifier    sMIMECapabilitiesVersions = pkcs_9.branch(\"15.3\");\n\n    //\n    // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)\n    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}\n    //\n    static final ASN1ObjectIdentifier    id_ct = new ASN1ObjectIdentifier(\"1.2.840.113549.1.9.16.1\");\n\n    static final ASN1ObjectIdentifier    id_ct_authData          = id_ct.branch(\"2\");\n    static final ASN1ObjectIdentifier    id_ct_TSTInfo           = id_ct.branch(\"4\");\n    static final ASN1ObjectIdentifier    id_ct_compressedData    = id_ct.branch(\"9\");\n    static final ASN1ObjectIdentifier    id_ct_authEnvelopedData = id_ct.branch(\"23\");\n    static final ASN1ObjectIdentifier    id_ct_timestampedData   = id_ct.branch(\"31\");\n\n    //\n    // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)\n    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}\n    //\n    static final ASN1ObjectIdentifier    id_cti = new ASN1ObjectIdentifier(\"1.2.840.113549.1.9.16.6\");\n    \n    static final ASN1ObjectIdentifier    id_cti_ets_proofOfOrigin  = id_cti.branch(\"1\");\n    static final ASN1ObjectIdentifier    id_cti_ets_proofOfReceipt = id_cti.branch(\"2\");\n    static final ASN1ObjectIdentifier    id_cti_ets_proofOfDelivery = id_cti.branch(\"3\");\n    static final ASN1ObjectIdentifier    id_cti_ets_proofOfSender = id_cti.branch(\"4\");\n    static final ASN1ObjectIdentifier    id_cti_ets_proofOfApproval = id_cti.branch(\"5\");\n    static final ASN1ObjectIdentifier    id_cti_ets_proofOfCreation = id_cti.branch(\"6\");\n    \n    //\n    // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)\n    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}\n    //\n    static final ASN1ObjectIdentifier    id_aa = new ASN1ObjectIdentifier(\"1.2.840.113549.1.9.16.2\");\n\n\n    static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch(\"1\");\n    \n    static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch(\"4\"); // See RFC 2634\n    static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch(\"5\");\n    static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch(\"10\");\n    /*\n     * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}\n     * \n     */\n    static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch(\"11\");\n    static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch(\"12\");\n    static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch(\"47\");\n\n    static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch(\"7\"); // See RFC 2634\n\n    /*\n     * RFC 3126\n     */\n    static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch(\"14\");\n    \n    static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch(\"15\");\n    static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch(\"16\");\n    static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch(\"17\");\n    static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch(\"18\");\n    static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch(\"19\");\n    static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch(\"20\");\n    static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch(\"21\");\n    static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch(\"22\");\n    static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch(\"23\");\n    static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch(\"24\");\n    static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch(\"25\");\n    static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch(\"26\");\n    static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch(\"27\");\n\n    /** @deprecated use id_aa_ets_sigPolicyId instead */\n    static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId;\n    /** @deprecated use id_aa_ets_commitmentType instead */\n    static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;\n    /** @deprecated use id_aa_ets_signerLocation instead */\n    static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;\n    /** @deprecated use id_aa_ets_otherSigCert instead */\n    static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert;\n    \n    //\n    // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)\n    // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}\n    //\n    final String id_spq = \"1.2.840.113549.1.9.16.5\";\n\n    static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + \".1\");\n    static final ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + \".2\");\n\n    //\n    // pkcs-12 OBJECT IDENTIFIER ::= {\n    //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }\n    //\n    static final ASN1ObjectIdentifier   pkcs_12                  = new ASN1ObjectIdentifier(\"1.2.840.113549.1.12\");\n    static final ASN1ObjectIdentifier   bagtypes                 = pkcs_12.branch(\"10.1\");\n\n    static final ASN1ObjectIdentifier    keyBag                  = bagtypes.branch(\"1\");\n    static final ASN1ObjectIdentifier    pkcs8ShroudedKeyBag     = bagtypes.branch(\"2\");\n    static final ASN1ObjectIdentifier    certBag                 = bagtypes.branch(\"3\");\n    static final ASN1ObjectIdentifier    crlBag                  = bagtypes.branch(\"4\");\n    static final ASN1ObjectIdentifier    secretBag               = bagtypes.branch(\"5\");\n    static final ASN1ObjectIdentifier    safeContentsBag         = bagtypes.branch(\"6\");\n\n    static final ASN1ObjectIdentifier    pkcs_12PbeIds  = pkcs_12.branch(\"1\");\n\n    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch(\"1\");\n    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC4  = pkcs_12PbeIds.branch(\"2\");\n    static final ASN1ObjectIdentifier    pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch(\"3\");\n    static final ASN1ObjectIdentifier    pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch(\"4\");\n    static final ASN1ObjectIdentifier    pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch(\"5\");\n    static final ASN1ObjectIdentifier    pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch(\"6\");\n\n    /**\n     * @deprecated use pbeWithSHAAnd40BitRC2_CBC\n     */\n    static final ASN1ObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch(\"6\");\n\n    static final ASN1ObjectIdentifier    id_alg_CMS3DESwrap = new ASN1ObjectIdentifier(\"1.2.840.113549.1.9.16.3.6\");\n    static final ASN1ObjectIdentifier    id_alg_CMSRC2wrap = new ASN1ObjectIdentifier(\"1.2.840.113549.1.9.16.3.7\");\n}\n\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java",
    "content": "package local.org.bouncycastle.asn1.pkcs;\n\nimport java.io.IOException;\nimport java.math.BigInteger;\nimport java.util.Enumeration;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Encoding;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1Set;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\n\npublic class PrivateKeyInfo\n    extends ASN1Object\n{\n    private ASN1OctetString         privKey;\n    private AlgorithmIdentifier     algId;\n    private ASN1Set                 attributes;\n\n    public static PrivateKeyInfo getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static PrivateKeyInfo getInstance(\n        Object  obj)\n    {\n        if (obj instanceof PrivateKeyInfo)\n        {\n            return (PrivateKeyInfo)obj;\n        }\n        else if (obj != null)\n        {\n            return new PrivateKeyInfo(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n        \n    public PrivateKeyInfo(\n        AlgorithmIdentifier algId,\n        ASN1Encodable       privateKey)\n        throws IOException\n    {\n        this(algId, privateKey, null);\n    }\n\n    public PrivateKeyInfo(\n        AlgorithmIdentifier algId,\n        ASN1Encodable       privateKey,\n        ASN1Set             attributes)\n        throws IOException\n    {\n        this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER));\n        this.algId = algId;\n        this.attributes = attributes;\n    }\n\n    /**\n     * @deprectaed use PrivateKeyInfo.getInstance()\n     * @param seq\n     */\n    public PrivateKeyInfo(\n        ASN1Sequence  seq)\n    {\n        Enumeration e = seq.getObjects();\n\n        BigInteger  version = ((ASN1Integer)e.nextElement()).getValue();\n        if (version.intValue() != 0)\n        {\n            throw new IllegalArgumentException(\"wrong version for private key info\");\n        }\n\n        algId = AlgorithmIdentifier.getInstance(e.nextElement());\n        privKey = ASN1OctetString.getInstance(e.nextElement());\n        \n        if (e.hasMoreElements())\n        {\n           attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);\n        }\n    }\n\n    public AlgorithmIdentifier getPrivateKeyAlgorithm()\n    {\n        return algId;\n    }\n        /**\n          * @deprecated use getPrivateKeyAlgorithm()\n     */\n    public AlgorithmIdentifier getAlgorithmId()\n    {\n        return algId;\n    }\n\n    public ASN1Encodable parsePrivateKey()\n        throws IOException\n    {\n        return ASN1Primitive.fromByteArray(privKey.getOctets());\n    }\n\n    /**\n          * @deprecated use parsePrivateKey()\n     */\n    public ASN1Primitive getPrivateKey()\n    {\n        try\n        {\n            return parsePrivateKey().toASN1Primitive();\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"unable to parse private key\");\n        }\n    }\n    \n    public ASN1Set getAttributes()\n    {\n        return attributes;\n    }\n\n    /**\n     * write out an RSA private key with its associated information\n     * as described in PKCS8.\n     * <pre>\n     *      PrivateKeyInfo ::= SEQUENCE {\n     *                              version Version,\n     *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},\n     *                              privateKey PrivateKey,\n     *                              attributes [0] IMPLICIT Attributes OPTIONAL \n     *                          }\n     *      Version ::= INTEGER {v1(0)} (v1,...)\n     *\n     *      PrivateKey ::= OCTET STRING\n     *\n     *      Attributes ::= SET OF Attribute\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(new ASN1Integer(0));\n        v.add(algId);\n        v.add(privKey);\n\n        if (attributes != null)\n        {\n            v.add(new DERTaggedObject(false, 0, attributes));\n        }\n        \n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java",
    "content": "package local.org.bouncycastle.asn1.pkcs;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERNull;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\n\npublic class RSASSAPSSparams\n    extends ASN1Object\n{\n    private AlgorithmIdentifier hashAlgorithm;\n    private AlgorithmIdentifier maskGenAlgorithm;\n    private ASN1Integer          saltLength;\n    private ASN1Integer          trailerField;\n    \n    public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);\n    public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);\n    public final static ASN1Integer          DEFAULT_SALT_LENGTH = new ASN1Integer(20);\n    public final static ASN1Integer          DEFAULT_TRAILER_FIELD = new ASN1Integer(1);\n    \n    public static RSASSAPSSparams getInstance(\n        Object  obj)\n    {\n        if (obj instanceof RSASSAPSSparams)\n        {\n            return (RSASSAPSSparams)obj;\n        }\n        else if (obj != null)\n        {\n            return new RSASSAPSSparams(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n    \n    /**\n     * The default version\n     */\n    public RSASSAPSSparams()\n    {\n        hashAlgorithm = DEFAULT_HASH_ALGORITHM;\n        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;\n        saltLength = DEFAULT_SALT_LENGTH;\n        trailerField = DEFAULT_TRAILER_FIELD;\n    }\n    \n    public RSASSAPSSparams(\n        AlgorithmIdentifier hashAlgorithm,\n        AlgorithmIdentifier maskGenAlgorithm,\n        ASN1Integer          saltLength,\n        ASN1Integer          trailerField)\n    {\n        this.hashAlgorithm = hashAlgorithm;\n        this.maskGenAlgorithm = maskGenAlgorithm;\n        this.saltLength = saltLength;\n        this.trailerField = trailerField;\n    }\n    \n    private RSASSAPSSparams(\n        ASN1Sequence seq)\n    {\n        hashAlgorithm = DEFAULT_HASH_ALGORITHM;\n        maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;\n        saltLength = DEFAULT_SALT_LENGTH;\n        trailerField = DEFAULT_TRAILER_FIELD;\n        \n        for (int i = 0; i != seq.size(); i++)\n        {\n            ASN1TaggedObject    o = (ASN1TaggedObject)seq.getObjectAt(i);\n            \n            switch (o.getTagNo())\n            {\n            case 0:\n                hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);\n                break;\n            case 1:\n                maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);\n                break;\n            case 2:\n                saltLength = ASN1Integer.getInstance(o, true);\n                break;\n            case 3:\n                trailerField = ASN1Integer.getInstance(o, true);\n                break;\n            default:\n                throw new IllegalArgumentException(\"unknown tag\");\n            }\n        }\n    }\n    \n    public AlgorithmIdentifier getHashAlgorithm()\n    {\n        return hashAlgorithm;\n    }\n    \n    public AlgorithmIdentifier getMaskGenAlgorithm()\n    {\n        return maskGenAlgorithm;\n    }\n    \n    public BigInteger getSaltLength()\n    {\n        return saltLength.getValue();\n    }\n    \n    public BigInteger getTrailerField()\n    {\n        return trailerField.getValue();\n    }\n    \n    /**\n     * <pre>\n     * RSASSA-PSS-params ::= SEQUENCE {\n     *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms  DEFAULT sha1,\n     *    maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,\n     *    saltLength         [2] INTEGER  DEFAULT 20,\n     *    trailerField       [3] TrailerField  DEFAULT trailerFieldBC\n     *  }\n     *\n     * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {\n     *    { OID id-sha1 PARAMETERS NULL   }|\n     *    { OID id-sha256 PARAMETERS NULL }|\n     *    { OID id-sha384 PARAMETERS NULL }|\n     *    { OID id-sha512 PARAMETERS NULL },\n     *    ...  -- Allows for future expansion --\n     * }\n     *\n     * PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {\n     *   { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },\n     *    ...  -- Allows for future expansion --\n     * }\n     * \n     * TrailerField ::= INTEGER { trailerFieldBC(1) }\n     * </pre>\n     * @return the asn1 primitive representing the parameters.\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n        \n        if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))\n        {\n            v.add(new DERTaggedObject(true, 0, hashAlgorithm));\n        }\n        \n        if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))\n        {\n            v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));\n        }\n        \n        if (!saltLength.equals(DEFAULT_SALT_LENGTH))\n        {\n            v.add(new DERTaggedObject(true, 2, saltLength));\n        }\n        \n        if (!trailerField.equals(DEFAULT_TRAILER_FIELD))\n        {\n            v.add(new DERTaggedObject(true, 3, trailerField));\n        }\n        \n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/sec/SECNamedCurves.java",
    "content": "package local.org.bouncycastle.asn1.sec;\n\nimport java.math.BigInteger;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x9.X9ECParameters;\nimport local.org.bouncycastle.asn1.x9.X9ECParametersHolder;\nimport local.org.bouncycastle.math.ec.ECConstants;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.math.ec.ECPoint;\nimport local.org.bouncycastle.util.Strings;\nimport local.org.bouncycastle.util.encoders.Hex;\n\n\npublic class SECNamedCurves\n{\n    private static BigInteger fromHex(\n        String hex)\n    {\n        return new BigInteger(1, Hex.decode(hex));\n    }\n\n    /*\n     * secp112r1\n     */\n    static X9ECParametersHolder secp112r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = (2^128 - 3) / 76439\n            BigInteger p = fromHex(\"DB7C2ABF62E35E668076BEAD208B\");\n            BigInteger a = fromHex(\"DB7C2ABF62E35E668076BEAD2088\");\n            BigInteger b = fromHex(\"659EF8BA043916EEDE8911702B22\");\n            byte[] S = Hex.decode(\"00F50B028E4D696E676875615175290472783FB1\");\n            BigInteger n = fromHex(\"DB7C2ABF62E35E7628DFAC6561C5\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"09487239995A5EE76B55F9C2F098\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"09487239995A5EE76B55F9C2F098\"\n                + \"A89CE5AF8724C0A23E0E0FF77500\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp112r2\n     */\n    static X9ECParametersHolder secp112r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = (2^128 - 3) / 76439\n            BigInteger p = fromHex(\"DB7C2ABF62E35E668076BEAD208B\");\n            BigInteger a = fromHex(\"6127C24C05F38A0AAAF65C0EF02C\");\n            BigInteger b = fromHex(\"51DEF1815DB5ED74FCC34C85D709\");\n            byte[] S = Hex.decode(\"002757A1114D696E6768756151755316C05E0BD4\");\n            BigInteger n = fromHex(\"36DF0AAFD8B8D7597CA10520D04B\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"4BA30AB5E892B4E1649DD0928643\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"4BA30AB5E892B4E1649DD0928643\"\n                + \"ADCD46F5882E3747DEF36E956E97\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp128r1\n     */\n    static X9ECParametersHolder secp128r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^128 - 2^97 - 1\n            BigInteger p = fromHex(\"FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF\");\n            BigInteger a = fromHex(\"FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC\");\n            BigInteger b = fromHex(\"E87579C11079F43DD824993C2CEE5ED3\");\n            byte[] S = Hex.decode(\"000E0D4D696E6768756151750CC03A4473D03679\");\n            BigInteger n = fromHex(\"FFFFFFFE0000000075A30D1B9038A115\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"161FF7528B899B2D0C28607CA52C5B86\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"161FF7528B899B2D0C28607CA52C5B86\"\n                + \"CF5AC8395BAFEB13C02DA292DDED7A83\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp128r2\n     */\n    static X9ECParametersHolder secp128r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^128 - 2^97 - 1\n            BigInteger p = fromHex(\"FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF\");\n            BigInteger a = fromHex(\"D6031998D1B3BBFEBF59CC9BBFF9AEE1\");\n            BigInteger b = fromHex(\"5EEEFCA380D02919DC2C6558BB6D8A5D\");\n            byte[] S = Hex.decode(\"004D696E67687561517512D8F03431FCE63B88F4\");\n            BigInteger n = fromHex(\"3FFFFFFF7FFFFFFFBE0024720613B5A3\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"7B6AA5D85E572983E6FB32A7CDEBC140\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"7B6AA5D85E572983E6FB32A7CDEBC140\"\n                + \"27B6916A894D3AEE7106FE805FC34B44\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp160k1\n     */\n    static X9ECParametersHolder secp160k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73\");\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(7);\n            byte[] S = null;\n            BigInteger n = fromHex(\"0100000000000000000001B8FA16DFAB9ACA16B6B3\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n//            ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n//                + \"3B4C382CE37AA192A4019E763036F4F5DD4D7EBB\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"3B4C382CE37AA192A4019E763036F4F5DD4D7EBB\"\n                + \"938CF935318FDCED6BC28286531733C3F03C4FEE\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp160r1\n     */\n    static X9ECParametersHolder secp160r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^160 - 2^31 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF\");\n            BigInteger a = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC\");\n            BigInteger b = fromHex(\"1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45\");\n            byte[] S = Hex.decode(\"1053CDE42C14D696E67687561517533BF3F83345\");\n            BigInteger n = fromHex(\"0100000000000000000001F4C8F927AED3CA752257\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n                //+ \"4A96B5688EF573284664698968C38BB913CBFC82\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"4A96B5688EF573284664698968C38BB913CBFC82\"\n                + \"23A628553168947D59DCC912042351377AC5FB32\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp160r2\n     */\n    static X9ECParametersHolder secp160r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73\");\n            BigInteger a = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70\");\n            BigInteger b = fromHex(\"B4E134D3FB59EB8BAB57274904664D5AF50388BA\");\n            byte[] S = Hex.decode(\"B99B99B099B323E02709A4D696E6768756151751\");\n            BigInteger n = fromHex(\"0100000000000000000000351EE786A818F3A1A16B\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"52DCB034293A117E1F4FF11B30F7199D3144CE6D\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"52DCB034293A117E1F4FF11B30F7199D3144CE6D\"\n                + \"FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp192k1\n     */\n    static X9ECParametersHolder secp192k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37\");\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(3);\n            byte[] S = null;\n            BigInteger n = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D\"\n                + \"9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp192r1\n     */\n    static X9ECParametersHolder secp192r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^192 - 2^64 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF\");\n            BigInteger a = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC\");\n            BigInteger b = fromHex(\"64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1\");\n            byte[] S = Hex.decode(\"3045AE6FC8422F64ED579528D38120EAE12196D5\");\n            BigInteger n = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012\"\n                + \"07192B95FFC8DA78631011ED6B24CDD573F977A11E794811\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp224k1\n     */\n    static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D\");\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(5);\n            byte[] S = null;\n            BigInteger n = fromHex(\"010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C\"\n                + \"7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp224r1\n     */\n    static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^224 - 2^96 + 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001\");\n            BigInteger a = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE\");\n            BigInteger b = fromHex(\"B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4\");\n            byte[] S = Hex.decode(\"BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5\");\n            BigInteger n = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21\"\n                + \"BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp256k1\n     */\n    static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\");\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(7);\n            byte[] S = null;\n            BigInteger n = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798\"\n                + \"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp256r1\n     */\n    static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1\n            BigInteger p = fromHex(\"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF\");\n            BigInteger a = fromHex(\"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC\");\n            BigInteger b = fromHex(\"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B\");\n            byte[] S = Hex.decode(\"C49D360886E704936A6678E1139D26B7819F7E90\");\n            BigInteger n = fromHex(\"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296\"\n                + \"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp384r1\n     */\n    static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^384 - 2^128 - 2^96 + 2^32 - 1\n            BigInteger p = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF\");\n            BigInteger a = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC\");\n            BigInteger b = fromHex(\"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF\");\n            byte[] S = Hex.decode(\"A335926AA319A27A1D00896A6773A4827ACDAC73\");\n            BigInteger n = fromHex(\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7\"\n                + \"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * secp521r1\n     */\n    static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            // p = 2^521 - 1\n            BigInteger p = fromHex(\"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\");\n            BigInteger a = fromHex(\"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC\");\n            BigInteger b = fromHex(\"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00\");\n            byte[] S = Hex.decode(\"D09E8800291CB85396CC6717393284AAA0DA64BA\");\n            BigInteger n = fromHex(\"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409\");\n            BigInteger h = BigInteger.valueOf(1);\n\n            ECCurve curve = new ECCurve.Fp(p, a, b);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66\"\n                + \"011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n    \n    /*\n     * sect113r1\n     */\n    static X9ECParametersHolder sect113r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 113;\n            int k = 9;\n\n            BigInteger a = fromHex(\"003088250CA6E7C7FE649CE85820F7\");\n            BigInteger b = fromHex(\"00E8BEE4D3E2260744188BE0E9C723\");\n            byte[] S = Hex.decode(\"10E723AB14D696E6768756151756FEBF8FCB49A9\");\n            BigInteger n = fromHex(\"0100000000000000D9CCEC8A39E56F\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"009D73616F35F4AB1407D73562C10F\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"009D73616F35F4AB1407D73562C10F\"\n                + \"00A52830277958EE84D1315ED31886\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect113r2\n     */\n    static X9ECParametersHolder sect113r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 113;\n            int k = 9;\n\n            BigInteger a = fromHex(\"00689918DBEC7E5A0DD6DFC0AA55C7\");\n            BigInteger b = fromHex(\"0095E9A9EC9B297BD4BF36E059184F\");\n            byte[] S = Hex.decode(\"10C0FB15760860DEF1EEF4D696E676875615175D\");\n            BigInteger n = fromHex(\"010000000000000108789B2496AF93\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"01A57A6A7B26CA5EF52FCDB8164797\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"01A57A6A7B26CA5EF52FCDB8164797\"\n                + \"00B3ADC94ED1FE674C06E695BABA1D\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect131r1\n     */\n    static X9ECParametersHolder sect131r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 131;\n            int k1 = 2;\n            int k2 = 3;\n            int k3 = 8;\n\n            BigInteger a = fromHex(\"07A11B09A76B562144418FF3FF8C2570B8\");\n            BigInteger b = fromHex(\"0217C05610884B63B9C6C7291678F9D341\");\n            byte[] S = Hex.decode(\"4D696E676875615175985BD3ADBADA21B43A97E2\");\n            BigInteger n = fromHex(\"0400000000000000023123953A9464B54D\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"0081BAF91FDF9833C40F9C181343638399\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"0081BAF91FDF9833C40F9C181343638399\"\n                + \"078C6E7EA38C001F73C8134B1B4EF9E150\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect131r2\n     */\n    static X9ECParametersHolder sect131r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 131;\n            int k1 = 2;\n            int k2 = 3;\n            int k3 = 8;\n\n            BigInteger a = fromHex(\"03E5A88919D7CAFCBF415F07C2176573B2\");\n            BigInteger b = fromHex(\"04B8266A46C55657AC734CE38F018F2192\");\n            byte[] S = Hex.decode(\"985BD3ADBAD4D696E676875615175A21B43A97E3\");\n            BigInteger n = fromHex(\"0400000000000000016954A233049BA98F\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"0356DCD8F2F95031AD652D23951BB366A8\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"0356DCD8F2F95031AD652D23951BB366A8\"\n                + \"0648F06D867940A5366D9E265DE9EB240F\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect163k1\n     */\n    static X9ECParametersHolder sect163k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 163;\n            int k1 = 3;\n            int k2 = 6;\n            int k3 = 7;\n\n            BigInteger a = BigInteger.valueOf(1);\n            BigInteger b = BigInteger.valueOf(1);\n            byte[] S = null;\n            BigInteger n = fromHex(\"04000000000000000000020108A2E0CC0D99F8A5EF\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8\"\n                + \"0289070FB05D38FF58321F2E800536D538CCDAA3D9\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect163r1\n     */\n    static X9ECParametersHolder sect163r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 163;\n            int k1 = 3;\n            int k2 = 6;\n            int k3 = 7;\n\n            BigInteger a = fromHex(\"07B6882CAAEFA84F9554FF8428BD88E246D2782AE2\");\n            BigInteger b = fromHex(\"0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9\");\n            byte[] S = Hex.decode(\"24B7B137C8A14D696E6768756151756FD0DA2E5C\");\n            BigInteger n = fromHex(\"03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"0369979697AB43897789566789567F787A7876A654\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"0369979697AB43897789566789567F787A7876A654\"\n                + \"00435EDB42EFAFB2989D51FEFCE3C80988F41FF883\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect163r2\n     */\n    static X9ECParametersHolder sect163r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 163;\n            int k1 = 3;\n            int k2 = 6;\n            int k3 = 7;\n\n            BigInteger a = BigInteger.valueOf(1);\n            BigInteger b = fromHex(\"020A601907B8C953CA1481EB10512F78744A3205FD\");\n            byte[] S = Hex.decode(\"85E25BFE5C86226CDB12016F7553F9D0E693A268\");\n            BigInteger n = fromHex(\"040000000000000000000292FE77E70C12A4234C33\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"03F0EBA16286A2D57EA0991168D4994637E8343E36\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"03F0EBA16286A2D57EA0991168D4994637E8343E36\"\n                + \"00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect193r1\n     */\n    static X9ECParametersHolder sect193r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 193;\n            int k = 15;\n\n            BigInteger a = fromHex(\"0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01\");\n            BigInteger b = fromHex(\"00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814\");\n            byte[] S = Hex.decode(\"103FAEC74D696E676875615175777FC5B191EF30\");\n            BigInteger n = fromHex(\"01000000000000000000000000C7F34A778F443ACC920EBA49\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1\"\n                + \"0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect193r2\n     */\n    static X9ECParametersHolder sect193r2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 193;\n            int k = 15;\n\n            BigInteger a = fromHex(\"0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B\");\n            BigInteger b = fromHex(\"00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE\");\n            byte[] S = Hex.decode(\"10B7B4D696E676875615175137C8A16FD0DA2211\");\n            BigInteger n = fromHex(\"010000000000000000000000015AAB561B005413CCD4EE99D5\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F\"\n                + \"01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect233k1\n     */\n    static X9ECParametersHolder sect233k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 233;\n            int k = 74;\n\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(1);\n            byte[] S = null;\n            BigInteger n = fromHex(\"8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126\"\n                + \"01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect233r1\n     */\n    static X9ECParametersHolder sect233r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 233;\n            int k = 74;\n\n            BigInteger a = BigInteger.valueOf(1);\n            BigInteger b = fromHex(\"0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD\");\n            byte[] S = Hex.decode(\"74D59FF07F6B413D0EA14B344B20A2DB049B50C3\");\n            BigInteger n = fromHex(\"01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B\"\n                + \"01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect239k1\n     */\n    static X9ECParametersHolder sect239k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 239;\n            int k = 158;\n\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(1);\n            byte[] S = null;\n            BigInteger n = fromHex(\"2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC\"\n                + \"76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect283k1\n     */\n    static X9ECParametersHolder sect283k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 283;\n            int k1 = 5;\n            int k2 = 7;\n            int k3 = 12;\n\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(1);\n            byte[] S = null;\n            BigInteger n = fromHex(\"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836\"\n                + \"01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect283r1\n     */\n    static X9ECParametersHolder sect283r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 283;\n            int k1 = 5;\n            int k2 = 7;\n            int k3 = 12;\n\n            BigInteger a = BigInteger.valueOf(1);\n            BigInteger b = fromHex(\"027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5\");\n            byte[] S = Hex.decode(\"77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE\");\n            BigInteger n = fromHex(\"03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053\"\n                + \"03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect409k1\n     */\n    static X9ECParametersHolder sect409k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 409;\n            int k = 87;\n\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(1);\n            byte[] S = null;\n            BigInteger n = fromHex(\"7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746\"\n                + \"01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect409r1\n     */\n    static X9ECParametersHolder sect409r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 409;\n            int k = 87;\n\n            BigInteger a = BigInteger.valueOf(1);\n            BigInteger b = fromHex(\"0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F\");\n            byte[] S = Hex.decode(\"4099B5A457F9D69F79213D094C4BCD4D4262210B\");\n            BigInteger n = fromHex(\"010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7\"\n                + \"0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect571k1\n     */\n    static X9ECParametersHolder sect571k1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 571;\n            int k1 = 2;\n            int k2 = 5;\n            int k3 = 10;\n\n            BigInteger a = ECConstants.ZERO;\n            BigInteger b = BigInteger.valueOf(1);\n            byte[] S = null;\n            BigInteger n = fromHex(\"020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001\");\n            BigInteger h = BigInteger.valueOf(4);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"02\"\n            //+ \"026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972\"\n                + \"0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n    /*\n     * sect571r1\n     */\n    static X9ECParametersHolder sect571r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            int m = 571;\n            int k1 = 2;\n            int k2 = 5;\n            int k3 = 10;\n\n            BigInteger a = BigInteger.valueOf(1);\n            BigInteger b = fromHex(\"02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A\");\n            byte[] S = Hex.decode(\"2AA058F73A0E33AB486B0F610410C53A7F132310\");\n            BigInteger n = fromHex(\"03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47\");\n            BigInteger h = BigInteger.valueOf(2);\n\n            ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b, n, h);\n            //ECPoint G = curve.decodePoint(Hex.decode(\"03\"\n            //+ \"0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19\"));\n            ECPoint G = curve.decodePoint(Hex.decode(\"04\"\n                + \"0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19\"\n                + \"037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B\"));\n\n            return new X9ECParameters(curve, G, n, h, S);\n        }\n    };\n\n\n    static final Hashtable objIds = new Hashtable();\n    static final Hashtable curves = new Hashtable();\n    static final Hashtable names = new Hashtable();\n\n    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)\n    {\n        objIds.put(name, oid);\n        names.put(oid, name);\n        curves.put(oid, holder);\n    }\n\n    static\n    {\n        defineCurve(\"secp112r1\", SECObjectIdentifiers.secp112r1, secp112r1);\n        defineCurve(\"secp112r2\", SECObjectIdentifiers.secp112r2, secp112r2);\n        defineCurve(\"secp128r1\", SECObjectIdentifiers.secp128r1, secp128r1);\n        defineCurve(\"secp128r2\", SECObjectIdentifiers.secp128r2, secp128r2);\n        defineCurve(\"secp160k1\", SECObjectIdentifiers.secp160k1, secp160k1);\n        defineCurve(\"secp160r1\", SECObjectIdentifiers.secp160r1, secp160r1);\n        defineCurve(\"secp160r2\", SECObjectIdentifiers.secp160r2, secp160r2);\n        defineCurve(\"secp192k1\", SECObjectIdentifiers.secp192k1, secp192k1);\n        defineCurve(\"secp192r1\", SECObjectIdentifiers.secp192r1, secp192r1);\n        defineCurve(\"secp224k1\", SECObjectIdentifiers.secp224k1, secp224k1);\n        defineCurve(\"secp224r1\", SECObjectIdentifiers.secp224r1, secp224r1); \n        defineCurve(\"secp256k1\", SECObjectIdentifiers.secp256k1, secp256k1);\n        defineCurve(\"secp256r1\", SECObjectIdentifiers.secp256r1, secp256r1); \n        defineCurve(\"secp384r1\", SECObjectIdentifiers.secp384r1, secp384r1); \n        defineCurve(\"secp521r1\", SECObjectIdentifiers.secp521r1, secp521r1); \n\n        defineCurve(\"sect113r1\", SECObjectIdentifiers.sect113r1, sect113r1);\n        defineCurve(\"sect113r2\", SECObjectIdentifiers.sect113r2, sect113r2);\n        defineCurve(\"sect131r1\", SECObjectIdentifiers.sect131r1, sect131r1);\n        defineCurve(\"sect131r2\", SECObjectIdentifiers.sect131r2, sect131r2);\n        defineCurve(\"sect163k1\", SECObjectIdentifiers.sect163k1, sect163k1);\n        defineCurve(\"sect163r1\", SECObjectIdentifiers.sect163r1, sect163r1);\n        defineCurve(\"sect163r2\", SECObjectIdentifiers.sect163r2, sect163r2);\n        defineCurve(\"sect193r1\", SECObjectIdentifiers.sect193r1, sect193r1);\n        defineCurve(\"sect193r2\", SECObjectIdentifiers.sect193r2, sect193r2);\n        defineCurve(\"sect233k1\", SECObjectIdentifiers.sect233k1, sect233k1);\n        defineCurve(\"sect233r1\", SECObjectIdentifiers.sect233r1, sect233r1);\n        defineCurve(\"sect239k1\", SECObjectIdentifiers.sect239k1, sect239k1);\n        defineCurve(\"sect283k1\", SECObjectIdentifiers.sect283k1, sect283k1);\n        defineCurve(\"sect283r1\", SECObjectIdentifiers.sect283r1, sect283r1);\n        defineCurve(\"sect409k1\", SECObjectIdentifiers.sect409k1, sect409k1);\n        defineCurve(\"sect409r1\", SECObjectIdentifiers.sect409r1, sect409r1);\n        defineCurve(\"sect571k1\", SECObjectIdentifiers.sect571k1, sect571k1);\n        defineCurve(\"sect571r1\", SECObjectIdentifiers.sect571r1, sect571r1); \n    }\n\n    public static X9ECParameters getByName(\n        String name)\n    {\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));\n\n        if (oid != null)\n        {\n            return getByOID(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * return the X9ECParameters object for the named curve represented by\n     * the passed in object identifier. Null if the curve isn't present.\n     *\n     * @param oid an object identifier representing a named curve, if present.\n     */\n    public static X9ECParameters getByOID(\n        ASN1ObjectIdentifier oid)\n    {\n        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);\n\n        if (holder != null)\n        {\n            return holder.getParameters();\n        }\n\n        return null;\n    }\n\n    /**\n     * return the object identifier signified by the passed in name. Null\n     * if there is no object identifier associated with name.\n     *\n     * @return the object identifier associated with name, if present.\n     */\n    public static ASN1ObjectIdentifier getOID(\n        String name)\n    {\n        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));\n    }\n\n    /**\n     * return the named curve name represented by the given object identifier.\n     */\n    public static String getName(\n        ASN1ObjectIdentifier oid)\n    {\n        return (String)names.get(oid);\n    }\n\n    /**\n     * returns an enumeration containing the name strings for curves\n     * contained in this structure.\n     */\n    public static Enumeration getNames()\n    {\n        return objIds.keys();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.sec;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;\n\npublic interface SECObjectIdentifiers\n{\n    /**\n     *  ellipticCurve OBJECT IDENTIFIER ::= {\n     *        iso(1) identified-organization(3) certicom(132) curve(0)\n     *  }\n     */\n    static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier(\"1.3.132.0\");\n\n    static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch(\"1\");\n    static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch(\"2\");\n    static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch(\"3\");\n    static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch(\"4\");\n    static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch(\"5\");\n    static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch(\"6\");\n    static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch(\"7\");\n    static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch(\"8\");\n    static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch(\"9\");\n    static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch(\"10\");\n    static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch(\"15\");\n    static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch(\"16\");\n    static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch(\"17\");\n    static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch(\"22\");\n    static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch(\"23\");\n    static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch(\"24\");\n    static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch(\"25\");\n    static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch(\"26\");\n    static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch(\"27\");\n    static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch(\"28\");\n    static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch(\"29\");\n    static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch(\"30\");\n    static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch(\"31\");\n    static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch(\"32\");\n    static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch(\"33\");\n    static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch(\"34\");\n    static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch(\"35\");\n    static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch(\"36\");\n    static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch(\"37\");\n    static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch(\"38\");\n    static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch(\"39\");\n\n    static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;\n    static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;\n\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java",
    "content": "package local.org.bouncycastle.asn1.teletrust;\n\nimport java.math.BigInteger;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x9.X9ECParameters;\nimport local.org.bouncycastle.asn1.x9.X9ECParametersHolder;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.util.Strings;\nimport local.org.bouncycastle.util.encoders.Hex;\n\n\n/**\n * elliptic curves defined in \"ECC Brainpool Standard Curves and Curve Generation\"\n * http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt\n */\npublic class TeleTrusTNamedCurves\n{\n    static X9ECParametersHolder brainpoolP160r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"E95E4A5F737059DC60DFC7AD95B3D8139515620F\", 16), // q\n                new BigInteger(\"340E7BE2A280EB74E2BE61BADA745D97E8F7C300\", 16), // a\n                new BigInteger(\"1E589A8595423412134FAA2DBDEC95C8D8675E58\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321\")), // G\n                new BigInteger(\"E95E4A5F737059DC60DF5991D45029409E60FC09\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n\n    static X9ECParametersHolder brainpoolP160t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //   new BigInteger(\"24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B\", 16), // Z\n                new BigInteger(\"E95E4A5F737059DC60DFC7AD95B3D8139515620F\", 16), // q\n                new BigInteger(\"E95E4A5F737059DC60DFC7AD95B3D8139515620C\", 16), // a'\n                new BigInteger(\"7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD\")), // G\n                new BigInteger(\"E95E4A5F737059DC60DF5991D45029409E60FC09\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n\n    static X9ECParametersHolder brainpoolP192r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297\", 16), // q\n                new BigInteger(\"6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF\", 16), // a\n                new BigInteger(\"469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F\")), // G\n                new BigInteger(\"C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n\n    static X9ECParametersHolder brainpoolP192t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //new BigInteger(\"1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB\") //Z\n                new BigInteger(\"C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297\", 16), // q\n                new BigInteger(\"C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294\", 16), // a'\n                new BigInteger(\"13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9\")), // G'\n                new BigInteger(\"C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n\n    static X9ECParametersHolder brainpoolP224r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF\", 16), // q\n                new BigInteger(\"68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43\", 16), // a\n                new BigInteger(\"2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD\")), // G\n                new BigInteger(\"D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F\", 16), //n\n                new BigInteger(\"01\", 16)); // n\n        }\n    };\n    static X9ECParametersHolder brainpoolP224t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //new BigInteger(\"2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F\") //Z\n                new BigInteger(\"D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF\", 16), // q\n                new BigInteger(\"D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC\", 16), // a'\n                new BigInteger(\"4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C\")), // G'\n                new BigInteger(\"D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP256r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377\", 16), // q\n                new BigInteger(\"7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9\", 16), // a\n                new BigInteger(\"26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997\")), // G\n                new BigInteger(\"A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP256t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //new BigInteger(\"3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0\") //Z\n                new BigInteger(\"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377\", 16), // q\n                new BigInteger(\"A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374\", 16), // a'\n                new BigInteger(\"662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE\")), // G'\n                new BigInteger(\"A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP320r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27\", 16), // q\n                new BigInteger(\"3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4\", 16), // a\n                new BigInteger(\"520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1\")), // G\n                new BigInteger(\"D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP320t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //new BigInteger(\"15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1\") //Z\n                new BigInteger(\"D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27\", 16), // q\n                new BigInteger(\"D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24\", 16), // a'\n                new BigInteger(\"A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3\")), // G'\n                new BigInteger(\"D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP384r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53\", 16), // q\n                new BigInteger(\"7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826\", 16), // a\n                new BigInteger(\"4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315\")), // G\n                new BigInteger(\"8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP384t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //new BigInteger(\"41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C\") //Z\n                new BigInteger(\"8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53\", 16), // q\n                new BigInteger(\"8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50\", 16), // a'\n                new BigInteger(\"7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928\")), // G'\n                new BigInteger(\"8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP512r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                new BigInteger(\"AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3\", 16), // q\n                new BigInteger(\"7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA\", 16), // a\n                new BigInteger(\"3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723\", 16)); // b\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892\")), // G\n                new BigInteger(\"AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n    static X9ECParametersHolder brainpoolP512t1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve curve = new ECCurve.Fp(\n                //new BigInteger(\"12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB\") //Z\n                new BigInteger(\"AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3\", 16), // q\n                new BigInteger(\"AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0\", 16), // a'\n                new BigInteger(\"7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E\", 16)); // b'\n\n            return new X9ECParameters(\n                curve,\n                curve.decodePoint(Hex.decode(\"04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332\")), // G'\n                new BigInteger(\"AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069\", 16), //n\n                new BigInteger(\"01\", 16)); // h\n        }\n    };\n\n    static final Hashtable objIds = new Hashtable();\n    static final Hashtable curves = new Hashtable();\n    static final Hashtable names = new Hashtable();\n\n    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)\n    {\n        objIds.put(name, oid);\n        names.put(oid, name);\n        curves.put(oid, holder);\n    }\n\n    static\n    {\n        defineCurve(\"brainpoolp160r1\", TeleTrusTObjectIdentifiers.brainpoolP160r1, brainpoolP160r1);\n        defineCurve(\"brainpoolp160t1\", TeleTrusTObjectIdentifiers.brainpoolP160t1, brainpoolP160t1);\n        defineCurve(\"brainpoolp192r1\", TeleTrusTObjectIdentifiers.brainpoolP192r1, brainpoolP192r1);\n        defineCurve(\"brainpoolp192t1\", TeleTrusTObjectIdentifiers.brainpoolP192t1, brainpoolP192t1);\n        defineCurve(\"brainpoolp224r1\", TeleTrusTObjectIdentifiers.brainpoolP224r1, brainpoolP224r1);\n        defineCurve(\"brainpoolp224t1\", TeleTrusTObjectIdentifiers.brainpoolP224t1, brainpoolP224t1);\n        defineCurve(\"brainpoolp256r1\", TeleTrusTObjectIdentifiers.brainpoolP256r1, brainpoolP256r1);\n        defineCurve(\"brainpoolp256t1\", TeleTrusTObjectIdentifiers.brainpoolP256t1, brainpoolP256t1);\n        defineCurve(\"brainpoolp320r1\", TeleTrusTObjectIdentifiers.brainpoolP320r1, brainpoolP320r1);\n        defineCurve(\"brainpoolp320t1\", TeleTrusTObjectIdentifiers.brainpoolP320t1, brainpoolP320t1);\n        defineCurve(\"brainpoolp384r1\", TeleTrusTObjectIdentifiers.brainpoolP384r1, brainpoolP384r1);\n        defineCurve(\"brainpoolp384t1\", TeleTrusTObjectIdentifiers.brainpoolP384t1, brainpoolP384t1);\n        defineCurve(\"brainpoolp512r1\", TeleTrusTObjectIdentifiers.brainpoolP512r1, brainpoolP512r1);\n        defineCurve(\"brainpoolp512t1\", TeleTrusTObjectIdentifiers.brainpoolP512t1, brainpoolP512t1);\n    }\n\n    public static X9ECParameters getByName(\n        String name)\n    {\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));\n\n        if (oid != null)\n        {\n            return getByOID(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * return the X9ECParameters object for the named curve represented by\n     * the passed in object identifier. Null if the curve isn't present.\n     *\n     * @param oid an object identifier representing a named curve, if present.\n     */\n    public static X9ECParameters getByOID(\n        ASN1ObjectIdentifier oid)\n    {\n        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);\n\n        if (holder != null)\n        {\n            return holder.getParameters();\n        }\n\n        return null;\n    }\n\n    /**\n     * return the object identifier signified by the passed in name. Null\n     * if there is no object identifier associated with name.\n     *\n     * @return the object identifier associated with name, if present.\n     */\n    public static ASN1ObjectIdentifier getOID(\n        String name)\n    {\n        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));\n    }\n\n    /**\n     * return the named curve name represented by the given object identifier.\n     */\n    public static String getName(\n        ASN1ObjectIdentifier oid)\n    {\n        return (String)names.get(oid);\n    }\n\n    /**\n     * returns an enumeration containing the name strings for curves\n     * contained in this structure.\n     */\n    public static Enumeration getNames()\n    {\n        return objIds.keys();\n    }\n\n    public static ASN1ObjectIdentifier getOID(short curvesize, boolean twisted)\n    {\n        return getOID(\"brainpoolP\" + curvesize + (twisted ? \"t\" : \"r\") + \"1\");\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.teletrust;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface TeleTrusTObjectIdentifiers\n{\n    static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier(\"1.3.36.3\");\n\n    static final ASN1ObjectIdentifier    ripemd160           = teleTrusTAlgorithm.branch(\"2.1\");\n    static final ASN1ObjectIdentifier    ripemd128           = teleTrusTAlgorithm.branch(\"2.2\");\n    static final ASN1ObjectIdentifier    ripemd256           = teleTrusTAlgorithm.branch(\"2.3\");\n\n    static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch(\"3.1\");\n\n    static final ASN1ObjectIdentifier    rsaSignatureWithripemd160           = teleTrusTRSAsignatureAlgorithm.branch(\"2\");\n    static final ASN1ObjectIdentifier    rsaSignatureWithripemd128           = teleTrusTRSAsignatureAlgorithm.branch(\"3\");\n    static final ASN1ObjectIdentifier    rsaSignatureWithripemd256           = teleTrusTRSAsignatureAlgorithm.branch(\"4\");\n\n    static final ASN1ObjectIdentifier    ecSign = teleTrusTAlgorithm.branch(\"3.2\");\n\n    static final ASN1ObjectIdentifier    ecSignWithSha1  = ecSign.branch(\"1\");\n    static final ASN1ObjectIdentifier    ecSignWithRipemd160  = ecSign.branch(\"2\");\n\n    static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch(\"3.2.8\");\n    static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch(\"1\");\n    static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch(\"1\");\n\n    static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch(\"1\");\n    static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch(\"2\");\n    static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch(\"3\");\n    static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch(\"4\");\n    static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch(\"5\");\n    static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch(\"6\");\n    static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch(\"7\");\n    static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch(\"8\");\n    static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch(\"9\");\n    static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch(\"10\");\n    static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch(\"11\");\n    static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch(\"12\");\n    static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch(\"13\");\n    static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch(\"14\");\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java",
    "content": "package local.org.bouncycastle.asn1.x500;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class AttributeTypeAndValue\n    extends ASN1Object\n{\n    private ASN1ObjectIdentifier type;\n    private ASN1Encodable       value;\n\n    private AttributeTypeAndValue(ASN1Sequence seq)\n    {\n        type = (ASN1ObjectIdentifier)seq.getObjectAt(0);\n        value = (ASN1Encodable)seq.getObjectAt(1);\n    }\n\n    public static AttributeTypeAndValue getInstance(Object o)\n    {\n        if (o instanceof AttributeTypeAndValue)\n        {\n            return (AttributeTypeAndValue)o;\n        }\n        else if (o != null)\n        {\n            return new AttributeTypeAndValue(ASN1Sequence.getInstance(o));\n        }\n\n        throw new IllegalArgumentException(\"null value in getInstance()\");\n    }\n\n    public AttributeTypeAndValue(\n        ASN1ObjectIdentifier type,\n        ASN1Encodable value)\n    {\n        this.type = type;\n        this.value = value;\n    }\n\n    public ASN1ObjectIdentifier getType()\n    {\n        return type;\n    }\n\n    public ASN1Encodable getValue()\n    {\n        return value;\n    }\n\n    /**\n     * <pre>\n     * AttributeTypeAndValue ::= SEQUENCE {\n     *           type         OBJECT IDENTIFIER,\n     *           value        ANY DEFINED BY type }\n     * </pre>\n     * @return a basic ASN.1 object representation.\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(type);\n        v.add(value);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/RDN.java",
    "content": "package local.org.bouncycastle.asn1.x500;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Set;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERSet;\n\npublic class RDN\n    extends ASN1Object\n{\n    private ASN1Set values;\n\n    private RDN(ASN1Set values)\n    {\n        this.values = values;\n    }\n\n    public static RDN getInstance(Object obj)\n    {\n        if (obj instanceof RDN)\n        {\n            return (RDN)obj;\n        }\n        else if (obj != null)\n        {\n            return new RDN(ASN1Set.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    /**\n     * Create a single valued RDN.\n     *\n     * @param oid RDN type.\n     * @param value RDN value.\n     */\n    public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value)\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(oid);\n        v.add(value);\n\n        this.values = new DERSet(new DERSequence(v));\n    }\n\n    public RDN(AttributeTypeAndValue attrTAndV)\n    {\n        this.values = new DERSet(attrTAndV);\n    }\n\n    /**\n     * Create a multi-valued RDN.\n     *\n     * @param aAndVs attribute type/value pairs making up the RDN\n     */\n    public RDN(AttributeTypeAndValue[] aAndVs)\n    {\n        this.values = new DERSet(aAndVs);\n    }\n\n    public boolean isMultiValued()\n    {\n        return this.values.size() > 1;\n    }\n\n    /**\n     * Return the number of AttributeTypeAndValue objects in this RDN,\n     *\n     * @return size of RDN, greater than 1 if multi-valued.\n     */\n    public int size()\n    {\n        return this.values.size();\n    }\n\n    public AttributeTypeAndValue getFirst()\n    {\n        if (this.values.size() == 0)\n        {\n            return null;\n        }\n\n        return AttributeTypeAndValue.getInstance(this.values.getObjectAt(0));\n    }\n\n    public AttributeTypeAndValue[] getTypesAndValues()\n    {\n        AttributeTypeAndValue[] tmp = new AttributeTypeAndValue[values.size()];\n\n        for (int i = 0; i != tmp.length; i++)\n        {\n            tmp[i] = AttributeTypeAndValue.getInstance(values.getObjectAt(i));\n        }\n\n        return tmp;\n    }\n\n    /**\n     * <pre>\n     * RelativeDistinguishedName ::=\n     *                     SET OF AttributeTypeAndValue\n\n     * AttributeTypeAndValue ::= SEQUENCE {\n     *        type     AttributeType,\n     *        value    AttributeValue }\n     * </pre>\n     * @return this object as an ASN1Primitive type\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        return values;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/X500Name.java",
    "content": "package local.org.bouncycastle.asn1.x500;\n\nimport java.util.Enumeration;\n\nimport local.org.bouncycastle.asn1.ASN1Choice;\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.x500.style.BCStyle;\n\n\n/**\n * <pre>\n *     Name ::= CHOICE {\n *                       RDNSequence }\n *\n *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName\n *\n *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue\n *\n *     AttributeTypeAndValue ::= SEQUENCE {\n *                                   type  OBJECT IDENTIFIER,\n *                                   value ANY }\n * </pre>\n */\npublic class X500Name\n    extends ASN1Object\n    implements ASN1Choice\n{\n    private static X500NameStyle    defaultStyle = BCStyle.INSTANCE;\n\n    private boolean                 isHashCodeCalculated;\n    private int                     hashCodeValue;\n\n    private X500NameStyle style;\n    private RDN[] rdns;\n\n    public X500Name(X500NameStyle style, X500Name name)\n    {\n        this.rdns = name.rdns;\n        this.style = style;\n    }\n\n    /**\n     * Return a X500Name based on the passed in tagged object.\n     * \n     * @param obj tag object holding name.\n     * @param explicit true if explicitly tagged false otherwise.\n     * @return the X500Name\n     */\n    public static X500Name getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        // must be true as choice item\n        return getInstance(ASN1Sequence.getInstance(obj, true));\n    }\n\n    public static X500Name getInstance(\n        Object  obj)\n    {\n        if (obj instanceof X500Name)\n        {\n            return (X500Name)obj;\n        }\n        else if (obj != null)\n        {\n            return new X500Name(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static X500Name getInstance(\n        X500NameStyle style,\n        Object        obj)\n    {\n        if (obj instanceof X500Name)\n        {\n            return getInstance(style, ((X500Name)obj).toASN1Primitive());\n        }\n        else if (obj != null)\n        {\n            return new X500Name(style, ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    /**\n     * Constructor from ASN1Sequence\n     *\n     * the principal will be a list of constructed sets, each containing an (OID, String) pair.\n     */\n    private X500Name(\n        ASN1Sequence  seq)\n    {\n        this(defaultStyle, seq);\n    }\n\n    private X500Name(\n        X500NameStyle style,\n        ASN1Sequence  seq)\n    {\n        this.style = style;\n        this.rdns = new RDN[seq.size()];\n\n        int index = 0;\n\n        for (Enumeration e = seq.getObjects(); e.hasMoreElements();)\n        {\n            rdns[index++] = RDN.getInstance(e.nextElement());\n        }\n    }\n\n    public X500Name(\n        RDN[] rDNs)\n    {\n        this(defaultStyle, rDNs);\n    }\n\n    public X500Name(\n        X500NameStyle style,\n        RDN[]         rDNs)\n    {\n        this.rdns = rDNs;\n        this.style = style;\n    }\n\n    public X500Name(\n        String dirName)\n    {\n        this(defaultStyle, dirName);\n    }\n\n    public X500Name(\n        X500NameStyle style,\n        String        dirName)\n    {\n        this(style.fromString(dirName));\n\n        this.style = style;\n    }\n\n    /**\n     * return an array of RDNs in structure order.\n     *\n     * @return an array of RDN objects.\n     */\n    public RDN[] getRDNs()\n    {\n        RDN[] tmp = new RDN[this.rdns.length];\n\n        System.arraycopy(rdns, 0, tmp, 0, tmp.length);\n\n        return tmp;\n    }\n\n    /**\n     * return an array of OIDs contained in the attribute type of each RDN in structure order.\n     *\n     * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects.\n     */\n    public ASN1ObjectIdentifier[] getAttributeTypes()\n    {\n        int   count = 0;\n\n        for (int i = 0; i != rdns.length; i++)\n        {\n            RDN rdn = rdns[i];\n\n            count += rdn.size();\n        }\n\n        ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count];\n\n        count = 0;\n\n        for (int i = 0; i != rdns.length; i++)\n        {\n            RDN rdn = rdns[i];\n\n            if (rdn.isMultiValued())\n            {\n                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();\n                for (int j = 0; j != attr.length; j++)\n                {\n                    res[count++] = attr[j].getType();\n                }\n            }\n            else if (rdn.size() != 0)\n            {\n                res[count++] = rdn.getFirst().getType();\n            }\n        }\n\n        return res;\n    }\n\n    /**\n     * return an array of RDNs containing the attribute type given by OID in structure order.\n     *\n     * @param attributeType the type OID we are looking for.\n     * @return an array, possibly zero length, of RDN objects.\n     */\n    public RDN[] getRDNs(ASN1ObjectIdentifier attributeType)\n    {\n        RDN[] res = new RDN[rdns.length];\n        int   count = 0;\n\n        for (int i = 0; i != rdns.length; i++)\n        {\n            RDN rdn = rdns[i];\n\n            if (rdn.isMultiValued())\n            {\n                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();\n                for (int j = 0; j != attr.length; j++)\n                {\n                    if (attr[j].getType().equals(attributeType))\n                    {\n                        res[count++] = rdn;\n                        break;\n                    }\n                }\n            }\n            else\n            {\n                if (rdn.getFirst().getType().equals(attributeType))\n                {\n                    res[count++] = rdn;\n                }\n            }\n        }\n\n        RDN[] tmp = new RDN[count];\n\n        System.arraycopy(res, 0, tmp, 0, tmp.length);\n\n        return tmp;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return new DERSequence(rdns);\n    }\n\n    public int hashCode()\n    {\n        if (isHashCodeCalculated)\n        {\n            return hashCodeValue;\n        }\n\n        isHashCodeCalculated = true;\n\n        hashCodeValue = style.calculateHashCode(this);\n\n        return hashCodeValue;\n    }\n\n    /**\n     * test for equality - note: case is ignored.\n     */\n    public boolean equals(Object obj)\n    {\n        if (obj == this)\n        {\n            return true;\n        }\n\n        if (!(obj instanceof X500Name || obj instanceof ASN1Sequence))\n        {\n            return false;\n        }\n        \n        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();\n\n        if (this.toASN1Primitive().equals(derO))\n        {\n            return true;\n        }\n\n        try\n        {\n            return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive())));\n        }\n        catch (Exception e)\n        {\n            return false;\n        }\n    }\n    \n    public String toString()\n    {\n        return style.toString(this);\n    }\n\n    /**\n     * Set the default style for X500Name construction.\n     *\n     * @param style  an X500NameStyle\n     */\n    public static void setDefaultStyle(X500NameStyle style)\n    {\n        if (style == null)\n        {\n            throw new NullPointerException(\"cannot set style to null\");\n        }\n\n        defaultStyle = style;\n    }\n\n    /**\n     * Return the current default style.\n     *\n     * @return default style for X500Name construction.\n     */\n    public static X500NameStyle getDefaultStyle()\n    {\n        return defaultStyle;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/X500NameBuilder.java",
    "content": "package local.org.bouncycastle.asn1.x500;\n\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x500.style.BCStyle;\n\n\npublic class X500NameBuilder\n{\n    private X500NameStyle template;\n    private Vector rdns = new Vector();\n\n    public X500NameBuilder()\n    {\n        this(BCStyle.INSTANCE);\n    }\n\n    public X500NameBuilder(X500NameStyle template)\n    {\n        this.template = template;\n    }\n\n    public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value)\n    {\n        this.addRDN(oid, template.stringToValue(oid, value));\n\n        return this;\n    }\n\n    public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value)\n    {\n        rdns.addElement(new RDN(oid, value));\n\n        return this;\n    }\n\n    public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV)\n    {\n        rdns.addElement(new RDN(attrTAndV));\n\n        return this;\n    }\n\n    public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] values)\n    {\n        ASN1Encodable[] vals = new ASN1Encodable[values.length];\n\n        for (int i = 0; i != vals.length; i++)\n        {\n            vals[i] = template.stringToValue(oids[i], values[i]);\n        }\n\n        return addMultiValuedRDN(oids, vals);\n    }\n\n    public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, ASN1Encodable[] values)\n    {\n        AttributeTypeAndValue[] avs = new AttributeTypeAndValue[oids.length];\n\n        for (int i = 0; i != oids.length; i++)\n        {\n            avs[i] = new AttributeTypeAndValue(oids[i], values[i]);\n        }\n\n        return addMultiValuedRDN(avs);\n    }\n\n    public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs)\n    {\n        rdns.addElement(new RDN(attrTAndVs));\n\n        return this;\n    }\n\n    public X500Name build()\n    {\n        RDN[] vals = new RDN[rdns.size()];\n\n        for (int i = 0; i != vals.length; i++)\n        {\n            vals[i] = (RDN)rdns.elementAt(i);\n        }\n\n        return new X500Name(template, vals);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/X500NameStyle.java",
    "content": "package local.org.bouncycastle.asn1.x500;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\n/**\n * It turns out that the number of standard ways the fields in a DN should be \n * encoded into their ASN.1 counterparts is rapidly approaching the\n * number of machines on the internet. By default the X500Name class\n * will produce UTF8Strings in line with the current recommendations (RFC 3280).\n * <p>\n */\npublic interface X500NameStyle\n{\n    /**\n     * Convert the passed in String value into the appropriate ASN.1\n     * encoded object.\n     * \n     * @param oid the OID associated with the value in the DN.\n     * @param value the value of the particular DN component.\n     * @return the ASN.1 equivalent for the value.\n     */\n    ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value);\n\n    /**\n     * Return the OID associated with the passed in name.\n     *\n     * @param attrName the string to match.\n     * @return an OID\n     */\n    ASN1ObjectIdentifier attrNameToOID(String attrName);\n\n    /**\n     * Return an array of RDN generated from the passed in String.\n     * @param dirName  the String representation.\n     * @return  an array of corresponding RDNs.\n     */\n    RDN[] fromString(String dirName);\n\n    /**\n     * Return true if the two names are equal.\n     *\n     * @param name1 first name for comparison.\n     * @param name2 second name for comparison.\n     * @return true if name1 = name 2, false otherwise.\n     */\n    boolean areEqual(X500Name name1, X500Name name2);\n\n    /**\n     * Calculate a hashCode for the passed in name.\n     *\n     * @param name the name the hashCode is required for.\n     * @return the calculated hashCode.\n     */\n    int calculateHashCode(X500Name name);\n\n    /**\n     * Convert the passed in X500Name to a String.\n     * @param name the name to convert.\n     * @return a String representation.\n     */\n    String toString(X500Name name);\n\n    /**\n     * Return the display name for toString() associated with the OID.\n     *\n     * @param oid  the OID of interest.\n     * @return the name displayed in toString(), null if no mapping provided.\n     */\n    String oidToDisplayName(ASN1ObjectIdentifier oid);\n\n    /**\n     * Return the acceptable names in a String DN that map to OID.\n     *\n     * @param oid  the OID of interest.\n     * @return an array of String aliases for the OID, zero length if there are none.\n     */\n    String[] oidToAttrNames(ASN1ObjectIdentifier oid);\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/style/BCStyle.java",
    "content": "package local.org.bouncycastle.asn1.x500.style;\n\nimport java.io.IOException;\nimport java.util.Hashtable;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1GeneralizedTime;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.DERIA5String;\nimport local.org.bouncycastle.asn1.DERPrintableString;\nimport local.org.bouncycastle.asn1.DERUTF8String;\nimport local.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;\nimport local.org.bouncycastle.asn1.x500.AttributeTypeAndValue;\nimport local.org.bouncycastle.asn1.x500.RDN;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x500.X500NameStyle;\nimport local.org.bouncycastle.asn1.x509.X509ObjectIdentifiers;\n\n\npublic class BCStyle\n    implements X500NameStyle\n{\n    public static final X500NameStyle INSTANCE = new BCStyle();\n\n    /**\n     * country code - StringType(SIZE(2))\n     */\n    public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier(\"2.5.4.6\");\n\n    /**\n     * organization - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier(\"2.5.4.10\");\n\n    /**\n     * organizational unit name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier(\"2.5.4.11\");\n\n    /**\n     * Title\n     */\n    public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier(\"2.5.4.12\");\n\n    /**\n     * common name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier(\"2.5.4.3\");\n\n    /**\n     * device serial number name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier(\"2.5.4.5\");\n\n    /**\n     * street - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier(\"2.5.4.9\");\n\n    /**\n     * device serial number name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier SERIALNUMBER = SN;\n\n    /**\n     * locality name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier(\"2.5.4.7\");\n\n    /**\n     * state, or province name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier(\"2.5.4.8\");\n\n    /**\n     * Naming attributes of type X520name\n     */\n    public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier(\"2.5.4.4\");\n    public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier(\"2.5.4.42\");\n    public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier(\"2.5.4.43\");\n    public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier(\"2.5.4.44\");\n    public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier(\"2.5.4.45\");\n\n    /**\n     * businessCategory - DirectoryString(SIZE(1..128)\n     */\n    public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(\n        \"2.5.4.15\");\n\n    /**\n     * postalCode - DirectoryString(SIZE(1..40)\n     */\n    public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(\n        \"2.5.4.17\");\n\n    /**\n     * dnQualifier - DirectoryString(SIZE(1..64)\n     */\n    public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(\n        \"2.5.4.46\");\n\n    /**\n     * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)\n     */\n    public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(\n        \"2.5.4.65\");\n\n\n    /**\n     * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z\n     */\n    public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(\n        \"1.3.6.1.5.5.7.9.1\");\n\n    /**\n     * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)\n     */\n    public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier(\n        \"1.3.6.1.5.5.7.9.2\");\n\n    /**\n     * RFC 3039 Gender - PrintableString (SIZE(1)) -- \"M\", \"F\", \"m\" or \"f\"\n     */\n    public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier(\n        \"1.3.6.1.5.5.7.9.3\");\n\n    /**\n     * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166\n     * codes only\n     */\n    public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier(\n        \"1.3.6.1.5.5.7.9.4\");\n\n    /**\n     * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166\n     * codes only\n     */\n    public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier(\n        \"1.3.6.1.5.5.7.9.5\");\n\n\n    /**\n     * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)\n     */\n    public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier(\"1.3.36.8.3.14\");\n\n    /**\n     * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF\n     * DirectoryString(SIZE(1..30))\n     */\n    public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier(\"2.5.4.16\");\n\n    /**\n     * RFC 2256 dmdName\n     */\n    public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier(\"2.5.4.54\");\n\n    /**\n     * id-at-telephoneNumber\n     */\n    public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;\n\n    /**\n     * id-at-name\n     */\n    public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;\n\n    /**\n     * Email address (RSA PKCS#9 extension) - IA5String.\n     * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.\n     */\n    public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;\n\n    /**\n     * more from PKCS#9\n     */\n    public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;\n    public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;\n\n    /**\n     * email address in Verisign certificates\n     */\n    public static final ASN1ObjectIdentifier E = EmailAddress;\n\n    /*\n    * others...\n    */\n    public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier(\"0.9.2342.19200300.100.1.25\");\n\n    /**\n     * LDAP User id.\n     */\n    public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier(\"0.9.2342.19200300.100.1.1\");\n\n    /**\n     * default look up table translating OID values into their common symbols following\n     * the convention in RFC 2253 with a few extras\n     */\n    private static final Hashtable DefaultSymbols = new Hashtable();\n\n    /**\n     * look up table translating common symbols into their OIDS.\n     */\n    private static final Hashtable DefaultLookUp = new Hashtable();\n\n    static\n    {\n        DefaultSymbols.put(C, \"C\");\n        DefaultSymbols.put(O, \"O\");\n        DefaultSymbols.put(T, \"T\");\n        DefaultSymbols.put(OU, \"OU\");\n        DefaultSymbols.put(CN, \"CN\");\n        DefaultSymbols.put(L, \"L\");\n        DefaultSymbols.put(ST, \"ST\");\n        DefaultSymbols.put(SN, \"SERIALNUMBER\");\n        DefaultSymbols.put(EmailAddress, \"E\");\n        DefaultSymbols.put(DC, \"DC\");\n        DefaultSymbols.put(UID, \"UID\");\n        DefaultSymbols.put(STREET, \"STREET\");\n        DefaultSymbols.put(SURNAME, \"SURNAME\");\n        DefaultSymbols.put(GIVENNAME, \"GIVENNAME\");\n        DefaultSymbols.put(INITIALS, \"INITIALS\");\n        DefaultSymbols.put(GENERATION, \"GENERATION\");\n        DefaultSymbols.put(UnstructuredAddress, \"unstructuredAddress\");\n        DefaultSymbols.put(UnstructuredName, \"unstructuredName\");\n        DefaultSymbols.put(UNIQUE_IDENTIFIER, \"UniqueIdentifier\");\n        DefaultSymbols.put(DN_QUALIFIER, \"DN\");\n        DefaultSymbols.put(PSEUDONYM, \"Pseudonym\");\n        DefaultSymbols.put(POSTAL_ADDRESS, \"PostalAddress\");\n        DefaultSymbols.put(NAME_AT_BIRTH, \"NameAtBirth\");\n        DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, \"CountryOfCitizenship\");\n        DefaultSymbols.put(COUNTRY_OF_RESIDENCE, \"CountryOfResidence\");\n        DefaultSymbols.put(GENDER, \"Gender\");\n        DefaultSymbols.put(PLACE_OF_BIRTH, \"PlaceOfBirth\");\n        DefaultSymbols.put(DATE_OF_BIRTH, \"DateOfBirth\");\n        DefaultSymbols.put(POSTAL_CODE, \"PostalCode\");\n        DefaultSymbols.put(BUSINESS_CATEGORY, \"BusinessCategory\");\n        DefaultSymbols.put(TELEPHONE_NUMBER, \"TelephoneNumber\");\n        DefaultSymbols.put(NAME, \"Name\");\n\n        DefaultLookUp.put(\"c\", C);\n        DefaultLookUp.put(\"o\", O);\n        DefaultLookUp.put(\"t\", T);\n        DefaultLookUp.put(\"ou\", OU);\n        DefaultLookUp.put(\"cn\", CN);\n        DefaultLookUp.put(\"l\", L);\n        DefaultLookUp.put(\"st\", ST);\n        DefaultLookUp.put(\"sn\", SN);\n        DefaultLookUp.put(\"serialnumber\", SN);\n        DefaultLookUp.put(\"street\", STREET);\n        DefaultLookUp.put(\"emailaddress\", E);\n        DefaultLookUp.put(\"dc\", DC);\n        DefaultLookUp.put(\"e\", E);\n        DefaultLookUp.put(\"uid\", UID);\n        DefaultLookUp.put(\"surname\", SURNAME);\n        DefaultLookUp.put(\"givenname\", GIVENNAME);\n        DefaultLookUp.put(\"initials\", INITIALS);\n        DefaultLookUp.put(\"generation\", GENERATION);\n        DefaultLookUp.put(\"unstructuredaddress\", UnstructuredAddress);\n        DefaultLookUp.put(\"unstructuredname\", UnstructuredName);\n        DefaultLookUp.put(\"uniqueidentifier\", UNIQUE_IDENTIFIER);\n        DefaultLookUp.put(\"dn\", DN_QUALIFIER);\n        DefaultLookUp.put(\"pseudonym\", PSEUDONYM);\n        DefaultLookUp.put(\"postaladdress\", POSTAL_ADDRESS);\n        DefaultLookUp.put(\"nameofbirth\", NAME_AT_BIRTH);\n        DefaultLookUp.put(\"countryofcitizenship\", COUNTRY_OF_CITIZENSHIP);\n        DefaultLookUp.put(\"countryofresidence\", COUNTRY_OF_RESIDENCE);\n        DefaultLookUp.put(\"gender\", GENDER);\n        DefaultLookUp.put(\"placeofbirth\", PLACE_OF_BIRTH);\n        DefaultLookUp.put(\"dateofbirth\", DATE_OF_BIRTH);\n        DefaultLookUp.put(\"postalcode\", POSTAL_CODE);\n        DefaultLookUp.put(\"businesscategory\", BUSINESS_CATEGORY);\n        DefaultLookUp.put(\"telephonenumber\", TELEPHONE_NUMBER);\n        DefaultLookUp.put(\"name\", NAME);\n    }\n\n    protected BCStyle()\n    {\n\n    }\n    \n    public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)\n    {\n        if (value.length() != 0 && value.charAt(0) == '#')\n        {\n            try\n            {\n                return IETFUtils.valueFromHexString(value, 1);\n            }\n            catch (IOException e)\n            {\n                throw new RuntimeException(\"can't recode value for oid \" + oid.getId());\n            }\n        }\n        else\n        {\n            if (value.length() != 0 && value.charAt(0) == '\\\\')\n            {\n                value = value.substring(1);\n            }\n            if (oid.equals(EmailAddress) || oid.equals(DC))\n            {\n                return new DERIA5String(value);\n            }\n            else if (oid.equals(DATE_OF_BIRTH))  // accept time string as well as # (for compatibility)\n            {\n                return new ASN1GeneralizedTime(value);\n            }\n            else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)\n                || oid.equals(TELEPHONE_NUMBER))\n            {\n                return new DERPrintableString(value);\n            }\n        }\n\n        return new DERUTF8String(value);\n    }\n\n    public String oidToDisplayName(ASN1ObjectIdentifier oid)\n    {\n        return (String)DefaultSymbols.get(oid);\n    }\n\n    public String[] oidToAttrNames(ASN1ObjectIdentifier oid)\n    {\n        return IETFUtils.findAttrNamesForOID(oid, DefaultLookUp);\n    }\n\n    public ASN1ObjectIdentifier attrNameToOID(String attrName)\n    {\n        return IETFUtils.decodeAttrName(attrName, DefaultLookUp);\n    }\n\n    public boolean areEqual(X500Name name1, X500Name name2)\n    {\n        RDN[] rdns1 = name1.getRDNs();\n        RDN[] rdns2 = name2.getRDNs();\n\n        if (rdns1.length != rdns2.length)\n        {\n            return false;\n        }\n\n        boolean reverse = false;\n\n        if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)\n        {\n            reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType());  // guess forward\n        }\n\n        for (int i = 0; i != rdns1.length; i++)\n        {\n            if (!foundMatch(reverse, rdns1[i], rdns2))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)\n    {\n        if (reverse)\n        {\n            for (int i = possRDNs.length - 1; i >= 0; i--)\n            {\n                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))\n                {\n                    possRDNs[i] = null;\n                    return true;\n                }\n            }\n        }\n        else\n        {\n            for (int i = 0; i != possRDNs.length; i++)\n            {\n                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))\n                {\n                    possRDNs[i] = null;\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)\n    {\n        return IETFUtils.rDNAreEqual(rdn1, rdn2);\n    }\n\n    public RDN[] fromString(String dirName)\n    {\n        return IETFUtils.rDNsFromString(dirName, this);\n    }\n\n    public int calculateHashCode(X500Name name)\n    {\n        int hashCodeValue = 0;\n        RDN[] rdns = name.getRDNs();\n\n        // this needs to be order independent, like equals\n        for (int i = 0; i != rdns.length; i++)\n        {\n            if (rdns[i].isMultiValued())\n            {\n                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();\n\n                for (int j = 0; j != atv.length; j++)\n                {\n                    hashCodeValue ^= atv[j].getType().hashCode();\n                    hashCodeValue ^= calcHashCode(atv[j].getValue());\n                }\n            }\n            else\n            {\n                hashCodeValue ^= rdns[i].getFirst().getType().hashCode();\n                hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());\n            }\n        }\n\n        return hashCodeValue;\n    }\n\n    private int calcHashCode(ASN1Encodable enc)\n    {\n        String value = IETFUtils.valueToString(enc);\n\n        value = IETFUtils.canonicalize(value);\n\n        return value.hashCode();\n    }\n\n    public String toString(X500Name name)\n    {\n        StringBuffer buf = new StringBuffer();\n        boolean first = true;\n\n        RDN[] rdns = name.getRDNs();\n\n        for (int i = 0; i < rdns.length; i++)\n        {\n            if (first)\n            {\n                first = false;\n            }\n            else\n            {\n                buf.append(',');\n            }\n\n            IETFUtils.appendRDN(buf, rdns[i], DefaultSymbols);\n        }\n\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/style/IETFUtils.java",
    "content": "package local.org.bouncycastle.asn1.x500.style;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Encoding;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1String;\nimport local.org.bouncycastle.asn1.DERUniversalString;\nimport local.org.bouncycastle.asn1.x500.AttributeTypeAndValue;\nimport local.org.bouncycastle.asn1.x500.RDN;\nimport local.org.bouncycastle.asn1.x500.X500NameBuilder;\nimport local.org.bouncycastle.asn1.x500.X500NameStyle;\nimport local.org.bouncycastle.util.Strings;\nimport local.org.bouncycastle.util.encoders.Hex;\n\n\npublic class IETFUtils\n{\n    private static String unescape(String elt)\n    {\n        if (elt.length() == 0 || (elt.indexOf('\\\\') < 0 && elt.indexOf('\"') < 0))\n        {\n            return elt.trim();\n        }\n\n        char[] elts = elt.toCharArray();\n        boolean escaped = false;\n        boolean quoted = false;\n        StringBuffer buf = new StringBuffer(elt.length());\n        int start = 0;\n\n        // if it's an escaped hash string and not an actual encoding in string form\n        // we need to leave it escaped.\n        if (elts[0] == '\\\\')\n        {\n            if (elts[1] == '#')\n            {\n                start = 2;\n                buf.append(\"\\\\#\");\n            }\n        }\n\n        boolean nonWhiteSpaceEncountered = false;\n        int     lastEscaped = 0;\n        char    hex1 = 0;\n\n        for (int i = start; i != elts.length; i++)\n        {\n            char c = elts[i];\n\n            if (c != ' ')\n            {\n                nonWhiteSpaceEncountered = true;\n            }\n\n            if (c == '\"')\n            {\n                if (!escaped)\n                {\n                    quoted = !quoted;\n                }\n                else\n                {\n                    buf.append(c);\n                }\n                escaped = false;\n            }\n            else if (c == '\\\\' && !(escaped || quoted))\n            {\n                escaped = true;\n                lastEscaped = buf.length();\n            }\n            else\n            {\n                if (c == ' ' && !escaped && !nonWhiteSpaceEncountered)\n                {\n                    continue;\n                }\n                if (escaped && isHexDigit(c))\n                {\n                    if (hex1 != 0)\n                    {\n                        buf.append((char)(convertHex(hex1) * 16 + convertHex(c)));\n                        escaped = false;\n                        hex1 = 0;\n                        continue;\n                    }\n                    hex1 = c;\n                    continue;\n                }\n                buf.append(c);\n                escaped = false;\n            }\n        }\n\n        if (buf.length() > 0)\n        {\n            while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1))\n            {\n                buf.setLength(buf.length() - 1);\n            }\n        }\n\n        return buf.toString();\n    }\n\n    private static boolean isHexDigit(char c)\n    {\n        return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');\n    }\n\n    private static int convertHex(char c)\n    {\n        if ('0' <= c && c <= '9')\n        {\n            return c - '0';\n        }\n        if ('a' <= c && c <= 'f')\n        {\n            return c - 'a' + 10;\n        }\n        return c - 'A' + 10;\n    }\n\n    public static RDN[] rDNsFromString(String name, X500NameStyle x500Style)\n    {\n        X500NameTokenizer nTok = new X500NameTokenizer(name);\n        X500NameBuilder builder = new X500NameBuilder(x500Style);\n\n        while (nTok.hasMoreTokens())\n        {\n            String  token = nTok.nextToken();\n\n            if (token.indexOf('+') > 0)\n            {\n                X500NameTokenizer   pTok = new X500NameTokenizer(token, '+');\n                X500NameTokenizer   vTok = new X500NameTokenizer(pTok.nextToken(), '=');\n\n                String              attr = vTok.nextToken();\n\n                if (!vTok.hasMoreTokens())\n                {\n                    throw new IllegalArgumentException(\"badly formatted directory string\");\n                }\n\n                String               value = vTok.nextToken();\n                ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr.trim());\n\n                if (pTok.hasMoreTokens())\n                {\n                    Vector oids = new Vector();\n                    Vector values = new Vector();\n\n                    oids.addElement(oid);\n                    values.addElement(unescape(value));\n\n                    while (pTok.hasMoreTokens())\n                    {\n                        vTok = new X500NameTokenizer(pTok.nextToken(), '=');\n\n                        attr = vTok.nextToken();\n\n                        if (!vTok.hasMoreTokens())\n                        {\n                            throw new IllegalArgumentException(\"badly formatted directory string\");\n                        }\n\n                        value = vTok.nextToken();\n                        oid = x500Style.attrNameToOID(attr.trim());\n\n\n                        oids.addElement(oid);\n                        values.addElement(unescape(value));\n                    }\n\n                    builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values));\n                }\n                else\n                {\n                    builder.addRDN(oid, unescape(value));\n                }\n            }\n            else\n            {\n                X500NameTokenizer   vTok = new X500NameTokenizer(token, '=');\n\n                String              attr = vTok.nextToken();\n\n                if (!vTok.hasMoreTokens())\n                {\n                    throw new IllegalArgumentException(\"badly formatted directory string\");\n                }\n\n                String               value = vTok.nextToken();\n                ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr.trim());\n\n                builder.addRDN(oid, unescape(value));\n            }\n        }\n\n        return builder.build().getRDNs();\n    }\n\n    private static String[] toValueArray(Vector values)\n    {\n        String[] tmp = new String[values.size()];\n\n        for (int i = 0; i != tmp.length; i++)\n        {\n            tmp[i] = (String)values.elementAt(i);\n        }\n\n        return tmp;\n    }\n\n    private static ASN1ObjectIdentifier[] toOIDArray(Vector oids)\n    {\n        ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[oids.size()];\n\n        for (int i = 0; i != tmp.length; i++)\n        {\n            tmp[i] = (ASN1ObjectIdentifier)oids.elementAt(i);\n        }\n\n        return tmp;\n    }\n\n    public static String[] findAttrNamesForOID(\n        ASN1ObjectIdentifier oid,\n        Hashtable            lookup)\n    {\n        int count = 0;\n        for (Enumeration en = lookup.elements(); en.hasMoreElements();)\n        {\n            if (oid.equals(en.nextElement()))\n            {\n                count++;\n            }\n        }\n\n        String[] aliases = new String[count];\n        count = 0;\n\n        for (Enumeration en = lookup.keys(); en.hasMoreElements();)\n        {\n            String key = (String)en.nextElement();\n            if (oid.equals(lookup.get(key)))\n            {\n                aliases[count++] = key;\n            }\n        }\n\n        return aliases;\n    }\n\n    public static ASN1ObjectIdentifier decodeAttrName(\n        String      name,\n        Hashtable   lookUp)\n    {\n        if (Strings.toUpperCase(name).startsWith(\"OID.\"))\n        {\n            return new ASN1ObjectIdentifier(name.substring(4));\n        }\n        else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')\n        {\n            return new ASN1ObjectIdentifier(name);\n        }\n\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));\n        if (oid == null)\n        {\n            throw new IllegalArgumentException(\"Unknown object id - \" + name + \" - passed to distinguished name\");\n        }\n\n        return oid;\n    }\n\n    public static ASN1Encodable valueFromHexString(\n        String  str,\n        int     off)\n        throws IOException\n    {\n        byte[] data = new byte[(str.length() - off) / 2];\n        for (int index = 0; index != data.length; index++)\n        {\n            char left = str.charAt((index * 2) + off);\n            char right = str.charAt((index * 2) + off + 1);\n\n            data[index] = (byte)((convertHex(left) << 4) | convertHex(right));\n        }\n\n        return ASN1Primitive.fromByteArray(data);\n    }\n\n    public static void appendRDN(\n        StringBuffer          buf,\n        RDN                   rdn,\n        Hashtable             oidSymbols)\n    {\n        if (rdn.isMultiValued())\n        {\n            AttributeTypeAndValue[] atv = rdn.getTypesAndValues();\n            boolean firstAtv = true;\n\n            for (int j = 0; j != atv.length; j++)\n            {\n                if (firstAtv)\n                {\n                    firstAtv = false;\n                }\n                else\n                {\n                    buf.append('+');\n                }\n\n                IETFUtils.appendTypeAndValue(buf, atv[j], oidSymbols);\n            }\n        }\n        else\n        {\n            IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols);\n        }\n    }\n\n    public static void appendTypeAndValue(\n        StringBuffer          buf,\n        AttributeTypeAndValue typeAndValue,\n        Hashtable             oidSymbols)\n    {\n        String  sym = (String)oidSymbols.get(typeAndValue.getType());\n\n        if (sym != null)\n        {\n            buf.append(sym);\n        }\n        else\n        {\n            buf.append(typeAndValue.getType().getId());\n        }\n\n        buf.append('=');\n\n        buf.append(valueToString(typeAndValue.getValue()));\n    }\n\n    public static String valueToString(ASN1Encodable value)\n    {\n        StringBuffer vBuf = new StringBuffer();\n\n        if (value instanceof ASN1String && !(value instanceof DERUniversalString))\n        {\n            String v = ((ASN1String)value).getString();\n            if (v.length() > 0 && v.charAt(0) == '#')\n            {\n                vBuf.append(\"\\\\\" + v);\n            }\n            else\n            {\n                vBuf.append(v);\n            }\n        }\n        else\n        {\n            try\n            {\n                vBuf.append(\"#\" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"Other value has no encoded form\");\n            }\n        }\n\n        int     end = vBuf.length();\n        int     index = 0;\n\n        if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\\\' && vBuf.charAt(1) == '#')\n        {\n            index += 2;\n        }\n\n        while (index != end)\n        {\n            if ((vBuf.charAt(index) == ',')\n               || (vBuf.charAt(index) == '\"')\n               || (vBuf.charAt(index) == '\\\\')\n               || (vBuf.charAt(index) == '+')\n               || (vBuf.charAt(index) == '=')\n               || (vBuf.charAt(index) == '<')\n               || (vBuf.charAt(index) == '>')\n               || (vBuf.charAt(index) == ';'))\n            {\n                vBuf.insert(index, \"\\\\\");\n                index++;\n                end++;\n            }\n\n            index++;\n        }\n\n        int start = 0;\n        if (vBuf.length() > 0)\n        {\n            while (vBuf.charAt(start) == ' ')\n            {\n                vBuf.insert(start, \"\\\\\");\n                start += 2;\n            }\n        }\n\n        int endBuf = vBuf.length() - 1;\n\n        while (endBuf >= 0 && vBuf.charAt(endBuf) == ' ')\n        {\n            vBuf.insert(endBuf, '\\\\');\n            endBuf--;\n        }\n\n        return vBuf.toString();\n    }\n\n    private static String bytesToString(\n        byte[] data)\n    {\n        char[]  cs = new char[data.length];\n\n        for (int i = 0; i != cs.length; i++)\n        {\n            cs[i] = (char)(data[i] & 0xff);\n        }\n\n        return new String(cs);\n    }\n\n    public static String canonicalize(String s)\n    {\n        String value = Strings.toLowerCase(s.trim());\n\n        if (value.length() > 0 && value.charAt(0) == '#')\n        {\n            ASN1Primitive obj = decodeObject(value);\n\n            if (obj instanceof ASN1String)\n            {\n                value = Strings.toLowerCase(((ASN1String)obj).getString().trim());\n            }\n        }\n\n        value = stripInternalSpaces(value);\n\n        return value;\n    }\n\n    private static ASN1Primitive decodeObject(String oValue)\n    {\n        try\n        {\n            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"unknown encoding in name: \" + e);\n        }\n    }\n\n    public static String stripInternalSpaces(\n        String str)\n    {\n        StringBuffer res = new StringBuffer();\n\n        if (str.length() != 0)\n        {\n            char c1 = str.charAt(0);\n\n            res.append(c1);\n\n            for (int k = 1; k < str.length(); k++)\n            {\n                char c2 = str.charAt(k);\n                if (!(c1 == ' ' && c2 == ' '))\n                {\n                    res.append(c2);\n                }\n                c1 = c2;\n            }\n        }\n\n        return res.toString();\n    }\n\n    public static boolean rDNAreEqual(RDN rdn1, RDN rdn2)\n    {\n        if (rdn1.isMultiValued())\n        {\n            if (rdn2.isMultiValued())\n            {\n                AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues();\n                AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues();\n\n                if (atvs1.length != atvs2.length)\n                {\n                    return false;\n                }\n\n                for (int i = 0; i != atvs1.length; i++)\n                {\n                    if (!atvAreEqual(atvs1[i], atvs2[i]))\n                    {\n                        return false;\n                    }\n                }\n            }\n            else\n            {\n                return false;\n            }\n        }\n        else\n        {\n            if (!rdn2.isMultiValued())\n            {\n                return atvAreEqual(rdn1.getFirst(), rdn2.getFirst());\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private static boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2)\n    {\n        if (atv1 == atv2)\n        {\n            return true;\n        }\n\n        if (atv1 == null)\n        {\n            return false;\n        }\n\n        if (atv2 == null)\n        {\n            return false;\n        }\n\n        ASN1ObjectIdentifier o1 = atv1.getType();\n        ASN1ObjectIdentifier o2 = atv2.getType();\n\n        if (!o1.equals(o2))\n        {\n            return false;\n        }\n\n        String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue()));\n        String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue()));\n\n        if (!v1.equals(v2))\n        {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java",
    "content": "package local.org.bouncycastle.asn1.x500.style;\n\n/**\n * class for breaking up an X500 Name into it's component tokens, ala\n * java.util.StringTokenizer. We need this class as some of the\n * lightweight Java environment don't support classes like\n * StringTokenizer.\n */\nclass X500NameTokenizer\n{\n    private String          value;\n    private int             index;\n    private char            separator;\n    private StringBuffer    buf = new StringBuffer();\n\n    public X500NameTokenizer(\n        String  oid)\n    {\n        this(oid, ',');\n    }\n    \n    public X500NameTokenizer(\n        String  oid,\n        char    separator)\n    {\n        this.value = oid;\n        this.index = -1;\n        this.separator = separator;\n    }\n\n    public boolean hasMoreTokens()\n    {\n        return (index != value.length());\n    }\n\n    public String nextToken()\n    {\n        if (index == value.length())\n        {\n            return null;\n        }\n\n        int     end = index + 1;\n        boolean quoted = false;\n        boolean escaped = false;\n\n        buf.setLength(0);\n\n        while (end != value.length())\n        {\n            char    c = value.charAt(end);\n\n            if (c == '\"')\n            {\n                if (!escaped)\n                {\n                    quoted = !quoted;\n                }\n                buf.append(c);\n                escaped = false;\n            }\n            else\n            {\n                if (escaped || quoted)\n                {\n                    buf.append(c);\n                    escaped = false;\n                }\n                else if (c == '\\\\')\n                {\n                    buf.append(c);\n                    escaped = true;\n                }\n                else if (c == separator)\n                {\n                    break;\n                }\n                else\n                {\n                    buf.append(c);\n                }\n            }\n            end++;\n        }\n\n        index = end;\n\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERNull;\nimport local.org.bouncycastle.asn1.DERObjectIdentifier;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class AlgorithmIdentifier\n    extends ASN1Object\n{\n    private ASN1ObjectIdentifier objectId;\n    private ASN1Encodable       parameters;\n    private boolean             parametersDefined = false;\n\n    public static AlgorithmIdentifier getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n    \n    public static AlgorithmIdentifier getInstance(\n        Object  obj)\n    {\n        if (obj== null || obj instanceof AlgorithmIdentifier)\n        {\n            return (AlgorithmIdentifier)obj;\n        }\n\n        // TODO: delete\n        if (obj instanceof ASN1ObjectIdentifier)\n        {\n            return new AlgorithmIdentifier((ASN1ObjectIdentifier)obj);\n        }\n\n        // TODO: delete\n        if (obj instanceof String)\n        {\n            return new AlgorithmIdentifier((String)obj);\n        }\n\n        return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj));\n    }\n\n    public AlgorithmIdentifier(\n        ASN1ObjectIdentifier     objectId)\n    {\n        this.objectId = objectId;\n    }\n\n    /**\n     * @deprecated use ASN1ObjectIdentifier\n     * @param objectId\n     */\n    public AlgorithmIdentifier(\n        String     objectId)\n    {\n        this.objectId = new ASN1ObjectIdentifier(objectId);\n    }\n\n    /**\n     * @deprecated use ASN1ObjectIdentifier\n     * @param objectId\n     */\n    public AlgorithmIdentifier(\n        DERObjectIdentifier    objectId)\n    {\n        this.objectId = new ASN1ObjectIdentifier(objectId.getId());\n    }\n\n    /**\n     * @deprecated use ASN1ObjectIdentifier\n     * @param objectId\n     * @param parameters\n     */\n    public AlgorithmIdentifier(\n        DERObjectIdentifier objectId,\n        ASN1Encodable           parameters)\n    {\n        parametersDefined = true;\n        this.objectId = new ASN1ObjectIdentifier(objectId.getId());\n        this.parameters = parameters;\n    }\n\n    public AlgorithmIdentifier(\n        ASN1ObjectIdentifier     objectId,\n        ASN1Encodable           parameters)\n    {\n        parametersDefined = true;\n        this.objectId = objectId;\n        this.parameters = parameters;\n    }\n\n    /**\n     * @deprecated use AlgorithmIdentifier.getInstance()\n     * @param seq\n     */\n    public AlgorithmIdentifier(\n        ASN1Sequence   seq)\n    {\n        if (seq.size() < 1 || seq.size() > 2)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \"\n                    + seq.size());\n        }\n        \n        objectId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));\n\n        if (seq.size() == 2)\n        {\n            parametersDefined = true;\n            parameters = seq.getObjectAt(1);\n        }\n        else\n        {\n            parameters = null;\n        }\n    }\n\n    public ASN1ObjectIdentifier getAlgorithm()\n    {\n        return new ASN1ObjectIdentifier(objectId.getId());\n    }\n\n    /**\n     * @deprecated use getAlgorithm\n     * @return\n     */\n    public ASN1ObjectIdentifier getObjectId()\n    {\n        return objectId;\n    }\n\n    public ASN1Encodable getParameters()\n    {\n        return parameters;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *      AlgorithmIdentifier ::= SEQUENCE {\n     *                            algorithm OBJECT IDENTIFIER,\n     *                            parameters ANY DEFINED BY algorithm OPTIONAL }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(objectId);\n\n        if (parametersDefined)\n        {\n            if (parameters != null)\n            {\n                v.add(parameters);\n            }\n            else\n            {\n                v.add(DERNull.INSTANCE);\n            }\n        }\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/AttCertIssuer.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Choice;\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\n\npublic class AttCertIssuer\n    extends ASN1Object\n    implements ASN1Choice\n{\n    ASN1Encodable   obj;\n    ASN1Primitive choiceObj;\n    \n    public static AttCertIssuer getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof AttCertIssuer)\n        {\n            return (AttCertIssuer)obj;\n        }\n        else if (obj instanceof V2Form)\n        {\n            return new AttCertIssuer(V2Form.getInstance(obj));\n        }\n        else if (obj instanceof GeneralNames)\n        {\n            return new AttCertIssuer((GeneralNames)obj);\n        }\n        else if (obj instanceof ASN1TaggedObject)\n        {\n            return new AttCertIssuer(V2Form.getInstance((ASN1TaggedObject)obj, false));\n        }\n        else if (obj instanceof ASN1Sequence)\n        {\n            return new AttCertIssuer(GeneralNames.getInstance(obj));\n        }\n\n        throw new IllegalArgumentException(\"unknown object in factory: \" + obj.getClass().getName());\n    }\n    \n    public static AttCertIssuer getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(obj.getObject()); // must be explicitly tagged\n    }\n\n    /**\n     * Don't use this one if you are trying to be RFC 3281 compliant.\n     * Use it for v1 attribute certificates only.\n     * \n     * @param names our GeneralNames structure\n     */\n    public AttCertIssuer(\n        GeneralNames  names)\n    {\n        obj = names;\n        choiceObj = obj.toASN1Primitive();\n    }\n    \n    public AttCertIssuer(\n        V2Form  v2Form)\n    {\n        obj = v2Form;\n        choiceObj = new DERTaggedObject(false, 0, obj);\n    }\n\n    public ASN1Encodable getIssuer()\n    {\n        return obj;\n    }\n    \n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  AttCertIssuer ::= CHOICE {\n     *       v1Form   GeneralNames,  -- MUST NOT be used in this\n     *                               -- profile\n     *       v2Form   [0] V2Form     -- v2 only\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        return choiceObj;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1GeneralizedTime;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class AttCertValidityPeriod\n    extends ASN1Object\n{\n    ASN1GeneralizedTime  notBeforeTime;\n    ASN1GeneralizedTime  notAfterTime;\n\n    public static AttCertValidityPeriod getInstance(\n            Object  obj)\n    {\n        if (obj instanceof AttCertValidityPeriod)\n        {\n            return (AttCertValidityPeriod)obj;\n        }\n        else if (obj != null)\n        {\n            return new AttCertValidityPeriod(ASN1Sequence.getInstance(obj));\n        }\n        \n        return null;\n    }\n    \n    private AttCertValidityPeriod(\n        ASN1Sequence    seq)\n    {\n        if (seq.size() != 2)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \"\n                    + seq.size());\n        }\n\n        notBeforeTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0));\n        notAfterTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(1));\n    }\n\n    /**\n     * @param notBeforeTime\n     * @param notAfterTime\n     */\n    public AttCertValidityPeriod(\n        ASN1GeneralizedTime notBeforeTime,\n        ASN1GeneralizedTime notAfterTime)\n    {\n        this.notBeforeTime = notBeforeTime;\n        this.notAfterTime = notAfterTime;\n    }\n\n    public ASN1GeneralizedTime getNotBeforeTime()\n    {\n        return notBeforeTime;\n    }\n\n    public ASN1GeneralizedTime getNotAfterTime()\n    {\n        return notAfterTime;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  AttCertValidityPeriod  ::= SEQUENCE {\n     *       notBeforeTime  GeneralizedTime,\n     *       notAfterTime   GeneralizedTime\n     *  } \n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(notBeforeTime);\n        v.add(notAfterTime);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/Attribute.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1Set;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class Attribute\n    extends ASN1Object\n{\n    private ASN1ObjectIdentifier attrType;\n    private ASN1Set             attrValues;\n\n    /**\n     * return an Attribute object from the given object.\n     *\n     * @param o the object we want converted.\n     * @exception IllegalArgumentException if the object cannot be converted.\n     */\n    public static Attribute getInstance(\n        Object o)\n    {\n        if (o instanceof Attribute)\n        {\n            return (Attribute)o;\n        }\n        \n        if (o != null)\n        {\n            return new Attribute(ASN1Sequence.getInstance(o));\n        }\n\n        return null;\n    }\n    \n    private Attribute(\n        ASN1Sequence seq)\n    {\n        if (seq.size() != 2)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n        }\n\n        attrType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));\n        attrValues = ASN1Set.getInstance(seq.getObjectAt(1));\n    }\n\n    public Attribute(\n        ASN1ObjectIdentifier attrType,\n        ASN1Set             attrValues)\n    {\n        this.attrType = attrType;\n        this.attrValues = attrValues;\n    }\n\n    public ASN1ObjectIdentifier getAttrType()\n    {\n        return new ASN1ObjectIdentifier(attrType.getId());\n    }\n\n    public ASN1Encodable[] getAttributeValues()\n    {\n        return attrValues.toArray();\n    }\n\n    public ASN1Set getAttrValues()\n    {\n        return attrValues;\n    }\n\n    /** \n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     * Attribute ::= SEQUENCE {\n     *     attrType OBJECT IDENTIFIER,\n     *     attrValues SET OF AttributeValue\n     * }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(attrType);\n        v.add(attrValues);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/AttributeCertificate.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class AttributeCertificate\n    extends ASN1Object\n{\n    AttributeCertificateInfo    acinfo;\n    AlgorithmIdentifier         signatureAlgorithm;\n    DERBitString                signatureValue;\n\n    /**\n     * @param obj\n     * @return an AttributeCertificate object\n     */\n    public static AttributeCertificate getInstance(Object obj)\n    {\n        if (obj instanceof AttributeCertificate)\n        {\n            return (AttributeCertificate)obj;\n        }\n        else if (obj != null)\n        {\n            return new AttributeCertificate(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n    \n    public AttributeCertificate(\n        AttributeCertificateInfo    acinfo,\n        AlgorithmIdentifier         signatureAlgorithm,\n        DERBitString                signatureValue)\n    {\n        this.acinfo = acinfo;\n        this.signatureAlgorithm = signatureAlgorithm;\n        this.signatureValue = signatureValue;\n    }\n    \n    public AttributeCertificate(\n        ASN1Sequence    seq)\n    {\n        if (seq.size() != 3)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \"\n                    + seq.size());\n        }\n\n        this.acinfo = AttributeCertificateInfo.getInstance(seq.getObjectAt(0));\n        this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));\n        this.signatureValue = DERBitString.getInstance(seq.getObjectAt(2));\n    }\n    \n    public AttributeCertificateInfo getAcinfo()\n    {\n        return acinfo;\n    }\n\n    public AlgorithmIdentifier getSignatureAlgorithm()\n    {\n        return signatureAlgorithm;\n    }\n\n    public DERBitString getSignatureValue()\n    {\n        return signatureValue;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  AttributeCertificate ::= SEQUENCE {\n     *       acinfo               AttributeCertificateInfo,\n     *       signatureAlgorithm   AlgorithmIdentifier,\n     *       signatureValue       BIT STRING\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(acinfo);\n        v.add(signatureAlgorithm);\n        v.add(signatureValue);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class AttributeCertificateInfo\n    extends ASN1Object\n{\n    private ASN1Integer              version;\n    private Holder                  holder;\n    private AttCertIssuer           issuer;\n    private AlgorithmIdentifier     signature;\n    private ASN1Integer              serialNumber;\n    private AttCertValidityPeriod   attrCertValidityPeriod;\n    private ASN1Sequence            attributes;\n    private DERBitString            issuerUniqueID;\n    private Extensions              extensions;\n\n    public static AttributeCertificateInfo getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static AttributeCertificateInfo getInstance(\n        Object  obj)\n    {\n        if (obj instanceof AttributeCertificateInfo)\n        {\n            return (AttributeCertificateInfo)obj;\n        }\n        else if (obj != null)\n        {\n            return new AttributeCertificateInfo(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    private AttributeCertificateInfo(\n        ASN1Sequence   seq)\n    {\n        if (seq.size() < 7 || seq.size() > 9)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n        }\n\n        this.version = ASN1Integer.getInstance(seq.getObjectAt(0));\n        this.holder = Holder.getInstance(seq.getObjectAt(1));\n        this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2));\n        this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3));\n        this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4));\n        this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5));\n        this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6));\n        \n        for (int i = 7; i < seq.size(); i++)\n        {\n            ASN1Encodable    obj = (ASN1Encodable)seq.getObjectAt(i);\n\n            if (obj instanceof DERBitString)\n            {\n                this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i));\n            }\n            else if (obj instanceof ASN1Sequence || obj instanceof Extensions)\n            {\n                this.extensions = Extensions.getInstance(seq.getObjectAt(i));\n            }\n        }\n    }\n    \n    public ASN1Integer getVersion()\n    {\n        return version;\n    }\n\n    public Holder getHolder()\n    {\n        return holder;\n    }\n\n    public AttCertIssuer getIssuer()\n    {\n        return issuer;\n    }\n\n    public AlgorithmIdentifier getSignature()\n    {\n        return signature;\n    }\n\n    public ASN1Integer getSerialNumber()\n    {\n        return serialNumber;\n    }\n\n    public AttCertValidityPeriod getAttrCertValidityPeriod()\n    {\n        return attrCertValidityPeriod;\n    }\n\n    public ASN1Sequence getAttributes()\n    {\n        return attributes;\n    }\n\n    public DERBitString getIssuerUniqueID()\n    {\n        return issuerUniqueID;\n    }\n\n    public Extensions getExtensions()\n    {\n        return extensions;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  AttributeCertificateInfo ::= SEQUENCE {\n     *       version              AttCertVersion -- version is v2,\n     *       holder               Holder,\n     *       issuer               AttCertIssuer,\n     *       signature            AlgorithmIdentifier,\n     *       serialNumber         CertificateSerialNumber,\n     *       attrCertValidityPeriod   AttCertValidityPeriod,\n     *       attributes           SEQUENCE OF Attribute,\n     *       issuerUniqueID       UniqueIdentifier OPTIONAL,\n     *       extensions           Extensions OPTIONAL\n     *  }\n     *\n     *  AttCertVersion ::= INTEGER { v2(1) }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(version);\n        v.add(holder);\n        v.add(issuer);\n        v.add(signature);\n        v.add(serialNumber);\n        v.add(attrCertValidityPeriod);\n        v.add(attributes);\n        \n        if (issuerUniqueID != null)\n        {\n            v.add(issuerUniqueID);\n        }\n        \n        if (extensions != null)\n        {\n            v.add(extensions);\n        }\n        \n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.math.BigInteger;\nimport java.util.Enumeration;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.crypto.Digest;\nimport local.org.bouncycastle.crypto.digests.SHA1Digest;\n\n\n/**\n * The AuthorityKeyIdentifier object.\n * <pre>\n * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }\n *\n *   AuthorityKeyIdentifier ::= SEQUENCE {\n *      keyIdentifier             [0] IMPLICIT KeyIdentifier           OPTIONAL,\n *      authorityCertIssuer       [1] IMPLICIT GeneralNames            OPTIONAL,\n *      authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL  }\n *\n *   KeyIdentifier ::= OCTET STRING\n * </pre>\n *\n */\npublic class AuthorityKeyIdentifier\n    extends ASN1Object\n{\n    ASN1OctetString keyidentifier=null;\n    GeneralNames certissuer=null;\n    ASN1Integer certserno=null;\n\n    public static AuthorityKeyIdentifier getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static AuthorityKeyIdentifier getInstance(\n        Object  obj)\n    {\n        if (obj instanceof AuthorityKeyIdentifier)\n        {\n            return (AuthorityKeyIdentifier)obj;\n        }\n        if (obj != null)\n        {\n            return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static AuthorityKeyIdentifier fromExtensions(Extensions extensions)\n    {\n         return AuthorityKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.authorityKeyIdentifier));\n    }\n\n    protected AuthorityKeyIdentifier(\n        ASN1Sequence   seq)\n    {\n        Enumeration     e = seq.getObjects();\n\n        while (e.hasMoreElements())\n        {\n            ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement());\n\n            switch (o.getTagNo())\n            {\n            case 0:\n                this.keyidentifier = ASN1OctetString.getInstance(o, false);\n                break;\n            case 1:\n                this.certissuer = GeneralNames.getInstance(o, false);\n                break;\n            case 2:\n                this.certserno = ASN1Integer.getInstance(o, false);\n                break;\n            default:\n                throw new IllegalArgumentException(\"illegal tag\");\n            }\n        }\n    }\n\n    /**\n     *\n     * Calulates the keyidentifier using a SHA1 hash over the BIT STRING\n     * from SubjectPublicKeyInfo as defined in RFC2459.\n     *\n     * Example of making a AuthorityKeyIdentifier:\n     * <pre>\n     *   SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(\n     *       publicKey.getEncoded()).readObject());\n     *   AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);\n     * </pre>\n     *\n     **/\n    public AuthorityKeyIdentifier(\n        SubjectPublicKeyInfo    spki)\n    {\n        Digest  digest = new SHA1Digest();\n        byte[]  resBuf = new byte[digest.getDigestSize()];\n\n        byte[] bytes = spki.getPublicKeyData().getBytes();\n        digest.update(bytes, 0, bytes.length);\n        digest.doFinal(resBuf, 0);\n        this.keyidentifier = new DEROctetString(resBuf);\n    }\n\n    /**\n     * create an AuthorityKeyIdentifier with the GeneralNames tag and\n     * the serial number provided as well.\n     */\n    public AuthorityKeyIdentifier(\n        SubjectPublicKeyInfo    spki,\n        GeneralNames            name,\n        BigInteger              serialNumber)\n    {\n        Digest  digest = new SHA1Digest();\n        byte[]  resBuf = new byte[digest.getDigestSize()];\n\n        byte[] bytes = spki.getPublicKeyData().getBytes();\n        digest.update(bytes, 0, bytes.length);\n        digest.doFinal(resBuf, 0);\n\n        this.keyidentifier = new DEROctetString(resBuf);\n        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());\n        this.certserno = new ASN1Integer(serialNumber);\n    }\n\n    /**\n     * create an AuthorityKeyIdentifier with the GeneralNames tag and\n     * the serial number provided.\n     */\n    public AuthorityKeyIdentifier(\n        GeneralNames            name,\n        BigInteger              serialNumber)\n    {\n        this.keyidentifier = null;\n        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());\n        this.certserno = new ASN1Integer(serialNumber);\n    }\n\n    /**\n      * create an AuthorityKeyIdentifier with a precomputed key identifier\n      */\n     public AuthorityKeyIdentifier(\n         byte[]                  keyIdentifier)\n     {\n         this.keyidentifier = new DEROctetString(keyIdentifier);\n         this.certissuer = null;\n         this.certserno = null;\n     }\n\n    /**\n     * create an AuthorityKeyIdentifier with a precomputed key identifier\n     * and the GeneralNames tag and the serial number provided as well.\n     */\n    public AuthorityKeyIdentifier(\n        byte[]                  keyIdentifier,\n        GeneralNames            name,\n        BigInteger              serialNumber)\n    {\n        this.keyidentifier = new DEROctetString(keyIdentifier);\n        this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());\n        this.certserno = new ASN1Integer(serialNumber);\n    }\n    \n    public byte[] getKeyIdentifier()\n    {\n        if (keyidentifier != null)\n        {\n            return keyidentifier.getOctets();\n        }\n\n        return null;\n    }\n\n    public GeneralNames getAuthorityCertIssuer()\n    {\n        return certissuer;\n    }\n    \n    public BigInteger getAuthorityCertSerialNumber()\n    {\n        if (certserno != null)\n        {\n            return certserno.getValue();\n        }\n        \n        return null;\n    }\n    \n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        if (keyidentifier != null)\n        {\n            v.add(new DERTaggedObject(false, 0, keyidentifier));\n        }\n\n        if (certissuer != null)\n        {\n            v.add(new DERTaggedObject(false, 1, certissuer));\n        }\n\n        if (certserno != null)\n        {\n            v.add(new DERTaggedObject(false, 2, certserno));\n        }\n\n\n        return new DERSequence(v);\n    }\n\n    public String toString()\n    {\n        return (\"AuthorityKeyIdentifier: KeyID(\" + this.keyidentifier.getOctets() + \")\");\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/BasicConstraints.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1Boolean;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBoolean;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\npublic class BasicConstraints\n    extends ASN1Object\n{\n    ASN1Boolean  cA = ASN1Boolean.getInstance(false);\n    ASN1Integer  pathLenConstraint = null;\n\n    public static BasicConstraints getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static BasicConstraints getInstance(\n        Object  obj)\n    {\n        if (obj instanceof BasicConstraints)\n        {\n            return (BasicConstraints)obj;\n        }\n        if (obj instanceof X509Extension)\n        {\n            return getInstance(X509Extension.convertValueToObject((X509Extension)obj));\n        }\n        if (obj != null)\n        {\n            return new BasicConstraints(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static BasicConstraints fromExtensions(Extensions extensions)\n    {\n        return BasicConstraints.getInstance(extensions.getExtensionParsedValue(Extension.basicConstraints));\n    }\n\n    private BasicConstraints(\n        ASN1Sequence   seq)\n    {\n        if (seq.size() == 0)\n        {\n            this.cA = null;\n            this.pathLenConstraint = null;\n        }\n        else\n        {\n            if (seq.getObjectAt(0) instanceof DERBoolean)\n            {\n                this.cA = DERBoolean.getInstance(seq.getObjectAt(0));\n            }\n            else\n            {\n                this.cA = null;\n                this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0));\n            }\n            if (seq.size() > 1)\n            {\n                if (this.cA != null)\n                {\n                    this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1));\n                }\n                else\n                {\n                    throw new IllegalArgumentException(\"wrong sequence in constructor\");\n                }\n            }\n        }\n    }\n\n    public BasicConstraints(\n        boolean cA)\n    {\n        if (cA)\n        {\n            this.cA = ASN1Boolean.getInstance(true);\n        }\n        else\n        {\n            this.cA = null;\n        }\n        this.pathLenConstraint = null;\n    }\n\n    /**\n     * create a cA=true object for the given path length constraint.\n     * \n     * @param pathLenConstraint\n     */\n    public BasicConstraints(\n        int     pathLenConstraint)\n    {\n        this.cA = ASN1Boolean.getInstance(true);\n        this.pathLenConstraint = new ASN1Integer(pathLenConstraint);\n    }\n\n    public boolean isCA()\n    {\n        return (cA != null) && cA.isTrue();\n    }\n\n    public BigInteger getPathLenConstraint()\n    {\n        if (pathLenConstraint != null)\n        {\n            return pathLenConstraint.getValue();\n        }\n\n        return null;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     * BasicConstraints := SEQUENCE {\n     *    cA                  BOOLEAN DEFAULT FALSE,\n     *    pathLenConstraint   INTEGER (0..MAX) OPTIONAL\n     * }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        if (cA != null)\n        {\n            v.add(cA);\n        }\n\n        if (pathLenConstraint != null)  // yes some people actually do this when cA is false...\n        {\n            v.add(pathLenConstraint);\n        }\n\n        return new DERSequence(v);\n    }\n\n    public String toString()\n    {\n        if (pathLenConstraint == null)\n        {\n            if (cA == null)\n            {\n                return \"BasicConstraints: isCa(false)\";\n            }\n            return \"BasicConstraints: isCa(\" + this.isCA() + \")\";\n        }\n        return \"BasicConstraints: isCa(\" + this.isCA() + \"), pathLenConstraint = \" + pathLenConstraint.getValue();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/Certificate.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.x500.X500Name;\n\n/**\n * an X509Certificate structure.\n * <pre>\n *  Certificate ::= SEQUENCE {\n *      tbsCertificate          TBSCertificate,\n *      signatureAlgorithm      AlgorithmIdentifier,\n *      signature               BIT STRING\n *  }\n * </pre>\n */\npublic class Certificate\n    extends ASN1Object\n{\n    ASN1Sequence  seq;\n    TBSCertificate tbsCert;\n    AlgorithmIdentifier     sigAlgId;\n    DERBitString            sig;\n\n    public static Certificate getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static Certificate getInstance(\n        Object  obj)\n    {\n        if (obj instanceof Certificate)\n        {\n            return (Certificate)obj;\n        }\n        else if (obj != null)\n        {\n            return new Certificate(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    private Certificate(\n        ASN1Sequence seq)\n    {\n        this.seq = seq;\n\n        //\n        // correct x509 certficate\n        //\n        if (seq.size() == 3)\n        {\n            tbsCert = TBSCertificate.getInstance(seq.getObjectAt(0));\n            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));\n\n            sig = DERBitString.getInstance(seq.getObjectAt(2));\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"sequence wrong size for a certificate\");\n        }\n    }\n\n    public TBSCertificate getTBSCertificate()\n    {\n        return tbsCert;\n    }\n\n    public ASN1Integer getVersion()\n    {\n        return tbsCert.getVersion();\n    }\n\n    public int getVersionNumber()\n    {\n        return tbsCert.getVersionNumber();\n    }\n\n    public ASN1Integer getSerialNumber()\n    {\n        return tbsCert.getSerialNumber();\n    }\n\n    public X500Name getIssuer()\n    {\n        return tbsCert.getIssuer();\n    }\n\n    public Time getStartDate()\n    {\n        return tbsCert.getStartDate();\n    }\n\n    public Time getEndDate()\n    {\n        return tbsCert.getEndDate();\n    }\n\n    public X500Name getSubject()\n    {\n        return tbsCert.getSubject();\n    }\n\n    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()\n    {\n        return tbsCert.getSubjectPublicKeyInfo();\n    }\n\n    public AlgorithmIdentifier getSignatureAlgorithm()\n    {\n        return sigAlgId;\n    }\n\n    public DERBitString getSignature()\n    {\n        return sig;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return seq;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/CertificateList.java",
    "content": "\npackage local.org.bouncycastle.asn1.x509;\n\nimport java.util.Enumeration;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.x500.X500Name;\n\n\n/**\n * PKIX RFC-2459\n *\n * The X.509 v2 CRL syntax is as follows.  For signature calculation,\n * the data that is to be signed is ASN.1 DER encoded.\n *\n * <pre>\n * CertificateList  ::=  SEQUENCE  {\n *      tbsCertList          TBSCertList,\n *      signatureAlgorithm   AlgorithmIdentifier,\n *      signatureValue       BIT STRING  }\n * </pre>\n */\npublic class CertificateList\n    extends ASN1Object\n{\n    TBSCertList            tbsCertList;\n    AlgorithmIdentifier    sigAlgId;\n    DERBitString           sig;\n\n    public static CertificateList getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static CertificateList getInstance(\n        Object  obj)\n    {\n        if (obj instanceof CertificateList)\n        {\n            return (CertificateList)obj;\n        }\n        else if (obj != null)\n        {\n            return new CertificateList(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public CertificateList(\n        ASN1Sequence seq)\n    {\n        if (seq.size() == 3)\n        {\n            tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0));\n            sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));\n            sig = DERBitString.getInstance(seq.getObjectAt(2));\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"sequence wrong size for CertificateList\");\n        }\n    }\n\n    public TBSCertList getTBSCertList()\n    {\n        return tbsCertList;\n    }\n\n    public TBSCertList.CRLEntry[] getRevokedCertificates()\n    {\n        return tbsCertList.getRevokedCertificates();\n    }\n\n    public Enumeration getRevokedCertificateEnumeration()\n    {\n        return tbsCertList.getRevokedCertificateEnumeration();\n    }\n\n    public AlgorithmIdentifier getSignatureAlgorithm()\n    {\n        return sigAlgId;\n    }\n\n    public DERBitString getSignature()\n    {\n        return sig;\n    }\n\n    public int getVersionNumber()\n    {\n        return tbsCertList.getVersionNumber();\n    }\n\n    public X500Name getIssuer()\n    {\n        return tbsCertList.getIssuer();\n    }\n\n    public Time getThisUpdate()\n    {\n        return tbsCertList.getThisUpdate();\n    }\n\n    public Time getNextUpdate()\n    {\n        return tbsCertList.getNextUpdate();\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(tbsCertList);\n        v.add(sigAlgId);\n        v.add(sig);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/DistributionPointName.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Choice;\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Set;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\n\n/**\n * The DistributionPointName object.\n * <pre>\n * DistributionPointName ::= CHOICE {\n *     fullName                 [0] GeneralNames,\n *     nameRelativeToCRLIssuer  [1] RDN\n * }\n * </pre>\n */\npublic class DistributionPointName\n    extends ASN1Object\n    implements ASN1Choice\n{\n    ASN1Encodable        name;\n    int                 type;\n\n    public static final int FULL_NAME = 0;\n    public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1;\n\n    public static DistributionPointName getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1TaggedObject.getInstance(obj, true));\n    }\n\n    public static DistributionPointName getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof DistributionPointName)\n        {\n            return (DistributionPointName)obj;\n        }\n        else if (obj instanceof ASN1TaggedObject)\n        {\n            return new DistributionPointName((ASN1TaggedObject)obj);\n        }\n\n        throw new IllegalArgumentException(\"unknown object in factory: \" + obj.getClass().getName());\n    }\n\n    public DistributionPointName(\n        int             type,\n        ASN1Encodable   name)\n    {\n        this.type = type;\n        this.name = name;\n    }\n\n    public DistributionPointName(\n        GeneralNames name)\n    {\n        this(FULL_NAME, name);\n    }\n\n    /**\n     * Return the tag number applying to the underlying choice.\n     * \n     * @return the tag number for this point name.\n     */\n    public int getType()\n    {\n        return this.type;\n    }\n    \n    /**\n     * Return the tagged object inside the distribution point name.\n     * \n     * @return the underlying choice item.\n     */\n    public ASN1Encodable getName()\n    {\n        return (ASN1Encodable)name;\n    }\n    \n    public DistributionPointName(\n        ASN1TaggedObject    obj)\n    {\n        this.type = obj.getTagNo();\n        \n        if (type == 0)\n        {\n            this.name = GeneralNames.getInstance(obj, false);\n        }\n        else\n        {\n            this.name = ASN1Set.getInstance(obj, false);\n        }\n    }\n    \n    public ASN1Primitive toASN1Primitive()\n    {\n        return new DERTaggedObject(false, type, name);\n    }\n\n    public String toString()\n    {\n        String       sep = System.getProperty(\"line.separator\");\n        StringBuffer buf = new StringBuffer();\n        buf.append(\"DistributionPointName: [\");\n        buf.append(sep);\n        if (type == FULL_NAME)\n        {\n            appendObject(buf, sep, \"fullName\", name.toString());\n        }\n        else\n        {\n            appendObject(buf, sep, \"nameRelativeToCRLIssuer\", name.toString());\n        }\n        buf.append(\"]\");\n        buf.append(sep);\n        return buf.toString();\n    }\n\n    private void appendObject(StringBuffer buf, String sep, String name, String value)\n    {\n        String       indent = \"    \";\n\n        buf.append(indent);\n        buf.append(name);\n        buf.append(\":\");\n        buf.append(sep);\n        buf.append(indent);\n        buf.append(indent);\n        buf.append(value);\n        buf.append(sep);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\n/**\n * The extendedKeyUsage object.\n * <pre>\n *      extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId\n * </pre>\n */\npublic class ExtendedKeyUsage\n    extends ASN1Object\n{\n    Hashtable     usageTable = new Hashtable();\n    ASN1Sequence  seq;\n\n    public static ExtendedKeyUsage getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static ExtendedKeyUsage getInstance(\n        Object obj)\n    {\n        if (obj instanceof ExtendedKeyUsage) \n        {\n            return (ExtendedKeyUsage)obj;\n        }\n        else if (obj != null)\n        {\n            return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static ExtendedKeyUsage fromExtensions(Extensions extensions)\n    {\n        return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage));\n    }\n\n    public ExtendedKeyUsage(\n        KeyPurposeId  usage)\n    {\n        this.seq = new DERSequence(usage);\n\n        this.usageTable.put(usage, usage);\n    }\n    \n    private ExtendedKeyUsage(\n        ASN1Sequence  seq)\n    {\n        this.seq = seq;\n\n        Enumeration e = seq.getObjects();\n\n        while (e.hasMoreElements())\n        {\n            ASN1Encodable o = (ASN1Encodable)e.nextElement();\n            if (!(o.toASN1Primitive() instanceof ASN1ObjectIdentifier))\n            {\n                throw new IllegalArgumentException(\"Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage.\");\n            }\n            this.usageTable.put(o, o);\n        }\n    }\n\n    public ExtendedKeyUsage(\n        KeyPurposeId[]  usages)\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        for (int i = 0; i != usages.length; i++)\n        {\n            v.add(usages[i]);\n            this.usageTable.put(usages[i], usages[i]);\n        }\n\n        this.seq = new DERSequence(v);\n    }\n\n    /**\n     * @deprecated use KeyPurposeId[] constructor.\n     */\n    public ExtendedKeyUsage(\n        Vector usages)\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n        Enumeration         e = usages.elements();\n\n        while (e.hasMoreElements())\n        {\n            ASN1Primitive  o = (ASN1Primitive)e.nextElement();\n\n            v.add(o);\n            this.usageTable.put(o, o);\n        }\n\n        this.seq = new DERSequence(v);\n    }\n\n    public boolean hasKeyPurposeId(\n        KeyPurposeId keyPurposeId)\n    {\n        return (usageTable.get(keyPurposeId) != null);\n    }\n    \n    /**\n     * Returns all extended key usages.\n     * The returned vector contains DERObjectIdentifiers.\n     * @return An array with all key purposes.\n     */\n    public KeyPurposeId[] getUsages()\n    {\n        KeyPurposeId[] temp = new KeyPurposeId[seq.size()];\n\n        int i = 0;\n        for (Enumeration it = seq.getObjects(); it.hasMoreElements();)\n        {\n            temp[i++] = KeyPurposeId.getInstance(it.nextElement());\n        }\n        return temp;\n    }\n\n    public int size()\n    {\n        return usageTable.size();\n    }\n    \n    public ASN1Primitive toASN1Primitive()\n    {\n        return seq;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/Extension.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.asn1.ASN1Boolean;\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\n/**\n * an object for the elements in the X.509 V3 extension block.\n */\npublic class Extension\n    extends ASN1Object\n{\n    /**\n     * Subject Directory Attributes\n     */\n    public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier(\"2.5.29.9\");\n    \n    /**\n     * Subject Key Identifier \n     */\n    public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier(\"2.5.29.14\");\n\n    /**\n     * Key Usage \n     */\n    public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier(\"2.5.29.15\");\n\n    /**\n     * Private Key Usage Period \n     */\n    public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier(\"2.5.29.16\");\n\n    /**\n     * Subject Alternative Name \n     */\n    public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier(\"2.5.29.17\");\n\n    /**\n     * Issuer Alternative Name \n     */\n    public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier(\"2.5.29.18\");\n\n    /**\n     * Basic Constraints \n     */\n    public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier(\"2.5.29.19\");\n\n    /**\n     * CRL Number \n     */\n    public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier(\"2.5.29.20\");\n\n    /**\n     * Reason code \n     */\n    public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier(\"2.5.29.21\");\n\n    /**\n     * Hold Instruction Code \n     */\n    public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier(\"2.5.29.23\");\n\n    /**\n     * Invalidity Date \n     */\n    public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier(\"2.5.29.24\");\n\n    /**\n     * Delta CRL indicator \n     */\n    public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier(\"2.5.29.27\");\n\n    /**\n     * Issuing Distribution Point \n     */\n    public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier(\"2.5.29.28\");\n\n    /**\n     * Certificate Issuer \n     */\n    public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier(\"2.5.29.29\");\n\n    /**\n     * Name Constraints \n     */\n    public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier(\"2.5.29.30\");\n\n    /**\n     * CRL Distribution Points \n     */\n    public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier(\"2.5.29.31\");\n\n    /**\n     * Certificate Policies \n     */\n    public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier(\"2.5.29.32\");\n\n    /**\n     * Policy Mappings \n     */\n    public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier(\"2.5.29.33\");\n\n    /**\n     * Authority Key Identifier \n     */\n    public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier(\"2.5.29.35\");\n\n    /**\n     * Policy Constraints \n     */\n    public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier(\"2.5.29.36\");\n\n    /**\n     * Extended Key Usage \n     */\n    public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier(\"2.5.29.37\");\n\n    /**\n     * Freshest CRL\n     */\n    public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier(\"2.5.29.46\");\n     \n    /**\n     * Inhibit Any Policy\n     */\n    public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier(\"2.5.29.54\");\n\n    /**\n     * Authority Info Access\n     */\n    public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.1\");\n\n    /**\n     * Subject Info Access\n     */\n    public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.11\");\n    \n    /**\n     * Logo Type\n     */\n    public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.12\");\n\n    /**\n     * BiometricInfo\n     */\n    public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.2\");\n    \n    /**\n     * QCStatements\n     */\n    public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.3\");\n\n    /**\n     * Audit identity extension in attribute certificates.\n     */\n    public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.4\");\n    \n    /**\n     * NoRevAvail extension in attribute certificates.\n     */\n    public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier(\"2.5.29.56\");\n\n    /**\n     * TargetInformation extension in attribute certificates.\n     */\n    public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier(\"2.5.29.55\");\n\n    private ASN1ObjectIdentifier extnId;\n    private boolean             critical;\n    private ASN1OctetString      value;\n\n    public Extension(\n        ASN1ObjectIdentifier extnId,\n        ASN1Boolean critical,\n        ASN1OctetString value)\n    {\n        this(extnId, critical.isTrue(), value);\n    }\n\n    public Extension(\n        ASN1ObjectIdentifier extnId,\n        boolean critical,\n        byte[] value)\n    {\n        this(extnId, critical, new DEROctetString(value));\n    }\n\n    public Extension(\n        ASN1ObjectIdentifier extnId,\n        boolean critical,\n        ASN1OctetString value)\n    {\n        this.extnId = extnId;\n        this.critical = critical;\n        this.value = value;\n    }\n\n    private Extension(ASN1Sequence seq)\n    {\n        if (seq.size() == 2)\n        {\n            this.extnId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));\n            this.critical = false;\n            this.value = ASN1OctetString.getInstance(seq.getObjectAt(1));\n        }\n        else if (seq.size() == 3)\n        {\n            this.extnId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));\n            this.critical = ASN1Boolean.getInstance(seq.getObjectAt(1)).isTrue();\n            this.value = ASN1OctetString.getInstance(seq.getObjectAt(2));\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n        }\n    }\n\n    public static Extension getInstance(Object obj)\n    {\n        if (obj instanceof Extension)\n        {\n            return (Extension)obj;\n        }\n        else if (obj != null)\n        {\n            return new Extension(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public ASN1ObjectIdentifier getExtnId()\n    {\n        return extnId;\n    }\n\n    public boolean isCritical()\n    {\n        return critical;\n    }\n\n    public ASN1OctetString getExtnValue()\n    {\n        return value;\n    }\n\n    public ASN1Encodable getParsedValue()\n    {\n        return convertValueToObject(this);\n    }\n\n    public int hashCode()\n    {\n        if (this.isCritical())\n        {\n            return this.getExtnValue().hashCode() ^ this.getExtnId().hashCode();\n        }\n\n        return ~(this.getExtnValue().hashCode() ^ this.getExtnId().hashCode());\n    }\n\n    public boolean equals(\n        Object  o)\n    {\n        if (!(o instanceof Extension))\n        {\n            return false;\n        }\n\n        Extension other = (Extension)o;\n\n        return other.getExtnId().equals(this.getExtnId())\n            && other.getExtnValue().equals(this.getExtnValue())\n            && (other.isCritical() == this.isCritical());\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(extnId);\n\n        if (critical)\n        {\n            v.add(ASN1Boolean.getInstance(true));\n        }\n\n        v.add(value);\n\n        return new DERSequence(v);\n    }\n\n    /**\n     * Convert the value of the passed in extension to an object\n     * @param ext the extension to parse\n     * @return the object the value string contains\n     * @exception IllegalArgumentException if conversion is not possible\n     */\n    private static ASN1Primitive convertValueToObject(\n        Extension ext)\n        throws IllegalArgumentException\n    {\n        try\n        {\n            return ASN1Primitive.fromByteArray(ext.getExtnValue().getOctets());\n        }\n        catch (IOException e)\n        {\n            throw new IllegalArgumentException(\"can't convert extension: \" +  e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/Extensions.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\npublic class Extensions\n    extends ASN1Object\n{\n    private Hashtable extensions = new Hashtable();\n    private Vector ordering = new Vector();\n\n    public static Extensions getInstance(\n        ASN1TaggedObject obj,\n        boolean explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static Extensions getInstance(\n        Object obj)\n    {\n        if (obj instanceof Extensions)\n        {\n            return (Extensions)obj;\n        }\n        else if (obj != null)\n        {\n            return new Extensions(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    /**\n     * Constructor from ASN1Sequence.\n     * <p/>\n     * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)\n     */\n    private Extensions(\n        ASN1Sequence seq)\n    {\n        Enumeration e = seq.getObjects();\n\n        while (e.hasMoreElements())\n        {\n            Extension ext = Extension.getInstance(e.nextElement());\n\n            extensions.put(ext.getExtnId(), ext);\n            ordering.addElement(ext.getExtnId());\n        }\n    }\n\n    /**\n     * Base Constructor\n     *\n     * @param extension a single extension.\n     */\n    public Extensions(\n        Extension extension)\n    {\n        this.ordering.addElement(extension.getExtnId());\n        this.extensions.put(extension.getExtnId(), extension);\n    }\n\n    /**\n     * Base Constructor\n     *\n     * @param extensions an array of extensions.\n     */\n    public Extensions(\n        Extension[] extensions)\n    {\n        for (int i = 0; i != extensions.length; i++)\n        {\n            Extension ext = extensions[i];\n\n            this.ordering.addElement(ext.getExtnId());\n            this.extensions.put(ext.getExtnId(), ext);\n        }\n    }\n\n    /**\n     * return an Enumeration of the extension field's object ids.\n     */\n    public Enumeration oids()\n    {\n        return ordering.elements();\n    }\n\n    /**\n     * return the extension represented by the object identifier\n     * passed in.\n     *\n     * @return the extension if it's present, null otherwise.\n     */\n    public Extension getExtension(\n        ASN1ObjectIdentifier oid)\n    {\n        return (Extension)extensions.get(oid);\n    }\n\n    /**\n     * return the parsed value of the extension represented by the object identifier\n     * passed in.\n     *\n     * @return the parsed value of the extension if it's present, null otherwise.\n     */\n    public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid)\n    {\n        Extension ext = this.getExtension(oid);\n\n        if (ext != null)\n        {\n            return ext.getParsedValue();\n        }\n\n        return null;\n    }\n\n    /**\n     * <pre>\n     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension\n     *\n     *     Extension         ::=   SEQUENCE {\n     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),\n     *        critical          BOOLEAN DEFAULT FALSE,\n     *        extnValue         OCTET STRING }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector vec = new ASN1EncodableVector();\n        Enumeration e = ordering.elements();\n\n        while (e.hasMoreElements())\n        {\n            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();\n            Extension ext = (Extension)extensions.get(oid);\n\n            vec.add(ext);\n        }\n\n        return new DERSequence(vec);\n    }\n\n    public boolean equivalent(\n        Extensions other)\n    {\n        if (extensions.size() != other.extensions.size())\n        {\n            return false;\n        }\n\n        Enumeration e1 = extensions.keys();\n\n        while (e1.hasMoreElements())\n        {\n            Object key = e1.nextElement();\n\n            if (!extensions.get(key).equals(other.extensions.get(key)))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public ASN1ObjectIdentifier[] getExtensionOIDs()\n    {\n        return toOidArray(ordering);\n    }\n\n    public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()\n    {\n        return getExtensionOIDs(false);\n    }\n\n    public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()\n    {\n        return getExtensionOIDs(true);\n    }\n\n    private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)\n    {\n        Vector oidVec = new Vector();\n\n        for (int i = 0; i != ordering.size(); i++)\n        {\n            Object oid = ordering.elementAt(i);\n\n            if (((Extension)extensions.get(oid)).isCritical() == isCritical)\n            {\n                oidVec.addElement(oid);\n            }\n        }\n\n        return toOidArray(oidVec);\n    }\n\n    private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)\n    {\n        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];\n\n        for (int i = 0; i != oids.length; i++)\n        {\n            oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);\n        }\n        return oids;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/ExtensionsGenerator.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Encoding;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.DEROctetString;\n\n\n/**\n * Generator for X.509 extensions\n */\npublic class ExtensionsGenerator\n{\n    private Hashtable extensions = new Hashtable();\n    private Vector extOrdering = new Vector();\n\n    /**\n     * Reset the generator\n     */\n    public void reset()\n    {\n        extensions = new Hashtable();\n        extOrdering = new Vector();\n    }\n\n    /**\n     * Add an extension with the given oid and the passed in value to be included\n     * in the OCTET STRING associated with the extension.\n     *\n     * @param oid  OID for the extension.\n     * @param critical  true if critical, false otherwise.\n     * @param value the ASN.1 object to be included in the extension.\n     */\n    public void addExtension(\n        ASN1ObjectIdentifier oid,\n        boolean              critical,\n        ASN1Encodable        value)\n        throws IOException\n    {\n        this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));\n    }\n\n    /**\n     * Add an extension with the given oid and the passed in byte array to be wrapped in the\n     * OCTET STRING associated with the extension.\n     *\n     * @param oid OID for the extension.\n     * @param critical true if critical, false otherwise.\n     * @param value the byte array to be wrapped.\n     */\n    public void addExtension(\n        ASN1ObjectIdentifier oid,\n        boolean             critical,\n        byte[]              value)\n    {\n        if (extensions.containsKey(oid))\n        {\n            throw new IllegalArgumentException(\"extension \" + oid + \" already added\");\n        }\n\n        extOrdering.addElement(oid);\n        extensions.put(oid, new Extension(oid, critical, new DEROctetString(value)));\n    }\n\n    /**\n     * Return true if there are no extension present in this generator.\n     *\n     * @return true if empty, false otherwise\n     */\n    public boolean isEmpty()\n    {\n        return extOrdering.isEmpty();\n    }\n\n    /**\n     * Generate an Extensions object based on the current state of the generator.\n     *\n     * @return  an X09Extensions object.\n     */\n    public Extensions generate()\n    {\n        Extension[] exts = new Extension[extOrdering.size()];\n\n        for (int i = 0; i != extOrdering.size(); i++)\n        {\n            exts[i] = (Extension)extensions.get(extOrdering.elementAt(i));\n        }\n\n        return new Extensions(exts);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/GeneralName.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\nimport java.util.StringTokenizer;\n\nimport local.org.bouncycastle.asn1.ASN1Choice;\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERIA5String;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.util.IPAddress;\n\n\n/**\n * The GeneralName object.\n * <pre>\n * GeneralName ::= CHOICE {\n *      otherName                       [0]     OtherName,\n *      rfc822Name                      [1]     IA5String,\n *      dNSName                         [2]     IA5String,\n *      x400Address                     [3]     ORAddress,\n *      directoryName                   [4]     Name,\n *      ediPartyName                    [5]     EDIPartyName,\n *      uniformResourceIdentifier       [6]     IA5String,\n *      iPAddress                       [7]     OCTET STRING,\n *      registeredID                    [8]     OBJECT IDENTIFIER}\n *\n * OtherName ::= SEQUENCE {\n *      type-id    OBJECT IDENTIFIER,\n *      value      [0] EXPLICIT ANY DEFINED BY type-id }\n *\n * EDIPartyName ::= SEQUENCE {\n *      nameAssigner            [0]     DirectoryString OPTIONAL,\n *      partyName               [1]     DirectoryString }\n * \n * Name ::= CHOICE { RDNSequence }\n * </pre>\n */\npublic class GeneralName\n    extends ASN1Object\n    implements ASN1Choice\n{\n    public static final int otherName                     = 0;\n    public static final int rfc822Name                    = 1;\n    public static final int dNSName                       = 2;\n    public static final int x400Address                   = 3;\n    public static final int directoryName                 = 4;\n    public static final int ediPartyName                  = 5;\n    public static final int uniformResourceIdentifier     = 6;\n    public static final int iPAddress                     = 7;\n    public static final int registeredID                  = 8;\n\n    private ASN1Encodable obj;\n    private int           tag;\n\n    /**\n     * @deprecated use X500Name constructor.\n     * @param dirName\n     */\n        public GeneralName(\n        X509Name  dirName)\n    {\n        this.obj = X500Name.getInstance(dirName);\n        this.tag = 4;\n    }\n\n    public GeneralName(\n        X500Name  dirName)\n    {\n        this.obj = dirName;\n        this.tag = 4;\n    }\n\n    /**\n     * When the subjectAltName extension contains an Internet mail address,\n     * the address MUST be included as an rfc822Name. The format of an\n     * rfc822Name is an \"addr-spec\" as defined in RFC 822 [RFC 822].\n     *\n     * When the subjectAltName extension contains a domain name service\n     * label, the domain name MUST be stored in the dNSName (an IA5String).\n     * The name MUST be in the \"preferred name syntax,\" as specified by RFC\n     * 1034 [RFC 1034].\n     *\n     * When the subjectAltName extension contains a URI, the name MUST be\n     * stored in the uniformResourceIdentifier (an IA5String). The name MUST\n     * be a non-relative URL, and MUST follow the URL syntax and encoding\n     * rules specified in [RFC 1738].  The name must include both a scheme\n     * (e.g., \"http\" or \"ftp\") and a scheme-specific-part.  The scheme-\n     * specific-part must include a fully qualified domain name or IP\n     * address as the host.\n     *\n     * When the subjectAltName extension contains a iPAddress, the address\n     * MUST be stored in the octet string in \"network byte order,\" as\n     * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of\n     * each octet is the LSB of the corresponding byte in the network\n     * address. For IP Version 4, as specified in RFC 791, the octet string\n     * MUST contain exactly four octets.  For IP Version 6, as specified in\n     * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC\n     * 1883].\n     */\n    public GeneralName(\n        int           tag,\n        ASN1Encodable name)\n    {\n        this.obj = name;\n        this.tag = tag;\n    }\n    \n    /**\n     * Create a GeneralName for the given tag from the passed in String.\n     * <p>\n     * This constructor can handle:\n     * <ul>\n     * <li>rfc822Name\n     * <li>iPAddress\n     * <li>directoryName\n     * <li>dNSName\n     * <li>uniformResourceIdentifier\n     * <li>registeredID\n     * </ul>\n     * For x400Address, otherName and ediPartyName there is no common string\n     * format defined.\n     * <p>\n     * Note: A directory name can be encoded in different ways into a byte\n     * representation. Be aware of this if the byte representation is used for\n     * comparing results.\n     *\n     * @param tag tag number\n     * @param name string representation of name\n     * @throws IllegalArgumentException if the string encoding is not correct or     *             not supported.\n     */\n    public GeneralName(\n        int       tag,\n        String    name)\n    {\n        this.tag = tag;\n\n        if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier)\n        {\n            this.obj = new DERIA5String(name);\n        }\n        else if (tag == registeredID)\n        {\n            this.obj = new ASN1ObjectIdentifier(name);\n        }\n        else if (tag == directoryName)\n        {\n            this.obj = new X500Name(name);\n        }\n        else if (tag == iPAddress)\n        {\n            byte[] enc = toGeneralNameEncoding(name);\n            if (enc != null)\n            {\n                this.obj = new DEROctetString(enc);\n            }\n            else\n            {\n                throw new IllegalArgumentException(\"IP Address is invalid\");\n            }\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"can't process String for tag: \" + tag);\n        }\n    }\n    \n    public static GeneralName getInstance(\n        Object obj)\n    {\n        if (obj == null || obj instanceof GeneralName)\n        {\n            return (GeneralName)obj;\n        }\n\n        if (obj instanceof ASN1TaggedObject)\n        {\n            ASN1TaggedObject    tagObj = (ASN1TaggedObject)obj;\n            int                 tag = tagObj.getTagNo();\n\n            switch (tag)\n            {\n            case otherName:\n                return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));\n            case rfc822Name:\n                return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));\n            case dNSName:\n                return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));\n            case x400Address:\n                throw new IllegalArgumentException(\"unknown tag: \" + tag);\n            case directoryName:\n                return new GeneralName(tag, X500Name.getInstance(tagObj, true));\n            case ediPartyName:\n                return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));\n            case uniformResourceIdentifier:\n                return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));\n            case iPAddress:\n                return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false));\n            case registeredID:\n                return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false));\n            }\n        }\n\n        if (obj instanceof byte[])\n        {\n            try\n            {\n                return getInstance(ASN1Primitive.fromByteArray((byte[])obj));\n            }\n            catch (IOException e)\n            {\n                throw new IllegalArgumentException(\"unable to parse encoded general name\");\n            }\n        }\n\n        throw new IllegalArgumentException(\"unknown object in getInstance: \" + obj.getClass().getName());\n    }\n\n    public static GeneralName getInstance(\n        ASN1TaggedObject tagObj,\n        boolean          explicit)\n    {\n        return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true));\n    }\n\n    public int getTagNo()\n    {\n        return tag;\n    }\n\n    public ASN1Encodable getName()\n    {\n        return obj;\n    }\n\n    public String toString()\n    {\n        StringBuffer buf = new StringBuffer();\n\n        buf.append(tag);\n        buf.append(\": \");\n        switch (tag)\n        {\n        case rfc822Name:\n        case dNSName:\n        case uniformResourceIdentifier:\n            buf.append(DERIA5String.getInstance(obj).getString());\n            break;\n        case directoryName:\n            buf.append(X500Name.getInstance(obj).toString());\n            break;\n        default:\n            buf.append(obj.toString());\n        }\n        return buf.toString();\n    }\n\n    private byte[] toGeneralNameEncoding(String ip)\n    {\n        if (IPAddress.isValidIPv6WithNetmask(ip) || IPAddress.isValidIPv6(ip))\n        {\n            int    slashIndex = ip.indexOf('/');\n\n            if (slashIndex < 0)\n            {\n                byte[] addr = new byte[16];\n                int[]  parsedIp = parseIPv6(ip);\n                copyInts(parsedIp, addr, 0);\n\n                return addr;\n            }\n            else\n            {\n                byte[] addr = new byte[32];\n                int[]  parsedIp = parseIPv6(ip.substring(0, slashIndex));\n                copyInts(parsedIp, addr, 0);\n                String mask = ip.substring(slashIndex + 1);\n                if (mask.indexOf(':') > 0)\n                {\n                    parsedIp = parseIPv6(mask);\n                }\n                else\n                {\n                    parsedIp = parseMask(mask);\n                }\n                copyInts(parsedIp, addr, 16);\n\n                return addr;\n            }\n        }\n        else if (IPAddress.isValidIPv4WithNetmask(ip) || IPAddress.isValidIPv4(ip))\n        {\n            int    slashIndex = ip.indexOf('/');\n\n            if (slashIndex < 0)\n            {\n                byte[] addr = new byte[4];\n\n                parseIPv4(ip, addr, 0);\n\n                return addr;\n            }\n            else\n            {\n                byte[] addr = new byte[8];\n\n                parseIPv4(ip.substring(0, slashIndex), addr, 0);\n\n                String mask = ip.substring(slashIndex + 1);\n                if (mask.indexOf('.') > 0)\n                {\n                    parseIPv4(mask, addr, 4);\n                }\n                else\n                {\n                    parseIPv4Mask(mask, addr, 4);\n                }\n\n                return addr;\n            }\n        }\n\n        return null;\n    }\n\n    private void parseIPv4Mask(String mask, byte[] addr, int offset)\n    {\n        int   maskVal = Integer.parseInt(mask);\n\n        for (int i = 0; i != maskVal; i++)\n        {\n            addr[(i / 8) + offset] |= 1 << (7 - (i % 8));\n        }\n    }\n\n    private void parseIPv4(String ip, byte[] addr, int offset)\n    {\n        StringTokenizer sTok = new StringTokenizer(ip, \"./\");\n        int    index = 0;\n\n        while (sTok.hasMoreTokens())\n        {\n            addr[offset + index++] = (byte)Integer.parseInt(sTok.nextToken());\n        }\n    }\n\n    private int[] parseMask(String mask)\n    {\n        int[] res = new int[8];\n        int   maskVal = Integer.parseInt(mask);\n\n        for (int i = 0; i != maskVal; i++)\n        {\n            res[i / 16] |= 1 << (15 - (i % 16));\n        }\n        return res;\n    }\n\n    private void copyInts(int[] parsedIp, byte[] addr, int offSet)\n    {\n        for (int i = 0; i != parsedIp.length; i++)\n        {\n            addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);\n            addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];\n        }\n    }\n\n    private int[] parseIPv6(String ip)\n    {\n        StringTokenizer sTok = new StringTokenizer(ip, \":\", true);\n        int index = 0;\n        int[] val = new int[8];\n\n        if (ip.charAt(0) == ':' && ip.charAt(1) == ':')\n        {\n           sTok.nextToken(); // skip the first one\n        }\n\n        int doubleColon = -1;\n\n        while (sTok.hasMoreTokens())\n        {\n            String e = sTok.nextToken();\n\n            if (e.equals(\":\"))\n            {\n                doubleColon = index;\n                val[index++] = 0;\n            }\n            else\n            {\n                if (e.indexOf('.') < 0)\n                {\n                    val[index++] = Integer.parseInt(e, 16);\n                    if (sTok.hasMoreTokens())\n                    {\n                        sTok.nextToken();\n                    }\n                }\n                else\n                {\n                    StringTokenizer eTok = new StringTokenizer(e, \".\");\n\n                    val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken());\n                    val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken());\n                }\n            }\n        }\n\n        if (index != val.length)\n        {\n            System.arraycopy(val, doubleColon, val, val.length - (index - doubleColon), index - doubleColon);\n            for (int i = doubleColon; i != val.length - (index - doubleColon); i++)\n            {\n                val[i] = 0;\n            }\n        }\n\n        return val;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        if (tag == directoryName)       // directoryName is explicitly tagged as it is a CHOICE\n        {\n            return new DERTaggedObject(true, tag, obj);\n        }\n        else\n        {\n            return new DERTaggedObject(false, tag, obj);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/GeneralNames.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\n\npublic class GeneralNames\n    extends ASN1Object\n{\n    private final GeneralName[] names;\n\n    public static GeneralNames getInstance(\n        Object  obj)\n    {\n        if (obj instanceof GeneralNames)\n        {\n            return (GeneralNames)obj;\n        }\n\n        if (obj != null)\n        {\n            return new GeneralNames(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static GeneralNames getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static GeneralNames fromExtensions(Extensions extensions, ASN1ObjectIdentifier extOID)\n    {\n        return GeneralNames.getInstance(extensions.getExtensionParsedValue(extOID));\n    }\n\n    /**\n     * Construct a GeneralNames object containing one GeneralName.\n     * \n     * @param name the name to be contained.\n     */\n    public GeneralNames(\n        GeneralName  name)\n    {\n        this.names = new GeneralName[] { name };\n    }\n\n\n    public GeneralNames(\n        GeneralName[]  names)\n    {\n        this.names = names;\n    }\n\n    private GeneralNames(\n        ASN1Sequence  seq)\n    {\n        this.names = new GeneralName[seq.size()];\n\n        for (int i = 0; i != seq.size(); i++)\n        {\n            names[i] = GeneralName.getInstance(seq.getObjectAt(i));\n        }\n    }\n\n    public GeneralName[] getNames()\n    {\n        GeneralName[] tmp = new GeneralName[names.length];\n\n        System.arraycopy(names, 0, tmp, 0, names.length);\n\n        return tmp;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        return new DERSequence(names);\n    }\n\n    public String toString()\n    {\n        StringBuffer  buf = new StringBuffer();\n        String        sep = System.getProperty(\"line.separator\");\n\n        buf.append(\"GeneralNames:\");\n        buf.append(sep);\n\n        for (int i = 0; i != names.length; i++)\n        {\n            buf.append(\"    \");\n            buf.append(names[i]);\n            buf.append(sep);\n        }\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/Holder.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\n\n/**\n * The Holder object.\n * <p>\n * For an v2 attribute certificate this is:\n * \n * <pre>\n *            Holder ::= SEQUENCE {\n *                  baseCertificateID   [0] IssuerSerial OPTIONAL,\n *                           -- the issuer and serial number of\n *                           -- the holder's Public Key Certificate\n *                  entityName          [1] GeneralNames OPTIONAL,\n *                           -- the name of the claimant or role\n *                  objectDigestInfo    [2] ObjectDigestInfo OPTIONAL\n *                           -- used to directly authenticate the holder,\n *                           -- for example, an executable\n *            }\n * </pre>\n * \n * <p>\n * For an v1 attribute certificate this is:\n * \n * <pre>\n *         subject CHOICE {\n *          baseCertificateID [0] IssuerSerial,\n *          -- associated with a Public Key Certificate\n *          subjectName [1] GeneralNames },\n *          -- associated with a name\n * </pre>\n */\npublic class Holder\n    extends ASN1Object\n{\n    public static final int V1_CERTIFICATE_HOLDER = 0;\n    public static final int V2_CERTIFICATE_HOLDER = 1;\n\n    IssuerSerial baseCertificateID;\n\n    GeneralNames entityName;\n\n    ObjectDigestInfo objectDigestInfo;\n\n    private int version = V2_CERTIFICATE_HOLDER;\n\n    public static Holder getInstance(Object obj)\n    {\n        if (obj instanceof Holder)\n        {\n            return (Holder)obj;\n        }\n        else if (obj instanceof ASN1TaggedObject)\n        {\n            return new Holder(ASN1TaggedObject.getInstance(obj));\n        }\n        else if (obj != null)\n        {\n            return new Holder(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    /**\n     * Constructor for a holder for an V1 attribute certificate.\n     * \n     * @param tagObj The ASN.1 tagged holder object.\n     */\n    private Holder(ASN1TaggedObject tagObj)\n    {\n        switch (tagObj.getTagNo())\n        {\n        case 0:\n            baseCertificateID = IssuerSerial.getInstance(tagObj, false);\n            break;\n        case 1:\n            entityName = GeneralNames.getInstance(tagObj, false);\n            break;\n        default:\n            throw new IllegalArgumentException(\"unknown tag in Holder\");\n        }\n        version = 0;\n    }\n\n    /**\n     * Constructor for a holder for an V2 attribute certificate.\n     * \n     * @param seq The ASN.1 sequence.\n     */\n    private Holder(ASN1Sequence seq)\n    {\n        if (seq.size() > 3)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \"\n                + seq.size());\n        }\n\n        for (int i = 0; i != seq.size(); i++)\n        {\n            ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(seq\n                .getObjectAt(i));\n\n            switch (tObj.getTagNo())\n            {\n            case 0:\n                baseCertificateID = IssuerSerial.getInstance(tObj, false);\n                break;\n            case 1:\n                entityName = GeneralNames.getInstance(tObj, false);\n                break;\n            case 2:\n                objectDigestInfo = ObjectDigestInfo.getInstance(tObj, false);\n                break;\n            default:\n                throw new IllegalArgumentException(\"unknown tag in Holder\");\n            }\n        }\n        version = 1;\n    }\n\n    public Holder(IssuerSerial baseCertificateID)\n    {\n        this(baseCertificateID, V2_CERTIFICATE_HOLDER);\n    }\n\n    /**\n     * Constructs a holder from a IssuerSerial for a V1 or V2 certificate.\n     * .\n     * @param baseCertificateID The IssuerSerial.\n     * @param version The version of the attribute certificate. \n     */\n    public Holder(IssuerSerial baseCertificateID, int version)\n    {\n        this.baseCertificateID = baseCertificateID;\n        this.version = version;\n    }\n    \n    /**\n     * Returns 1 for V2 attribute certificates or 0 for V1 attribute\n     * certificates. \n     * @return The version of the attribute certificate.\n     */\n    public int getVersion()\n    {\n        return version;\n    }\n\n    /**\n     * Constructs a holder with an entityName for V2 attribute certificates.\n     * \n     * @param entityName The entity or subject name.\n     */\n    public Holder(GeneralNames entityName)\n    {\n        this(entityName, V2_CERTIFICATE_HOLDER);\n    }\n\n    /**\n     * Constructs a holder with an entityName for V2 attribute certificates or\n     * with a subjectName for V1 attribute certificates.\n     * \n     * @param entityName The entity or subject name.\n     * @param version The version of the attribute certificate. \n     */\n    public Holder(GeneralNames entityName, int version)\n    {\n        this.entityName = entityName;\n        this.version = version;\n    }\n    \n    /**\n     * Constructs a holder from an object digest info.\n     * \n     * @param objectDigestInfo The object digest info object.\n     */\n    public Holder(ObjectDigestInfo objectDigestInfo)\n    {\n        this.objectDigestInfo = objectDigestInfo;\n    }\n\n    public IssuerSerial getBaseCertificateID()\n    {\n        return baseCertificateID;\n    }\n\n    /**\n     * Returns the entityName for an V2 attribute certificate or the subjectName\n     * for an V1 attribute certificate.\n     * \n     * @return The entityname or subjectname.\n     */\n    public GeneralNames getEntityName()\n    {\n        return entityName;\n    }\n\n    public ObjectDigestInfo getObjectDigestInfo()\n    {\n        return objectDigestInfo;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        if (version == 1)\n        {\n            ASN1EncodableVector v = new ASN1EncodableVector();\n\n            if (baseCertificateID != null)\n            {\n                v.add(new DERTaggedObject(false, 0, baseCertificateID));\n            }\n\n            if (entityName != null)\n            {\n                v.add(new DERTaggedObject(false, 1, entityName));\n            }\n\n            if (objectDigestInfo != null)\n            {\n                v.add(new DERTaggedObject(false, 2, objectDigestInfo));\n            }\n\n            return new DERSequence(v);\n        }\n        else\n        {\n            if (entityName != null)\n            {\n                return new DERTaggedObject(false, 1, entityName);\n            }\n            else\n            {\n                return new DERTaggedObject(false, 0, baseCertificateID);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/IssuerSerial.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\npublic class IssuerSerial\n    extends ASN1Object\n{\n    GeneralNames            issuer;\n    ASN1Integer              serial;\n    DERBitString            issuerUID;\n\n    public static IssuerSerial getInstance(\n            Object  obj)\n    {\n        if (obj instanceof IssuerSerial)\n        {\n            return (IssuerSerial)obj;\n        }\n\n        if (obj != null)\n        {\n            return new IssuerSerial(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static IssuerSerial getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n    \n    private IssuerSerial(\n        ASN1Sequence    seq)\n    {\n        if (seq.size() != 2 && seq.size() != 3)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n        }\n        \n        issuer = GeneralNames.getInstance(seq.getObjectAt(0));\n        serial = ASN1Integer.getInstance(seq.getObjectAt(1));\n\n        if (seq.size() == 3)\n        {\n            issuerUID = DERBitString.getInstance(seq.getObjectAt(2));\n        }\n    }\n\n    public IssuerSerial(\n        GeneralNames    issuer,\n        BigInteger serial)\n    {\n        this(issuer, new ASN1Integer(serial));\n    }\n\n    public IssuerSerial(\n        GeneralNames    issuer,\n        ASN1Integer      serial)\n    {\n        this.issuer = issuer;\n        this.serial = serial;\n    }\n\n    public GeneralNames getIssuer()\n    {\n        return issuer;\n    }\n\n    public ASN1Integer getSerial()\n    {\n        return serial;\n    }\n\n    public DERBitString getIssuerUID()\n    {\n        return issuerUID;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  IssuerSerial  ::=  SEQUENCE {\n     *       issuer         GeneralNames,\n     *       serial         CertificateSerialNumber,\n     *       issuerUID      UniqueIdentifier OPTIONAL\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(issuer);\n        v.add(serial);\n\n        if (issuerUID != null)\n        {\n            v.add(issuerUID);\n        }\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Boolean;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\n\n/**\n * <pre>\n * IssuingDistributionPoint ::= SEQUENCE { \n *   distributionPoint          [0] DistributionPointName OPTIONAL, \n *   onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE, \n *   onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE, \n *   onlySomeReasons            [3] ReasonFlags OPTIONAL, \n *   indirectCRL                [4] BOOLEAN DEFAULT FALSE,\n *   onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }\n * </pre>\n */\npublic class IssuingDistributionPoint\n    extends ASN1Object\n{\n    private DistributionPointName distributionPoint;\n\n    private boolean onlyContainsUserCerts;\n\n    private boolean onlyContainsCACerts;\n\n    private ReasonFlags onlySomeReasons;\n\n    private boolean indirectCRL;\n\n    private boolean onlyContainsAttributeCerts;\n\n    private ASN1Sequence seq;\n\n    public static IssuingDistributionPoint getInstance(\n        ASN1TaggedObject obj,\n        boolean explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static IssuingDistributionPoint getInstance(\n        Object obj)\n    {\n        if (obj instanceof IssuingDistributionPoint)\n        {\n            return (IssuingDistributionPoint)obj;\n        }\n        else if (obj != null)\n        {\n            return new IssuingDistributionPoint(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    /**\n     * Constructor from given details.\n     * \n     * @param distributionPoint\n     *            May contain an URI as pointer to most current CRL.\n     * @param onlyContainsUserCerts Covers revocation information for end certificates.\n     * @param onlyContainsCACerts Covers revocation information for CA certificates.\n     * \n     * @param onlySomeReasons\n     *            Which revocation reasons does this point cover.\n     * @param indirectCRL\n     *            If <code>true</code> then the CRL contains revocation\n     *            information about certificates ssued by other CAs.\n     * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.\n     */\n    public IssuingDistributionPoint(\n        DistributionPointName distributionPoint,\n        boolean onlyContainsUserCerts,\n        boolean onlyContainsCACerts,\n        ReasonFlags onlySomeReasons,\n        boolean indirectCRL,\n        boolean onlyContainsAttributeCerts)\n    {\n        this.distributionPoint = distributionPoint;\n        this.indirectCRL = indirectCRL;\n        this.onlyContainsAttributeCerts = onlyContainsAttributeCerts;\n        this.onlyContainsCACerts = onlyContainsCACerts;\n        this.onlyContainsUserCerts = onlyContainsUserCerts;\n        this.onlySomeReasons = onlySomeReasons;\n\n        ASN1EncodableVector vec = new ASN1EncodableVector();\n        if (distributionPoint != null)\n        {                                    // CHOICE item so explicitly tagged\n            vec.add(new DERTaggedObject(true, 0, distributionPoint));\n        }\n        if (onlyContainsUserCerts)\n        {\n            vec.add(new DERTaggedObject(false, 1, ASN1Boolean.getInstance(true)));\n        }\n        if (onlyContainsCACerts)\n        {\n            vec.add(new DERTaggedObject(false, 2, ASN1Boolean.getInstance(true)));\n        }\n        if (onlySomeReasons != null)\n        {\n            vec.add(new DERTaggedObject(false, 3, onlySomeReasons));\n        }\n        if (indirectCRL)\n        {\n            vec.add(new DERTaggedObject(false, 4, ASN1Boolean.getInstance(true)));\n        }\n        if (onlyContainsAttributeCerts)\n        {\n            vec.add(new DERTaggedObject(false, 5, ASN1Boolean.getInstance(true)));\n        }\n\n        seq = new DERSequence(vec);\n    }\n\n    /**\n     * Shorthand Constructor from given details.\n     *\n     * @param distributionPoint\n     *            May contain an URI as pointer to most current CRL.\n     * @param indirectCRL\n     *            If <code>true</code> then the CRL contains revocation\n     *            information about certificates ssued by other CAs.\n     * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.\n     */\n    public IssuingDistributionPoint(\n        DistributionPointName distributionPoint,\n        boolean indirectCRL,\n        boolean onlyContainsAttributeCerts)\n    {\n        this(distributionPoint, false, false, null, indirectCRL, onlyContainsAttributeCerts);\n    }\n\n    /**\n     * Constructor from ASN1Sequence\n     */\n    private IssuingDistributionPoint(\n        ASN1Sequence seq)\n    {\n        this.seq = seq;\n\n        for (int i = 0; i != seq.size(); i++)\n        {\n            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));\n\n            switch (o.getTagNo())\n            {\n            case 0:\n                                                    // CHOICE so explicit\n                distributionPoint = DistributionPointName.getInstance(o, true);\n                break;\n            case 1:\n                onlyContainsUserCerts = ASN1Boolean.getInstance(o, false).isTrue();\n                break;\n            case 2:\n                onlyContainsCACerts = ASN1Boolean.getInstance(o, false).isTrue();\n                break;\n            case 3:\n                onlySomeReasons = new ReasonFlags(ReasonFlags.getInstance(o, false));\n                break;\n            case 4:\n                indirectCRL = ASN1Boolean.getInstance(o, false).isTrue();\n                break;\n            case 5:\n                onlyContainsAttributeCerts = ASN1Boolean.getInstance(o, false).isTrue();\n                break;\n            default:\n                throw new IllegalArgumentException(\n                        \"unknown tag in IssuingDistributionPoint\");\n            }\n        }\n    }\n\n    public boolean onlyContainsUserCerts()\n    {\n        return onlyContainsUserCerts;\n    }\n\n    public boolean onlyContainsCACerts()\n    {\n        return onlyContainsCACerts;\n    }\n\n    public boolean isIndirectCRL()\n    {\n        return indirectCRL;\n    }\n\n    public boolean onlyContainsAttributeCerts()\n    {\n        return onlyContainsAttributeCerts;\n    }\n\n    /**\n     * @return Returns the distributionPoint.\n     */\n    public DistributionPointName getDistributionPoint()\n    {\n        return distributionPoint;\n    }\n\n    /**\n     * @return Returns the onlySomeReasons.\n     */\n    public ReasonFlags getOnlySomeReasons()\n    {\n        return onlySomeReasons;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return seq;\n    }\n\n    public String toString()\n    {\n        String       sep = System.getProperty(\"line.separator\");\n        StringBuffer buf = new StringBuffer();\n\n        buf.append(\"IssuingDistributionPoint: [\");\n        buf.append(sep);\n        if (distributionPoint != null)\n        {\n            appendObject(buf, sep, \"distributionPoint\", distributionPoint.toString());\n        }\n        if (onlyContainsUserCerts)\n        {\n            appendObject(buf, sep, \"onlyContainsUserCerts\", booleanToString(onlyContainsUserCerts));\n        }\n        if (onlyContainsCACerts)\n        {\n            appendObject(buf, sep, \"onlyContainsCACerts\", booleanToString(onlyContainsCACerts));\n        }\n        if (onlySomeReasons != null)\n        {\n            appendObject(buf, sep, \"onlySomeReasons\", onlySomeReasons.toString());\n        }\n        if (onlyContainsAttributeCerts)\n        {\n            appendObject(buf, sep, \"onlyContainsAttributeCerts\", booleanToString(onlyContainsAttributeCerts));\n        }\n        if (indirectCRL)\n        {\n            appendObject(buf, sep, \"indirectCRL\", booleanToString(indirectCRL));\n        }\n        buf.append(\"]\");\n        buf.append(sep);\n        return buf.toString();\n    }\n\n    private void appendObject(StringBuffer buf, String sep, String name, String value)\n    {\n        String       indent = \"    \";\n\n        buf.append(indent);\n        buf.append(name);\n        buf.append(\":\");\n        buf.append(sep);\n        buf.append(indent);\n        buf.append(indent);\n        buf.append(value);\n        buf.append(sep);\n    }\n\n    private String booleanToString(boolean value)\n    {\n        return value ? \"true\" : \"false\";\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/KeyPurposeId.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\n\n/**\n * The KeyPurposeId object.\n * <pre>\n *     KeyPurposeId ::= OBJECT IDENTIFIER\n *\n *     id-kp ::= OBJECT IDENTIFIER { iso(1) identified-organization(3) \n *          dod(6) internet(1) security(5) mechanisms(5) pkix(7) 3}\n *\n * </pre>\n * To create a new KeyPurposeId where none of the below suit, use\n * <pre>\n *     ASN1ObjectIdentifier newKeyPurposeIdOID = new ASN1ObjectIdentifier(\"1.3.6.1...\");\n *\n *     KeyPurposeId newKeyPurposeId = KeyPurposeId.getInstance(newKeyPurposeIdOID);\n * </pre>\n */\npublic class KeyPurposeId\n    extends ASN1Object\n{\n    private static final ASN1ObjectIdentifier id_kp = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.3\");\n\n    /**\n     * { 2 5 29 37 0 }\n     */\n    public static final KeyPurposeId anyExtendedKeyUsage = new KeyPurposeId(Extension.extendedKeyUsage.branch(\"0\"));\n\n    /**\n     * { id-kp 1 }\n     */\n    public static final KeyPurposeId id_kp_serverAuth = new KeyPurposeId(id_kp.branch(\"1\"));\n    /**\n     * { id-kp 2 }\n     */\n    public static final KeyPurposeId id_kp_clientAuth = new KeyPurposeId(id_kp.branch(\"2\"));\n    /**\n     * { id-kp 3 }\n     */\n    public static final KeyPurposeId id_kp_codeSigning = new KeyPurposeId(id_kp.branch(\"3\"));\n    /**\n     * { id-kp 4 }\n     */\n    public static final KeyPurposeId id_kp_emailProtection = new KeyPurposeId(id_kp.branch(\"4\"));\n    /**\n     * Usage deprecated by RFC4945 - was { id-kp 5 }\n     */\n    public static final KeyPurposeId id_kp_ipsecEndSystem = new KeyPurposeId(id_kp.branch(\"5\"));\n    /**\n     * Usage deprecated by RFC4945 - was { id-kp 6 }\n     */\n    public static final KeyPurposeId id_kp_ipsecTunnel = new KeyPurposeId(id_kp.branch(\"6\"));\n    /**\n     * Usage deprecated by RFC4945 - was { idkp 7 }\n     */\n    public static final KeyPurposeId id_kp_ipsecUser = new KeyPurposeId(id_kp.branch(\"7\"));\n    /**\n     * { id-kp 8 }\n     */\n    public static final KeyPurposeId id_kp_timeStamping = new KeyPurposeId(id_kp.branch(\"8\"));\n    /**\n     * { id-kp 9 }\n     */\n    public static final KeyPurposeId id_kp_OCSPSigning = new KeyPurposeId(id_kp.branch(\"9\"));\n    /**\n     * { id-kp 10 }\n     */\n    public static final KeyPurposeId id_kp_dvcs = new KeyPurposeId(id_kp.branch(\"10\"));\n    /**\n     * { id-kp 11 }\n     */\n    public static final KeyPurposeId id_kp_sbgpCertAAServerAuth = new KeyPurposeId(id_kp.branch(\"11\"));\n    /**\n     * { id-kp 12 }\n     */\n    public static final KeyPurposeId id_kp_scvp_responder = new KeyPurposeId(id_kp.branch(\"12\"));\n    /**\n     * { id-kp 13 }\n     */\n    public static final KeyPurposeId id_kp_eapOverPPP = new KeyPurposeId(id_kp.branch(\"13\"));\n    /**\n     * { id-kp 14 }\n     */\n    public static final KeyPurposeId id_kp_eapOverLAN = new KeyPurposeId(id_kp.branch(\"14\"));\n    /**\n     * { id-kp 15 }\n     */\n    public static final KeyPurposeId id_kp_scvpServer = new KeyPurposeId(id_kp.branch(\"15\"));\n    /**\n     * { id-kp 16 }\n     */\n    public static final KeyPurposeId id_kp_scvpClient = new KeyPurposeId(id_kp.branch(\"16\"));\n    /**\n     * { id-kp 17 }\n     */\n    public static final KeyPurposeId id_kp_ipsecIKE = new KeyPurposeId(id_kp.branch(\"17\"));\n    /**\n     * { id-kp 18 }\n     */\n    public static final KeyPurposeId id_kp_capwapAC = new KeyPurposeId(id_kp.branch(\"18\"));\n    /**\n     * { id-kp 19 }\n     */\n    public static final KeyPurposeId id_kp_capwapWTP = new KeyPurposeId(id_kp.branch(\"19\"));\n\n    //\n    // microsoft key purpose ids\n    //\n    /**\n     * { 1 3 6 1 4 1 311 20 2 2 }\n     */\n    public static final KeyPurposeId id_kp_smartcardlogon = new KeyPurposeId(new ASN1ObjectIdentifier(\"1.3.6.1.4.1.311.20.2.2\"));\n\n    private ASN1ObjectIdentifier id;\n\n    private KeyPurposeId(ASN1ObjectIdentifier id)\n    {\n        this.id = id;\n    }\n\n    /**\n     * @deprecated use getInstance and an OID or one of the constants above.\n     * @param id string representation of an OID.\n     */\n    public KeyPurposeId(String id)\n    {\n        this(new ASN1ObjectIdentifier(id));\n    }\n\n    public static KeyPurposeId getInstance(Object o)\n    {\n        if (o instanceof KeyPurposeId)\n        {\n            return (KeyPurposeId)o;\n        }\n        else if (o != null)\n        {\n            return new KeyPurposeId(ASN1ObjectIdentifier.getInstance(o));\n        }\n\n        return null;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return id;\n    }\n\n    public String getId()\n    {\n        return id.getId();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/KeyUsage.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DERBitString;\n\n/**\n * The KeyUsage object.\n * <pre>\n *    id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }\n *\n *    KeyUsage ::= BIT STRING {\n *         digitalSignature        (0),\n *         nonRepudiation          (1),\n *         keyEncipherment         (2),\n *         dataEncipherment        (3),\n *         keyAgreement            (4),\n *         keyCertSign             (5),\n *         cRLSign                 (6),\n *         encipherOnly            (7),\n *         decipherOnly            (8) }\n * </pre>\n */\npublic class KeyUsage\n    extends ASN1Object\n{\n    public static final int        digitalSignature = (1 << 7); \n    public static final int        nonRepudiation   = (1 << 6);\n    public static final int        keyEncipherment  = (1 << 5);\n    public static final int        dataEncipherment = (1 << 4);\n    public static final int        keyAgreement     = (1 << 3);\n    public static final int        keyCertSign      = (1 << 2);\n    public static final int        cRLSign          = (1 << 1);\n    public static final int        encipherOnly     = (1 << 0);\n    public static final int        decipherOnly     = (1 << 15);\n\n    private DERBitString bitString;\n\n    public static KeyUsage getInstance(Object obj)   // needs to be DERBitString for other VMs\n    {\n        if (obj instanceof KeyUsage)\n        {\n            return (KeyUsage)obj;\n        }\n        else if (obj != null)\n        {\n            return new KeyUsage(DERBitString.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static KeyUsage fromExtensions(Extensions extensions)\n    {\n        return KeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.keyUsage));\n    }\n\n    /**\n     * Basic constructor.\n     * \n     * @param usage - the bitwise OR of the Key Usage flags giving the\n     * allowed uses for the key.\n     * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)\n     */\n    public KeyUsage(\n        int usage)\n    {\n        this.bitString = new DERBitString(usage);\n    }\n\n    private KeyUsage(\n        DERBitString bitString)\n    {\n        this.bitString = bitString;\n    }\n\n    public byte[] getBytes()\n    {\n        return bitString.getBytes();\n    }\n\n    public int getPadBits()\n    {\n        return bitString.getPadBits();\n    }\n\n    public String toString()\n    {\n        byte[] data = bitString.getBytes();\n\n        if (data.length == 1)\n        {\n            return \"KeyUsage: 0x\" + Integer.toHexString(data[0] & 0xff);\n        }\n        return \"KeyUsage: 0x\" + Integer.toHexString((data[1] & 0xff) << 8 | (data[0] & 0xff));\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return bitString;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/ObjectDigestInfo.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Enumerated;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n/**\n * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.\n * \n * <pre>\n *  \n *    ObjectDigestInfo ::= SEQUENCE {\n *         digestedObjectType  ENUMERATED {\n *                 publicKey            (0),\n *                 publicKeyCert        (1),\n *                 otherObjectTypes     (2) },\n *                         -- otherObjectTypes MUST NOT\n *                         -- be used in this profile\n *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,\n *         digestAlgorithm     AlgorithmIdentifier,\n *         objectDigest        BIT STRING\n *    }\n *   \n * </pre>\n * \n */\npublic class ObjectDigestInfo\n    extends ASN1Object\n{\n    /**\n     * The public key is hashed.\n     */\n    public final static int publicKey = 0;\n\n    /**\n     * The public key certificate is hashed.\n     */\n    public final static int publicKeyCert = 1;\n\n    /**\n     * An other object is hashed.\n     */\n    public final static int otherObjectDigest = 2;\n\n    ASN1Enumerated digestedObjectType;\n\n    ASN1ObjectIdentifier otherObjectTypeID;\n\n    AlgorithmIdentifier digestAlgorithm;\n\n    DERBitString objectDigest;\n\n    public static ObjectDigestInfo getInstance(\n        Object obj)\n    {\n        if (obj instanceof ObjectDigestInfo)\n        {\n            return (ObjectDigestInfo)obj;\n        }\n\n        if (obj != null)\n        {\n            return new ObjectDigestInfo(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static ObjectDigestInfo getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    /**\n     * Constructor from given details.\n     * <p>\n     * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or\n     * {@link #publicKey} <code>otherObjectTypeID</code> must be given,\n     * otherwise it is ignored.\n     * \n     * @param digestedObjectType The digest object type.\n     * @param otherObjectTypeID The object type ID for\n     *            <code>otherObjectDigest</code>.\n     * @param digestAlgorithm The algorithm identifier for the hash.\n     * @param objectDigest The hash value.\n     */\n    public ObjectDigestInfo(\n        int digestedObjectType,\n        ASN1ObjectIdentifier otherObjectTypeID,\n        AlgorithmIdentifier digestAlgorithm,\n        byte[] objectDigest)\n    {\n        this.digestedObjectType = new ASN1Enumerated(digestedObjectType);\n        if (digestedObjectType == otherObjectDigest)\n        {\n            this.otherObjectTypeID = otherObjectTypeID;\n        }\n\n        this.digestAlgorithm = digestAlgorithm;\n        this.objectDigest = new DERBitString(objectDigest);\n    }\n\n    private ObjectDigestInfo(\n        ASN1Sequence seq)\n    {\n        if (seq.size() > 4 || seq.size() < 3)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \"\n                + seq.size());\n        }\n\n        digestedObjectType = ASN1Enumerated.getInstance(seq.getObjectAt(0));\n\n        int offset = 0;\n\n        if (seq.size() == 4)\n        {\n            otherObjectTypeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));\n            offset++;\n        }\n\n        digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset));\n\n        objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset));\n    }\n\n    public ASN1Enumerated getDigestedObjectType()\n    {\n        return digestedObjectType;\n    }\n\n    public ASN1ObjectIdentifier getOtherObjectTypeID()\n    {\n        return otherObjectTypeID;\n    }\n\n    public AlgorithmIdentifier getDigestAlgorithm()\n    {\n        return digestAlgorithm;\n    }\n\n    public DERBitString getObjectDigest()\n    {\n        return objectDigest;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * \n     * <pre>\n     *  \n     *    ObjectDigestInfo ::= SEQUENCE {\n     *         digestedObjectType  ENUMERATED {\n     *                 publicKey            (0),\n     *                 publicKeyCert        (1),\n     *                 otherObjectTypes     (2) },\n     *                         -- otherObjectTypes MUST NOT\n     *                         -- be used in this profile\n     *         otherObjectTypeID   OBJECT IDENTIFIER OPTIONAL,\n     *         digestAlgorithm     AlgorithmIdentifier,\n     *         objectDigest        BIT STRING\n     *    }\n     *   \n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(digestedObjectType);\n\n        if (otherObjectTypeID != null)\n        {\n            v.add(otherObjectTypeID);\n        }\n\n        v.add(digestAlgorithm);\n        v.add(objectDigest);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/ReasonFlags.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.DERBitString;\n\n/**\n * The ReasonFlags object.\n * <pre>\n * ReasonFlags ::= BIT STRING {\n *      unused                  (0),\n *      keyCompromise           (1),\n *      cACompromise            (2),\n *      affiliationChanged      (3),\n *      superseded              (4),\n *      cessationOfOperation    (5),\n *      certificateHold         (6),\n *      privilegeWithdrawn      (7),\n *      aACompromise            (8) }\n * </pre>\n */\npublic class ReasonFlags\n    extends DERBitString\n{\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int UNUSED                  = (1 << 7);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int KEY_COMPROMISE          = (1 << 6);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int CA_COMPROMISE           = (1 << 5);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int AFFILIATION_CHANGED     = (1 << 4);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int SUPERSEDED              = (1 << 3);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int CESSATION_OF_OPERATION  = (1 << 2);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int CERTIFICATE_HOLD        = (1 << 1);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int PRIVILEGE_WITHDRAWN     = (1 << 0);\n    /**\n     * @deprecated use lower case version\n     */\n    public static final int AA_COMPROMISE           = (1 << 15);\n    \n    public static final int unused                  = (1 << 7);\n    public static final int keyCompromise           = (1 << 6);\n    public static final int cACompromise            = (1 << 5);\n    public static final int affiliationChanged      = (1 << 4);\n    public static final int superseded              = (1 << 3);\n    public static final int cessationOfOperation    = (1 << 2);\n    public static final int certificateHold         = (1 << 1);\n    public static final int privilegeWithdrawn      = (1 << 0);\n    public static final int aACompromise            = (1 << 15);\n\n    /**\n     * @param reasons - the bitwise OR of the Key Reason flags giving the\n     * allowed uses for the key.\n     */\n    public ReasonFlags(\n        int reasons)\n    {\n        super(getBytes(reasons), getPadBits(reasons));\n    }\n\n    public ReasonFlags(\n        DERBitString reasons)\n    {\n        super(reasons.getBytes(), reasons.getPadBits());\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.crypto.Digest;\nimport local.org.bouncycastle.crypto.digests.SHA1Digest;\n\n/**\n * The SubjectKeyIdentifier object.\n * <pre>\n * SubjectKeyIdentifier::= OCTET STRING\n * </pre>\n */\npublic class SubjectKeyIdentifier\n    extends ASN1Object\n{\n    private byte[] keyidentifier;\n\n    public static SubjectKeyIdentifier getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1OctetString.getInstance(obj, explicit));\n    }\n\n    public static SubjectKeyIdentifier getInstance(\n        Object obj)\n    {\n        if (obj instanceof SubjectKeyIdentifier)\n        {\n            return (SubjectKeyIdentifier)obj;\n        }\n        else if (obj != null)\n        {\n            return new SubjectKeyIdentifier(ASN1OctetString.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public static SubjectKeyIdentifier fromExtensions(Extensions extensions)\n    {\n        return SubjectKeyIdentifier.getInstance(extensions.getExtensionParsedValue(Extension.subjectKeyIdentifier));\n    }\n\n    public SubjectKeyIdentifier(\n        byte[] keyid)\n    {\n        this.keyidentifier = keyid;\n    }\n\n    protected SubjectKeyIdentifier(\n        ASN1OctetString keyid)\n    {\n        this.keyidentifier = keyid.getOctets();\n    }\n\n    public byte[] getKeyIdentifier()\n    {\n        return keyidentifier;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return new DEROctetString(keyidentifier);\n    }\n\n\n    /**\n     * Calculates the keyidentifier using a SHA1 hash over the BIT STRING\n     * from SubjectPublicKeyInfo as defined in RFC3280.\n     *\n     * @param spki the subject public key info.\n     * @deprecated\n     */\n    public SubjectKeyIdentifier(\n        SubjectPublicKeyInfo    spki)\n    {\n        this.keyidentifier = getDigest(spki);\n    }\n\n    /**\n     * Return a RFC 3280 type 1 key identifier. As in:\n     * <pre>\n     * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the\n     * value of the BIT STRING subjectPublicKey (excluding the tag,\n     * length, and number of unused bits).\n     * </pre>\n     * @param keyInfo the key info object containing the subjectPublicKey field.\n     * @return the key identifier.\n     * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createSubjectKeyIdentifier\n     */\n    public static SubjectKeyIdentifier createSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo)\n    {\n        return new SubjectKeyIdentifier(keyInfo);\n    }\n\n    /**\n     * Return a RFC 3280 type 2 key identifier. As in:\n     * <pre>\n     * (2) The keyIdentifier is composed of a four bit type field with\n     * the value 0100 followed by the least significant 60 bits of the\n     * SHA-1 hash of the value of the BIT STRING subjectPublicKey.\n     * </pre>\n     * @param keyInfo the key info object containing the subjectPublicKey field.\n     * @return the key identifier.\n     * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createTruncatedSubjectKeyIdentifier\n     */\n    public static SubjectKeyIdentifier createTruncatedSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo)\n    {\n        byte[] dig = getDigest(keyInfo);\n        byte[] id = new byte[8];\n\n        System.arraycopy(dig, dig.length - 8, id, 0, id.length);\n\n        id[0] &= 0x0f;\n        id[0] |= 0x40;\n        \n        return new SubjectKeyIdentifier(id);\n    }\n\n    private static byte[] getDigest(SubjectPublicKeyInfo spki)\n    {\n        Digest digest = new SHA1Digest();\n        byte[]  resBuf = new byte[digest.getDigestSize()];\n\n        byte[] bytes = spki.getPublicKeyData().getBytes();\n        digest.update(bytes, 0, bytes.length);\n        digest.doFinal(resBuf, 0);\n        return resBuf;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1InputStream;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\n/**\n * The object that contains the public key stored in a certficate.\n * <p>\n * The getEncoded() method in the public keys in the JCE produces a DER\n * encoded one of these.\n */\npublic class SubjectPublicKeyInfo\n    extends ASN1Object\n{\n    private AlgorithmIdentifier     algId;\n    private DERBitString            keyData;\n\n    public static SubjectPublicKeyInfo getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static SubjectPublicKeyInfo getInstance(\n        Object  obj)\n    {\n        if (obj instanceof SubjectPublicKeyInfo)\n        {\n            return (SubjectPublicKeyInfo)obj;\n        }\n        else if (obj != null)\n        {\n            return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public SubjectPublicKeyInfo(\n        AlgorithmIdentifier algId,\n        ASN1Encodable       publicKey)\n        throws IOException\n    {\n        this.keyData = new DERBitString(publicKey);\n        this.algId = algId;\n    }\n\n    public SubjectPublicKeyInfo(\n        AlgorithmIdentifier algId,\n        byte[]              publicKey)\n    {\n        this.keyData = new DERBitString(publicKey);\n        this.algId = algId;\n    }\n\n    public SubjectPublicKeyInfo(\n        ASN1Sequence  seq)\n    {\n        if (seq.size() != 2)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \"\n                    + seq.size());\n        }\n\n        Enumeration         e = seq.getObjects();\n\n        this.algId = AlgorithmIdentifier.getInstance(e.nextElement());\n        this.keyData = DERBitString.getInstance(e.nextElement());\n    }\n\n    public AlgorithmIdentifier getAlgorithm()\n    {\n        return algId;\n    }\n\n    /**\n     * @deprecated use getAlgorithm()\n     * @return    alg ID.\n     */\n    public AlgorithmIdentifier getAlgorithmId()\n    {\n        return algId;\n    }\n\n    /**\n     * for when the public key is an encoded object - if the bitstring\n     * can't be decoded this routine throws an IOException.\n     *\n     * @exception IOException - if the bit string doesn't represent a DER\n     * encoded object.\n     * @return the public key as an ASN.1 primitive.\n     */\n    public ASN1Primitive parsePublicKey()\n        throws IOException\n    {\n        ASN1InputStream         aIn = new ASN1InputStream(keyData.getBytes());\n\n        return aIn.readObject();\n    }\n\n    /**\n     * for when the public key is an encoded object - if the bitstring\n     * can't be decoded this routine throws an IOException.\n     *\n     * @exception IOException - if the bit string doesn't represent a DER\n     * encoded object.\n     * @deprecated use parsePublicKey\n     * @return the public key as an ASN.1 primitive.\n     */\n    public ASN1Primitive getPublicKey()\n        throws IOException\n    {\n        ASN1InputStream         aIn = new ASN1InputStream(keyData.getBytes());\n\n        return aIn.readObject();\n    }\n\n    /**\n     * for when the public key is raw bits.\n     *\n     * @return the public key as the raw bit string...\n     */\n    public DERBitString getPublicKeyData()\n    {\n        return keyData;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     * SubjectPublicKeyInfo ::= SEQUENCE {\n     *                          algorithm AlgorithmIdentifier,\n     *                          publicKey BIT STRING }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(algId);\n        v.add(keyData);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/TBSCertList.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.util.Enumeration;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERGeneralizedTime;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.asn1.DERUTCTime;\nimport local.org.bouncycastle.asn1.x500.X500Name;\n\n\n/**\n * PKIX RFC-2459 - TBSCertList object.\n * <pre>\n * TBSCertList  ::=  SEQUENCE  {\n *      version                 Version OPTIONAL,\n *                                   -- if present, shall be v2\n *      signature               AlgorithmIdentifier,\n *      issuer                  Name,\n *      thisUpdate              Time,\n *      nextUpdate              Time OPTIONAL,\n *      revokedCertificates     SEQUENCE OF SEQUENCE  {\n *           userCertificate         CertificateSerialNumber,\n *           revocationDate          Time,\n *           crlEntryExtensions      Extensions OPTIONAL\n *                                         -- if present, shall be v2\n *                                }  OPTIONAL,\n *      crlExtensions           [0]  EXPLICIT Extensions OPTIONAL\n *                                         -- if present, shall be v2\n *                                }\n * </pre>\n */\npublic class TBSCertList\n    extends ASN1Object\n{\n    public static class CRLEntry\n        extends ASN1Object\n    {\n        ASN1Sequence  seq;\n\n        Extensions    crlEntryExtensions;\n\n        private CRLEntry(\n            ASN1Sequence  seq)\n        {\n            if (seq.size() < 2 || seq.size() > 3)\n            {\n                throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n            }\n            \n            this.seq = seq;\n        }\n\n        public static CRLEntry getInstance(Object o)\n        {\n            if (o instanceof CRLEntry)\n            {\n                return ((CRLEntry)o);\n            }\n            else if (o != null)\n            {\n                return new CRLEntry(ASN1Sequence.getInstance(o));\n            }\n\n            return null;\n        }\n\n        public ASN1Integer getUserCertificate()\n        {\n            return ASN1Integer.getInstance(seq.getObjectAt(0));\n        }\n\n        public Time getRevocationDate()\n        {\n            return Time.getInstance(seq.getObjectAt(1));\n        }\n\n        public Extensions getExtensions()\n        {\n            if (crlEntryExtensions == null && seq.size() == 3)\n            {\n                crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2));\n            }\n            \n            return crlEntryExtensions;\n        }\n\n        public ASN1Primitive toASN1Primitive()\n        {\n            return seq;\n        }\n\n        public boolean hasExtensions()\n        {\n            return seq.size() == 3;\n        }\n    }\n\n    private class RevokedCertificatesEnumeration\n        implements Enumeration\n    {\n        private final Enumeration en;\n\n        RevokedCertificatesEnumeration(Enumeration en)\n        {\n            this.en = en;\n        }\n\n        public boolean hasMoreElements()\n        {\n            return en.hasMoreElements();\n        }\n\n        public Object nextElement()\n        {\n            return CRLEntry.getInstance(en.nextElement());\n        }\n    }\n\n    private class EmptyEnumeration\n        implements Enumeration\n    {\n        public boolean hasMoreElements()\n        {\n            return false;\n        }\n\n        public Object nextElement()\n        {\n            return null;   // TODO: check exception handling\n        }\n    }\n\n    ASN1Integer             version;\n    AlgorithmIdentifier     signature;\n    X500Name                issuer;\n    Time                    thisUpdate;\n    Time                    nextUpdate;\n    ASN1Sequence            revokedCertificates;\n    Extensions              crlExtensions;\n\n    public static TBSCertList getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static TBSCertList getInstance(\n        Object  obj)\n    {\n        if (obj instanceof TBSCertList)\n        {\n            return (TBSCertList)obj;\n        }\n        else if (obj != null)\n        {\n            return new TBSCertList(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public TBSCertList(\n        ASN1Sequence  seq)\n    {\n        if (seq.size() < 3 || seq.size() > 7)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n        }\n\n        int seqPos = 0;\n\n        if (seq.getObjectAt(seqPos) instanceof ASN1Integer)\n        {\n            version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++));\n        }\n        else\n        {\n            version = null;  // version is optional\n        }\n\n        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));\n        issuer = X500Name.getInstance(seq.getObjectAt(seqPos++));\n        thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));\n\n        if (seqPos < seq.size()\n            && (seq.getObjectAt(seqPos) instanceof DERUTCTime\n               || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime\n               || seq.getObjectAt(seqPos) instanceof Time))\n        {\n            nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++));\n        }\n\n        if (seqPos < seq.size()\n            && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject))\n        {\n            revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));\n        }\n\n        if (seqPos < seq.size()\n            && seq.getObjectAt(seqPos) instanceof DERTaggedObject)\n        {\n            crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true));\n        }\n    }\n\n    public int getVersionNumber()\n    {\n        if (version == null)\n        {\n            return 1;\n        }\n        return version.getValue().intValue() + 1;\n    }\n\n    public ASN1Integer getVersion()\n    {\n        return version;\n    }\n\n    public AlgorithmIdentifier getSignature()\n    {\n        return signature;\n    }\n\n    public X500Name getIssuer()\n    {\n        return issuer;\n    }\n\n    public Time getThisUpdate()\n    {\n        return thisUpdate;\n    }\n\n    public Time getNextUpdate()\n    {\n        return nextUpdate;\n    }\n\n    public CRLEntry[] getRevokedCertificates()\n    {\n        if (revokedCertificates == null)\n        {\n            return new CRLEntry[0];\n        }\n\n        CRLEntry[] entries = new CRLEntry[revokedCertificates.size()];\n\n        for (int i = 0; i < entries.length; i++)\n        {\n            entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i));\n        }\n        \n        return entries;\n    }\n\n    public Enumeration getRevokedCertificateEnumeration()\n    {\n        if (revokedCertificates == null)\n        {\n            return new EmptyEnumeration();\n        }\n\n        return new RevokedCertificatesEnumeration(revokedCertificates.getObjects());\n    }\n\n    public Extensions getExtensions()\n    {\n        return crlExtensions;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        if (version != null)\n        {\n            v.add(version);\n        }\n        v.add(signature);\n        v.add(issuer);\n\n        v.add(thisUpdate);\n        if (nextUpdate != null)\n        {\n            v.add(nextUpdate);\n        }\n\n        // Add CRLEntries if they exist\n        if (revokedCertificates != null)\n        {\n            v.add(revokedCertificates);\n        }\n\n        if (crlExtensions != null)\n        {\n            v.add(new DERTaggedObject(0, crlExtensions));\n        }\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/TBSCertificate.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.asn1.x500.X500Name;\n\n/**\n * The TBSCertificate object.\n * <pre>\n * TBSCertificate ::= SEQUENCE {\n *      version          [ 0 ]  Version DEFAULT v1(0),\n *      serialNumber            CertificateSerialNumber,\n *      signature               AlgorithmIdentifier,\n *      issuer                  Name,\n *      validity                Validity,\n *      subject                 Name,\n *      subjectPublicKeyInfo    SubjectPublicKeyInfo,\n *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,\n *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,\n *      extensions        [ 3 ] Extensions OPTIONAL\n *      }\n * </pre>\n * <p>\n * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class\n * will parse them, but you really shouldn't be creating new ones.\n */\npublic class TBSCertificate\n    extends ASN1Object\n{\n    ASN1Sequence            seq;\n\n    ASN1Integer             version;\n    ASN1Integer             serialNumber;\n    AlgorithmIdentifier     signature;\n    X500Name                issuer;\n    Time                    startDate, endDate;\n    X500Name                subject;\n    SubjectPublicKeyInfo    subjectPublicKeyInfo;\n    DERBitString            issuerUniqueId;\n    DERBitString            subjectUniqueId;\n    Extensions              extensions;\n\n    public static TBSCertificate getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static TBSCertificate getInstance(\n        Object  obj)\n    {\n        if (obj instanceof TBSCertificate)\n        {\n            return (TBSCertificate)obj;\n        }\n        else if (obj != null)\n        {\n            return new TBSCertificate(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    private TBSCertificate(\n        ASN1Sequence seq)\n    {\n        int         seqStart = 0;\n\n        this.seq = seq;\n\n        //\n        // some certficates don't include a version number - we assume v1\n        //\n        if (seq.getObjectAt(0) instanceof DERTaggedObject)\n        {\n            version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);\n        }\n        else\n        {\n            seqStart = -1;          // field 0 is missing!\n            version = new ASN1Integer(0);\n        }\n\n        serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));\n\n        signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));\n        issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));\n\n        //\n        // before and after dates\n        //\n        ASN1Sequence  dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);\n\n        startDate = Time.getInstance(dates.getObjectAt(0));\n        endDate = Time.getInstance(dates.getObjectAt(1));\n\n        subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));\n\n        //\n        // public key info.\n        //\n        subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));\n\n        for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)\n        {\n            DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);\n\n            switch (extra.getTagNo())\n            {\n            case 1:\n                issuerUniqueId = DERBitString.getInstance(extra, false);\n                break;\n            case 2:\n                subjectUniqueId = DERBitString.getInstance(extra, false);\n                break;\n            case 3:\n                extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true));\n            }\n        }\n    }\n\n    public int getVersionNumber()\n    {\n        return version.getValue().intValue() + 1;\n    }\n\n    public ASN1Integer getVersion()\n    {\n        return version;\n    }\n\n    public ASN1Integer getSerialNumber()\n    {\n        return serialNumber;\n    }\n\n    public AlgorithmIdentifier getSignature()\n    {\n        return signature;\n    }\n\n    public X500Name getIssuer()\n    {\n        return issuer;\n    }\n\n    public Time getStartDate()\n    {\n        return startDate;\n    }\n\n    public Time getEndDate()\n    {\n        return endDate;\n    }\n\n    public X500Name getSubject()\n    {\n        return subject;\n    }\n\n    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()\n    {\n        return subjectPublicKeyInfo;\n    }\n\n    public DERBitString getIssuerUniqueId()\n    {\n        return issuerUniqueId;\n    }\n\n    public DERBitString getSubjectUniqueId()\n    {\n        return subjectUniqueId;\n    }\n\n    public Extensions getExtensions()\n    {\n        return extensions;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        return seq;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/Time.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.SimpleTimeZone;\n\nimport local.org.bouncycastle.asn1.ASN1Choice;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERGeneralizedTime;\nimport local.org.bouncycastle.asn1.DERUTCTime;\n\n\npublic class Time\n    extends ASN1Object\n    implements ASN1Choice\n{\n    ASN1Primitive time;\n\n    public static Time getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(obj.getObject()); // must be explicitly tagged\n    }\n\n    public Time(\n        ASN1Primitive   time)\n    {\n        if (!(time instanceof DERUTCTime)\n            && !(time instanceof DERGeneralizedTime))\n        {\n            throw new IllegalArgumentException(\"unknown object passed to Time\");\n        }\n\n        this.time = time; \n    }\n\n    /**\n     * creates a time object from a given date - if the date is between 1950\n     * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime\n     * is used.\n     */\n    public Time(\n        Date    date)\n    {\n        SimpleTimeZone      tz = new SimpleTimeZone(0, \"Z\");\n        SimpleDateFormat    dateF = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n\n        dateF.setTimeZone(tz);\n\n        String  d = dateF.format(date) + \"Z\";\n        int     year = Integer.parseInt(d.substring(0, 4));\n\n        if (year < 1950 || year > 2049)\n        {\n            time = new DERGeneralizedTime(d);\n        }\n        else\n        {\n            time = new DERUTCTime(d.substring(2));\n        }\n    }\n\n    public static Time getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof Time)\n        {\n            return (Time)obj;\n        }\n        else if (obj instanceof DERUTCTime)\n        {\n            return new Time((DERUTCTime)obj);\n        }\n        else if (obj instanceof DERGeneralizedTime)\n        {\n            return new Time((DERGeneralizedTime)obj);\n        }\n\n        throw new IllegalArgumentException(\"unknown object in factory: \" + obj.getClass().getName());\n    }\n\n    public String getTime()\n    {\n        if (time instanceof DERUTCTime)\n        {\n            return ((DERUTCTime)time).getAdjustedTime();\n        }\n        else\n        {\n            return ((DERGeneralizedTime)time).getTime();\n        }\n    }\n\n    public Date getDate()\n    {\n        try\n        {\n            if (time instanceof DERUTCTime)\n            {\n                return ((DERUTCTime)time).getAdjustedDate();\n            }\n            else\n            {\n                return ((DERGeneralizedTime)time).getDate();\n            }\n        }\n        catch (ParseException e)\n        {         // this should never happen\n            throw new IllegalStateException(\"invalid date string: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     * Time ::= CHOICE {\n     *             utcTime        UTCTime,\n     *             generalTime    GeneralizedTime }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        return time;\n    }\n\n    public String toString()\n    {\n        return getTime();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/V2Form.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\n\npublic class V2Form\n    extends ASN1Object\n{\n    GeneralNames        issuerName;\n    IssuerSerial        baseCertificateID;\n    ObjectDigestInfo    objectDigestInfo;\n\n    public static V2Form getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static V2Form getInstance(\n        Object  obj)\n    {\n        if (obj instanceof V2Form)\n        {\n            return (V2Form)obj;\n        }\n        else if (obj != null)\n        {\n            return new V2Form(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n    \n    public V2Form(\n        GeneralNames    issuerName)\n    {\n        this(issuerName, null, null);\n    }\n\n    public V2Form(\n        GeneralNames    issuerName,\n        IssuerSerial    baseCertificateID)\n    {\n        this(issuerName, baseCertificateID, null);\n    }\n\n    public V2Form(\n        GeneralNames    issuerName,\n        ObjectDigestInfo objectDigestInfo)\n    {\n        this(issuerName, null, objectDigestInfo);\n    }\n\n    public V2Form(\n        GeneralNames    issuerName,\n        IssuerSerial    baseCertificateID,\n        ObjectDigestInfo objectDigestInfo)\n    {\n        this.issuerName = issuerName;\n        this.baseCertificateID = baseCertificateID;\n        this.objectDigestInfo = objectDigestInfo;\n    }\n\n    /**\n     * @deprecated use getInstance().\n     */\n    public V2Form(\n        ASN1Sequence seq)\n    {\n        if (seq.size() > 3)\n        {\n            throw new IllegalArgumentException(\"Bad sequence size: \" + seq.size());\n        }\n        \n        int    index = 0;\n\n        if (!(seq.getObjectAt(0) instanceof ASN1TaggedObject))\n        {\n            index++;\n            this.issuerName = GeneralNames.getInstance(seq.getObjectAt(0));\n        }\n\n        for (int i = index; i != seq.size(); i++)\n        {\n            ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));\n            if (o.getTagNo() == 0)\n            {\n                baseCertificateID = IssuerSerial.getInstance(o, false);\n            }\n            else if (o.getTagNo() == 1)\n            {\n                objectDigestInfo = ObjectDigestInfo.getInstance(o, false);\n            }\n            else \n            {\n                throw new IllegalArgumentException(\"Bad tag number: \"\n                        + o.getTagNo());\n            }\n        }\n    }\n    \n    public GeneralNames getIssuerName()\n    {\n        return issuerName;\n    }\n\n    public IssuerSerial getBaseCertificateID()\n    {\n        return baseCertificateID;\n    }\n\n    public ObjectDigestInfo getObjectDigestInfo()\n    {\n        return objectDigestInfo;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  V2Form ::= SEQUENCE {\n     *       issuerName            GeneralNames  OPTIONAL,\n     *       baseCertificateID     [0] IssuerSerial  OPTIONAL,\n     *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL\n     *         -- issuerName MUST be present in this profile\n     *         -- baseCertificateID and objectDigestInfo MUST NOT\n     *         -- be present in this profile\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        if (issuerName != null)\n        {\n            v.add(issuerName);\n        }\n\n        if (baseCertificateID != null)\n        {\n            v.add(new DERTaggedObject(false, 0, baseCertificateID));\n        }\n\n        if (objectDigestInfo != null)\n        {\n            v.add(new DERTaggedObject(false, 1, objectDigestInfo));\n        }\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERTaggedObject;\nimport local.org.bouncycastle.asn1.DERUTCTime;\nimport local.org.bouncycastle.asn1.x500.X500Name;\n\n/**\n * Generator for Version 3 TBSCertificateStructures.\n * <pre>\n * TBSCertificate ::= SEQUENCE {\n *      version          [ 0 ]  Version DEFAULT v1(0),\n *      serialNumber            CertificateSerialNumber,\n *      signature               AlgorithmIdentifier,\n *      issuer                  Name,\n *      validity                Validity,\n *      subject                 Name,\n *      subjectPublicKeyInfo    SubjectPublicKeyInfo,\n *      issuerUniqueID    [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,\n *      subjectUniqueID   [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,\n *      extensions        [ 3 ] Extensions OPTIONAL\n *      }\n * </pre>\n *\n */\npublic class V3TBSCertificateGenerator\n{\n    DERTaggedObject         version = new DERTaggedObject(true, 0, new ASN1Integer(2));\n\n    ASN1Integer              serialNumber;\n    AlgorithmIdentifier     signature;\n    X500Name                issuer;\n    Time                    startDate, endDate;\n    X500Name                subject;\n    SubjectPublicKeyInfo    subjectPublicKeyInfo;\n    Extensions              extensions;\n\n    private boolean altNamePresentAndCritical;\n    private DERBitString issuerUniqueID;\n    private DERBitString subjectUniqueID;\n\n    public V3TBSCertificateGenerator()\n    {\n    }\n\n    public void setSerialNumber(\n        ASN1Integer  serialNumber)\n    {\n        this.serialNumber = serialNumber;\n    }\n\n    public void setSignature(\n        AlgorithmIdentifier    signature)\n    {\n        this.signature = signature;\n    }\n\n        /**\n     * @deprecated use X500Name method\n     */\n    public void setIssuer(\n        X509Name    issuer)\n    {\n        this.issuer = X500Name.getInstance(issuer);\n    }\n\n    public void setIssuer(\n        X500Name issuer)\n    {\n        this.issuer = issuer;\n    }\n    \n    public void setStartDate(\n        DERUTCTime startDate)\n    {\n        this.startDate = new Time(startDate);\n    }\n\n    public void setStartDate(\n        Time startDate)\n    {\n        this.startDate = startDate;\n    }\n\n    public void setEndDate(\n        DERUTCTime endDate)\n    {\n        this.endDate = new Time(endDate);\n    }\n\n    public void setEndDate(\n        Time endDate)\n    {\n        this.endDate = endDate;\n    }\n\n        /**\n     * @deprecated use X500Name method\n     */\n    public void setSubject(\n        X509Name    subject)\n    {\n        this.subject = X500Name.getInstance(subject.toASN1Primitive());\n    }\n\n    public void setSubject(\n        X500Name subject)\n    {\n        this.subject = subject;\n    }\n\n    public void setIssuerUniqueID(\n        DERBitString uniqueID)\n    {\n        this.issuerUniqueID = uniqueID;\n    }\n\n    public void setSubjectUniqueID(\n        DERBitString uniqueID)\n    {\n        this.subjectUniqueID = uniqueID;\n    }\n\n    public void setSubjectPublicKeyInfo(\n        SubjectPublicKeyInfo    pubKeyInfo)\n    {\n        this.subjectPublicKeyInfo = pubKeyInfo;\n    }\n\n    /**\n     * @deprecated use method taking Extensions\n     * @param extensions\n     */\n    public void setExtensions(\n        X509Extensions    extensions)\n    {\n        setExtensions(Extensions.getInstance(extensions));\n    }\n\n    public void setExtensions(\n        Extensions    extensions)\n    {\n        this.extensions = extensions;\n        if (extensions != null)\n        {\n            Extension altName = extensions.getExtension(Extension.subjectAlternativeName);\n\n            if (altName != null && altName.isCritical())\n            {\n                altNamePresentAndCritical = true;\n            }\n        }\n    }\n\n    public TBSCertificate generateTBSCertificate()\n    {\n        if ((serialNumber == null) || (signature == null)\n            || (issuer == null) || (startDate == null) || (endDate == null)\n            || (subject == null && !altNamePresentAndCritical) || (subjectPublicKeyInfo == null))\n        {\n            throw new IllegalStateException(\"not all mandatory fields set in V3 TBScertificate generator\");\n        }\n\n        ASN1EncodableVector  v = new ASN1EncodableVector();\n\n        v.add(version);\n        v.add(serialNumber);\n        v.add(signature);\n        v.add(issuer);\n\n        //\n        // before and after dates\n        //\n        ASN1EncodableVector  validity = new ASN1EncodableVector();\n\n        validity.add(startDate);\n        validity.add(endDate);\n\n        v.add(new DERSequence(validity));\n\n        if (subject != null)\n        {\n            v.add(subject);\n        }\n        else\n        {\n            v.add(new DERSequence());\n        }\n\n        v.add(subjectPublicKeyInfo);\n\n        if (issuerUniqueID != null)\n        {\n            v.add(new DERTaggedObject(false, 1, issuerUniqueID));\n        }\n\n        if (subjectUniqueID != null)\n        {\n            v.add(new DERTaggedObject(false, 2, subjectUniqueID));\n        }\n\n        if (extensions != null)\n        {\n            v.add(new DERTaggedObject(true, 3, extensions));\n        }\n\n        return TBSCertificate.getInstance(new DERSequence(v));\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DERGeneralizedTime;\nimport local.org.bouncycastle.asn1.DERIA5String;\nimport local.org.bouncycastle.asn1.DERPrintableString;\nimport local.org.bouncycastle.asn1.DERUTF8String;\n\n\n/**\n * The default converter for X509 DN entries when going from their\n * string value to ASN.1 strings.\n */\npublic class X509DefaultEntryConverter\n    extends X509NameEntryConverter\n{\n    /**\n     * Apply default coversion for the given value depending on the oid\n     * and the character range of the value.\n     * \n     * @param oid the object identifier for the DN entry\n     * @param value the value associated with it\n     * @return the ASN.1 equivalent for the string value.\n     */\n    public ASN1Primitive getConvertedValue(\n        ASN1ObjectIdentifier  oid,\n        String               value)\n    {\n        if (value.length() != 0 && value.charAt(0) == '#')\n        {\n            try\n            {\n                return convertHexEncoded(value, 1);\n            }\n            catch (IOException e)\n            {\n                throw new RuntimeException(\"can't recode value for oid \" + oid.getId());\n            }\n        }\n        else\n        {\n            if (value.length() != 0 && value.charAt(0) == '\\\\')\n            {\n                value = value.substring(1);\n            }\n            if (oid.equals(X509Name.EmailAddress) || oid.equals(X509Name.DC))\n            {\n                return new DERIA5String(value);\n            }\n            else if (oid.equals(X509Name.DATE_OF_BIRTH))  // accept time string as well as # (for compatibility)\n            {\n                return new DERGeneralizedTime(value);\n            }\n            else if (oid.equals(X509Name.C) || oid.equals(X509Name.SN) || oid.equals(X509Name.DN_QUALIFIER)\n                || oid.equals(X509Name.TELEPHONE_NUMBER))\n            {\n                 return new DERPrintableString(value);\n            }\n        }\n        \n        return new DERUTF8String(value);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509Extension.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DERBoolean;\n\n\n/**\n * an object for the elements in the X.509 V3 extension block.\n */\npublic class X509Extension\n{\n    /**\n     * Subject Directory Attributes\n     */\n    public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier(\"2.5.29.9\");\n    \n    /**\n     * Subject Key Identifier \n     */\n    public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier(\"2.5.29.14\");\n\n    /**\n     * Key Usage \n     */\n    public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier(\"2.5.29.15\");\n\n    /**\n     * Private Key Usage Period \n     */\n    public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier(\"2.5.29.16\");\n\n    /**\n     * Subject Alternative Name \n     */\n    public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier(\"2.5.29.17\");\n\n    /**\n     * Issuer Alternative Name \n     */\n    public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier(\"2.5.29.18\");\n\n    /**\n     * Basic Constraints \n     */\n    public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier(\"2.5.29.19\");\n\n    /**\n     * CRL Number \n     */\n    public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier(\"2.5.29.20\");\n\n    /**\n     * Reason code \n     */\n    public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier(\"2.5.29.21\");\n\n    /**\n     * Hold Instruction Code \n     */\n    public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier(\"2.5.29.23\");\n\n    /**\n     * Invalidity Date \n     */\n    public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier(\"2.5.29.24\");\n\n    /**\n     * Delta CRL indicator \n     */\n    public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier(\"2.5.29.27\");\n\n    /**\n     * Issuing Distribution Point \n     */\n    public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier(\"2.5.29.28\");\n\n    /**\n     * Certificate Issuer \n     */\n    public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier(\"2.5.29.29\");\n\n    /**\n     * Name Constraints \n     */\n    public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier(\"2.5.29.30\");\n\n    /**\n     * CRL Distribution Points \n     */\n    public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier(\"2.5.29.31\");\n\n    /**\n     * Certificate Policies \n     */\n    public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier(\"2.5.29.32\");\n\n    /**\n     * Policy Mappings \n     */\n    public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier(\"2.5.29.33\");\n\n    /**\n     * Authority Key Identifier \n     */\n    public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier(\"2.5.29.35\");\n\n    /**\n     * Policy Constraints \n     */\n    public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier(\"2.5.29.36\");\n\n    /**\n     * Extended Key Usage \n     */\n    public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier(\"2.5.29.37\");\n\n    /**\n     * Freshest CRL\n     */\n    public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier(\"2.5.29.46\");\n     \n    /**\n     * Inhibit Any Policy\n     */\n    public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier(\"2.5.29.54\");\n\n    /**\n     * Authority Info Access\n     */\n    public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.1\");\n\n    /**\n     * Subject Info Access\n     */\n    public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.11\");\n    \n    /**\n     * Logo Type\n     */\n    public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.12\");\n\n    /**\n     * BiometricInfo\n     */\n    public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.2\");\n    \n    /**\n     * QCStatements\n     */\n    public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.3\");\n\n    /**\n     * Audit identity extension in attribute certificates.\n     */\n    public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.4\");\n    \n    /**\n     * NoRevAvail extension in attribute certificates.\n     */\n    public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier(\"2.5.29.56\");\n\n    /**\n     * TargetInformation extension in attribute certificates.\n     */\n    public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier(\"2.5.29.55\");\n        \n    boolean             critical;\n    ASN1OctetString     value;\n\n    public X509Extension(\n        DERBoolean              critical,\n        ASN1OctetString         value)\n    {\n        this.critical = critical.isTrue();\n        this.value = value;\n    }\n\n    public X509Extension(\n        boolean                 critical,\n        ASN1OctetString         value)\n    {\n        this.critical = critical;\n        this.value = value;\n    }\n\n    public boolean isCritical()\n    {\n        return critical;\n    }\n\n    public ASN1OctetString getValue()\n    {\n        return value;\n    }\n\n    public ASN1Encodable getParsedValue()\n    {\n        return convertValueToObject(this);\n    }\n\n    public int hashCode()\n    {\n        if (this.isCritical())\n        {\n            return this.getValue().hashCode();\n        }\n\n        return ~this.getValue().hashCode();\n    }\n\n    public boolean equals(\n        Object  o)\n    {\n        if (!(o instanceof X509Extension))\n        {\n            return false;\n        }\n\n        X509Extension   other = (X509Extension)o;\n\n        return other.getValue().equals(this.getValue())\n            && (other.isCritical() == this.isCritical());\n    }\n\n    /**\n     * Convert the value of the passed in extension to an object\n     * @param ext the extension to parse\n     * @return the object the value string contains\n     * @exception IllegalArgumentException if conversion is not possible\n     */\n    public static ASN1Primitive convertValueToObject(\n        X509Extension ext)\n        throws IllegalArgumentException\n    {\n        try\n        {\n            return ASN1Primitive.fromByteArray(ext.getValue().getOctets());\n        }\n        catch (IOException e)\n        {\n            throw new IllegalArgumentException(\"can't convert extension: \" +  e);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509Extensions.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERBoolean;\nimport local.org.bouncycastle.asn1.DERObjectIdentifier;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\n/**\n * @deprecated use Extensions\n */\npublic class X509Extensions\n    extends ASN1Object\n{\n    /**\n     * Subject Directory Attributes\n     * @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier SubjectDirectoryAttributes = new ASN1ObjectIdentifier(\"2.5.29.9\");\n    \n    /**\n     * Subject Key Identifier\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier SubjectKeyIdentifier = new ASN1ObjectIdentifier(\"2.5.29.14\");\n\n    /**\n     * Key Usage\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier KeyUsage = new ASN1ObjectIdentifier(\"2.5.29.15\");\n\n    /**\n     * Private Key Usage Period\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier PrivateKeyUsagePeriod = new ASN1ObjectIdentifier(\"2.5.29.16\");\n\n    /**\n     * Subject Alternative Name\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier SubjectAlternativeName = new ASN1ObjectIdentifier(\"2.5.29.17\");\n\n    /**\n     * Issuer Alternative Name\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier IssuerAlternativeName = new ASN1ObjectIdentifier(\"2.5.29.18\");\n\n    /**\n     * Basic Constraints\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier BasicConstraints = new ASN1ObjectIdentifier(\"2.5.29.19\");\n\n    /**\n     * CRL Number\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier CRLNumber = new ASN1ObjectIdentifier(\"2.5.29.20\");\n\n    /**\n     * Reason code\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier ReasonCode = new ASN1ObjectIdentifier(\"2.5.29.21\");\n\n    /**\n     * Hold Instruction Code\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier InstructionCode = new ASN1ObjectIdentifier(\"2.5.29.23\");\n\n    /**\n     * Invalidity Date\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier InvalidityDate = new ASN1ObjectIdentifier(\"2.5.29.24\");\n\n    /**\n     * Delta CRL indicator\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier DeltaCRLIndicator = new ASN1ObjectIdentifier(\"2.5.29.27\");\n\n    /**\n     * Issuing Distribution Point\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier IssuingDistributionPoint = new ASN1ObjectIdentifier(\"2.5.29.28\");\n\n    /**\n     * Certificate Issuer\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier CertificateIssuer = new ASN1ObjectIdentifier(\"2.5.29.29\");\n\n    /**\n     * Name Constraints\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier NameConstraints = new ASN1ObjectIdentifier(\"2.5.29.30\");\n\n    /**\n     * CRL Distribution Points\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier CRLDistributionPoints = new ASN1ObjectIdentifier(\"2.5.29.31\");\n\n    /**\n     * Certificate Policies\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier CertificatePolicies = new ASN1ObjectIdentifier(\"2.5.29.32\");\n\n    /**\n     * Policy Mappings\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier PolicyMappings = new ASN1ObjectIdentifier(\"2.5.29.33\");\n\n    /**\n     * Authority Key Identifier\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier AuthorityKeyIdentifier = new ASN1ObjectIdentifier(\"2.5.29.35\");\n\n    /**\n     * Policy Constraints\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier PolicyConstraints = new ASN1ObjectIdentifier(\"2.5.29.36\");\n\n    /**\n     * Extended Key Usage\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier ExtendedKeyUsage = new ASN1ObjectIdentifier(\"2.5.29.37\");\n\n    /**\n     * Freshest CRL\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier FreshestCRL = new ASN1ObjectIdentifier(\"2.5.29.46\");\n     \n    /**\n     * Inhibit Any Policy\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier InhibitAnyPolicy = new ASN1ObjectIdentifier(\"2.5.29.54\");\n\n    /**\n     * Authority Info Access\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier AuthorityInfoAccess = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.1\");\n\n    /**\n     * Subject Info Access\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier SubjectInfoAccess = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.11\");\n    \n    /**\n     * Logo Type\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier LogoType = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.12\");\n\n    /**\n     * BiometricInfo\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier BiometricInfo = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.2\");\n    \n    /**\n     * QCStatements\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier QCStatements = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.3\");\n\n    /**\n     * Audit identity extension in attribute certificates.\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier AuditIdentity = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7.1.4\");\n    \n    /**\n     * NoRevAvail extension in attribute certificates.\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier NoRevAvail = new ASN1ObjectIdentifier(\"2.5.29.56\");\n\n    /**\n     * TargetInformation extension in attribute certificates.\n     *  @deprecated use X509Extension value.\n     */\n    public static final ASN1ObjectIdentifier TargetInformation = new ASN1ObjectIdentifier(\"2.5.29.55\");\n    \n    private Hashtable               extensions = new Hashtable();\n    private Vector                  ordering = new Vector();\n\n    public static X509Extensions getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static X509Extensions getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof X509Extensions)\n        {\n            return (X509Extensions)obj;\n        }\n\n        if (obj instanceof ASN1Sequence)\n        {\n            return new X509Extensions((ASN1Sequence)obj);\n        }\n\n        if (obj instanceof Extensions)\n        {\n            return new X509Extensions((ASN1Sequence)((Extensions)obj).toASN1Primitive());\n        }\n\n        if (obj instanceof ASN1TaggedObject)\n        {\n            return getInstance(((ASN1TaggedObject)obj).getObject());\n        }\n\n        throw new IllegalArgumentException(\"illegal object in getInstance: \" + obj.getClass().getName());\n    }\n\n    /**\n     * Constructor from ASN1Sequence.\n     *\n     * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)\n     */\n    public X509Extensions(\n        ASN1Sequence  seq)\n    {\n        Enumeration e = seq.getObjects();\n\n        while (e.hasMoreElements())\n        {\n            ASN1Sequence            s = ASN1Sequence.getInstance(e.nextElement());\n\n            if (s.size() == 3)\n            {\n                extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));\n            }\n            else if (s.size() == 2)\n            {\n                extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1))));\n            }\n            else\n            {\n                throw new IllegalArgumentException(\"Bad sequence size: \" + s.size());\n            }\n\n            ordering.addElement(s.getObjectAt(0));\n        }\n    }\n\n    /**\n     * constructor from a table of extensions.\n     * <p>\n     * it's is assumed the table contains OID/String pairs.\n     */\n    public X509Extensions(\n        Hashtable  extensions)\n    {\n        this(null, extensions);\n    }\n\n    /**\n     * Constructor from a table of extensions with ordering.\n     * <p>\n     * It's is assumed the table contains OID/String pairs.\n     * @deprecated use Extensions\n     */\n    public X509Extensions(\n        Vector      ordering,\n        Hashtable   extensions)\n    {\n        Enumeration e;\n\n        if (ordering == null)\n        {\n            e = extensions.keys();\n        }\n        else\n        {\n            e = ordering.elements();\n        }\n\n        while (e.hasMoreElements())\n        {\n            this.ordering.addElement(ASN1ObjectIdentifier.getInstance(e.nextElement()));\n        }\n\n        e = this.ordering.elements();\n\n        while (e.hasMoreElements())\n        {\n            ASN1ObjectIdentifier     oid = ASN1ObjectIdentifier.getInstance(e.nextElement());\n            X509Extension           ext = (X509Extension)extensions.get(oid);\n\n            this.extensions.put(oid, ext);\n        }\n    }\n\n    /**\n     * Constructor from two vectors\n     * \n     * @param objectIDs a vector of the object identifiers.\n     * @param values a vector of the extension values.\n     * @deprecated use Extensions\n     */\n    public X509Extensions(\n        Vector      objectIDs,\n        Vector      values)\n    {\n        Enumeration e = objectIDs.elements();\n\n        while (e.hasMoreElements())\n        {\n            this.ordering.addElement(e.nextElement()); \n        }\n\n        int count = 0;\n        \n        e = this.ordering.elements();\n\n        while (e.hasMoreElements())\n        {\n            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();\n            X509Extension           ext = (X509Extension)values.elementAt(count);\n\n            this.extensions.put(oid, ext);\n            count++;\n        }\n    }\n    \n    /**\n     * return an Enumeration of the extension field's object ids.\n     */\n    public Enumeration oids()\n    {\n        return ordering.elements();\n    }\n\n    /**\n     * return the extension represented by the object identifier\n     * passed in.\n     *\n     * @return the extension if it's present, null otherwise.\n     */\n    public X509Extension getExtension(\n        DERObjectIdentifier oid)\n    {\n        return (X509Extension)extensions.get(oid);\n    }\n\n    /**\n     * @deprecated\n     * @param oid\n     * @return\n     */\n    public X509Extension getExtension(\n        ASN1ObjectIdentifier oid)\n    {\n        return (X509Extension)extensions.get(oid);\n    }\n\n    /**\n     * <pre>\n     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension\n     *\n     *     Extension         ::=   SEQUENCE {\n     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),\n     *        critical          BOOLEAN DEFAULT FALSE,\n     *        extnValue         OCTET STRING }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector     vec = new ASN1EncodableVector();\n        Enumeration             e = ordering.elements();\n\n        while (e.hasMoreElements())\n        {\n            ASN1ObjectIdentifier    oid = (ASN1ObjectIdentifier)e.nextElement();\n            X509Extension           ext = (X509Extension)extensions.get(oid);\n            ASN1EncodableVector     v = new ASN1EncodableVector();\n\n            v.add(oid);\n\n            if (ext.isCritical())\n            {\n                v.add(DERBoolean.TRUE);\n            }\n\n            v.add(ext.getValue());\n\n            vec.add(new DERSequence(v));\n        }\n\n        return new DERSequence(vec);\n    }\n\n    public boolean equivalent(\n        X509Extensions other)\n    {\n        if (extensions.size() != other.extensions.size())\n        {\n            return false;\n        }\n\n        Enumeration     e1 = extensions.keys();\n\n        while (e1.hasMoreElements())\n        {\n            Object  key = e1.nextElement();\n\n            if (!extensions.get(key).equals(other.extensions.get(key)))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public ASN1ObjectIdentifier[] getExtensionOIDs()\n    {\n        return toOidArray(ordering);\n    }\n    \n    public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()\n    {\n        return getExtensionOIDs(false);\n    }\n\n    public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()\n    {\n        return getExtensionOIDs(true);\n    }\n\n    private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)\n    {\n        Vector oidVec = new Vector();\n\n        for (int i = 0; i != ordering.size(); i++)\n        {\n            Object oid = ordering.elementAt(i);\n\n            if (((X509Extension)extensions.get(oid)).isCritical() == isCritical)\n            {\n                oidVec.addElement(oid);\n            }\n        }\n\n        return toOidArray(oidVec);\n    }\n\n    private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)\n    {\n        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];\n\n        for (int i = 0; i != oids.length; i++)\n        {\n            oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);\n        }\n        return oids;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509Name.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Encoding;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.ASN1Set;\nimport local.org.bouncycastle.asn1.ASN1String;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.DERSet;\nimport local.org.bouncycastle.asn1.DERUniversalString;\nimport local.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.util.Strings;\nimport local.org.bouncycastle.util.encoders.Hex;\n\n\n/**\n * <pre>\n *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName\n *\n *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue\n *\n *     AttributeTypeAndValue ::= SEQUENCE {\n *                                   type  OBJECT IDENTIFIER,\n *                                   value ANY }\n * </pre>\n * @deprecated use org.bouncycastle.asn1.x500.X500Name.\n */\npublic class X509Name\n    extends ASN1Object\n{\n    /**\n     * country code - StringType(SIZE(2))\n     * @deprecated use a X500NameStyle\n     */\n    public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier(\"2.5.4.6\");\n\n    /**\n     * organization - StringType(SIZE(1..64))\n     * @deprecated use a X500NameStyle\n     */\n    public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier(\"2.5.4.10\");\n\n    /**\n     * organizational unit name - StringType(SIZE(1..64))\n     * @deprecated use a X500NameStyle\n     */\n    public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier(\"2.5.4.11\");\n\n    /**\n     * Title\n     * @deprecated use a X500NameStyle\n     */\n    public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier(\"2.5.4.12\");\n\n    /**\n     * common name - StringType(SIZE(1..64))\n     * @deprecated use a X500NameStyle\n     */\n    public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier(\"2.5.4.3\");\n\n    /**\n     * device serial number name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier(\"2.5.4.5\");\n\n    /**\n     * street - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier(\"2.5.4.9\");\n    \n    /**\n     * device serial number name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier SERIALNUMBER = SN;\n\n    /**\n     * locality name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier(\"2.5.4.7\");\n\n    /**\n     * state, or province name - StringType(SIZE(1..64))\n     */\n    public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier(\"2.5.4.8\");\n\n    /**\n     * Naming attributes of type X520name\n     */\n    public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier(\"2.5.4.4\");\n    public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier(\"2.5.4.42\");\n    public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier(\"2.5.4.43\");\n    public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier(\"2.5.4.44\");\n    public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier(\"2.5.4.45\");\n\n    /**\n     * businessCategory - DirectoryString(SIZE(1..128)\n     */\n    public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(\n                    \"2.5.4.15\");\n\n    /**\n     * postalCode - DirectoryString(SIZE(1..40)\n     */\n    public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(\n                    \"2.5.4.17\");\n    \n    /**\n     * dnQualifier - DirectoryString(SIZE(1..64)\n     */\n    public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(\n                    \"2.5.4.46\");\n\n    /**\n     * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)\n     */\n    public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(\n                    \"2.5.4.65\");\n\n\n    /**\n     * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z\n     */\n    public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(\n                    \"1.3.6.1.5.5.7.9.1\");\n\n    /**\n     * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)\n     */\n    public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier(\n                    \"1.3.6.1.5.5.7.9.2\");\n\n    /**\n     * RFC 3039 Gender - PrintableString (SIZE(1)) -- \"M\", \"F\", \"m\" or \"f\"\n     */\n    public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier(\n                    \"1.3.6.1.5.5.7.9.3\");\n\n    /**\n     * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166\n     * codes only\n     */\n    public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier(\n                    \"1.3.6.1.5.5.7.9.4\");\n\n    /**\n     * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166\n     * codes only\n     */\n    public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier(\n                    \"1.3.6.1.5.5.7.9.5\");\n\n\n    /**\n     * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)\n     */\n    public static final ASN1ObjectIdentifier NAME_AT_BIRTH =  new ASN1ObjectIdentifier(\"1.3.36.8.3.14\");\n\n    /**\n     * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF\n     * DirectoryString(SIZE(1..30))\n     */\n    public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier(\"2.5.4.16\");\n\n    /**\n     * RFC 2256 dmdName\n     */\n    public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier(\"2.5.4.54\");\n\n    /**\n     * id-at-telephoneNumber\n     */\n    public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;\n\n    /**\n     * id-at-name\n     */\n    public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;\n\n    /**\n     * Email address (RSA PKCS#9 extension) - IA5String.\n     * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.\n     * @deprecated use a X500NameStyle\n     */\n    public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;\n    \n    /**\n     * more from PKCS#9\n     */\n    public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;\n    public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;\n    \n    /**\n     * email address in Verisign certificates\n     */\n    public static final ASN1ObjectIdentifier E = EmailAddress;\n    \n    /*\n     * others...\n     */\n    public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier(\"0.9.2342.19200300.100.1.25\");\n\n    /**\n     * LDAP User id.\n     */\n    public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier(\"0.9.2342.19200300.100.1.1\");\n\n    /**\n     * determines whether or not strings should be processed and printed\n     * from back to front.\n     */\n    public static boolean DefaultReverse = false;\n\n    /**\n     * default look up table translating OID values into their common symbols following\n     * the convention in RFC 2253 with a few extras\n     */\n    public static final Hashtable DefaultSymbols = new Hashtable();\n\n    /**\n     * look up table translating OID values into their common symbols following the convention in RFC 2253\n     * \n     */\n    public static final Hashtable RFC2253Symbols = new Hashtable();\n\n    /**\n     * look up table translating OID values into their common symbols following the convention in RFC 1779\n     * \n     */\n    public static final Hashtable RFC1779Symbols = new Hashtable();\n\n    /**\n     * look up table translating common symbols into their OIDS.\n     */\n    public static final Hashtable DefaultLookUp = new Hashtable();\n\n    /**\n     * look up table translating OID values into their common symbols\n     * @deprecated use DefaultSymbols\n     */\n    public static final Hashtable OIDLookUp = DefaultSymbols;\n\n    /**\n     * look up table translating string values into their OIDS -\n     * @deprecated use DefaultLookUp\n     */\n    public static final Hashtable SymbolLookUp = DefaultLookUp;\n\n    private static final Boolean TRUE = new Boolean(true); // for J2ME compatibility\n    private static final Boolean FALSE = new Boolean(false);\n\n    static\n    {\n        DefaultSymbols.put(C, \"C\");\n        DefaultSymbols.put(O, \"O\");\n        DefaultSymbols.put(T, \"T\");\n        DefaultSymbols.put(OU, \"OU\");\n        DefaultSymbols.put(CN, \"CN\");\n        DefaultSymbols.put(L, \"L\");\n        DefaultSymbols.put(ST, \"ST\");\n        DefaultSymbols.put(SN, \"SERIALNUMBER\");\n        DefaultSymbols.put(EmailAddress, \"E\");\n        DefaultSymbols.put(DC, \"DC\");\n        DefaultSymbols.put(UID, \"UID\");\n        DefaultSymbols.put(STREET, \"STREET\");\n        DefaultSymbols.put(SURNAME, \"SURNAME\");\n        DefaultSymbols.put(GIVENNAME, \"GIVENNAME\");\n        DefaultSymbols.put(INITIALS, \"INITIALS\");\n        DefaultSymbols.put(GENERATION, \"GENERATION\");\n        DefaultSymbols.put(UnstructuredAddress, \"unstructuredAddress\");\n        DefaultSymbols.put(UnstructuredName, \"unstructuredName\");\n        DefaultSymbols.put(UNIQUE_IDENTIFIER, \"UniqueIdentifier\");\n        DefaultSymbols.put(DN_QUALIFIER, \"DN\");\n        DefaultSymbols.put(PSEUDONYM, \"Pseudonym\");\n        DefaultSymbols.put(POSTAL_ADDRESS, \"PostalAddress\");\n        DefaultSymbols.put(NAME_AT_BIRTH, \"NameAtBirth\");\n        DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, \"CountryOfCitizenship\");\n        DefaultSymbols.put(COUNTRY_OF_RESIDENCE, \"CountryOfResidence\");\n        DefaultSymbols.put(GENDER, \"Gender\");\n        DefaultSymbols.put(PLACE_OF_BIRTH, \"PlaceOfBirth\");\n        DefaultSymbols.put(DATE_OF_BIRTH, \"DateOfBirth\");\n        DefaultSymbols.put(POSTAL_CODE, \"PostalCode\");\n        DefaultSymbols.put(BUSINESS_CATEGORY, \"BusinessCategory\");\n        DefaultSymbols.put(TELEPHONE_NUMBER, \"TelephoneNumber\");\n        DefaultSymbols.put(NAME, \"Name\");\n\n        RFC2253Symbols.put(C, \"C\");\n        RFC2253Symbols.put(O, \"O\");\n        RFC2253Symbols.put(OU, \"OU\");\n        RFC2253Symbols.put(CN, \"CN\");\n        RFC2253Symbols.put(L, \"L\");\n        RFC2253Symbols.put(ST, \"ST\");\n        RFC2253Symbols.put(STREET, \"STREET\");\n        RFC2253Symbols.put(DC, \"DC\");\n        RFC2253Symbols.put(UID, \"UID\");\n\n        RFC1779Symbols.put(C, \"C\");\n        RFC1779Symbols.put(O, \"O\");\n        RFC1779Symbols.put(OU, \"OU\");\n        RFC1779Symbols.put(CN, \"CN\");\n        RFC1779Symbols.put(L, \"L\");\n        RFC1779Symbols.put(ST, \"ST\");\n        RFC1779Symbols.put(STREET, \"STREET\");\n\n        DefaultLookUp.put(\"c\", C);\n        DefaultLookUp.put(\"o\", O);\n        DefaultLookUp.put(\"t\", T);\n        DefaultLookUp.put(\"ou\", OU);\n        DefaultLookUp.put(\"cn\", CN);\n        DefaultLookUp.put(\"l\", L);\n        DefaultLookUp.put(\"st\", ST);\n        DefaultLookUp.put(\"sn\", SN);\n        DefaultLookUp.put(\"serialnumber\", SN);\n        DefaultLookUp.put(\"street\", STREET);\n        DefaultLookUp.put(\"emailaddress\", E);\n        DefaultLookUp.put(\"dc\", DC);\n        DefaultLookUp.put(\"e\", E);\n        DefaultLookUp.put(\"uid\", UID);\n        DefaultLookUp.put(\"surname\", SURNAME);\n        DefaultLookUp.put(\"givenname\", GIVENNAME);\n        DefaultLookUp.put(\"initials\", INITIALS);\n        DefaultLookUp.put(\"generation\", GENERATION);\n        DefaultLookUp.put(\"unstructuredaddress\", UnstructuredAddress);\n        DefaultLookUp.put(\"unstructuredname\", UnstructuredName);\n        DefaultLookUp.put(\"uniqueidentifier\", UNIQUE_IDENTIFIER);\n        DefaultLookUp.put(\"dn\", DN_QUALIFIER);\n        DefaultLookUp.put(\"pseudonym\", PSEUDONYM);\n        DefaultLookUp.put(\"postaladdress\", POSTAL_ADDRESS);\n        DefaultLookUp.put(\"nameofbirth\", NAME_AT_BIRTH);\n        DefaultLookUp.put(\"countryofcitizenship\", COUNTRY_OF_CITIZENSHIP);\n        DefaultLookUp.put(\"countryofresidence\", COUNTRY_OF_RESIDENCE);\n        DefaultLookUp.put(\"gender\", GENDER);\n        DefaultLookUp.put(\"placeofbirth\", PLACE_OF_BIRTH);\n        DefaultLookUp.put(\"dateofbirth\", DATE_OF_BIRTH);\n        DefaultLookUp.put(\"postalcode\", POSTAL_CODE);\n        DefaultLookUp.put(\"businesscategory\", BUSINESS_CATEGORY);\n        DefaultLookUp.put(\"telephonenumber\", TELEPHONE_NUMBER);\n        DefaultLookUp.put(\"name\", NAME);\n    }\n\n    private X509NameEntryConverter  converter = null;\n    private Vector                  ordering = new Vector();\n    private Vector                  values = new Vector();\n    private Vector                  added = new Vector();\n\n    private ASN1Sequence            seq;\n\n    private boolean                 isHashCodeCalculated;\n    private int                     hashCodeValue;\n\n    /**\n     * Return a X509Name based on the passed in tagged object.\n     * \n     * @param obj tag object holding name.\n     * @param explicit true if explicitly tagged false otherwise.\n     * @return the X509Name\n     */\n    public static X509Name getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(ASN1Sequence.getInstance(obj, explicit));\n    }\n\n    public static X509Name getInstance(\n        Object  obj)\n    {\n        if (obj == null || obj instanceof X509Name)\n        {\n            return (X509Name)obj;\n        }\n        else if (obj instanceof X500Name)\n        {\n            return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).toASN1Primitive()));\n        }\n        else if (obj != null)\n        {\n            return new X509Name(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    protected X509Name()\n    {\n        // constructure use by new X500 Name class\n    }\n    /**\n     * Constructor from ASN1Sequence\n     *\n     * the principal will be a list of constructed sets, each containing an (OID, String) pair.\n     * @deprecated use X500Name.getInstance()\n     */\n    public X509Name(\n        ASN1Sequence  seq)\n    {\n        this.seq = seq;\n\n        Enumeration e = seq.getObjects();\n\n        while (e.hasMoreElements())\n        {\n            ASN1Set         set = ASN1Set.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());\n\n            for (int i = 0; i < set.size(); i++) \n            {\n                   ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i).toASN1Primitive());\n\n                   if (s.size() != 2)\n                   {\n                       throw new IllegalArgumentException(\"badly sized pair\");\n                   }\n\n                   ordering.addElement(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)));\n                   \n                   ASN1Encodable value = s.getObjectAt(1);\n                   if (value instanceof ASN1String && !(value instanceof DERUniversalString))\n                   {\n                       String v = ((ASN1String)value).getString();\n                       if (v.length() > 0 && v.charAt(0) == '#')\n                       {\n                           values.addElement(\"\\\\\" + v);\n                       }\n                       else\n                       {\n                           values.addElement(v);\n                       }\n                   }\n                   else\n                   {\n                       try\n                       {\n                           values.addElement(\"#\" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));\n                       }\n                       catch (IOException e1)\n                       {\n                           throw new IllegalArgumentException(\"cannot encode value\");\n                       }\n                   }\n                   added.addElement((i != 0) ? TRUE : FALSE);  // to allow earlier JDK compatibility\n            }\n        }\n    }\n\n    /**\n     * constructor from a table of attributes.\n     * <p>\n     * it's is assumed the table contains OID/String pairs, and the contents\n     * of the table are copied into an internal table as part of the\n     * construction process.\n     * <p>\n     * <b>Note:</b> if the name you are trying to generate should be\n     * following a specific ordering, you should use the constructor\n     * with the ordering specified below.\n     * @deprecated use an ordered constructor! The hashtable ordering is rarely correct\n     */\n    public X509Name(\n        Hashtable  attributes)\n    {\n        this(null, attributes);\n    }\n\n    /**\n     * Constructor from a table of attributes with ordering.\n     * <p>\n     * it's is assumed the table contains OID/String pairs, and the contents\n     * of the table are copied into an internal table as part of the\n     * construction process. The ordering vector should contain the OIDs\n     * in the order they are meant to be encoded or printed in toString.\n     */\n    public X509Name(\n        Vector      ordering,\n        Hashtable   attributes)\n    {\n        this(ordering, attributes, new X509DefaultEntryConverter());\n    }\n\n    /**\n     * Constructor from a table of attributes with ordering.\n     * <p>\n     * it's is assumed the table contains OID/String pairs, and the contents\n     * of the table are copied into an internal table as part of the\n     * construction process. The ordering vector should contain the OIDs\n     * in the order they are meant to be encoded or printed in toString.\n     * <p>\n     * The passed in converter will be used to convert the strings into their\n     * ASN.1 counterparts.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        Vector                   ordering,\n        Hashtable                attributes,\n        X509NameEntryConverter   converter)\n    {\n        this.converter = converter;\n\n        if (ordering != null)\n        {\n            for (int i = 0; i != ordering.size(); i++)\n            {\n                this.ordering.addElement(ordering.elementAt(i));\n                this.added.addElement(FALSE);\n            }\n        }\n        else\n        {\n            Enumeration     e = attributes.keys();\n\n            while (e.hasMoreElements())\n            {\n                this.ordering.addElement(e.nextElement());\n                this.added.addElement(FALSE);\n            }\n        }\n\n        for (int i = 0; i != this.ordering.size(); i++)\n        {\n            ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)this.ordering.elementAt(i);\n\n            if (attributes.get(oid) == null)\n            {\n                throw new IllegalArgumentException(\"No attribute for object id - \" + oid.getId() + \" - passed to distinguished name\");\n            }\n\n            this.values.addElement(attributes.get(oid)); // copy the hash table\n        }\n    }\n\n    /**\n     * Takes two vectors one of the oids and the other of the values.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        Vector  oids,\n        Vector  values)\n    {\n        this(oids, values, new X509DefaultEntryConverter());\n    }\n\n    /**\n     * Takes two vectors one of the oids and the other of the values.\n     * <p>\n     * The passed in converter will be used to convert the strings into their\n     * ASN.1 counterparts.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        Vector                  oids,\n        Vector                  values,\n        X509NameEntryConverter  converter)\n    {\n        this.converter = converter;\n\n        if (oids.size() != values.size())\n        {\n            throw new IllegalArgumentException(\"oids vector must be same length as values.\");\n        }\n\n        for (int i = 0; i < oids.size(); i++)\n        {\n            this.ordering.addElement(oids.elementAt(i));\n            this.values.addElement(values.elementAt(i));\n            this.added.addElement(FALSE);\n        }\n    }\n\n//    private Boolean isEncoded(String s)\n//    {\n//        if (s.charAt(0) == '#')\n//        {\n//            return TRUE;\n//        }\n//\n//        return FALSE;\n//    }\n\n    /**\n     * Takes an X509 dir name as a string of the format \"C=AU, ST=Victoria\", or\n     * some such, converting it into an ordered set of name attributes.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        String  dirName)\n    {\n        this(DefaultReverse, DefaultLookUp, dirName);\n    }\n\n    /**\n     * Takes an X509 dir name as a string of the format \"C=AU, ST=Victoria\", or\n     * some such, converting it into an ordered set of name attributes with each\n     * string value being converted to its associated ASN.1 type using the passed\n     * in converter.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        String                  dirName,\n        X509NameEntryConverter  converter)\n    {\n        this(DefaultReverse, DefaultLookUp, dirName, converter);\n    }\n\n    /**\n     * Takes an X509 dir name as a string of the format \"C=AU, ST=Victoria\", or\n     * some such, converting it into an ordered set of name attributes. If reverse\n     * is true, create the encoded version of the sequence starting from the\n     * last element in the string.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        boolean reverse,\n        String  dirName)\n    {\n        this(reverse, DefaultLookUp, dirName);\n    }\n\n    /**\n     * Takes an X509 dir name as a string of the format \"C=AU, ST=Victoria\", or\n     * some such, converting it into an ordered set of name attributes with each\n     * string value being converted to its associated ASN.1 type using the passed\n     * in converter. If reverse is true the ASN.1 sequence representing the DN will\n     * be built by starting at the end of the string, rather than the start.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        boolean                 reverse,\n        String                  dirName,\n        X509NameEntryConverter  converter)\n    {\n        this(reverse, DefaultLookUp, dirName, converter);\n    }\n\n    /**\n     * Takes an X509 dir name as a string of the format \"C=AU, ST=Victoria\", or\n     * some such, converting it into an ordered set of name attributes. lookUp\n     * should provide a table of lookups, indexed by lowercase only strings and\n     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids\n     * will be processed automatically.\n     * <br>\n     * If reverse is true, create the encoded version of the sequence\n     * starting from the last element in the string.\n     * @param reverse true if we should start scanning from the end (RFC 2553).\n     * @param lookUp table of names and their oids.\n     * @param dirName the X.500 string to be parsed.\n     * @deprecated use X500Name, X500NameBuilder\n     */\n    public X509Name(\n        boolean     reverse,\n        Hashtable   lookUp,\n        String      dirName)\n    {\n        this(reverse, lookUp, dirName, new X509DefaultEntryConverter());\n    }\n\n    private ASN1ObjectIdentifier decodeOID(\n        String      name,\n        Hashtable   lookUp)\n    {\n        name = name.trim();\n        if (Strings.toUpperCase(name).startsWith(\"OID.\"))\n        {\n            return new ASN1ObjectIdentifier(name.substring(4));\n        }\n        else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')\n        {\n            return new ASN1ObjectIdentifier(name);\n        }\n\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));\n        if (oid == null)\n        {\n            throw new IllegalArgumentException(\"Unknown object id - \" + name + \" - passed to distinguished name\");\n        }\n\n        return oid;\n    }\n\n    private String unescape(String elt)\n    {\n        if (elt.length() == 0 || (elt.indexOf('\\\\') < 0 && elt.indexOf('\"') < 0))\n        {\n            return elt.trim();\n        }\n\n        char[] elts = elt.toCharArray();\n        boolean escaped = false;\n        boolean quoted = false;\n        StringBuffer buf = new StringBuffer(elt.length());\n        int start = 0;\n\n        // if it's an escaped hash string and not an actual encoding in string form\n        // we need to leave it escaped.\n        if (elts[0] == '\\\\')\n        {\n            if (elts[1] == '#')\n            {\n                start = 2;\n                buf.append(\"\\\\#\");\n            }\n        }\n\n        boolean nonWhiteSpaceEncountered = false;\n        int     lastEscaped = 0;\n\n        for (int i = start; i != elts.length; i++)\n        {\n            char c = elts[i];\n\n            if (c != ' ')\n            {\n                nonWhiteSpaceEncountered = true;\n            }\n\n            if (c == '\"')\n            {\n                if (!escaped)\n                {\n                    quoted = !quoted;\n                }\n                else\n                {\n                    buf.append(c);\n                }\n                escaped = false;\n            }\n            else if (c == '\\\\' && !(escaped || quoted))\n            {\n                escaped = true;\n                lastEscaped = buf.length();\n            }\n            else\n            {\n                if (c == ' ' && !escaped && !nonWhiteSpaceEncountered)\n                {\n                    continue;\n                }\n                buf.append(c);\n                escaped = false;\n            }\n        }\n\n        if (buf.length() > 0)\n        {\n            while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1))\n            {\n                buf.setLength(buf.length() - 1);\n            }\n        }\n\n        return buf.toString();\n    }\n\n    /**\n     * Takes an X509 dir name as a string of the format \"C=AU, ST=Victoria\", or\n     * some such, converting it into an ordered set of name attributes. lookUp\n     * should provide a table of lookups, indexed by lowercase only strings and\n     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids\n     * will be processed automatically. The passed in converter is used to convert the\n     * string values to the right of each equals sign to their ASN.1 counterparts.\n     * <br>\n     * @param reverse true if we should start scanning from the end, false otherwise.\n     * @param lookUp table of names and oids.\n     * @param dirName the string dirName\n     * @param converter the converter to convert string values into their ASN.1 equivalents\n     */\n    public X509Name(\n        boolean                 reverse,\n        Hashtable               lookUp,\n        String                  dirName,\n        X509NameEntryConverter  converter)\n    {\n        this.converter = converter;\n        X509NameTokenizer   nTok = new X509NameTokenizer(dirName);\n\n        while (nTok.hasMoreTokens())\n        {\n            String  token = nTok.nextToken();\n\n            if (token.indexOf('+') > 0)\n            {\n                X509NameTokenizer   pTok = new X509NameTokenizer(token, '+');\n\n                addEntry(lookUp, pTok.nextToken(), FALSE);\n\n                while (pTok.hasMoreTokens())\n                {\n                    addEntry(lookUp, pTok.nextToken(), TRUE);\n                }\n            }\n            else\n            {\n                addEntry(lookUp, token, FALSE);\n            }\n        }\n\n        if (reverse)\n        {\n            Vector  o = new Vector();\n            Vector  v = new Vector();\n            Vector  a = new Vector();\n\n            int count = 1;\n\n            for (int i = 0; i < this.ordering.size(); i++)\n            {\n                if (((Boolean)this.added.elementAt(i)).booleanValue())\n                {\n                    o.insertElementAt(this.ordering.elementAt(i), count);\n                    v.insertElementAt(this.values.elementAt(i), count);\n                    a.insertElementAt(this.added.elementAt(i), count);\n                    count++;\n                }\n                else\n                {\n                    o.insertElementAt(this.ordering.elementAt(i), 0);\n                    v.insertElementAt(this.values.elementAt(i), 0);\n                    a.insertElementAt(this.added.elementAt(i), 0);\n                    count = 1;\n                }\n            }\n\n            this.ordering = o;\n            this.values = v;\n            this.added = a;\n        }\n    }\n\n    private void addEntry(Hashtable lookUp, String token, Boolean isAdded)\n    {\n        X509NameTokenizer vTok;\n        String name;\n        String value;ASN1ObjectIdentifier oid;\n        vTok = new X509NameTokenizer(token, '=');\n\n        name = vTok.nextToken();\n\n        if (!vTok.hasMoreTokens())\n        {\n           throw new IllegalArgumentException(\"badly formatted directory string\");\n        }\n\n        value = vTok.nextToken();\n\n        oid = decodeOID(name, lookUp);\n\n        this.ordering.addElement(oid);\n        this.values.addElement(unescape(value));\n        this.added.addElement(isAdded);\n    }\n\n    /**\n     * return a vector of the oids in the name, in the order they were found.\n     */\n    public Vector getOIDs()\n    {\n        Vector  v = new Vector();\n\n        for (int i = 0; i != ordering.size(); i++)\n        {\n            v.addElement(ordering.elementAt(i));\n        }\n\n        return v;\n    }\n\n    /**\n     * return a vector of the values found in the name, in the order they\n     * were found.\n     */\n    public Vector getValues()\n    {\n        Vector  v = new Vector();\n\n        for (int i = 0; i != values.size(); i++)\n        {\n            v.addElement(values.elementAt(i));\n        }\n\n        return v;\n    }\n\n    /**\n     * return a vector of the values found in the name, in the order they\n     * were found, with the DN label corresponding to passed in oid.\n     */\n    public Vector getValues(\n        ASN1ObjectIdentifier oid)\n    {\n        Vector  v = new Vector();\n\n        for (int i = 0; i != values.size(); i++)\n        {\n            if (ordering.elementAt(i).equals(oid))\n            {\n                String val = (String)values.elementAt(i);\n\n                if (val.length() > 2 && val.charAt(0) == '\\\\' && val.charAt(1) == '#')\n                {\n                    v.addElement(val.substring(1));\n                }\n                else\n                {\n                    v.addElement(val);\n                }\n            }\n        }\n\n        return v;\n    }\n\n    public ASN1Primitive toASN1Primitive()\n    {\n        if (seq == null)\n        {\n            ASN1EncodableVector  vec = new ASN1EncodableVector();\n            ASN1EncodableVector  sVec = new ASN1EncodableVector();\n            ASN1ObjectIdentifier  lstOid = null;\n            \n            for (int i = 0; i != ordering.size(); i++)\n            {\n                ASN1EncodableVector     v = new ASN1EncodableVector();\n                ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)ordering.elementAt(i);\n\n                v.add(oid);\n\n                String  str = (String)values.elementAt(i);\n\n                v.add(converter.getConvertedValue(oid, str));\n \n                if (lstOid == null \n                    || ((Boolean)this.added.elementAt(i)).booleanValue())\n                {\n                    sVec.add(new DERSequence(v));\n                }\n                else\n                {\n                    vec.add(new DERSet(sVec));\n                    sVec = new ASN1EncodableVector();\n                    \n                    sVec.add(new DERSequence(v));\n                }\n                \n                lstOid = oid;\n            }\n            \n            vec.add(new DERSet(sVec));\n            \n            seq = new DERSequence(vec);\n        }\n\n        return seq;\n    }\n\n    /**\n     * @param inOrder if true the order of both X509 names must be the same,\n     * as well as the values associated with each element.\n     */\n    public boolean equals(Object obj, boolean inOrder)\n    {\n        if (!inOrder)\n        {\n            return this.equals(obj);\n        }\n\n        if (obj == this)\n        {\n            return true;\n        }\n\n        if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))\n        {\n            return false;\n        }\n\n        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();\n\n        if (this.toASN1Primitive().equals(derO))\n        {\n            return true;\n        }\n\n        X509Name other;\n\n        try\n        {\n            other = X509Name.getInstance(obj);\n        }\n        catch (IllegalArgumentException e)\n        {\n            return false;\n        }\n\n        int      orderingSize = ordering.size();\n\n        if (orderingSize != other.ordering.size())\n        {\n            return false;\n        }\n\n        for (int i = 0; i < orderingSize; i++)\n        {\n            ASN1ObjectIdentifier  oid = (ASN1ObjectIdentifier)ordering.elementAt(i);\n            ASN1ObjectIdentifier  oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(i);\n\n            if (oid.equals(oOid))\n            {\n                String value = (String)values.elementAt(i);\n                String oValue = (String)other.values.elementAt(i);\n\n                if (!equivalentStrings(value, oValue))\n                {\n                    return false;\n                }\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public int hashCode()\n    {\n        if (isHashCodeCalculated)\n        {\n            return hashCodeValue;\n        }\n\n        isHashCodeCalculated = true;\n\n        // this needs to be order independent, like equals\n        for (int i = 0; i != ordering.size(); i += 1)\n        {\n            String value = (String)values.elementAt(i);\n\n            value = canonicalize(value);\n            value = stripInternalSpaces(value);\n\n            hashCodeValue ^= ordering.elementAt(i).hashCode();\n            hashCodeValue ^= value.hashCode();\n        }\n\n        return hashCodeValue;\n    }\n\n    /**\n     * test for equality - note: case is ignored.\n     */\n    public boolean equals(Object obj)\n    {\n        if (obj == this)\n        {\n            return true;\n        }\n\n        if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))\n        {\n            return false;\n        }\n        \n        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();\n        \n        if (this.toASN1Primitive().equals(derO))\n        {\n            return true;\n        }\n\n        X509Name other;\n\n        try\n        {\n            other = X509Name.getInstance(obj);\n        }\n        catch (IllegalArgumentException e)\n        { \n            return false;\n        }\n\n        int      orderingSize = ordering.size();\n\n        if (orderingSize != other.ordering.size())\n        {\n            return false;\n        }\n        \n        boolean[] indexes = new boolean[orderingSize];\n        int       start, end, delta;\n\n        if (ordering.elementAt(0).equals(other.ordering.elementAt(0)))   // guess forward\n        {\n            start = 0;\n            end = orderingSize;\n            delta = 1;\n        }\n        else  // guess reversed - most common problem\n        {\n            start = orderingSize - 1;\n            end = -1;\n            delta = -1;\n        }\n\n        for (int i = start; i != end; i += delta)\n        {\n            boolean              found = false;\n            ASN1ObjectIdentifier  oid = (ASN1ObjectIdentifier)ordering.elementAt(i);\n            String               value = (String)values.elementAt(i);\n\n            for (int j = 0; j < orderingSize; j++)\n            {\n                if (indexes[j])\n                {\n                    continue;\n                }\n\n                ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(j);\n\n                if (oid.equals(oOid))\n                {\n                    String oValue = (String)other.values.elementAt(j);\n\n                    if (equivalentStrings(value, oValue))\n                    {\n                        indexes[j] = true;\n                        found      = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!found)\n            {\n                return false;\n            }\n        }\n        \n        return true;\n    }\n\n    private boolean equivalentStrings(String s1, String s2)\n    {\n        String value = canonicalize(s1);\n        String oValue = canonicalize(s2);\n        \n        if (!value.equals(oValue))\n        {\n            value = stripInternalSpaces(value);\n            oValue = stripInternalSpaces(oValue);\n\n            if (!value.equals(oValue))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private String canonicalize(String s)\n    {\n        String value = Strings.toLowerCase(s.trim());\n        \n        if (value.length() > 0 && value.charAt(0) == '#')\n        {\n            ASN1Primitive obj = decodeObject(value);\n\n            if (obj instanceof ASN1String)\n            {\n                value = Strings.toLowerCase(((ASN1String)obj).getString().trim());\n            }\n        }\n\n        return value;\n    }\n\n    private ASN1Primitive decodeObject(String oValue)\n    {\n        try\n        {\n            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"unknown encoding in name: \" + e);\n        }\n    }\n\n    private String stripInternalSpaces(\n        String str)\n    {\n        StringBuffer res = new StringBuffer();\n\n        if (str.length() != 0)\n        {\n            char    c1 = str.charAt(0);\n\n            res.append(c1);\n\n            for (int k = 1; k < str.length(); k++)\n            {\n                char    c2 = str.charAt(k);\n                if (!(c1 == ' ' && c2 == ' '))\n                {\n                    res.append(c2);\n                }\n                c1 = c2;\n            }\n        }\n\n        return res.toString();\n    }\n\n    private void appendValue(\n        StringBuffer        buf,\n        Hashtable           oidSymbols,\n        ASN1ObjectIdentifier oid,\n        String              value)\n    {\n        String  sym = (String)oidSymbols.get(oid);\n\n        if (sym != null)\n        {\n            buf.append(sym);\n        }\n        else\n        {\n            buf.append(oid.getId());\n        }\n\n        buf.append('=');\n\n        int     index = buf.length();\n        int     start = index;\n\n        buf.append(value);\n\n        int     end = buf.length();\n\n        if (value.length() >= 2 && value.charAt(0) == '\\\\' && value.charAt(1) == '#')\n        {\n            index += 2;   \n        }\n\n        while (index != end)\n        {\n            if ((buf.charAt(index) == ',')\n               || (buf.charAt(index) == '\"')\n               || (buf.charAt(index) == '\\\\')\n               || (buf.charAt(index) == '+')\n               || (buf.charAt(index) == '=')\n               || (buf.charAt(index) == '<')\n               || (buf.charAt(index) == '>')\n               || (buf.charAt(index) == ';'))\n            {\n                buf.insert(index, \"\\\\\");\n                index++;\n                end++;\n            }\n\n            index++;\n        }\n\n        while (buf.charAt(start) == ' ')\n        {\n            buf.insert(start, \"\\\\\");\n            start += 2;\n        }\n\n        int endBuf = buf.length() - 1;\n\n        while (endBuf >= 0 && buf.charAt(endBuf) == ' ')\n        {\n            buf.insert(endBuf, '\\\\');\n            endBuf--;\n        }\n    }\n\n    /**\n     * convert the structure to a string - if reverse is true the\n     * oids and values are listed out starting with the last element\n     * in the sequence (ala RFC 2253), otherwise the string will begin\n     * with the first element of the structure. If no string definition\n     * for the oid is found in oidSymbols the string value of the oid is\n     * added. Two standard symbol tables are provided DefaultSymbols, and\n     * RFC2253Symbols as part of this class.\n     *\n     * @param reverse if true start at the end of the sequence and work back.\n     * @param oidSymbols look up table strings for oids.\n     */\n    public String toString(\n        boolean     reverse,\n        Hashtable   oidSymbols)\n    {\n        StringBuffer            buf = new StringBuffer();\n        Vector                  components = new Vector();\n        boolean                 first = true;\n\n        StringBuffer ava = null;\n\n        for (int i = 0; i < ordering.size(); i++)\n        {\n            if (((Boolean)added.elementAt(i)).booleanValue())\n            {\n                ava.append('+');\n                appendValue(ava, oidSymbols,\n                    (ASN1ObjectIdentifier)ordering.elementAt(i),\n                    (String)values.elementAt(i));\n            }\n            else\n            {\n                ava = new StringBuffer();\n                appendValue(ava, oidSymbols,\n                    (ASN1ObjectIdentifier)ordering.elementAt(i),\n                    (String)values.elementAt(i));\n                components.addElement(ava);\n            }\n        }\n\n        if (reverse)\n        {\n            for (int i = components.size() - 1; i >= 0; i--)\n            {\n                if (first)\n                {\n                    first = false;\n                }\n                else\n                {\n                    buf.append(',');\n                }\n\n                buf.append(components.elementAt(i).toString());\n            }\n        }\n        else\n        {\n            for (int i = 0; i < components.size(); i++)\n            {\n                if (first)\n                {\n                    first = false;\n                }\n                else\n                {\n                    buf.append(',');\n                }\n\n                buf.append(components.elementAt(i).toString());\n            }\n        }\n\n        return buf.toString();\n    }\n\n    private String bytesToString(\n        byte[] data)\n    {\n        char[]  cs = new char[data.length];\n\n        for (int i = 0; i != cs.length; i++)\n        {\n            cs[i] = (char)(data[i] & 0xff);\n        }\n\n        return new String(cs);\n    }\n    \n    public String toString()\n    {\n        return toString(DefaultReverse, DefaultSymbols);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509NameEntryConverter.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport java.io.IOException;\n\nimport local.org.bouncycastle.asn1.ASN1InputStream;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DERPrintableString;\nimport local.org.bouncycastle.util.Strings;\n\n\n/**\n * It turns out that the number of standard ways the fields in a DN should be \n * encoded into their ASN.1 counterparts is rapidly approaching the\n * number of machines on the internet. By default the X509Name class \n * will produce UTF8Strings in line with the current recommendations (RFC 3280).\n * <p>\n * An example of an encoder look like below:\n * <pre>\n * public class X509DirEntryConverter\n *     extends X509NameEntryConverter\n * {\n *     public ASN1Primitive getConvertedValue(\n *         ASN1ObjectIdentifier  oid,\n *         String               value)\n *     {\n *         if (str.length() != 0 && str.charAt(0) == '#')\n *         {\n *             return convertHexEncoded(str, 1);\n *         }\n *         if (oid.equals(EmailAddress))\n *         {\n *             return new DERIA5String(str);\n *         }\n *         else if (canBePrintable(str))\n *         {\n *             return new DERPrintableString(str);\n *         }\n *         else if (canBeUTF8(str))\n *         {\n *             return new DERUTF8String(str);\n *         }\n *         else\n *         {\n *             return new DERBMPString(str);\n *         }\n *     }\n * }\n */\npublic abstract class X509NameEntryConverter\n{\n    /**\n     * Convert an inline encoded hex string rendition of an ASN.1\n     * object back into its corresponding ASN.1 object.\n     * \n     * @param str the hex encoded object\n     * @param off the index at which the encoding starts\n     * @return the decoded object\n     */\n    protected ASN1Primitive convertHexEncoded(\n        String  str,\n        int     off)\n        throws IOException\n    {\n        str = Strings.toLowerCase(str);\n        byte[] data = new byte[(str.length() - off) / 2];\n        for (int index = 0; index != data.length; index++)\n        {\n            char left = str.charAt((index * 2) + off);\n            char right = str.charAt((index * 2) + off + 1);\n            \n            if (left < 'a')\n            {\n                data[index] = (byte)((left - '0') << 4);\n            }\n            else\n            {\n                data[index] = (byte)((left - 'a' + 10) << 4);\n            }\n            if (right < 'a')\n            {\n                data[index] |= (byte)(right - '0');\n            }\n            else\n            {\n                data[index] |= (byte)(right - 'a' + 10);\n            }\n        }\n\n        ASN1InputStream aIn = new ASN1InputStream(data);\n                                            \n        return aIn.readObject();\n    }\n    \n    /**\n     * return true if the passed in String can be represented without\n     * loss as a PrintableString, false otherwise.\n     */\n    protected boolean canBePrintable(\n        String  str)\n    {\n        return DERPrintableString.isPrintableString(str);\n    }\n    \n    /**\n     * Convert the passed in String value into the appropriate ASN.1\n     * encoded object.\n     * \n     * @param oid the oid associated with the value in the DN.\n     * @param value the value of the particular DN component.\n     * @return the ASN.1 equivalent for the value.\n     */\n    public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value);\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509NameTokenizer.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\n/**\n * class for breaking up an X500 Name into it's component tokens, ala\n * java.util.StringTokenizer. We need this class as some of the\n * lightweight Java environment don't support classes like\n * StringTokenizer.\n * @deprecated use X500NameTokenizer\n */\npublic class X509NameTokenizer\n{\n    private String          value;\n    private int             index;\n    private char separator;\n    private StringBuffer    buf = new StringBuffer();\n\n    public X509NameTokenizer(\n        String  oid)\n    {\n        this(oid, ',');\n    }\n    \n    public X509NameTokenizer(\n        String  oid,\n        char separator)\n    {\n        this.value = oid;\n        this.index = -1;\n        this.separator = separator;\n    }\n\n    public boolean hasMoreTokens()\n    {\n        return (index != value.length());\n    }\n\n    public String nextToken()\n    {\n        if (index == value.length())\n        {\n            return null;\n        }\n\n        int     end = index + 1;\n        boolean quoted = false;\n        boolean escaped = false;\n\n        buf.setLength(0);\n\n        while (end != value.length())\n        {\n            char    c = value.charAt(end);\n\n            if (c == '\"')\n            {\n                if (!escaped)\n                {\n                    quoted = !quoted;\n                }\n                buf.append(c);\n                escaped = false;\n            }\n            else\n            {\n                if (escaped || quoted)\n                {\n                    buf.append(c);\n                    escaped = false;\n                }\n                else if (c == '\\\\')\n                {\n                    buf.append(c);\n                    escaped = true;\n                }\n                else if (c == separator)\n                {\n                    break;\n                }\n                else\n                {\n                    buf.append(c);\n                }\n            }\n            end++;\n        }\n\n        index = end;\n\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.x509;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface X509ObjectIdentifiers\n{\n    //\n    // base id\n    //\n    static final String                 id                      = \"2.5.4\";\n\n    static final ASN1ObjectIdentifier    commonName              = new ASN1ObjectIdentifier(id + \".3\");\n    static final ASN1ObjectIdentifier    countryName             = new ASN1ObjectIdentifier(id + \".6\");\n    static final ASN1ObjectIdentifier    localityName            = new ASN1ObjectIdentifier(id + \".7\");\n    static final ASN1ObjectIdentifier    stateOrProvinceName     = new ASN1ObjectIdentifier(id + \".8\");\n    static final ASN1ObjectIdentifier    organization            = new ASN1ObjectIdentifier(id + \".10\");\n    static final ASN1ObjectIdentifier    organizationalUnitName  = new ASN1ObjectIdentifier(id + \".11\");\n\n    static final ASN1ObjectIdentifier    id_at_telephoneNumber   = new ASN1ObjectIdentifier(\"2.5.4.20\");\n    static final ASN1ObjectIdentifier    id_at_name              = new ASN1ObjectIdentifier(id + \".41\");\n\n    // id-SHA1 OBJECT IDENTIFIER ::=    \n    //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //\n    static final ASN1ObjectIdentifier    id_SHA1                 = new ASN1ObjectIdentifier(\"1.3.14.3.2.26\");\n\n    //\n    // ripemd160 OBJECT IDENTIFIER ::=\n    //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}\n    //\n    static final ASN1ObjectIdentifier    ripemd160               = new ASN1ObjectIdentifier(\"1.3.36.3.2.1\");\n\n    //\n    // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=\n    //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }\n    //\n    static final ASN1ObjectIdentifier    ripemd160WithRSAEncryption = new ASN1ObjectIdentifier(\"1.3.36.3.3.1.2\");\n\n\n    static final ASN1ObjectIdentifier    id_ea_rsa = new ASN1ObjectIdentifier(\"2.5.8.1.1\");\n    \n    // id-pkix\n    static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier(\"1.3.6.1.5.5.7\");\n\n    //\n    // private internet extensions\n    //\n    static final ASN1ObjectIdentifier  id_pe = new ASN1ObjectIdentifier(id_pkix + \".1\");\n\n    //\n    // ISO ARC for standard certificate and CRL extensions\n    //\n    static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier(\"2.5.29\");\n\n    //\n    // authority information access\n    //\n    static final ASN1ObjectIdentifier  id_ad = new ASN1ObjectIdentifier(id_pkix + \".48\");\n    static final ASN1ObjectIdentifier  id_ad_caIssuers = new ASN1ObjectIdentifier(id_ad + \".2\");\n    static final ASN1ObjectIdentifier  id_ad_ocsp = new ASN1ObjectIdentifier(id_ad + \".1\");\n\n    //\n    //    OID for ocsp and crl uri in AuthorityInformationAccess extension\n    //\n    static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp;\n    static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers;\n}\n\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X962NamedCurves.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport java.math.BigInteger;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.util.Strings;\nimport local.org.bouncycastle.util.encoders.Hex;\n\n\n\n/**\n * table of the current named curves defined in X.962 EC-DSA.\n */\npublic class X962NamedCurves\n{\n    static X9ECParametersHolder prime192v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp192v1 = new ECCurve.Fp(\n                new BigInteger(\"6277101735386680763835789423207666416083908700390324961279\"),\n                new BigInteger(\"fffffffffffffffffffffffffffffffefffffffffffffffc\", 16),\n                new BigInteger(\"64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1\", 16));\n\n            return new X9ECParameters(\n                cFp192v1,\n                cFp192v1.decodePoint(\n                    Hex.decode(\"03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012\")),\n                new BigInteger(\"ffffffffffffffffffffffff99def836146bc9b1b4d22831\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"3045AE6FC8422f64ED579528D38120EAE12196D5\"));\n        }\n    };\n\n    static X9ECParametersHolder prime192v2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp192v2 = new ECCurve.Fp(\n                new BigInteger(\"6277101735386680763835789423207666416083908700390324961279\"),\n                new BigInteger(\"fffffffffffffffffffffffffffffffefffffffffffffffc\", 16),\n                new BigInteger(\"cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953\", 16));\n\n            return new X9ECParameters(\n                cFp192v2,\n                cFp192v2.decodePoint(\n                    Hex.decode(\"03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a\")),\n                new BigInteger(\"fffffffffffffffffffffffe5fb1a724dc80418648d8dd31\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"31a92ee2029fd10d901b113e990710f0d21ac6b6\"));\n        }\n    };\n\n    static X9ECParametersHolder prime192v3 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp192v3 = new ECCurve.Fp(\n                new BigInteger(\"6277101735386680763835789423207666416083908700390324961279\"),\n                new BigInteger(\"fffffffffffffffffffffffffffffffefffffffffffffffc\", 16),\n                new BigInteger(\"22123dc2395a05caa7423daeccc94760a7d462256bd56916\", 16));\n\n            return new X9ECParameters(\n                cFp192v3,\n                cFp192v3.decodePoint(\n                    Hex.decode(\"027d29778100c65a1da1783716588dce2b8b4aee8e228f1896\")),\n                new BigInteger(\"ffffffffffffffffffffffff7a62d031c83f4294f640ec13\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"c469684435deb378c4b65ca9591e2a5763059a2e\"));\n        }\n    };\n\n    static X9ECParametersHolder prime239v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp239v1 = new ECCurve.Fp(\n                new BigInteger(\"883423532389192164791648750360308885314476597252960362792450860609699839\"),\n                new BigInteger(\"7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc\", 16),\n                new BigInteger(\"6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a\", 16));\n\n            return new X9ECParameters(\n                cFp239v1,\n                cFp239v1.decodePoint(\n                    Hex.decode(\"020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf\")),\n                new BigInteger(\"7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"e43bb460f0b80cc0c0b075798e948060f8321b7d\"));\n        }\n    };\n\n    static X9ECParametersHolder prime239v2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp239v2 = new ECCurve.Fp(\n                new BigInteger(\"883423532389192164791648750360308885314476597252960362792450860609699839\"),\n                new BigInteger(\"7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc\", 16),\n                new BigInteger(\"617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c\", 16));\n\n            return new X9ECParameters(\n                cFp239v2,\n                cFp239v2.decodePoint(\n                    Hex.decode(\"0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7\")),\n                new BigInteger(\"7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"e8b4011604095303ca3b8099982be09fcb9ae616\"));\n        }\n    };\n\n    static X9ECParametersHolder prime239v3 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp239v3 = new ECCurve.Fp(\n                new BigInteger(\"883423532389192164791648750360308885314476597252960362792450860609699839\"),\n                new BigInteger(\"7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc\", 16),\n                new BigInteger(\"255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e\", 16));\n\n            return new X9ECParameters(\n                cFp239v3,\n                cFp239v3.decodePoint(\n                    Hex.decode(\"036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a\")),\n                new BigInteger(\"7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"7d7374168ffe3471b60a857686a19475d3bfa2ff\"));\n        }\n    };\n\n    static X9ECParametersHolder prime256v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            ECCurve cFp256v1 = new ECCurve.Fp(\n                new BigInteger(\"115792089210356248762697446949407573530086143415290314195533631308867097853951\"),\n                new BigInteger(\"ffffffff00000001000000000000000000000000fffffffffffffffffffffffc\", 16),\n                new BigInteger(\"5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b\", 16));\n\n            return new X9ECParameters(\n                cFp256v1,\n                cFp256v1.decodePoint(\n                    Hex.decode(\"036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\")),\n                new BigInteger(\"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551\", 16),\n                BigInteger.valueOf(1),\n                Hex.decode(\"c49d360886e704936a6678e1139d26b7819f7e90\"));\n        }\n    };\n\n    /*\n     * F2m Curves\n     */\n    static X9ECParametersHolder c2pnb163v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m163v1n = new BigInteger(\"0400000000000000000001E60FC8821CC74DAEAFC1\", 16);\n            BigInteger c2m163v1h = BigInteger.valueOf(2);\n\n            ECCurve c2m163v1 = new ECCurve.F2m(\n                163,\n                1, 2, 8,\n                new BigInteger(\"072546B5435234A422E0789675F432C89435DE5242\", 16),\n                new BigInteger(\"00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9\", 16),\n                c2m163v1n, c2m163v1h);\n\n            return new X9ECParameters(\n                c2m163v1,\n                c2m163v1.decodePoint(\n                    Hex.decode(\"0307AF69989546103D79329FCC3D74880F33BBE803CB\")),\n                c2m163v1n, c2m163v1h,\n                Hex.decode(\"D2C0FB15760860DEF1EEF4D696E6768756151754\"));\n        }\n    };\n\n    static X9ECParametersHolder c2pnb163v2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m163v2n = new BigInteger(\"03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7\", 16);\n            BigInteger c2m163v2h = BigInteger.valueOf(2);\n\n            ECCurve c2m163v2 = new ECCurve.F2m(\n                163,\n                1, 2, 8,\n                new BigInteger(\"0108B39E77C4B108BED981ED0E890E117C511CF072\", 16),\n                new BigInteger(\"0667ACEB38AF4E488C407433FFAE4F1C811638DF20\", 16),\n                c2m163v2n, c2m163v2h);\n\n            return new X9ECParameters(\n                c2m163v2,\n                c2m163v2.decodePoint(\n                    Hex.decode(\"030024266E4EB5106D0A964D92C4860E2671DB9B6CC5\")),\n                c2m163v2n, c2m163v2h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2pnb163v3 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m163v3n = new BigInteger(\"03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309\", 16);\n            BigInteger c2m163v3h = BigInteger.valueOf(2);\n\n            ECCurve c2m163v3 = new ECCurve.F2m(\n                163,\n                1, 2, 8,\n                new BigInteger(\"07A526C63D3E25A256A007699F5447E32AE456B50E\", 16),\n                new BigInteger(\"03F7061798EB99E238FD6F1BF95B48FEEB4854252B\", 16),\n                c2m163v3n, c2m163v3h);\n\n            return new X9ECParameters(\n                c2m163v3,\n                c2m163v3.decodePoint(\n                    Hex.decode(\"0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB\")),\n                c2m163v3n, c2m163v3h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2pnb176w1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m176w1n = new BigInteger(\"010092537397ECA4F6145799D62B0A19CE06FE26AD\", 16);\n            BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E);\n\n            ECCurve c2m176w1 = new ECCurve.F2m(\n                176,\n                1, 2, 43,\n                new BigInteger(\"00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B\", 16),\n                new BigInteger(\"005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2\", 16),\n                c2m176w1n, c2m176w1h);\n\n            return new X9ECParameters(\n                c2m176w1,\n                c2m176w1.decodePoint(\n                    Hex.decode(\"038D16C2866798B600F9F08BB4A8E860F3298CE04A5798\")),\n                c2m176w1n, c2m176w1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb191v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m191v1n = new BigInteger(\"40000000000000000000000004A20E90C39067C893BBB9A5\", 16);\n            BigInteger c2m191v1h = BigInteger.valueOf(2);\n\n            ECCurve c2m191v1 = new ECCurve.F2m(\n                191,\n                9,\n                new BigInteger(\"2866537B676752636A68F56554E12640276B649EF7526267\", 16),\n                new BigInteger(\"2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC\", 16),\n                c2m191v1n, c2m191v1h);\n\n            return new X9ECParameters(\n                c2m191v1,\n                c2m191v1.decodePoint(\n                    Hex.decode(\"0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D\")),\n                c2m191v1n, c2m191v1h,\n                Hex.decode(\"4E13CA542744D696E67687561517552F279A8C84\"));\n        }\n    };\n\n    static X9ECParametersHolder c2tnb191v2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m191v2n = new BigInteger(\"20000000000000000000000050508CB89F652824E06B8173\", 16);\n            BigInteger c2m191v2h = BigInteger.valueOf(4);\n\n            ECCurve c2m191v2 = new ECCurve.F2m(\n                191,\n                9,\n                new BigInteger(\"401028774D7777C7B7666D1366EA432071274F89FF01E718\", 16),\n                new BigInteger(\"0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01\", 16),\n                c2m191v2n, c2m191v2h);\n\n            return new X9ECParameters(\n                c2m191v2,\n                c2m191v2.decodePoint(\n                    Hex.decode(\"023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10\")),\n                c2m191v2n, c2m191v2h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb191v3 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m191v3n = new BigInteger(\"155555555555555555555555610C0B196812BFB6288A3EA3\", 16);\n            BigInteger c2m191v3h = BigInteger.valueOf(6);\n\n            ECCurve c2m191v3 = new ECCurve.F2m(\n                191,\n                9,\n                new BigInteger(\"6C01074756099122221056911C77D77E77A777E7E7E77FCB\", 16),\n                new BigInteger(\"71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8\", 16),\n                c2m191v3n, c2m191v3h);\n\n            return new X9ECParameters(\n                c2m191v3,\n                c2m191v3.decodePoint(\n                    Hex.decode(\"03375D4CE24FDE434489DE8746E71786015009E66E38A926DD\")),\n                c2m191v3n, c2m191v3h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2pnb208w1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m208w1n = new BigInteger(\"0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D\", 16);\n            BigInteger c2m208w1h = BigInteger.valueOf(0xFE48);\n\n            ECCurve c2m208w1 = new ECCurve.F2m(\n                208,\n                1, 2, 83,\n                new BigInteger(\"0\", 16),\n                new BigInteger(\"00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E\", 16),\n                c2m208w1n, c2m208w1h);\n\n            return new X9ECParameters(\n                c2m208w1,\n                c2m208w1.decodePoint(\n                    Hex.decode(\"0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A\")),\n                c2m208w1n, c2m208w1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb239v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m239v1n = new BigInteger(\"2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447\", 16);\n            BigInteger c2m239v1h = BigInteger.valueOf(4);\n\n            ECCurve c2m239v1 = new ECCurve.F2m(\n                239,\n                36,\n                new BigInteger(\"32010857077C5431123A46B808906756F543423E8D27877578125778AC76\", 16),\n                new BigInteger(\"790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16\", 16),\n                c2m239v1n, c2m239v1h);\n\n            return new X9ECParameters(\n                c2m239v1,\n                c2m239v1.decodePoint(\n                    Hex.decode(\"0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D\")),\n                c2m239v1n, c2m239v1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb239v2 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m239v2n = new BigInteger(\"1555555555555555555555555555553C6F2885259C31E3FCDF154624522D\", 16);\n            BigInteger c2m239v2h = BigInteger.valueOf(6);\n\n            ECCurve c2m239v2 = new ECCurve.F2m(\n                239,\n                36,\n                new BigInteger(\"4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F\", 16),\n                new BigInteger(\"5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B\", 16),\n                c2m239v2n, c2m239v2h);\n\n            return new X9ECParameters(\n                c2m239v2,\n                c2m239v2.decodePoint(\n                    Hex.decode(\"0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205\")),\n                c2m239v2n, c2m239v2h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb239v3 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m239v3n = new BigInteger(\"0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF\", 16);\n            BigInteger c2m239v3h = BigInteger.valueOf(10);\n\n            ECCurve c2m239v3 = new ECCurve.F2m(\n                239,\n                36,\n                new BigInteger(\"01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F\", 16),\n                new BigInteger(\"6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40\", 16),\n                c2m239v3n, c2m239v3h);\n\n            return new X9ECParameters(\n                c2m239v3,\n                c2m239v3.decodePoint(\n                    Hex.decode(\"0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92\")),\n                c2m239v3n, c2m239v3h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2pnb272w1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m272w1n = new BigInteger(\"0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521\", 16);\n            BigInteger c2m272w1h = BigInteger.valueOf(0xFF06);\n\n            ECCurve c2m272w1 = new ECCurve.F2m(\n                272,\n                1, 3, 56,\n                new BigInteger(\"0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20\", 16),\n                new BigInteger(\"7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7\", 16),\n                c2m272w1n, c2m272w1h);\n\n            return new X9ECParameters(\n                c2m272w1,\n                c2m272w1.decodePoint(\n                    Hex.decode(\"026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D\")),\n                c2m272w1n, c2m272w1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2pnb304w1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m304w1n = new BigInteger(\"0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D\", 16);\n            BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E);\n\n            ECCurve c2m304w1 = new ECCurve.F2m(\n                304,\n                1, 2, 11,\n                new BigInteger(\"00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681\", 16),\n                new BigInteger(\"00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE\", 16),\n                c2m304w1n, c2m304w1h);\n\n            return new X9ECParameters(\n                c2m304w1,\n                c2m304w1.decodePoint(\n                    Hex.decode(\"02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614\")),\n                c2m304w1n, c2m304w1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb359v1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m359v1n = new BigInteger(\"01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B\", 16);\n            BigInteger c2m359v1h = BigInteger.valueOf(0x4C);\n\n            ECCurve c2m359v1 = new ECCurve.F2m(\n                359,\n                68,\n                new BigInteger(\"5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557\", 16),\n                new BigInteger(\"2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988\", 16),\n                c2m359v1n, c2m359v1h);\n\n            return new X9ECParameters(\n                c2m359v1,\n                c2m359v1.decodePoint(\n                    Hex.decode(\"033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097\")),\n                c2m359v1n, c2m359v1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2pnb368w1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m368w1n = new BigInteger(\"010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967\", 16);\n            BigInteger c2m368w1h = BigInteger.valueOf(0xFF70);\n\n            ECCurve c2m368w1 = new ECCurve.F2m(\n                368,\n                1, 2, 85,\n                new BigInteger(\"00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D\", 16),\n                new BigInteger(\"00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A\", 16),\n                c2m368w1n, c2m368w1h);\n\n            return new X9ECParameters(\n                c2m368w1,\n                c2m368w1.decodePoint(\n                    Hex.decode(\"021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F\")),\n                c2m368w1n, c2m368w1h,\n                null);\n        }\n    };\n\n    static X9ECParametersHolder c2tnb431r1 = new X9ECParametersHolder()\n    {\n        protected X9ECParameters createParameters()\n        {\n            BigInteger c2m431r1n = new BigInteger(\"0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91\", 16);\n            BigInteger c2m431r1h = BigInteger.valueOf(0x2760);\n\n            ECCurve c2m431r1 = new ECCurve.F2m(\n                431,\n                120,\n                new BigInteger(\"1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F\", 16),\n                new BigInteger(\"10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618\", 16),\n                c2m431r1n, c2m431r1h);\n\n            return new X9ECParameters(\n                c2m431r1,\n                c2m431r1.decodePoint(\n                    Hex.decode(\"02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7\")),\n                c2m431r1n, c2m431r1h,\n                null);\n        }\n    };\n\n    static final Hashtable objIds = new Hashtable();\n    static final Hashtable curves = new Hashtable();\n    static final Hashtable names = new Hashtable();\n\n    static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)\n    {\n        objIds.put(name, oid);\n        names.put(oid, name);\n        curves.put(oid, holder);\n    }\n\n    static\n    {\n        defineCurve(\"prime192v1\", X9ObjectIdentifiers.prime192v1, prime192v1);\n        defineCurve(\"prime192v2\", X9ObjectIdentifiers.prime192v2, prime192v2);\n        defineCurve(\"prime192v3\", X9ObjectIdentifiers.prime192v3, prime192v3);\n        defineCurve(\"prime239v1\", X9ObjectIdentifiers.prime239v1, prime239v1);\n        defineCurve(\"prime239v2\", X9ObjectIdentifiers.prime239v2, prime239v2);\n        defineCurve(\"prime239v3\", X9ObjectIdentifiers.prime239v3, prime239v3);\n        defineCurve(\"prime256v1\", X9ObjectIdentifiers.prime256v1, prime256v1);\n        defineCurve(\"c2pnb163v1\", X9ObjectIdentifiers.c2pnb163v1, c2pnb163v1);\n        defineCurve(\"c2pnb163v2\", X9ObjectIdentifiers.c2pnb163v2, c2pnb163v2);\n        defineCurve(\"c2pnb163v3\", X9ObjectIdentifiers.c2pnb163v3, c2pnb163v3);\n        defineCurve(\"c2pnb176w1\", X9ObjectIdentifiers.c2pnb176w1, c2pnb176w1);\n        defineCurve(\"c2tnb191v1\", X9ObjectIdentifiers.c2tnb191v1, c2tnb191v1);\n        defineCurve(\"c2tnb191v2\", X9ObjectIdentifiers.c2tnb191v2, c2tnb191v2);\n        defineCurve(\"c2tnb191v3\", X9ObjectIdentifiers.c2tnb191v3, c2tnb191v3);\n        defineCurve(\"c2pnb208w1\", X9ObjectIdentifiers.c2pnb208w1, c2pnb208w1);\n        defineCurve(\"c2tnb239v1\", X9ObjectIdentifiers.c2tnb239v1, c2tnb239v1);\n        defineCurve(\"c2tnb239v2\", X9ObjectIdentifiers.c2tnb239v2, c2tnb239v2);\n        defineCurve(\"c2tnb239v3\", X9ObjectIdentifiers.c2tnb239v3, c2tnb239v3);\n        defineCurve(\"c2pnb272w1\", X9ObjectIdentifiers.c2pnb272w1, c2pnb272w1);\n        defineCurve(\"c2pnb304w1\", X9ObjectIdentifiers.c2pnb304w1, c2pnb304w1);\n        defineCurve(\"c2tnb359v1\", X9ObjectIdentifiers.c2tnb359v1, c2tnb359v1);\n        defineCurve(\"c2pnb368w1\", X9ObjectIdentifiers.c2pnb368w1, c2pnb368w1);\n        defineCurve(\"c2tnb431r1\", X9ObjectIdentifiers.c2tnb431r1, c2tnb431r1);\n    }\n\n    public static X9ECParameters getByName(\n        String name)\n    {\n        ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));\n\n        if (oid != null)\n        {\n            return getByOID(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * return the X9ECParameters object for the named curve represented by\n     * the passed in object identifier. Null if the curve isn't present.\n     *\n     * @param oid an object identifier representing a named curve, if present.\n     */\n    public static X9ECParameters getByOID(\n        ASN1ObjectIdentifier oid)\n    {\n        X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid);\n\n        if (holder != null)\n        {\n            return holder.getParameters();\n        }\n\n        return null;\n    }\n\n    /**\n     * return the object identifier signified by the passed in name. Null\n     * if there is no object identifier associated with name.\n     *\n     * @return the object identifier associated with name, if present.\n     */\n    public static ASN1ObjectIdentifier getOID(\n        String name)\n    {\n        return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));\n    }\n\n    /**\n     * return the named curve name represented by the given object identifier.\n     */\n    public static String getName(\n        ASN1ObjectIdentifier oid)\n    {\n        return (String)names.get(oid);\n    }\n\n    /**\n     * returns an enumeration containing the name strings for curves\n     * contained in this structure.\n     */\n    public static Enumeration getNames()\n    {\n        return objIds.keys();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X962Parameters.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport local.org.bouncycastle.asn1.ASN1Choice;\nimport local.org.bouncycastle.asn1.ASN1Null;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1TaggedObject;\n\npublic class X962Parameters\n    extends ASN1Object\n    implements ASN1Choice\n{\n    private ASN1Primitive           params = null;\n\n    public static X962Parameters getInstance(\n        Object obj)\n    {\n        if (obj == null || obj instanceof X962Parameters) \n        {\n            return (X962Parameters)obj;\n        }\n        \n        if (obj instanceof ASN1Primitive) \n        {\n            return new X962Parameters((ASN1Primitive)obj);\n        }\n        \n        throw new IllegalArgumentException(\"unknown object in getInstance()\");\n    }\n    \n    public static X962Parameters getInstance(\n        ASN1TaggedObject obj,\n        boolean          explicit)\n    {\n        return getInstance(obj.getObject()); // must be explicitly tagged\n    }\n    \n    public X962Parameters(\n        X9ECParameters      ecParameters)\n    {\n        this.params = ecParameters.toASN1Primitive();\n    }\n\n    public X962Parameters(\n        ASN1ObjectIdentifier  namedCurve)\n    {\n        this.params = namedCurve;\n    }\n\n    public X962Parameters(\n        ASN1Primitive           obj)\n    {\n        this.params = obj;\n    }\n\n    public boolean isNamedCurve()\n    {\n        return (params instanceof ASN1ObjectIdentifier);\n    }\n\n    public boolean isImplicitlyCA()\n    {\n        return (params instanceof ASN1Null);\n    }\n\n    public ASN1Primitive getParameters()\n    {\n        return params;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     * Parameters ::= CHOICE {\n     *    ecParameters ECParameters,\n     *    namedCurve   CURVES.&id({CurveNames}),\n     *    implicitlyCA NULL\n     * }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        return (ASN1Primitive)params;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9Curve.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.math.ec.ECCurve;\n\n\n/**\n * ASN.1 def for Elliptic-Curve Curve structure. See\n * X9.62, for further details.\n */\npublic class X9Curve\n    extends ASN1Object\n    implements X9ObjectIdentifiers\n{\n    private ECCurve     curve;\n    private byte[]      seed;\n    private ASN1ObjectIdentifier fieldIdentifier = null;\n\n    public X9Curve(\n        ECCurve     curve)\n    {\n        this.curve = curve;\n        this.seed = null;\n        setFieldIdentifier();\n    }\n\n    public X9Curve(\n        ECCurve     curve,\n        byte[]      seed)\n    {\n        this.curve = curve;\n        this.seed = seed;\n        setFieldIdentifier();\n    }\n\n    public X9Curve(\n        X9FieldID     fieldID,\n        ASN1Sequence  seq)\n    {\n        fieldIdentifier = fieldID.getIdentifier();\n        if (fieldIdentifier.equals(prime_field))\n        {\n            BigInteger      p = ((ASN1Integer)fieldID.getParameters()).getValue();\n            X9FieldElement  x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0));\n            X9FieldElement  x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1));\n            curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());\n        }\n        else if (fieldIdentifier.equals(characteristic_two_field)) \n        {\n            // Characteristic two field\n            ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters());\n            int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue().\n                intValue();\n            ASN1ObjectIdentifier representation\n                = (ASN1ObjectIdentifier)parameters.getObjectAt(1);\n\n            int k1 = 0;\n            int k2 = 0;\n            int k3 = 0;\n\n            if (representation.equals(tpBasis)) \n            {\n                // Trinomial basis representation\n                k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue();\n            }\n            else if (representation.equals(ppBasis))\n            {\n                // Pentanomial basis representation\n                ASN1Sequence pentanomial = ASN1Sequence.getInstance(parameters.getObjectAt(2));\n                k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue();\n                k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue();\n                k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue();\n            }\n            else\n            {\n                throw new IllegalArgumentException(\"This type of EC basis is not implemented\");\n            }\n            X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0));\n            X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1));\n            // TODO Is it possible to get the order (n) and cofactor(h) too?\n            curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This type of ECCurve is not implemented\");\n        }\n\n        if (seq.size() == 3)\n        {\n            seed = ((DERBitString)seq.getObjectAt(2)).getBytes();\n        }\n    }\n\n    private void setFieldIdentifier()\n    {\n        if (curve instanceof ECCurve.Fp)\n        {\n            fieldIdentifier = prime_field;\n        }\n        else if (curve instanceof ECCurve.F2m)\n        {\n            fieldIdentifier = characteristic_two_field;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This type of ECCurve is not implemented\");\n        }\n    }\n\n    public ECCurve  getCurve()\n    {\n        return curve;\n    }\n\n    public byte[]   getSeed()\n    {\n        return seed;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  Curve ::= SEQUENCE {\n     *      a               FieldElement,\n     *      b               FieldElement,\n     *      seed            BIT STRING      OPTIONAL\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        if (fieldIdentifier.equals(prime_field)) \n        { \n            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());\n            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());\n        } \n        else if (fieldIdentifier.equals(characteristic_two_field)) \n        {\n            v.add(new X9FieldElement(curve.getA()).toASN1Primitive());\n            v.add(new X9FieldElement(curve.getB()).toASN1Primitive());\n        }\n\n        if (seed != null)\n        {\n            v.add(new DERBitString(seed));\n        }\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9ECParameters.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.math.ec.ECPoint;\n\n\n/**\n * ASN.1 def for Elliptic-Curve ECParameters structure. See\n * X9.62, for further details.\n */\npublic class X9ECParameters\n    extends ASN1Object\n    implements X9ObjectIdentifiers\n{\n    private static final BigInteger   ONE = BigInteger.valueOf(1);\n\n    private X9FieldID           fieldID;\n    private ECCurve             curve;\n    private ECPoint             g;\n    private BigInteger          n;\n    private BigInteger          h;\n    private byte[]              seed;\n\n    private X9ECParameters(\n        ASN1Sequence  seq)\n    {\n        if (!(seq.getObjectAt(0) instanceof ASN1Integer)\n           || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE))\n        {\n            throw new IllegalArgumentException(\"bad version in X9ECParameters\");\n        }\n\n        X9Curve     x9c = new X9Curve(\n                        new X9FieldID((ASN1Sequence)seq.getObjectAt(1)),\n                        (ASN1Sequence)seq.getObjectAt(2));\n\n        this.curve = x9c.getCurve();\n        this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint();\n        this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();\n        this.seed = x9c.getSeed();\n\n        if (seq.size() == 6)\n        {\n            this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();\n        }\n    }\n\n    public static X9ECParameters getInstance(Object obj)\n    {\n        if (obj instanceof X9ECParameters)\n        {\n            return (X9ECParameters)obj;\n        }\n\n        if (obj != null)\n        {\n            return new X9ECParameters(ASN1Sequence.getInstance(obj));\n        }\n\n        return null;\n    }\n\n    public X9ECParameters(\n        ECCurve     curve,\n        ECPoint     g,\n        BigInteger  n)\n    {\n        this(curve, g, n, ONE, null);\n    }\n\n    public X9ECParameters(\n        ECCurve     curve,\n        ECPoint     g,\n        BigInteger  n,\n        BigInteger  h)\n    {\n        this(curve, g, n, h, null);\n    }\n\n    public X9ECParameters(\n        ECCurve     curve,\n        ECPoint     g,\n        BigInteger  n,\n        BigInteger  h,\n        byte[]      seed)\n    {\n        this.curve = curve;\n        this.g = g;\n        this.n = n;\n        this.h = h;\n        this.seed = seed;\n\n        if (curve instanceof ECCurve.Fp)\n        {\n            this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ());\n        }\n        else\n        {\n            if (curve instanceof ECCurve.F2m)\n            {\n                ECCurve.F2m curveF2m = (ECCurve.F2m)curve;\n                this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(),\n                    curveF2m.getK2(), curveF2m.getK3());\n            }\n        }\n    }\n\n    public ECCurve getCurve()\n    {\n        return curve;\n    }\n\n    public ECPoint getG()\n    {\n        return g;\n    }\n\n    public BigInteger getN()\n    {\n        return n;\n    }\n\n    public BigInteger getH()\n    {\n        if (h == null)\n        {\n            return ONE;        // TODO - this should be calculated, it will cause issues with custom curves.\n        }\n\n        return h;\n    }\n\n    public byte[] getSeed()\n    {\n        return seed;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  ECParameters ::= SEQUENCE {\n     *      version         INTEGER { ecpVer1(1) } (ecpVer1),\n     *      fieldID         FieldID {{FieldTypes}},\n     *      curve           X9Curve,\n     *      base            X9ECPoint,\n     *      order           INTEGER,\n     *      cofactor        INTEGER OPTIONAL\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(new ASN1Integer(1));\n        v.add(fieldID);\n        v.add(new X9Curve(curve, seed));\n        v.add(new X9ECPoint(g));\n        v.add(new ASN1Integer(n));\n\n        if (h != null)\n        {\n            v.add(new ASN1Integer(h));\n        }\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9ECParametersHolder.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\npublic abstract class X9ECParametersHolder\n{\n    private X9ECParameters params;\n\n    public X9ECParameters getParameters()\n    {\n        if (params == null)\n        {\n            params = createParameters();\n        }\n\n        return params;\n    }\n\n    protected abstract X9ECParameters createParameters();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9ECPoint.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.math.ec.ECPoint;\n\n/**\n * class for describing an ECPoint as a DER object.\n */\npublic class X9ECPoint\n    extends ASN1Object\n{\n    ECPoint p;\n\n    public X9ECPoint(\n        ECPoint p)\n    {\n        this.p = p;\n    }\n\n    public X9ECPoint(\n        ECCurve          c,\n        ASN1OctetString  s)\n    {\n        this.p = c.decodePoint(s.getOctets());\n    }\n\n    public ECPoint getPoint()\n    {\n        return p;\n    }\n\n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  ECPoint ::= OCTET STRING\n     * </pre>\n     * <p>\n     * Octet string produced using ECPoint.getEncoded().\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        return new DEROctetString(p.getEncoded());\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9FieldElement.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DEROctetString;\nimport local.org.bouncycastle.math.ec.ECFieldElement;\n\n\n/**\n * class for processing an FieldElement as a DER object.\n */\npublic class X9FieldElement\n    extends ASN1Object\n{\n    protected ECFieldElement  f;\n    \n    private static X9IntegerConverter converter = new X9IntegerConverter();\n\n    public X9FieldElement(ECFieldElement f)\n    {\n        this.f = f;\n    }\n    \n    public X9FieldElement(BigInteger p, ASN1OctetString s)\n    {\n        this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets())));\n    }\n    \n    public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s)\n    {\n        this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets())));\n    }\n    \n    public ECFieldElement getValue()\n    {\n        return f;\n    }\n    \n    /**\n     * Produce an object suitable for an ASN1OutputStream.\n     * <pre>\n     *  FieldElement ::= OCTET STRING\n     * </pre>\n     * <p>\n     * <ol>\n     * <li> if <i>q</i> is an odd prime then the field element is\n     * processed as an Integer and converted to an octet string\n     * according to x 9.62 4.3.1.</li>\n     * <li> if <i>q</i> is 2<sup>m</sup> then the bit string\n     * contained in the field element is converted into an octet\n     * string with the same ordering padded at the front if necessary.\n     * </li>\n     * </ol>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        int byteCount = converter.getByteLength(f);\n        byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount);\n\n        return new DEROctetString(paddedBigInteger);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9FieldID.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1Object;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DERSequence;\n\n\n/**\n * ASN.1 def for Elliptic-Curve Field ID structure. See\n * X9.62, for further details.\n */\npublic class X9FieldID\n    extends ASN1Object\n    implements X9ObjectIdentifiers\n{\n    private ASN1ObjectIdentifier     id;\n    private ASN1Primitive parameters;\n\n    /**\n     * Constructor for elliptic curves over prime fields\n     * <code>F<sub>2</sub></code>.\n     * @param primeP The prime <code>p</code> defining the prime field.\n     */\n    public X9FieldID(BigInteger primeP)\n    {\n        this.id = prime_field;\n        this.parameters = new ASN1Integer(primeP);\n    }\n\n    /**\n     * Constructor for elliptic curves over binary fields\n     * <code>F<sub>2<sup>m</sup></sub></code>.\n     * @param m  The exponent <code>m</code> of\n     * <code>F<sub>2<sup>m</sup></sub></code>.\n     * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +\n     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n     * represents the reduction polynomial <code>f(z)</code>.\n     * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +\n     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n     * represents the reduction polynomial <code>f(z)</code>.\n     * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +\n     * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n     * represents the reduction polynomial <code>f(z)</code>..\n     */\n    public X9FieldID(int m, int k1, int k2, int k3)\n    {\n        this.id = characteristic_two_field;\n        ASN1EncodableVector fieldIdParams = new ASN1EncodableVector();\n        fieldIdParams.add(new ASN1Integer(m));\n        \n        if (k2 == 0) \n        {\n            fieldIdParams.add(tpBasis);\n            fieldIdParams.add(new ASN1Integer(k1));\n        } \n        else \n        {\n            fieldIdParams.add(ppBasis);\n            ASN1EncodableVector pentanomialParams = new ASN1EncodableVector();\n            pentanomialParams.add(new ASN1Integer(k1));\n            pentanomialParams.add(new ASN1Integer(k2));\n            pentanomialParams.add(new ASN1Integer(k3));\n            fieldIdParams.add(new DERSequence(pentanomialParams));\n        }\n        \n        this.parameters = new DERSequence(fieldIdParams);\n    }\n\n    public X9FieldID(\n        ASN1Sequence  seq)\n    {\n        this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0);\n        this.parameters = (ASN1Primitive)seq.getObjectAt(1);\n    }\n\n    public ASN1ObjectIdentifier getIdentifier()\n    {\n        return id;\n    }\n\n    public ASN1Primitive getParameters()\n    {\n        return parameters;\n    }\n\n    /**\n     * Produce a DER encoding of the following structure.\n     * <pre>\n     *  FieldID ::= SEQUENCE {\n     *      fieldType       FIELD-ID.&amp;id({IOSet}),\n     *      parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})\n     *  }\n     * </pre>\n     */\n    public ASN1Primitive toASN1Primitive()\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(this.id);\n        v.add(this.parameters);\n\n        return new DERSequence(v);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9IntegerConverter.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.math.ec.ECFieldElement;\n\n\npublic class X9IntegerConverter\n{\n    public int getByteLength(\n        ECCurve c)\n    {\n        return (c.getFieldSize() + 7) / 8;\n    }\n\n    public int getByteLength(\n        ECFieldElement fe)\n    {\n        return (fe.getFieldSize() + 7) / 8;\n    }\n\n    public byte[] integerToBytes(\n        BigInteger s,\n        int        qLength)\n    {\n        byte[] bytes = s.toByteArray();\n        \n        if (qLength < bytes.length)\n        {\n            byte[] tmp = new byte[qLength];\n        \n            System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length);\n            \n            return tmp;\n        }\n        else if (qLength > bytes.length)\n        {\n            byte[] tmp = new byte[qLength];\n        \n            System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);\n            \n            return tmp; \n        }\n    \n        return bytes;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java",
    "content": "package local.org.bouncycastle.asn1.x9;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\n\npublic interface X9ObjectIdentifiers\n{\n    //\n    // X9.62\n    //\n    // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)\n    //            us(840) ansi-x962(10045) }\n    //\n    static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier(\"1.2.840.10045\");\n    static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch(\"1\");\n\n    static final ASN1ObjectIdentifier prime_field = id_fieldType.branch(\"1\");\n\n    static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch(\"2\");\n\n    static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch(\"3.1\");\n\n    static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch(\"3.2\");\n\n    static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch(\"3.3\");\n\n    static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch(\"4\");\n\n    static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + \".1\");\n\n    static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch(\"2\");\n\n    static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch(\"1\");\n\n    static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch(\"3\");\n\n    static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch(\"1\");\n\n    static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch(\"2\");\n\n    static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch(\"3\");\n\n    static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch(\"4\");\n\n    //\n    // named curves\n    //\n    static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch(\"3\");\n\n    //\n    // Two Curves\n    //\n    static final ASN1ObjectIdentifier  cTwoCurve = ellipticCurve.branch(\"0\");\n\n    static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch(\"1\");\n    static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch(\"2\");\n    static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch(\"3\");\n    static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch(\"4\");\n    static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch(\"5\");\n    static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch(\"6\");\n    static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch(\"7\");\n    static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch(\"8\");\n    static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch(\"9\");\n    static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch(\"10\");\n    static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch(\"11\");\n    static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch(\"12\");\n    static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch(\"13\");\n    static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch(\"14\");\n    static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch(\"15\");\n    static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch(\"16\");\n    static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch(\"17\");\n    static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch(\"18\");\n    static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch(\"19\");\n    static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch(\"20\");\n\n    //\n    // Prime\n    //\n    static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch(\"1\");\n\n    static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch(\"1\");\n    static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch(\"2\");\n    static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch(\"3\");\n    static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch(\"4\");\n    static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch(\"5\");\n    static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch(\"6\");\n    static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch(\"7\");\n\n    //\n    // DSA\n    //\n    // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)\n    //            us(840) ansi-x957(10040) number-type(4) 1 }\n    static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier(\"1.2.840.10040.4.1\");\n\n    /**\n     * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57\n     * (10040) x9cm(4) 3 }\n     */\n    public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier(\"1.2.840.10040.4.3\");\n\n    /**\n     * X9.63\n     */\n    public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier(\"1.3.133.16.840.63.0\");\n    public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch(\"2\");\n    public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch(\"3\");\n    public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch(\"16\");\n\n    /**\n     * X9.42\n     */\n\n    static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier(\"1.2.840.10046\");\n\n    //\n    // Diffie-Hellman\n    //\n    // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)\n    //            us(840) ansi-x942(10046) number-type(2) 1 }\n    //\n    public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch(\"2.1\");\n\n    public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch(\"3\");\n    public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch(\"1\");\n    public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch(\"2\");\n    public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch(\"3\");\n    public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch(\"4\");\n    public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch(\"5\");\n    public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch(\"6\");\n    public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch(\"7\");\n    public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch(\"8\");\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/AttributeCertificateHolder.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.asn1.x509.GeneralName;\nimport local.org.bouncycastle.asn1.x509.GeneralNames;\nimport local.org.bouncycastle.asn1.x509.Holder;\nimport local.org.bouncycastle.asn1.x509.IssuerSerial;\nimport local.org.bouncycastle.asn1.x509.ObjectDigestInfo;\nimport local.org.bouncycastle.operator.DigestCalculator;\nimport local.org.bouncycastle.operator.DigestCalculatorProvider;\nimport local.org.bouncycastle.util.Arrays;\nimport local.org.bouncycastle.util.Selector;\n\n\n/**\n * The Holder object.\n * \n * <pre>\n *          Holder ::= SEQUENCE {\n *                baseCertificateID   [0] IssuerSerial OPTIONAL,\n *                         -- the issuer and serial number of\n *                         -- the holder's Public Key Certificate\n *                entityName          [1] GeneralNames OPTIONAL,\n *                         -- the name of the claimant or role\n *                objectDigestInfo    [2] ObjectDigestInfo OPTIONAL\n *                         -- used to directly authenticate the holder,\n *                         -- for example, an executable\n *          }\n * </pre>\n * <p>\n * <b>Note:</b> If objectDigestInfo comparisons are to be carried out the static\n * method setDigestCalculatorProvider <b>must</b> be called once to configure the class\n * to do the necessary calculations.\n * </p>\n */\npublic class AttributeCertificateHolder\n    implements Selector\n{\n    private static DigestCalculatorProvider digestCalculatorProvider;\n\n    final Holder holder;\n\n    AttributeCertificateHolder(ASN1Sequence seq)\n    {\n        holder = Holder.getInstance(seq);\n    }\n\n    public AttributeCertificateHolder(X500Name issuerName,\n        BigInteger serialNumber)\n    {\n        holder = new Holder(new IssuerSerial(\n            new GeneralNames(new GeneralName(issuerName)),\n            new ASN1Integer(serialNumber)));\n    }\n\n    public AttributeCertificateHolder(X509CertificateHolder cert)\n    {\n        holder = new Holder(new IssuerSerial(generateGeneralNames(cert.getIssuer()),\n            new ASN1Integer(cert.getSerialNumber())));\n    }\n\n    public AttributeCertificateHolder(X500Name principal)\n    {\n        holder = new Holder(generateGeneralNames(principal));\n    }\n\n    /**\n     * Constructs a holder for v2 attribute certificates with a hash value for\n     * some type of object.\n     * <p>\n     * <code>digestedObjectType</code> can be one of the following:\n     * <ul>\n     * <li>0 - publicKey - A hash of the public key of the holder must be\n     * passed.\n     * <li>1 - publicKeyCert - A hash of the public key certificate of the\n     * holder must be passed.\n     * <li>2 - otherObjectDigest - A hash of some other object type must be\n     * passed. <code>otherObjectTypeID</code> must not be empty.\n     * </ul>\n     * <p>\n     * This cannot be used if a v1 attribute certificate is used.\n     * \n     * @param digestedObjectType The digest object type.\n     * @param digestAlgorithm The algorithm identifier for the hash.\n     * @param otherObjectTypeID The object type ID if\n     *            <code>digestedObjectType</code> is\n     *            <code>otherObjectDigest</code>.\n     * @param objectDigest The hash value.\n     */\n    public AttributeCertificateHolder(int digestedObjectType,\n        ASN1ObjectIdentifier digestAlgorithm, ASN1ObjectIdentifier otherObjectTypeID, byte[] objectDigest)\n    {\n        holder = new Holder(new ObjectDigestInfo(digestedObjectType,\n            otherObjectTypeID, new AlgorithmIdentifier(digestAlgorithm), Arrays\n                .clone(objectDigest)));\n    }\n\n    /**\n     * Returns the digest object type if an object digest info is used.\n     * <p>\n     * <ul>\n     * <li>0 - publicKey - A hash of the public key of the holder must be\n     * passed.\n     * <li>1 - publicKeyCert - A hash of the public key certificate of the\n     * holder must be passed.\n     * <li>2 - otherObjectDigest - A hash of some other object type must be\n     * passed. <code>otherObjectTypeID</code> must not be empty.\n     * </ul>\n     * \n     * @return The digest object type or -1 if no object digest info is set.\n     */\n    public int getDigestedObjectType()\n    {\n        if (holder.getObjectDigestInfo() != null)\n        {\n            return holder.getObjectDigestInfo().getDigestedObjectType()\n                .getValue().intValue();\n        }\n        return -1;\n    }\n\n    /**\n     * Returns algorithm identifier for the digest used if ObjectDigestInfo is present.\n     * \n     * @return digest AlgorithmIdentifier or <code>null</code> if ObjectDigestInfo is absent.\n     */\n    public AlgorithmIdentifier getDigestAlgorithm()\n    {\n        if (holder.getObjectDigestInfo() != null)\n        {\n            return holder.getObjectDigestInfo().getDigestAlgorithm();\n        }\n        return null;\n    }\n\n    /**\n     * Returns the hash if an object digest info is used.\n     * \n     * @return The hash or <code>null</code> if ObjectDigestInfo is absent.\n     */\n    public byte[] getObjectDigest()\n    {\n        if (holder.getObjectDigestInfo() != null)\n        {\n            return holder.getObjectDigestInfo().getObjectDigest().getBytes();\n        }\n        return null;\n    }\n\n    /**\n     * Returns the digest algorithm ID if an object digest info is used.\n     * \n     * @return The digest algorithm ID or <code>null</code> if no object\n     *         digest info is set.\n     */\n    public ASN1ObjectIdentifier getOtherObjectTypeID()\n    {\n        if (holder.getObjectDigestInfo() != null)\n        {\n            new ASN1ObjectIdentifier(holder.getObjectDigestInfo().getOtherObjectTypeID().getId());\n        }\n        return null;\n    }\n\n    private GeneralNames generateGeneralNames(X500Name principal)\n    {\n        return new GeneralNames(new GeneralName(principal));\n    }\n\n    private boolean matchesDN(X500Name subject, GeneralNames targets)\n    {\n        GeneralName[] names = targets.getNames();\n\n        for (int i = 0; i != names.length; i++)\n        {\n            GeneralName gn = names[i];\n\n            if (gn.getTagNo() == GeneralName.directoryName)\n            {\n                if (X500Name.getInstance(gn.getName()).equals(subject))\n                {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    private X500Name[] getPrincipals(GeneralName[] names)\n    {\n        List l = new ArrayList(names.length);\n\n        for (int i = 0; i != names.length; i++)\n        {\n            if (names[i].getTagNo() == GeneralName.directoryName)\n            {\n                l.add(X500Name.getInstance(names[i].getName()));\n            }\n        }\n\n        return (X500Name[])l.toArray(new X500Name[l.size()]);\n    }\n\n    /**\n     * Return any principal objects inside the attribute certificate holder\n     * entity names field.\n     * \n     * @return an array of Principal objects (usually X500Principal), null if no\n     *         entity names field is set.\n     */\n    public X500Name[] getEntityNames()\n    {\n        if (holder.getEntityName() != null)\n        {\n            return getPrincipals(holder.getEntityName().getNames());\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the principals associated with the issuer attached to this holder\n     * \n     * @return an array of principals, null if no BaseCertificateID is set.\n     */\n    public X500Name[] getIssuer()\n    {\n        if (holder.getBaseCertificateID() != null)\n        {\n            return getPrincipals(holder.getBaseCertificateID().getIssuer().getNames());\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the serial number associated with the issuer attached to this\n     * holder.\n     * \n     * @return the certificate serial number, null if no BaseCertificateID is\n     *         set.\n     */\n    public BigInteger getSerialNumber()\n    {\n        if (holder.getBaseCertificateID() != null)\n        {\n            return holder.getBaseCertificateID().getSerial().getValue();\n        }\n\n        return null;\n    }\n\n    public Object clone()\n    {\n        return new AttributeCertificateHolder((ASN1Sequence)holder.toASN1Primitive());\n    }\n\n    public boolean match(Object obj)\n    {\n        if (!(obj instanceof X509CertificateHolder))\n        {\n            return false;\n        }\n\n        X509CertificateHolder x509Cert = (X509CertificateHolder)obj;\n\n        if (holder.getBaseCertificateID() != null)\n        {\n            return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())\n                && matchesDN(x509Cert.getIssuer(), holder.getBaseCertificateID().getIssuer());\n        }\n\n        if (holder.getEntityName() != null)\n        {\n            if (matchesDN(x509Cert.getSubject(),\n                holder.getEntityName()))\n            {\n                return true;\n            }\n        }\n\n        if (holder.getObjectDigestInfo() != null)\n        {\n            try\n            {\n                DigestCalculator digCalc = digestCalculatorProvider.get(holder.getObjectDigestInfo().getDigestAlgorithm());\n                OutputStream     digOut = digCalc.getOutputStream();\n\n                switch (getDigestedObjectType())\n                {\n                case ObjectDigestInfo.publicKey:\n                    // TODO: DSA Dss-parms\n                    digOut.write(x509Cert.getSubjectPublicKeyInfo().getEncoded());\n                    break;\n                case ObjectDigestInfo.publicKeyCert:\n                    digOut.write(x509Cert.getEncoded());\n                    break;\n                }\n\n                digOut.close();\n\n                if (!Arrays.areEqual(digCalc.getDigest(), getObjectDigest()))\n                {\n                    return false;\n                }\n            }\n            catch (Exception e)\n            {\n                return false;\n            }\n        }\n\n        return false;\n    }\n\n    public boolean equals(Object obj)\n    {\n        if (obj == this)\n        {\n            return true;\n        }\n\n        if (!(obj instanceof AttributeCertificateHolder))\n        {\n            return false;\n        }\n\n        AttributeCertificateHolder other = (AttributeCertificateHolder)obj;\n\n        return this.holder.equals(other.holder);\n    }\n\n    public int hashCode()\n    {\n        return this.holder.hashCode();\n    }\n\n    /**\n     * Set a digest calculator provider to be used if matches are attempted using\n     * ObjectDigestInfo,\n     *\n     * @param digCalcProvider a provider of digest calculators.\n     */\n    public static void setDigestCalculatorProvider(DigestCalculatorProvider digCalcProvider)\n    {\n        digestCalculatorProvider = digCalcProvider;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/AttributeCertificateIssuer.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.AttCertIssuer;\nimport local.org.bouncycastle.asn1.x509.GeneralName;\nimport local.org.bouncycastle.asn1.x509.GeneralNames;\nimport local.org.bouncycastle.asn1.x509.V2Form;\nimport local.org.bouncycastle.util.Selector;\n\n\n/**\n * Carrying class for an attribute certificate issuer.\n */\npublic class AttributeCertificateIssuer\n    implements Selector\n{\n    final ASN1Encodable form;\n\n    /**\n     * Set the issuer directly with the ASN.1 structure.\n     *\n     * @param issuer The issuer\n     */\n    public AttributeCertificateIssuer(AttCertIssuer issuer)\n    {\n        form = issuer.getIssuer();\n    }\n\n    public AttributeCertificateIssuer(X500Name principal)\n    {\n        form = new V2Form(new GeneralNames(new GeneralName(principal)));\n    }\n\n    public X500Name[] getNames()\n    {\n        GeneralNames name;\n\n        if (form instanceof V2Form)\n        {\n            name = ((V2Form)form).getIssuerName();\n        }\n        else\n        {\n            name = (GeneralNames)form;\n        }\n\n        GeneralName[] names = name.getNames();\n\n        List l = new ArrayList(names.length);\n\n        for (int i = 0; i != names.length; i++)\n        {\n            if (names[i].getTagNo() == GeneralName.directoryName)\n            {\n                l.add(X500Name.getInstance(names[i].getName()));\n            }\n        }\n\n        return (X500Name[])l.toArray(new X500Name[l.size()]);\n    }\n\n    private boolean matchesDN(X500Name subject, GeneralNames targets)\n    {\n        GeneralName[] names = targets.getNames();\n\n        for (int i = 0; i != names.length; i++)\n        {\n            GeneralName gn = names[i];\n\n            if (gn.getTagNo() == GeneralName.directoryName)\n            {\n                if (X500Name.getInstance(gn.getName()).equals(subject))\n                {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public Object clone()\n    {\n        return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));\n    }\n\n    public boolean equals(Object obj)\n    {\n        if (obj == this)\n        {\n            return true;\n        }\n\n        if (!(obj instanceof AttributeCertificateIssuer))\n        {\n            return false;\n        }\n\n        AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;\n\n        return this.form.equals(other.form);\n    }\n\n    public int hashCode()\n    {\n        return this.form.hashCode();\n    }\n\n    public boolean match(Object obj)\n    {\n        if (!(obj instanceof X509CertificateHolder))\n        {\n            return false;\n        }\n\n        X509CertificateHolder x509Cert = (X509CertificateHolder)obj;\n\n        if (form instanceof V2Form)\n        {\n            V2Form issuer = (V2Form)form;\n            if (issuer.getBaseCertificateID() != null)\n            {\n                return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())\n                    && matchesDN(x509Cert.getIssuer(), issuer.getBaseCertificateID().getIssuer());\n            }\n\n            GeneralNames name = issuer.getIssuerName();\n            if (matchesDN(x509Cert.getSubject(), name))\n            {\n                return true;\n            }\n        }\n        else\n        {\n            GeneralNames name = (GeneralNames)form;\n            if (matchesDN(x509Cert.getSubject(), name))\n            {\n                return true;\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/CertException.java",
    "content": "package local.org.bouncycastle.cert;\n\n/**\n * General checked Exception thrown in the cert package and its sub-packages.\n */\npublic class CertException\n    extends Exception\n{\n    private Throwable cause;\n\n    public CertException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public CertException(String msg)\n    {\n        super(msg);\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/CertIOException.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.IOException;\n\n/**\n * General IOException thrown in the cert package and its sub-packages.\n */\npublic class CertIOException\n    extends IOException\n{\n    private Throwable cause;\n\n    public CertIOException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public CertIOException(String msg)\n    {\n        super(msg);\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/CertRuntimeException.java",
    "content": "package local.org.bouncycastle.cert;\n\npublic class CertRuntimeException\n    extends RuntimeException\n{\n    private Throwable cause;\n\n    public CertRuntimeException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/CertUtils.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1EncodableVector;\nimport local.org.bouncycastle.asn1.ASN1GeneralizedTime;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.DERBitString;\nimport local.org.bouncycastle.asn1.DERNull;\nimport local.org.bouncycastle.asn1.DEROutputStream;\nimport local.org.bouncycastle.asn1.DERSequence;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.asn1.x509.AttributeCertificate;\nimport local.org.bouncycastle.asn1.x509.AttributeCertificateInfo;\nimport local.org.bouncycastle.asn1.x509.Certificate;\nimport local.org.bouncycastle.asn1.x509.CertificateList;\nimport local.org.bouncycastle.asn1.x509.Extensions;\nimport local.org.bouncycastle.asn1.x509.ExtensionsGenerator;\nimport local.org.bouncycastle.asn1.x509.TBSCertList;\nimport local.org.bouncycastle.asn1.x509.TBSCertificate;\nimport local.org.bouncycastle.operator.ContentSigner;\n\n\nclass CertUtils\n{\n    private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet());\n    private static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());\n\n    static X509CertificateHolder generateFullCert(ContentSigner signer, TBSCertificate tbsCert)\n    {\n        try\n        {\n            return new X509CertificateHolder(generateStructure(tbsCert, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCert)));\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"cannot produce certificate signature\");\n        }\n    }\n\n    static X509AttributeCertificateHolder generateFullAttrCert(ContentSigner signer, AttributeCertificateInfo attrInfo)\n    {\n        try\n        {\n            return new X509AttributeCertificateHolder(generateAttrStructure(attrInfo, signer.getAlgorithmIdentifier(), generateSig(signer, attrInfo)));\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"cannot produce attribute certificate signature\");\n        }\n    }\n\n    static X509CRLHolder generateFullCRL(ContentSigner signer, TBSCertList tbsCertList)\n    {\n        try\n        {\n            return new X509CRLHolder(generateCRLStructure(tbsCertList, signer.getAlgorithmIdentifier(), generateSig(signer, tbsCertList)));\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"cannot produce certificate signature\");\n        }\n    }\n\n    private static byte[] generateSig(ContentSigner signer, ASN1Encodable tbsObj)\n        throws IOException\n    {\n        OutputStream sOut = signer.getOutputStream();\n        DEROutputStream dOut = new DEROutputStream(sOut);\n\n        dOut.writeObject(tbsObj);\n\n        sOut.close();\n\n        return signer.getSignature();\n    }\n\n    private static Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature)\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(tbsCert);\n        v.add(sigAlgId);\n        v.add(new DERBitString(signature));\n\n        return Certificate.getInstance(new DERSequence(v));\n    }\n\n    private static AttributeCertificate generateAttrStructure(AttributeCertificateInfo attrInfo, AlgorithmIdentifier sigAlgId, byte[] signature)\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(attrInfo);\n        v.add(sigAlgId);\n        v.add(new DERBitString(signature));\n\n        return AttributeCertificate.getInstance(new DERSequence(v));\n    }\n\n    private static CertificateList generateCRLStructure(TBSCertList tbsCertList, AlgorithmIdentifier sigAlgId, byte[] signature)\n    {\n        ASN1EncodableVector v = new ASN1EncodableVector();\n\n        v.add(tbsCertList);\n        v.add(sigAlgId);\n        v.add(new DERBitString(signature));\n\n        return CertificateList.getInstance(new DERSequence(v));\n    }\n\n    static Set getCriticalExtensionOIDs(Extensions extensions)\n    {\n        if (extensions == null)\n        {\n            return EMPTY_SET;\n        }\n\n        return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs())));\n    }\n\n    static Set getNonCriticalExtensionOIDs(Extensions extensions)\n    {\n        if (extensions == null)\n        {\n            return EMPTY_SET;\n        }\n\n        // TODO: should probably produce a set that imposes correct ordering\n        return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs())));\n    }\n\n    static List getExtensionOIDs(Extensions extensions)\n    {\n        if (extensions == null)\n        {\n            return EMPTY_LIST;\n        }\n\n        return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs()));\n    }\n\n    static void addExtension(ExtensionsGenerator extGenerator, ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)\n        throws CertIOException\n    {\n        try\n        {\n            extGenerator.addExtension(oid, isCritical, value);\n        }\n        catch (IOException e)\n        {\n            throw new CertIOException(\"cannot encode extension: \" + e.getMessage(), e);\n        }\n    }\n\n    static DERBitString booleanToBitString(boolean[] id)\n    {\n        byte[] bytes = new byte[(id.length + 7) / 8];\n\n        for (int i = 0; i != id.length; i++)\n        {\n            bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;\n        }\n\n        int pad = id.length % 8;\n\n        if (pad == 0)\n        {\n            return new DERBitString(bytes);\n        }\n        else\n        {\n            return new DERBitString(bytes, 8 - pad);\n        }\n    }\n\n    static boolean[] bitStringToBoolean(DERBitString bitString)\n    {\n        if (bitString != null)\n        {\n            byte[]          bytes = bitString.getBytes();\n            boolean[]       boolId = new boolean[bytes.length * 8 - bitString.getPadBits()];\n\n            for (int i = 0; i != boolId.length; i++)\n            {\n                boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;\n            }\n\n            return boolId;\n        }\n\n        return null;\n    }\n\n    static Date recoverDate(ASN1GeneralizedTime time)\n    {\n        try\n        {\n            return time.getDate();\n        }\n        catch (ParseException e)\n        {\n            throw new IllegalStateException(\"unable to recover date: \" + e.getMessage());\n        }\n    }\n\n    static boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)\n    {\n        if (!id1.getAlgorithm().equals(id2.getAlgorithm()))\n        {\n            return false;\n        }\n\n        if (id1.getParameters() == null)\n        {\n            if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))\n            {\n                return false;\n            }\n\n            return true;\n        }\n\n        if (id2.getParameters() == null)\n        {\n            if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))\n            {\n                return false;\n            }\n\n            return true;\n        }\n\n        return id1.getParameters().equals(id2.getParameters());\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/X509AttributeCertificateHolder.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Set;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.ASN1Sequence;\nimport local.org.bouncycastle.asn1.DEROutputStream;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.asn1.x509.AttCertValidityPeriod;\nimport local.org.bouncycastle.asn1.x509.Attribute;\nimport local.org.bouncycastle.asn1.x509.AttributeCertificate;\nimport local.org.bouncycastle.asn1.x509.AttributeCertificateInfo;\nimport local.org.bouncycastle.asn1.x509.Extension;\nimport local.org.bouncycastle.asn1.x509.Extensions;\nimport local.org.bouncycastle.operator.ContentVerifier;\nimport local.org.bouncycastle.operator.ContentVerifierProvider;\n\n\n/**\n * Holding class for an X.509 AttributeCertificate structure.\n */\npublic class X509AttributeCertificateHolder\n{\n    private static Attribute[] EMPTY_ARRAY = new Attribute[0];\n    \n    private AttributeCertificate attrCert;\n    private Extensions extensions;\n\n    private static AttributeCertificate parseBytes(byte[] certEncoding)\n        throws IOException\n    {\n        try\n        {\n            return AttributeCertificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));\n        }\n        catch (ClassCastException e)\n        {\n            throw new CertIOException(\"malformed data: \" + e.getMessage(), e);\n        }\n        catch (IllegalArgumentException e)\n        {\n            throw new CertIOException(\"malformed data: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Create a X509AttributeCertificateHolder from the passed in bytes.\n     *\n     * @param certEncoding BER/DER encoding of the certificate.\n     * @throws IOException in the event of corrupted data, or an incorrect structure.\n     */\n    public X509AttributeCertificateHolder(byte[] certEncoding)\n        throws IOException\n    {\n        this(parseBytes(certEncoding));\n    }\n\n    /**\n     * Create a X509AttributeCertificateHolder from the passed in ASN.1 structure.\n     *\n     * @param attrCert an ASN.1 AttributeCertificate structure.\n     */\n    public X509AttributeCertificateHolder(AttributeCertificate attrCert)\n    {\n        this.attrCert = attrCert;\n        this.extensions = attrCert.getAcinfo().getExtensions();\n    }\n\n    /**\n     * Return the ASN.1 encoding of this holder's attribute certificate.\n     *\n     * @return a DER encoded byte array.\n     * @throws IOException if an encoding cannot be generated.\n     */\n    public byte[] getEncoded()\n        throws IOException\n    {\n        return attrCert.getEncoded();\n    }\n\n    public int getVersion()\n    {\n        return attrCert.getAcinfo().getVersion().getValue().intValue() + 1;\n    }\n\n    /**\n     * Return the serial number of this attribute certificate.\n     *\n     * @return the serial number.\n     */\n    public BigInteger getSerialNumber()\n    {\n        return attrCert.getAcinfo().getSerialNumber().getValue();\n    }\n\n    /**\n     * Return the holder details for this attribute certificate.\n     *\n     * @return this attribute certificate's holder structure.\n     */\n    public AttributeCertificateHolder getHolder()\n    {\n        return new AttributeCertificateHolder((ASN1Sequence)attrCert.getAcinfo().getHolder().toASN1Primitive());\n    }\n\n    /**\n     * Return the issuer details for this attribute certificate.\n     *\n     * @return this attribute certificate's issuer structure,\n     */\n    public AttributeCertificateIssuer getIssuer()\n    {\n        return new AttributeCertificateIssuer(attrCert.getAcinfo().getIssuer());\n    }\n\n    /**\n     * Return the date before which this attribute certificate is not valid.\n     *\n     * @return the start date for the attribute certificate's validity period.\n     */\n    public Date getNotBefore()\n    {\n        return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime());\n    }\n\n    /**\n     * Return the date after which this attribute certificate is not valid.\n     *\n     * @return the final date for the attribute certificate's validity period.\n     */\n    public Date getNotAfter()\n    {\n        return CertUtils.recoverDate(attrCert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime());\n    }\n\n    /**\n     * Return the attributes, if any associated with this request.\n     *\n     * @return an array of Attribute, zero length if none present.\n     */\n    public Attribute[] getAttributes()\n    {\n        ASN1Sequence seq = attrCert.getAcinfo().getAttributes();\n        Attribute[] attrs = new Attribute[seq.size()];\n\n        for (int i = 0; i != seq.size(); i++)\n        {\n            attrs[i] = Attribute.getInstance(seq.getObjectAt(i));\n        }\n\n        return attrs;\n    }\n\n    /**\n     * Return an  array of attributes matching the passed in type OID.\n     *\n     * @param type the type of the attribute being looked for.\n     * @return an array of Attribute of the requested type, zero length if none present.\n     */\n    public Attribute[] getAttributes(ASN1ObjectIdentifier type)\n    {\n        ASN1Sequence    seq = attrCert.getAcinfo().getAttributes();\n        List            list = new ArrayList();\n\n        for (int i = 0; i != seq.size(); i++)\n        {\n            Attribute attr = Attribute.getInstance(seq.getObjectAt(i));\n            if (attr.getAttrType().equals(type))\n            {\n                list.add(attr);\n            }\n        }\n\n        if (list.size() == 0)\n        {\n            return EMPTY_ARRAY;\n        }\n\n        return (Attribute[])list.toArray(new Attribute[list.size()]);\n    }\n\n    /**\n     * Return whether or not the holder's attribute certificate contains extensions.\n     *\n     * @return true if extension are present, false otherwise.\n     */\n    public boolean hasExtensions()\n    {\n        return extensions != null;\n    }\n\n    /**\n     * Look up the extension associated with the passed in OID.\n     *\n     * @param oid the OID of the extension of interest.\n     *\n     * @return the extension if present, null otherwise.\n     */\n    public Extension getExtension(ASN1ObjectIdentifier oid)\n    {\n        if (extensions != null)\n        {\n            return extensions.getExtension(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the extensions block associated with this certificate if there is one.\n     *\n     * @return the extensions block, null otherwise.\n     */\n    public Extensions getExtensions()\n    {\n        return extensions;\n    }\n\n    /**\n     * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the\n     * extensions contained in this holder's attribute certificate.\n     *\n     * @return a list of extension OIDs.\n     */\n    public List getExtensionOIDs()\n    {\n        return CertUtils.getExtensionOIDs(extensions);\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * critical extensions contained in this holder's attribute certificate.\n     *\n     * @return a set of critical extension OIDs.\n     */\n    public Set getCriticalExtensionOIDs()\n    {\n        return CertUtils.getCriticalExtensionOIDs(extensions);\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * non-critical extensions contained in this holder's attribute certificate.\n     *\n     * @return a set of non-critical extension OIDs.\n     */\n    public Set getNonCriticalExtensionOIDs()\n    {\n        return CertUtils.getNonCriticalExtensionOIDs(extensions);\n    }\n\n    public boolean[] getIssuerUniqueID()\n    {\n        return CertUtils.bitStringToBoolean(attrCert.getAcinfo().getIssuerUniqueID());\n    }\n\n    /**\n     * Return the details of the signature algorithm used to create this attribute certificate.\n     *\n     * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.\n     */\n    public AlgorithmIdentifier getSignatureAlgorithm()\n    {\n        return attrCert.getSignatureAlgorithm();\n    }\n\n    /**\n     * Return the bytes making up the signature associated with this attribute certificate.\n     *\n     * @return the attribute certificate signature bytes.\n     */\n    public byte[] getSignature()\n    {\n        return attrCert.getSignatureValue().getBytes();\n    }\n\n    /**\n     * Return the underlying ASN.1 structure for the attribute certificate in this holder.\n     *\n     * @return a AttributeCertificate object.\n     */\n    public AttributeCertificate toASN1Structure()\n    {\n        return attrCert;\n    }\n\n    /**\n     * Return whether or not this attribute certificate is valid on a particular date.\n     *\n     * @param date the date of interest.\n     * @return true if the attribute certificate is valid, false otherwise.\n     */\n    public boolean isValidOn(Date date)\n    {\n        AttCertValidityPeriod certValidityPeriod = attrCert.getAcinfo().getAttrCertValidityPeriod();\n\n        return !date.before(CertUtils.recoverDate(certValidityPeriod.getNotBeforeTime())) && !date.after(CertUtils.recoverDate(certValidityPeriod.getNotAfterTime()));\n    }\n\n    /**\n     * Validate the signature on the attribute certificate in this holder.\n     *\n     * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.\n     * @return true if the signature is valid, false otherwise.\n     * @throws CertException if the signature cannot be processed or is inappropriate.\n     */\n    public boolean isSignatureValid(ContentVerifierProvider verifierProvider)\n        throws CertException\n    {\n        AttributeCertificateInfo acinfo = attrCert.getAcinfo();\n\n        if (!CertUtils.isAlgIdEqual(acinfo.getSignature(), attrCert.getSignatureAlgorithm()))\n        {\n            throw new CertException(\"signature invalid - algorithm identifier mismatch\");\n        }\n\n        ContentVerifier verifier;\n\n        try\n        {\n            verifier = verifierProvider.get((acinfo.getSignature()));\n\n            OutputStream sOut = verifier.getOutputStream();\n            DEROutputStream dOut = new DEROutputStream(sOut);\n\n            dOut.writeObject(acinfo);\n\n            sOut.close();\n        }\n        catch (Exception e)\n        {\n            throw new CertException(\"unable to process signature: \" + e.getMessage(), e);\n        }\n\n        return verifier.verify(attrCert.getSignatureValue().getBytes());\n    }\n\n    public boolean equals(\n        Object o)\n    {\n        if (o == this)\n        {\n            return true;\n        }\n\n        if (!(o instanceof X509AttributeCertificateHolder))\n        {\n            return false;\n        }\n\n        X509AttributeCertificateHolder other = (X509AttributeCertificateHolder)o;\n\n        return this.attrCert.equals(other.attrCert);\n    }\n\n    public int hashCode()\n    {\n        return this.attrCert.hashCode();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/X509CRLEntryHolder.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.math.BigInteger;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Set;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x509.Extension;\nimport local.org.bouncycastle.asn1.x509.Extensions;\nimport local.org.bouncycastle.asn1.x509.GeneralNames;\nimport local.org.bouncycastle.asn1.x509.TBSCertList;\n\n\n/**\n * Holding class for an X.509 CRL Entry structure.\n */\npublic class X509CRLEntryHolder\n{\n    private TBSCertList.CRLEntry entry;\n    private GeneralNames ca;\n\n    X509CRLEntryHolder(TBSCertList.CRLEntry entry, boolean isIndirect, GeneralNames previousCA)\n    {\n        this.entry = entry;\n        this.ca = previousCA;\n\n        if (isIndirect && entry.hasExtensions())\n        {\n            Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);\n\n            if (currentCaName != null)\n            {\n                ca = GeneralNames.getInstance(currentCaName.getParsedValue());\n            }\n        }\n    }\n\n    /**\n     * Return the serial number of the certificate associated with this CRLEntry.\n     *\n     * @return the revoked certificate's serial number.\n     */\n    public BigInteger getSerialNumber()\n    {\n        return entry.getUserCertificate().getValue();\n    }\n\n    /**\n     * Return the date on which the certificate associated with this CRLEntry was revoked.\n     *\n     * @return the revocation date for the revoked certificate.\n     */\n    public Date getRevocationDate()\n    {\n        return entry.getRevocationDate().getDate();\n    }\n\n    /**\n     * Return whether or not the holder's CRL entry contains extensions.\n     *\n     * @return true if extension are present, false otherwise.\n     */\n    public boolean hasExtensions()\n    {\n        return entry.hasExtensions();\n    }\n\n    /**\n     * Return the available names for the certificate issuer for the certificate referred to by this CRL entry.\n     * <p>\n     * Note: this will be the issuer of the CRL unless it has been specified that the CRL is indirect\n     * in the IssuingDistributionPoint extension and either a previous entry, or the current one,\n     * has specified a different CA via the certificateIssuer extension.\n     * </p>\n     *\n     * @return the revoked certificate's issuer.\n     */\n    public GeneralNames getCertificateIssuer()\n    {\n        return this.ca;\n    }\n\n    /**\n     * Look up the extension associated with the passed in OID.\n     *\n     * @param oid the OID of the extension of interest.\n     *\n     * @return the extension if present, null otherwise.\n     */\n    public Extension getExtension(ASN1ObjectIdentifier oid)\n    {\n        Extensions extensions = entry.getExtensions();\n\n        if (extensions != null)\n        {\n            return extensions.getExtension(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the extensions block associated with this CRL entry if there is one.\n     *\n     * @return the extensions block, null otherwise.\n     */\n    public Extensions getExtensions()\n    {\n        return entry.getExtensions();\n    }\n\n    /**\n     * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the\n     * extensions contained in this holder's CRL entry.\n     *\n     * @return a list of extension OIDs.\n     */\n    public List getExtensionOIDs()\n    {\n        return CertUtils.getExtensionOIDs(entry.getExtensions());\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * critical extensions contained in this holder's CRL entry.\n     *\n     * @return a set of critical extension OIDs.\n     */\n    public Set getCriticalExtensionOIDs()\n    {\n        return CertUtils.getCriticalExtensionOIDs(entry.getExtensions());\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * non-critical extensions contained in this holder's CRL entry.\n     *\n     * @return a set of non-critical extension OIDs.\n     */\n    public Set getNonCriticalExtensionOIDs()\n    {\n        return CertUtils.getNonCriticalExtensionOIDs(entry.getExtensions());\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/X509CRLHolder.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Set;\n\nimport local.org.bouncycastle.asn1.ASN1InputStream;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.DEROutputStream;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.CertificateList;\nimport local.org.bouncycastle.asn1.x509.Extension;\nimport local.org.bouncycastle.asn1.x509.Extensions;\nimport local.org.bouncycastle.asn1.x509.GeneralName;\nimport local.org.bouncycastle.asn1.x509.GeneralNames;\nimport local.org.bouncycastle.asn1.x509.IssuingDistributionPoint;\nimport local.org.bouncycastle.asn1.x509.TBSCertList;\nimport local.org.bouncycastle.operator.ContentVerifier;\nimport local.org.bouncycastle.operator.ContentVerifierProvider;\n\n\n/**\n * Holding class for an X.509 CRL structure.\n */\npublic class X509CRLHolder\n{\n    private CertificateList x509CRL;\n    private boolean isIndirect;\n    private Extensions extensions;\n    private GeneralNames issuerName;\n\n    private static CertificateList parseStream(InputStream stream)\n        throws IOException\n    {\n        try\n        {\n            return CertificateList.getInstance(new ASN1InputStream(stream, true).readObject());\n        }\n        catch (ClassCastException e)\n        {\n            throw new CertIOException(\"malformed data: \" + e.getMessage(), e);\n        }\n        catch (IllegalArgumentException e)\n        {\n            throw new CertIOException(\"malformed data: \" + e.getMessage(), e);\n        }\n    }\n\n    private static boolean isIndirectCRL(Extensions extensions)\n    {\n        if (extensions == null)\n        {\n            return false;\n        }\n\n        Extension ext = extensions.getExtension(Extension.issuingDistributionPoint);\n\n        return ext != null && IssuingDistributionPoint.getInstance(ext.getParsedValue()).isIndirectCRL();\n    }\n\n    /**\n     * Create a X509CRLHolder from the passed in bytes.\n     *\n     * @param crlEncoding BER/DER encoding of the CRL\n     * @throws IOException in the event of corrupted data, or an incorrect structure.\n     */\n    public X509CRLHolder(byte[] crlEncoding)\n        throws IOException\n    {\n        this(parseStream(new ByteArrayInputStream(crlEncoding)));\n    }\n\n    /**\n     * Create a X509CRLHolder from the passed in InputStream.\n     *\n     * @param crlStream BER/DER encoded InputStream of the CRL\n     * @throws IOException in the event of corrupted data, or an incorrect structure.\n     */\n    public X509CRLHolder(InputStream crlStream)\n        throws IOException\n    {\n        this(parseStream(crlStream));\n    }\n\n    /**\n     * Create a X509CRLHolder from the passed in ASN.1 structure.\n     *\n     * @param x509CRL an ASN.1 CertificateList structure.\n     */\n    public X509CRLHolder(CertificateList x509CRL)\n    {\n        this.x509CRL = x509CRL;\n        this.extensions = x509CRL.getTBSCertList().getExtensions();\n        this.isIndirect = isIndirectCRL(extensions);\n        this.issuerName = new GeneralNames(new GeneralName(x509CRL.getIssuer()));\n    }\n\n    /**\n     * Return the ASN.1 encoding of this holder's CRL.\n     *\n     * @return a DER encoded byte array.\n     * @throws IOException if an encoding cannot be generated.\n     */\n    public byte[] getEncoded()\n        throws IOException\n    {\n        return x509CRL.getEncoded();\n    }\n\n    /**\n     * Return the issuer of this holder's CRL.\n     *\n     * @return the CRL issuer.\n     */\n    public X500Name getIssuer()\n    {\n        return X500Name.getInstance(x509CRL.getIssuer());\n    }\n\n    public X509CRLEntryHolder getRevokedCertificate(BigInteger serialNumber)\n    {\n        GeneralNames currentCA = issuerName;\n        for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();)\n        {\n            TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement();\n\n            if (entry.getUserCertificate().getValue().equals(serialNumber))\n            {\n                return new X509CRLEntryHolder(entry, isIndirect, currentCA);\n            }\n\n            if (isIndirect && entry.hasExtensions())\n            {\n                Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);\n\n                if (currentCaName != null)\n                {\n                    currentCA = GeneralNames.getInstance(currentCaName.getParsedValue());\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Return a collection of X509CRLEntryHolder objects, giving the details of the\n     * revoked certificates that appear on this CRL.\n     *\n     * @return the revoked certificates as a collection of X509CRLEntryHolder objects.\n     */\n    public Collection getRevokedCertificates()\n    {\n        TBSCertList.CRLEntry[] entries = x509CRL.getRevokedCertificates();\n        List l = new ArrayList(entries.length);\n        GeneralNames currentCA = issuerName;\n\n        for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();)\n        {\n            TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement();\n            X509CRLEntryHolder crlEntry = new X509CRLEntryHolder(entry, isIndirect, currentCA);\n\n            l.add(crlEntry);\n\n            currentCA = crlEntry.getCertificateIssuer();\n        }\n\n        return l;\n    }\n    \n    /**\n     * Return whether or not the holder's CRL contains extensions.\n     *\n     * @return true if extension are present, false otherwise.\n     */\n    public boolean hasExtensions()\n    {\n        return extensions != null;\n    }\n\n    /**\n     * Look up the extension associated with the passed in OID.\n     *\n     * @param oid the OID of the extension of interest.\n     *\n     * @return the extension if present, null otherwise.\n     */\n    public Extension getExtension(ASN1ObjectIdentifier oid)\n    {\n        if (extensions != null)\n        {\n            return extensions.getExtension(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the extensions block associated with this CRL if there is one.\n     *\n     * @return the extensions block, null otherwise.\n     */\n    public Extensions getExtensions()\n    {\n        return extensions;\n    }\n\n    /**\n     * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the\n     * extensions contained in this holder's CRL.\n     *\n     * @return a list of extension OIDs.\n     */\n    public List getExtensionOIDs()\n    {\n        return CertUtils.getExtensionOIDs(extensions);\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * critical extensions contained in this holder's CRL.\n     *\n     * @return a set of critical extension OIDs.\n     */\n    public Set getCriticalExtensionOIDs()\n    {\n        return CertUtils.getCriticalExtensionOIDs(extensions);\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * non-critical extensions contained in this holder's CRL.\n     *\n     * @return a set of non-critical extension OIDs.\n     */\n    public Set getNonCriticalExtensionOIDs()\n    {\n        return CertUtils.getNonCriticalExtensionOIDs(extensions);\n    }\n\n    /**\n     * Return the underlying ASN.1 structure for the CRL in this holder.\n     *\n     * @return a CertificateList object.\n     */\n    public CertificateList toASN1Structure()\n    {\n        return x509CRL;\n    }\n\n    /**\n     * Validate the signature on the CRL.\n     *\n     * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.\n     * @return true if the signature is valid, false otherwise.\n     * @throws CertException if the signature cannot be processed or is inappropriate.\n     */\n    public boolean isSignatureValid(ContentVerifierProvider verifierProvider)\n        throws CertException\n    {\n        TBSCertList tbsCRL = x509CRL.getTBSCertList();\n\n        if (!CertUtils.isAlgIdEqual(tbsCRL.getSignature(), x509CRL.getSignatureAlgorithm()))\n        {\n            throw new CertException(\"signature invalid - algorithm identifier mismatch\");\n        }\n\n        ContentVerifier verifier;\n\n        try\n        {\n            verifier = verifierProvider.get((tbsCRL.getSignature()));\n\n            OutputStream sOut = verifier.getOutputStream();\n            DEROutputStream dOut = new DEROutputStream(sOut);\n\n            dOut.writeObject(tbsCRL);\n\n            sOut.close();\n        }\n        catch (Exception e)\n        {\n            throw new CertException(\"unable to process signature: \" + e.getMessage(), e);\n        }\n\n        return verifier.verify(x509CRL.getSignature().getBytes());\n    }\n\n    public boolean equals(\n        Object o)\n    {\n        if (o == this)\n        {\n            return true;\n        }\n\n        if (!(o instanceof X509CRLHolder))\n        {\n            return false;\n        }\n\n        X509CRLHolder other = (X509CRLHolder)o;\n\n        return this.x509CRL.equals(other.x509CRL);\n    }\n\n    public int hashCode()\n    {\n        return this.x509CRL.hashCode();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/X509CertificateHolder.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Set;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.DEROutputStream;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.asn1.x509.Certificate;\nimport local.org.bouncycastle.asn1.x509.Extension;\nimport local.org.bouncycastle.asn1.x509.Extensions;\nimport local.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport local.org.bouncycastle.asn1.x509.TBSCertificate;\nimport local.org.bouncycastle.operator.ContentVerifier;\nimport local.org.bouncycastle.operator.ContentVerifierProvider;\n\n\n/**\n * Holding class for an X.509 Certificate structure.\n */\npublic class X509CertificateHolder\n{\n    private Certificate x509Certificate;\n    private Extensions  extensions;\n\n    private static Certificate parseBytes(byte[] certEncoding)\n        throws IOException\n    {\n        try\n        {\n            return Certificate.getInstance(ASN1Primitive.fromByteArray(certEncoding));\n        }\n        catch (ClassCastException e)\n        {\n            throw new CertIOException(\"malformed data: \" + e.getMessage(), e);\n        }\n        catch (IllegalArgumentException e)\n        {\n            throw new CertIOException(\"malformed data: \" + e.getMessage(), e);\n        }\n    }\n\n    /**\n     * Create a X509CertificateHolder from the passed in bytes.\n     *\n     * @param certEncoding BER/DER encoding of the certificate.\n     * @throws IOException in the event of corrupted data, or an incorrect structure.\n     */\n    public X509CertificateHolder(byte[] certEncoding)\n        throws IOException\n    {\n        this(parseBytes(certEncoding));\n    }\n\n    /**\n     * Create a X509CertificateHolder from the passed in ASN.1 structure.\n     *\n     * @param x509Certificate an ASN.1 Certificate structure.\n     */\n    public X509CertificateHolder(Certificate x509Certificate)\n    {\n        this.x509Certificate = x509Certificate;\n        this.extensions = x509Certificate.getTBSCertificate().getExtensions();\n    }\n\n    public int getVersionNumber()\n    {\n        return x509Certificate.getVersionNumber();\n    }\n\n    /**\n     * @deprecated use getVersionNumber\n     */\n    public int getVersion()\n    {\n        return x509Certificate.getVersionNumber();\n    }\n\n    /**\n     * Return whether or not the holder's certificate contains extensions.\n     *\n     * @return true if extension are present, false otherwise.\n     */\n    public boolean hasExtensions()\n    {\n        return extensions != null;\n    }\n\n    /**\n     * Look up the extension associated with the passed in OID.\n     *\n     * @param oid the OID of the extension of interest.\n     *\n     * @return the extension if present, null otherwise.\n     */\n    public Extension getExtension(ASN1ObjectIdentifier oid)\n    {\n        if (extensions != null)\n        {\n            return extensions.getExtension(oid);\n        }\n\n        return null;\n    }\n\n    /**\n     * Return the extensions block associated with this certificate if there is one.\n     *\n     * @return the extensions block, null otherwise.\n     */\n    public Extensions getExtensions()\n    {\n        return extensions;\n    }\n\n    /**\n     * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the\n     * extensions contained in this holder's certificate.\n     *\n     * @return a list of extension OIDs.\n     */\n    public List getExtensionOIDs()\n    {\n        return CertUtils.getExtensionOIDs(extensions);\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * critical extensions contained in this holder's certificate.\n     *\n     * @return a set of critical extension OIDs.\n     */\n    public Set getCriticalExtensionOIDs()\n    {\n        return CertUtils.getCriticalExtensionOIDs(extensions);\n    }\n\n    /**\n     * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the\n     * non-critical extensions contained in this holder's certificate.\n     *\n     * @return a set of non-critical extension OIDs.\n     */\n    public Set getNonCriticalExtensionOIDs()\n    {\n        return CertUtils.getNonCriticalExtensionOIDs(extensions);\n    }\n\n    /**\n     * Return the serial number of this attribute certificate.\n     *\n     * @return the serial number.\n     */\n    public BigInteger getSerialNumber()\n    {\n        return x509Certificate.getSerialNumber().getValue();\n    }\n\n    /**\n     * Return the issuer of this certificate.\n     *\n     * @return the certificate issuer.\n     */\n    public X500Name getIssuer()\n    {\n        return X500Name.getInstance(x509Certificate.getIssuer());\n    }\n\n    /**\n     * Return the subject this certificate is for.\n     *\n     * @return the subject for the certificate.\n     */\n    public X500Name getSubject()\n    {\n        return X500Name.getInstance(x509Certificate.getSubject());\n    }\n\n    /**\n     * Return the date before which this certificate is not valid.\n     *\n     * @return the start time for the certificate's validity period.\n     */\n    public Date getNotBefore()\n    {\n        return x509Certificate.getStartDate().getDate();\n    }\n\n    /**\n     * Return the date after which this certificate is not valid.\n     *\n     * @return the final time for the certificate's validity period.\n     */\n    public Date getNotAfter()\n    {\n        return x509Certificate.getEndDate().getDate();\n    }\n\n    /**\n     * Return the SubjectPublicKeyInfo describing the public key this certificate is carrying.\n     *\n     * @return the public key ASN.1 structure contained in the certificate.\n     */\n    public SubjectPublicKeyInfo getSubjectPublicKeyInfo()\n    {\n        return x509Certificate.getSubjectPublicKeyInfo();\n    }\n\n    /**\n     * Return the underlying ASN.1 structure for the certificate in this holder.\n     *\n     * @return a X509CertificateStructure object.\n     */\n    public Certificate toASN1Structure()\n    {\n        return x509Certificate;\n    }\n\n    /**\n     * Return the details of the signature algorithm used to create this attribute certificate.\n     *\n     * @return the AlgorithmIdentifier describing the signature algorithm used to create this attribute certificate.\n     */\n    public AlgorithmIdentifier getSignatureAlgorithm()\n    {\n        return x509Certificate.getSignatureAlgorithm();\n    }\n\n    /**\n     * Return the bytes making up the signature associated with this attribute certificate.\n     *\n     * @return the attribute certificate signature bytes.\n     */\n    public byte[] getSignature()\n    {\n        return x509Certificate.getSignature().getBytes();\n    }\n\n    /**\n     * Return whether or not this certificate is valid on a particular date.\n     *\n     * @param date the date of interest.\n     * @return true if the certificate is valid, false otherwise.\n     */\n    public boolean isValidOn(Date date)\n    {\n        return !date.before(x509Certificate.getStartDate().getDate()) && !date.after(x509Certificate.getEndDate().getDate());\n    }\n\n    /**\n     * Validate the signature on the certificate in this holder.\n     *\n     * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.\n     * @return true if the signature is valid, false otherwise.\n     * @throws CertException if the signature cannot be processed or is inappropriate.\n     */\n    public boolean isSignatureValid(ContentVerifierProvider verifierProvider)\n        throws CertException\n    {\n        TBSCertificate tbsCert = x509Certificate.getTBSCertificate();\n\n        if (!CertUtils.isAlgIdEqual(tbsCert.getSignature(), x509Certificate.getSignatureAlgorithm()))\n        {\n            throw new CertException(\"signature invalid - algorithm identifier mismatch\");\n        }\n\n        ContentVerifier verifier;\n\n        try\n        {\n            verifier = verifierProvider.get((tbsCert.getSignature()));\n\n            OutputStream sOut = verifier.getOutputStream();\n            DEROutputStream dOut = new DEROutputStream(sOut);\n\n            dOut.writeObject(tbsCert);\n\n            sOut.close();\n        }\n        catch (Exception e)\n        {\n            throw new CertException(\"unable to process signature: \" + e.getMessage(), e);\n        }\n\n        return verifier.verify(x509Certificate.getSignature().getBytes());\n    }\n\n    public boolean equals(\n        Object o)\n    {\n        if (o == this)\n        {\n            return true;\n        }\n\n        if (!(o instanceof X509CertificateHolder))\n        {\n            return false;\n        }\n\n        X509CertificateHolder other = (X509CertificateHolder)o;\n\n        return this.x509Certificate.equals(other.x509Certificate);\n    }\n\n    public int hashCode()\n    {\n        return this.x509Certificate.hashCode();\n    }\n\n    /**\n     * Return the ASN.1 encoding of this holder's certificate.\n     *\n     * @return a DER encoded byte array.\n     * @throws IOException if an encoding cannot be generated.\n     */\n    public byte[] getEncoded()\n        throws IOException\n    {\n        return x509Certificate.getEncoded();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/X509ExtensionUtils.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;\nimport local.org.bouncycastle.asn1.x509.Extension;\nimport local.org.bouncycastle.asn1.x509.GeneralName;\nimport local.org.bouncycastle.asn1.x509.GeneralNames;\nimport local.org.bouncycastle.asn1.x509.SubjectKeyIdentifier;\nimport local.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport local.org.bouncycastle.operator.DigestCalculator;\n\n\n/**\n * General utility class for creating calculated extensions using the standard methods.\n * <p>\n * <b>Note:</b> This class is not thread safe!\n * </p>\n */\npublic class X509ExtensionUtils\n{\n    private DigestCalculator calculator;\n\n    public X509ExtensionUtils(DigestCalculator calculator)\n    {\n        this.calculator = calculator;\n    }\n\n    public AuthorityKeyIdentifier createAuthorityKeyIdentifier(\n        X509CertificateHolder certHolder)\n    {\n        if (certHolder.getVersionNumber() != 3)\n        {\n            GeneralName genName = new GeneralName(certHolder.getIssuer());\n            SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo();\n\n            return new AuthorityKeyIdentifier(\n                           calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber());\n        }\n        else\n        {\n            GeneralName             genName = new GeneralName(certHolder.getIssuer());\n            Extension ext = certHolder.getExtension(Extension.subjectKeyIdentifier);\n\n            if (ext != null)\n            {\n                ASN1OctetString str = ASN1OctetString.getInstance(ext.getParsedValue());\n\n                return new AuthorityKeyIdentifier(\n                                str.getOctets(), new GeneralNames(genName), certHolder.getSerialNumber());\n            }\n            else\n            {\n                SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo();\n\n                return new AuthorityKeyIdentifier(\n                        calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber());\n            }\n        }\n    }\n\n    public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo)\n    {\n        return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo));\n    }\n\n    /**\n     * Return a RFC 3280 type 1 key identifier. As in:\n     * <pre>\n     * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the\n     * value of the BIT STRING subjectPublicKey (excluding the tag,\n     * length, and number of unused bits).\n     * </pre>\n     * @param publicKeyInfo the key info object containing the subjectPublicKey field.\n     * @return the key identifier.\n     */\n    public SubjectKeyIdentifier createSubjectKeyIdentifier(\n        SubjectPublicKeyInfo publicKeyInfo)\n    {\n        return new SubjectKeyIdentifier(calculateIdentifier(publicKeyInfo));\n    }\n\n    /**\n     * Return a RFC 3280 type 2 key identifier. As in:\n     * <pre>\n     * (2) The keyIdentifier is composed of a four bit type field with\n     * the value 0100 followed by the least significant 60 bits of the\n     * SHA-1 hash of the value of the BIT STRING subjectPublicKey.\n     * </pre>\n     * @param publicKeyInfo the key info object containing the subjectPublicKey field.\n     * @return the key identifier.\n     */\n    public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo)\n    {\n        byte[] digest = calculateIdentifier(publicKeyInfo);\n        byte[] id = new byte[8];\n\n        System.arraycopy(digest, digest.length - 8, id, 0, id.length);\n\n        id[0] &= 0x0f;\n        id[0] |= 0x40;\n\n        return new SubjectKeyIdentifier(id);\n    }\n\n    private byte[] calculateIdentifier(SubjectPublicKeyInfo publicKeyInfo)\n    {\n        byte[] bytes = publicKeyInfo.getPublicKeyData().getBytes();\n\n        OutputStream cOut = calculator.getOutputStream();\n\n        try\n        {\n            cOut.write(bytes);\n\n            cOut.close();\n        }\n        catch (IOException e)\n        {   // it's hard to imagine this happening, but yes it does!\n            throw new CertRuntimeException(\"unable to calculate identifier: \" + e.getMessage(), e);\n        }\n\n        return calculator.getDigest();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/X509v3CertificateBuilder.java",
    "content": "package local.org.bouncycastle.cert;\n\nimport java.math.BigInteger;\nimport java.util.Date;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.Certificate;\nimport local.org.bouncycastle.asn1.x509.Extension;\nimport local.org.bouncycastle.asn1.x509.ExtensionsGenerator;\nimport local.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport local.org.bouncycastle.asn1.x509.Time;\nimport local.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;\nimport local.org.bouncycastle.operator.ContentSigner;\n\n\n\n/**\n * class to produce an X.509 Version 3 certificate.\n */\npublic class X509v3CertificateBuilder\n{\n    private V3TBSCertificateGenerator   tbsGen;\n    private ExtensionsGenerator extGenerator;\n\n    /**\n     * Create a builder for a version 3 certificate.\n     *\n     * @param issuer the certificate issuer\n     * @param serial the certificate serial number\n     * @param notBefore the date before which the certificate is not valid\n     * @param notAfter the date after which the certificate is not valid\n     * @param subject the certificate subject\n     * @param publicKeyInfo the info structure for the public key to be associated with this certificate.\n     */\n    public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)\n    {\n        tbsGen = new V3TBSCertificateGenerator();\n        tbsGen.setSerialNumber(new ASN1Integer(serial));\n        tbsGen.setIssuer(issuer);\n        tbsGen.setStartDate(new Time(notBefore));\n        tbsGen.setEndDate(new Time(notAfter));\n        tbsGen.setSubject(subject);\n        tbsGen.setSubjectPublicKeyInfo(publicKeyInfo);\n\n        extGenerator = new ExtensionsGenerator();\n    }\n\n    /**\n     * Set the subjectUniqueID - note: it is very rare that it is correct to do this.\n     *\n     * @param uniqueID a boolean array representing the bits making up the subjectUniqueID.\n     * @return this builder object.\n     */\n    public X509v3CertificateBuilder setSubjectUniqueID(boolean[] uniqueID)\n    {\n        tbsGen.setSubjectUniqueID(CertUtils.booleanToBitString(uniqueID));\n\n        return this;\n    }\n\n    /**\n     * Set the issuerUniqueID - note: it is very rare that it is correct to do this.\n     *\n     * @param uniqueID a boolean array representing the bits making up the issuerUniqueID.\n     * @return this builder object.\n     */\n    public X509v3CertificateBuilder setIssuerUniqueID(boolean[] uniqueID)\n    {\n        tbsGen.setIssuerUniqueID(CertUtils.booleanToBitString(uniqueID));\n\n        return this;\n    }\n\n    /**\n     * Add a given extension field for the standard extensions tag (tag 3)\n     *\n     * @param oid the OID defining the extension type.\n     * @param isCritical true if the extension is critical, false otherwise.\n     * @param value the ASN.1 structure that forms the extension's value.\n     * @return this builder object.\n     */\n    public X509v3CertificateBuilder addExtension(\n        ASN1ObjectIdentifier oid,\n        boolean isCritical,\n        ASN1Encodable value)\n        throws CertIOException\n    {\n        CertUtils.addExtension(extGenerator, oid, isCritical, value);\n\n        return this;\n    }\n\n    /**\n     * Add a given extension field for the standard extensions tag (tag 3)\n     * copying the extension value from another certificate.\n     *\n     * @param oid the OID defining the extension type.\n     * @param isCritical true if the copied extension is to be marked as critical, false otherwise.\n     * @param certHolder the holder for the certificate that the extension is to be copied from.\n     * @return this builder object.\n     */\n    public X509v3CertificateBuilder copyAndAddExtension(\n        ASN1ObjectIdentifier oid,\n        boolean isCritical,\n        X509CertificateHolder certHolder)\n    {\n        Certificate cert = certHolder.toASN1Structure();\n\n        Extension extension = cert.getTBSCertificate().getExtensions().getExtension(oid);\n\n        if (extension == null)\n        {\n            throw new NullPointerException(\"extension \" + oid + \" not present\");\n        }\n\n        extGenerator.addExtension(oid, isCritical, extension.getExtnValue().getOctets());\n\n        return this;\n    }\n\n    /**\n     * Generate an X.509 certificate, based on the current issuer and subject\n     * using the passed in signer.\n     *\n     * @param signer the content signer to be used to generate the signature validating the certificate.\n     * @return a holder containing the resulting signed certificate.\n     */\n    public X509CertificateHolder build(\n        ContentSigner signer)\n    {\n        tbsGen.setSignature(signer.getAlgorithmIdentifier());\n\n        if (!extGenerator.isEmpty())\n        {\n            tbsGen.setExtensions(extGenerator.generate());\n        }\n\n        return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate());\n    }\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/CertHelper.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.security.NoSuchProviderException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\n\nabstract class CertHelper\n{\n    public CertificateFactory getCertificateFactory(String type)\n        throws NoSuchProviderException, CertificateException\n    {\n        return createCertificateFactory(type);\n    }\n\n    protected abstract CertificateFactory createCertificateFactory(String type)\n        throws CertificateException, NoSuchProviderException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/DefaultCertHelper.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\n\nclass DefaultCertHelper\n    extends CertHelper\n{\n    protected CertificateFactory createCertificateFactory(String type)\n        throws CertificateException\n    {\n        return CertificateFactory.getInstance(type);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/JcaX509CertificateConverter.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.security.NoSuchProviderException;\nimport java.security.Provider;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.CertificateParsingException;\nimport java.security.cert.X509Certificate;\n\nimport local.org.bouncycastle.cert.X509CertificateHolder;\n\n\n/**\n * Converter for producing X509Certificate objects tied to a specific provider from X509CertificateHolder objects.\n */\npublic class JcaX509CertificateConverter\n{\n    private CertHelper helper = new DefaultCertHelper();\n\n    /**\n     * Base constructor, configure with the default provider.\n     */\n    public JcaX509CertificateConverter()\n    {\n        this.helper = new DefaultCertHelper();\n    }\n\n    /**\n     * Set the provider to use from a Provider object.\n     *\n     * @param provider the provider to use.\n     * @return the converter instance.\n     */\n    public JcaX509CertificateConverter setProvider(Provider provider)\n    {\n        this.helper = new ProviderCertHelper(provider);\n\n        return this;\n    }\n\n    /**\n     * Set the provider to use by name.\n     *\n     * @param providerName name of the provider to use.\n     * @return the converter instance.\n     */\n    public JcaX509CertificateConverter setProvider(String providerName)\n    {\n        this.helper = new NamedCertHelper(providerName);\n\n        return this;\n    }\n\n    /**\n     * Use the configured converter to produce a X509Certificate object from a X509CertificateHolder object.\n     *\n     * @param certHolder  the holder to be converted\n     * @return a X509Certificate object\n     * @throws CertificateException if the conversion is unable to be made.\n     */\n    public X509Certificate getCertificate(X509CertificateHolder certHolder)\n        throws CertificateException\n    {\n        try\n        {\n            CertificateFactory cFact = helper.getCertificateFactory(\"X.509\");\n\n            return (X509Certificate)cFact.generateCertificate(new ByteArrayInputStream(certHolder.getEncoded()));\n        }\n        catch (IOException e)\n        {\n            throw new ExCertificateParsingException(\"exception parsing certificate: \" + e.getMessage(), e);\n        }\n        catch (NoSuchProviderException e)\n        {\n            throw new ExCertificateException(\"cannot find required provider:\" + e.getMessage(), e);\n        }\n    }\n\n    private class ExCertificateParsingException\n        extends CertificateParsingException\n    {\n        private Throwable cause;\n\n        public ExCertificateParsingException(String msg, Throwable cause)\n        {\n            super(msg);\n\n            this.cause = cause;\n        }\n\n        public Throwable getCause()\n        {\n            return cause;\n        }\n    }\n    \n    private class ExCertificateException\n        extends CertificateException\n    {\n        private Throwable cause;\n\n        public ExCertificateException(String msg, Throwable cause)\n        {\n            super(msg);\n\n            this.cause = cause;\n        }\n\n        public Throwable getCause()\n        {\n            return cause;\n        }\n    }\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/JcaX509CertificateHolder.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\n\nimport local.org.bouncycastle.asn1.x509.Certificate;\nimport local.org.bouncycastle.cert.X509CertificateHolder;\n\n\n/**\n * JCA helper class for converting an X509Certificate into a X509CertificateHolder object.\n */\npublic class JcaX509CertificateHolder\n    extends X509CertificateHolder\n{\n    /**\n     * Base constructor.\n     *\n     * @param cert certificate to be used a the source for the holder creation.\n     * @throws CertificateEncodingException if there is a problem extracting the certificate information.\n     */\n    public JcaX509CertificateHolder(X509Certificate cert)\n        throws CertificateEncodingException\n    {\n        super(Certificate.getInstance(cert.getEncoded()));\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/JcaX509ExtensionUtils.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PublicKey;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\n\nimport local.org.bouncycastle.asn1.ASN1OctetString;\nimport local.org.bouncycastle.asn1.ASN1Primitive;\nimport local.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;\nimport local.org.bouncycastle.asn1.x509.SubjectKeyIdentifier;\nimport local.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport local.org.bouncycastle.cert.X509ExtensionUtils;\nimport local.org.bouncycastle.operator.DigestCalculator;\n\n\npublic class JcaX509ExtensionUtils\n    extends X509ExtensionUtils\n{\n    /**\n     * Create a utility class pre-configured with a SHA-1 digest calculator based on the\n     * default implementation.\n     *\n     * @throws NoSuchAlgorithmException\n     */\n    public JcaX509ExtensionUtils()\n        throws NoSuchAlgorithmException\n    {\n        super(new SHA1DigestCalculator(MessageDigest.getInstance(\"SHA1\")));\n    }\n\n    public JcaX509ExtensionUtils(DigestCalculator calculator)\n    {\n        super(calculator);\n    }\n\n    public AuthorityKeyIdentifier createAuthorityKeyIdentifier(\n        X509Certificate cert)\n        throws CertificateEncodingException\n    {\n        return super.createAuthorityKeyIdentifier(new JcaX509CertificateHolder(cert));\n    }\n\n    public AuthorityKeyIdentifier createAuthorityKeyIdentifier(\n        PublicKey pubKey)\n    {\n        return super.createAuthorityKeyIdentifier(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()));\n    }\n\n    /**\n     * Return a RFC 3280 type 1 key identifier. As in:\n     * <pre>\n     * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the\n     * value of the BIT STRING subjectPublicKey (excluding the tag,\n     * length, and number of unused bits).\n     * </pre>\n     * @param publicKey the key object containing the key identifier is to be based on.\n     * @return the key identifier.\n     */\n    public SubjectKeyIdentifier createSubjectKeyIdentifier(\n        PublicKey publicKey)\n    {\n        return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));\n    }\n\n    /**\n     * Return a RFC 3280 type 2 key identifier. As in:\n     * <pre>\n     * (2) The keyIdentifier is composed of a four bit type field with\n     * the value 0100 followed by the least significant 60 bits of the\n     * SHA-1 hash of the value of the BIT STRING subjectPublicKey.\n     * </pre>\n     * @param publicKey the key object of interest.\n     * @return the key identifier.\n     */\n    public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(PublicKey publicKey)\n    {\n       return super.createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));\n    }\n\n    /**\n     * Return the ASN.1 object contained in a byte[] returned by a getExtensionValue() call.\n     *\n     * @param encExtValue DER encoded OCTET STRING containing the DER encoded extension object.\n     * @return an ASN.1 object\n     * @throws java.io.IOException on a parsing error.\n     */\n    public static ASN1Primitive parseExtensionValue(byte[] encExtValue)\n        throws IOException\n    {\n        return ASN1Primitive.fromByteArray(ASN1OctetString.getInstance(encExtValue).getOctets());\n    }\n\n    private static class SHA1DigestCalculator\n        implements DigestCalculator\n    {\n        private ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n        private MessageDigest digest;\n\n        public SHA1DigestCalculator(MessageDigest digest)\n        {\n            this.digest = digest;\n        }\n\n        public AlgorithmIdentifier getAlgorithmIdentifier()\n        {\n            return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1);\n        }\n\n        public OutputStream getOutputStream()\n        {\n            return bOut;\n        }\n\n        public byte[] getDigest()\n        {\n            byte[] bytes = digest.digest(bOut.toByteArray());\n\n            bOut.reset();\n\n            return bytes;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.math.BigInteger;\nimport java.security.PublicKey;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.Date;\n\nimport javax.security.auth.x500.X500Principal;\n\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.x500.X500Name;\nimport local.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport local.org.bouncycastle.cert.X509v3CertificateBuilder;\n\n\n/**\n * JCA helper class to allow JCA objects to be used in the construction of a Version 3 certificate.\n */\npublic class JcaX509v3CertificateBuilder\n    extends X509v3CertificateBuilder\n{\n    /**\n     * Initialise the builder using a PublicKey.\n     *\n     * @param issuer X500Name representing the issuer of this certificate.\n     * @param serial the serial number for the certificate.\n     * @param notBefore date before which the certificate is not valid.\n     * @param notAfter date after which the certificate is not valid.\n     * @param subject X500Name representing the subject of this certificate.\n     * @param publicKey the public key to be associated with the certificate.\n     */\n    public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)\n    {\n        super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));\n    }\n\n    /**\n     * Initialise the builder using X500Principal objects and a PublicKey.\n     *\n     * @param issuer principal representing the issuer of this certificate.\n     * @param serial the serial number for the certificate.\n     * @param notBefore date before which the certificate is not valid.\n     * @param notAfter date after which the certificate is not valid.\n     * @param subject principal representing the subject of this certificate.\n     * @param publicKey the public key to be associated with the certificate.\n     */\n    public JcaX509v3CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey)\n    {\n        super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()));\n    }\n\n    /**\n     * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as\n     * passing through and converting the other objects provided.\n     *\n     * @param issuerCert certificate who's subject is the issuer of the certificate we are building.\n     * @param serial the serial number for the certificate.\n     * @param notBefore date before which the certificate is not valid.\n     * @param notAfter date after which the certificate is not valid.\n     * @param subject principal representing the subject of this certificate.\n     * @param publicKey the public key to be associated with the certificate.\n     */\n    public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey)\n    {\n        this(issuerCert.getSubjectX500Principal(), serial, notBefore, notAfter, subject, publicKey);\n    }\n\n    /**\n     * Initialise the builder using the subject from the passed in issuerCert as the issuer, as well as\n     * passing through and converting the other objects provided.\n     *\n     * @param issuerCert certificate who's subject is the issuer of the certificate we are building.\n     * @param serial the serial number for the certificate.\n     * @param notBefore date before which the certificate is not valid.\n     * @param notAfter date after which the certificate is not valid.\n     * @param subject principal representing the subject of this certificate.\n     * @param publicKey the public key to be associated with the certificate.\n     */\n    public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey)\n    {\n        this(X500Name.getInstance(issuerCert.getSubjectX500Principal().getEncoded()), serial, notBefore, notAfter, subject, publicKey);\n    }\n\n    /**\n     * Add a given extension field for the standard extensions tag (tag 3)\n     * copying the extension value from another certificate.\n     *\n     * @param oid the type of the extension to be copied.\n     * @param critical true if the extension is to be marked critical, false otherwise.\n     * @param certificate the source of the extension to be copied.\n     * @return the builder instance.\n     */\n    public JcaX509v3CertificateBuilder copyAndAddExtension(\n        ASN1ObjectIdentifier oid,\n        boolean critical,\n        X509Certificate certificate)\n        throws CertificateEncodingException\n    {\n        this.copyAndAddExtension(oid, critical, new JcaX509CertificateHolder(certificate));\n\n        return this;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/NamedCertHelper.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.security.NoSuchProviderException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\n\nclass NamedCertHelper\n    extends CertHelper\n{\n    private final String providerName;\n\n    NamedCertHelper(String providerName)\n    {\n        this.providerName = providerName;\n    }\n\n    protected CertificateFactory createCertificateFactory(String type)\n        throws CertificateException, NoSuchProviderException\n    {\n        return CertificateFactory.getInstance(type, providerName);\n    }\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/cert/jcajce/ProviderCertHelper.java",
    "content": "package local.org.bouncycastle.cert.jcajce;\n\nimport java.security.Provider;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\n\nclass ProviderCertHelper\n    extends CertHelper\n{\n    private final Provider provider;\n\n    ProviderCertHelper(Provider provider)\n    {\n        this.provider = provider;\n    }\n\n    protected CertificateFactory createCertificateFactory(String type)\n        throws CertificateException\n    {\n        return CertificateFactory.getInstance(type, provider);\n    }\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/CipherParameters.java",
    "content": "package local.org.bouncycastle.crypto;\n\n/**\n * all parameter classes implement this.\n */\npublic interface CipherParameters\n{\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/Digest.java",
    "content": "package local.org.bouncycastle.crypto;\n\n/**\n * interface that a message digest conforms to.\n */\npublic interface Digest\n{\n    /**\n     * return the algorithm name\n     *\n     * @return the algorithm name\n     */\n    public String getAlgorithmName();\n\n    /**\n     * return the size, in bytes, of the digest produced by this message digest.\n     *\n     * @return the size, in bytes, of the digest produced by this message digest.\n     */\n    public int getDigestSize();\n\n    /**\n     * update the message digest with a single byte.\n     *\n     * @param in the input byte to be entered.\n     */\n    public void update(byte in);\n\n    /**\n     * update the message digest with a block of bytes.\n     *\n     * @param in the byte array containing the data.\n     * @param inOff the offset into the byte array where the data starts.\n     * @param len the length of the data.\n     */\n    public void update(byte[] in, int inOff, int len);\n\n    /**\n     * close the digest, producing the final digest value. The doFinal\n     * call leaves the digest reset.\n     *\n     * @param out the array the digest is to be copied into.\n     * @param outOff the offset into the out array the digest is to start at.\n     */\n    public int doFinal(byte[] out, int outOff);\n\n    /**\n     * reset the digest back to it's initial state.\n     */\n    public void reset();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/ExtendedDigest.java",
    "content": "package local.org.bouncycastle.crypto;\n\npublic interface ExtendedDigest \n    extends Digest\n{\n    /**\n     * Return the size in bytes of the internal buffer the digest applies it's compression\n     * function to.\n     * \n     * @return byte length of the digests internal buffer.\n     */\n    public int getByteLength();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/digests/GeneralDigest.java",
    "content": "package local.org.bouncycastle.crypto.digests;\n\nimport local.org.bouncycastle.crypto.ExtendedDigest;\nimport local.org.bouncycastle.util.Memoable;\n\n/**\n * base implementation of MD4 family style digest as outlined in\n * \"Handbook of Applied Cryptography\", pages 344 - 347.\n */\npublic abstract class GeneralDigest\n    implements ExtendedDigest, Memoable\n{\n    private static final int BYTE_LENGTH = 64;\n    private byte[]  xBuf;\n    private int     xBufOff;\n\n    private long    byteCount;\n\n    /**\n     * Standard constructor\n     */\n    protected GeneralDigest()\n    {\n        xBuf = new byte[4];\n        xBufOff = 0;\n    }\n\n    /**\n     * Copy constructor.  We are using copy constructors in place\n     * of the Object.clone() interface as this interface is not\n     * supported by J2ME.\n     */\n    protected GeneralDigest(GeneralDigest t)\n    {\n        xBuf = new byte[t.xBuf.length];\n\n        copyIn(t);\n    }\n\n    protected void copyIn(GeneralDigest t)\n    {\n        System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);\n\n        xBufOff = t.xBufOff;\n        byteCount = t.byteCount;\n    }\n\n    public void update(\n        byte in)\n    {\n        xBuf[xBufOff++] = in;\n\n        if (xBufOff == xBuf.length)\n        {\n            processWord(xBuf, 0);\n            xBufOff = 0;\n        }\n\n        byteCount++;\n    }\n\n    public void update(\n        byte[]  in,\n        int     inOff,\n        int     len)\n    {\n        //\n        // fill the current word\n        //\n        while ((xBufOff != 0) && (len > 0))\n        {\n            update(in[inOff]);\n\n            inOff++;\n            len--;\n        }\n\n        //\n        // process whole words.\n        //\n        while (len > xBuf.length)\n        {\n            processWord(in, inOff);\n\n            inOff += xBuf.length;\n            len -= xBuf.length;\n            byteCount += xBuf.length;\n        }\n\n        //\n        // load in the remainder.\n        //\n        while (len > 0)\n        {\n            update(in[inOff]);\n\n            inOff++;\n            len--;\n        }\n    }\n\n    public void finish()\n    {\n        long    bitLength = (byteCount << 3);\n\n        //\n        // add the pad bytes.\n        //\n        update((byte)128);\n\n        while (xBufOff != 0)\n        {\n            update((byte)0);\n        }\n\n        processLength(bitLength);\n\n        processBlock();\n    }\n\n    public void reset()\n    {\n        byteCount = 0;\n\n        xBufOff = 0;\n        for (int i = 0; i < xBuf.length; i++)\n        {\n            xBuf[i] = 0;\n        }\n    }\n\n    public int getByteLength()\n    {\n        return BYTE_LENGTH;\n    }\n    \n    protected abstract void processWord(byte[] in, int inOff);\n\n    protected abstract void processLength(long bitLength);\n\n    protected abstract void processBlock();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/digests/SHA1Digest.java",
    "content": "package local.org.bouncycastle.crypto.digests;\n\nimport local.org.bouncycastle.crypto.util.Pack;\nimport local.org.bouncycastle.util.Memoable;\n\n/**\n * implementation of SHA-1 as outlined in \"Handbook of Applied Cryptography\", pages 346 - 349.\n *\n * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5\n * is the \"endianness\" of the word processing!\n */\npublic class SHA1Digest\n    extends GeneralDigest\n{\n    private static final int    DIGEST_LENGTH = 20;\n\n    private int     H1, H2, H3, H4, H5;\n\n    private int[]   X = new int[80];\n    private int     xOff;\n\n    /**\n     * Standard constructor\n     */\n    public SHA1Digest()\n    {\n        reset();\n    }\n\n    /**\n     * Copy constructor.  This will copy the state of the provided\n     * message digest.\n     */\n    public SHA1Digest(SHA1Digest t)\n    {\n        super(t);\n\n        copyIn(t);\n    }\n\n    private void copyIn(SHA1Digest t)\n    {\n        H1 = t.H1;\n        H2 = t.H2;\n        H3 = t.H3;\n        H4 = t.H4;\n        H5 = t.H5;\n\n        System.arraycopy(t.X, 0, X, 0, t.X.length);\n        xOff = t.xOff;\n    }\n\n    public String getAlgorithmName()\n    {\n        return \"SHA-1\";\n    }\n\n    public int getDigestSize()\n    {\n        return DIGEST_LENGTH;\n    }\n\n    protected void processWord(\n        byte[]  in,\n        int     inOff)\n    {\n        // Note: Inlined for performance\n//        X[xOff] = Pack.bigEndianToInt(in, inOff);\n        int n = in[  inOff] << 24;\n        n |= (in[++inOff] & 0xff) << 16;\n        n |= (in[++inOff] & 0xff) << 8;\n        n |= (in[++inOff] & 0xff);\n        X[xOff] = n;\n\n        if (++xOff == 16)\n        {\n            processBlock();\n        }        \n    }\n\n    protected void processLength(\n        long    bitLength)\n    {\n        if (xOff > 14)\n        {\n            processBlock();\n        }\n\n        X[14] = (int)(bitLength >>> 32);\n        X[15] = (int)(bitLength & 0xffffffff);\n    }\n\n    public int doFinal(\n        byte[]  out,\n        int     outOff)\n    {\n        finish();\n\n        Pack.intToBigEndian(H1, out, outOff);\n        Pack.intToBigEndian(H2, out, outOff + 4);\n        Pack.intToBigEndian(H3, out, outOff + 8);\n        Pack.intToBigEndian(H4, out, outOff + 12);\n        Pack.intToBigEndian(H5, out, outOff + 16);\n\n        reset();\n\n        return DIGEST_LENGTH;\n    }\n\n    /**\n     * reset the chaining variables\n     */\n    public void reset()\n    {\n        super.reset();\n\n        H1 = 0x67452301;\n        H2 = 0xefcdab89;\n        H3 = 0x98badcfe;\n        H4 = 0x10325476;\n        H5 = 0xc3d2e1f0;\n\n        xOff = 0;\n        for (int i = 0; i != X.length; i++)\n        {\n            X[i] = 0;\n        }\n    }\n\n    //\n    // Additive constants\n    //\n    private static final int    Y1 = 0x5a827999;\n    private static final int    Y2 = 0x6ed9eba1;\n    private static final int    Y3 = 0x8f1bbcdc;\n    private static final int    Y4 = 0xca62c1d6;\n   \n    private int f(\n        int    u,\n        int    v,\n        int    w)\n    {\n        return ((u & v) | ((~u) & w));\n    }\n\n    private int h(\n        int    u,\n        int    v,\n        int    w)\n    {\n        return (u ^ v ^ w);\n    }\n\n    private int g(\n        int    u,\n        int    v,\n        int    w)\n    {\n        return ((u & v) | (u & w) | (v & w));\n    }\n\n    protected void processBlock()\n    {\n        //\n        // expand 16 word block into 80 word block.\n        //\n        for (int i = 16; i < 80; i++)\n        {\n            int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];\n            X[i] = t << 1 | t >>> 31;\n        }\n\n        //\n        // set up working variables.\n        //\n        int     A = H1;\n        int     B = H2;\n        int     C = H3;\n        int     D = H4;\n        int     E = H5;\n\n        //\n        // round 1\n        //\n        int idx = 0;\n        \n        for (int j = 0; j < 4; j++)\n        {\n            // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1\n            // B = rotateLeft(B, 30)\n            E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;\n            B = B << 30 | B >>> 2;\n        \n            D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;\n            A = A << 30 | A >>> 2;\n       \n            C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;\n            E = E << 30 | E >>> 2;\n       \n            B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;\n            D = D << 30 | D >>> 2;\n\n            A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;\n            C = C << 30 | C >>> 2;\n        }\n        \n        //\n        // round 2\n        //\n        for (int j = 0; j < 4; j++)\n        {\n            // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2\n            // B = rotateLeft(B, 30)\n            E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;\n            B = B << 30 | B >>> 2;   \n            \n            D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;\n            A = A << 30 | A >>> 2;\n            \n            C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;\n            E = E << 30 | E >>> 2;\n            \n            B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;\n            D = D << 30 | D >>> 2;\n\n            A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;\n            C = C << 30 | C >>> 2;\n        }\n        \n        //\n        // round 3\n        //\n        for (int j = 0; j < 4; j++)\n        {\n            // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3\n            // B = rotateLeft(B, 30)\n            E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;\n            B = B << 30 | B >>> 2;\n            \n            D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;\n            A = A << 30 | A >>> 2;\n            \n            C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;\n            E = E << 30 | E >>> 2;\n            \n            B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;\n            D = D << 30 | D >>> 2;\n\n            A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;\n            C = C << 30 | C >>> 2;\n        }\n\n        //\n        // round 4\n        //\n        for (int j = 0; j <= 3; j++)\n        {\n            // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4\n            // B = rotateLeft(B, 30)\n            E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;\n            B = B << 30 | B >>> 2;\n            \n            D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;\n            A = A << 30 | A >>> 2;\n            \n            C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;\n            E = E << 30 | E >>> 2;\n            \n            B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;\n            D = D << 30 | D >>> 2;\n\n            A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;\n            C = C << 30 | C >>> 2;\n        }\n\n\n        H1 += A;\n        H2 += B;\n        H3 += C;\n        H4 += D;\n        H5 += E;\n\n        //\n        // reset start of the buffer.\n        //\n        xOff = 0;\n        for (int i = 0; i < 16; i++)\n        {\n            X[i] = 0;\n        }\n    }\n\n    public Memoable copy()\n    {\n        return new SHA1Digest(this);\n    }\n\n    public void reset(Memoable other)\n    {\n        SHA1Digest d = (SHA1Digest)other;\n\n        super.copyIn(d);\n        copyIn(d);\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java",
    "content": "package local.org.bouncycastle.crypto.params;\n\nimport local.org.bouncycastle.crypto.CipherParameters;\n\npublic class AsymmetricKeyParameter\n    implements CipherParameters\n{\n    boolean privateKey;\n\n    public AsymmetricKeyParameter(\n        boolean privateKey)\n    {\n        this.privateKey = privateKey;\n    }\n\n    public boolean isPrivate()\n    {\n        return privateKey;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/params/ECDomainParameters.java",
    "content": "package local.org.bouncycastle.crypto.params;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.math.ec.ECConstants;\nimport local.org.bouncycastle.math.ec.ECCurve;\nimport local.org.bouncycastle.math.ec.ECPoint;\nimport local.org.bouncycastle.util.Arrays;\n\n\npublic class ECDomainParameters\n    implements ECConstants\n{\n    private ECCurve     curve;\n    private byte[]      seed;\n    private ECPoint     G;\n    private BigInteger  n;\n    private BigInteger  h;\n\n    public ECDomainParameters(\n        ECCurve     curve,\n        ECPoint     G,\n        BigInteger  n)\n    {\n        this(curve, G, n, ONE, null);\n    }\n\n    public ECDomainParameters(\n        ECCurve     curve,\n        ECPoint     G,\n        BigInteger  n,\n        BigInteger  h)\n    {\n        this(curve, G, n, h, null);\n    }\n\n    public ECDomainParameters(\n        ECCurve     curve,\n        ECPoint     G,\n        BigInteger  n,\n        BigInteger  h,\n        byte[]      seed)\n    {\n        this.curve = curve;\n        this.G = G;\n        this.n = n;\n        this.h = h;\n        this.seed = seed;\n    }\n\n    public ECCurve getCurve()\n    {\n        return curve;\n    }\n\n    public ECPoint getG()\n    {\n        return G;\n    }\n\n    public BigInteger getN()\n    {\n        return n;\n    }\n\n    public BigInteger getH()\n    {\n        return h;\n    }\n\n    public byte[] getSeed()\n    {\n        return Arrays.clone(seed);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/params/ECKeyParameters.java",
    "content": "package local.org.bouncycastle.crypto.params;\n\npublic class ECKeyParameters\n    extends AsymmetricKeyParameter\n{\n    ECDomainParameters params;\n\n    protected ECKeyParameters(\n        boolean             isPrivate,\n        ECDomainParameters  params)\n    {\n        super(isPrivate);\n\n        this.params = params;\n    }\n\n    public ECDomainParameters getParameters()\n    {\n        return params;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java",
    "content": "package local.org.bouncycastle.crypto.params;\n\nimport java.math.BigInteger;\n\npublic class ECPrivateKeyParameters\n    extends ECKeyParameters\n{\n    BigInteger d;\n\n    public ECPrivateKeyParameters(\n        BigInteger          d,\n        ECDomainParameters  params)\n    {\n        super(true, params);\n        this.d = d;\n    }\n\n    public BigInteger getD()\n    {\n        return d;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/params/ECPublicKeyParameters.java",
    "content": "package local.org.bouncycastle.crypto.params;\n\nimport local.org.bouncycastle.math.ec.ECPoint;\n\npublic class ECPublicKeyParameters\n    extends ECKeyParameters\n{\n    ECPoint Q;\n\n    public ECPublicKeyParameters(\n        ECPoint             Q,\n        ECDomainParameters  params)\n    {\n        super(false, params);\n        this.Q = Q;\n    }\n\n    public ECPoint getQ()\n    {\n        return Q;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/crypto/util/Pack.java",
    "content": "package local.org.bouncycastle.crypto.util;\n\npublic abstract class Pack\n{\n    public static int bigEndianToInt(byte[] bs, int off)\n    {\n        int n = bs[  off] << 24;\n        n |= (bs[++off] & 0xff) << 16;\n        n |= (bs[++off] & 0xff) << 8;\n        n |= (bs[++off] & 0xff);\n        return n;\n    }\n\n    public static void bigEndianToInt(byte[] bs, int off, int[] ns)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            ns[i] = bigEndianToInt(bs, off);\n            off += 4;\n        }\n    }\n\n    public static byte[] intToBigEndian(int n)\n    {\n        byte[] bs = new byte[4];\n        intToBigEndian(n, bs, 0);\n        return bs;\n    }\n\n    public static void intToBigEndian(int n, byte[] bs, int off)\n    {\n        bs[  off] = (byte)(n >>> 24);\n        bs[++off] = (byte)(n >>> 16);\n        bs[++off] = (byte)(n >>>  8);\n        bs[++off] = (byte)(n       );\n    }\n\n    public static byte[] intToBigEndian(int[] ns)\n    {\n        byte[] bs = new byte[4 * ns.length];\n        intToBigEndian(ns, bs, 0);\n        return bs;\n    }\n\n    public static void intToBigEndian(int[] ns, byte[] bs, int off)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            intToBigEndian(ns[i], bs, off);\n            off += 4;\n        }\n    }\n\n    public static long bigEndianToLong(byte[] bs, int off)\n    {\n        int hi = bigEndianToInt(bs, off);\n        int lo = bigEndianToInt(bs, off + 4);\n        return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);\n    }\n\n    public static void bigEndianToLong(byte[] bs, int off, long[] ns)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            ns[i] = bigEndianToLong(bs, off);\n            off += 8;\n        }\n    }\n\n    public static byte[] longToBigEndian(long n)\n    {\n        byte[] bs = new byte[8];\n        longToBigEndian(n, bs, 0);\n        return bs;\n    }\n\n    public static void longToBigEndian(long n, byte[] bs, int off)\n    {\n        intToBigEndian((int)(n >>> 32), bs, off);\n        intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);\n    }\n\n    public static byte[] longToBigEndian(long[] ns)\n    {\n        byte[] bs = new byte[8 * ns.length];\n        longToBigEndian(ns, bs, 0);\n        return bs;\n    }\n\n    public static void longToBigEndian(long[] ns, byte[] bs, int off)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            longToBigEndian(ns[i], bs, off);\n            off += 8;\n        }\n    }\n\n    public static int littleEndianToInt(byte[] bs, int off)\n    {\n        int n = bs[  off] & 0xff;\n        n |= (bs[++off] & 0xff) << 8;\n        n |= (bs[++off] & 0xff) << 16;\n        n |= bs[++off] << 24;\n        return n;\n    }\n\n    public static void littleEndianToInt(byte[] bs, int off, int[] ns)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            ns[i] = littleEndianToInt(bs, off);\n            off += 4;\n        }\n    }\n\n    public static byte[] intToLittleEndian(int n)\n    {\n        byte[] bs = new byte[4];\n        intToLittleEndian(n, bs, 0);\n        return bs;\n    }\n\n    public static void intToLittleEndian(int n, byte[] bs, int off)\n    {\n        bs[  off] = (byte)(n       );\n        bs[++off] = (byte)(n >>>  8);\n        bs[++off] = (byte)(n >>> 16);\n        bs[++off] = (byte)(n >>> 24);\n    }\n\n    public static byte[] intToLittleEndian(int[] ns)\n    {\n        byte[] bs = new byte[4 * ns.length];\n        intToLittleEndian(ns, bs, 0);\n        return bs;\n    }\n\n    public static void intToLittleEndian(int[] ns, byte[] bs, int off)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            intToLittleEndian(ns[i], bs, off);\n            off += 4;\n        }\n    }\n\n    public static long littleEndianToLong(byte[] bs, int off)\n    {\n        int lo = littleEndianToInt(bs, off);\n        int hi = littleEndianToInt(bs, off + 4);\n        return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);\n    }\n\n    public static void littleEndianToLong(byte[] bs, int off, long[] ns)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            ns[i] = littleEndianToLong(bs, off);\n            off += 8;\n        }\n    }\n\n    public static byte[] longToLittleEndian(long n)\n    {\n        byte[] bs = new byte[8];\n        longToLittleEndian(n, bs, 0);\n        return bs;\n    }\n\n    public static void longToLittleEndian(long n, byte[] bs, int off)\n    {\n        intToLittleEndian((int)(n & 0xffffffffL), bs, off);\n        intToLittleEndian((int)(n >>> 32), bs, off + 4);\n    }\n\n    public static byte[] longToLittleEndian(long[] ns)\n    {\n        byte[] bs = new byte[8 * ns.length];\n        longToLittleEndian(ns, bs, 0);\n        return bs;\n    }\n\n    public static void longToLittleEndian(long[] ns, byte[] bs, int off)\n    {\n        for (int i = 0; i < ns.length; ++i)\n        {\n            longToLittleEndian(ns[i], bs, off);\n            off += 8;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/ECConstants.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\npublic interface ECConstants\n{\n    public static final BigInteger ZERO = BigInteger.valueOf(0);\n    public static final BigInteger ONE = BigInteger.valueOf(1);\n    public static final BigInteger TWO = BigInteger.valueOf(2);\n    public static final BigInteger THREE = BigInteger.valueOf(3);\n    public static final BigInteger FOUR = BigInteger.valueOf(4);\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/ECCurve.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\nimport java.util.Random;\n\n/**\n * base class for an elliptic curve\n */\npublic abstract class ECCurve\n{\n    ECFieldElement a, b;\n\n    public abstract int getFieldSize();\n\n    public abstract ECFieldElement fromBigInteger(BigInteger x);\n\n    public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);\n\n    public abstract ECPoint getInfinity();\n\n    public ECFieldElement getA()\n    {\n        return a;\n    }\n\n    public ECFieldElement getB()\n    {\n        return b;\n    }\n\n    protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1);\n\n    /**\n     * Decode a point on this curve from its ASN.1 encoding. The different\n     * encodings are taken account of, including point compression for\n     * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).\n     * @return The decoded point.\n     */\n    public ECPoint decodePoint(byte[] encoded)\n    {\n        ECPoint p = null;\n        int expectedLength = (getFieldSize() + 7) / 8;\n\n        switch (encoded[0])\n        {\n        case 0x00: // infinity\n        {\n            if (encoded.length != 1)\n            {\n                throw new IllegalArgumentException(\"Incorrect length for infinity encoding\");\n            }\n\n            p = getInfinity();\n            break;\n        }\n        case 0x02: // compressed\n        case 0x03: // compressed\n        {\n            if (encoded.length != (expectedLength + 1))\n            {\n                throw new IllegalArgumentException(\"Incorrect length for compressed encoding\");\n            }\n\n            int yTilde = encoded[0] & 1;\n            BigInteger X1 = fromArray(encoded, 1, expectedLength);\n\n            p = decompressPoint(yTilde, X1);\n            break;\n        }\n        case 0x04: // uncompressed\n        case 0x06: // hybrid\n        case 0x07: // hybrid\n        {\n            if (encoded.length != (2 * expectedLength + 1))\n            {\n                throw new IllegalArgumentException(\"Incorrect length for uncompressed/hybrid encoding\");\n            }\n\n            BigInteger X1 = fromArray(encoded, 1, expectedLength);\n            BigInteger Y1 = fromArray(encoded, 1 + expectedLength, expectedLength);\n\n            p = createPoint(X1, Y1, false);\n            break;\n        }\n        default:\n            throw new IllegalArgumentException(\"Invalid point encoding 0x\" + Integer.toString(encoded[0], 16));\n        }\n\n        return p;\n    }\n\n    private static BigInteger fromArray(byte[] buf, int off, int length)\n    {\n        byte[] mag = new byte[length];\n        System.arraycopy(buf, off, mag, 0, length);\n        return new BigInteger(1, mag);\n    }\n\n    /**\n     * Elliptic curve over Fp\n     */\n    public static class Fp extends ECCurve\n    {\n        BigInteger q;\n        ECPoint.Fp infinity;\n\n        public Fp(BigInteger q, BigInteger a, BigInteger b)\n        {\n            this.q = q;\n            this.a = fromBigInteger(a);\n            this.b = fromBigInteger(b);\n            this.infinity = new ECPoint.Fp(this, null, null);\n        }\n\n        public BigInteger getQ()\n        {\n            return q;\n        }\n\n        public int getFieldSize()\n        {\n            return q.bitLength();\n        }\n\n        public ECFieldElement fromBigInteger(BigInteger x)\n        {\n            return new ECFieldElement.Fp(this.q, x);\n        }\n\n        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)\n        {\n            return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);\n        }\n\n        protected ECPoint decompressPoint(int yTilde, BigInteger X1)\n        {\n            ECFieldElement x = fromBigInteger(X1);\n            ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);\n            ECFieldElement beta = alpha.sqrt();\n\n            //\n            // if we can't find a sqrt we haven't got a point on the\n            // curve - run!\n            //\n            if (beta == null)\n            {\n                throw new RuntimeException(\"Invalid point compression\");\n            }\n\n            BigInteger betaValue = beta.toBigInteger();\n            int bit0 = betaValue.testBit(0) ? 1 : 0;\n\n            if (bit0 != yTilde)\n            {\n                // Use the other root\n                beta = fromBigInteger(q.subtract(betaValue));\n            }\n\n            return new ECPoint.Fp(this, x, beta, true);\n        }\n\n        public ECPoint getInfinity()\n        {\n            return infinity;\n        }\n\n        public boolean equals(\n            Object anObject) \n        {\n            if (anObject == this) \n            {\n                return true;\n            }\n\n            if (!(anObject instanceof ECCurve.Fp)) \n            {\n                return false;\n            }\n\n            ECCurve.Fp other = (ECCurve.Fp) anObject;\n\n            return this.q.equals(other.q) \n                    && a.equals(other.a) && b.equals(other.b);\n        }\n\n        public int hashCode() \n        {\n            return a.hashCode() ^ b.hashCode() ^ q.hashCode();\n        }\n    }\n\n    /**\n     * Elliptic curves over F2m. The Weierstrass equation is given by\n     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.\n     */\n    public static class F2m extends ECCurve\n    {\n        /**\n         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.\n         */\n        private int m;  // can't be final - JDK 1.1\n\n        /**\n         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +\n         * x<sup>k</sup> + 1</code> represents the reduction polynomial\n         * <code>f(z)</code>.<br>\n         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        private int k1;  // can't be final - JDK 1.1\n\n        /**\n         * TPB: Always set to <code>0</code><br>\n         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        private int k2;  // can't be final - JDK 1.1\n\n        /**\n         * TPB: Always set to <code>0</code><br>\n         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        private int k3;  // can't be final - JDK 1.1\n\n        /**\n         * The order of the base point of the curve.\n         */\n        private BigInteger n;  // can't be final - JDK 1.1\n\n        /**\n         * The cofactor of the curve.\n         */\n        private BigInteger h;  // can't be final - JDK 1.1\n        \n         /**\n         * The point at infinity on this curve.\n         */\n        private ECPoint.F2m infinity;  // can't be final - JDK 1.1\n\n        /**\n         * The parameter <code>&mu;</code> of the elliptic curve if this is\n         * a Koblitz curve.\n         */\n        private byte mu = 0;\n\n        /**\n         * The auxiliary values <code>s<sub>0</sub></code> and\n         * <code>s<sub>1</sub></code> used for partial modular reduction for\n         * Koblitz curves.\n         */\n        private BigInteger[] si = null;\n\n        /**\n         * Constructor for Trinomial Polynomial Basis (TPB).\n         * @param m  The exponent <code>m</code> of\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +\n         * x<sup>k</sup> + 1</code> represents the reduction\n         * polynomial <code>f(z)</code>.\n         * @param a The coefficient <code>a</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param b The coefficient <code>b</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         */\n        public F2m(\n            int m,\n            int k,\n            BigInteger a,\n            BigInteger b)\n        {\n            this(m, k, 0, 0, a, b, null, null);\n        }\n\n        /**\n         * Constructor for Trinomial Polynomial Basis (TPB).\n         * @param m  The exponent <code>m</code> of\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +\n         * x<sup>k</sup> + 1</code> represents the reduction\n         * polynomial <code>f(z)</code>.\n         * @param a The coefficient <code>a</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param b The coefficient <code>b</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param n The order of the main subgroup of the elliptic curve.\n         * @param h The cofactor of the elliptic curve, i.e.\n         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.\n         */\n        public F2m(\n            int m, \n            int k, \n            BigInteger a, \n            BigInteger b,\n            BigInteger n,\n            BigInteger h)\n        {\n            this(m, k, 0, 0, a, b, n, h);\n        }\n\n        /**\n         * Constructor for Pentanomial Polynomial Basis (PPB).\n         * @param m  The exponent <code>m</code> of\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param a The coefficient <code>a</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param b The coefficient <code>b</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         */\n        public F2m(\n            int m,\n            int k1,\n            int k2,\n            int k3,\n            BigInteger a,\n            BigInteger b)\n        {\n            this(m, k1, k2, k3, a, b, null, null);\n        }\n\n        /**\n         * Constructor for Pentanomial Polynomial Basis (PPB).\n         * @param m  The exponent <code>m</code> of\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param a The coefficient <code>a</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param b The coefficient <code>b</code> in the Weierstrass equation\n         * for non-supersingular elliptic curves over\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param n The order of the main subgroup of the elliptic curve.\n         * @param h The cofactor of the elliptic curve, i.e.\n         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.\n         */\n        public F2m(\n            int m, \n            int k1, \n            int k2, \n            int k3,\n            BigInteger a, \n            BigInteger b,\n            BigInteger n,\n            BigInteger h)\n        {\n            this.m = m;\n            this.k1 = k1;\n            this.k2 = k2;\n            this.k3 = k3;\n            this.n = n;\n            this.h = h;\n\n            if (k1 == 0)\n            {\n                throw new IllegalArgumentException(\"k1 must be > 0\");\n            }\n\n            if (k2 == 0)\n            {\n                if (k3 != 0)\n                {\n                    throw new IllegalArgumentException(\"k3 must be 0 if k2 == 0\");\n                }\n            }\n            else\n            {\n                if (k2 <= k1)\n                {\n                    throw new IllegalArgumentException(\"k2 must be > k1\");\n                }\n\n                if (k3 <= k2)\n                {\n                    throw new IllegalArgumentException(\"k3 must be > k2\");\n                }\n            }\n\n            this.a = fromBigInteger(a);\n            this.b = fromBigInteger(b);\n            this.infinity = new ECPoint.F2m(this, null, null);\n        }\n\n        public int getFieldSize()\n        {\n            return m;\n        }\n\n        public ECFieldElement fromBigInteger(BigInteger x)\n        {\n            return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);\n        }\n\n        public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)\n        {\n            return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);\n        }\n\n        public ECPoint getInfinity()\n        {\n            return infinity;\n        }\n\n        /**\n         * Returns true if this is a Koblitz curve (ABC curve).\n         * @return true if this is a Koblitz curve (ABC curve), false otherwise\n         */\n        public boolean isKoblitz()\n        {\n            return ((n != null) && (h != null) &&\n                    ((a.toBigInteger().equals(ECConstants.ZERO)) ||\n                    (a.toBigInteger().equals(ECConstants.ONE))) &&\n                    (b.toBigInteger().equals(ECConstants.ONE)));\n        }\n\n        /**\n         * Returns the parameter <code>&mu;</code> of the elliptic curve.\n         * @return <code>&mu;</code> of the elliptic curve.\n         * @throws IllegalArgumentException if the given ECCurve is not a\n         * Koblitz curve.\n         */\n        synchronized byte getMu()\n        {\n            if (mu == 0)\n            {\n                mu = Tnaf.getMu(this);\n            }\n            return mu;\n        }\n\n        /**\n         * @return the auxiliary values <code>s<sub>0</sub></code> and\n         * <code>s<sub>1</sub></code> used for partial modular reduction for\n         * Koblitz curves.\n         */\n        synchronized BigInteger[] getSi()\n        {\n            if (si == null)\n            {\n                si = Tnaf.getSi(this);\n            }\n            return si;\n        }\n\n        /**\n         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).\n         * \n         * @param yTilde\n         *            ~yp, an indication bit for the decompression of yp.\n         * @param X1\n         *            The field element xp.\n         * @return the decompressed point.\n         */\n        protected ECPoint decompressPoint(int yTilde, BigInteger X1)\n        {\n            ECFieldElement xp = fromBigInteger(X1);\n            ECFieldElement yp = null;\n            if (xp.toBigInteger().equals(ECConstants.ZERO))\n            {\n                yp = (ECFieldElement.F2m)b;\n                for (int i = 0; i < m - 1; i++)\n                {\n                    yp = yp.square();\n                }\n            }\n            else\n            {\n                ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert()));\n                ECFieldElement z = solveQuadradicEquation(beta);\n                if (z == null)\n                {\n                    throw new IllegalArgumentException(\"Invalid point compression\");\n                }\n                int zBit = z.toBigInteger().testBit(0) ? 1 : 0;\n                if (zBit != yTilde)\n                {\n                    z = z.add(fromBigInteger(ECConstants.ONE));\n                }\n                yp = xp.multiply(z);\n            }\n\n            return new ECPoint.F2m(this, xp, yp, true);\n        }\n        \n        /**\n         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62\n         * D.1.6) The other solution is <code>z + 1</code>.\n         * \n         * @param beta\n         *            The value to solve the qradratic equation for.\n         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or\n         *         <code>null</code> if no solution exists.\n         */\n        private ECFieldElement solveQuadradicEquation(ECFieldElement beta)\n        {\n            ECFieldElement zeroElement = new ECFieldElement.F2m(\n                    this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);\n\n            if (beta.toBigInteger().equals(ECConstants.ZERO))\n            {\n                return zeroElement;\n            }\n\n            ECFieldElement z = null;\n            ECFieldElement gamma = zeroElement;\n\n            Random rand = new Random();\n            do\n            {\n                ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,\n                        this.k2, this.k3, new BigInteger(m, rand));\n                z = zeroElement;\n                ECFieldElement w = beta;\n                for (int i = 1; i <= m - 1; i++)\n                {\n                    ECFieldElement w2 = w.square();\n                    z = z.square().add(w2.multiply(t));\n                    w = w2.add(beta);\n                }\n                if (!w.toBigInteger().equals(ECConstants.ZERO))\n                {\n                    return null;\n                }\n                gamma = z.square().add(z);\n            }\n            while (gamma.toBigInteger().equals(ECConstants.ZERO));\n\n            return z;\n        }\n        \n        public boolean equals(\n            Object anObject)\n        {\n            if (anObject == this) \n            {\n                return true;\n            }\n\n            if (!(anObject instanceof ECCurve.F2m)) \n            {\n                return false;\n            }\n\n            ECCurve.F2m other = (ECCurve.F2m)anObject;\n            \n            return (this.m == other.m) && (this.k1 == other.k1)\n                && (this.k2 == other.k2) && (this.k3 == other.k3)\n                && a.equals(other.a) && b.equals(other.b);\n        }\n\n        public int hashCode()\n        {\n            return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;\n        }\n\n        public int getM()\n        {\n            return m;\n        }\n\n        /**\n         * Return true if curve uses a Trinomial basis.\n         * \n         * @return true if curve Trinomial, false otherwise.\n         */\n        public boolean isTrinomial()\n        {\n            return k2 == 0 && k3 == 0;\n        }\n        \n        public int getK1()\n        {\n            return k1;\n        }\n\n        public int getK2()\n        {\n            return k2;\n        }\n\n        public int getK3()\n        {\n            return k3;\n        }\n\n        public BigInteger getN()\n        {\n            return n;\n        }\n\n        public BigInteger getH()\n        {\n            return h;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/ECFieldElement.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\nimport java.util.Random;\n\npublic abstract class ECFieldElement\n    implements ECConstants\n{\n\n    public abstract BigInteger     toBigInteger();\n    public abstract String         getFieldName();\n    public abstract int            getFieldSize();\n    public abstract ECFieldElement add(ECFieldElement b);\n    public abstract ECFieldElement subtract(ECFieldElement b);\n    public abstract ECFieldElement multiply(ECFieldElement b);\n    public abstract ECFieldElement divide(ECFieldElement b);\n    public abstract ECFieldElement negate();\n    public abstract ECFieldElement square();\n    public abstract ECFieldElement invert();\n    public abstract ECFieldElement sqrt();\n\n    public String toString()\n    {\n        return this.toBigInteger().toString(2);\n    }\n\n    public static class Fp extends ECFieldElement\n    {\n        BigInteger x;\n\n        BigInteger q;\n        \n        public Fp(BigInteger q, BigInteger x)\n        {\n            this.x = x;\n            \n            if (x.compareTo(q) >= 0)\n            {\n                throw new IllegalArgumentException(\"x value too large in field element\");\n            }\n\n            this.q = q;\n        }\n\n        public BigInteger toBigInteger()\n        {\n            return x;\n        }\n\n        /**\n         * return the field name for this field.\n         *\n         * @return the string \"Fp\".\n         */\n        public String getFieldName()\n        {\n            return \"Fp\";\n        }\n\n        public int getFieldSize()\n        {\n            return q.bitLength();\n        }\n\n        public BigInteger getQ()\n        {\n            return q;\n        }\n        \n        public ECFieldElement add(ECFieldElement b)\n        {\n            return new Fp(q, x.add(b.toBigInteger()).mod(q));\n        }\n\n        public ECFieldElement subtract(ECFieldElement b)\n        {\n            return new Fp(q, x.subtract(b.toBigInteger()).mod(q));\n        }\n\n        public ECFieldElement multiply(ECFieldElement b)\n        {\n            return new Fp(q, x.multiply(b.toBigInteger()).mod(q));\n        }\n\n        public ECFieldElement divide(ECFieldElement b)\n        {\n            return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q));\n        }\n\n        public ECFieldElement negate()\n        {\n            return new Fp(q, x.negate().mod(q));\n        }\n\n        public ECFieldElement square()\n        {\n            return new Fp(q, x.multiply(x).mod(q));\n        }\n\n        public ECFieldElement invert()\n        {\n            return new Fp(q, x.modInverse(q));\n        }\n\n        // D.1.4 91\n        /**\n         * return a sqrt root - the routine verifies that the calculation\n         * returns the right value - if none exists it returns null.\n         */\n        public ECFieldElement sqrt()\n        {\n            if (!q.testBit(0))\n            {\n                throw new RuntimeException(\"not done yet\");\n            }\n\n            // note: even though this class implements ECConstants don't be tempted to\n            // remove the explicit declaration, some J2ME environments don't cope.\n            // p mod 4 == 3\n            if (q.testBit(1))\n            {\n                // z = g^(u+1) + p, p = 4u + 3\n                ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));\n\n                return z.square().equals(this) ? z : null;\n            }\n\n            // p mod 4 == 1\n            BigInteger qMinusOne = q.subtract(ECConstants.ONE);\n\n            BigInteger legendreExponent = qMinusOne.shiftRight(1);\n            if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))\n            {\n                return null;\n            }\n\n            BigInteger u = qMinusOne.shiftRight(2);\n            BigInteger k = u.shiftLeft(1).add(ECConstants.ONE);\n\n            BigInteger Q = this.x;\n            BigInteger fourQ = Q.shiftLeft(2).mod(q);\n\n            BigInteger U, V;\n            Random rand = new Random();\n            do\n            {\n                BigInteger P;\n                do\n                {\n                    P = new BigInteger(q.bitLength(), rand);\n                }\n                while (P.compareTo(q) >= 0\n                    || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne)));\n\n                BigInteger[] result = lucasSequence(q, P, Q, k);\n                U = result[0];\n                V = result[1];\n\n                if (V.multiply(V).mod(q).equals(fourQ))\n                {\n                    // Integer division by 2, mod q\n                    if (V.testBit(0))\n                    {\n                        V = V.add(q);\n                    }\n\n                    V = V.shiftRight(1);\n\n                    //assert V.multiply(V).mod(q).equals(x);\n\n                    return new ECFieldElement.Fp(q, V);\n                }\n            }\n            while (U.equals(ECConstants.ONE) || U.equals(qMinusOne));\n\n            return null;\n\n//            BigInteger qMinusOne = q.subtract(ECConstants.ONE);\n//            BigInteger legendreExponent = qMinusOne.shiftRight(1); //divide(ECConstants.TWO);\n//            if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE)))\n//            {\n//                return null;\n//            }\n//\n//            Random rand = new Random();\n//            BigInteger fourX = x.shiftLeft(2);\n//\n//            BigInteger r;\n//            do\n//            {\n//                r = new BigInteger(q.bitLength(), rand);\n//            }\n//            while (r.compareTo(q) >= 0\n//                || !(r.multiply(r).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne)));\n//\n//            BigInteger n1 = qMinusOne.shiftRight(2); //.divide(ECConstants.FOUR);\n//            BigInteger n2 = n1.add(ECConstants.ONE); //q.add(ECConstants.THREE).divide(ECConstants.FOUR);\n//\n//            BigInteger wOne = WOne(r, x, q);\n//            BigInteger wSum = W(n1, wOne, q).add(W(n2, wOne, q)).mod(q);\n//            BigInteger twoR = r.shiftLeft(1); //ECConstants.TWO.multiply(r);\n//\n//            BigInteger root = twoR.modPow(q.subtract(ECConstants.TWO), q)\n//                .multiply(x).mod(q)\n//                .multiply(wSum).mod(q);\n//\n//            return new Fp(q, root);\n        }\n\n//        private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p)\n//        {\n//            if (n.equals(ECConstants.ONE))\n//            {\n//                return wOne;\n//            }\n//            boolean isEven = !n.testBit(0);\n//            n = n.shiftRight(1);//divide(ECConstants.TWO);\n//            if (isEven)\n//            {\n//                BigInteger w = W(n, wOne, p);\n//                return w.multiply(w).subtract(ECConstants.TWO).mod(p);\n//            }\n//            BigInteger w1 = W(n.add(ECConstants.ONE), wOne, p);\n//            BigInteger w2 = W(n, wOne, p);\n//            return w1.multiply(w2).subtract(wOne).mod(p);\n//        }\n//\n//        private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p)\n//        {\n//            return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p);\n//        }\n\n        private static BigInteger[] lucasSequence(\n            BigInteger  p,\n            BigInteger  P,\n            BigInteger  Q,\n            BigInteger  k)\n        {\n            int n = k.bitLength();\n            int s = k.getLowestSetBit();\n\n            BigInteger Uh = ECConstants.ONE;\n            BigInteger Vl = ECConstants.TWO;\n            BigInteger Vh = P;\n            BigInteger Ql = ECConstants.ONE;\n            BigInteger Qh = ECConstants.ONE;\n\n            for (int j = n - 1; j >= s + 1; --j)\n            {\n                Ql = Ql.multiply(Qh).mod(p);\n\n                if (k.testBit(j))\n                {\n                    Qh = Ql.multiply(Q).mod(p);\n                    Uh = Uh.multiply(Vh).mod(p);\n                    Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);\n                    Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);\n                }\n                else\n                {\n                    Qh = Ql;\n                    Uh = Uh.multiply(Vl).subtract(Ql).mod(p);\n                    Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);\n                    Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);\n                }\n            }\n\n            Ql = Ql.multiply(Qh).mod(p);\n            Qh = Ql.multiply(Q).mod(p);\n            Uh = Uh.multiply(Vl).subtract(Ql).mod(p);\n            Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);\n            Ql = Ql.multiply(Qh).mod(p);\n\n            for (int j = 1; j <= s; ++j)\n            {\n                Uh = Uh.multiply(Vl).mod(p);\n                Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);\n                Ql = Ql.multiply(Ql).mod(p);\n            }\n\n            return new BigInteger[]{ Uh, Vl };\n        }\n        \n        public boolean equals(Object other)\n        {\n            if (other == this)\n            {\n                return true;\n            }\n\n            if (!(other instanceof ECFieldElement.Fp))\n            {\n                return false;\n            }\n            \n            ECFieldElement.Fp o = (ECFieldElement.Fp)other;\n            return q.equals(o.q) && x.equals(o.x);\n        }\n\n        public int hashCode()\n        {\n            return q.hashCode() ^ x.hashCode();\n        }\n    }\n\n//    /**\n//     * Class representing the Elements of the finite field\n//     * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)\n//     * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial\n//     * basis representations are supported. Gaussian normal basis (GNB)\n//     * representation is not supported.\n//     */\n//    public static class F2m extends ECFieldElement\n//    {\n//        BigInteger x;\n//\n//        /**\n//         * Indicates gaussian normal basis representation (GNB). Number chosen\n//         * according to X9.62. GNB is not implemented at present.\n//         */\n//        public static final int GNB = 1;\n//\n//        /**\n//         * Indicates trinomial basis representation (TPB). Number chosen\n//         * according to X9.62.\n//         */\n//        public static final int TPB = 2;\n//\n//        /**\n//         * Indicates pentanomial basis representation (PPB). Number chosen\n//         * according to X9.62.\n//         */\n//        public static final int PPB = 3;\n//\n//        /**\n//         * TPB or PPB.\n//         */\n//        private int representation;\n//\n//        /**\n//         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.\n//         */\n//        private int m;\n//\n//        /**\n//         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +\n//         * x<sup>k</sup> + 1</code> represents the reduction polynomial\n//         * <code>f(z)</code>.<br>\n//         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.<br>\n//         */\n//        private int k1;\n//\n//        /**\n//         * TPB: Always set to <code>0</code><br>\n//         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.<br>\n//         */\n//        private int k2;\n//\n//        /**\n//         * TPB: Always set to <code>0</code><br>\n//         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.<br>\n//         */\n//        private int k3;\n//        \n//        /**\n//         * Constructor for PPB.\n//         * @param m  The exponent <code>m</code> of\n//         * <code>F<sub>2<sup>m</sup></sub></code>.\n//         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.\n//         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.\n//         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.\n//         * @param x The BigInteger representing the value of the field element.\n//         */\n//        public F2m(\n//            int m, \n//            int k1, \n//            int k2, \n//            int k3,\n//            BigInteger x)\n//        {\n////            super(x);\n//            this.x = x;\n//\n//            if ((k2 == 0) && (k3 == 0))\n//            {\n//                this.representation = TPB;\n//            }\n//            else\n//            {\n//                if (k2 >= k3)\n//                {\n//                    throw new IllegalArgumentException(\n//                            \"k2 must be smaller than k3\");\n//                }\n//                if (k2 <= 0)\n//                {\n//                    throw new IllegalArgumentException(\n//                            \"k2 must be larger than 0\");\n//                }\n//                this.representation = PPB;\n//            }\n//\n//            if (x.signum() < 0)\n//            {\n//                throw new IllegalArgumentException(\"x value cannot be negative\");\n//            }\n//\n//            this.m = m;\n//            this.k1 = k1;\n//            this.k2 = k2;\n//            this.k3 = k3;\n//        }\n//\n//        /**\n//         * Constructor for TPB.\n//         * @param m  The exponent <code>m</code> of\n//         * <code>F<sub>2<sup>m</sup></sub></code>.\n//         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +\n//         * x<sup>k</sup> + 1</code> represents the reduction\n//         * polynomial <code>f(z)</code>.\n//         * @param x The BigInteger representing the value of the field element.\n//         */\n//        public F2m(int m, int k, BigInteger x)\n//        {\n//            // Set k1 to k, and set k2 and k3 to 0\n//            this(m, k, 0, 0, x);\n//        }\n//\n//        public BigInteger toBigInteger()\n//        {\n//            return x;\n//        }\n//\n//        public String getFieldName()\n//        {\n//            return \"F2m\";\n//        }\n//\n//        public int getFieldSize()\n//        {\n//            return m;\n//        }\n//\n//        /**\n//         * Checks, if the ECFieldElements <code>a</code> and <code>b</code>\n//         * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>\n//         * (having the same representation).\n//         * @param a field element.\n//         * @param b field element to be compared.\n//         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>\n//         * are not elements of the same field\n//         * <code>F<sub>2<sup>m</sup></sub></code> (having the same\n//         * representation). \n//         */\n//        public static void checkFieldElements(\n//            ECFieldElement a,\n//            ECFieldElement b)\n//        {\n//            if ((!(a instanceof F2m)) || (!(b instanceof F2m)))\n//            {\n//                throw new IllegalArgumentException(\"Field elements are not \"\n//                        + \"both instances of ECFieldElement.F2m\");\n//            }\n//\n//            if ((a.toBigInteger().signum() < 0) || (b.toBigInteger().signum() < 0))\n//            {\n//                throw new IllegalArgumentException(\n//                        \"x value may not be negative\");\n//            }\n//\n//            ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;\n//            ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;\n//\n//            if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)\n//                    || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))\n//            {\n//                throw new IllegalArgumentException(\"Field elements are not \"\n//                        + \"elements of the same field F2m\");\n//            }\n//\n//            if (aF2m.representation != bF2m.representation)\n//            {\n//                // Should never occur\n//                throw new IllegalArgumentException(\n//                        \"One of the field \"\n//                                + \"elements are not elements has incorrect representation\");\n//            }\n//        }\n//\n//        /**\n//         * Computes <code>z * a(z) mod f(z)</code>, where <code>f(z)</code> is\n//         * the reduction polynomial of <code>this</code>.\n//         * @param a The polynomial <code>a(z)</code> to be multiplied by\n//         * <code>z mod f(z)</code>.\n//         * @return <code>z * a(z) mod f(z)</code>\n//         */\n//        private BigInteger multZModF(final BigInteger a)\n//        {\n//            // Left-shift of a(z)\n//            BigInteger az = a.shiftLeft(1);\n//            if (az.testBit(this.m)) \n//            {\n//                // If the coefficient of z^m in a(z) equals 1, reduction\n//                // modulo f(z) is performed: Add f(z) to to a(z):\n//                // Step 1: Unset mth coeffient of a(z)\n//                az = az.clearBit(this.m);\n//\n//                // Step 2: Add r(z) to a(z), where r(z) is defined as\n//                // f(z) = z^m + r(z), and k1, k2, k3 are the positions of\n//                // the non-zero coefficients in r(z)\n//                az = az.flipBit(0);\n//                az = az.flipBit(this.k1);\n//                if (this.representation == PPB) \n//                {\n//                    az = az.flipBit(this.k2);\n//                    az = az.flipBit(this.k3);\n//                }\n//            }\n//            return az;\n//        }\n//\n//        public ECFieldElement add(final ECFieldElement b)\n//        {\n//            // No check performed here for performance reasons. Instead the\n//            // elements involved are checked in ECPoint.F2m\n//            // checkFieldElements(this, b);\n//            if (b.toBigInteger().signum() == 0)\n//            {\n//                return this;\n//            }\n//\n//            return new F2m(this.m, this.k1, this.k2, this.k3, this.x.xor(b.toBigInteger()));\n//        }\n//\n//        public ECFieldElement subtract(final ECFieldElement b)\n//        {\n//            // Addition and subtraction are the same in F2m\n//            return add(b);\n//        }\n//\n//\n//        public ECFieldElement multiply(final ECFieldElement b)\n//        {\n//            // Left-to-right shift-and-add field multiplication in F2m\n//            // Input: Binary polynomials a(z) and b(z) of degree at most m-1\n//            // Output: c(z) = a(z) * b(z) mod f(z)\n//\n//            // No check performed here for performance reasons. Instead the\n//            // elements involved are checked in ECPoint.F2m\n//            // checkFieldElements(this, b);\n//            final BigInteger az = this.x;\n//            BigInteger bz = b.toBigInteger();\n//            BigInteger cz;\n//\n//            // Compute c(z) = a(z) * b(z) mod f(z)\n//            if (az.testBit(0)) \n//            {\n//                cz = bz;\n//            } \n//            else \n//            {\n//                cz = ECConstants.ZERO;\n//            }\n//\n//            for (int i = 1; i < this.m; i++) \n//            {\n//                // b(z) := z * b(z) mod f(z)\n//                bz = multZModF(bz);\n//\n//                if (az.testBit(i)) \n//                {\n//                    // If the coefficient of x^i in a(z) equals 1, b(z) is added\n//                    // to c(z)\n//                    cz = cz.xor(bz);\n//                }\n//            }\n//            return new ECFieldElement.F2m(m, this.k1, this.k2, this.k3, cz);\n//        }\n//\n//\n//        public ECFieldElement divide(final ECFieldElement b)\n//        {\n//            // There may be more efficient implementations\n//            ECFieldElement bInv = b.invert();\n//            return multiply(bInv);\n//        }\n//\n//        public ECFieldElement negate()\n//        {\n//            // -x == x holds for all x in F2m\n//            return this;\n//        }\n//\n//        public ECFieldElement square()\n//        {\n//            // Naive implementation, can probably be speeded up using modular\n//            // reduction\n//            return multiply(this);\n//        }\n//\n//        public ECFieldElement invert()\n//        {\n//            // Inversion in F2m using the extended Euclidean algorithm\n//            // Input: A nonzero polynomial a(z) of degree at most m-1\n//            // Output: a(z)^(-1) mod f(z)\n//\n//            // u(z) := a(z)\n//            BigInteger uz = this.x;\n//            if (uz.signum() <= 0) \n//            {\n//                throw new ArithmeticException(\"x is zero or negative, \" +\n//                        \"inversion is impossible\");\n//            }\n//\n//            // v(z) := f(z)\n//            BigInteger vz = ECConstants.ZERO.setBit(m);\n//            vz = vz.setBit(0);\n//            vz = vz.setBit(this.k1);\n//            if (this.representation == PPB) \n//            {\n//                vz = vz.setBit(this.k2);\n//                vz = vz.setBit(this.k3);\n//            }\n//\n//            // g1(z) := 1, g2(z) := 0\n//            BigInteger g1z = ECConstants.ONE;\n//            BigInteger g2z = ECConstants.ZERO;\n//\n//            // while u != 1\n//            while (!(uz.equals(ECConstants.ZERO))) \n//            {\n//                // j := deg(u(z)) - deg(v(z))\n//                int j = uz.bitLength() - vz.bitLength();\n//\n//                // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j\n//                if (j < 0) \n//                {\n//                    final BigInteger uzCopy = uz;\n//                    uz = vz;\n//                    vz = uzCopy;\n//\n//                    final BigInteger g1zCopy = g1z;\n//                    g1z = g2z;\n//                    g2z = g1zCopy;\n//\n//                    j = -j;\n//                }\n//\n//                // u(z) := u(z) + z^j * v(z)\n//                // Note, that no reduction modulo f(z) is required, because\n//                // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))\n//                // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))\n//                // = deg(u(z))\n//                uz = uz.xor(vz.shiftLeft(j));\n//\n//                // g1(z) := g1(z) + z^j * g2(z)\n//                g1z = g1z.xor(g2z.shiftLeft(j));\n////                if (g1z.bitLength() > this.m) {\n////                    throw new ArithmeticException(\n////                            \"deg(g1z) >= m, g1z = \" + g1z.toString(2));\n////                }\n//            }\n//            return new ECFieldElement.F2m(\n//                    this.m, this.k1, this.k2, this.k3, g2z);\n//        }\n//\n//        public ECFieldElement sqrt()\n//        {\n//            throw new RuntimeException(\"Not implemented\");\n//        }\n//\n//        /**\n//         * @return the representation of the field\n//         * <code>F<sub>2<sup>m</sup></sub></code>, either of\n//         * TPB (trinomial\n//         * basis representation) or\n//         * PPB (pentanomial\n//         * basis representation).\n//         */\n//        public int getRepresentation()\n//        {\n//            return this.representation;\n//        }\n//\n//        /**\n//         * @return the degree <code>m</code> of the reduction polynomial\n//         * <code>f(z)</code>.\n//         */\n//        public int getM()\n//        {\n//            return this.m;\n//        }\n//\n//        /**\n//         * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +\n//         * x<sup>k</sup> + 1</code> represents the reduction polynomial\n//         * <code>f(z)</code>.<br>\n//         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.<br>\n//         */\n//        public int getK1()\n//        {\n//            return this.k1;\n//        }\n//\n//        /**\n//         * @return TPB: Always returns <code>0</code><br>\n//         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.<br>\n//         */\n//        public int getK2()\n//        {\n//            return this.k2;\n//        }\n//\n//        /**\n//         * @return TPB: Always set to <code>0</code><br>\n//         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +\n//         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n//         * represents the reduction polynomial <code>f(z)</code>.<br>\n//         */\n//        public int getK3()\n//        {\n//            return this.k3;\n//        }\n//\n//        public boolean equals(Object anObject)\n//        {\n//            if (anObject == this) \n//            {\n//                return true;\n//            }\n//\n//            if (!(anObject instanceof ECFieldElement.F2m)) \n//            {\n//                return false;\n//            }\n//\n//            ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;\n//            \n//            return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)\n//                && (this.k3 == b.k3)\n//                && (this.representation == b.representation)\n//                && (this.x.equals(b.x)));\n//        }\n//\n//        public int hashCode()\n//        {\n//            return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;\n//        }\n//    }\n\n    /**\n     * Class representing the Elements of the finite field\n     * <code>F<sub>2<sup>m</sup></sub></code> in polynomial basis (PB)\n     * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial\n     * basis representations are supported. Gaussian normal basis (GNB)\n     * representation is not supported.\n     */\n    public static class F2m extends ECFieldElement\n    {\n        /**\n         * Indicates gaussian normal basis representation (GNB). Number chosen\n         * according to X9.62. GNB is not implemented at present.\n         */\n        public static final int GNB = 1;\n\n        /**\n         * Indicates trinomial basis representation (TPB). Number chosen\n         * according to X9.62.\n         */\n        public static final int TPB = 2;\n\n        /**\n         * Indicates pentanomial basis representation (PPB). Number chosen\n         * according to X9.62.\n         */\n        public static final int PPB = 3;\n\n        /**\n         * TPB or PPB.\n         */\n        private int representation;\n\n        /**\n         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.\n         */\n        private int m;\n\n        /**\n         * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +\n         * x<sup>k</sup> + 1</code> represents the reduction polynomial\n         * <code>f(z)</code>.<br>\n         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        private int k1;\n\n        /**\n         * TPB: Always set to <code>0</code><br>\n         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        private int k2;\n\n        /**\n         * TPB: Always set to <code>0</code><br>\n         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        private int k3;\n\n        /**\n         * The <code>IntArray</code> holding the bits.\n         */\n        private IntArray x;\n\n        /**\n         * The number of <code>int</code>s required to hold <code>m</code> bits.\n         */\n        private int t;\n\n        /**\n         * Constructor for PPB.\n         * @param m  The exponent <code>m</code> of\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.\n         * @param x The BigInteger representing the value of the field element.\n         */\n        public F2m(\n            int m, \n            int k1, \n            int k2, \n            int k3,\n            BigInteger x)\n        {\n            // t = m / 32 rounded up to the next integer\n            t = (m + 31) >> 5;\n            this.x = new IntArray(x, t);\n\n            if ((k2 == 0) && (k3 == 0))\n            {\n                this.representation = TPB;\n            }\n            else\n            {\n                if (k2 >= k3)\n                {\n                    throw new IllegalArgumentException(\n                            \"k2 must be smaller than k3\");\n                }\n                if (k2 <= 0)\n                {\n                    throw new IllegalArgumentException(\n                            \"k2 must be larger than 0\");\n                }\n                this.representation = PPB;\n            }\n\n            if (x.signum() < 0)\n            {\n                throw new IllegalArgumentException(\"x value cannot be negative\");\n            }\n\n            this.m = m;\n            this.k1 = k1;\n            this.k2 = k2;\n            this.k3 = k3;\n        }\n\n        /**\n         * Constructor for TPB.\n         * @param m  The exponent <code>m</code> of\n         * <code>F<sub>2<sup>m</sup></sub></code>.\n         * @param k The integer <code>k</code> where <code>x<sup>m</sup> +\n         * x<sup>k</sup> + 1</code> represents the reduction\n         * polynomial <code>f(z)</code>.\n         * @param x The BigInteger representing the value of the field element.\n         */\n        public F2m(int m, int k, BigInteger x)\n        {\n            // Set k1 to k, and set k2 and k3 to 0\n            this(m, k, 0, 0, x);\n        }\n\n        private F2m(int m, int k1, int k2, int k3, IntArray x)\n        {\n            t = (m + 31) >> 5;\n            this.x = x;\n            this.m = m;\n            this.k1 = k1;\n            this.k2 = k2;\n            this.k3 = k3;\n\n            if ((k2 == 0) && (k3 == 0))\n            {\n                this.representation = TPB;\n            }\n            else\n            {\n                this.representation = PPB;\n            }\n\n        }\n\n        public BigInteger toBigInteger()\n        {\n            return x.toBigInteger();\n        }\n\n        public String getFieldName()\n        {\n            return \"F2m\";\n        }\n\n        public int getFieldSize()\n        {\n            return m;\n        }\n\n        /**\n         * Checks, if the ECFieldElements <code>a</code> and <code>b</code>\n         * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>\n         * (having the same representation).\n         * @param a field element.\n         * @param b field element to be compared.\n         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>\n         * are not elements of the same field\n         * <code>F<sub>2<sup>m</sup></sub></code> (having the same\n         * representation). \n         */\n        public static void checkFieldElements(\n            ECFieldElement a,\n            ECFieldElement b)\n        {\n            if ((!(a instanceof F2m)) || (!(b instanceof F2m)))\n            {\n                throw new IllegalArgumentException(\"Field elements are not \"\n                        + \"both instances of ECFieldElement.F2m\");\n            }\n\n            ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a;\n            ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b;\n\n            if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)\n                    || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))\n            {\n                throw new IllegalArgumentException(\"Field elements are not \"\n                        + \"elements of the same field F2m\");\n            }\n\n            if (aF2m.representation != bF2m.representation)\n            {\n                // Should never occur\n                throw new IllegalArgumentException(\n                        \"One of the field \"\n                                + \"elements are not elements has incorrect representation\");\n            }\n        }\n\n        public ECFieldElement add(final ECFieldElement b)\n        {\n            // No check performed here for performance reasons. Instead the\n            // elements involved are checked in ECPoint.F2m\n            // checkFieldElements(this, b);\n            IntArray iarrClone = (IntArray)this.x.clone();\n            F2m bF2m = (F2m)b;\n            iarrClone.addShifted(bF2m.x, 0);\n            return new F2m(m, k1, k2, k3, iarrClone);\n        }\n\n        public ECFieldElement subtract(final ECFieldElement b)\n        {\n            // Addition and subtraction are the same in F2m\n            return add(b);\n        }\n\n        public ECFieldElement multiply(final ECFieldElement b)\n        {\n            // Right-to-left comb multiplication in the IntArray\n            // Input: Binary polynomials a(z) and b(z) of degree at most m-1\n            // Output: c(z) = a(z) * b(z) mod f(z)\n\n            // No check performed here for performance reasons. Instead the\n            // elements involved are checked in ECPoint.F2m\n            // checkFieldElements(this, b);\n            F2m bF2m = (F2m)b;\n            IntArray mult = x.multiply(bF2m.x, m);\n            mult.reduce(m, new int[]{k1, k2, k3});\n            return new F2m(m, k1, k2, k3, mult);\n        }\n\n        public ECFieldElement divide(final ECFieldElement b)\n        {\n            // There may be more efficient implementations\n            ECFieldElement bInv = b.invert();\n            return multiply(bInv);\n        }\n\n        public ECFieldElement negate()\n        {\n            // -x == x holds for all x in F2m\n            return this;\n        }\n\n        public ECFieldElement square()\n        {\n            IntArray squared = x.square(m);\n            squared.reduce(m, new int[]{k1, k2, k3});\n            return new F2m(m, k1, k2, k3, squared);\n        }\n\n\n        public ECFieldElement invert()\n        {\n            // Inversion in F2m using the extended Euclidean algorithm\n            // Input: A nonzero polynomial a(z) of degree at most m-1\n            // Output: a(z)^(-1) mod f(z)\n\n            // u(z) := a(z)\n            IntArray uz = (IntArray)this.x.clone();\n\n            // v(z) := f(z)\n            IntArray vz = new IntArray(t);\n            vz.setBit(m);\n            vz.setBit(0);\n            vz.setBit(this.k1);\n            if (this.representation == PPB) \n            {\n                vz.setBit(this.k2);\n                vz.setBit(this.k3);\n            }\n\n            // g1(z) := 1, g2(z) := 0\n            IntArray g1z = new IntArray(t);\n            g1z.setBit(0);\n            IntArray g2z = new IntArray(t);\n\n            // while u != 0\n            while (!uz.isZero())\n//            while (uz.getUsedLength() > 0)\n//            while (uz.bitLength() > 1)\n            {\n                // j := deg(u(z)) - deg(v(z))\n                int j = uz.bitLength() - vz.bitLength();\n\n                // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j\n                if (j < 0) \n                {\n                    final IntArray uzCopy = uz;\n                    uz = vz;\n                    vz = uzCopy;\n\n                    final IntArray g1zCopy = g1z;\n                    g1z = g2z;\n                    g2z = g1zCopy;\n\n                    j = -j;\n                }\n\n                // u(z) := u(z) + z^j * v(z)\n                // Note, that no reduction modulo f(z) is required, because\n                // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z)))\n                // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z))\n                // = deg(u(z))\n                // uz = uz.xor(vz.shiftLeft(j));\n                // jInt = n / 32\n                int jInt = j >> 5;\n                // jInt = n % 32\n                int jBit = j & 0x1F;\n                IntArray vzShift = vz.shiftLeft(jBit);\n                uz.addShifted(vzShift, jInt);\n\n                // g1(z) := g1(z) + z^j * g2(z)\n//                g1z = g1z.xor(g2z.shiftLeft(j));\n                IntArray g2zShift = g2z.shiftLeft(jBit);\n                g1z.addShifted(g2zShift, jInt);\n                \n            }\n            return new ECFieldElement.F2m(\n                    this.m, this.k1, this.k2, this.k3, g2z);\n        }\n\n        public ECFieldElement sqrt()\n        {\n            throw new RuntimeException(\"Not implemented\");\n        }\n\n        /**\n         * @return the representation of the field\n         * <code>F<sub>2<sup>m</sup></sub></code>, either of\n         * TPB (trinomial\n         * basis representation) or\n         * PPB (pentanomial\n         * basis representation).\n         */\n        public int getRepresentation()\n        {\n            return this.representation;\n        }\n\n        /**\n         * @return the degree <code>m</code> of the reduction polynomial\n         * <code>f(z)</code>.\n         */\n        public int getM()\n        {\n            return this.m;\n        }\n\n        /**\n         * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +\n         * x<sup>k</sup> + 1</code> represents the reduction polynomial\n         * <code>f(z)</code>.<br>\n         * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        public int getK1()\n        {\n            return this.k1;\n        }\n\n        /**\n         * @return TPB: Always returns <code>0</code><br>\n         * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        public int getK2()\n        {\n            return this.k2;\n        }\n\n        /**\n         * @return TPB: Always set to <code>0</code><br>\n         * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +\n         * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>\n         * represents the reduction polynomial <code>f(z)</code>.<br>\n         */\n        public int getK3()\n        {\n            return this.k3;\n        }\n\n        public boolean equals(Object anObject)\n        {\n            if (anObject == this) \n            {\n                return true;\n            }\n\n            if (!(anObject instanceof ECFieldElement.F2m)) \n            {\n                return false;\n            }\n\n            ECFieldElement.F2m b = (ECFieldElement.F2m)anObject;\n            \n            return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2)\n                && (this.k3 == b.k3)\n                && (this.representation == b.representation)\n                && (this.x.equals(b.x)));\n        }\n\n        public int hashCode()\n        {\n            return x.hashCode() ^ m ^ k1 ^ k2 ^ k3;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/ECMultiplier.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Interface for classes encapsulating a point multiplication algorithm\n * for <code>ECPoint</code>s.\n */\ninterface ECMultiplier\n{\n    /**\n     * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.\n     * <code>p</code> is added <code>k</code> times to itself.\n     * @param p The <code>ECPoint</code> to be multiplied.\n     * @param k The factor by which <code>p</code> i multiplied.\n     * @return <code>p</code> multiplied by <code>k</code>.\n     */\n    ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/ECPoint.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.asn1.x9.X9IntegerConverter;\n\n\n/**\n * base class for points on elliptic curves.\n */\npublic abstract class ECPoint\n{\n    ECCurve        curve;\n    ECFieldElement x;\n    ECFieldElement y;\n\n    protected boolean withCompression;\n\n    protected ECMultiplier multiplier = null;\n\n    protected PreCompInfo preCompInfo = null;\n\n    private static X9IntegerConverter converter = new X9IntegerConverter();\n\n    protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)\n    {\n        this.curve = curve;\n        this.x = x;\n        this.y = y;\n    }\n    \n    public ECCurve getCurve()\n    {\n        return curve;\n    }\n    \n    public ECFieldElement getX()\n    {\n        return x;\n    }\n\n    public ECFieldElement getY()\n    {\n        return y;\n    }\n\n    public boolean isInfinity()\n    {\n        return x == null && y == null;\n    }\n\n    public boolean isCompressed()\n    {\n        return withCompression;\n    }\n\n    public boolean equals(\n        Object  other)\n    {\n        if (other == this)\n        {\n            return true;\n        }\n\n        if (!(other instanceof ECPoint))\n        {\n            return false;\n        }\n\n        ECPoint o = (ECPoint)other;\n\n        if (this.isInfinity())\n        {\n            return o.isInfinity();\n        }\n\n        return x.equals(o.x) && y.equals(o.y);\n    }\n\n    public int hashCode()\n    {\n        if (this.isInfinity())\n        {\n            return 0;\n        }\n        \n        return x.hashCode() ^ y.hashCode();\n    }\n\n//    /**\n//     * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.\n//     * @param multiplier The <code>ECMultiplier</code> to be used to multiply\n//     * this <code>ECPoint</code>.\n//     */\n//    public void setECMultiplier(ECMultiplier multiplier)\n//    {\n//        this.multiplier = multiplier;\n//    }\n\n    /**\n     * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s\n     * to save the precomputation for this <code>ECPoint</code> to store the\n     * precomputation result for use by subsequent multiplication.\n     * @param preCompInfo The values precomputed by the\n     * <code>ECMultiplier</code>.\n     */\n    void setPreCompInfo(PreCompInfo preCompInfo)\n    {\n        this.preCompInfo = preCompInfo;\n    }\n\n    public byte[] getEncoded()\n    {\n        return getEncoded(withCompression);\n    }\n\n    public abstract byte[] getEncoded(boolean compressed);\n\n    public abstract ECPoint add(ECPoint b);\n    public abstract ECPoint subtract(ECPoint b);\n    public abstract ECPoint negate();\n    public abstract ECPoint twice();\n\n    /**\n     * Sets the default <code>ECMultiplier</code>, unless already set. \n     */\n    synchronized void assertECMultiplier()\n    {\n        if (this.multiplier == null)\n        {\n            this.multiplier = new FpNafMultiplier();\n        }\n    }\n\n    /**\n     * Multiplies this <code>ECPoint</code> by the given number.\n     * @param k The multiplicator.\n     * @return <code>k * this</code>.\n     */\n    public ECPoint multiply(BigInteger k)\n    {\n        if (k.signum() < 0)\n        {\n            throw new IllegalArgumentException(\"The multiplicator cannot be negative\");\n        }\n\n        if (this.isInfinity())\n        {\n            return this;\n        }\n\n        if (k.signum() == 0)\n        {\n            return this.curve.getInfinity();\n        }\n\n        assertECMultiplier();\n        return this.multiplier.multiply(this, k, preCompInfo);\n    }\n\n    /**\n     * Elliptic curve points over Fp\n     */\n    public static class Fp extends ECPoint\n    {\n        \n        /**\n         * Create a point which encodes with point compression.\n         * \n         * @param curve the curve to use\n         * @param x affine x co-ordinate\n         * @param y affine y co-ordinate\n         */\n        public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)\n        {\n            this(curve, x, y, false);\n        }\n\n        /**\n         * Create a point that encodes with or without point compresion.\n         * \n         * @param curve the curve to use\n         * @param x affine x co-ordinate\n         * @param y affine y co-ordinate\n         * @param withCompression if true encode with point compression\n         */\n        public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)\n        {\n            super(curve, x, y);\n\n            if ((x != null && y == null) || (x == null && y != null))\n            {\n                throw new IllegalArgumentException(\"Exactly one of the field elements is null\");\n            }\n\n            this.withCompression = withCompression;\n        }\n         \n        /**\n         * return the field element encoded with point compression. (S 4.3.6)\n         */\n        public byte[] getEncoded(boolean compressed)\n        {\n            if (this.isInfinity()) \n            {\n                return new byte[1];\n            }\n\n            int qLength = converter.getByteLength(x);\n            \n            if (compressed)\n            {\n                byte    PC;\n    \n                if (this.getY().toBigInteger().testBit(0))\n                {\n                    PC = 0x03;\n                }\n                else\n                {\n                    PC = 0x02;\n                }\n    \n                byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);\n                byte[]  PO = new byte[X.length + 1];\n    \n                PO[0] = PC;\n                System.arraycopy(X, 0, PO, 1, X.length);\n    \n                return PO;\n            }\n            else\n            {\n                byte[]  X = converter.integerToBytes(this.getX().toBigInteger(), qLength);\n                byte[]  Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);\n                byte[]  PO = new byte[X.length + Y.length + 1];\n                \n                PO[0] = 0x04;\n                System.arraycopy(X, 0, PO, 1, X.length);\n                System.arraycopy(Y, 0, PO, X.length + 1, Y.length);\n\n                return PO;\n            }\n        }\n\n        // B.3 pg 62\n        public ECPoint add(ECPoint b)\n        {\n            if (this.isInfinity())\n            {\n                return b;\n            }\n\n            if (b.isInfinity())\n            {\n                return this;\n            }\n\n            // Check if b = this or b = -this\n            if (this.x.equals(b.x))\n            {\n                if (this.y.equals(b.y))\n                {\n                    // this = b, i.e. this must be doubled\n                    return this.twice();\n                }\n\n                // this = -b, i.e. the result is the point at infinity\n                return this.curve.getInfinity();\n            }\n\n            ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));\n\n            ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);\n            ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);\n\n            return new ECPoint.Fp(curve, x3, y3, withCompression);\n        }\n\n        // B.3 pg 62\n        public ECPoint twice()\n        {\n            if (this.isInfinity())\n            {\n                // Twice identity element (point at infinity) is identity\n                return this;\n            }\n\n            if (this.y.toBigInteger().signum() == 0) \n            {\n                // if y1 == 0, then (x1, y1) == (x1, -y1)\n                // and hence this = -this and thus 2(x1, y1) == infinity\n                return this.curve.getInfinity();\n            }\n\n            ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));\n            ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));\n            ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));\n\n            ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));\n            ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);\n                \n            return new ECPoint.Fp(curve, x3, y3, this.withCompression);\n        }\n\n        // D.3.2 pg 102 (see Note:)\n        public ECPoint subtract(ECPoint b)\n        {\n            if (b.isInfinity())\n            {\n                return this;\n            }\n\n            // Add -b\n            return add(b.negate());\n        }\n\n        public ECPoint negate()\n        {\n            return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);\n        }\n\n        /**\n         * Sets the default <code>ECMultiplier</code>, unless already set. \n         */\n        synchronized void assertECMultiplier()\n        {\n            if (this.multiplier == null)\n            {\n                this.multiplier = new WNafMultiplier();\n            }\n        }\n    }\n\n    /**\n     * Elliptic curve points over F2m\n     */\n    public static class F2m extends ECPoint\n    {\n        /**\n         * @param curve base curve\n         * @param x x point\n         * @param y y point\n         */\n        public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)\n        {\n            this(curve, x, y, false);\n        }\n        \n        /**\n         * @param curve base curve\n         * @param x x point\n         * @param y y point\n         * @param withCompression true if encode with point compression.\n         */\n        public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)\n        {\n            super(curve, x, y);\n\n            if ((x != null && y == null) || (x == null && y != null))\n            {\n                throw new IllegalArgumentException(\"Exactly one of the field elements is null\");\n            }\n            \n            if (x != null)\n            {\n                // Check if x and y are elements of the same field\n                ECFieldElement.F2m.checkFieldElements(this.x, this.y);\n    \n                // Check if x and a are elements of the same field\n                if (curve != null)\n                {\n                    ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());\n                }\n            }\n            \n            this.withCompression = withCompression;\n        }\n\n        /* (non-Javadoc)\n         * @see org.bouncycastle.math.ec.ECPoint#getEncoded()\n         */\n        public byte[] getEncoded(boolean compressed)\n        {\n            if (this.isInfinity()) \n            {\n                return new byte[1];\n            }\n\n            int byteCount = converter.getByteLength(this.x);\n            byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);\n            byte[] PO;\n\n            if (compressed)\n            {\n                // See X9.62 4.3.6 and 4.2.2\n                PO = new byte[byteCount + 1];\n\n                PO[0] = 0x02;\n                // X9.62 4.2.2 and 4.3.6:\n                // if x = 0 then ypTilde := 0, else ypTilde is the rightmost\n                // bit of y * x^(-1)\n                // if ypTilde = 0, then PC := 02, else PC := 03\n                // Note: PC === PO[0]\n                if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))\n                {\n                    if (this.getY().multiply(this.getX().invert())\n                            .toBigInteger().testBit(0))\n                    {\n                        // ypTilde = 1, hence PC = 03\n                        PO[0] = 0x03;\n                    }\n                }\n\n                System.arraycopy(X, 0, PO, 1, byteCount);\n            }\n            else\n            {\n                byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);\n    \n                PO = new byte[byteCount + byteCount + 1];\n    \n                PO[0] = 0x04;\n                System.arraycopy(X, 0, PO, 1, byteCount);\n                System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);    \n            }\n\n            return PO;\n        }\n\n        /**\n         * Check, if two <code>ECPoint</code>s can be added or subtracted.\n         * @param a The first <code>ECPoint</code> to check.\n         * @param b The second <code>ECPoint</code> to check.\n         * @throws IllegalArgumentException if <code>a</code> and <code>b</code>\n         * cannot be added.\n         */\n        private static void checkPoints(ECPoint a, ECPoint b)\n        {\n            // Check, if points are on the same curve\n            if (!(a.curve.equals(b.curve)))\n            {\n                throw new IllegalArgumentException(\"Only points on the same \"\n                        + \"curve can be added or subtracted\");\n            }\n\n//            ECFieldElement.F2m.checkFieldElements(a.x, b.x);\n        }\n\n        /* (non-Javadoc)\n         * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)\n         */\n        public ECPoint add(ECPoint b)\n        {\n            checkPoints(this, b);\n            return addSimple((ECPoint.F2m)b);\n        }\n\n        /**\n         * Adds another <code>ECPoints.F2m</code> to <code>this</code> without\n         * checking if both points are on the same curve. Used by multiplication\n         * algorithms, because there all points are a multiple of the same point\n         * and hence the checks can be omitted.\n         * @param b The other <code>ECPoints.F2m</code> to add to\n         * <code>this</code>.\n         * @return <code>this + b</code>\n         */\n        public ECPoint.F2m addSimple(ECPoint.F2m b)\n        {\n            ECPoint.F2m other = b;\n            if (this.isInfinity())\n            {\n                return other;\n            }\n\n            if (other.isInfinity())\n            {\n                return this;\n            }\n\n            ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();\n            ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();\n\n            // Check if other = this or other = -this\n            if (this.x.equals(x2))\n            {\n                if (this.y.equals(y2))\n                {\n                    // this = other, i.e. this must be doubled\n                    return (ECPoint.F2m)this.twice();\n                }\n\n                // this = -other, i.e. the result is the point at infinity\n                return (ECPoint.F2m)this.curve.getInfinity();\n            }\n\n            ECFieldElement.F2m lambda\n                = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));\n\n            ECFieldElement.F2m x3\n                = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());\n\n            ECFieldElement.F2m y3\n                = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);\n\n            return new ECPoint.F2m(curve, x3, y3, withCompression);\n        }\n\n        /* (non-Javadoc)\n         * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)\n         */\n        public ECPoint subtract(ECPoint b)\n        {\n            checkPoints(this, b);\n            return subtractSimple((ECPoint.F2m)b);\n        }\n\n        /**\n         * Subtracts another <code>ECPoints.F2m</code> from <code>this</code>\n         * without checking if both points are on the same curve. Used by\n         * multiplication algorithms, because there all points are a multiple\n         * of the same point and hence the checks can be omitted.\n         * @param b The other <code>ECPoints.F2m</code> to subtract from\n         * <code>this</code>.\n         * @return <code>this - b</code>\n         */\n        public ECPoint.F2m subtractSimple(ECPoint.F2m b)\n        {\n            if (b.isInfinity())\n            {\n                return this;\n            }\n\n            // Add -b\n            return addSimple((ECPoint.F2m)b.negate());\n        }\n\n        /* (non-Javadoc)\n         * @see org.bouncycastle.math.ec.ECPoint#twice()\n         */\n        public ECPoint twice()\n        {\n            if (this.isInfinity()) \n            {\n                // Twice identity element (point at infinity) is identity\n                return this;\n            }\n\n            if (this.x.toBigInteger().signum() == 0) \n            {\n                // if x1 == 0, then (x1, y1) == (x1, x1 + y1)\n                // and hence this = -this and thus 2(x1, y1) == infinity\n                return this.curve.getInfinity();\n            }\n\n            ECFieldElement.F2m lambda\n                = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));\n\n            ECFieldElement.F2m x3\n                = (ECFieldElement.F2m)lambda.square().add(lambda).\n                    add(this.curve.getA());\n\n            ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);\n            ECFieldElement.F2m y3\n                = (ECFieldElement.F2m)this.x.square().add(\n                    x3.multiply(lambda.add(ONE)));\n\n            return new ECPoint.F2m(this.curve, x3, y3, withCompression);\n        }\n\n        public ECPoint negate()\n        {\n            return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);\n        }\n\n        /**\n         * Sets the appropriate <code>ECMultiplier</code>, unless already set. \n         */\n        synchronized void assertECMultiplier()\n        {\n            if (this.multiplier == null)\n            {\n                if (((ECCurve.F2m)this.curve).isKoblitz())\n                {\n                    this.multiplier = new WTauNafMultiplier();\n                }\n                else\n                {\n                    this.multiplier = new WNafMultiplier();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/FpNafMultiplier.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.\n */\nclass FpNafMultiplier implements ECMultiplier\n{\n    /**\n     * D.3.2 pg 101\n     * @see local.org.bouncycastle.math.ec.ECMultiplier#multiply(local.org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)\n     */\n    public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)\n    {\n        // TODO Probably should try to add this\n        // BigInteger e = k.mod(n); // n == order of p\n        BigInteger e = k;\n        BigInteger h = e.multiply(BigInteger.valueOf(3));\n\n        ECPoint neg = p.negate();\n        ECPoint R = p;\n\n        for (int i = h.bitLength() - 2; i > 0; --i)\n        {             \n            R = R.twice();\n\n            boolean hBit = h.testBit(i);\n            boolean eBit = e.testBit(i);\n\n            if (hBit != eBit)\n            {\n                R = R.add(hBit ? p : neg);\n            }\n        }\n\n        return R;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/IntArray.java",
    "content": "package local.org.bouncycastle.math.ec;\n\n\nimport java.math.BigInteger;\n\nimport local.org.bouncycastle.util.Arrays;\n\nclass IntArray\n{\n    // TODO make m fixed for the IntArray, and hence compute T once and for all\n\n    private int[] m_ints;\n\n    public IntArray(int intLen)\n    {\n        m_ints = new int[intLen];\n    }\n\n    public IntArray(int[] ints)\n    {\n        m_ints = ints;\n    }\n\n    public IntArray(BigInteger bigInt)\n    {\n        this(bigInt, 0);\n    }\n\n    public IntArray(BigInteger bigInt, int minIntLen)\n    {\n        if (bigInt.signum() == -1)\n        {\n            throw new IllegalArgumentException(\"Only positive Integers allowed\");\n        }\n        if (bigInt.equals(ECConstants.ZERO))\n        {\n            m_ints = new int[] { 0 };\n            return;\n        }\n\n        byte[] barr = bigInt.toByteArray();\n        int barrLen = barr.length;\n        int barrStart = 0;\n        if (barr[0] == 0)\n        {\n            // First byte is 0 to enforce highest (=sign) bit is zero.\n            // In this case ignore barr[0].\n            barrLen--;\n            barrStart = 1;\n        }\n        int intLen = (barrLen + 3) / 4;\n        if (intLen < minIntLen)\n        {\n            m_ints = new int[minIntLen];\n        }\n        else\n        {\n            m_ints = new int[intLen];\n        }\n\n        int iarrJ = intLen - 1;\n        int rem = barrLen % 4 + barrStart;\n        int temp = 0;\n        int barrI = barrStart;\n        if (barrStart < rem)\n        {\n            for (; barrI < rem; barrI++)\n            {\n                temp <<= 8;\n                int barrBarrI = barr[barrI];\n                if (barrBarrI < 0)\n                {\n                    barrBarrI += 256;\n                }\n                temp |= barrBarrI;\n            }\n            m_ints[iarrJ--] = temp;\n        }\n\n        for (; iarrJ >= 0; iarrJ--)\n        {\n            temp = 0;\n            for (int i = 0; i < 4; i++)\n            {\n                temp <<= 8;\n                int barrBarrI = barr[barrI++];\n                if (barrBarrI < 0)\n                {\n                    barrBarrI += 256;\n                }\n                temp |= barrBarrI;\n            }\n            m_ints[iarrJ] = temp;\n        }\n    }\n\n    public boolean isZero()\n    {\n        return m_ints.length == 0\n            || (m_ints[0] == 0 && getUsedLength() == 0);\n    }\n\n    public int getUsedLength()\n    {\n        int highestIntPos = m_ints.length;\n\n        if (highestIntPos < 1)\n        {\n            return 0;\n        }\n\n        // Check if first element will act as sentinel\n        if (m_ints[0] != 0)\n        {\n            while (m_ints[--highestIntPos] == 0)\n            {\n            }\n            return highestIntPos + 1;\n        }\n\n        do\n        {\n            if (m_ints[--highestIntPos] != 0)\n            {\n                return highestIntPos + 1;\n            }\n        }\n        while (highestIntPos > 0);\n\n        return 0;\n    }\n\n    public int bitLength()\n    {\n        // JDK 1.5: see Integer.numberOfLeadingZeros()\n        int intLen = getUsedLength();\n        if (intLen == 0)\n        {\n            return 0;\n        }\n\n        int last = intLen - 1;\n        int highest = m_ints[last];\n        int bits = (last << 5) + 1;\n\n        // A couple of binary search steps\n        if ((highest & 0xffff0000) != 0)\n        {\n            if ((highest & 0xff000000) != 0)\n            {\n                bits += 24;\n                highest >>>= 24;\n            }\n            else\n            {\n                bits += 16;\n                highest >>>= 16;\n            }\n        }\n        else if (highest > 0x000000ff)\n        {\n            bits += 8;\n            highest >>>= 8;\n        }\n\n        while (highest != 1)\n        {\n            ++bits;\n            highest >>>= 1;\n        }\n\n        return bits;\n    }\n\n    private int[] resizedInts(int newLen)\n    {\n        int[] newInts = new int[newLen];\n        int oldLen = m_ints.length;\n        int copyLen = oldLen < newLen ? oldLen : newLen;\n        System.arraycopy(m_ints, 0, newInts, 0, copyLen);\n        return newInts;\n    }\n\n    public BigInteger toBigInteger()\n    {\n        int usedLen = getUsedLength();\n        if (usedLen == 0)\n        {\n            return ECConstants.ZERO;\n        }\n\n        int highestInt = m_ints[usedLen - 1];\n        byte[] temp = new byte[4];\n        int barrI = 0;\n        boolean trailingZeroBytesDone = false;\n        for (int j = 3; j >= 0; j--)\n        {\n            byte thisByte = (byte) (highestInt >>> (8 * j));\n            if (trailingZeroBytesDone || (thisByte != 0))\n            {\n                trailingZeroBytesDone = true;\n                temp[barrI++] = thisByte;\n            }\n        }\n\n        int barrLen = 4 * (usedLen - 1) + barrI;\n        byte[] barr = new byte[barrLen];\n        for (int j = 0; j < barrI; j++)\n        {\n            barr[j] = temp[j];\n        }\n        // Highest value int is done now\n\n        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)\n        {\n            for (int j = 3; j >= 0; j--)\n            {\n                barr[barrI++] = (byte) (m_ints[iarrJ] >>> (8 * j));\n            }\n        }\n        return new BigInteger(1, barr);\n    }\n\n    public void shiftLeft()\n    {\n        int usedLen = getUsedLength();\n        if (usedLen == 0)\n        {\n            return;\n        }\n        if (m_ints[usedLen - 1] < 0)\n        {\n            // highest bit of highest used byte is set, so shifting left will\n            // make the IntArray one byte longer\n            usedLen++;\n            if (usedLen > m_ints.length)\n            {\n                // make the m_ints one byte longer, because we need one more\n                // byte which is not available in m_ints\n                m_ints = resizedInts(m_ints.length + 1);\n            }\n        }\n\n        boolean carry = false;\n        for (int i = 0; i < usedLen; i++)\n        {\n            // nextCarry is true if highest bit is set\n            boolean nextCarry = m_ints[i] < 0;\n            m_ints[i] <<= 1;\n            if (carry)\n            {\n                // set lowest bit\n                m_ints[i] |= 1;\n            }\n            carry = nextCarry;\n        }\n    }\n\n    public IntArray shiftLeft(int n)\n    {\n        int usedLen = getUsedLength();\n        if (usedLen == 0)\n        {\n            return this;\n        }\n\n        if (n == 0)\n        {\n            return this;\n        }\n\n        if (n > 31)\n        {\n            throw new IllegalArgumentException(\"shiftLeft() for max 31 bits \"\n                + \", \" + n + \"bit shift is not possible\");\n        }\n\n        int[] newInts = new int[usedLen + 1];\n\n        int nm32 = 32 - n;\n        newInts[0] = m_ints[0] << n;\n        for (int i = 1; i < usedLen; i++)\n        {\n            newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);\n        }\n        newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;\n\n        return new IntArray(newInts);\n    }\n\n    public void addShifted(IntArray other, int shift)\n    {\n        int usedLenOther = other.getUsedLength();\n        int newMinUsedLen = usedLenOther + shift;\n        if (newMinUsedLen > m_ints.length)\n        {\n            m_ints = resizedInts(newMinUsedLen);\n            //System.out.println(\"Resize required\");\n        }\n\n        for (int i = 0; i < usedLenOther; i++)\n        {\n            m_ints[i + shift] ^= other.m_ints[i];\n        }\n    }\n\n    public int getLength()\n    {\n        return m_ints.length;\n    }\n\n    public boolean testBit(int n)\n    {\n        // theInt = n / 32\n        int theInt = n >> 5;\n        // theBit = n % 32\n        int theBit = n & 0x1F;\n        int tester = 1 << theBit;\n        return ((m_ints[theInt] & tester) != 0);\n    }\n\n    public void flipBit(int n)\n    {\n        // theInt = n / 32\n        int theInt = n >> 5;\n        // theBit = n % 32\n        int theBit = n & 0x1F;\n        int flipper = 1 << theBit;\n        m_ints[theInt] ^= flipper;\n    }\n\n    public void setBit(int n)\n    {\n        // theInt = n / 32\n        int theInt = n >> 5;\n        // theBit = n % 32\n        int theBit = n & 0x1F;\n        int setter = 1 << theBit;\n        m_ints[theInt] |= setter;\n    }\n\n    public IntArray multiply(IntArray other, int m)\n    {\n        // Lenght of c is 2m bits rounded up to the next int (32 bit)\n        int t = (m + 31) >> 5;\n        if (m_ints.length < t)\n        {\n            m_ints = resizedInts(t);\n        }\n\n        IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));\n        IntArray c = new IntArray((m + m + 31) >> 5);\n        // IntArray c = new IntArray(t + t);\n        int testBit = 1;\n        for (int k = 0; k < 32; k++)\n        {\n            for (int j = 0; j < t; j++)\n            {\n                if ((m_ints[j] & testBit) != 0)\n                {\n                    // The kth bit of m_ints[j] is set\n                    c.addShifted(b, j);\n                }\n            }\n            testBit <<= 1;\n            b.shiftLeft();\n        }\n        return c;\n    }\n\n    // public IntArray multiplyLeftToRight(IntArray other, int m) {\n    // // Lenght of c is 2m bits rounded up to the next int (32 bit)\n    // int t = (m + 31) / 32;\n    // if (m_ints.length < t) {\n    // m_ints = resizedInts(t);\n    // }\n    //\n    // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));\n    // IntArray c = new IntArray((m + m + 31) / 32);\n    // // IntArray c = new IntArray(t + t);\n    // int testBit = 1 << 31;\n    // for (int k = 31; k >= 0; k--) {\n    // for (int j = 0; j < t; j++) {\n    // if ((m_ints[j] & testBit) != 0) {\n    // // The kth bit of m_ints[j] is set\n    // c.addShifted(b, j);\n    // }\n    // }\n    // testBit >>>= 1;\n    // if (k > 0) {\n    // c.shiftLeft();\n    // }\n    // }\n    // return c;\n    // }\n\n    // TODO note, redPol.length must be 3 for TPB and 5 for PPB\n    public void reduce(int m, int[] redPol)\n    {\n        for (int i = m + m - 2; i >= m; i--)\n        {\n            if (testBit(i))\n            {\n                int bit = i - m;\n                flipBit(bit);\n                flipBit(i);\n                int l = redPol.length;\n                while (--l >= 0)\n                {\n                    flipBit(redPol[l] + bit);\n                }\n            }\n        }\n        m_ints = resizedInts((m + 31) >> 5);\n    }\n\n    public IntArray square(int m)\n    {\n        // TODO make the table static final\n        final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,\n            0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };\n\n        int t = (m + 31) >> 5;\n        if (m_ints.length < t)\n        {\n            m_ints = resizedInts(t);\n        }\n\n        IntArray c = new IntArray(t + t);\n\n        // TODO twice the same code, put in separate private method\n        for (int i = 0; i < t; i++)\n        {\n            int v0 = 0;\n            for (int j = 0; j < 4; j++)\n            {\n                v0 = v0 >>> 8;\n                int u = (m_ints[i] >>> (j * 4)) & 0xF;\n                int w = table[u] << 24;\n                v0 |= w;\n            }\n            c.m_ints[i + i] = v0;\n\n            v0 = 0;\n            int upper = m_ints[i] >>> 16;\n            for (int j = 0; j < 4; j++)\n            {\n                v0 = v0 >>> 8;\n                int u = (upper >>> (j * 4)) & 0xF;\n                int w = table[u] << 24;\n                v0 |= w;\n            }\n            c.m_ints[i + i + 1] = v0;\n        }\n        return c;\n    }\n\n    public boolean equals(Object o)\n    {\n        if (!(o instanceof IntArray))\n        {\n            return false;\n        }\n        IntArray other = (IntArray) o;\n        int usedLen = getUsedLength();\n        if (other.getUsedLength() != usedLen)\n        {\n            return false;\n        }\n        for (int i = 0; i < usedLen; i++)\n        {\n            if (m_ints[i] != other.m_ints[i])\n            {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public int hashCode()\n    {\n        int usedLen = getUsedLength();\n        int hash = 1;\n        for (int i = 0; i < usedLen; i++)\n        {\n            hash = hash * 31 + m_ints[i];\n        }\n        return hash;\n    }\n\n    public Object clone()\n    {\n        return new IntArray(Arrays.clone(m_ints));\n    }\n\n    public String toString()\n    {\n        int usedLen = getUsedLength();\n        if (usedLen == 0)\n        {\n            return \"0\";\n        }\n\n        StringBuffer sb = new StringBuffer(Integer\n            .toBinaryString(m_ints[usedLen - 1]));\n        for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)\n        {\n            String hexString = Integer.toBinaryString(m_ints[iarrJ]);\n\n            // Add leading zeroes, except for highest significant int\n            for (int i = hexString.length(); i < 8; i++)\n            {\n                hexString = \"0\" + hexString;\n            }\n            sb.append(hexString);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/PreCompInfo.java",
    "content": "package local.org.bouncycastle.math.ec;\n\n/**\n * Interface for classes storing precomputation data for multiplication\n * algorithms. Used as a Memento (see GOF patterns) for\n * <code>WNafMultiplier</code>.\n */\ninterface PreCompInfo\n{\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/SimpleBigDecimal.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Class representing a simple version of a big decimal. A\n * <code>SimpleBigDecimal</code> is basically a\n * {@link java.math.BigInteger BigInteger} with a few digits on the right of\n * the decimal point. The number of (binary) digits on the right of the decimal\n * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.\n * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted\n * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s\n * taking part in the same arithmetic operation must have equal scale. The\n * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a\n * <code>SimpleBigDecimal</code> with double scale.\n */\nclass SimpleBigDecimal\n    //extends Number   // not in J2ME - add compatibility class?\n{\n    private static final long serialVersionUID = 1L;\n\n    private final BigInteger bigInt;\n    private final int scale;\n\n    /**\n     * Returns a <code>SimpleBigDecimal</code> representing the same numerical\n     * value as <code>value</code>.\n     * @param value The value of the <code>SimpleBigDecimal</code> to be\n     * created. \n     * @param scale The scale of the <code>SimpleBigDecimal</code> to be\n     * created. \n     * @return The such created <code>SimpleBigDecimal</code>.\n     */\n    public static SimpleBigDecimal getInstance(BigInteger value, int scale)\n    {\n        return new SimpleBigDecimal(value.shiftLeft(scale), scale);\n    }\n\n    /**\n     * Constructor for <code>SimpleBigDecimal</code>. The value of the\n     * constructed <code>SimpleBigDecimal</code> equals <code>bigInt / \n     * 2<sup>scale</sup></code>.\n     * @param bigInt The <code>bigInt</code> value parameter.\n     * @param scale The scale of the constructed <code>SimpleBigDecimal</code>.\n     */\n    public SimpleBigDecimal(BigInteger bigInt, int scale)\n    {\n        if (scale < 0)\n        {\n            throw new IllegalArgumentException(\"scale may not be negative\");\n        }\n\n        this.bigInt = bigInt;\n        this.scale = scale;\n    }\n\n    private SimpleBigDecimal(SimpleBigDecimal limBigDec)\n    {\n        bigInt = limBigDec.bigInt;\n        scale = limBigDec.scale;\n    }\n\n    private void checkScale(SimpleBigDecimal b)\n    {\n        if (scale != b.scale)\n        {\n            throw new IllegalArgumentException(\"Only SimpleBigDecimal of \" +\n                \"same scale allowed in arithmetic operations\");\n        }\n    }\n\n    public SimpleBigDecimal adjustScale(int newScale)\n    {\n        if (newScale < 0)\n        {\n            throw new IllegalArgumentException(\"scale may not be negative\");\n        }\n\n        if (newScale == scale)\n        {\n            return new SimpleBigDecimal(this);\n        }\n\n        return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),\n                newScale);\n    }\n\n    public SimpleBigDecimal add(SimpleBigDecimal b)\n    {\n        checkScale(b);\n        return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);\n    }\n\n    public SimpleBigDecimal add(BigInteger b)\n    {\n        return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale);\n    }\n\n    public SimpleBigDecimal negate()\n    {\n        return new SimpleBigDecimal(bigInt.negate(), scale);\n    }\n\n    public SimpleBigDecimal subtract(SimpleBigDecimal b)\n    {\n        return add(b.negate());\n    }\n\n    public SimpleBigDecimal subtract(BigInteger b)\n    {\n        return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)),\n                scale);\n    }\n\n    public SimpleBigDecimal multiply(SimpleBigDecimal b)\n    {\n        checkScale(b);\n        return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale);\n    }\n\n    public SimpleBigDecimal multiply(BigInteger b)\n    {\n        return new SimpleBigDecimal(bigInt.multiply(b), scale);\n    }\n\n    public SimpleBigDecimal divide(SimpleBigDecimal b)\n    {\n        checkScale(b);\n        BigInteger dividend = bigInt.shiftLeft(scale);\n        return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);\n    }\n\n    public SimpleBigDecimal divide(BigInteger b)\n    {\n        return new SimpleBigDecimal(bigInt.divide(b), scale);\n    }\n\n    public SimpleBigDecimal shiftLeft(int n)\n    {\n        return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);\n    }\n\n    public int compareTo(SimpleBigDecimal val)\n    {\n        checkScale(val);\n        return bigInt.compareTo(val.bigInt);\n    }\n\n    public int compareTo(BigInteger val)\n    {\n        return bigInt.compareTo(val.shiftLeft(scale));\n    }\n\n    public BigInteger floor()\n    {\n        return bigInt.shiftRight(scale);\n    }\n\n    public BigInteger round()\n    {\n        SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1);\n        return add(oneHalf.adjustScale(scale)).floor();\n    }\n\n    public int intValue()\n    {\n        return floor().intValue();\n    }\n    \n    public long longValue()\n    {\n        return floor().longValue();\n    }\n          /* NON-J2ME compliant.\n    public double doubleValue()\n    {\n        return Double.valueOf(toString()).doubleValue();\n    }\n\n    public float floatValue()\n    {\n        return Float.valueOf(toString()).floatValue();\n    }\n       */\n    public int getScale()\n    {\n        return scale;\n    }\n\n    public String toString()\n    {\n        if (scale == 0)\n        {\n            return bigInt.toString();\n        }\n\n        BigInteger floorBigInt = floor();\n        \n        BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale));\n        if (bigInt.signum() == -1)\n        {\n            fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);\n        }\n\n        if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO))))\n        {\n            floorBigInt = floorBigInt.add(ECConstants.ONE);\n        }\n        String leftOfPoint = floorBigInt.toString();\n\n        char[] fractCharArr = new char[scale];\n        String fractStr = fract.toString(2);\n        int fractLen = fractStr.length();\n        int zeroes = scale - fractLen;\n        for (int i = 0; i < zeroes; i++)\n        {\n            fractCharArr[i] = '0';\n        }\n        for (int j = 0; j < fractLen; j++)\n        {\n            fractCharArr[zeroes + j] = fractStr.charAt(j);\n        }\n        String rightOfPoint = new String(fractCharArr);\n\n        StringBuffer sb = new StringBuffer(leftOfPoint);\n        sb.append(\".\");\n        sb.append(rightOfPoint);\n\n        return sb.toString();\n    }\n\n    public boolean equals(Object o)\n    {\n        if (this == o)\n        {\n            return true;\n        }\n\n        if (!(o instanceof SimpleBigDecimal))\n        {\n            return false;\n        }\n\n        SimpleBigDecimal other = (SimpleBigDecimal)o;\n        return ((bigInt.equals(other.bigInt)) && (scale == other.scale));\n    }\n\n    public int hashCode()\n    {\n        return bigInt.hashCode() ^ scale;\n    }\n\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/Tnaf.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Class holding methods for point multiplication based on the window\n * &tau;-adic nonadjacent form (WTNAF). The algorithms are based on the\n * paper \"Improved Algorithms for Arithmetic on Anomalous Binary Curves\"\n * by Jerome A. Solinas. The paper first appeared in the Proceedings of\n * Crypto 1997.\n */\nclass Tnaf\n{\n    private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();\n    private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();\n    private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();\n\n    /**\n     * The window width of WTNAF. The standard value of 4 is slightly less\n     * than optimal for running time, but keeps space requirements for\n     * precomputation low. For typical curves, a value of 5 or 6 results in\n     * a better running time. When changing this value, the\n     * <code>&alpha;<sub>u</sub></code>'s must be computed differently, see\n     * e.g. \"Guide to Elliptic Curve Cryptography\", Darrel Hankerson,\n     * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,\n     * p. 121-122\n     */\n    public static final byte WIDTH = 4;\n\n    /**\n     * 2<sup>4</sup>\n     */\n    public static final byte POW_2_WIDTH = 16;\n\n    /**\n     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array\n     * of <code>ZTauElement</code>s.\n     */\n    public static final ZTauElement[] alpha0 = {\n        null,\n        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,\n        new ZTauElement(MINUS_THREE, MINUS_ONE), null,\n        new ZTauElement(MINUS_ONE, MINUS_ONE), null,\n        new ZTauElement(ECConstants.ONE, MINUS_ONE), null\n    };\n\n    /**\n     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array\n     * of TNAFs.\n     */\n    public static final byte[][] alpha0Tnaf = {\n        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}\n    };\n\n    /**\n     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array\n     * of <code>ZTauElement</code>s.\n     */\n    public static final ZTauElement[] alpha1 = {null,\n        new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,\n        new ZTauElement(MINUS_THREE, ECConstants.ONE), null,\n        new ZTauElement(MINUS_ONE, ECConstants.ONE), null,\n        new ZTauElement(ECConstants.ONE, ECConstants.ONE), null\n    };\n\n    /**\n     * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array\n     * of TNAFs.\n     */\n    public static final byte[][] alpha1Tnaf = {\n        null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}\n    };\n\n    /**\n     * Computes the norm of an element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code>.\n     * @param mu The parameter <code>&mu;</code> of the elliptic curve.\n     * @param lambda The element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code>.\n     * @return The norm of <code>&lambda;</code>.\n     */\n    public static BigInteger norm(final byte mu, ZTauElement lambda)\n    {\n        BigInteger norm;\n\n        // s1 = u^2\n        BigInteger s1 = lambda.u.multiply(lambda.u);\n\n        // s2 = u * v\n        BigInteger s2 = lambda.u.multiply(lambda.v);\n\n        // s3 = 2 * v^2\n        BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);\n\n        if (mu == 1)\n        {\n            norm = s1.add(s2).add(s3);\n        }\n        else if (mu == -1)\n        {\n            norm = s1.subtract(s2).add(s3);\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n\n        return norm;\n    }\n\n    /**\n     * Computes the norm of an element <code>&lambda;</code> of\n     * <code><b>R</b>[&tau;]</code>, where <code>&lambda; = u + v&tau;</code>\n     * and <code>u</code> and <code>u</code> are real numbers (elements of\n     * <code><b>R</b></code>). \n     * @param mu The parameter <code>&mu;</code> of the elliptic curve.\n     * @param u The real part of the element <code>&lambda;</code> of\n     * <code><b>R</b>[&tau;]</code>.\n     * @param v The <code>&tau;</code>-adic part of the element\n     * <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>.\n     * @return The norm of <code>&lambda;</code>.\n     */\n    public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,\n            SimpleBigDecimal v)\n    {\n        SimpleBigDecimal norm;\n\n        // s1 = u^2\n        SimpleBigDecimal s1 = u.multiply(u);\n\n        // s2 = u * v\n        SimpleBigDecimal s2 = u.multiply(v);\n\n        // s3 = 2 * v^2\n        SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);\n\n        if (mu == 1)\n        {\n            norm = s1.add(s2).add(s3);\n        }\n        else if (mu == -1)\n        {\n            norm = s1.subtract(s2).add(s3);\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n\n        return norm;\n    }\n\n    /**\n     * Rounds an element <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>\n     * to an element of <code><b>Z</b>[&tau;]</code>, such that their difference\n     * has minimal norm. <code>&lambda;</code> is given as\n     * <code>&lambda; = &lambda;<sub>0</sub> + &lambda;<sub>1</sub>&tau;</code>.\n     * @param lambda0 The component <code>&lambda;<sub>0</sub></code>.\n     * @param lambda1 The component <code>&lambda;<sub>1</sub></code>.\n     * @param mu The parameter <code>&mu;</code> of the elliptic curve. Must\n     * equal 1 or -1.\n     * @return The rounded element of <code><b>Z</b>[&tau;]</code>.\n     * @throws IllegalArgumentException if <code>lambda0</code> and\n     * <code>lambda1</code> do not have same scale.\n     */\n    public static ZTauElement round(SimpleBigDecimal lambda0,\n            SimpleBigDecimal lambda1, byte mu)\n    {\n        int scale = lambda0.getScale();\n        if (lambda1.getScale() != scale)\n        {\n            throw new IllegalArgumentException(\"lambda0 and lambda1 do not \" +\n                    \"have same scale\");\n        }\n\n        if (!((mu == 1) || (mu == -1)))\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n\n        BigInteger f0 = lambda0.round();\n        BigInteger f1 = lambda1.round();\n\n        SimpleBigDecimal eta0 = lambda0.subtract(f0);\n        SimpleBigDecimal eta1 = lambda1.subtract(f1);\n\n        // eta = 2*eta0 + mu*eta1\n        SimpleBigDecimal eta = eta0.add(eta0);\n        if (mu == 1)\n        {\n            eta = eta.add(eta1);\n        }\n        else\n        {\n            // mu == -1\n            eta = eta.subtract(eta1);\n        }\n\n        // check1 = eta0 - 3*mu*eta1\n        // check2 = eta0 + 4*mu*eta1\n        SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);\n        SimpleBigDecimal fourEta1 = threeEta1.add(eta1);\n        SimpleBigDecimal check1;\n        SimpleBigDecimal check2;\n        if (mu == 1)\n        {\n            check1 = eta0.subtract(threeEta1);\n            check2 = eta0.add(fourEta1);\n        }\n        else\n        {\n            // mu == -1\n            check1 = eta0.add(threeEta1);\n            check2 = eta0.subtract(fourEta1);\n        }\n\n        byte h0 = 0;\n        byte h1 = 0;\n\n        // if eta >= 1\n        if (eta.compareTo(ECConstants.ONE) >= 0)\n        {\n            if (check1.compareTo(MINUS_ONE) < 0)\n            {\n                h1 = mu;\n            }\n            else\n            {\n                h0 = 1;\n            }\n        }\n        else\n        {\n            // eta < 1\n            if (check2.compareTo(ECConstants.TWO) >= 0)\n            {\n                h1 = mu;\n            }\n        }\n\n        // if eta < -1\n        if (eta.compareTo(MINUS_ONE) < 0)\n        {\n            if (check1.compareTo(ECConstants.ONE) >= 0)\n            {\n                h1 = (byte)-mu;\n            }\n            else\n            {\n                h0 = -1;\n            }\n        }\n        else\n        {\n            // eta >= -1\n            if (check2.compareTo(MINUS_TWO) < 0)\n            {\n                h1 = (byte)-mu;\n            }\n        }\n\n        BigInteger q0 = f0.add(BigInteger.valueOf(h0));\n        BigInteger q1 = f1.add(BigInteger.valueOf(h1));\n        return new ZTauElement(q0, q1);\n    }\n\n    /**\n     * Approximate division by <code>n</code>. For an integer\n     * <code>k</code>, the value <code>&lambda; = s k / n</code> is\n     * computed to <code>c</code> bits of accuracy.\n     * @param k The parameter <code>k</code>.\n     * @param s The curve parameter <code>s<sub>0</sub></code> or\n     * <code>s<sub>1</sub></code>.\n     * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.\n     * @param a The parameter <code>a</code> of the elliptic curve.\n     * @param m The bit length of the finite field\n     * <code><b>F</b><sub>m</sub></code>.\n     * @param c The number of bits of accuracy, i.e. the scale of the returned\n     * <code>SimpleBigDecimal</code>.\n     * @return The value <code>&lambda; = s k / n</code> computed to\n     * <code>c</code> bits of accuracy.\n     */\n    public static SimpleBigDecimal approximateDivisionByN(BigInteger k,\n            BigInteger s, BigInteger vm, byte a, int m, int c)\n    {\n        int _k = (m + 5)/2 + c;\n        BigInteger ns = k.shiftRight(m - _k - 2 + a);\n\n        BigInteger gs = s.multiply(ns);\n\n        BigInteger hs = gs.shiftRight(m);\n\n        BigInteger js = vm.multiply(hs);\n\n        BigInteger gsPlusJs = gs.add(js);\n        BigInteger ls = gsPlusJs.shiftRight(_k-c);\n        if (gsPlusJs.testBit(_k-c-1))\n        {\n            // round up\n            ls = ls.add(ECConstants.ONE);\n        }\n\n        return new SimpleBigDecimal(ls, c);\n    }\n\n    /**\n     * Computes the <code>&tau;</code>-adic NAF (non-adjacent form) of an\n     * element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.\n     * @param mu The parameter <code>&mu;</code> of the elliptic curve.\n     * @param lambda The element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code>.\n     * @return The <code>&tau;</code>-adic NAF of <code>&lambda;</code>.\n     */\n    public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)\n    {\n        if (!((mu == 1) || (mu == -1)))\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n        \n        BigInteger norm = norm(mu, lambda);\n\n        // Ceiling of log2 of the norm \n        int log2Norm = norm.bitLength();\n\n        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52\n        int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;\n\n        // The array holding the TNAF\n        byte[] u = new byte[maxLength];\n        int i = 0;\n\n        // The actual length of the TNAF\n        int length = 0;\n\n        BigInteger r0 = lambda.u;\n        BigInteger r1 = lambda.v;\n\n        while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))\n        {\n            // If r0 is odd\n            if (r0.testBit(0))\n            {\n                u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();\n\n                // r0 = r0 - u[i]\n                if (u[i] == 1)\n                {\n                    r0 = r0.clearBit(0);\n                }\n                else\n                {\n                    // u[i] == -1\n                    r0 = r0.add(ECConstants.ONE);\n                }\n                length = i;\n            }\n            else\n            {\n                u[i] = 0;\n            }\n\n            BigInteger t = r0;\n            BigInteger s = r0.shiftRight(1);\n            if (mu == 1)\n            {\n                r0 = r1.add(s);\n            }\n            else\n            {\n                // mu == -1\n                r0 = r1.subtract(s);\n            }\n\n            r1 = t.shiftRight(1).negate();\n            i++;\n        }\n\n        length++;\n\n        // Reduce the TNAF array to its actual length\n        byte[] tnaf = new byte[length];\n        System.arraycopy(u, 0, tnaf, 0, length);\n        return tnaf;\n    }\n\n    /**\n     * Applies the operation <code>&tau;()</code> to an\n     * <code>ECPoint.F2m</code>. \n     * @param p The ECPoint.F2m to which <code>&tau;()</code> is applied.\n     * @return <code>&tau;(p)</code>\n     */\n    public static ECPoint.F2m tau(ECPoint.F2m p)\n    {\n        if (p.isInfinity())\n        {\n            return p;\n        }\n\n        ECFieldElement x = p.getX();\n        ECFieldElement y = p.getY();\n\n        return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());\n    }\n\n    /**\n     * Returns the parameter <code>&mu;</code> of the elliptic curve.\n     * @param curve The elliptic curve from which to obtain <code>&mu;</code>.\n     * The curve must be a Koblitz curve, i.e. <code>a</code> equals\n     * <code>0</code> or <code>1</code> and <code>b</code> equals\n     * <code>1</code>. \n     * @return <code>&mu;</code> of the elliptic curve.\n     * @throws IllegalArgumentException if the given ECCurve is not a Koblitz\n     * curve.\n     */\n    public static byte getMu(ECCurve.F2m curve)\n    {\n        BigInteger a = curve.getA().toBigInteger();\n        byte mu;\n\n        if (a.equals(ECConstants.ZERO))\n        {\n            mu = -1;\n        }\n        else if (a.equals(ECConstants.ONE))\n        {\n            mu = 1;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"No Koblitz curve (ABC), \" +\n                    \"TNAF multiplication not possible\");\n        }\n        return mu;\n    }\n\n    /**\n     * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and\n     * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and\n     * <code>V<sub>k</sub></code>.\n     * @param mu The parameter <code>&mu;</code> of the elliptic curve.\n     * @param k The index of the second element of the Lucas Sequence to be\n     * returned.\n     * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and\n     * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and\n     * <code>U<sub>k</sub></code>.\n     * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>\n     * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>\n     * and <code>V<sub>k</sub></code>.\n     */\n    public static BigInteger[] getLucas(byte mu, int k, boolean doV)\n    {\n        if (!((mu == 1) || (mu == -1)))\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n\n        BigInteger u0;\n        BigInteger u1;\n        BigInteger u2;\n\n        if (doV)\n        {\n            u0 = ECConstants.TWO;\n            u1 = BigInteger.valueOf(mu);\n        }\n        else\n        {\n            u0 = ECConstants.ZERO;\n            u1 = ECConstants.ONE;\n        }\n\n        for (int i = 1; i < k; i++)\n        {\n            // u2 = mu*u1 - 2*u0;\n            BigInteger s = null;\n            if (mu == 1)\n            {\n                s = u1;\n            }\n            else\n            {\n                // mu == -1\n                s = u1.negate();\n            }\n            \n            u2 = s.subtract(u0.shiftLeft(1));\n            u0 = u1;\n            u1 = u2;\n//            System.out.println(i + \": \" + u2);\n//            System.out.println();\n        }\n\n        BigInteger[] retVal = {u0, u1};\n        return retVal;\n    }\n\n    /**\n     * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is\n     * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for\n     * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code> \n     * @param mu The parameter <code>&mu;</code> of the elliptic curve.\n     * @param w The window width of the WTNAF.\n     * @return the auxiliary value <code>t<sub>w</sub></code>\n     */\n    public static BigInteger getTw(byte mu, int w)\n    {\n        if (w == 4)\n        {\n            if (mu == 1)\n            {\n                return BigInteger.valueOf(6);\n            }\n            else\n            {\n                // mu == -1\n                return BigInteger.valueOf(10);\n            }\n        }\n        else\n        {\n            // For w <> 4, the values must be computed\n            BigInteger[] us = getLucas(mu, w, false);\n            BigInteger twoToW = ECConstants.ZERO.setBit(w);\n            BigInteger u1invert = us[1].modInverse(twoToW);\n            BigInteger tw;\n            tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);\n//            System.out.println(\"mu = \" + mu);\n//            System.out.println(\"tw = \" + tw);\n            return tw;\n        }\n    }\n\n    /**\n     * Computes the auxiliary values <code>s<sub>0</sub></code> and\n     * <code>s<sub>1</sub></code> used for partial modular reduction. \n     * @param curve The elliptic curve for which to compute\n     * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.\n     * @throws IllegalArgumentException if <code>curve</code> is not a\n     * Koblitz curve (Anomalous Binary Curve, ABC).\n     */\n    public static BigInteger[] getSi(ECCurve.F2m curve)\n    {\n        if (!curve.isKoblitz())\n        {\n            throw new IllegalArgumentException(\"si is defined for Koblitz curves only\");\n        }\n\n        int m = curve.getM();\n        int a = curve.getA().toBigInteger().intValue();\n        byte mu = curve.getMu();\n        int h = curve.getH().intValue();\n        int index = m + 3 - a;\n        BigInteger[] ui = getLucas(mu, index, false);\n\n        BigInteger dividend0;\n        BigInteger dividend1;\n        if (mu == 1)\n        {\n            dividend0 = ECConstants.ONE.subtract(ui[1]);\n            dividend1 = ECConstants.ONE.subtract(ui[0]);\n        }\n        else if (mu == -1)\n        {\n            dividend0 = ECConstants.ONE.add(ui[1]);\n            dividend1 = ECConstants.ONE.add(ui[0]);\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n\n        BigInteger[] si = new BigInteger[2];\n\n        if (h == 2)\n        {\n            si[0] = dividend0.shiftRight(1);\n            si[1] = dividend1.shiftRight(1).negate();\n        }\n        else if (h == 4)\n        {\n            si[0] = dividend0.shiftRight(2);\n            si[1] = dividend1.shiftRight(2).negate();\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"h (Cofactor) must be 2 or 4\");\n        }\n\n        return si;\n    }\n\n    /**\n     * Partial modular reduction modulo\n     * <code>(&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>.\n     * @param k The integer to be reduced.\n     * @param m The bitlength of the underlying finite field.\n     * @param a The parameter <code>a</code> of the elliptic curve.\n     * @param s The auxiliary values <code>s<sub>0</sub></code> and\n     * <code>s<sub>1</sub></code>.\n     * @param mu The parameter &mu; of the elliptic curve.\n     * @param c The precision (number of bits of accuracy) of the partial\n     * modular reduction.\n     * @return <code>&rho; := k partmod (&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>\n     */\n    public static ZTauElement partModReduction(BigInteger k, int m, byte a,\n            BigInteger[] s, byte mu, byte c)\n    {\n        // d0 = s[0] + mu*s[1]; mu is either 1 or -1\n        BigInteger d0;\n        if (mu == 1)\n        {\n            d0 = s[0].add(s[1]);\n        }\n        else\n        {\n            d0 = s[0].subtract(s[1]);\n        }\n\n        BigInteger[] v = getLucas(mu, m, true);\n        BigInteger vm = v[1];\n\n        SimpleBigDecimal lambda0 = approximateDivisionByN(\n                k, s[0], vm, a, m, c);\n        \n        SimpleBigDecimal lambda1 = approximateDivisionByN(\n                k, s[1], vm, a, m, c);\n\n        ZTauElement q = round(lambda0, lambda1, mu);\n\n        // r0 = n - d0*q0 - 2*s1*q1\n        BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(\n                BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));\n\n        // r1 = s1*q0 - s0*q1\n        BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));\n        \n        return new ZTauElement(r0, r1);\n    }\n\n    /**\n     * Multiplies a {@link local.org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}\n     * by a <code>BigInteger</code> using the reduced <code>&tau;</code>-adic\n     * NAF (RTNAF) method.\n     * @param p The ECPoint.F2m to multiply.\n     * @param k The <code>BigInteger</code> by which to multiply <code>p</code>.\n     * @return <code>k * p</code>\n     */\n    public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m p, BigInteger k)\n    {\n        ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();\n        int m = curve.getM();\n        byte a = (byte) curve.getA().toBigInteger().intValue();\n        byte mu = curve.getMu();\n        BigInteger[] s = curve.getSi();\n        ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10);\n\n        return multiplyTnaf(p, rho);\n    }\n\n    /**\n     * Multiplies a {@link local.org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}\n     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>\n     * using the <code>&tau;</code>-adic NAF (TNAF) method.\n     * @param p The ECPoint.F2m to multiply.\n     * @param lambda The element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code>.\n     * @return <code>&lambda; * p</code>\n     */\n    public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda)\n    {\n        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();\n        byte mu = curve.getMu();\n        byte[] u = tauAdicNaf(mu, lambda);\n\n        ECPoint.F2m q = multiplyFromTnaf(p, u);\n\n        return q;\n    }\n\n    /**\n    * Multiplies a {@link local.org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}\n    * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>\n    * using the <code>&tau;</code>-adic NAF (TNAF) method, given the TNAF\n    * of <code>&lambda;</code>.\n    * @param p The ECPoint.F2m to multiply.\n    * @param u The the TNAF of <code>&lambda;</code>..\n    * @return <code>&lambda; * p</code>\n    */\n    public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u)\n    {\n        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();\n        ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity();\n        for (int i = u.length - 1; i >= 0; i--)\n        {\n            q = tau(q);\n            if (u[i] == 1)\n            {\n                q = (ECPoint.F2m)q.addSimple(p);\n            }\n            else if (u[i] == -1)\n            {\n                q = (ECPoint.F2m)q.subtractSimple(p);\n            }\n        }\n        return q;\n    }\n\n    /**\n     * Computes the <code>[&tau;]</code>-adic window NAF of an element\n     * <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.\n     * @param mu The parameter &mu; of the elliptic curve.\n     * @param lambda The element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code> of which to compute the\n     * <code>[&tau;]</code>-adic NAF.\n     * @param width The window width of the resulting WNAF.\n     * @param pow2w 2<sup>width</sup>.\n     * @param tw The auxiliary value <code>t<sub>w</sub></code>.\n     * @param alpha The <code>&alpha;<sub>u</sub></code>'s for the window width.\n     * @return The <code>[&tau;]</code>-adic window NAF of\n     * <code>&lambda;</code>.\n     */\n    public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,\n            byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)\n    {\n        if (!((mu == 1) || (mu == -1)))\n        {\n            throw new IllegalArgumentException(\"mu must be 1 or -1\");\n        }\n\n        BigInteger norm = norm(mu, lambda);\n\n        // Ceiling of log2 of the norm \n        int log2Norm = norm.bitLength();\n\n        // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52\n        int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;\n\n        // The array holding the TNAF\n        byte[] u = new byte[maxLength];\n\n        // 2^(width - 1)\n        BigInteger pow2wMin1 = pow2w.shiftRight(1);\n\n        // Split lambda into two BigIntegers to simplify calculations\n        BigInteger r0 = lambda.u;\n        BigInteger r1 = lambda.v;\n        int i = 0;\n\n        // while lambda <> (0, 0)\n        while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))\n        {\n            // if r0 is odd\n            if (r0.testBit(0))\n            {\n                // uUnMod = r0 + r1*tw mod 2^width\n                BigInteger uUnMod\n                    = r0.add(r1.multiply(tw)).mod(pow2w);\n                \n                byte uLocal;\n                // if uUnMod >= 2^(width - 1)\n                if (uUnMod.compareTo(pow2wMin1) >= 0)\n                {\n                    uLocal = (byte) uUnMod.subtract(pow2w).intValue();\n                }\n                else\n                {\n                    uLocal = (byte) uUnMod.intValue();\n                }\n                // uLocal is now in [-2^(width-1), 2^(width-1)-1]\n\n                u[i] = uLocal;\n                boolean s = true;\n                if (uLocal < 0)\n                {\n                    s = false;\n                    uLocal = (byte)-uLocal;\n                }\n                // uLocal is now >= 0\n\n                if (s)\n                {\n                    r0 = r0.subtract(alpha[uLocal].u);\n                    r1 = r1.subtract(alpha[uLocal].v);\n                }\n                else\n                {\n                    r0 = r0.add(alpha[uLocal].u);\n                    r1 = r1.add(alpha[uLocal].v);\n                }\n            }\n            else\n            {\n                u[i] = 0;\n            }\n\n            BigInteger t = r0;\n\n            if (mu == 1)\n            {\n                r0 = r1.add(r0.shiftRight(1));\n            }\n            else\n            {\n                // mu == -1\n                r0 = r1.subtract(r0.shiftRight(1));\n            }\n            r1 = t.shiftRight(1).negate();\n            i++;\n        }\n        return u;\n    }\n\n    /**\n     * Does the precomputation for WTNAF multiplication.\n     * @param p The <code>ECPoint</code> for which to do the precomputation.\n     * @param a The parameter <code>a</code> of the elliptic curve.\n     * @return The precomputation array for <code>p</code>. \n     */\n    public static ECPoint.F2m[] getPreComp(ECPoint.F2m p, byte a)\n    {\n        ECPoint.F2m[] pu;\n        pu = new ECPoint.F2m[16];\n        pu[1] = p;\n        byte[][] alphaTnaf;\n        if (a == 0)\n        {\n            alphaTnaf = Tnaf.alpha0Tnaf;\n        }\n        else\n        {\n            // a == 1\n            alphaTnaf = Tnaf.alpha1Tnaf;\n        }\n\n        int precompLen = alphaTnaf.length;\n        for (int i = 3; i < precompLen; i = i + 2)\n        {\n            pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);\n        }\n        \n        return pu;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/WNafMultiplier.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Class implementing the WNAF (Window Non-Adjacent Form) multiplication\n * algorithm.\n */\nclass WNafMultiplier implements ECMultiplier\n{\n    /**\n     * Computes the Window NAF (non-adjacent Form) of an integer.\n     * @param width The width <code>w</code> of the Window NAF. The width is\n     * defined as the minimal number <code>w</code>, such that for any\n     * <code>w</code> consecutive digits in the resulting representation, at\n     * most one is non-zero.\n     * @param k The integer of which the Window NAF is computed.\n     * @return The Window NAF of the given width, such that the following holds:\n     * <code>k = &sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>\n     * </code>, where the <code>k<sub>i</sub></code> denote the elements of the\n     * returned <code>byte[]</code>.\n     */\n    public byte[] windowNaf(byte width, BigInteger k)\n    {\n        // The window NAF is at most 1 element longer than the binary\n        // representation of the integer k. byte can be used instead of short or\n        // int unless the window width is larger than 8. For larger width use\n        // short or int. However, a width of more than 8 is not efficient for\n        // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than\n        // 1000 Bits are currently not used in practice.\n        byte[] wnaf = new byte[k.bitLength() + 1];\n\n        // 2^width as short and BigInteger\n        short pow2wB = (short)(1 << width);\n        BigInteger pow2wBI = BigInteger.valueOf(pow2wB);\n\n        int i = 0;\n\n        // The actual length of the WNAF\n        int length = 0;\n\n        // while k >= 1\n        while (k.signum() > 0)\n        {\n            // if k is odd\n            if (k.testBit(0))\n            {\n                // k mod 2^width\n                BigInteger remainder = k.mod(pow2wBI);\n\n                // if remainder > 2^(width - 1) - 1\n                if (remainder.testBit(width - 1))\n                {\n                    wnaf[i] = (byte)(remainder.intValue() - pow2wB);\n                }\n                else\n                {\n                    wnaf[i] = (byte)remainder.intValue();\n                }\n                // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]\n\n                k = k.subtract(BigInteger.valueOf(wnaf[i]));\n                length = i;\n            }\n            else\n            {\n                wnaf[i] = 0;\n            }\n\n            // k = k/2\n            k = k.shiftRight(1);\n            i++;\n        }\n\n        length++;\n\n        // Reduce the WNAF array to its actual length\n        byte[] wnafShort = new byte[length];\n        System.arraycopy(wnaf, 0, wnafShort, 0, length);\n        return wnafShort;\n    }\n\n    /**\n     * Multiplies <code>this</code> by an integer <code>k</code> using the\n     * Window NAF method.\n     * @param k The integer by which <code>this</code> is multiplied.\n     * @return A new <code>ECPoint</code> which equals <code>this</code>\n     * multiplied by <code>k</code>.\n     */\n    public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)\n    {\n        WNafPreCompInfo wnafPreCompInfo;\n\n        if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))\n        {\n            wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;\n        }\n        else\n        {\n            // Ignore empty PreCompInfo or PreCompInfo of incorrect type\n            wnafPreCompInfo = new WNafPreCompInfo();\n        }\n\n        // floor(log2(k))\n        int m = k.bitLength();\n\n        // width of the Window NAF\n        byte width;\n\n        // Required length of precomputation array\n        int reqPreCompLen;\n\n        // Determine optimal width and corresponding length of precomputation\n        // array based on literature values\n        if (m < 13)\n        {\n            width = 2;\n            reqPreCompLen = 1;\n        }\n        else\n        {\n            if (m < 41)\n            {\n                width = 3;\n                reqPreCompLen = 2;\n            }\n            else\n            {\n                if (m < 121)\n                {\n                    width = 4;\n                    reqPreCompLen = 4;\n                }\n                else\n                {\n                    if (m < 337)\n                    {\n                        width = 5;\n                        reqPreCompLen = 8;\n                    }\n                    else\n                    {\n                        if (m < 897)\n                        {\n                            width = 6;\n                            reqPreCompLen = 16;\n                        }\n                        else\n                        {\n                            if (m < 2305)\n                            {\n                                width = 7;\n                                reqPreCompLen = 32;\n                            }\n                            else\n                            {\n                                width = 8;\n                                reqPreCompLen = 127;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        // The length of the precomputation array\n        int preCompLen = 1;\n\n        ECPoint[] preComp = wnafPreCompInfo.getPreComp();\n        ECPoint twiceP = wnafPreCompInfo.getTwiceP();\n\n        // Check if the precomputed ECPoints already exist\n        if (preComp == null)\n        {\n            // Precomputation must be performed from scratch, create an empty\n            // precomputation array of desired length\n            preComp = new ECPoint[]{ p };\n        }\n        else\n        {\n            // Take the already precomputed ECPoints to start with\n            preCompLen = preComp.length;\n        }\n\n        if (twiceP == null)\n        {\n            // Compute twice(p)\n            twiceP = p.twice();\n        }\n\n        if (preCompLen < reqPreCompLen)\n        {\n            // Precomputation array must be made bigger, copy existing preComp\n            // array into the larger new preComp array\n            ECPoint[] oldPreComp = preComp;\n            preComp = new ECPoint[reqPreCompLen];\n            System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen);\n\n            for (int i = preCompLen; i < reqPreCompLen; i++)\n            {\n                // Compute the new ECPoints for the precomputation array.\n                // The values 1, 3, 5, ..., 2^(width-1)-1 times p are\n                // computed\n                preComp[i] = twiceP.add(preComp[i - 1]);\n            }            \n        }\n\n        // Compute the Window NAF of the desired width\n        byte[] wnaf = windowNaf(width, k);\n        int l = wnaf.length;\n\n        // Apply the Window NAF to p using the precomputed ECPoint values.\n        ECPoint q = p.getCurve().getInfinity();\n        for (int i = l - 1; i >= 0; i--)\n        {\n            q = q.twice();\n\n            if (wnaf[i] != 0)\n            {\n                if (wnaf[i] > 0)\n                {\n                    q = q.add(preComp[(wnaf[i] - 1)/2]);\n                }\n                else\n                {\n                    // wnaf[i] < 0\n                    q = q.subtract(preComp[(-wnaf[i] - 1)/2]);\n                }\n            }\n        }\n\n        // Set PreCompInfo in ECPoint, such that it is available for next\n        // multiplication.\n        wnafPreCompInfo.setPreComp(preComp);\n        wnafPreCompInfo.setTwiceP(twiceP);\n        p.setPreCompInfo(wnafPreCompInfo);\n        return q;\n    }\n\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/WNafPreCompInfo.java",
    "content": "package local.org.bouncycastle.math.ec;\n\n/**\n * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)\n * algorithm.\n */\nclass WNafPreCompInfo implements PreCompInfo\n{\n    /**\n     * Array holding the precomputed <code>ECPoint</code>s used for the Window\n     * NAF multiplication in <code>\n     * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()\n     * WNafMultiplier.multiply()}</code>.\n     */\n    private ECPoint[] preComp = null;\n\n    /**\n     * Holds an <code>ECPoint</code> representing twice(this). Used for the\n     * Window NAF multiplication in <code>\n     * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()\n     * WNafMultiplier.multiply()}</code>.\n     */\n    private ECPoint twiceP = null;\n\n    protected ECPoint[] getPreComp()\n    {\n        return preComp;\n    }\n\n    protected void setPreComp(ECPoint[] preComp)\n    {\n        this.preComp = preComp;\n    }\n\n    protected ECPoint getTwiceP()\n    {\n        return twiceP;\n    }\n\n    protected void setTwiceP(ECPoint twiceThis)\n    {\n        this.twiceP = twiceThis;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/WTauNafMultiplier.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Class implementing the WTNAF (Window\n * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.\n */\nclass WTauNafMultiplier implements ECMultiplier\n{\n    /**\n     * Multiplies a {@link local.org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}\n     * by <code>k</code> using the reduced <code>&tau;</code>-adic NAF (RTNAF)\n     * method.\n     * @param p The ECPoint.F2m to multiply.\n     * @param k The integer by which to multiply <code>k</code>.\n     * @return <code>p</code> multiplied by <code>k</code>.\n     */\n    public ECPoint multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo)\n    {\n        if (!(point instanceof ECPoint.F2m))\n        {\n            throw new IllegalArgumentException(\"Only ECPoint.F2m can be \" +\n                    \"used in WTauNafMultiplier\");\n        }\n\n        ECPoint.F2m p = (ECPoint.F2m)point;\n\n        ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();\n        int m = curve.getM();\n        byte a = curve.getA().toBigInteger().byteValue();\n        byte mu = curve.getMu();\n        BigInteger[] s = curve.getSi();\n\n        ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);\n\n        return multiplyWTnaf(p, rho, preCompInfo, a, mu);\n    }\n\n    /**\n     * Multiplies a {@link local.org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}\n     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code> using\n     * the <code>&tau;</code>-adic NAF (TNAF) method.\n     * @param p The ECPoint.F2m to multiply.\n     * @param lambda The element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code> of which to compute the\n     * <code>[&tau;]</code>-adic NAF.\n     * @return <code>p</code> multiplied by <code>&lambda;</code>.\n     */\n    private ECPoint.F2m multiplyWTnaf(ECPoint.F2m p, ZTauElement lambda,\n            PreCompInfo preCompInfo, byte a, byte mu)\n    {\n        ZTauElement[] alpha;\n        if (a == 0)\n        {\n            alpha = Tnaf.alpha0;\n        }\n        else\n        {\n            // a == 1\n            alpha = Tnaf.alpha1;\n        }\n\n        BigInteger tw = Tnaf.getTw(mu, Tnaf.WIDTH);\n\n        byte[]u = Tnaf.tauAdicWNaf(mu, lambda, Tnaf.WIDTH,\n                BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha);\n\n        return multiplyFromWTnaf(p, u, preCompInfo);\n    }\n\n    /**\n     * Multiplies a {@link local.org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}\n     * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>\n     * using the window <code>&tau;</code>-adic NAF (TNAF) method, given the\n     * WTNAF of <code>&lambda;</code>.\n     * @param p The ECPoint.F2m to multiply.\n     * @param u The the WTNAF of <code>&lambda;</code>..\n     * @return <code>&lambda; * p</code>\n     */\n    private static ECPoint.F2m multiplyFromWTnaf(ECPoint.F2m p, byte[] u,\n            PreCompInfo preCompInfo)\n    {\n        ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();\n        byte a = curve.getA().toBigInteger().byteValue();\n\n        ECPoint.F2m[] pu;\n        if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo))\n        {\n            pu = Tnaf.getPreComp(p, a);\n            p.setPreCompInfo(new WTauNafPreCompInfo(pu));\n        }\n        else\n        {\n            pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp();\n        }\n\n        // q = infinity\n        ECPoint.F2m q = (ECPoint.F2m) p.getCurve().getInfinity();\n        for (int i = u.length - 1; i >= 0; i--)\n        {\n            q = Tnaf.tau(q);\n            if (u[i] != 0)\n            {\n                if (u[i] > 0)\n                {\n                    q = q.addSimple(pu[u[i]]);\n                }\n                else\n                {\n                    // u[i] < 0\n                    q = q.subtractSimple(pu[-u[i]]);\n                }\n            }\n        }\n\n        return q;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/WTauNafPreCompInfo.java",
    "content": "package local.org.bouncycastle.math.ec;\n\n/**\n * Class holding precomputation data for the WTNAF (Window\n * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.\n */\nclass WTauNafPreCompInfo implements PreCompInfo\n{\n    /**\n     * Array holding the precomputed <code>ECPoint.F2m</code>s used for the\n     * WTNAF multiplication in <code>\n     * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()\n     * WTauNafMultiplier.multiply()}</code>.\n     */\n    private ECPoint.F2m[] preComp = null;\n\n    /**\n     * Constructor for <code>WTauNafPreCompInfo</code>\n     * @param preComp Array holding the precomputed <code>ECPoint.F2m</code>s\n     * used for the WTNAF multiplication in <code>\n     * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()\n     * WTauNafMultiplier.multiply()}</code>.\n     */\n    WTauNafPreCompInfo(ECPoint.F2m[] preComp)\n    {\n        this.preComp = preComp;\n    }\n\n    /**\n     * @return the array holding the precomputed <code>ECPoint.F2m</code>s\n     * used for the WTNAF multiplication in <code>\n     * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()\n     * WTauNafMultiplier.multiply()}</code>.\n     */\n    protected ECPoint.F2m[] getPreComp()\n    {\n        return preComp;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/math/ec/ZTauElement.java",
    "content": "package local.org.bouncycastle.math.ec;\n\nimport java.math.BigInteger;\n\n/**\n * Class representing an element of <code><b>Z</b>[&tau;]</code>. Let\n * <code>&lambda;</code> be an element of <code><b>Z</b>[&tau;]</code>. Then\n * <code>&lambda;</code> is given as <code>&lambda; = u + v&tau;</code>. The\n * components <code>u</code> and <code>v</code> may be used directly, there\n * are no accessor methods.\n * Immutable class.\n */\nclass ZTauElement\n{\n    /**\n     * The &quot;real&quot; part of <code>&lambda;</code>.\n     */\n    public final BigInteger u;\n\n    /**\n     * The &quot;<code>&tau;</code>-adic&quot; part of <code>&lambda;</code>.\n     */\n    public final BigInteger v;\n\n    /**\n     * Constructor for an element <code>&lambda;</code> of\n     * <code><b>Z</b>[&tau;]</code>.\n     * @param u The &quot;real&quot; part of <code>&lambda;</code>.\n     * @param v The &quot;<code>&tau;</code>-adic&quot; part of\n     * <code>&lambda;</code>.\n     */\n    public ZTauElement(BigInteger u, BigInteger v)\n    {\n        this.u = u;\n        this.v = v;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/ContentSigner.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport java.io.OutputStream;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\n\npublic interface ContentSigner\n{\n    AlgorithmIdentifier getAlgorithmIdentifier();\n\n    /**\n     * Returns a stream that will accept data for the purpose of calculating\n     * a signature. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate\n     * the data on the fly as well.\n     *\n     * @return an OutputStream\n     */\n    OutputStream getOutputStream();\n\n    /**\n     * Returns a signature based on the current data written to the stream, since the\n     * start or the last call to getSignature().\n     *\n     * @return bytes representing the signature.\n     */\n    byte[] getSignature();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/ContentVerifier.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport java.io.OutputStream;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\n\npublic interface ContentVerifier\n{\n    /**\n     * Return the algorithm identifier describing the signature\n     * algorithm and parameters this expander supports.\n     *\n     * @return algorithm oid and parameters.\n     */\n    AlgorithmIdentifier getAlgorithmIdentifier();\n\n    /**\n     * Returns a stream that will accept data for the purpose of calculating\n     * a signature for later verification. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate\n     * the data on the fly as well.\n     *\n     * @return an OutputStream\n     */\n    OutputStream getOutputStream();\n\n    /**\n     * @param expected expected value of the signature on the data.\n     * @return true if the signature verifies, false otherwise\n     */\n    boolean verify(byte[] expected);\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/ContentVerifierProvider.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.cert.X509CertificateHolder;\n\n/**\n * General interface for providers of ContentVerifier objects.\n */\npublic interface ContentVerifierProvider\n{\n    /**\n     * Return whether or not this verifier has a certificate associated with it.\n     *\n     * @return true if there is an associated certificate, false otherwise.\n     */\n    boolean hasAssociatedCertificate();\n\n    /**\n     * Return the associated certificate if there is one.\n     *\n     * @return a holder containing the associated certificate if there is one, null if there is not.\n     */\n    X509CertificateHolder getAssociatedCertificate();\n\n    /**\n     * Return a ContentVerifier that matches the passed in algorithm identifier,\n     *\n     * @param verifierAlgorithmIdentifier the algorithm and parameters required.\n     * @return a matching ContentVerifier\n     * @throws OperatorCreationException if the required ContentVerifier cannot be created.\n     */\n    ContentVerifier get(AlgorithmIdentifier verifierAlgorithmIdentifier)\n        throws OperatorCreationException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport local.org.bouncycastle.asn1.ASN1Encodable;\nimport local.org.bouncycastle.asn1.ASN1Integer;\nimport local.org.bouncycastle.asn1.ASN1ObjectIdentifier;\nimport local.org.bouncycastle.asn1.DERNull;\nimport local.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;\nimport local.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;\nimport local.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;\nimport local.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;\nimport local.org.bouncycastle.asn1.pkcs.RSASSAPSSparams;\nimport local.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\nimport local.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;\nimport local.org.bouncycastle.util.Strings;\n\n\npublic class DefaultSignatureAlgorithmIdentifierFinder\n    implements SignatureAlgorithmIdentifierFinder\n{\n    private static Map algorithms = new HashMap();\n    private static Set noParams = new HashSet();\n    private static Map params = new HashMap();\n    private static Set pkcs15RsaEncryption = new HashSet();\n    private static Map digestOids = new HashMap();\n\n    private static final ASN1ObjectIdentifier ENCRYPTION_RSA = PKCSObjectIdentifiers.rsaEncryption;\n    private static final ASN1ObjectIdentifier ENCRYPTION_DSA = X9ObjectIdentifiers.id_dsa_with_sha1;\n    private static final ASN1ObjectIdentifier ENCRYPTION_ECDSA = X9ObjectIdentifiers.ecdsa_with_SHA1;\n    private static final ASN1ObjectIdentifier ENCRYPTION_RSA_PSS = PKCSObjectIdentifiers.id_RSASSA_PSS;\n    private static final ASN1ObjectIdentifier ENCRYPTION_GOST3410 = CryptoProObjectIdentifiers.gostR3410_94;\n    private static final ASN1ObjectIdentifier ENCRYPTION_ECGOST3410 = CryptoProObjectIdentifiers.gostR3410_2001;\n\n    static\n    {\n        algorithms.put(\"MD2WITHRSAENCRYPTION\", PKCSObjectIdentifiers.md2WithRSAEncryption);\n        algorithms.put(\"MD2WITHRSA\", PKCSObjectIdentifiers.md2WithRSAEncryption);\n        algorithms.put(\"MD5WITHRSAENCRYPTION\", PKCSObjectIdentifiers.md5WithRSAEncryption);\n        algorithms.put(\"MD5WITHRSA\", PKCSObjectIdentifiers.md5WithRSAEncryption);\n        algorithms.put(\"SHA1WITHRSAENCRYPTION\", PKCSObjectIdentifiers.sha1WithRSAEncryption);\n        algorithms.put(\"SHA1WITHRSA\", PKCSObjectIdentifiers.sha1WithRSAEncryption);\n        algorithms.put(\"SHA224WITHRSAENCRYPTION\", PKCSObjectIdentifiers.sha224WithRSAEncryption);\n        algorithms.put(\"SHA224WITHRSA\", PKCSObjectIdentifiers.sha224WithRSAEncryption);\n        algorithms.put(\"SHA256WITHRSAENCRYPTION\", PKCSObjectIdentifiers.sha256WithRSAEncryption);\n        algorithms.put(\"SHA256WITHRSA\", PKCSObjectIdentifiers.sha256WithRSAEncryption);\n        algorithms.put(\"SHA384WITHRSAENCRYPTION\", PKCSObjectIdentifiers.sha384WithRSAEncryption);\n        algorithms.put(\"SHA384WITHRSA\", PKCSObjectIdentifiers.sha384WithRSAEncryption);\n        algorithms.put(\"SHA512WITHRSAENCRYPTION\", PKCSObjectIdentifiers.sha512WithRSAEncryption);\n        algorithms.put(\"SHA512WITHRSA\", PKCSObjectIdentifiers.sha512WithRSAEncryption);\n        algorithms.put(\"SHA1WITHRSAANDMGF1\", PKCSObjectIdentifiers.id_RSASSA_PSS);\n        algorithms.put(\"SHA224WITHRSAANDMGF1\", PKCSObjectIdentifiers.id_RSASSA_PSS);\n        algorithms.put(\"SHA256WITHRSAANDMGF1\", PKCSObjectIdentifiers.id_RSASSA_PSS);\n        algorithms.put(\"SHA384WITHRSAANDMGF1\", PKCSObjectIdentifiers.id_RSASSA_PSS);\n        algorithms.put(\"SHA512WITHRSAANDMGF1\", PKCSObjectIdentifiers.id_RSASSA_PSS);\n        algorithms.put(\"RIPEMD160WITHRSAENCRYPTION\", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);\n        algorithms.put(\"RIPEMD160WITHRSA\", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);\n        algorithms.put(\"RIPEMD128WITHRSAENCRYPTION\", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);\n        algorithms.put(\"RIPEMD128WITHRSA\", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);\n        algorithms.put(\"RIPEMD256WITHRSAENCRYPTION\", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);\n        algorithms.put(\"RIPEMD256WITHRSA\", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);\n        algorithms.put(\"SHA1WITHDSA\", X9ObjectIdentifiers.id_dsa_with_sha1);\n        algorithms.put(\"DSAWITHSHA1\", X9ObjectIdentifiers.id_dsa_with_sha1);\n        algorithms.put(\"SHA224WITHDSA\", NISTObjectIdentifiers.dsa_with_sha224);\n        algorithms.put(\"SHA256WITHDSA\", NISTObjectIdentifiers.dsa_with_sha256);\n        algorithms.put(\"SHA384WITHDSA\", NISTObjectIdentifiers.dsa_with_sha384);\n        algorithms.put(\"SHA512WITHDSA\", NISTObjectIdentifiers.dsa_with_sha512);\n        algorithms.put(\"SHA1WITHECDSA\", X9ObjectIdentifiers.ecdsa_with_SHA1);\n        algorithms.put(\"ECDSAWITHSHA1\", X9ObjectIdentifiers.ecdsa_with_SHA1);\n        algorithms.put(\"SHA224WITHECDSA\", X9ObjectIdentifiers.ecdsa_with_SHA224);\n        algorithms.put(\"SHA256WITHECDSA\", X9ObjectIdentifiers.ecdsa_with_SHA256);\n        algorithms.put(\"SHA384WITHECDSA\", X9ObjectIdentifiers.ecdsa_with_SHA384);\n        algorithms.put(\"SHA512WITHECDSA\", X9ObjectIdentifiers.ecdsa_with_SHA512);\n        algorithms.put(\"GOST3411WITHGOST3410\", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);\n        algorithms.put(\"GOST3411WITHGOST3410-94\", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);\n        algorithms.put(\"GOST3411WITHECGOST3410\", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);\n        algorithms.put(\"GOST3411WITHECGOST3410-2001\", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);\n        algorithms.put(\"GOST3411WITHGOST3410-2001\", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);\n               \n        //\n        // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.\n        // The parameters field SHALL be NULL for RSA based signature algorithms.\n        //\n        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);\n        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);\n        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);\n        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);\n        noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);\n        noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);\n        noParams.add(NISTObjectIdentifiers.dsa_with_sha224);\n        noParams.add(NISTObjectIdentifiers.dsa_with_sha256);\n        noParams.add(NISTObjectIdentifiers.dsa_with_sha384);\n        noParams.add(NISTObjectIdentifiers.dsa_with_sha512);\n\n        //\n        // RFC 4491\n        //\n        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);\n        noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);\n\n        //\n        // PKCS 1.5 encrypted  algorithms\n        //\n        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha1WithRSAEncryption);\n        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha224WithRSAEncryption);\n        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha256WithRSAEncryption);\n        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha384WithRSAEncryption);\n        pkcs15RsaEncryption.add(PKCSObjectIdentifiers.sha512WithRSAEncryption);\n        pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);\n        pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);\n        pkcs15RsaEncryption.add(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);\n\n        //\n        // explicit params\n        //\n        AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);\n        params.put(\"SHA1WITHRSAANDMGF1\", createPSSParams(sha1AlgId, 20));\n\n        AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);\n        params.put(\"SHA224WITHRSAANDMGF1\", createPSSParams(sha224AlgId, 28));\n\n        AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);\n        params.put(\"SHA256WITHRSAANDMGF1\", createPSSParams(sha256AlgId, 32));\n\n        AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);\n        params.put(\"SHA384WITHRSAANDMGF1\", createPSSParams(sha384AlgId, 48));\n\n        AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);\n        params.put(\"SHA512WITHRSAANDMGF1\", createPSSParams(sha512AlgId, 64));\n\n        //\n        // digests\n        //\n        digestOids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224);\n        digestOids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256);\n        digestOids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384);\n        digestOids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512);\n        digestOids.put(PKCSObjectIdentifiers.md2WithRSAEncryption, PKCSObjectIdentifiers.md2);\n        digestOids.put(PKCSObjectIdentifiers.md4WithRSAEncryption, PKCSObjectIdentifiers.md4);\n        digestOids.put(PKCSObjectIdentifiers.md5WithRSAEncryption, PKCSObjectIdentifiers.md5);\n        digestOids.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, OIWObjectIdentifiers.idSHA1);\n        digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, TeleTrusTObjectIdentifiers.ripemd128);\n        digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, TeleTrusTObjectIdentifiers.ripemd160);\n        digestOids.put(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, TeleTrusTObjectIdentifiers.ripemd256);\n        digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, CryptoProObjectIdentifiers.gostR3411);\n        digestOids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, CryptoProObjectIdentifiers.gostR3411);\n    }\n\n    private static AlgorithmIdentifier generate(String signatureAlgorithm)\n    {\n        AlgorithmIdentifier sigAlgId;\n        AlgorithmIdentifier encAlgId;\n        AlgorithmIdentifier digAlgId;\n\n        String algorithmName = Strings.toUpperCase(signatureAlgorithm);\n        ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName);\n        if (sigOID == null)\n        {\n            throw new IllegalArgumentException(\"Unknown signature type requested: \" + algorithmName);\n        }\n\n        if (noParams.contains(sigOID))\n        {\n            sigAlgId = new AlgorithmIdentifier(sigOID);\n        }\n        else if (params.containsKey(algorithmName))\n        {\n            sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));\n        }\n        else\n        {\n            sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);\n        }\n\n        if (pkcs15RsaEncryption.contains(sigOID))\n        {\n            encAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);\n        }\n        else\n        {\n            encAlgId = sigAlgId;\n        }\n\n        if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))\n        {\n            digAlgId = ((RSASSAPSSparams)sigAlgId.getParameters()).getHashAlgorithm();\n        }\n        else\n        {\n            digAlgId = new AlgorithmIdentifier((ASN1ObjectIdentifier)digestOids.get(sigOID), DERNull.INSTANCE);\n        }\n\n        return sigAlgId;\n    }\n\n    private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)\n    {\n        return new RSASSAPSSparams(\n            hashAlgId,\n            new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),\n            new ASN1Integer(saltSize),\n            new ASN1Integer(1));\n    }\n\n    public AlgorithmIdentifier find(String sigAlgName)\n    {\n        return generate(sigAlgName);\n    }\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/DigestCalculator.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport java.io.OutputStream;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\n\n/**\n * General interface for an operator that is able to calculate a digest from\n * a stream of output.\n */\npublic interface DigestCalculator\n{\n    /**\n     * Return the algorithm identifier representing the digest implemented by\n     * this calculator.\n     *\n     * @return algorithm id and parameters.\n     */\n    AlgorithmIdentifier getAlgorithmIdentifier();\n\n    /**\n     * Returns a stream that will accept data for the purpose of calculating\n     * a digest. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate\n     * the data on the fly as well.\n     *\n     * @return an OutputStream\n     */\n    OutputStream getOutputStream();\n\n    /**\n     * Return the digest calculated on what has been written to the calculator's output stream.\n     *\n     * @return a digest.\n     */\n    byte[] getDigest();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/DigestCalculatorProvider.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\npublic interface DigestCalculatorProvider\n{\n    DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier)\n        throws OperatorCreationException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/OperatorCreationException.java",
    "content": "package local.org.bouncycastle.operator;\n\npublic class OperatorCreationException\n    extends OperatorException\n{\n    public OperatorCreationException(String msg, Throwable cause)\n    {\n        super(msg, cause);\n    }\n\n    public OperatorCreationException(String msg)\n    {\n        super(msg);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/OperatorException.java",
    "content": "package local.org.bouncycastle.operator;\n\npublic class OperatorException\n    extends Exception\n{\n    private Throwable cause;\n\n    public OperatorException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public OperatorException(String msg)\n    {\n        super(msg);\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/OperatorStreamException.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport java.io.IOException;\n\npublic class OperatorStreamException\n    extends IOException\n{\n    private Throwable cause;\n\n    public OperatorStreamException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause; \n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/RuntimeOperatorException.java",
    "content": "package local.org.bouncycastle.operator;\n\npublic class RuntimeOperatorException\n    extends RuntimeException\n{\n    private Throwable cause;\n\n    public RuntimeOperatorException(String msg)\n    {\n        super(msg);\n    }\n\n    public RuntimeOperatorException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/operator/SignatureAlgorithmIdentifierFinder.java",
    "content": "package local.org.bouncycastle.operator;\n\nimport local.org.bouncycastle.asn1.x509.AlgorithmIdentifier;\n\npublic interface SignatureAlgorithmIdentifierFinder\n{\n    /**\n     * Find the signature algorithm identifier that matches with\n     * the passed in signature algorithm name.\n     *\n     * @param sigAlgName the name of the signature algorithm of interest.\n     * @return an algorithm identifier for the corresponding signature.\n     */\n    AlgorithmIdentifier find(String sigAlgName);\n}"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/Arrays.java",
    "content": "package local.org.bouncycastle.util;\n\nimport java.math.BigInteger;\n\n/**\n * General array utilities.\n */\npublic final class Arrays\n{\n    private Arrays() \n    {\n        // static class, hide constructor\n    }\n    \n    public static boolean areEqual(\n        boolean[]  a,\n        boolean[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        for (int i = 0; i != a.length; i++)\n        {\n            if (a[i] != b[i])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static boolean areEqual(\n        char[]  a,\n        char[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        for (int i = 0; i != a.length; i++)\n        {\n            if (a[i] != b[i])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static boolean areEqual(\n        byte[]  a,\n        byte[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        for (int i = 0; i != a.length; i++)\n        {\n            if (a[i] != b[i])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * A constant time equals comparison - does not terminate early if\n     * test will fail.\n     *\n     * @param a first array\n     * @param b second array\n     * @return true if arrays equal, false otherwise.\n     */\n    public static boolean constantTimeAreEqual(\n        byte[]  a,\n        byte[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        int nonEqual = 0;\n\n        for (int i = 0; i != a.length; i++)\n        {\n            nonEqual |= (a[i] ^ b[i]);\n        }\n\n        return nonEqual == 0;\n    }\n\n    public static boolean areEqual(\n        int[]  a,\n        int[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        for (int i = 0; i != a.length; i++)\n        {\n            if (a[i] != b[i])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static boolean areEqual(\n        long[]  a,\n        long[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        for (int i = 0; i != a.length; i++)\n        {\n            if (a[i] != b[i])\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static boolean areEqual(\n        BigInteger[]  a,\n        BigInteger[]  b)\n    {\n        if (a == b)\n        {\n            return true;\n        }\n\n        if (a == null || b == null)\n        {\n            return false;\n        }\n\n        if (a.length != b.length)\n        {\n            return false;\n        }\n\n        for (int i = 0; i != a.length; i++)\n        {\n            if (!a[i].equals(b[i]))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    public static void fill(\n        byte[] array,\n        byte value)\n    {\n        for (int i = 0; i < array.length; i++)\n        {\n            array[i] = value;\n        }\n    }\n\n    public static void fill(\n        char[] array,\n        char value)\n    {\n        for (int i = 0; i < array.length; i++)\n        {\n            array[i] = value;\n        }\n    }\n\n    public static void fill(\n        long[] array,\n        long value)\n    {\n        for (int i = 0; i < array.length; i++)\n        {\n            array[i] = value;\n        }\n    }\n\n    public static void fill(\n        short[] array, \n        short value)\n    {\n        for (int i = 0; i < array.length; i++)\n        {\n            array[i] = value;\n        }\n    }\n\n    public static void fill(\n        int[] array,\n        int value)\n    {\n        for (int i = 0; i < array.length; i++)\n        {\n            array[i] = value;\n        }\n    }\n    \n    public static int hashCode(byte[] data)\n    {\n        if (data == null)\n        {\n            return 0;\n        }\n\n        int i = data.length;\n        int hc = i + 1;\n\n        while (--i >= 0)\n        {\n            hc *= 257;\n            hc ^= data[i];\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(char[] data)\n    {\n        if (data == null)\n        {\n            return 0;\n        }\n\n        int i = data.length;\n        int hc = i + 1;\n\n        while (--i >= 0)\n        {\n            hc *= 257;\n            hc ^= data[i];\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(int[][] ints)\n    {\n        int hc = 0;\n\n        for (int i = 0; i != ints.length; i++)\n        {\n            hc = hc * 257 + hashCode(ints[i]);\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(int[] data)\n    {\n        if (data == null)\n        {\n            return 0;\n        }\n\n        int i = data.length;\n        int hc = i + 1;\n\n        while (--i >= 0)\n        {\n            hc *= 257;\n            hc ^= data[i];\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(short[][][] shorts)\n    {\n        int hc = 0;\n\n        for (int i = 0; i != shorts.length; i++)\n        {\n            hc = hc * 257 + hashCode(shorts[i]);\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(short[][] shorts)\n    {\n        int hc = 0;\n\n        for (int i = 0; i != shorts.length; i++)\n        {\n            hc = hc * 257 + hashCode(shorts[i]);\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(short[] data)\n    {\n        if (data == null)\n        {\n            return 0;\n        }\n\n        int i = data.length;\n        int hc = i + 1;\n\n        while (--i >= 0)\n        {\n            hc *= 257;\n            hc ^= (data[i] & 0xff);\n        }\n\n        return hc;\n    }\n\n    public static int hashCode(BigInteger[] data)\n    {\n        if (data == null)\n        {\n            return 0;\n        }\n\n        int i = data.length;\n        int hc = i + 1;\n\n        while (--i >= 0)\n        {\n            hc *= 257;\n            hc ^= data[i].hashCode();\n        }\n\n        return hc;\n    }\n\n    public static byte[] clone(byte[] data)\n    {\n        if (data == null)\n        {\n            return null;\n        }\n        byte[] copy = new byte[data.length];\n\n        System.arraycopy(data, 0, copy, 0, data.length);\n\n        return copy;\n    }\n\n    public static byte[][] clone(byte[][] data)\n    {\n        if (data == null)\n        {\n            return null;\n        }\n\n        byte[][] copy = new byte[data.length][];\n\n        for (int i = 0; i != copy.length; i++)\n        {\n            copy[i] = clone(data[i]);\n        }\n\n        return copy;\n    }\n\n    public static byte[][][] clone(byte[][][] data)\n    {\n        if (data == null)\n        {\n            return null;\n        }\n\n        byte[][][] copy = new byte[data.length][][];\n\n        for (int i = 0; i != copy.length; i++)\n        {\n            copy[i] = clone(data[i]);\n        }\n\n        return copy;\n    }\n\n    public static int[] clone(int[] data)\n    {\n        if (data == null)\n        {\n            return null;\n        }\n        int[] copy = new int[data.length];\n\n        System.arraycopy(data, 0, copy, 0, data.length);\n\n        return copy;\n    }\n\n    public static short[] clone(short[] data)\n    {\n        if (data == null)\n        {\n            return null;\n        }\n        short[] copy = new short[data.length];\n\n        System.arraycopy(data, 0, copy, 0, data.length);\n\n        return copy;\n    }\n\n    public static BigInteger[] clone(BigInteger[] data)\n    {\n        if (data == null)\n        {\n            return null;\n        }\n        BigInteger[] copy = new BigInteger[data.length];\n\n        System.arraycopy(data, 0, copy, 0, data.length);\n\n        return copy;\n    }\n\n    public static byte[] copyOf(byte[] data, int newLength)\n    {\n        byte[] tmp = new byte[newLength];\n\n        if (newLength < data.length)\n        {\n            System.arraycopy(data, 0, tmp, 0, newLength);\n        }\n        else\n        {\n            System.arraycopy(data, 0, tmp, 0, data.length);\n        }\n\n        return tmp;\n    }\n\n    public static char[] copyOf(char[] data, int newLength)\n    {\n        char[] tmp = new char[newLength];\n\n        if (newLength < data.length)\n        {\n            System.arraycopy(data, 0, tmp, 0, newLength);\n        }\n        else\n        {\n            System.arraycopy(data, 0, tmp, 0, data.length);\n        }\n\n        return tmp;\n    }\n\n    public static int[] copyOf(int[] data, int newLength)\n    {\n        int[] tmp = new int[newLength];\n\n        if (newLength < data.length)\n        {\n            System.arraycopy(data, 0, tmp, 0, newLength);\n        }\n        else\n        {\n            System.arraycopy(data, 0, tmp, 0, data.length);\n        }\n\n        return tmp;\n    }\n\n    public static long[] copyOf(long[] data, int newLength)\n    {\n        long[] tmp = new long[newLength];\n\n        if (newLength < data.length)\n        {\n            System.arraycopy(data, 0, tmp, 0, newLength);\n        }\n        else\n        {\n            System.arraycopy(data, 0, tmp, 0, data.length);\n        }\n\n        return tmp;\n    }\n\n    public static BigInteger[] copyOf(BigInteger[] data, int newLength)\n    {\n        BigInteger[] tmp = new BigInteger[newLength];\n\n        if (newLength < data.length)\n        {\n            System.arraycopy(data, 0, tmp, 0, newLength);\n        }\n        else\n        {\n            System.arraycopy(data, 0, tmp, 0, data.length);\n        }\n\n        return tmp;\n    }\n\n    public static byte[] copyOfRange(byte[] data, int from, int to)\n    {\n        int newLength = getLength(from, to);\n\n        byte[] tmp = new byte[newLength];\n\n        if (data.length - from < newLength)\n        {\n            System.arraycopy(data, from, tmp, 0, data.length - from);\n        }\n        else\n        {\n            System.arraycopy(data, from, tmp, 0, newLength);\n        }\n\n        return tmp;\n    }\n\n    public static int[] copyOfRange(int[] data, int from, int to)\n    {\n        int newLength = getLength(from, to);\n\n        int[] tmp = new int[newLength];\n\n        if (data.length - from < newLength)\n        {\n            System.arraycopy(data, from, tmp, 0, data.length - from);\n        }\n        else\n        {\n            System.arraycopy(data, from, tmp, 0, newLength);\n        }\n\n        return tmp;\n    }\n\n    public static long[] copyOfRange(long[] data, int from, int to)\n    {\n        int newLength = getLength(from, to);\n\n        long[] tmp = new long[newLength];\n\n        if (data.length - from < newLength)\n        {\n            System.arraycopy(data, from, tmp, 0, data.length - from);\n        }\n        else\n        {\n            System.arraycopy(data, from, tmp, 0, newLength);\n        }\n\n        return tmp;\n    }\n\n    public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to)\n    {\n        int newLength = getLength(from, to);\n\n        BigInteger[] tmp = new BigInteger[newLength];\n\n        if (data.length - from < newLength)\n        {\n            System.arraycopy(data, from, tmp, 0, data.length - from);\n        }\n        else\n        {\n            System.arraycopy(data, from, tmp, 0, newLength);\n        }\n\n        return tmp;\n    }\n\n    private static int getLength(int from, int to)\n    {\n        int newLength = to - from;\n        if (newLength < 0)\n        {\n            StringBuffer sb = new StringBuffer(from);\n            sb.append(\" > \").append(to);\n            throw new IllegalArgumentException(sb.toString());\n        }\n        return newLength;\n    }\n\n    public static byte[] concatenate(byte[] a, byte[] b)\n    {\n        if (a != null && b != null)\n        {\n            byte[] rv = new byte[a.length + b.length];\n\n            System.arraycopy(a, 0, rv, 0, a.length);\n            System.arraycopy(b, 0, rv, a.length, b.length);\n\n            return rv;\n        }\n        else if (b != null)\n        {\n            return clone(b);\n        }\n        else\n        {\n            return clone(a);\n        }\n    }\n\n    public static byte[] concatenate(byte[] a, byte[] b, byte[] c)\n    {\n        if (a != null && b != null && c != null)\n        {\n            byte[] rv = new byte[a.length + b.length + c.length];\n\n            System.arraycopy(a, 0, rv, 0, a.length);\n            System.arraycopy(b, 0, rv, a.length, b.length);\n            System.arraycopy(c, 0, rv, a.length + b.length, c.length);\n\n            return rv;\n        }\n        else if (b == null)\n        {\n            return concatenate(a, c);\n        }\n        else\n        {\n            return concatenate(a, b);\n        }\n    }\n\n    public static byte[] concatenate(byte[] a, byte[] b, byte[] c, byte[] d)\n    {\n        if (a != null && b != null && c != null && d != null)\n        {\n            byte[] rv = new byte[a.length + b.length + c.length + d.length];\n\n            System.arraycopy(a, 0, rv, 0, a.length);\n            System.arraycopy(b, 0, rv, a.length, b.length);\n            System.arraycopy(c, 0, rv, a.length + b.length, c.length);\n            System.arraycopy(d, 0, rv, a.length + b.length + c.length, d.length);\n\n            return rv;\n        }\n        else if (d == null)\n        {\n            return concatenate(a, b, c);\n        }\n        else if (c == null)\n        {\n            return concatenate(a, b, d);\n        }\n        else if (b == null)\n        {\n            return concatenate(a, c, d);\n        }\n        else\n        {\n            return concatenate(b, c, d);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/IPAddress.java",
    "content": "package local.org.bouncycastle.util;\n\npublic class IPAddress\n{\n    /**\n     * Validate the given IPv4 or IPv6 address.\n     *\n     * @param address the IP address as a String.\n     *\n     * @return true if a valid address, false otherwise\n     */\n    public static boolean isValid(\n        String address)\n    {\n        return isValidIPv4(address) || isValidIPv6(address);\n    }\n\n    /**\n     * Validate the given IPv4 or IPv6 address and netmask.\n     *\n     * @param address the IP address as a String.\n     *\n     * @return true if a valid address with netmask, false otherwise\n     */\n    public static boolean isValidWithNetMask(\n        String address)\n    {\n        return isValidIPv4WithNetmask(address) || isValidIPv6WithNetmask(address);\n    }\n\n    /**\n     * Validate the given IPv4 address.\n     * \n     * @param address the IP address as a String.\n     *\n     * @return true if a valid IPv4 address, false otherwise\n     */\n    public static boolean isValidIPv4(\n        String address)\n    {\n        if (address.length() == 0)\n        {\n            return false;\n        }\n\n        int octet;\n        int octets = 0;\n        \n        String temp = address+\".\";\n\n        int pos;\n        int start = 0;\n        while (start < temp.length()\n            && (pos = temp.indexOf('.', start)) > start)\n        {\n            if (octets == 4)\n            {\n                return false;\n            }\n            try\n            {\n                octet = Integer.parseInt(temp.substring(start, pos));\n            }\n            catch (NumberFormatException ex)\n            {\n                return false;\n            }\n            if (octet < 0 || octet > 255)\n            {\n                return false;\n            }\n            start = pos + 1;\n            octets++;\n        }\n\n        return octets == 4;\n    }\n\n    public static boolean isValidIPv4WithNetmask(\n        String address)\n    {\n        int index = address.indexOf(\"/\");\n        String mask = address.substring(index + 1);\n\n        return (index > 0) && isValidIPv4(address.substring(0, index))\n                           && (isValidIPv4(mask) || isMaskValue(mask, 32));\n    }\n\n    public static boolean isValidIPv6WithNetmask(\n        String address)\n    {\n        int index = address.indexOf(\"/\");\n        String mask = address.substring(index + 1);\n\n        return (index > 0) && (isValidIPv6(address.substring(0, index))\n                           && (isValidIPv6(mask) || isMaskValue(mask, 128)));\n    }\n\n    private static boolean isMaskValue(String component, int size)\n    {\n        try\n        {\n            int value = Integer.parseInt(component);\n\n            return value >= 0 && value <= size;\n        }\n        catch (NumberFormatException e)\n        {\n            return false;\n        }\n    }\n\n    /**\n     * Validate the given IPv6 address.\n     *\n     * @param address the IP address as a String.\n     *\n     * @return true if a valid IPv4 address, false otherwise\n     */\n    public static boolean isValidIPv6(\n        String address)\n    {\n        if (address.length() == 0)\n        {\n            return false;\n        }\n\n        int octet;\n        int octets = 0;\n\n        String temp = address + \":\";\n        boolean doubleColonFound = false;\n        int pos;\n        int start = 0;\n        while (start < temp.length()\n            && (pos = temp.indexOf(':', start)) >= start)\n        {\n            if (octets == 8)\n            {\n                return false;\n            }\n\n            if (start != pos)\n            {\n                String value = temp.substring(start, pos);\n\n                if (pos == (temp.length() - 1) && value.indexOf('.') > 0)\n                {\n                    if (!isValidIPv4(value))\n                    {\n                        return false;\n                    }\n\n                    octets++; // add an extra one as address covers 2 words.\n                }\n                else\n                {\n                    try\n                    {\n                        octet = Integer.parseInt(temp.substring(start, pos), 16);\n                    }\n                    catch (NumberFormatException ex)\n                    {\n                        return false;\n                    }\n                    if (octet < 0 || octet > 0xffff)\n                    {\n                        return false;\n                    }\n                }\n            }\n            else\n            {\n                if (pos != 1 && pos != temp.length() - 1 && doubleColonFound)\n                {\n                    return false;\n                }\n                doubleColonFound = true;\n            }\n            start = pos + 1;\n            octets++;\n        }\n\n        return octets == 8 || doubleColonFound;\n    }\n}\n\n\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/Memoable.java",
    "content": "package local.org.bouncycastle.util;\n\npublic interface Memoable\n{\n    /**\n     * Produce a copy of this object with its configuration and in its current state.\n     * <p/>\n     * The returned object may be used simply to store the state, or may be used as a similar object\n     * starting from the copied state.\n     */\n    public Memoable copy();\n\n    /**\n     * Restore a copied object state into this object.\n     * <p/>\n     * Implementations of this method <em>should</em> try to avoid or minimise memory allocation to perform the reset.\n     *\n     * @param other an object originally {@link #copy() copied} from an object of the same type as this instance.\n     * @throws ClassCastException if the provided object is not of the correct type.\n     * @throws MemoableResetException if the <b>other</b> parameter is in some other way invalid.\n     */\n    public void reset(Memoable other);\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/Selector.java",
    "content": "package local.org.bouncycastle.util;\n\npublic interface Selector\n    extends Cloneable\n{\n    boolean match(Object obj);\n\n    Object clone();\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/Strings.java",
    "content": "package local.org.bouncycastle.util;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Vector;\n\npublic final class Strings\n{\n    public static String fromUTF8ByteArray(byte[] bytes)\n    {\n        int i = 0;\n        int length = 0;\n\n        while (i < bytes.length)\n        {\n            length++;\n            if ((bytes[i] & 0xf0) == 0xf0)\n            {\n                // surrogate pair\n                length++;\n                i += 4;\n            }\n            else if ((bytes[i] & 0xe0) == 0xe0)\n            {\n                i += 3;\n            }\n            else if ((bytes[i] & 0xc0) == 0xc0)\n            {\n                i += 2;\n            }\n            else\n            {\n                i += 1;\n            }\n        }\n\n        char[] cs = new char[length];\n\n        i = 0;\n        length = 0;\n\n        while (i < bytes.length)\n        {\n            char ch;\n\n            if ((bytes[i] & 0xf0) == 0xf0)\n            {\n                int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i+1] & 0x3F) << 12) | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F);\n                int U = codePoint - 0x10000;\n                char W1 = (char)(0xD800 | (U >> 10));\n                char W2 = (char)(0xDC00 | (U & 0x3FF));\n                cs[length++] = W1;\n                ch = W2;\n                i += 4;\n            }\n            else if ((bytes[i] & 0xe0) == 0xe0)\n            {\n                ch = (char)(((bytes[i] & 0x0f) << 12)\n                        | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));\n                i += 3;\n            }\n            else if ((bytes[i] & 0xd0) == 0xd0)\n            {\n                ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));\n                i += 2;\n            }\n            else if ((bytes[i] & 0xc0) == 0xc0)\n            {\n                ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));\n                i += 2;\n            }\n            else\n            {\n                ch = (char)(bytes[i] & 0xff);\n                i += 1;\n            }\n\n            cs[length++] = ch;\n        }\n\n        return new String(cs);\n    }\n    \n    public static byte[] toUTF8ByteArray(String string)\n    {\n        return toUTF8ByteArray(string.toCharArray());\n    }\n\n    public static byte[] toUTF8ByteArray(char[] string)\n    {\n        ByteArrayOutputStream bOut = new ByteArrayOutputStream();\n\n        try\n        {\n            toUTF8ByteArray(string, bOut);\n        }\n        catch (IOException e)\n        {\n            throw new IllegalStateException(\"cannot encode string to byte array!\");\n        }\n        \n        return bOut.toByteArray();\n    }\n\n    public static void toUTF8ByteArray(char[] string, OutputStream sOut)\n        throws IOException\n    {\n        char[] c = string;\n        int i = 0;\n\n        while (i < c.length)\n        {\n            char ch = c[i];\n\n            if (ch < 0x0080)\n            {\n                sOut.write(ch);\n            }\n            else if (ch < 0x0800)\n            {\n                sOut.write(0xc0 | (ch >> 6));\n                sOut.write(0x80 | (ch & 0x3f));\n            }\n            // surrogate pair\n            else if (ch >= 0xD800 && ch <= 0xDFFF)\n            {\n                // in error - can only happen, if the Java String class has a\n                // bug.\n                if (i + 1 >= c.length)\n                {\n                    throw new IllegalStateException(\"invalid UTF-16 codepoint\");\n                }\n                char W1 = ch;\n                ch = c[++i];\n                char W2 = ch;\n                // in error - can only happen, if the Java String class has a\n                // bug.\n                if (W1 > 0xDBFF)\n                {\n                    throw new IllegalStateException(\"invalid UTF-16 codepoint\");\n                }\n                int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;\n                sOut.write(0xf0 | (codePoint >> 18));\n                sOut.write(0x80 | ((codePoint >> 12) & 0x3F));\n                sOut.write(0x80 | ((codePoint >> 6) & 0x3F));\n                sOut.write(0x80 | (codePoint & 0x3F));\n            }\n            else\n            {\n                sOut.write(0xe0 | (ch >> 12));\n                sOut.write(0x80 | ((ch >> 6) & 0x3F));\n                sOut.write(0x80 | (ch & 0x3F));\n            }\n\n            i++;\n        }\n    }\n\n    /**\n     * A locale independent version of toUpperCase.\n     * \n     * @param string input to be converted\n     * @return a US Ascii uppercase version\n     */\n    public static String toUpperCase(String string)\n    {\n        boolean changed = false;\n        char[] chars = string.toCharArray();\n        \n        for (int i = 0; i != chars.length; i++)\n        {\n            char ch = chars[i];\n            if ('a' <= ch && 'z' >= ch)\n            {\n                changed = true;\n                chars[i] = (char)(ch - 'a' + 'A');\n            }\n        }\n        \n        if (changed)\n        {\n            return new String(chars);\n        }\n        \n        return string;\n    }\n    \n    /**\n     * A locale independent version of toLowerCase.\n     * \n     * @param string input to be converted\n     * @return a US ASCII lowercase version\n     */\n    public static String toLowerCase(String string)\n    {\n        boolean changed = false;\n        char[] chars = string.toCharArray();\n        \n        for (int i = 0; i != chars.length; i++)\n        {\n            char ch = chars[i];\n            if ('A' <= ch && 'Z' >= ch)\n            {\n                changed = true;\n                chars[i] = (char)(ch - 'A' + 'a');\n            }\n        }\n        \n        if (changed)\n        {\n            return new String(chars);\n        }\n        \n        return string;\n    }\n\n    public static byte[] toByteArray(char[] chars)\n    {\n        byte[] bytes = new byte[chars.length];\n\n        for (int i = 0; i != bytes.length; i++)\n        {\n            bytes[i] = (byte)chars[i];\n        }\n\n        return bytes;\n    }\n\n    public static byte[] toByteArray(String string)\n    {\n        byte[] bytes = new byte[string.length()];\n\n        for (int i = 0; i != bytes.length; i++)\n        {\n            char ch = string.charAt(i);\n\n            bytes[i] = (byte)ch;\n        }\n\n        return bytes;\n    }\n\n    /**\n     * Convert an array of 8 bit characters into a string.\n     *\n     * @param bytes 8 bit characters.\n     * @return resulting String.\n     */\n    public static String fromByteArray(byte[] bytes)\n    {\n        return new String(asCharArray(bytes));\n    }\n\n    /**\n     * Do a simple conversion of an array of 8 bit characters into a string.\n     *\n     * @param bytes 8 bit characters.\n     * @return resulting String.\n     */\n    public static char[] asCharArray(byte[] bytes)\n    {\n        char[] chars = new char[bytes.length];\n\n        for (int i = 0; i != chars.length; i++)\n        {\n            chars[i] = (char)(bytes[i] & 0xff);\n        }\n\n        return chars;\n    }\n\n    public static String[] split(String input, char delimiter)\n    {\n        Vector           v = new Vector();\n        boolean moreTokens = true;\n        String subString;\n\n        while (moreTokens)\n        {\n            int tokenLocation = input.indexOf(delimiter);\n            if (tokenLocation > 0)\n            {\n                subString = input.substring(0, tokenLocation);\n                v.addElement(subString);\n                input = input.substring(tokenLocation + 1);\n            }\n            else\n            {\n                moreTokens = false;\n                v.addElement(input);\n            }\n        }\n\n        String[] res = new String[v.size()];\n\n        for (int i = 0; i != res.length; i++)\n        {\n            res[i] = (String)v.elementAt(i);\n        }\n        return res;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/encoders/DecoderException.java",
    "content": "package local.org.bouncycastle.util.encoders;\n\npublic class DecoderException\n    extends IllegalStateException\n{\n    private Throwable cause;\n\n    DecoderException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/encoders/Encoder.java",
    "content": "package local.org.bouncycastle.util.encoders;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Encode and decode byte arrays (typically from binary to 7-bit ASCII \n * encodings).\n */\npublic interface Encoder\n{\n    int encode(byte[] data, int off, int length, OutputStream out) throws IOException;\n    \n    int decode(byte[] data, int off, int length, OutputStream out) throws IOException;\n\n    int decode(String data, OutputStream out) throws IOException;\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/encoders/EncoderException.java",
    "content": "package local.org.bouncycastle.util.encoders;\n\npublic class EncoderException\n    extends IllegalStateException\n{\n    private Throwable cause;\n\n    EncoderException(String msg, Throwable cause)\n    {\n        super(msg);\n\n        this.cause = cause;\n    }\n\n    public Throwable getCause()\n    {\n        return cause;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/encoders/Hex.java",
    "content": "package local.org.bouncycastle.util.encoders;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport local.org.bouncycastle.util.Strings;\n\n\npublic class Hex\n{\n    private static final Encoder encoder = new HexEncoder();\n    \n    public static String toHexString(\n        byte[] data)\n    {\n        return toHexString(data, 0, data.length);\n    }\n\n    public static String toHexString(\n        byte[] data,\n        int    off,\n        int    length)\n    {\n        byte[] encoded = encode(data, off, length);\n        return Strings.fromByteArray(encoded);\n    }\n\n    /**\n     * encode the input data producing a Hex encoded byte array.\n     *\n     * @return a byte array containing the Hex encoded data.\n     */\n    public static byte[] encode(\n        byte[]    data)\n    {\n        return encode(data, 0, data.length);\n    }\n    \n    /**\n     * encode the input data producing a Hex encoded byte array.\n     *\n     * @return a byte array containing the Hex encoded data.\n     */\n    public static byte[] encode(\n        byte[]    data,\n        int       off,\n        int       length)\n    {\n        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();\n        \n        try\n        {\n            encoder.encode(data, off, length, bOut);\n        }\n        catch (Exception e)\n        {\n            throw new EncoderException(\"exception encoding Hex string: \" + e.getMessage(), e);\n        }\n        \n        return bOut.toByteArray();\n    }\n\n    /**\n     * Hex encode the byte data writing it to the given output stream.\n     *\n     * @return the number of bytes produced.\n     */\n    public static int encode(\n        byte[]         data,\n        OutputStream   out)\n        throws IOException\n    {\n        return encoder.encode(data, 0, data.length, out);\n    }\n    \n    /**\n     * Hex encode the byte data writing it to the given output stream.\n     *\n     * @return the number of bytes produced.\n     */\n    public static int encode(\n        byte[]         data,\n        int            off,\n        int            length,\n        OutputStream   out)\n        throws IOException\n    {\n        return encoder.encode(data, off, length, out);\n    }\n    \n    /**\n     * decode the Hex encoded input data. It is assumed the input data is valid.\n     *\n     * @return a byte array representing the decoded data.\n     */\n    public static byte[] decode(\n        byte[]    data)\n    {\n        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();\n        \n        try\n        {\n            encoder.decode(data, 0, data.length, bOut);\n        }\n        catch (Exception e)\n        {\n            throw new DecoderException(\"exception decoding Hex data: \" + e.getMessage(), e);\n        }\n        \n        return bOut.toByteArray();\n    }\n    \n    /**\n     * decode the Hex encoded String data - whitespace will be ignored.\n     *\n     * @return a byte array representing the decoded data.\n     */\n    public static byte[] decode(\n        String    data)\n    {\n        ByteArrayOutputStream    bOut = new ByteArrayOutputStream();\n        \n        try\n        {\n            encoder.decode(data, bOut);\n        }\n        catch (Exception e)\n        {\n            throw new DecoderException(\"exception decoding Hex string: \" + e.getMessage(), e);\n        }\n        \n        return bOut.toByteArray();\n    }\n    \n    /**\n     * decode the Hex encoded String data writing it to the given output stream,\n     * whitespace characters will be ignored.\n     *\n     * @return the number of bytes produced.\n     */\n    public static int decode(\n        String          data,\n        OutputStream    out)\n        throws IOException\n    {\n        return encoder.decode(data, out);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/encoders/HexEncoder.java",
    "content": "package local.org.bouncycastle.util.encoders;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\npublic class HexEncoder\n    implements Encoder\n{\n    protected final byte[] encodingTable =\n        {\n            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',\n            (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'\n        };\n    \n    /*\n     * set up the decoding table.\n     */\n    protected final byte[] decodingTable = new byte[128];\n\n    protected void initialiseDecodingTable()\n    {\n        for (int i = 0; i < decodingTable.length; i++)\n        {\n            decodingTable[i] = (byte)0xff;\n        }\n\n        for (int i = 0; i < encodingTable.length; i++)\n        {\n            decodingTable[encodingTable[i]] = (byte)i;\n        }\n        \n        decodingTable['A'] = decodingTable['a'];\n        decodingTable['B'] = decodingTable['b'];\n        decodingTable['C'] = decodingTable['c'];\n        decodingTable['D'] = decodingTable['d'];\n        decodingTable['E'] = decodingTable['e'];\n        decodingTable['F'] = decodingTable['f'];\n    }\n    \n    public HexEncoder()\n    {\n        initialiseDecodingTable();\n    }\n    \n    /**\n     * encode the input data producing a Hex output stream.\n     *\n     * @return the number of bytes produced.\n     */\n    public int encode(\n        byte[]                data,\n        int                    off,\n        int                    length,\n        OutputStream    out) \n        throws IOException\n    {        \n        for (int i = off; i < (off + length); i++)\n        {\n            int    v = data[i] & 0xff;\n\n            out.write(encodingTable[(v >>> 4)]);\n            out.write(encodingTable[v & 0xf]);\n        }\n\n        return length * 2;\n    }\n\n    private static boolean ignore(\n        char    c)\n    {\n        return c == '\\n' || c =='\\r' || c == '\\t' || c == ' ';\n    }\n\n    /**\n     * decode the Hex encoded byte data writing it to the given output stream,\n     * whitespace characters will be ignored.\n     *\n     * @return the number of bytes produced.\n     */\n    public int decode(\n        byte[]          data,\n        int             off,\n        int             length,\n        OutputStream    out)\n        throws IOException\n    {\n        byte    b1, b2;\n        int     outLen = 0;\n        \n        int     end = off + length;\n        \n        while (end > off)\n        {\n            if (!ignore((char)data[end - 1]))\n            {\n                break;\n            }\n            \n            end--;\n        }\n        \n        int i = off;\n        while (i < end)\n        {\n            while (i < end && ignore((char)data[i]))\n            {\n                i++;\n            }\n            \n            b1 = decodingTable[data[i++]];\n            \n            while (i < end && ignore((char)data[i]))\n            {\n                i++;\n            }\n            \n            b2 = decodingTable[data[i++]];\n\n            if ((b1 | b2) < 0)\n            {\n                throw new IOException(\"invalid characters encountered in Hex data\");\n            }\n\n            out.write((b1 << 4) | b2);\n            \n            outLen++;\n        }\n\n        return outLen;\n    }\n    \n    /**\n     * decode the Hex encoded String data writing it to the given output stream,\n     * whitespace characters will be ignored.\n     *\n     * @return the number of bytes produced.\n     */\n    public int decode(\n        String          data,\n        OutputStream    out)\n        throws IOException\n    {\n        byte    b1, b2;\n        int     length = 0;\n        \n        int     end = data.length();\n        \n        while (end > 0)\n        {\n            if (!ignore(data.charAt(end - 1)))\n            {\n                break;\n            }\n            \n            end--;\n        }\n        \n        int i = 0;\n        while (i < end)\n        {\n            while (i < end && ignore(data.charAt(i)))\n            {\n                i++;\n            }\n            \n            b1 = decodingTable[data.charAt(i++)];\n            \n            while (i < end && ignore(data.charAt(i)))\n            {\n                i++;\n            }\n            \n            b2 = decodingTable[data.charAt(i++)];\n\n            if ((b1 | b2) < 0)\n            {\n                throw new IOException(\"invalid characters encountered in Hex string\");\n            }\n\n            out.write((b1 << 4) | b2);\n            \n            length++;\n        }\n\n        return length;\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/io/StreamOverflowException.java",
    "content": "package local.org.bouncycastle.util.io;\n\nimport java.io.IOException;\n\npublic class StreamOverflowException\n    extends IOException\n{\n    public StreamOverflowException(String msg)\n    {\n        super(msg);\n    }\n}\n"
  },
  {
    "path": "libs/bouncycastle/src/local/org/bouncycastle/util/io/Streams.java",
    "content": "package local.org.bouncycastle.util.io;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic final class Streams\n{\n    private static int BUFFER_SIZE = 512;\n\n    public static void drain(InputStream inStr)\n        throws IOException\n    {\n        byte[] bs = new byte[BUFFER_SIZE];\n        while (inStr.read(bs, 0, bs.length) >= 0)\n        {\n        }\n    }\n\n    public static byte[] readAll(InputStream inStr)\n        throws IOException\n    {\n        ByteArrayOutputStream buf = new ByteArrayOutputStream();\n        pipeAll(inStr, buf);\n        return buf.toByteArray();\n    }\n\n    public static byte[] readAllLimited(InputStream inStr, int limit)\n        throws IOException\n    {\n        ByteArrayOutputStream buf = new ByteArrayOutputStream();\n        pipeAllLimited(inStr, limit, buf);\n        return buf.toByteArray();\n    }\n\n    public static int readFully(InputStream inStr, byte[] buf)\n        throws IOException\n    {\n        return readFully(inStr, buf, 0, buf.length);\n    }\n\n    public static int readFully(InputStream inStr, byte[] buf, int off, int len)\n        throws IOException\n    {\n        int totalRead = 0;\n        while (totalRead < len)\n        {\n            int numRead = inStr.read(buf, off + totalRead, len - totalRead);\n            if (numRead < 0)\n            {\n                break;\n            }\n            totalRead += numRead;\n        }\n        return totalRead;\n    }\n\n    public static void pipeAll(InputStream inStr, OutputStream outStr)\n        throws IOException\n    {\n        byte[] bs = new byte[BUFFER_SIZE];\n        int numRead;\n        while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)\n        {\n            outStr.write(bs, 0, numRead);\n        }\n    }\n\n    public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr)\n        throws IOException\n    {\n        long total = 0;\n        byte[] bs = new byte[BUFFER_SIZE];\n        int numRead;\n        while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)\n        {\n            total += numRead;\n            if (total > limit)\n            {\n                throw new StreamOverflowException(\"Data Overflow\");\n            }\n            outStr.write(bs, 0, numRead);\n        }\n        return total;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/AndroidManifestLibrary.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     package=\"gov2.nist\">\n</manifest>"
  },
  {
    "path": "libs/nist_sip/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifestLibrary.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\t\n}"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/Debug.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n*******************************************************************************/\npackage gov2.nist.core;\n\n\n/**\n *   A class to do debug printfs\n */\npublic class Debug {\n\n    public static  boolean debug = false;\n    public static  boolean parserDebug = false;\n    \n    static StackLogger stackLogger;\n    \n    public static void setStackLogger(StackLogger stackLogger) {\n        Debug.stackLogger = stackLogger;\n    }\n\n    public static void println(String s) {\n        if ((parserDebug || debug )&& stackLogger != null )\n            stackLogger.logDebug(s + \"\\n\");\n    }\n    public static void printStackTrace(Exception ex) {\n        if ((parserDebug || debug ) && stackLogger != null) {\n            stackLogger.logError(\"Stack Trace\",ex);\n        }\n    }\n\n    public static void logError(String message, Exception ex) {\n      if ((parserDebug || debug) &&  stackLogger != null ) {\n          stackLogger.logError(message,ex);\n      }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/DuplicateNameValueList.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\npackage gov2.nist.core;\n\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * \n * \n * This is a Duplicate Name Value List that will allow multiple values map to the same key.\n * \n * The parsing and encoding logic for it is the same as that of NameValueList. Only the HashMap\n * container is different.\n * \n * @author aayush.bhatnagar\n * @since 2.0\n * \n */\npublic class DuplicateNameValueList implements Serializable, Cloneable {\n\n    private MultiValueMapImpl<NameValue> nameValueMap = new MultiValueMapImpl<NameValue>();\n    private String separator;\n\n    private static final long serialVersionUID = -5611332957903796952L;\n\n    public DuplicateNameValueList()\n\n    {\n        this.separator = \";\";\n    }\n\n    // ------------------\n\n    public void setSeparator(String separator) {\n        this.separator = separator;\n    }\n\n    /**\n     * Encode the list in semicolon separated form.\n     * \n     * @return an encoded string containing the objects in this list.\n     * @since v1.0\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (!nameValueMap.isEmpty()) {\n            Iterator<NameValue> iterator = nameValueMap.values().iterator();\n            if (iterator.hasNext()) {\n                while (true) {\n                    Object obj = iterator.next();\n                    if (obj instanceof GenericObject) {\n                        GenericObject gobj = (GenericObject) obj;\n                        gobj.encode(buffer);\n                    } else {\n                        buffer.append(obj.toString());\n                    }\n                    if (iterator.hasNext())\n                        buffer.append(separator);\n                    else\n                        break;\n                }\n            }\n        }\n        return buffer;\n    }\n\n    public String toString() {\n        return this.encode();\n    }\n\n    /**\n     * Set a namevalue object in this list.\n     */\n\n    public void set(NameValue nv) {\n        this.nameValueMap.put(nv.getName().toLowerCase(), nv);\n    }\n\n    /**\n     * Set a namevalue object in this list.\n     */\n    public void set(String name, Object value) {\n        NameValue nameValue = new NameValue(name, value);\n        nameValueMap.put(name.toLowerCase(), nameValue);\n\n    }\n\n    /**\n     * Compare if two NameValue lists are equal.\n     * \n     * @param otherObject is the object to compare to.\n     * @return true if the two objects compare for equality.\n     */\n    public boolean equals(Object otherObject) {\n        if ( otherObject == null ) {\n            return false;\n        }\n        if (!otherObject.getClass().equals(this.getClass())) {\n            return false;\n        }\n        DuplicateNameValueList other = (DuplicateNameValueList) otherObject;\n\n        if (nameValueMap.size() != other.nameValueMap.size()) {\n            return false;\n        }\n        Iterator<String> li = this.nameValueMap.keySet().iterator();\n\n        while (li.hasNext()) {\n            String key = (String) li.next();\n            Collection nv1 = this.getNameValue(key);\n            Collection nv2 = (Collection) other.nameValueMap.get(key);\n            if (nv2 == null)\n                return false;\n            else if (!nv2.equals(nv1))\n                return false;\n        }\n        return true;\n    }\n\n    /**\n     * Do a lookup on a given name and return value associated with it.\n     */\n    public Object getValue(String name) {\n        Collection nv = this.getNameValue(name.toLowerCase());\n        if (nv != null)\n            return nv;\n        else\n            return null;\n    }\n\n    /**\n     * Get the NameValue record given a name.\n     * \n     */\n    public Collection getNameValue(String name) {\n        return (Collection) this.nameValueMap.get(name.toLowerCase());\n    }\n\n    /**\n     * Returns a boolean telling if this NameValueList has a record with this name\n     */\n    public boolean hasNameValue(String name) {\n        return nameValueMap.containsKey(name.toLowerCase());\n    }\n\n    /**\n     * Remove the element corresponding to this name.\n     */\n    public boolean delete(String name) {\n        String lcName = name.toLowerCase();\n        if (this.nameValueMap.containsKey(lcName)) {\n            this.nameValueMap.remove(lcName);\n            return true;\n        } else {\n            return false;\n        }\n\n    }\n\n    public Object clone() {\n        DuplicateNameValueList retval = new DuplicateNameValueList();\n        retval.setSeparator(this.separator);\n        Iterator<NameValue> it = this.nameValueMap.values().iterator();\n        while (it.hasNext()) {\n            retval.set((NameValue) ((NameValue) it.next()).clone());\n        }\n        return retval;\n    }\n\n    /**\n     * Return an iterator for the name-value pairs of this list.\n     * \n     * @return the iterator.\n     */\n    public Iterator<NameValue> iterator() {\n        return this.nameValueMap.values().iterator();\n    }\n\n    /**\n     * Get a list of parameter names.\n     * \n     * @return a list iterator that has the names of the parameters.\n     */\n    public Iterator<String> getNames() {\n        return this.nameValueMap.keySet().iterator();\n\n    }\n\n    /**\n     * Get the parameter as a String.\n     * \n     * @return the parameter as a string.\n     */\n    public String getParameter(String name) {\n        Object val = this.getValue(name);\n        if (val == null)\n            return null;\n        if (val instanceof GenericObject)\n            return ((GenericObject) val).encode();\n        else\n            return val.toString();\n    }\n\n    public void clear() {\n        nameValueMap.clear();\n\n    }\n\n    public boolean isEmpty() {\n        return this.nameValueMap.isEmpty();\n    }\n\n    public NameValue put(String key, NameValue value) {\n        return (NameValue) this.nameValueMap.put(key, value);\n    }\n\n    public NameValue remove(Object key) {\n        return (NameValue) this.nameValueMap.remove(key);\n    }\n\n    public int size() {\n        return this.nameValueMap.size();\n    }\n\n    public Collection<NameValue> values() {\n        return this.nameValueMap.values();\n    }\n\n    public int hashCode() {\n        return this.nameValueMap.keySet().hashCode();\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/GenericObject.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.core;\nimport java.lang.reflect.*;\nimport java.io.Serializable;\nimport java.util.*;\n\n/**\n* The base class from which all the other classes in the\n* sipheader, sdpfields and sipmessage packages are extended.\n* Provides a few utility funcitons such as indentation and\n* pretty printing that all other classes benifit from.\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\n\npublic abstract class GenericObject implements Serializable, Cloneable {\n    // Useful constants.\n    protected static final String SEMICOLON = Separators.SEMICOLON;\n    protected static final String COLON = Separators.COLON;\n    protected static final String COMMA = Separators.COMMA;\n    protected static final String SLASH = Separators.SLASH;\n    protected static final String SP = Separators.SP;\n    protected static final String EQUALS = Separators.EQUALS;\n    protected static final String STAR = Separators.STAR;\n    protected static final String NEWLINE = Separators.NEWLINE;\n    protected static final String RETURN = Separators.RETURN;\n    protected static final String LESS_THAN = Separators.LESS_THAN;\n    protected static final String GREATER_THAN = Separators.GREATER_THAN;\n    protected static final String AT = Separators.AT;\n    protected static final String DOT = Separators.DOT;\n    protected static final String QUESTION = Separators.QUESTION;\n    protected static final String POUND = Separators.POUND;\n    protected static final String AND = Separators.AND;\n    protected static final String LPAREN = Separators.LPAREN;\n    protected static final String RPAREN = Separators.RPAREN;\n    protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE;\n    protected static final String QUOTE = Separators.QUOTE;\n    protected static final String HT = Separators.HT;\n    protected static final String PERCENT = Separators.PERCENT;\n\n    protected static final Set<Class<?>> immutableClasses = new HashSet<Class<?>> (10);\n    static final String[] immutableClassNames ={\n        \"String\", \"Character\",\n        \"Boolean\", \"Byte\", \"Short\", \"Integer\", \"Long\",\n        \"Float\", \"Double\"\n        };\n\n    protected int indentation;\n    protected String stringRepresentation;\n    protected Match matchExpression; // Pattern matcher.\n\n    static {\n        try {\n            for (int i = 0; i < immutableClassNames.length; i++)\n                immutableClasses.add(Class.forName(\"java.lang.\" + immutableClassNames [i]));\n        } catch (ClassNotFoundException e) {\n            throw new RuntimeException (\"Internal error\", e);\n        }\n    }\n\n    /** Set the  pattern matcher. To match on the\n     * field of a sip message, set the match expression in the match template\n     * and invoke the match function. This useful because\n     * SIP headers and parameters may appear in different orders and are not\n     * necessarily in canonical form. This makes it hard to write a pattern\n     * matcher that relies on regular expressions alone.\n     * Thus we rely on the following  strategy i.e. To do pattern matching on\n     * an incoming message, first parse it, and then construct a match template,\n     * filling in the fields that you want to\n     * match. The rules for matching are: A null object matches wild card -\n     * that is a match template of null matches any parsed SIP object.\n     * To match with any subfield, set the match template on a template object\n     * of the same type and invoke the match interface.\n     * Regular expressions matching implements the gov2.nist.sip.Match interface\n     * that can be done using the Jakarta regexp package for example.\n     * package included herein. This can be used to implement the Match interface\n     * <a href=http://www.apache.org> See the APACHE website for documents </a>\n     *\n     */\n    public void setMatcher(Match matchExpression) {\n        if (matchExpression == null)\n            throw new IllegalArgumentException(\"null arg!\");\n        this.matchExpression = matchExpression;\n    }\n\n    /** Return the match expression.\n     *@return the match expression that has previously been set.\n     */\n    public Match getMatcher() {\n        return matchExpression;\n    }\n\n    public static Class<?> getClassFromName(String className) {\n        try {\n            return Class.forName(className);\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n            return null;\n        }\n    }\n\n    public static boolean isMySubclass(Class<?> other) {\n\n            return GenericObject.class.isAssignableFrom(other);\n\n    }\n\n    /** Clones the given object.\n     *  If the object is a wrapped type, an array, a GenericObject\n     *  or a GenericObjectList, it is cast to the appropriate type\n     *  and the clone() method is invoked. Else if the object implements\n     *  Cloneable, reflection is used to discover and invoke\n     *  clone() method. Otherwise, the original object is returned.\n     */\n    public static Object makeClone(Object obj) {\n        if (obj == null)\n            throw new NullPointerException(\"null obj!\");\n        Class<?> c = obj.getClass();\n        Object clone_obj = obj;\n        if (immutableClasses.contains (c))\n            return obj;\n        else if (c.isArray ()) {\n            Class<?> ec = c.getComponentType();\n            if (! ec.isPrimitive())\n                clone_obj = ((Object []) obj).clone();\n            else {\n                if (ec == Character.TYPE)\n                    clone_obj = ((char []) obj).clone();\n                else if (ec == Boolean.TYPE)\n                    clone_obj = ((boolean []) obj).clone();\n                if (ec == Byte.TYPE)\n                    clone_obj = ((byte []) obj).clone();\n                else if (ec == Short.TYPE)\n                    clone_obj = ((short []) obj).clone();\n                else if (ec == Integer.TYPE)\n                    clone_obj = ((int []) obj).clone();\n                else if (ec == Long.TYPE)\n                    clone_obj = ((long []) obj).clone();\n                else if (ec == Float.TYPE)\n                    clone_obj = ((float []) obj).clone();\n                else if (ec == Double.TYPE)\n                    clone_obj = ((double []) obj).clone();\n            }\n        } else if (GenericObject.class.isAssignableFrom (c))\n            clone_obj = ((GenericObject) obj).clone();\n        else if (GenericObjectList.class.isAssignableFrom (c))\n            clone_obj = ((GenericObjectList) obj).clone();\n        else if (Cloneable.class.isAssignableFrom (c)) {\n            // If a clone method exists for the object, then\n            // invoke it\n            try {\n                Method meth = c.getMethod(\"clone\", (Class[]) null);\n                clone_obj = meth.invoke(obj,(Object[]) null);\n            } catch (SecurityException ex) {\n            } catch (IllegalArgumentException ex) {\n                InternalErrorHandler.handleException(ex);\n            } catch (IllegalAccessException ex) {\n            } catch (InvocationTargetException ex) {\n            } catch (NoSuchMethodException ex) {\n            }\n        }\n        return clone_obj;\n    }\n\n    /** Clones this object.\n     */\n    public Object clone() {\n        try {\n            return super.clone();\n        } catch (CloneNotSupportedException e) {\n            throw new RuntimeException(\"Internal error\");\n        }\n    }\n    /**\n     * Recursively override the fields of this object with the fields\n     * of a new object. This is useful when you want to genrate a template\n     * and override the fields of an incoming SIPMessage with another\n     * SIP message that you have already generated.\n     *\n     * @param mergeObject is the replacement object.  The override\n     * obect must be of the same class as this object.\n     * Set any fields that you do not want to override as null in the\n     * mergeOject object.\n     */\n    public void merge(Object mergeObject) {\n        // Base case.\n        if (mergeObject == null)\n            return;\n\n        if (!mergeObject.getClass().equals(this.getClass()))\n            throw new IllegalArgumentException(\"Bad override object\");\n                        \n        Class<?> myclass = this.getClass();\n        while (true) {\n            Field[] fields = myclass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                int modifier = f.getModifiers();\n                if (Modifier.isPrivate(modifier)) {\n                    continue;\n                } else if (Modifier.isStatic(modifier)) {\n                    continue;\n                } else if (Modifier.isInterface(modifier)) {\n                    continue;\n                }\n                Class<?> fieldType = f.getType();\n                String fname = fieldType.toString();\n                try {\n                    // Primitive fields are printed with type: value\n                    if (fieldType.isPrimitive()) {\n                        if (fname.compareTo(\"int\") == 0) {\n                            int intfield = f.getInt(mergeObject);\n                            f.setInt(this, intfield);\n                        } else if (fname.compareTo(\"short\") == 0) {\n                            short shortField = f.getShort(mergeObject);\n                            f.setShort(this, shortField);\n                        } else if (fname.compareTo(\"char\") == 0) {\n                            char charField = f.getChar(mergeObject);\n                            f.setChar(this, charField);\n                        } else if (fname.compareTo(\"long\") == 0) {\n                            long longField = f.getLong(mergeObject);\n                            f.setLong(this, longField);\n                        } else if (fname.compareTo(\"boolean\") == 0) {\n                            boolean booleanField = f.getBoolean(mergeObject);\n                            f.setBoolean(this, booleanField);\n                        } else if (fname.compareTo(\"double\") == 0) {\n                            double doubleField = f.getDouble(mergeObject);\n                            f.setDouble(this, doubleField);\n                        } else if (fname.compareTo(\"float\") == 0) {\n                            float floatField = f.getFloat(mergeObject);\n                            f.setFloat(this, floatField);\n                        }\n                    } else {\n                        Object obj = f.get(this);\n                        Object mobj = f.get(mergeObject);\n                        if (mobj == null)\n                            continue;\n                        if (obj == null) {\n                            f.set(this, mobj);\n                            continue;\n                        }\n                        if (obj instanceof GenericObject) {\n                            GenericObject gobj = (GenericObject) obj;\n                            gobj.merge(mobj);\n                        } else {\n                            f.set(this, mobj);\n                        }\n                    }\n                } catch (IllegalAccessException ex1) {\n                    ex1.printStackTrace();\n                    continue; // we are accessing a private field...\n                }\n            }\n            myclass = myclass.getSuperclass();\n            if (myclass.equals(GenericObject.class))\n                break;\n        }\n    }\n\n    protected GenericObject() {\n        indentation = 0;\n        stringRepresentation = \"\";\n    }\n\n    protected String getIndentation() {\n    char [] chars = new char [indentation];\n    java.util.Arrays.fill (chars, ' ');\n    return new String (chars);\n    }\n\n    /**\n     * Add a new string to the accumulated string representation.\n     */\n\n    protected void sprint(String a) {\n        if (a == null) {\n            stringRepresentation += getIndentation();\n            stringRepresentation += \"<null>\\n\";\n            return;\n        }\n        if (a.compareTo(\"}\") == 0 || a.compareTo(\"]\") == 0) {\n            indentation--;\n        }\n        stringRepresentation += getIndentation();\n        stringRepresentation += a;\n        stringRepresentation += \"\\n\";\n        if (a.compareTo(\"{\") == 0 || a.compareTo(\"[\") == 0) {\n            indentation++;\n        }\n\n    }\n\n    /**\n     * Pretty printing function accumulator for objects.\n     */\n\n    protected void sprint(Object o) {\n        sprint(o.toString());\n    }\n\n    /**\n     * Pretty printing accumulator function for ints\n     */\n\n    protected void sprint(int intField) {\n        sprint(String.valueOf(intField));\n    }\n\n    /**\n     * Pretty printing accumulator function for shorts\n     */\n    protected void sprint(short shortField) {\n        sprint(String.valueOf(shortField));\n    }\n\n    /**\n     * Pretty printing accumulator function for chars\n     */\n\n    protected void sprint(char charField) {\n        sprint(String.valueOf(charField));\n\n    }\n\n    /**\n     * Pretty printing accumulator function for longs\n     */\n\n    protected void sprint(long longField) {\n        sprint(String.valueOf(longField));\n    }\n\n    /**\n     * Pretty printing accumulator function for booleans\n     */\n\n    protected void sprint(boolean booleanField) {\n        sprint(String.valueOf(booleanField));\n    }\n\n    /**\n     * Pretty printing accumulator function for doubles\n     */\n\n    protected void sprint(double doubleField) {\n        sprint(String.valueOf(doubleField));\n    }\n\n    /**\n     * Pretty printing accumulator function for floats\n     */\n\n    protected void sprint(float floatField) {\n        sprint(String.valueOf(floatField));\n    }\n\n    /**\n     * Debug printing function.\n     */\n\n    protected void dbgPrint() {\n        Debug.println(debugDump());\n    }\n\n    /**\n     * Debug printing function.\n     */\n    protected void dbgPrint(String s) {\n        Debug.println(s);\n    }\n\n    /**\n     * An introspection based equality predicate for GenericObjects.\n     *@param that is the other object to test against.\n     *@return true if the objects are euqal and false otherwise\n     */\n    public boolean equals(Object that) {\n        if ( that == null ) return false;\n        if (!this.getClass().equals(that.getClass()))\n            return false;\n        Class<?> myclass = this.getClass();\n        Class<?> hisclass = that.getClass();\n        while (true) {\n            Field[] fields = myclass.getDeclaredFields();\n            Field[] hisfields = hisclass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                Field g = hisfields[i];\n                // Only print protected and public members.\n                int modifier = f.getModifiers();\n                if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                    continue;\n                Class<?> fieldType = f.getType();\n                String fieldName = f.getName();\n                if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                    continue;\n                }\n                if (fieldName.compareTo(\"indentation\") == 0) {\n                    continue;\n                }\n                try {\n                    // Primitive fields are printed with type: value\n                    if (fieldType.isPrimitive()) {\n                        String fname = fieldType.toString();\n                        if (fname.compareTo(\"int\") == 0) {\n                            if (f.getInt(this) != g.getInt(that))\n                                return false;\n                        } else if (fname.compareTo(\"short\") == 0) {\n                            if (f.getShort(this) != g.getShort(that))\n                                return false;\n                        } else if (fname.compareTo(\"char\") == 0) {\n                            if (f.getChar(this) != g.getChar(that))\n                                return false;\n                        } else if (fname.compareTo(\"long\") == 0) {\n                            if (f.getLong(this) != g.getLong(that))\n                                return false;\n                        } else if (fname.compareTo(\"boolean\") == 0) {\n                            if (f.getBoolean(this) != g.getBoolean(that))\n                                return false;\n                        } else if (fname.compareTo(\"double\") == 0) {\n                            if (f.getDouble(this) != g.getDouble(that))\n                                return false;\n                        } else if (fname.compareTo(\"float\") == 0) {\n                            if (f.getFloat(this) != g.getFloat(that))\n                                return false;\n                        }\n                    } else if (g.get(that) == f.get(this))\n                        return true;\n                    else if (f.get(this) == null)\n                        return false;\n                    else if (g.get(that) == null)\n                        return false;\n                    else if (g.get(that) == null && f.get(this) != null)\n                        return false;\n                    else if (!f.get(this).equals(g.get(that)))\n                        return false;\n                } catch (IllegalAccessException ex1) {\n                    InternalErrorHandler.handleException(ex1);\n                }\n            }\n            if (myclass.equals(GenericObject.class))\n                break;\n            else {\n                myclass = myclass.getSuperclass();\n                hisclass = hisclass.getSuperclass();\n            }\n\n        }\n        return true;\n    }\n\n    /** An introspection based predicate matching using a template\n     * object. Allows for partial match of two protocl Objects.\n     *@param other the match pattern to test against. The match object\n     * has to be of the same type (class). Primitive types\n     * and non-sip fields that are non null are matched for equality.\n     * Null in any field  matches anything. Some book-keeping fields\n     * are ignored when making the comparison.\n     */\n\n    public boolean match(Object other) {\n        if (other == null)\n            return true;\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        GenericObject that = (GenericObject) other;\n        Class<?> myclass = this.getClass();\n        Field[] fields = myclass.getDeclaredFields();\n        Class<?> hisclass = other.getClass();\n        Field[] hisfields = hisclass.getDeclaredFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field f = fields[i];\n            Field g = hisfields[i];\n            // Only print protected and public members.\n            int modifier = f.getModifiers();\n            if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                continue;\n            Class<?> fieldType = f.getType();\n            String fieldName = f.getName();\n            if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                continue;\n            }\n            if (fieldName.compareTo(\"indentation\") == 0) {\n                continue;\n            }\n            try {\n                // Primitive fields are printed with type: value\n                if (fieldType.isPrimitive()) {\n                    String fname = fieldType.toString();\n                    if (fname.compareTo(\"int\") == 0) {\n                        if (f.getInt(this) != g.getInt(that))\n                            return false;\n                    } else if (fname.compareTo(\"short\") == 0) {\n                        if (f.getShort(this) != g.getShort(that))\n                            return false;\n                    } else if (fname.compareTo(\"char\") == 0) {\n                        if (f.getChar(this) != g.getChar(that))\n                            return false;\n                    } else if (fname.compareTo(\"long\") == 0) {\n                        if (f.getLong(this) != g.getLong(that))\n                            return false;\n                    } else if (fname.compareTo(\"boolean\") == 0) {\n                        if (f.getBoolean(this) != g.getBoolean(that))\n                            return false;\n                    } else if (fname.compareTo(\"double\") == 0) {\n                        if (f.getDouble(this) != g.getDouble(that))\n                            return false;\n                    } else if (fname.compareTo(\"float\") == 0) {\n                        if (f.getFloat(this) != g.getFloat(that))\n                            return false;\n                    }\n                } else {\n                    Object myObj = f.get(this);\n                    Object hisObj = g.get(that);\n                    if (hisObj != null && myObj == null)\n                        return false;\n                    else if (hisObj == null && myObj != null)\n                        continue;\n                    else if (hisObj == null && myObj == null)\n                        continue;\n                    else if (\n                        hisObj instanceof java.lang.String\n                            && myObj instanceof java.lang.String) {\n                        if ((((String) hisObj).trim()).equals(\"\"))\n                            continue;\n                        if (((String) myObj)\n                            .compareToIgnoreCase((String) hisObj)\n                            != 0)\n                            return false;\n                    } else if (\n                        GenericObject.isMySubclass(myObj.getClass())\n                            && !((GenericObject) myObj).match(hisObj))\n                        return false;\n                    else if (\n                        GenericObjectList.isMySubclass(myObj.getClass())\n                            && !((GenericObjectList) myObj).match(hisObj))\n                        return false;\n\n                }\n            } catch (IllegalAccessException ex1) {\n                InternalErrorHandler.handleException(ex1);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Generic print formatting function:\n     * Does depth-first descent of the structure and\n     * recursively prints all non-private objects pointed to\n     * by this object.\n     * <bf>\n     * Warning - the following generic string routine will\n     * bomb (go into infinite loop) if there are any circularly linked\n     * structures so if you have these, they had better be private!\n     * </bf>\n     * We dont have to worry about such things for our structures\n     *(we never use circular linked structures).\n     */\n\n    public String debugDump() {\n        stringRepresentation = \"\";\n        Class<?> myclass = getClass();\n        sprint(myclass.getName());\n        sprint(\"{\");\n        Field[] fields = myclass.getDeclaredFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field f = fields[i];\n            // Only print protected and public members.\n            int modifier = f.getModifiers();\n            if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                continue;\n            Class<?> fieldType = f.getType();\n            String fieldName = f.getName();\n            if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                // avoid nasty recursions...\n                continue;\n            }\n            if (fieldName.compareTo(\"indentation\") == 0) {\n                // formatting stuff - not relevant here.\n                continue;\n            }\n            sprint(fieldName + \":\");\n            try {\n                // Primitive fields are printed with type: value\n                if (fieldType.isPrimitive()) {\n                    String fname = fieldType.toString();\n                    sprint(fname + \":\");\n                    if (fname.compareTo(\"int\") == 0) {\n                        int intfield = f.getInt(this);\n                        sprint(intfield);\n                    } else if (fname.compareTo(\"short\") == 0) {\n                        short shortField = f.getShort(this);\n                        sprint(shortField);\n                    } else if (fname.compareTo(\"char\") == 0) {\n                        char charField = f.getChar(this);\n                        sprint(charField);\n                    } else if (fname.compareTo(\"long\") == 0) {\n                        long longField = f.getLong(this);\n                        sprint(longField);\n                    } else if (fname.compareTo(\"boolean\") == 0) {\n                        boolean booleanField = f.getBoolean(this);\n                        sprint(booleanField);\n                    } else if (fname.compareTo(\"double\") == 0) {\n                        double doubleField = f.getDouble(this);\n                        sprint(doubleField);\n                    } else if (fname.compareTo(\"float\") == 0) {\n                        float floatField = f.getFloat(this);\n                        sprint(floatField);\n                    }\n                } else if (GenericObject.class.isAssignableFrom(fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObject) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else if (\n                    GenericObjectList.class.isAssignableFrom(fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObjectList) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else {\n                    // Dont do recursion on things that are not\n                    // of our header type...\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).getClass().getName() + \":\");\n                    } else {\n                        sprint(fieldType.getName() + \":\");\n                    }\n\n                    sprint(\"{\");\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).toString());\n                    } else {\n                        sprint(\"<null>\");\n                    }\n                    sprint(\"}\");\n                }\n            } catch (IllegalAccessException ex1) {\n                continue; // we are accessing a private field...\n            } catch (Exception ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n        }\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n    /**\n     * Formatter with a given starting indentation.\n     */\n    public String debugDump(int indent) {\n        indentation = indent;\n        String retval = this.debugDump();\n        indentation = 0;\n        return retval;\n    }\n\n\n    /**\n     *  Get the string encoded version of this object\n     * @since v1.0\n     */\n    public abstract String encode();\n\n    /**\n     * Put the encoded version of this object in the given StringBuffer.\n     */\n    public StringBuffer encode(StringBuffer buffer) {\n        return buffer.append(encode());\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/GenericObjectList.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.core;\n\nimport java.util.*;\nimport java.io.Serializable;\n\n/**\n * Implements a homogenous consistent linked list. All the objects in the linked\n * list must derive from the same root class. This is a useful constraint to\n * place on our code as this property is invariant.The list is created with the\n * superclass which can be specified as either a class name or a Class.\n *\n * @version 1.2\n *\n * @author M. Ranganathan <br/>\n *\n *\n *\n */\npublic abstract class GenericObjectList extends LinkedList<GenericObject> implements\n        Serializable, Cloneable{\n    // Useful constants.\n    protected static final String SEMICOLON = Separators.SEMICOLON;\n\n    protected static final String COLON = Separators.COLON;\n\n    protected static final String COMMA = Separators.COMMA;\n\n    protected static final String SLASH = Separators.SLASH;\n\n    protected static final String SP = Separators.SP;\n\n    protected static final String EQUALS = Separators.EQUALS;\n\n    protected static final String STAR = Separators.STAR;\n\n    protected static final String NEWLINE = Separators.NEWLINE;\n\n    protected static final String RETURN = Separators.RETURN;\n\n    protected static final String LESS_THAN = Separators.LESS_THAN;\n\n    protected static final String GREATER_THAN = Separators.GREATER_THAN;\n\n    protected static final String AT = Separators.AT;\n\n    protected static final String DOT = Separators.DOT;\n\n    protected static final String QUESTION = Separators.QUESTION;\n\n    protected static final String POUND = Separators.POUND;\n\n    protected static final String AND = Separators.AND;\n\n    protected static final String LPAREN = Separators.LPAREN;\n\n    protected static final String RPAREN = Separators.RPAREN;\n\n    protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE;\n\n    protected static final String QUOTE = Separators.QUOTE;\n\n    protected static final String HT = Separators.HT;\n\n    protected static final String PERCENT = Separators.PERCENT;\n\n    protected int indentation;\n\n    protected String listName; // For debugging\n\n    private ListIterator<? extends GenericObject> myListIterator;\n\n    private String stringRep;\n\n    protected Class<?> myClass;\n\n    protected String separator;\n\n    protected String getIndentation() {\n        char[] chars = new char[indentation];\n        java.util.Arrays.fill(chars, ' ');\n        return new String(chars);\n    }\n\n    /**\n     * Return true if this supports reflection based cloning.\n     */\n    protected static boolean isCloneable(Object obj) {\n        return obj instanceof Cloneable;\n    }\n\n    public static boolean isMySubclass(Class<?> other) {\n        return GenericObjectList.class.isAssignableFrom(other);\n\n    }\n\n    /**\n     * Makes a deep clone of this list.\n     */\n    public Object clone() {\n        GenericObjectList retval = (GenericObjectList) super.clone();\n        for (ListIterator<GenericObject> iter = retval.listIterator(); iter.hasNext();) {\n            GenericObject obj = (GenericObject) ((GenericObject) iter.next())\n                    .clone();\n            iter.set(obj);\n        }\n        return retval;\n    }\n\n\n\n    public void setMyClass(Class cl) {\n        myClass = cl;\n    }\n\n    protected GenericObjectList() {\n        super();\n        listName = null;\n        stringRep = \"\";\n        separator = \";\";\n    }\n\n    protected GenericObjectList(String lname) {\n        this();\n        listName = lname;\n    }\n\n    /**\n     * A Constructor which takes a list name and a class name (for assertion\n     * checking).\n     */\n\n    protected GenericObjectList(String lname, String classname) {\n        this(lname);\n        try {\n            myClass = Class.forName(classname);\n        } catch (ClassNotFoundException ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n\n    }\n\n    /**\n     * A Constructor which takes a list name and a class (for assertion\n     * checking).\n     */\n\n    protected GenericObjectList(String lname, Class objclass) {\n        this(lname);\n        myClass = objclass;\n    }\n\n    /**\n     * Traverse the list given a list iterator\n     */\n    protected GenericObject next(ListIterator iterator) {\n        try {\n            return (GenericObject) iterator.next();\n        } catch (NoSuchElementException ex) {\n            return null;\n        }\n    }\n\n    /**\n     * This is the default list iterator.This will not handle nested list\n     * traversal.\n     */\n    protected GenericObject first() {\n        myListIterator = this.listIterator(0);\n        try {\n            return (GenericObject) myListIterator.next();\n        } catch (NoSuchElementException ex) {\n            return null;\n        }\n    }\n\n    /**\n     * Fetch the next object from the list based on the default list iterator\n     */\n    protected GenericObject next() {\n        if (myListIterator == null) {\n            myListIterator = this.listIterator(0);\n        }\n        try {\n            return (GenericObject) myListIterator.next();\n        } catch (NoSuchElementException ex) {\n            myListIterator = null;\n            return null;\n        }\n    }\n\n    /**\n     * Concatenate two compatible header lists, adding the argument to the tail\n     * end of this list.\n     *\n     * @param <var>\n     *            topFlag </var> set to true to add items to top of list\n     */\n    protected void concatenate(GenericObjectList objList) {\n        concatenate(objList, false);\n    }\n\n    /**\n     * Concatenate two compatible header lists, adding the argument either to\n     * the beginning or the tail end of this list. A type check is done before\n     * concatenation.\n     *\n     * @param <var>\n     *            topFlag </var> set to true to add items to top of list else\n     *            add them to the tail end of the list.\n     */\n    protected void concatenate(GenericObjectList objList, boolean topFlag) {\n        if (!topFlag) {\n            this.addAll(objList);\n        } else {\n            // add given items to the top end of the list.\n            this.addAll(0, objList);\n        }\n    }\n\n    /**\n     * string formatting function.\n     */\n\n    private void sprint(String s) {\n        if (s == null) {\n            stringRep += getIndentation();\n            stringRep += \"<null>\\n\";\n            return;\n        }\n\n        if (s.compareTo(\"}\") == 0 || s.compareTo(\"]\") == 0) {\n            indentation--;\n        }\n        stringRep += getIndentation();\n        stringRep += s;\n        stringRep += \"\\n\";\n        if (s.compareTo(\"{\") == 0 || s.compareTo(\"[\") == 0) {\n            indentation++;\n        }\n    }\n\n    /**\n     * Convert this list of headers to a formatted string.\n     */\n\n    public String debugDump() {\n        stringRep = \"\";\n        Object obj = this.first();\n        if (obj == null)\n            return \"<null>\";\n        sprint(\"listName:\");\n        sprint(listName);\n        sprint(\"{\");\n        while (obj != null) {\n            sprint(\"[\");\n            sprint(((GenericObject) obj).debugDump(this.indentation));\n            obj = next();\n            sprint(\"]\");\n        }\n        sprint(\"}\");\n        return stringRep;\n    }\n\n    /**\n     * Convert this list of headers to a string (for printing) with an\n     * indentation given.\n     */\n\n    public String debugDump(int indent) {\n        int save = indentation;\n        indentation = indent;\n        String retval = this.debugDump();\n        indentation = save;\n        return retval;\n    }\n\n    public void addFirst(GenericObject objToAdd) {\n        if (myClass == null) {\n            myClass = objToAdd.getClass();\n        } else {\n            super.addFirst(objToAdd);\n        }\n    }\n\n    /**\n     * Do a merge of the GenericObjects contained in this list with the\n     * GenericObjects in the mergeList. Note that this does an inplace\n     * modification of the given list. This does an object by object merge of\n     * the given objects.\n     *\n     * @param mergeList\n     *            is the list of Generic objects that we want to do an object by\n     *            object merge with. Note that no new objects are added to this\n     *            list.\n     *\n     */\n\n    public void mergeObjects(GenericObjectList mergeList) {\n\n        if (mergeList == null)\n            return;\n        Iterator it1 = this.listIterator();\n        Iterator it2 = mergeList.listIterator();\n        while (it1.hasNext()) {\n            GenericObject outerObj = (GenericObject) it1.next();\n            while (it2.hasNext()) {\n                Object innerObj = it2.next();\n                outerObj.merge(innerObj);\n            }\n        }\n    }\n\n    /**\n     * Encode the list in semicolon separated form.\n     *\n     * @return an encoded string containing the objects in this list.\n     * @since v1.0\n     */\n    public String encode() {\n        if (this.isEmpty())\n            return \"\";\n        StringBuffer encoding = new StringBuffer();\n        ListIterator iterator = this.listIterator();\n        if (iterator.hasNext()) {\n            while (true) {\n                Object obj = iterator.next();\n                if (obj instanceof GenericObject) {\n                    GenericObject gobj = (GenericObject) obj;\n                    encoding.append(gobj.encode());\n                } else {\n                    encoding.append(obj.toString());\n                }\n                if (iterator.hasNext())\n                    encoding.append(separator);\n                else\n                    break;\n            }\n        }\n        return encoding.toString();\n    }\n\n    /**\n     * Alias for the encode function above.\n     */\n    public String toString() {\n        return this.encode();\n    }\n\n    /**\n     * Set the separator (for encoding the list)\n     *\n     * @since v1.0\n     * @param sep\n     *            is the new seperator (default is semicolon)\n     */\n    public void setSeparator(String sep) {\n        separator = sep;\n    }\n    \n    /**\n     * Hash code. We never expect to put this in a hash table so return a constant.\n     */\n    public int hashCode() { return 42; }\n\n    /**\n     * Equality checking predicate.\n     *\n     * @param other\n     *            is the object to compare ourselves to.\n     * @return true if the objects are equal.\n     */\n    public boolean equals(Object other) {\n        if (other == null ) return false;\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        GenericObjectList that = (GenericObjectList) other;\n        if (this.size() != that.size())\n            return false;\n        ListIterator myIterator = this.listIterator();\n        while (myIterator.hasNext()) {\n            Object myobj = myIterator.next();\n            ListIterator hisIterator = that.listIterator();\n            try {\n                while (true) {\n                    Object hisobj = hisIterator.next();\n                    if (myobj.equals(hisobj))\n                        break;\n                }\n            } catch (NoSuchElementException ex) {\n                return false;\n            }\n        }\n        ListIterator hisIterator = that.listIterator();\n        while (hisIterator.hasNext()) {\n            Object hisobj = hisIterator.next();\n            myIterator = this.listIterator();\n            try {\n                while (true) {\n                    Object myobj = myIterator.next();\n                    if (hisobj.equals(myobj))\n                        break;\n                }\n            } catch (NoSuchElementException ex) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Match with a template (return true if we have a superset of the given\n     * template. This can be used for partial match (template matching of SIP\n     * objects). Note -- this implementation is not unnecessarily efficient :-)\n     *\n     * @param other\n     *            template object to compare against.\n     */\n\n    public boolean match(Object other) {\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        GenericObjectList that = (GenericObjectList) other;\n        ListIterator hisIterator = that.listIterator();\n        outer: while (hisIterator.hasNext()) {\n            Object hisobj = hisIterator.next();\n            Object myobj = null;\n            ListIterator myIterator = this.listIterator();\n            while (myIterator.hasNext()) {\n                myobj = myIterator.next();\n                if (myobj instanceof GenericObject)\n                    System.out.println(\"Trying to match  = \"\n                            + ((GenericObject) myobj).encode());\n                if (GenericObject.isMySubclass(myobj.getClass())\n                        && ((GenericObject) myobj).match(hisobj))\n                    break outer;\n                else if (GenericObjectList.isMySubclass(myobj.getClass())\n                        && ((GenericObjectList) myobj).match(hisobj))\n                    break outer;\n            }\n            System.out.println(((GenericObject) hisobj).encode());\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/Host.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/***************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division(ANTD).   *\n **************************************************************************/\npackage gov2.nist.core;\n\nimport java.net.*;\n\n/*\n * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>\n * Network Research Team (http://www-r2.u-strasbg.fr))<br/>\n * Louis Pasteur University - Strasbourg - France<br/>\n *\n * Frank Feif reported a bug.\n *\n *\n */\n/**\n * Stores hostname.\n * @version 1.2\n *\n * @author M. Ranganathan\n * @author Emil Ivov <emil_ivov@yahoo.com> IPV6 Support. <br/>\n *\n *\n *\n\n * Marc Bednarek <bednarek@nist.gov> (Bugfixes).<br/>\n *\n */\npublic class Host extends GenericObject {\n\n    /**\n     * Determines whether or not we should tolerate and strip address scope\n     * zones from IPv6 addresses. Address scope zones are sometimes returned\n     * at the end of IPv6 addresses generated by InetAddress.getHostAddress().\n     * They are however not part of the SIP semantics so basically this method\n     * determines whether or not the parser should be stripping them (as\n     * opposed simply being blunt and throwing an exception).\n     */\n    private boolean stripAddressScopeZones = false;\n\n    private static final long serialVersionUID = -7233564517978323344L;\n    protected static final int HOSTNAME = 1;\n    protected static final int IPV4ADDRESS = 2;\n    protected static final int IPV6ADDRESS = 3;\n\n    /** hostName field\n     */\n    protected String hostname;\n\n    /** address field\n     */\n\n    protected int addressType;\n\n    private InetAddress inetAddress;\n\n    /** default constructor\n     */\n    public Host() {\n        addressType = HOSTNAME;\n\n        stripAddressScopeZones\n            = Boolean.getBoolean(\"gov2.nist.core.STRIP_ADDR_SCOPES\");\n    }\n\n    /** Constructor given host name or IP address.\n     */\n    public Host(String hostName) throws IllegalArgumentException {\n        if (hostName == null)\n            throw new IllegalArgumentException(\"null host name\");\n\n        stripAddressScopeZones\n            = Boolean.getBoolean(\"gov2.nist.core.STRIP_ADDR_SCOPES\");\n\n        setHost(hostName, IPV4ADDRESS);\n    }\n\n    /** constructor\n     * @param name String to set\n     * @param addrType int to set\n     */\n    public Host(String name, int addrType) {\n        stripAddressScopeZones\n            = Boolean.getBoolean(\"gov2.nist.core.STRIP_ADDR_SCOPES\");\n\n        setHost(name, addrType);\n    }\n\n    /**\n     * Return the host name in encoded form.\n     * @return String\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (addressType == IPV6ADDRESS && !isIPv6Reference(hostname)) {\n            buffer.append('[').append(hostname).append(']');\n        } else {\n            buffer.append(hostname);\n        }\n        return buffer;\n    }\n\n    /**\n     * Compare for equality of hosts.\n     * Host names are compared by textual equality. No dns lookup\n     * is performed.\n     * @param obj Object to set\n     * @return boolean\n     */\n    public boolean equals(Object obj) {\n        if ( obj == null ) return false;\n        if (!this.getClass().equals(obj.getClass())) {\n            return false;\n        }\n        Host otherHost = (Host) obj;\n        return otherHost.hostname.equals(hostname);\n\n    }\n\n    /** get the HostName field\n     * @return String\n     */\n    public String getHostname() {\n        return hostname;\n    }\n\n    /** get the Address field\n     * @return String\n     */\n    public String getAddress() {\n        return hostname;\n    }\n\n    /**\n     * Convenience function to get the raw IP destination address\n     * of a SIP message as a String.\n     * @return String\n     */\n    public String getIpAddress() {\n        String rawIpAddress = null;\n        if (hostname == null)\n            return null;\n        if (addressType == HOSTNAME) {\n            try {\n                if (inetAddress == null)\n                    inetAddress = InetAddress.getByName(hostname);\n                rawIpAddress = inetAddress.getHostAddress();\n            } catch (UnknownHostException ex) {\n                dbgPrint(\"Could not resolve hostname \" + ex);\n            }\n        } else {\n            rawIpAddress = hostname;\n        }\n        return rawIpAddress;\n    }\n\n    /**\n     * Set the hostname member.\n     * @param h String to set\n     */\n    public void setHostname(String h) {\n        setHost(h, HOSTNAME);\n    }\n\n    /** Set the IP Address.\n     *@param address is the address string to set.\n     */\n    public void setHostAddress(String address) {\n        setHost(address, IPV4ADDRESS);\n    }\n\n    /**\n     * Sets the host address or name of this object.\n     *\n     * @param host that host address/name value\n     * @param type determines whether host is an address or a host name\n     */\n    private void setHost(String host, int type){\n        //set inetAddress to null so that it would be reinited\n        //upon next call to getInetAddress()\n        inetAddress = null;\n\n        if (isIPv6Address(host))\n            addressType = IPV6ADDRESS;\n        else\n            addressType = type;\n\n        // Null check bug fix sent in by jpaulo@ipb.pt\n        if (host != null){\n            hostname = host.trim();\n\n            //if this is an FQDN, make it lowercase to simplify processing\n            if(addressType == HOSTNAME)\n                hostname = hostname.toLowerCase();\n\n            //remove address scope zones if this is an IPv6 address as they\n            //are not allowed by the RFC\n            int zoneStart = -1;\n            if(addressType == IPV6ADDRESS\n                && stripAddressScopeZones\n                && (zoneStart = hostname.indexOf('%'))!= -1){\n\n                hostname = hostname.substring(0, zoneStart);\n            }\n        }\n    }\n\n    /**\n     * Set the address member\n     * @param address address String to set\n     */\n    public void setAddress(String address) {\n        this.setHostAddress(address);\n    }\n\n    /** Return true if the address is a DNS host name\n     *  (and not an IPV4 address)\n     *@return true if the hostname is a DNS name\n     */\n    public boolean isHostname() {\n        return addressType == HOSTNAME;\n    }\n\n    /** Return true if the address is a DNS host name\n     *  (and not an IPV4 address)\n     *@return true if the hostname is host address.\n     */\n    public boolean isIPAddress() {\n        return addressType != HOSTNAME;\n    }\n\n    /** Get the inet address from this host.\n     * Caches the inet address returned from dns lookup to avoid\n     * lookup delays.\n     *\n     *@throws UnkownHostexception when the host name cannot be resolved.\n     */\n    public InetAddress getInetAddress() throws java.net.UnknownHostException {\n        if (hostname == null)\n            return null;\n        if (inetAddress != null)\n            return inetAddress;\n        inetAddress = InetAddress.getByName(hostname);\n        return inetAddress;\n\n    }\n\n    //----- IPv6\n    /**\n     * Verifies whether the <code>address</code> could\n     * be an IPv6 address\n     */\n    private boolean isIPv6Address(String address) {\n        return (address != null && address.indexOf(':') != -1);\n    }\n\n    /**\n     * Verifies whether the ipv6reference, i.e. whether it enclosed in\n     * square brackets\n     */\n    public static boolean isIPv6Reference(String address) {\n        return address.charAt(0) == '['\n            && address.charAt(address.length() - 1) == ']';\n    }\n    \n    @Override\n    public int hashCode() {\n        return this.getHostname().hashCode();\n        \n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/HostNameParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*\n *\n * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>\n * Network Research Team (http://www-r2.u-strasbg.fr))<br/>\n * Louis Pasteur University - Strasbourg - France<br/>\n *\n *Bug fixes for corner cases were contributed by Thomas Froment.\n */\npackage gov2.nist.core;\n\n// BEGIN android-deleted\n//import gov2.nist.javax2.sdp.parser.Lexer;\n// END android-deleted\n\nimport java.text.ParseException;\n\n/**\n * Parser for host names.\n *\n *@version 1.2\n *\n *@author M. Ranganathan\n */\n\npublic class HostNameParser extends ParserCore {\n// BEGIN android-added\n    private static LexerCore Lexer;\n// END android-added\n\n    /**\n     * Determines whether or not we should tolerate and strip address scope\n     * zones from IPv6 addresses. Address scope zones are sometimes returned\n     * at the end of IPv6 addresses generated by InetAddress.getHostAddress().\n     * They are however not part of the SIP semantics so basically this method\n     * determines whether or not the parser should be stripping them (as\n     * opposed simply being blunt and throwing an exception).\n     */\n    private boolean stripAddressScopeZones = false;\n\n    public HostNameParser(String hname) {\n        this.lexer = new LexerCore(\"charLexer\", hname);\n\n        stripAddressScopeZones\n            = Boolean.getBoolean(\"gov2.nist.core.STRIP_ADDR_SCOPES\");\n    }\n\n    /**\n     * The lexer is initialized with the buffer.\n     */\n    public HostNameParser(LexerCore lexer) {\n        this.lexer = lexer;\n        lexer.selectLexer(\"charLexer\");\n\n        stripAddressScopeZones\n            = Boolean.getBoolean(\"gov2.nist.core.STRIP_ADDR_SCOPES\");\n    }\n\n    private static final char[] VALID_DOMAIN_LABEL_CHAR =\n        new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, '-', '.'};\n    protected void consumeDomainLabel() throws ParseException {\n        if (debug)\n            dbg_enter(\"domainLabel\");\n        try {\n            lexer.consumeValidChars(VALID_DOMAIN_LABEL_CHAR);\n        } finally {\n            if (debug)\n                dbg_leave(\"domainLabel\");\n        }\n    }\n\n    protected String ipv6Reference() throws ParseException {\n        StringBuffer retval = new StringBuffer();\n        if (debug)\n            dbg_enter(\"ipv6Reference\");\n\n        try {\n\n            if(stripAddressScopeZones){\n                while (lexer.hasMoreChars()) {\n                    char la = lexer.lookAhead(0);\n                    //'%' is ipv6 address scope zone. see detail at\n                    //java.sun.com/j2se/1.5.0/docs/api/java/net/Inet6Address.html\n                    if (LexerCore.isHexDigit(la) || la == '.' || la == ':'\n                            || la == '[' ) {\n                        lexer.consume(1);\n                        retval.append(la);\n                    } else if (la == ']') {\n                        lexer.consume(1);\n                        retval.append(la);\n                        return retval.toString();\n                    } else if (la == '%'){\n                        //we need to strip the address scope zone.\n                        lexer.consume(1);\n\n                        String rest = lexer.getRest();\n\n                        if(rest == null || rest.length() == 0){\n                            //head for the parse exception\n                            break;\n                        }\n\n                        //we strip everything until either the end of the string\n                        //or a closing square bracket (])\n                        int stripLen = rest.indexOf(']');\n\n                        if (stripLen == -1){\n                            //no square bracket -> not a valid ipv6 reference\n                            break;\n                        }\n\n                        lexer.consume(stripLen+1);\n                        retval.append(\"]\");\n                        return retval.toString();\n\n                    } else\n                        break;\n                }\n            }\n            else\n            {\n                while (lexer.hasMoreChars())\n                {\n                    char la = lexer.lookAhead(0);\n                    if (LexerCore.isHexDigit(la) || la == '.'\n                            || la == ':' || la == '[') {\n                        lexer.consume(1);\n                        retval.append(la);\n                    } else if (la == ']') {\n                        lexer.consume(1);\n                        retval.append(la);\n                        return retval.toString();\n                    } else\n                    break;\n                }\n            }\n\n            throw new ParseException(\n                lexer.getBuffer() + \": Illegal Host name \",\n                lexer.getPtr());\n        } finally {\n            if (debug)\n                dbg_leave(\"ipv6Reference\");\n        }\n    }\n\n    public Host host() throws ParseException {\n        if (debug)\n            dbg_enter(\"host\");\n        try {\n            String hostname;\n\n            //IPv6 referene\n            if (lexer.lookAhead(0) == '[') {\n                hostname = ipv6Reference();\n            }\n            //IPv6 address (i.e. missing square brackets)\n            else if( isIPv6Address(lexer.getRest()) )\n            {\n                int startPtr = lexer.getPtr();\n                lexer.consumeValidChars(\n                        new char[] {LexerCore.ALPHADIGIT_VALID_CHARS, ':'});\n                hostname\n                    = new StringBuffer(\"[\").append(\n                        lexer.getBuffer().substring(startPtr, lexer.getPtr()))\n                        .append(\"]\").toString();\n            }\n            //IPv4 address or hostname\n            else {\n                int startPtr = lexer.getPtr();\n                consumeDomainLabel();\n                hostname = lexer.getBuffer().substring(startPtr, lexer.getPtr());\n            }\n\n            if (hostname.length() == 0)\n                throw new ParseException(\n                    lexer.getBuffer() + \": Missing host name\",\n                    lexer.getPtr());\n            else\n                return new Host(hostname);\n        } finally {\n            if (debug)\n                dbg_leave(\"host\");\n        }\n    }\n\n    /**\n     * Tries to determine whether the address in <tt>uriHeader</tt> could be\n     * an IPv6 address by counting the number of colons that appear in it.\n     *\n     * @param uriHeader the string (supposedly the value of a URI header) that\n     * we have received for parsing.\n     *\n     * @return true if the host part of <tt>uriHeader</tt> could be an IPv6\n     * address (i.e. contains at least two colons) and false otherwise.\n     */\n    private boolean isIPv6Address(String uriHeader)\n    {\n        // approximately detect the end the host part.\n        //first check if we have an uri param\n        int hostEnd = uriHeader.indexOf(Lexer.QUESTION);\n\n        //if not or if it appears after a semi-colon then the end of the\n        //address would be a header param.\n        int semiColonIndex = uriHeader.indexOf(Lexer.SEMICOLON);\n        if ( hostEnd == -1\n            || (semiColonIndex!= -1 && hostEnd > semiColonIndex) )\n            hostEnd = semiColonIndex;\n\n        //if there was no header param either the address\n        //continues until the end of the string\n        if ( hostEnd == -1 )\n            hostEnd = uriHeader.length();\n\n        //extract the address\n        String host = uriHeader.substring(0, hostEnd);\n\n        int firstColonIndex = host.indexOf(Lexer.COLON);\n\n        if(firstColonIndex == -1)\n            return false;\n\n        int secondColonIndex = host.indexOf(Lexer.COLON, firstColonIndex + 1);\n\n        if(secondColonIndex == -1)\n            return false;\n\n        return true;\n    }\n    /**\n     * Parses a host:port string\n     *\n     * @param allowWS - whether whitespace is allowed around ':', only true for Via headers\n     * @return\n     * @throws ParseException\n     */\n    public HostPort hostPort( boolean allowWS ) throws ParseException {\n        if (debug)\n            dbg_enter(\"hostPort\");\n        try {\n            Host host = this.host();\n            HostPort hp = new HostPort();\n            hp.setHost(host);\n            // Has a port?\n            if (allowWS) lexer.SPorHT(); // white space before \":port\" should be accepted\n            if (lexer.hasMoreChars()) {\n                char la = lexer.lookAhead(0);\n                switch (la)\n                {\n                case ':':\n                    lexer.consume(1);\n                    if (allowWS) lexer.SPorHT(); // white space before port number should be accepted\n                    try {\n                        String port = lexer.number();\n                        hp.setPort(Integer.parseInt(port));\n                    } catch (NumberFormatException nfe) {\n                        throw new ParseException(\n                            lexer.getBuffer() + \" :Error parsing port \",\n                            lexer.getPtr());\n                    }\n                    break;\n\n                case ',':\t// allowed in case of multi-headers, e.g. Route\n                \t\t\t// Could check that current header is a multi hdr\n                    \n                case ';':   // OK, can appear in URIs (parameters)\n                case '?':   // same, header parameters\n                case '>':   // OK, can appear in headers\n                case ' ':   // OK, allow whitespace\n                case '\\t':\n                case '\\r':\n                case '\\n':\n                case '/':   // e.g. http://[::1]/xyz.html\n                    break;\n                case '%':\n                    if(stripAddressScopeZones){\n                        break;//OK,allow IPv6 address scope zone\n                    }\n                    \n                default:\n                    if (!allowWS) {\n                        throw new ParseException( lexer.getBuffer() +\n                                \" Illegal character in hostname:\" + lexer.lookAhead(0),\n                                lexer.getPtr() );\n                    }\n                }\n            }\n            return hp;\n        } finally {\n            if (debug)\n                dbg_leave(\"hostPort\");\n        }\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String hostNames[] =\n            {\n                \"foo.bar.com:1234\",\n                \"proxima.chaplin.bt.co.uk\",\n                \"129.6.55.181:2345\",\n                \":1234\",\n                \"foo.bar.com:         1234\",\n                \"foo.bar.com     :      1234   \",\n                \"MIK_S:1234\"\n            };\n\n        for (int i = 0; i < hostNames.length; i++) {\n            try {\n                HostNameParser hnp = new HostNameParser(hostNames[i]);\n                HostPort hp = hnp.hostPort(true);\n                System.out.println(\"[\"+hp.encode()+\"]\");\n            } catch (ParseException ex) {\n                System.out.println(\"exception text = \" + ex.getMessage());\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/HostPort.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.core;\nimport java.net.*;\n\n/**\n* Holds the hostname:port.\n*\n*@version 1.2\n*\n*@author M. Ranganathan\n*\n*\n*\n*/\npublic final class HostPort extends GenericObject {\n\n\n    private static final long serialVersionUID = -7103412227431884523L;\n\n    // host / ipv4/ ipv6/\n    /** host field\n     */\n    protected Host host;\n\n    /** port field\n     *\n     */\n    protected int port;\n\n    /** Default constructor\n     */\n    public HostPort() {\n\n        host = null;\n        port = -1; // marker for not set.\n    }\n\n    /**\n     * Encode this hostport into its string representation.\n     * Note that this could be different from the string that has\n     * been parsed if something has been edited.\n     * @return String\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        host.encode(buffer);\n        if (port != -1)\n            buffer.append(COLON).append(port);\n        return buffer;\n    }\n\n    /** returns true if the two objects are equals, false otherwise.\n     * @param other Object to set\n     * @return boolean\n     */\n    public boolean equals(Object other) {\n        if (other == null) return false;\n        if (getClass () != other.getClass ()) {\n            return false;\n        }\n        HostPort that = (HostPort) other;\n        return port == that.port && host.equals(that.host);\n    }\n\n    /** get the Host field\n     * @return host field\n     */\n    public Host getHost() {\n        return host;\n    }\n\n    /** get the port field\n     * @return int\n     */\n    public int getPort() {\n        return port;\n    }\n\n    /**\n     * Returns boolean value indicating if Header has port\n     * @return boolean value indicating if Header has port\n     */\n    public boolean hasPort() {\n        return port != -1;\n    }\n\n    /** remove port.\n     */\n    public void removePort() {\n        port = -1;\n    }\n\n    /**\n         * Set the host member\n         * @param h Host to set\n         */\n    public void setHost(Host h) {\n        host = h;\n    }\n\n    /**\n         * Set the port member\n         * @param p int to set\n         */\n    public void setPort(int p) {\n        port = p;\n    }\n\n    /** Return the internet address corresponding to the host.\n     *@throws java.net.UnkownHostException if host name cannot be resolved.\n     *@return the inet address for the host.\n     */\n    public InetAddress getInetAddress() throws java.net.UnknownHostException {\n        if (host == null)\n            return null;\n        else\n            return host.getInetAddress();\n    }\n\n    public void merge(Object mergeObject) {\n        super.merge (mergeObject);\n        if (port == -1)\n            port = ((HostPort) mergeObject).port;\n    }\n\n    public Object clone() {\n        HostPort retval = (HostPort) super.clone();\n        if (this.host != null)\n            retval.host = (Host) this.host.clone();\n        return retval;\n    }\n\n    public String toString() {\n        return this.encode();\n    }\n    \n    @Override\n    public int hashCode() {\n        return this.host.hashCode() + this.port;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/InternalErrorHandler.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.core;\n/**\n*  Handle Internal error failures and print a stack trace (for debugging).\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\npublic class InternalErrorHandler {\n\n    public static void handleException(Exception ex) throws RuntimeException {\n        System.err.println (\"Unexpected internal error FIXME!! \"  + ex.getMessage());\n        ex.printStackTrace();\n        throw new RuntimeException(\"Unexpected internal error FIXME!! \"  + ex.getMessage(), ex);\n\n    }\n    /**\n    * Handle an unexpected exception.\n    */\n    public static void handleException(Exception ex, StackLogger stackLogger) {\n        System.err.println (\"Unexpected internal error FIXME!! \"  + ex.getMessage());\n        stackLogger.logError(\"UNEXPECTED INTERNAL ERROR FIXME \" +  ex.getMessage());\n        ex.printStackTrace();\n        stackLogger.logException(ex);\n        throw new RuntimeException(\"Unexpected internal error FIXME!! \"  + ex.getMessage(), ex);\n\n    }\n    /**\n    * Handle an unexpected condition (and print the error code).\n    */\n\n    public static void handleException(String emsg) {\n        new Exception().printStackTrace();\n        System.err.println(\"Unexepcted INTERNAL ERROR FIXME!!\");\n        System.err.println(emsg);\n        throw new RuntimeException(emsg);\n\n    }\n\n    public static void handleException(String emsg, StackLogger stackLogger) {\n        stackLogger.logStackTrace();\n        stackLogger.logError(\"Unexepcted INTERNAL ERROR FIXME!!\");\n        stackLogger.logFatalError(emsg);\n        throw new RuntimeException(emsg);\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/LexerCore.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core;\n\nimport java.text.ParseException;\nimport java.util.Hashtable;\n\n/** A lexical analyzer that is used by all parsers in our implementation.\n *\n *@version 1.2\n *@since 1.1\n *\n *@author M. Ranganathan\n */\npublic class LexerCore extends StringTokenizer {\n\n    // IMPORTANT - All keyword matches should be between START and END\n    public static final int START = 2048;\n    public static final int END = START + 2048;\n    // IMPORTANT -- This should be < END\n    public static final int ID = END - 1;\n    public static final int SAFE = END - 2;\n    // Individial token classes.\n    public static final int WHITESPACE = END + 1;\n    public static final int DIGIT = END + 2;\n    public static final int ALPHA = END + 3;\n    public static final int BACKSLASH = (int) '\\\\';\n    public static final int QUOTE = (int) '\\'';\n    public static final int AT = (int) '@';\n    public static final int SP = (int) ' ';\n    public static final int HT = (int) '\\t';\n    public static final int COLON = (int) ':';\n    public static final int STAR = (int) '*';\n    public static final int DOLLAR = (int) '$';\n    public static final int PLUS = (int) '+';\n    public static final int POUND = (int) '#';\n    public static final int MINUS = (int) '-';\n    public static final int DOUBLEQUOTE = (int) '\\\"';\n    public static final int TILDE = (int) '~';\n    public static final int BACK_QUOTE = (int) '`';\n    public static final int NULL = (int) '\\0';\n    public static final int EQUALS = (int) '=';\n    public static final int SEMICOLON = (int) ';';\n    public static final int SLASH = (int) '/';\n    public static final int L_SQUARE_BRACKET = (int) '[';\n    public static final int R_SQUARE_BRACKET = (int) ']';\n    public static final int R_CURLY = (int) '}';\n    public static final int L_CURLY = (int) '{';\n    public static final int HAT = (int) '^';\n    public static final int BAR = (int) '|';\n    public static final int DOT = (int) '.';\n    public static final int EXCLAMATION = (int) '!';\n    public static final int LPAREN = (int) '(';\n    public static final int RPAREN = (int) ')';\n    public static final int GREATER_THAN = (int) '>';\n    public static final int LESS_THAN = (int) '<';\n    public static final int PERCENT = (int) '%';\n    public static final int QUESTION = (int) '?';\n    public static final int AND = (int) '&';\n    public static final int UNDERSCORE = (int) '_';\n\n    protected static final Hashtable globalSymbolTable;\n    protected static final Hashtable lexerTables;\n    protected Hashtable currentLexer;\n    protected String currentLexerName;\n    protected Token currentMatch;\n\n    static {\n        globalSymbolTable = new Hashtable();\n        lexerTables = new Hashtable();\n    }\n\n    protected void addKeyword(String name, int value) {\n        // System.out.println(\"addKeyword \" + name + \" value = \" + value);\n        // new Exception().printStackTrace();\n        Integer val = Integer.valueOf(value);\n        currentLexer.put(name, val);\n        if (!globalSymbolTable.containsKey(val))\n            globalSymbolTable.put(val, name);\n    }\n\n    public String lookupToken(int value) {\n        if (value > START) {\n            return (String) globalSymbolTable.get(Integer.valueOf(value));\n        } else {\n            Character ch = Character.valueOf((char) value);\n            return ch.toString();\n        }\n    }\n\n    protected Hashtable addLexer(String lexerName) {\n        currentLexer = (Hashtable) lexerTables.get(lexerName);\n        if (currentLexer == null) {\n            currentLexer = new Hashtable();\n            lexerTables.put(lexerName, currentLexer);\n        }\n        return currentLexer;\n    }\n\n    //public abstract void selectLexer(String lexerName);\n\n    public void selectLexer(String lexerName) {\n        this.currentLexerName = lexerName;\n    }\n\n    protected LexerCore() {\n        this.currentLexer = new Hashtable();\n        this.currentLexerName = \"charLexer\";\n    }\n\n    /** Initialize the lexer with a buffer.\n     */\n    public LexerCore(String lexerName, String buffer) {\n        super(buffer);\n        this.currentLexerName = lexerName;\n    }\n\n    /** Peek the next id but dont move the buffer pointer forward.\n     */\n\n    public String peekNextId() {\n        int oldPtr = ptr;\n        String retval = ttoken();\n        savedPtr = ptr;\n        ptr = oldPtr;\n        return retval;\n    }\n\n    /** Get the next id.\n     */\n    public String getNextId() {\n        return ttoken();\n    }\n\n    // call this after you call match\n    public Token getNextToken() {\n        return this.currentMatch;\n\n    }\n\n    /** Look ahead for one token.\n     */\n    public Token peekNextToken() throws ParseException {\n        return (Token) peekNextToken(1)[0];\n    }\n\n    public Token[] peekNextToken(int ntokens) throws ParseException {\n        int old = ptr;\n        Token[] retval = new Token[ntokens];\n        for (int i = 0; i < ntokens; i++) {\n            Token tok = new Token();\n            if (startsId()) {\n                String id = ttoken();\n                tok.tokenValue = id;\n                String idUppercase = id.toUpperCase();\n                if (currentLexer.containsKey(idUppercase)) {\n                    Integer type = (Integer) currentLexer.get(idUppercase);\n                    tok.tokenType = type.intValue();\n                } else\n                    tok.tokenType = ID;\n            } else {\n                char nextChar = getNextChar();\n                tok.tokenValue = String.valueOf(nextChar);\n                if (isAlpha(nextChar)) {\n                    tok.tokenType = ALPHA;\n                } else if (isDigit(nextChar)) {\n                    tok.tokenType = DIGIT;\n                } else\n                    tok.tokenType = (int) nextChar;\n            }\n            retval[i] = tok;\n        }\n        savedPtr = ptr;\n        ptr = old;\n        return retval;\n    }\n\n    /** Match the given token or throw an exception if no such token\n     * can be matched.\n     */\n    public Token match(int tok) throws ParseException {\n        if (Debug.parserDebug) {\n            Debug.println(\"match \" + tok);\n        }\n        if (tok > START && tok < END) {\n            if (tok == ID) {\n                // Generic ID sought.\n                if (!startsId())\n                    throw new ParseException(buffer + \"\\nID expected\", ptr);\n                String id = getNextId();\n                this.currentMatch = new Token();\n                this.currentMatch.tokenValue = id;\n                this.currentMatch.tokenType = ID;\n            } else if (tok == SAFE) {\n                if (!startsSafeToken())\n                    throw new ParseException(buffer + \"\\nID expected\", ptr);\n                String id = ttokenSafe();\n                this.currentMatch = new Token();\n                this.currentMatch.tokenValue = id;\n                this.currentMatch.tokenType = SAFE;\n            } else {\n                String nexttok = getNextId();\n                Integer cur = (Integer) currentLexer.get(nexttok.toUpperCase());\n\n                if (cur == null || cur.intValue() != tok)\n                    throw new ParseException(\n                        buffer + \"\\nUnexpected Token : \" + nexttok,\n                        ptr);\n                this.currentMatch = new Token();\n                this.currentMatch.tokenValue = nexttok;\n                this.currentMatch.tokenType = tok;\n            }\n        } else if (tok > END) {\n            // Character classes.\n            char next = lookAhead(0);\n            if (tok == DIGIT) {\n                if (!isDigit(next))\n                    throw new ParseException(buffer + \"\\nExpecting DIGIT\", ptr);\n                this.currentMatch = new Token();\n                this.currentMatch.tokenValue =\n                    String.valueOf(next);\n                this.currentMatch.tokenType = tok;\n                consume(1);\n\n            } else if (tok == ALPHA) {\n                if (!isAlpha(next))\n                    throw new ParseException(buffer + \"\\nExpecting ALPHA\", ptr);\n                this.currentMatch = new Token();\n                this.currentMatch.tokenValue =\n                    String.valueOf(next);\n                this.currentMatch.tokenType = tok;\n                consume(1);\n\n            }\n\n        } else {\n            // This is a direct character spec.\n            char ch = (char) tok;\n            char next = lookAhead(0);\n            if (next == ch) {\n                /*this.currentMatch = new Token();\n                this.currentMatch.tokenValue =\n                    String.valueOf(ch);\n                this.currentMatch.tokenType = tok;*/\n                consume(1);\n            } else\n                throw new ParseException(\n                    buffer + \"\\nExpecting  >>>\" + ch + \"<<< got >>>\"\n                    + next + \"<<<\", ptr);\n        }\n        return this.currentMatch;\n    }\n\n    public void SPorHT() {\n        try {\n            char c = lookAhead(0);\n            while (c == ' ' || c == '\\t') {\n                consume(1);\n                c = lookAhead(0);\n            }\n        } catch (ParseException ex) {\n            // Ignore\n        }\n    }\n\n    /**\n     * JvB: utility function added to validate tokens\n     *\n     * @see RFC3261 section 25.1:\n     * token       =  1*(alphanum / \"-\" / \".\" / \"!\" / \"%\" / \"*\"\n                     / \"_\" / \"+\" / \"`\" / \"'\" / \"~\" )\n\n     * @param c - character to check\n     * @return true iff character c is a valid token character as per RFC3261\n     */\n    public static final boolean isTokenChar( char c ) {\n        if ( isAlphaDigit(c) ) return true;\n        else switch (c)\n        {\n            case '-':\n            case '.':\n            case '!':\n            case '%':\n            case '*':\n            case '_':\n            case '+':\n            case '`':\n            case '\\'':\n            case '~':\n                return true;\n            default:\n                return false;\n        }\n    }\n\n\n    public boolean startsId() {\n        try {\n            char nextChar = lookAhead(0);\n            return isTokenChar(nextChar);\n        } catch (ParseException ex) {\n            return false;\n        }\n    }\n\n    public boolean startsSafeToken() {\n        try {\n            char nextChar = lookAhead(0);\n            if (isAlphaDigit(nextChar)) {\n                return true;\n            }\n            else {\n                switch (nextChar) {\n                    case '_':\n                    case '+':\n                    case '-':\n                    case '!':\n                    case '`':\n                    case '\\'':\n                    case '.':\n                    case '/':\n                    case '}':\n                    case '{':\n                    case ']':\n                    case '[':\n                    case '^':\n                    case '|':\n                    case '~':\n                    case '%': // bug fix by Bruno Konik, JvB copied here\n                    case '#':\n                    case '@':\n                    case '$':\n                    case ':':\n                    case ';':\n                    case '?':\n                    case '\\\"':\n                    case '*':\n                    case '=': // Issue 155 on java.net\n                        return true;\n                    default:\n                        return false;\n                }\n            }\n        } catch (ParseException ex) {\n            return false;\n        }\n    }\n\n    public String ttoken() {\n        int startIdx = ptr;\n        try {\n            while (hasMoreChars()) {\n                char nextChar = lookAhead(0);\n                if ( isTokenChar(nextChar) ) {\n                    consume(1);\n                } else {\n                    break;\n                }\n            }\n            return buffer.substring(startIdx, ptr);\n        } catch (ParseException ex) {\n            return null;\n        }\n    }\n\n    /* JvB: unreferenced\n    public String ttokenAllowSpace() {\n        int startIdx = ptr;\n        try {\n            while (hasMoreChars()) {\n                char nextChar = lookAhead(0);\n                if (isAlphaDigit(nextChar)) {\n                    consume(1);\n                }\n                else {\n                    boolean isValidChar = false;\n                    switch (nextChar) {\n                        case '_':\n                        case '+':\n                        case '-':\n                        case '!':\n                        case '`':\n                        case '\\'':\n                        case '~':\n                        case '%': // bug fix by Bruno Konik, JvB copied here\n                        case '.':\n                        case ' ':\n                        case '\\t':\n                        case '*':\n                            isValidChar = true;\n                    }\n                    if (isValidChar) {\n                        consume(1);\n                    }\n                    else {\n                        break;\n                    }\n                }\n\n            }\n            return buffer.substring(startIdx, ptr);\n        } catch (ParseException ex) {\n            return null;\n        }\n    }*/\n\n    public String ttokenSafe() {\n        int startIdx = ptr;\n        try {\n            while (hasMoreChars()) {\n                char nextChar = lookAhead(0);\n                if (isAlphaDigit(nextChar)) {\n                    consume(1);\n                }\n                else {\n                    boolean isValidChar = false;\n                    switch (nextChar) {\n                        case '_':\n                        case '+':\n                        case '-':\n                        case '!':\n                        case '`':\n                        case '\\'':\n                        case '.':\n                        case '/':\n                        case '}':\n                        case '{':\n                        case ']':\n                        case '[':\n                        case '^':\n                        case '|':\n                        case '~':\n                        case '%': // bug fix by Bruno Konik, JvB copied here\n                        case '#':\n                        case '@':\n                        case '$':\n                        case ':':\n                        case ';':\n                        case '?':\n                        case '\\\"':\n                        case '*':\n                            isValidChar = true;\n                    }\n                    if (isValidChar) {\n                        consume(1);\n                    }\n                    else {\n                        break;\n                    }\n                }\n            }\n            return buffer.substring(startIdx, ptr);\n        } catch (ParseException ex) {\n            return null;\n        }\n    }\n\n    static final char ALPHA_VALID_CHARS = Character.MAX_VALUE;\n    static final char DIGIT_VALID_CHARS = Character.MAX_VALUE - 1;\n    static final char ALPHADIGIT_VALID_CHARS = Character.MAX_VALUE - 2;\n    public void consumeValidChars(char[] validChars) {\n        int validCharsLength = validChars.length;\n        try {\n            while (hasMoreChars()) {\n                char nextChar = lookAhead(0);\n                boolean isValid = false;\n                for (int i = 0; i < validCharsLength; i++) {\n                    char validChar = validChars[i];\n                    switch(validChar) {\n                        case ALPHA_VALID_CHARS:\n                            isValid = isAlpha(nextChar);\n                            break;\n                        case DIGIT_VALID_CHARS:\n                            isValid = isDigit(nextChar);\n                            break;\n                        case ALPHADIGIT_VALID_CHARS:\n                            isValid = isAlphaDigit(nextChar);\n                            break;\n                        default:\n                            isValid = nextChar == validChar;\n                    }\n                    if (isValid) {\n                        break;\n                    }\n                }\n                if (isValid) {\n                    consume(1);\n                }\n                else {\n                    break;\n                }\n            }\n        } catch (ParseException ex) {\n\n        }\n    }\n\n    /** Parse a comment string cursor is at a \". Leave cursor at closing \"\n    *@return the substring containing the quoted string excluding the\n    * closing quote.\n    */\n    public String quotedString() throws ParseException {\n        int startIdx = ptr + 1;\n        if (lookAhead(0) != '\\\"')\n            return null;\n        consume(1);\n        while (true) {\n            char next = getNextChar();\n            if (next == '\\\"') {\n                // Got to the terminating quote.\n                break;\n            } else if (next == '\\0') {\n                throw new ParseException(\n                    this.buffer + \" :unexpected EOL\",\n                    this.ptr);\n            } else if (next == '\\\\') {\n                consume(1);\n            }\n        }\n        return buffer.substring(startIdx, ptr - 1);\n    }\n\n    /** Parse a comment string cursor is at a \"(\". Leave cursor at )\n    *@return the substring containing the comment excluding the\n    * closing brace.\n    */\n    public String comment() throws ParseException {\n        StringBuffer retval = new StringBuffer();\n        if (lookAhead(0) != '(')\n            return null;\n        consume(1);\n        while (true) {\n            char next = getNextChar();\n            if (next == ')') {\n                break;\n            } else if (next == '\\0') {\n                throw new ParseException(\n                    this.buffer + \" :unexpected EOL\",\n                    this.ptr);\n            } else if (next == '\\\\') {\n                retval.append(next);\n                next = getNextChar();\n                if (next == '\\0')\n                    throw new ParseException(\n                        this.buffer + \" : unexpected EOL\",\n                        this.ptr);\n                retval.append(next);\n            } else {\n                retval.append(next);\n            }\n        }\n        return retval.toString();\n    }\n\n    /** Return a substring containing no semicolons.\n    *@return a substring containing no semicolons.\n    */\n    public String byteStringNoSemicolon() {\n        StringBuffer retval = new StringBuffer();\n        try {\n            while (true) {\n                char next = lookAhead(0);\n                // bug fix from Ben Evans.\n                if (next == '\\0' || next == '\\n' || next == ';' || next == ',' ) {\n                    break;\n                } else {\n                    consume(1);\n                    retval.append(next);\n                }\n            }\n        } catch (ParseException ex) {\n            return retval.toString();\n        }\n        return retval.toString();\n    }\n\n    /**\n     * Scan until you see a slash or an EOL.\n     *\n     * @return substring containing no slash.\n     */\n    public String byteStringNoSlash() {\n        StringBuffer retval = new StringBuffer();\n        try {\n            while (true) {\n                char next = lookAhead(0);\n                // bug fix from Ben Evans.\n                if (next == '\\0' || next == '\\n' || next == '/'  ) {\n                    break;\n                } else {\n                    consume(1);\n                    retval.append(next);\n                }\n            }\n        } catch (ParseException ex) {\n            return retval.toString();\n        }\n        return retval.toString();\n    }\n\n    /** Return a substring containing no commas\n    *@return a substring containing no commas.\n    */\n\n    public String byteStringNoComma() {\n        StringBuffer retval = new StringBuffer();\n        try {\n            while (true) {\n                char next = lookAhead(0);\n                if (next == '\\n' || next == ',') {\n                    break;\n                } else {\n                    consume(1);\n                    retval.append(next);\n                }\n            }\n        } catch (ParseException ex) {\n        }\n        return retval.toString();\n    }\n\n    public static String charAsString(char ch) {\n        return String.valueOf(ch);\n    }\n\n    /** Lookahead in the inputBuffer for n chars and return as a string.\n     * Do not consume the input.\n     */\n    public String charAsString(int nchars) {\n        return buffer.substring(ptr, ptr + nchars);\n    }\n\n    /** Get and consume the next number.\n     *@return a substring corresponding to a number\n     *(i.e. sequence of digits).\n     */\n    public String number() throws ParseException {\n\n        int startIdx = ptr;\n        try {\n            if (!isDigit(lookAhead(0))) {\n                throw new ParseException(\n                    buffer + \": Unexpected token at \" + lookAhead(0),\n                    ptr);\n            }\n            consume(1);\n            while (true) {\n                char next = lookAhead(0);\n                if (isDigit(next)) {\n                    consume(1);\n                } else\n                    break;\n            }\n            return buffer.substring(startIdx, ptr);\n        } catch (ParseException ex) {\n            return buffer.substring(startIdx, ptr);\n        }\n    }\n\n    /** Mark the position for backtracking.\n     *@return the current location of the pointer.\n     */\n    public int markInputPosition() {\n        return ptr;\n    }\n\n    /** Rewind the input ptr to the marked position.\n     *@param position - the position to rewind the parser to.\n     */\n    public void rewindInputPosition(int position) {\n        this.ptr = position;\n    }\n\n    /** Get the rest of the String\n     * @return rest of the buffer.\n     */\n    public String getRest() {\n        if (ptr >= buffer.length())\n            return null;\n        else\n            return buffer.substring(ptr);\n    }\n\n    /** Get the sub-String until the character is encountered\n     * @param c the character to match\n     * @return the substring that matches.\n     */\n    public String getString(char c) throws ParseException {\n        StringBuffer retval = new StringBuffer();\n        while (true) {\n            char next = lookAhead(0);\n            //System.out.println(\" next = [\" + next + ']' + \"ptr = \" + ptr);\n            //System.out.println(next == '\\0');\n\n            if (next == '\\0') {\n                throw new ParseException(\n                    this.buffer + \"unexpected EOL\",\n                    this.ptr);\n            } else if (next == c) {\n                consume(1);\n                break;\n            } else if (next == '\\\\') {\n                consume(1);\n                char nextchar = lookAhead(0);\n                if (nextchar == '\\0') {\n                    throw new ParseException(\n                        this.buffer + \"unexpected EOL\",\n                        this.ptr);\n                } else {\n                    consume(1);\n                    retval.append(nextchar);\n                }\n            } else {\n                consume(1);\n                retval.append(next);\n            }\n        }\n        return retval.toString();\n    }\n\n    /** Get the read pointer.\n     */\n    public int getPtr() {\n        return this.ptr;\n    }\n\n    /** Get the buffer.\n     */\n    public String getBuffer() {\n        return this.buffer;\n    }\n\n    /** Create a parse exception.\n     */\n    public ParseException createParseException() {\n        return new ParseException(this.buffer, this.ptr);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/LogLevels.java",
    "content": "package gov2.nist.core;\n\npublic interface LogLevels {\n    /*\n     * Each of these levels must be mapped internally to logically equivalent\n     * logging levels in your logger.\n     */\n    public static final int TRACE_NONE  =  0;\n    public static final int TRACE_FATAL =  2;\n    public static final int TRACE_ERROR =  4;\n    public static final int TRACE_WARN  =  8;\n    public static final int TRACE_INFO  = 16;\n    public static final int TRACE_DEBUG = 32;\n    public static final int TRACE_TRACE = 64;\n    public static final int TRACE_MESSAGES = TRACE_INFO;\n    public static final int TRACE_EXCEPTION = TRACE_ERROR;\n    \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/LogWriter.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\n/***************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).    *\n ***************************************************************************/\npackage gov2.nist.core;\n\nimport java.io.*;\nimport java.util.Properties;\n\n// BEGIN ANDROID-added\n// TODO: this class should be replaced by android logging mechanism.\npublic class LogWriter implements StackLogger {\n    private static final String TAG = \"SIP_STACK\";\n\n    private boolean mEnabled = true;\n\n    public void logStackTrace() {\n        // TODO\n    }\n\n    public void logStackTrace(int traceLevel) {\n        // TODO\n    }\n\n    public int getLineCount() {\n        return 0;\n    }\n\n    public void logException(Throwable ex) {\n        //Log.e(TAG, \"\", ex);\n    }\n    public void logDebug(String message) {\n        //Log.d(TAG, message);\n    }\n    public void logTrace(String message) {\n        //Log.d(TAG, message);\n    }\n    public void logFatalError(String message) {\n        //Log.e(TAG, message);\n    }\n    public void logError(String message) {\n        //Log.e(TAG, message);\n    }\n    public boolean isLoggingEnabled() {\n        return mEnabled;\n    }\n    public boolean isLoggingEnabled(int logLevel) {\n        // TODO\n        return mEnabled;\n    }\n    public void logError(String message, Exception ex) {\n        //Log.e(TAG, message, ex);\n    }\n    public void logWarning(String string) {\n        //Log.w(TAG, string);\n    }\n    public void logInfo(String string) {\n        //Log.i(TAG, string);\n    }\n\n    public void disableLogging() {\n        mEnabled = false;\n    }\n\n    public void enableLogging() {\n        mEnabled = true;\n    }\n\n    public void setBuildTimeStamp(String buildTimeStamp) {\n    }\n\n    public void setStackProperties(Properties stackProperties) {\n    }\n\n    public String getLoggerName() {\n        return \"Android SIP Logger\";\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/Match.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core;\n\n/** Match template for pattern matching.\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\n\npublic interface Match {\n    /** Return true if a match occurs for searchString.\n    * This is used for pattern matching in the find and replace and match\n    * functions of the sipheaders and sdpfields packages. We have avoided\n    * picking a specific regexp package to avoid code dependencies.\n    * Use a package such as the jakarta regexp package to implement this.\n    */\n    public boolean match(String searchString);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/MultiValueMap.java",
    "content": "package gov2.nist.core;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\npublic interface MultiValueMap<K,V> extends Map<K,List<V>>, Serializable {\n    // remove(K, V) conflicts with a Map method added in 1.8. http://b/27426743\n    /* public Object remove( K key, V item ); */\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/MultiValueMapImpl.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\npackage gov2.nist.core;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class MultiValueMapImpl<V> implements MultiValueMap<String, V>, Cloneable {\n    private HashMap<String, ArrayList<V>> map = new HashMap<String, ArrayList<V>>();\n\n    private static final long serialVersionUID = 4275505380960964605L;\n\n    public MultiValueMapImpl() {\n        super();\n\n    }\n\n    public List<V> put(String key, V value) {\n        ArrayList<V> keyList = map.get(key);\n        if (keyList == null) {\n            keyList = new ArrayList<V>(10);\n            map.put(key, keyList);\n        }\n\n        keyList.add(value);\n        return keyList;\n    }\n\n    public boolean containsValue(Object value) {\n        Set pairs = map.entrySet();\n\n        if (pairs == null)\n            return false;\n\n        Iterator pairsIterator = pairs.iterator();\n        while (pairsIterator.hasNext()) {\n            Map.Entry keyValuePair = (Map.Entry) (pairsIterator.next());\n            ArrayList list = (ArrayList) (keyValuePair.getValue());\n            if (list.contains(value))\n                return true;\n        }\n        return false;\n    }\n\n    public void clear() {\n        Set pairs = map.entrySet();\n        Iterator pairsIterator = pairs.iterator();\n        while (pairsIterator.hasNext()) {\n            Map.Entry keyValuePair = (Map.Entry) (pairsIterator.next());\n            ArrayList list = (ArrayList) (keyValuePair.getValue());\n            list.clear();\n        }\n        map.clear();\n    }\n\n    public Collection values() {\n        ArrayList returnList = new ArrayList(map.size());\n\n        Set pairs = map.entrySet();\n        Iterator pairsIterator = pairs.iterator();\n        while (pairsIterator.hasNext()) {\n            Map.Entry keyValuePair = (Map.Entry) (pairsIterator.next());\n            ArrayList list = (ArrayList) (keyValuePair.getValue());\n\n            Object[] values = list.toArray();\n            for (int ii = 0; ii < values.length; ii++) {\n                returnList.add(values[ii]);\n            }\n        }\n        return returnList;\n    }\n\n    public Object clone() {\n        MultiValueMapImpl obj = new MultiValueMapImpl<V>();\n        obj.map = (HashMap<Object, ArrayList<V>>) this.map.clone();\n        return obj;\n    }\n\n    public int size() {\n        return this.map.size();\n    }\n\n    public boolean containsKey(Object key) {\n        return map.containsKey(key);\n    }\n\n    public Set entrySet() {\n        return map.entrySet();\n    }\n\n    public boolean isEmpty() {\n        return map.isEmpty();\n    }\n\n    public Set<String> keySet() {\n        return this.map.keySet();\n    }\n\n    // remove(K, V) conflicts with a Map method added in 1.8. http://b/27426743\n    /* public Object remove(String key, V item) {\n        ArrayList<V> list = this.map.get(key);\n        if (list == null) {\n            return null;\n        } else {\n            return list.remove(item);\n        }\n    } */\n\n    public List<V> get(Object key) {\n        return map.get(key);\n    }\n\n    public List<V> put(String key, List<V> value) {\n        return this.map.put(key,(ArrayList<V>) value);\n    }\n\n    public List<V> remove(Object key) {\n        return map.remove(key);\n    }\n    \n    public void putAll(Map< ? extends String, ? extends List<V>> mapToPut) {\n        for (String k : mapToPut.keySet()) {\n            ArrayList<V> al = new ArrayList<V>();\n            al.addAll(mapToPut.get(k));\n            this.map.put(k, al);\n        }  \n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/NameValue.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.core;\n\nimport java.util.Map.Entry;\n\n/*\n * Bug reports and fixes: Kirby Kiem, Jeroen van Bemmel.\n */\n\n/**\n * Generic structure for storing name-value pairs.\n *\n * @version 1.2\n *\n * @author M. Ranganathan <br/>\n *\n *\n *\n */\npublic class NameValue extends GenericObject implements Entry<String,String> {\n\n    private static final long serialVersionUID = -1857729012596437950L;\n\n    protected boolean isQuotedString;\n\n    protected final boolean isFlagParameter;\n\n    private String separator;\n\n    private String quotes;\n\n    private String name;\n\n    private Object value;\n\n    public NameValue() {\n        name = null;\n        value = \"\";\n        separator = Separators.EQUALS;\n        this.quotes = \"\";\n        this.isFlagParameter = false;\n    }\n\n    /**\n     * New constructor, taking a boolean which is set if the NV pair is a flag\n     *\n     * @param n\n     * @param v\n     * @param isFlag\n     */\n    public NameValue(String n, Object v, boolean isFlag) {\n\n        // assert (v != null ); // I dont think this assertion is correct mranga\n\n        name = n;\n        value = v;\n        separator = Separators.EQUALS;\n        quotes = \"\";\n        this.isFlagParameter = isFlag;\n    }\n\n    /**\n     * Original constructor, sets isFlagParameter to 'false'\n     *\n     * @param n\n     * @param v\n     */\n    public NameValue(String n, Object v) {\n        this(n, v, false);\n    }\n\n    /**\n     * Set the separator for the encoding method below.\n     */\n    public void setSeparator(String sep) {\n        separator = sep;\n    }\n\n    /**\n     * A flag that indicates that doublequotes should be put around the value\n     * when encoded (for example name=value when value is doublequoted).\n     */\n    public void setQuotedValue() {\n        isQuotedString = true;\n        this.quotes = Separators.DOUBLE_QUOTE;\n    }\n\n    /**\n     * Return true if the value is quoted in doublequotes.\n     */\n    public boolean isValueQuoted() {\n        return isQuotedString;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public Object getValueAsObject() {\n        return isFlagParameter ? \"\" : value; // never return null for flag\n                                                // params\n    }\n\n    /**\n     * Set the name member\n     */\n    public void setName(String n) {\n        name = n;\n    }\n\n    /**\n     * Set the value member\n     */\n    public void setValueAsObject(Object v) {\n        value = v;\n    }\n\n    /**\n     * Get the encoded representation of this namevalue object. Added\n     * doublequote for encoding doublequoted values.\n     *\n     * Bug: RFC3261 stipulates that an opaque parameter in authenticate header\n     * has to be:\n     * opaque              =  \"opaque\" EQUAL quoted-string\n     * so returning just the name is not acceptable. (e.g. LinkSys phones\n     * are picky about this)\n     *\n     * @since 1.0\n     * @return an encoded name value (eg. name=value) string.\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (name != null && value != null && !isFlagParameter) {\n            if (GenericObject.isMySubclass(value.getClass())) {\n                GenericObject gv = (GenericObject) value;\n                buffer.append(name).append(separator).append(quotes);\n                gv.encode(buffer);\n                buffer.append(quotes);\n                return buffer;\n            } else if (GenericObjectList.isMySubclass(value.getClass())) {\n                GenericObjectList gvlist = (GenericObjectList) value;\n                buffer.append(name).append(separator).append(gvlist.encode());\n                return buffer;\n            } else if ( value.toString().length() == 0) {\n                // opaque=\"\" bug fix - pmusgrave\n                /*if (name.toString().equals(gov2.nist.javax2.sip.header.ParameterNames.OPAQUE))\n                    return name + separator + quotes + quotes;\n                else\n                    return name;*/\n                if ( this.isQuotedString ) {\n                    buffer.append(name).append(separator).append(quotes).append(quotes);\n                    return buffer;\n                } else {\n                    buffer.append(name).append(separator); // JvB: fix, case: \"sip:host?subject=\"\n                    return buffer;\n                }\n            } else {\n                buffer.append(name).append(separator).append(quotes).append(value.toString()).append(quotes);\n                return buffer;\n            }\n        } else if (name == null && value != null) {\n            if (GenericObject.isMySubclass(value.getClass())) {\n                GenericObject gv = (GenericObject) value;\n                gv.encode(buffer);\n                return buffer;\n            } else if (GenericObjectList.isMySubclass(value.getClass())) {\n                GenericObjectList gvlist = (GenericObjectList) value;\n                buffer.append(gvlist.encode());\n                return buffer;\n            } else {\n                buffer.append(quotes).append(value.toString()).append(quotes);\n                return buffer;\n            }\n        } else if (name != null && (value == null || isFlagParameter)) {\n            buffer.append(name);\n            return buffer;\n        } else {\n            return buffer;\n        }\n    }\n\n    public Object clone() {\n        NameValue retval = (NameValue) super.clone();\n        if (value != null)\n            retval.value = makeClone(value);\n        return retval;\n    }\n\n    /**\n     * Equality comparison predicate.\n     */\n    public boolean equals(Object other) {\n        if (other == null ) return false;\n        if (!other.getClass().equals(this.getClass()))\n            return false;\n        NameValue that = (NameValue) other;\n        if (this == that)\n            return true;\n        if (this.name == null && that.name != null || this.name != null\n                && that.name == null)\n            return false;\n        if (this.name != null && that.name != null\n                && this.name.compareToIgnoreCase(that.name) != 0)\n            return false;\n        if (this.value != null && that.value == null || this.value == null\n                && that.value != null)\n            return false;\n        if (this.value == that.value)\n            return true;\n        if (value instanceof String) {\n            // Quoted string comparisions are case sensitive.\n            if (isQuotedString)\n                return this.value.equals(that.value);\n            String val = (String) this.value;\n            String val1 = (String) that.value;\n            return val.compareToIgnoreCase(val1) == 0;\n        } else\n            return this.value.equals(that.value);\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map$Entry#getKey()\n     */\n    public String getKey() {\n\n        return this.name;\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map$Entry#getValue()\n     */\n    public String getValue() {\n\n        return  value == null ? null : this.value.toString();\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map$Entry#setValue(java.lang.Object)\n     */\n    public String setValue(String value) {\n        String retval = this.value == null ? null : value;\n        this.value = value;\n        return retval;\n\n    }\n    \n    @Override\n    public int hashCode() {\n        return this.encode().toLowerCase().hashCode();\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/NameValueList.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.core;\n\nimport java.util.concurrent.*;\n\nimport java.io.Serializable;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n/**\n * Implements a simple NameValue association with a quick lookup function (via a\n * hash map) the default behavior for this class is not thread safe.\n * specify a constructor with boolean true to make this thread safe.\n *\n * @version 1.2\n *\n * @author M. Ranganathan <br/>\n *\n *\n *\n */\n\npublic class NameValueList implements Serializable, Cloneable, Map<String,NameValue> {\n\n\n    private static final long serialVersionUID = -6998271876574260243L;\n\n    private Map<String,NameValue> hmap;\n\n    private String separator;\n\n    /**\n     * default constructor.\n     */\n    public NameValueList() {\n        this.separator = \";\";\n        this.hmap = new LinkedHashMap<String,NameValue>();\n    }\n\n    public NameValueList(boolean sync) {\n        this.separator = \";\";\n        if (sync)\n            this.hmap = new ConcurrentHashMap<String,NameValue>();\n        else\n            this.hmap = new LinkedHashMap<String,NameValue>();\n    }\n\n    public void setSeparator(String separator) {\n        this.separator = separator;\n    }\n\n    /**\n     * Encode the list in semicolon separated form.\n     *\n     * @return an encoded string containing the objects in this list.\n     * @since v1.0\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (!hmap.isEmpty()) {\n            Iterator<NameValue> iterator = hmap.values().iterator();\n            if (iterator.hasNext()) {\n                while (true) {\n                    Object obj = iterator.next();\n                    if (obj instanceof GenericObject) {\n                        GenericObject gobj = (GenericObject) obj;\n                        gobj.encode(buffer);\n                    } else {\n                        buffer.append(obj.toString());\n                    }\n                    if (iterator.hasNext())\n                        buffer.append(separator);\n                    else\n                        break;\n                }\n            }\n        }\n        return buffer;\n    }\n\n    public String toString() {\n        return this.encode();\n    }\n\n    /**\n     * Set a namevalue object in this list.\n     */\n\n    public void set(NameValue nv) {\n        this.hmap.put(nv.getName().toLowerCase(), nv);\n    }\n\n    /**\n     * Set a namevalue object in this list.\n     */\n    public void set(String name, Object value) {\n        NameValue nameValue = new NameValue(name, value);\n        hmap.put(name.toLowerCase(), nameValue);\n\n    }\n\n    /**\n     * Compare if two NameValue lists are equal.\n     *\n     * @param otherObject\n     *            is the object to compare to.\n     * @return true if the two objects compare for equality.\n     */\n    public boolean equals(Object otherObject) {\n        if ( otherObject == null ) {\n            return false;\n        }\n        if (!otherObject.getClass().equals(this.getClass())) {\n            return false;\n        }\n        NameValueList other = (NameValueList) otherObject;\n\n        if (hmap.size() != other.hmap.size()) {\n            return false;\n        }\n        Iterator<String> li = this.hmap.keySet().iterator();\n\n        while (li.hasNext()) {\n            String key = (String) li.next();\n            NameValue nv1 = this.getNameValue(key);\n            NameValue nv2 = (NameValue) other.hmap.get(key);\n            if (nv2 == null)\n                return false;\n            else if (!nv2.equals(nv1))\n                return false;\n        }\n        return true;\n    }\n\n    /**\n     * Do a lookup on a given name and return value associated with it.\n     */\n    public Object getValue(String name) {\n        NameValue nv = this.getNameValue(name.toLowerCase());\n        if (nv != null)\n            return nv.getValueAsObject();\n        else\n            return null;\n    }\n\n    /**\n     * Get the NameValue record given a name.\n     *\n     * @since 1.0\n     */\n    public NameValue getNameValue(String name) {\n        return (NameValue) this.hmap.get(name.toLowerCase());\n    }\n\n    /**\n     * Returns a boolean telling if this NameValueList has a record with this\n     * name\n     *\n     * @since 1.0\n     */\n    public boolean hasNameValue(String name) {\n        return hmap.containsKey(name.toLowerCase());\n    }\n\n    /**\n     * Remove the element corresponding to this name.\n     *\n     * @since 1.0\n     */\n    public boolean delete(String name) {\n        String lcName = name.toLowerCase();\n        if (this.hmap.containsKey(lcName)) {\n            this.hmap.remove(lcName);\n            return true;\n        } else {\n            return false;\n        }\n\n    }\n\n    public Object clone() {\n        NameValueList retval = new NameValueList();\n        retval.setSeparator(this.separator);\n        Iterator<NameValue> it = this.hmap.values().iterator();\n        while (it.hasNext()) {\n            retval.set((NameValue) ((NameValue) it.next()).clone());\n        }\n        return retval;\n    }\n\n    /**\n     * Return the size of the embedded map\n     */\n    public int size() {\n        return this.hmap.size();\n    }\n\n    /**\n     * Return true if empty.\n     */\n    public boolean isEmpty() {\n        return hmap.isEmpty();\n    }\n\n    /**\n     * Return an iterator for the name-value pairs of this list.\n     *\n     * @return the iterator.\n     */\n    public Iterator<NameValue> iterator() {\n        return this.hmap.values().iterator();\n    }\n\n    /**\n     * Get a list of parameter names.\n     *\n     * @return a list iterator that has the names of the parameters.\n     */\n    public Iterator<String> getNames() {\n        return this.hmap.keySet().iterator();\n\n    }\n\n    /**\n     * Get the parameter as a String.\n     *\n     * @return the parameter as a string.\n     */\n    public String getParameter(String name) {\n        Object val = this.getValue(name);\n        if (val == null)\n            return null;\n        if (val instanceof GenericObject)\n            return ((GenericObject) val).encode();\n        else\n            return val.toString();\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#clear()\n     */\n\n    public void clear() {\n        this.hmap.clear();\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#containsKey(java.lang.Object)\n     */\n    public boolean containsKey(Object key) {\n        return this.hmap.containsKey(key.toString().toLowerCase());\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#containsValue(java.lang.Object)\n     */\n    public boolean containsValue(Object value) {\n        return this.hmap.containsValue(value);\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#entrySet()\n     */\n    public Set<java.util.Map.Entry<String, NameValue>> entrySet() {\n        return this.hmap.entrySet();\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#get(java.lang.Object)\n     */\n    public NameValue get(Object key) {\n        return this.hmap.get(key.toString().toLowerCase());\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#keySet()\n     */\n    public Set<String> keySet() {\n        return this.hmap.keySet();\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#put(java.lang.Object, java.lang.Object)\n     */\n    public NameValue put(String name, NameValue nameValue) {\n        return this.hmap.put(name, nameValue);\n    }\n\n    public void putAll(Map<? extends String, ? extends NameValue> map) {\n        this.hmap.putAll(map);\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#remove(java.lang.Object)\n     */\n    public NameValue remove(Object key) {\n        return this.hmap.remove(key.toString().toLowerCase());\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see java.util.Map#values()\n     */\n    public Collection<NameValue> values() {\n        return this.hmap.values();\n    }\n    \n    @Override\n    public int hashCode() {\n        return this.hmap.keySet().hashCode();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/PackageNames.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.core;\n/**\n* Names for the packages that are referenced herein.\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\n\npublic interface PackageNames {\n    public static final String JAIN_HEADER_PACKAGE = \"javax2.sip.header\";\n    public static final String JAIN_PACKAGE = \"javax2.sip\";\n    public static final String SIPHEADERS_PACKAGE = \"gov2.nist.javax2.sip.header\";\n    public static final String PARSER_PACKAGE = \"gov2.nist.javax2.sip.parser\";\n    public static final String NET_PACKAGE = \"gov2.nist.javax2.sip.address\";\n    public static final String SIP_PACKAGE = \"gov2.nist.javax2.sip\";\n    public static final String STACK_PACKAGE = \"gov2.nist.javax2.sip.stack\";\n    public static final String CORE_PACKAGE = \"gov2.nist.core\";\n    public static final String MESSAGE_PACKAGE = \"gov2.nist.javax2.sip.message\";\n\n    // SDP packages\n    public static final String SDP_PACKAGE = \"gov2.nist.javax2.sdp\";\n    public static final String SDP_PARSER_PACKAGE = SDP_PACKAGE + \".parser\";\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/ParserCore.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core;\n\nimport java.text.ParseException;\n\n/** Generic parser class.\n* All parsers inherit this class.\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\npublic abstract class ParserCore {\n    public static final boolean debug = Debug.parserDebug;\n\n    static int nesting_level;\n\n    protected LexerCore lexer;\n\n\n    protected NameValue nameValue(char separator) throws ParseException  {\n        if (debug) dbg_enter(\"nameValue\");\n        try {\n\n        lexer.match(LexerCore.ID);\n        Token name = lexer.getNextToken();\n        // eat white space.\n        lexer.SPorHT();\n        try {\n\n\n                boolean quoted = false;\n\n            char la = lexer.lookAhead(0);\n\n            if (la == separator ) {\n                lexer.consume(1);\n                lexer.SPorHT();\n                String str = null;\n                boolean isFlag = false;\n                if (lexer.lookAhead(0) == '\\\"')  {\n                     str = lexer.quotedString();\n                     quoted = true;\n                } else {\n                   lexer.match(LexerCore.ID);\n                   Token value = lexer.getNextToken();\n                   str = value.tokenValue;\n\n                   // JvB: flag parameters must be empty string!\n                   if (str==null) {\n                       str = \"\";\n                       isFlag = true;\n                   }\n                }\n                NameValue nv = new NameValue(name.tokenValue,str,isFlag);\n                if (quoted) nv.setQuotedValue();\n                return nv;\n            }  else {\n                // JvB: flag parameters must be empty string!\n                return new NameValue(name.tokenValue,\"\",true);\n            }\n        } catch (ParseException ex) {\n            return new NameValue(name.tokenValue,null,false);\n        }\n\n        } finally {\n            if (debug) dbg_leave(\"nameValue\");\n        }\n\n\n    }\n\n    protected  void dbg_enter(String rule) {\n        StringBuffer stringBuffer = new StringBuffer();\n        for (int i = 0; i < nesting_level ; i++)\n            stringBuffer.append(\">\");\n\n        if (debug)  {\n            System.out.println(\n                stringBuffer + rule +\n                \"\\nlexer buffer = \\n\" +\n                lexer.getRest());\n        }\n        nesting_level++;\n    }\n\n    protected void dbg_leave(String rule) {\n        StringBuffer stringBuffer = new StringBuffer();\n        for (int i = 0; i < nesting_level ; i++)\n            stringBuffer.append(\"<\");\n\n        if (debug)  {\n            System.out.println(\n                stringBuffer +\n                rule +\n                \"\\nlexer buffer = \\n\" +\n                lexer.getRest());\n        }\n        nesting_level --;\n    }\n\n    protected NameValue nameValue() throws ParseException  {\n        return nameValue('=');\n    }\n\n\n\n    protected void peekLine(String rule) {\n        if (debug) {\n            Debug.println(rule +\" \" + lexer.peekLine());\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/Separators.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core;\n\n/** Separators.\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\npublic interface Separators {\n    public static final String SEMICOLON = \";\";\n    public static final String COLON = \":\";\n    public static final String COMMA = \",\";\n    public static final String SLASH = \"/\";\n    public static final String SP = \" \";\n    public static final String EQUALS = \"=\";\n    public static final String STAR = \"*\";\n    public static final String NEWLINE = \"\\r\\n\";\n    public static final String RETURN = \"\\n\";\n    public static final String LESS_THAN = \"<\";\n    public static final String GREATER_THAN = \">\";\n    public static final String AT = \"@\";\n    public static final String DOT = \".\";\n    public static final String QUESTION = \"?\";\n    public static final String POUND = \"#\";\n    public static final String AND = \"&\";\n    public static final String LPAREN = \"(\";\n    public static final String RPAREN = \")\";\n    public static final String DOUBLE_QUOTE = \"\\\"\";\n    public static final String QUOTE = \"\\'\";\n    public static final String HT = \"\\t\";\n    public static final String PERCENT = \"%\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/ServerLogger.java",
    "content": "/*\n * JBoss, Home of Professional Open Source.\n * \n * This code has been contributed to the public domain.\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.core;\n\nimport java.util.Properties;\n\nimport javax2.sip.SipStack;\n\nimport gov2.nist.javax2.sip.message.SIPMessage;\n\n/**\n * @author jean.deruelle@gmail.com\n *\n */\npublic interface ServerLogger extends LogLevels {\n\t\n   \n\t void closeLogFile();\n\t \n\t void logMessage(SIPMessage message, String from, String to, boolean sender, long time);\n\t \n\t void logMessage(SIPMessage message, String from, String to, String status,\n\t            boolean sender, long time);\n\t \n\t void logMessage(SIPMessage message, String from, String to, String status,\n\t            boolean sender);\n\t            \t\n\t void logException(Exception ex);\n\t \n\t public void setStackProperties(Properties stackProperties);\n\t \n\t public void setSipStack(SipStack sipStack);\n\t \n\t\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/StackLogger.java",
    "content": "package gov2.nist.core;\n\nimport java.util.Properties;\n\n\n/**\n * interface that loggers should implement so that the stack can log to various\n * loggers impl such as log4j, commons logging, sl4j, ...\n * @author jean.deruelle@gmail.com\n *\n */\npublic interface StackLogger extends LogLevels {\n\n    /**\n     * log a stack trace. This helps to look at the stack frame.\n     */\n\tpublic void logStackTrace();\n\t\n\t/**\n\t * Log a stack trace if the current logging level exceeds \n\t * given trace level.\n\t * @param traceLevel\n\t */\n\tpublic void logStackTrace(int traceLevel);\n\t\n\t/**\n     * Get the line count in the log stream.\n     *\n     * @return\n     */\n\tpublic int getLineCount();\n\t\n\t/**\n     * Log an exception.\n     *\n     * @param ex\n     */\n    public void logException(Throwable ex);\n    /**\n     * Log a message into the log file.\n     *\n     * @param message\n     *            message to log into the log file.\n     */\n    public void logDebug(String message);\n    /**\n     * Log a message into the log file.\n     *\n     * @param message\n     *            message to log into the log file.\n     */\n    public void logTrace(String message);\n    /**\n     * Log an error message.\n     *\n     * @param message --\n     *            error message to log.\n     */\n    public void logFatalError(String message);\n    /**\n     * Log an error message.\n     *\n     * @param message --\n     *            error message to log.\n     *\n     */\n    public void logError(String message);\n    /**\n     * @return flag to indicate if logging is enabled.\n     */\n    public boolean isLoggingEnabled();\n    /**\n     * Return true/false if loging is enabled at a given level.\n     *\n     * @param logLevel\n     */\n    public boolean isLoggingEnabled(int logLevel);\n    /**\n     * Log an error message.\n     *\n     * @param message\n     * @param ex\n     */\n    public void logError(String message, Exception ex);\n    /**\n     * Log a warning mesasge.\n     *\n     * @param string\n     */\n    public void logWarning(String string);\n    /**\n     * Log an info message.\n     *\n     * @param string\n     */\n    public void logInfo(String string);\n    \n   \n    /**\n     * Disable logging altogether.\n     *\n     */\n    public void disableLogging();\n\n    /**\n     * Enable logging (globally).\n     */\n    public void enableLogging();\n    \n    /**\n     * Set the build time stamp. This is logged into the logging stream.\n     */\n    public void setBuildTimeStamp(String buildTimeStamp);\n    \n    /**\n     * Stack creation properties.\n     * @param stackProperties\n     */\n    \n    public void setStackProperties(Properties stackProperties);\n    \n    /**\n     * The category for the logger.\n     * @return\n     */\n    public String getLoggerName();\n    \n    \n   \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/StringTokenizer.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core;\n\nimport java.util.*;\nimport java.text.ParseException;\n\n/** Base string token splitter.\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\n\npublic class StringTokenizer {\n\n    protected String buffer;\n    protected int bufferLen;\n    protected int ptr;\n    protected int savedPtr;\n\n    protected StringTokenizer() {\n    }\n\n    public StringTokenizer(String buffer) {\n        this.buffer = buffer;\n        bufferLen = buffer.length();\n        ptr = 0;\n    }\n\n    public String nextToken() {\n        int startIdx = ptr;\n\n        while (ptr < bufferLen) {\n            char c = buffer.charAt(ptr);\n            ptr++;\n            if (c == '\\n') {\n                break;\n            }\n        }\n\n        return buffer.substring(startIdx, ptr);\n    }\n\n    public boolean hasMoreChars() {\n        return ptr < bufferLen;\n    }\n\n    public static boolean isHexDigit(char ch) {\n        return (ch >= 'A' && ch <= 'F') ||\n               (ch >= 'a' && ch <= 'f') ||\n               isDigit(ch);\n    }\n\n    public static boolean isAlpha(char ch) {\n        if (ch <= 127) {\n            return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));\n        }\n        else {\n            return Character.isLowerCase(ch) || Character.isUpperCase(ch);\n        }\n    }\n\n    public static boolean isDigit(char ch) {\n        if (ch <= 127) {\n            return (ch <= '9' && ch >= '0');\n        }\n        else {\n            return Character.isDigit(ch);\n        }\n    }\n\n    public static boolean isAlphaDigit(char ch) {\n        if (ch <= 127) {\n            return (ch >= 'a' && ch <= 'z') ||\n                (ch >= 'A' && ch <= 'Z') ||\n                (ch <= '9' && ch >= '0');\n        }\n        else {\n            return Character.isLowerCase(ch) ||\n                Character.isUpperCase(ch) ||\n                Character.isDigit(ch);\n        }\n    }\n\n    public String getLine() {\n        int startIdx = ptr;\n        while (ptr < bufferLen && buffer.charAt(ptr) != '\\n') {\n            ptr++;\n        }\n        if (ptr < bufferLen && buffer.charAt(ptr) == '\\n') {\n            ptr++;\n        }\n        return buffer.substring(startIdx, ptr);\n    }\n\n    public String peekLine() {\n        int curPos = ptr;\n        String retval = this.getLine();\n        ptr = curPos;\n        return retval;\n    }\n\n    public char lookAhead() throws ParseException {\n        return lookAhead(0);\n    }\n\n    public char lookAhead(int k) throws ParseException {\n        // Debug.out.println(\"ptr = \" + ptr);\n        try {\n            return buffer.charAt(ptr + k);\n        }\n        catch (IndexOutOfBoundsException e) {\n            return '\\0';\n        }\n    }\n\n    public char getNextChar() throws ParseException {\n        if (ptr >= bufferLen)\n            throw new ParseException(\n                buffer + \" getNextChar: End of buffer\",\n                ptr);\n        else\n            return buffer.charAt(ptr++);\n    }\n\n    public void consume() {\n        ptr = savedPtr;\n    }\n\n    public void consume(int k) {\n        ptr += k;\n    }\n\n    /** Get a Vector of the buffer tokenized by lines\n     */\n    public Vector<String> getLines() {\n        Vector<String> result = new Vector<String>();\n        while (hasMoreChars()) {\n            String line = getLine();\n            result.addElement(line);\n        }\n        return result;\n    }\n\n    /** Get the next token from the buffer.\n    */\n    public String getNextToken(char delim) throws ParseException {\n        int startIdx = ptr;\n        while (true) {\n            char la = lookAhead(0);\n            if (la == delim)\n                break;\n            else if (la == '\\0')\n                throw new ParseException(\"EOL reached\", 0);\n            consume(1);\n        }\n        return buffer.substring(startIdx, ptr);\n    }\n\n    /** get the SDP field name of the line\n     *  @return String\n     */\n    public static String getSDPFieldName(String line) {\n        if (line == null)\n            return null;\n        String fieldName = null;\n        try {\n            int begin = line.indexOf(\"=\");\n            fieldName = line.substring(0, begin);\n        } catch (IndexOutOfBoundsException e) {\n            return null;\n        }\n        return fieldName;\n    }\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/ThreadAuditor.java",
    "content": "package gov2.nist.core;\n\nimport java.util.*;\n\n/**\n * Thread Auditor class:\n *   - Provides a mechanism for applications to check the health of internal threads\n *   - The mechanism is fairly simple:\n *   - Threads register with the auditor at startup and \"ping\" the auditor every so often.\n *   - The application queries the auditor about the health of the system periodically. The\n *     auditor reports if the threads are healthy or if any of them failed to ping and are\n *     considered dead or stuck.\n *   - The main implication for the monitored threads is that they can no longer block\n *     waiting for an event forever. Any wait() must be implemented with a timeout so that\n *     the thread can periodically ping the auditor.\n *\n * This code is in the public domain.\n *\n * @author R. Borba (Natural Convergence)   <br/>\n * @version 1.2\n */\n\npublic class ThreadAuditor {\n    /// Threads being monitored\n    private Map<Thread,ThreadHandle> threadHandles = new HashMap<Thread,ThreadHandle>();\n\n    /// How often are threads supposed to ping\n    private long pingIntervalInMillisecs = 0;\n\n    /// Internal class, used as a handle by the monitored threads\n    public class ThreadHandle {\n        /// Set to true when the thread pings, periodically reset to false by the auditor\n        private boolean isThreadActive;\n\n        /// Thread being monitored\n        private Thread thread;\n\n        /// Thread auditor monitoring this thread\n        private ThreadAuditor threadAuditor;\n\n        /// Constructor\n        public ThreadHandle(ThreadAuditor aThreadAuditor) {\n            isThreadActive = false;\n            thread = Thread.currentThread();\n            threadAuditor = aThreadAuditor;\n        }\n\n        /// Called by the auditor thread to check the ping status of the thread\n        public boolean isThreadActive() {\n            return isThreadActive;\n        }\n\n        /// Called by the auditor thread to reset the ping status of the thread\n        protected void setThreadActive(boolean value) {\n            isThreadActive = value;\n        }\n\n        /// Return the thread being monitored\n        public Thread getThread() {\n            return thread;\n        }\n\n        // Helper function to allow threads to ping using this handle\n        public void ping() {\n            threadAuditor.ping(this);\n        }\n\n        // Helper function to allow threads to get the ping interval directly from this handle\n        public long getPingIntervalInMillisecs() {\n            return threadAuditor.getPingIntervalInMillisecs();\n        }\n\n        /**\n         * Returns a string representation of the object\n         *\n         * @return a string representation of the object\n         */\n        public String toString() {\n            StringBuffer toString = new StringBuffer()\n                    .append(\"Thread Name: \").append(thread.getName())\n                    .append(\", Alive: \").append(thread.isAlive());\n            return toString.toString();\n        }\n    }\n\n    /// Indicates how often monitored threads are supposed to ping (0 = no thread monitoring)\n    public long getPingIntervalInMillisecs() {\n        return pingIntervalInMillisecs;\n    }\n\n    /// Defines how often monitored threads are supposed to ping\n    public void setPingIntervalInMillisecs(long value) {\n        pingIntervalInMillisecs = value;\n    }\n\n    /// Indicates if the auditing of threads is enabled\n    public boolean isEnabled() {\n        return (pingIntervalInMillisecs > 0);\n    }\n\n    /// Called by a thread that wants to be monitored\n    public synchronized ThreadHandle addCurrentThread() {\n        // Create and return a thread handle but only add it\n        // to the list of monitored threads if the auditor is enabled\n        ThreadHandle threadHandle = new ThreadHandle(this);\n        if (isEnabled()) {\n            threadHandles.put(Thread.currentThread(), threadHandle);\n        }\n        return threadHandle;\n    }\n\n    /// Stops monitoring a given thread\n    public synchronized void removeThread(Thread thread) {\n        threadHandles.remove(thread);\n    }\n\n    /// Called by a monitored thread reporting that it's alive and well\n    public synchronized void ping(ThreadHandle threadHandle) {\n        threadHandle.setThreadActive(true);\n    }\n\n    /// Resets the auditor\n    public synchronized void reset() {\n        threadHandles.clear();\n    }\n\n    /**\n     * Audits the sanity of all threads\n     *\n     * @return An audit report string (multiple lines), or null if all is well\n     */\n    public synchronized String auditThreads() {\n        String auditReport = null;\n        // Map stackTraces = null;\n\n        // Scan all monitored threads looking for non-responsive ones\n        Iterator<ThreadHandle> it = threadHandles.values().iterator();\n        while (it.hasNext()) {\n            ThreadHandle threadHandle = (ThreadHandle) it.next();\n            if (!threadHandle.isThreadActive()) {\n                // Get the non-responsive thread\n                Thread thread = threadHandle.getThread();\n\n                // Update the audit report\n                if (auditReport == null) {\n                    auditReport = \"Thread Auditor Report:\\n\";\n                }\n                auditReport += \"   Thread [\" + thread.getName() + \"] has failed to respond to an audit request.\\n\";\n\n                /*\n                 * Stack traces are not available with JDK 1.4.\n                 * Feel free to uncomment this block to get a better report if you're using JDK 1.5.\n                 */\n                //  // Get stack traces for all live threads (do this only once per audit)\n                //  if (stackTraces == null) {\n                //      stackTraces = Thread.getAllStackTraces();\n                //  }\n                //\n                //  // Get the stack trace for the non-responsive thread\n                //  StackTraceElement[] stackTraceElements = (StackTraceElement[])stackTraces.get(thread);\n                //  if (stackTraceElements != null && stackTraceElements.length > 0) {\n                //      auditReport += \"      Stack trace:\\n\";\n                //\n                //      for (int i = 0; i < stackTraceElements.length ; i ++ ) {\n                //          StackTraceElement stackTraceElement = stackTraceElements[i];\n                //          auditReport += \"         \" + stackTraceElement.toString() + \"\\n\";\n                //      }\n                //  } else {\n                //      auditReport += \"      Stack trace is not available.\\n\";\n                //  }\n            }\n\n            // Reset the ping status of the thread\n            threadHandle.setThreadActive(false);\n        }\n        return auditReport;\n    }\n\n    /**\n     * Returns a string representation of the object\n     *\n     * @return a string representation of the object\n     */\n    public synchronized String toString() {\n        String toString = \"Thread Auditor - List of monitored threads:\\n\";\n        Iterator<ThreadHandle> it = threadHandles.values().iterator();\n        while ( it.hasNext()) {\n            ThreadHandle threadHandle = (ThreadHandle)it.next();\n            toString += \"   \" + threadHandle.toString() + \"\\n\";\n        }\n        return toString;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/Token.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core;\n\n/**\n * Base token class.\n * @version 1.2\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\n\npublic class Token {\n    protected String tokenValue;\n    protected int tokenType;\n    public String getTokenValue() {\n        return this.tokenValue;\n    }\n    public int getTokenType() {\n        return this.tokenType;\n    }\n    public String toString() {\n        return \"tokenValue = \" + tokenValue + \"/tokenType = \" + tokenType;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/net/AddressResolver.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core.net;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport javax2.sip.address.Hop;\n\n/**\n * An interface that allows you to customize address lookup.\n * The user can implement this interface to do DNS lookups or other lookup\n * schemes and register it with the stack.\n * The default implementation of the address resolver does nothing more than just return back\n * the Hop that it was passed (fixing up the port if necessary).\n * However, this behavior can be overriden. To override\n * implement this interface and register it with the stack using\n * {@link gov2.nist.javax2.sip.SipStackExt#setAddressResolver(AddressResolver)}.\n * This interface will be incorporated into version 2.0 of the JAIN-SIP Specification.\n *\n * @since 2.0\n *\n *\n * @author M. Ranganathan\n *\n */\npublic interface AddressResolver {\n\n    /**\n     * Do a name lookup and resolve the given IP address.\n     * The default implementation is just an identity mapping\n     * (returns the argument).\n     *\n     * @param hop - an incoming Hop containing a potenitally unresolved address.\n     * @return a new hop ( if the address is recomputed ) or the original hop\n     * if this is just an identity mapping ( the default behavior ).\n     */\n    public Hop resolveAddress( Hop hop);\n\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/net/DefaultNetworkLayer.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core.net;\n\nimport java.io.IOException;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.MulticastSocket;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketException;\n\n/* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.SSLServerSocket;\nimport javax.net.ssl.SSLServerSocketFactory;\n\n/**\n * default implementation which passes straight through to java platform\n *\n * @author m.andrews\n * @version 1.2\n * @since 1.1\n *\n */\npublic class DefaultNetworkLayer implements NetworkLayer {\n\n    private SSLSocketFactory sslSocketFactory;\n\n    private SSLServerSocketFactory sslServerSocketFactory;\n\n    /**\n     * single default network layer; for flexibility, it may be better not to\n     * make it a singleton, but singleton seems to make sense currently.\n     */\n    public static final DefaultNetworkLayer SINGLETON = new DefaultNetworkLayer();\n\n    private DefaultNetworkLayer() {\n        sslServerSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory\n                .getDefault();\n        sslSocketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();\n    }\n\n    public ServerSocket createServerSocket(int port, int backlog,\n            InetAddress bindAddress) throws IOException {\n        return new ServerSocket(port, backlog, bindAddress);\n    }\n\n    public Socket createSocket(InetAddress address, int port)\n            throws IOException {\n        return new Socket(address, port);\n    }\n\n    public DatagramSocket createDatagramSocket() throws SocketException {\n        return new DatagramSocket();\n    }\n\n    public DatagramSocket createDatagramSocket(int port, InetAddress laddr)\n            throws SocketException {\n\n        if ( laddr.isMulticastAddress() ) {\n            try {\n                MulticastSocket ds = new MulticastSocket( port );\n                ds.joinGroup( laddr );\n                return ds;\n            } catch (IOException e) {\n                throw new SocketException( e.getLocalizedMessage() );\n            }\n        } else return new DatagramSocket(port, laddr);\n    }\n\n    /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\n    public SSLServerSocket createSSLServerSocket(int port, int backlog,\n            InetAddress bindAddress) throws IOException {\n        return (SSLServerSocket) sslServerSocketFactory.createServerSocket(\n                port, backlog, bindAddress);\n    }\n\n    /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\n    public SSLSocket createSSLSocket(InetAddress address, int port)\n            throws IOException {\n        return (SSLSocket) sslSocketFactory.createSocket(address, port);\n    }\n\n    /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\n    public SSLSocket createSSLSocket(InetAddress address, int port,\n            InetAddress myAddress) throws IOException {\n        return (SSLSocket) sslSocketFactory.createSocket(address, port,\n                myAddress, 0);\n    }\n\n    public Socket createSocket(InetAddress address, int port,\n            InetAddress myAddress) throws IOException {\n        if (myAddress != null)\n            return new Socket(address, port, myAddress, 0);\n        else\n            return new Socket(address, port);\n    }\n\n    /**\n     * Creates a new Socket, binds it to myAddress:myPort and connects it to\n     * address:port.\n     *\n     * @param address the InetAddress that we'd like to connect to.\n     * @param port the port that we'd like to connect to\n     * @param myAddress the address that we are supposed to bind on or null\n     *        for the \"any\" address.\n     * @param myPort the port that we are supposed to bind on or 0 for a random\n     * one.\n     *\n     * @return a new Socket, bound on myAddress:myPort and connected to\n     * address:port.\n     * @throws IOException if binding or connecting the socket fail for a reason\n     * (exception relayed from the correspoonding Socket methods)\n     */\n    public Socket createSocket(InetAddress address, int port,\n                    InetAddress myAddress, int myPort)\n        throws IOException\n    {\n        if (myAddress != null)\n            return new Socket(address, port, myAddress, myPort);\n        else if (port != 0)\n        {\n            //myAddress is null (i.e. any)  but we have a port number\n            Socket sock = new Socket();\n            sock.bind(new InetSocketAddress(port));\n            sock.connect(new InetSocketAddress(address, port));\n            return sock;\n        }\n        else\n            return new Socket(address, port);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/net/NetworkLayer.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core.net;\n\nimport java.io.IOException;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketException;\n\n// Added by Daniel J. Martinez Manzano <dani@dif.um.es>\nimport javax.net.ssl.SSLServerSocket;\nimport javax.net.ssl.SSLSocket;\n\n\n/**\n * basic interface to the network layer\n *\n * @author m.andrews\n *\n */\npublic interface NetworkLayer {\n\n    /**\n     * Creates a server with the specified port, listen backlog, and local IP address to bind to.\n     * comparable to \"new java.net.ServerSocket(port,backlog,bindAddress);\"\n     *\n     * @param port\n     * @param backlog\n     * @param bindAddress\n     * @return the server socket\n     */\n    public ServerSocket createServerSocket(int port, int backlog,\n            InetAddress bindAddress) throws IOException;\n\n    /**\n     * Creates an SSL server with the specified port, listen backlog, and local IP address to bind to.\n     * Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n     *\n     * @param port\n     * @param backlog\n     * @param bindAddress\n     * @return the server socket\n     */\n    public SSLServerSocket createSSLServerSocket(int port, int backlog,\n            InetAddress bindAddress) throws IOException;\n\n    /**\n     * Creates a stream socket and connects it to the specified port number at the specified IP address.\n     * comparable to \"new java.net.Socket(address, port);\"\n     *\n     * @param address\n     * @param port\n     * @return the socket\n     */\n    public Socket createSocket(InetAddress address, int port) throws IOException;\n\n    /**\n     * Creates a stream socket and connects it to the specified port number at the specified IP address.\n     * comparable to \"new java.net.Socket(address, port,localaddress);\"\n     *\n     * @param address\n     * @param port\n     * @param localAddress\n     * @return the socket\n     */\n    public Socket createSocket(InetAddress address, int port, InetAddress localAddress) throws IOException;\n\n    /**\n     * Creates a new Socket, binds it to myAddress:myPort and connects it to\n     * address:port.\n     *\n     * @param address the InetAddress that we'd like to connect to.\n     * @param port the port that we'd like to connect to\n     * @param myAddress the address that we are supposed to bind on or null\n     *        for the \"any\" address.\n     * @param myPort the port that we are supposed to bind on or 0 for a random\n     * one.\n     *\n     * @return a new Socket, bound on myAddress:myPort and connected to\n     * address:port.\n     * @throws IOException if binding or connecting the socket fail for a reason\n     * (exception relayed from the correspoonding Socket methods)\n     */\n    public Socket createSocket(InetAddress address, int port,\n                    InetAddress myAddress, int myPort)\n        throws IOException;\n\n    /**\n     * Creates a stream SSL socket and connects it to the specified port number at the specified IP address.\n     * Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n     *\n     * @param address\n     * @param port\n     * @return the socket\n     */\n    public SSLSocket createSSLSocket(InetAddress address, int port) throws IOException;\n\n    /**\n     * Creates a stream SSL socket and connects it to the specified port number at the specified IP address.\n     * Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n     *\n     * @param address\n     * @param port\n     * @param localAddress -- my address.\n     * @return the socket\n     */\n    public SSLSocket createSSLSocket(InetAddress address, int port, InetAddress localAddress) throws IOException;\n\n    /**\n     * Constructs a datagram socket and binds it to any available port on the local host machine.\n     * comparable to \"new java.net.DatagramSocket();\"\n     *\n     * @return the datagram socket\n     */\n    public DatagramSocket createDatagramSocket() throws SocketException;\n\n    /**\n     * Creates a datagram socket, bound to the specified local address.\n     * comparable to \"new java.net.DatagramSocket(port,laddr);\"\n     *\n     * @param port\n     * @param laddr\n     * @return the datagram socket\n     */\n    public DatagramSocket createDatagramSocket(int port, InetAddress laddr)\n            throws SocketException;\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/core/net/SslNetworkLayer.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.core.net;\n\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore;\nimport java.security.SecureRandom;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLServerSocket;\nimport javax.net.ssl.SSLServerSocketFactory;\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManagerFactory;\n\n/**\n * extended implementation of a network layer that allows to define a private java\n * keystores/truststores\n *\n * @author f.reif\n * @version 1.2\n * @since 1.2\n *\n */\npublic class SslNetworkLayer implements NetworkLayer {\n\n    private SSLSocketFactory sslSocketFactory;\n\n    private SSLServerSocketFactory sslServerSocketFactory;\n\n    public SslNetworkLayer() throws IOException, GeneralSecurityException {\n    \t        this(null, null, null, null);\n    }\n    \n\tpublic SslNetworkLayer(String trustStoreFile, String keyStoreFile,\n\t\t\tchar[] keyStorePassword, String keyStoreType)\n\t\t\tthrows GeneralSecurityException, FileNotFoundException, IOException {\n\t\tSSLContext sslContext;\n\t\tsslContext = SSLContext.getInstance(\"TLS\");\n\t\tString algorithm = KeyManagerFactory.getDefaultAlgorithm();\n\t\tTrustManagerFactory tmFactory = TrustManagerFactory\n\t\t\t\t.getInstance(algorithm);\n\t\tSecureRandom secureRandom = new SecureRandom();\n\t\tsecureRandom.nextInt();\n\t\tKeyManagerFactory kmFactory = null;\n\t\tKeyStore keyStore = null;\n\t\tKeyStore trustStore = null;\n\t\tKeyManager[] km = null;\n\t\tif (keyStoreFile != null) {\n\t\t\t// use specific keystore with own certificate\n\t\t\ttrustStore = KeyStore.getInstance(keyStoreType);\n\t\t\ttrustStore.load(new FileInputStream(trustStoreFile),\n\t\t\t\t\tkeyStorePassword);\n\t\t\ttmFactory.init(trustStore);\n\n\t\t\tkeyStore = KeyStore.getInstance(keyStoreType);\n\t\t\tkeyStore.load(new FileInputStream(keyStoreFile), keyStorePassword);\n\n\t\t\tkmFactory = KeyManagerFactory.getInstance(algorithm);\n\t\t\tkmFactory.init(keyStore, keyStorePassword);\n\n\t\t\tkm = kmFactory.getKeyManagers();\n\t\t} else {\n\t\t\t// use default keystore with built-in certificates\n\t\t\ttmFactory.init((KeyStore) null);\n\t\t}\n\t\tsslContext.init(km, tmFactory.getTrustManagers(), secureRandom);\n\t\tsslServerSocketFactory = sslContext.getServerSocketFactory();\n\t\tsslSocketFactory = sslContext.getSocketFactory();\n\t}\n\n    public ServerSocket createServerSocket(int port, int backlog,\n            InetAddress bindAddress) throws IOException {\n        return new ServerSocket(port, backlog, bindAddress);\n    }\n\n    public Socket createSocket(InetAddress address, int port)\n            throws IOException {\n        return new Socket(address, port);\n    }\n\n    public DatagramSocket createDatagramSocket() throws SocketException {\n        return new DatagramSocket();\n    }\n\n    public DatagramSocket createDatagramSocket(int port, InetAddress laddr)\n            throws SocketException {\n        return new DatagramSocket(port, laddr);\n    }\n\n    /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\n    public SSLServerSocket createSSLServerSocket(int port, int backlog,\n            InetAddress bindAddress) throws IOException {\n        return (SSLServerSocket) sslServerSocketFactory.createServerSocket(\n                port, backlog, bindAddress);\n    }\n\n    /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\n    public SSLSocket createSSLSocket(InetAddress address, int port)\n            throws IOException {\n        return (SSLSocket) sslSocketFactory.createSocket(address, port);\n    }\n\n    /* Added by Daniel J. Martinez Manzano <dani@dif.um.es> */\n    public SSLSocket createSSLSocket(InetAddress address, int port,\n            InetAddress myAddress) throws IOException {\n        return (SSLSocket) sslSocketFactory.createSocket(address, port,\n                myAddress, 0);\n    }\n\n    public Socket createSocket(InetAddress address, int port,\n            InetAddress myAddress) throws IOException {\n        if (myAddress != null)\n            return new Socket(address, port, myAddress, 0);\n        else\n            return new Socket(address, port);\n    }\n\n    /**\n     * Creates a new Socket, binds it to myAddress:myPort and connects it to\n     * address:port.\n     *\n     * @param address the InetAddress that we'd like to connect to.\n     * @param port the port that we'd like to connect to\n     * @param myAddress the address that we are supposed to bind on or null\n     *        for the \"any\" address.\n     * @param myPort the port that we are supposed to bind on or 0 for a random\n     * one.\n     *\n     * @return a new Socket, bound on myAddress:myPort and connected to\n     * address:port.\n     * @throws IOException if binding or connecting the socket fail for a reason\n     * (exception relayed from the correspoonding Socket methods)\n     */\n    public Socket createSocket(InetAddress address, int port,\n                    InetAddress myAddress, int myPort)\n        throws IOException\n    {\n        if (myAddress != null)\n            return new Socket(address, port, myAddress, myPort);\n        else if (port != 0)\n        {\n            //myAddress is null (i.e. any)  but we have a port number\n            Socket sock = new Socket();\n            sock.bind(new InetSocketAddress(port));\n            sock.connect(new InetSocketAddress(address, port));\n            return sock;\n        }\n        else\n            return new Socket(address, port);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/ClientTransactionExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport java.security.cert.Certificate;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.SSLPeerUnverifiedException;\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.Timeout;\nimport javax2.sip.address.Hop;\n\npublic interface ClientTransactionExt extends ClientTransaction, TransactionExt {\n\n    /**\n     * Notify on retransmission from the client transaction side. The listener will get a\n     * notification on retransmission when this flag is set. When set the client transaction\n     * listener will get a Timeout.RETRANSMIT event on each retransmission.\n     * \n     * @param flag -- the flag that indicates whether or not notification is desired.\n     * \n     * @since 2.0\n     */\n    public void setNotifyOnRetransmit(boolean flag);\n\n    /**\n     * Send a transaction timeout event to the application if Tx is still in Calling state in the\n     * given time period ( in base timer interval count ) after sending request. The stack will\n     * start a timer and alert the application if the client transaction does not transition out\n     * of the Trying state by the given interval. This is a \"one shot\" alert.\n     * \n     * @param count -- the number of base timer intervals after which an alert is issued.\n     * \n     * \n     * @since 2.0\n     */\n    public void alertIfStillInCallingStateBy(int count);\n    \n    /**\n     * Get the next hop that was computed by the routing layer.\n     * when it sent out the request. This allows you to route requests\n     * to the SAME destination if required ( for example if you get\n     * an authentication challenge ).\n     */\n    public Hop getNextHop();\n    \n    /**\n     * Return true if this Ctx is a secure transport.\n     * \n     */\n    public boolean isSecure();\n    \n  \n   \n   \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/DefaultAddressResolver.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport javax2.sip.address.Hop;\n\nimport gov2.nist.core.net.AddressResolver;\nimport gov2.nist.javax2.sip.stack.HopImpl;\nimport gov2.nist.javax2.sip.stack.MessageProcessor;\n\n/**\n * This is the default implementation of the AddressResolver. The AddressResolver is a NIST-SIP specific\n * feature. The address resolover is consulted to convert a Hop into a meaningful address. The default\n * implementation is a passthrough. It only gets involved in setting the default port. However, you\n * can register your own AddressResolver implementation\n * Note that\n * The RI checks incoming via headers for resolving the sentBy field. If you want to set it to\n * some address that cannot be resolved you should register an AddressResolver with the stack.\n * This feature is also useful for DNS SRV lookup which is not implemented by the RI at present.\n *\n * @version 1.2\n * @since 1.2\n * @see gov2.nist.javax2.sip.SipStackImpl#setAddressResolver(AddressResolver)\n *\n * @author M. Ranganathan\n *\n */\npublic class DefaultAddressResolver implements AddressResolver {\n\n    public DefaultAddressResolver() {\n\n    }\n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.core.net.AddressResolver#resolveAddress(javax2.sip.address.Hop)\n     */\n    public Hop resolveAddress(Hop inputAddress) {\n        if  (inputAddress.getPort()  != -1)\n            return inputAddress;\n        else {\n            return new HopImpl(inputAddress.getHost(),\n                    MessageProcessor.getDefaultPort(inputAddress.getTransport()),inputAddress.getTransport());\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/DialogExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport javax2.sip.Dialog;\nimport javax2.sip.SipProvider;\n\n/**\n * Extensions for Next specification revision. These interfaces will remain unchanged and be\n * merged with the next revision of the spec.\n * \n * \n * @author mranga\n * \n */\npublic interface DialogExt extends Dialog {\n\n    /**\n     * Returns the SipProvider that was used for the first transaction in this Dialog\n     * \n     * @return SipProvider\n     * \n     * @since 2.0\n     */\n    public SipProvider getSipProvider();\n\n    /**\n     * Sets a flag that indicates that this Dialog is part of a BackToBackUserAgent. If this flag\n     * is set, INVITEs are not allowed to interleave and timed out ACK transmission results in a\n     * BYE being sent to the other side. Setting this flag instructs the stack to automatically\n     * handle dialog errors. Once this flag is set for a dialog, it cannot be changed.\n     * This flag can be set on a stack-wide basis, on a per-provider basis or on a per Dialog basis.\n     * This flag must only be set at the time of Dialog creation. If the flag is set after the first\n     * request or response is seen by the Dialog, the behavior of this flag is undefined.\n     * \n     * @since 2.0\n     */\n    public void setBackToBackUserAgent();\n    \n    \n    /**\n     * Turn off sequence number validation for this dialog. This passes all requests to the\n     * application layer including those that arrive out of order. This is good for testing\n     * purposes. Validation is delegated to the application and the stack will not attempt to\n     * block requests arriving out of sequence from reaching the application. In particular, the\n     * validation of CSeq and the ACK retransmission recognition are delegated to the application.\n     * Your application will be responsible for error handling of these cases.\n     * \n     * @since 2.0\n     */\n    public void disableSequenceNumberValidation();\n\n  \n    \n    \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/DialogFilter.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.header.Contact;\nimport gov2.nist.javax2.sip.header.Event;\nimport gov2.nist.javax2.sip.header.ReferTo;\nimport gov2.nist.javax2.sip.header.RetryAfter;\nimport gov2.nist.javax2.sip.header.Route;\nimport gov2.nist.javax2.sip.header.RouteList;\nimport gov2.nist.javax2.sip.header.Server;\nimport gov2.nist.javax2.sip.message.MessageFactoryImpl;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\nimport gov2.nist.javax2.sip.stack.MessageChannel;\nimport gov2.nist.javax2.sip.stack.SIPClientTransaction;\nimport gov2.nist.javax2.sip.stack.SIPDialog;\nimport gov2.nist.javax2.sip.stack.SIPServerTransaction;\nimport gov2.nist.javax2.sip.stack.SIPTransaction;\nimport gov2.nist.javax2.sip.stack.ServerRequestInterface;\nimport gov2.nist.javax2.sip.stack.ServerResponseInterface;\n\nimport java.io.IOException;\nimport java.util.TimerTask;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.DialogState;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.RequestEvent;\nimport javax2.sip.ResponseEvent;\nimport javax2.sip.ServerTransaction;\nimport javax2.sip.SipException;\nimport javax2.sip.SipProvider;\nimport javax2.sip.TransactionState;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.header.ReferToHeader;\nimport javax2.sip.header.ServerHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/*\n * Bug fix Contributions by Lamine Brahimi, Andreas Bystrom, Bill Roome, John Martin, Daniel\n * Machin Vasquez-Illa, Antonis Karydas, Joe Provino, Bruce Evangelder, Jeroen van Bemmel, Robert\n * S. Rosen.\n */\n/**\n * An adapter class from the JAIN implementation objects to the NIST-SIP stack. The primary\n * purpose of this class is to do early rejection of bad messages and deliver meaningful messages\n * to the application. This class is essentially a Dialog filter. It is a helper for the UAC Core.\n * It checks for and rejects requests and responses which may be filtered out because of sequence\n * number, Dialog not found, etc. Note that this is not part of the JAIN-SIP spec (it does not\n * implement a JAIN-SIP interface). This is part of the glue that ties together the NIST-SIP stack\n * and event model with the JAIN-SIP stack. This is strictly an implementation class.\n * \n * @version 1.2 $Revision: 1.64 $ $Date: 2010/01/14 18:58:30 $\n * \n * @author M. Ranganathan\n */\nclass DialogFilter implements ServerRequestInterface, ServerResponseInterface {\n\n    protected SIPTransaction transactionChannel;\n\n    protected ListeningPointImpl listeningPoint;\n\n    private SipStackImpl sipStack;\n\n    public DialogFilter(SipStackImpl sipStack) {\n        this.sipStack = sipStack;\n\n    }\n\n    /**\n     * Send back a Request Pending response.\n     * \n     * @param sipRequest\n     * @param transaction\n     */\n    private void sendRequestPendingResponse(SIPRequest sipRequest,\n            SIPServerTransaction transaction) {\n        SIPResponse sipResponse = sipRequest.createResponse(Response.REQUEST_PENDING);\n        ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();\n        if (serverHeader != null) {\n            sipResponse.setHeader(serverHeader);\n        }\n        try {\n            RetryAfter retryAfter = new RetryAfter();\n            retryAfter.setRetryAfter(1);\n            sipResponse.setHeader(retryAfter);\n            if (sipRequest.getMethod().equals(Request.INVITE)) {\n                sipStack.addTransactionPendingAck(transaction);\n            }\n            transaction.sendResponse(sipResponse);\n            transaction.releaseSem();\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Problem sending error response\", ex);\n            transaction.releaseSem();\n            sipStack.removeTransaction(transaction);\n        }\n    }\n\n    /**\n     * Send a BAD REQUEST response.\n     * \n     * @param sipRequest\n     * @param transaction\n     * @param reasonPhrase\n     */\n\n    private void sendBadRequestResponse(SIPRequest sipRequest, SIPServerTransaction transaction,\n            String reasonPhrase) {\n        SIPResponse sipResponse = sipRequest.createResponse(Response.BAD_REQUEST);\n        if (reasonPhrase != null)\n            sipResponse.setReasonPhrase(reasonPhrase);\n        ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();\n        if (serverHeader != null) {\n            sipResponse.setHeader(serverHeader);\n        }\n        try {\n            if (sipRequest.getMethod().equals(Request.INVITE)) {\n                sipStack.addTransactionPendingAck(transaction);\n            }\n            transaction.sendResponse(sipResponse);\n            transaction.releaseSem();\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Problem sending error response\", ex);\n            transaction.releaseSem();\n            sipStack.removeTransaction(transaction);\n\n        }\n    }\n\n    /**\n     * Send a CALL OR TRANSACTION DOES NOT EXIST response.\n     * \n     * @param sipRequest\n     * @param transaction\n     */\n\n    private void sendCallOrTransactionDoesNotExistResponse(SIPRequest sipRequest,\n            SIPServerTransaction transaction) {\n\n        SIPResponse sipResponse = sipRequest\n                .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);\n\n        ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();\n        if (serverHeader != null) {\n            sipResponse.setHeader(serverHeader);\n        }\n        try {\n            if (sipRequest.getMethod().equals(Request.INVITE)) {\n                sipStack.addTransactionPendingAck(transaction);\n            }\n            transaction.sendResponse(sipResponse);\n            transaction.releaseSem();\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Problem sending error response\", ex);\n            transaction.releaseSem();\n            sipStack.removeTransaction(transaction);\n\n        }\n\n    }\n\n    /**\n     * Send back a LOOP Detected Response.\n     * \n     * @param sipRequest\n     * @param transaction\n     * \n     */\n    private void sendLoopDetectedResponse(SIPRequest sipRequest, SIPServerTransaction transaction) {\n        SIPResponse sipResponse = sipRequest.createResponse(Response.LOOP_DETECTED);\n\n        ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();\n        if (serverHeader != null) {\n            sipResponse.setHeader(serverHeader);\n        }\n        try {\n            sipStack.addTransactionPendingAck(transaction);\n            transaction.sendResponse(sipResponse);\n            transaction.releaseSem();\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Problem sending error response\", ex);\n            transaction.releaseSem();\n            sipStack.removeTransaction(transaction);\n\n        }\n\n    }\n\n    /**\n     * Send back an error Response.\n     * \n     * @param sipRequest\n     * @param transaction\n     */\n\n    private void sendServerInternalErrorResponse(SIPRequest sipRequest,\n            SIPServerTransaction transaction) {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger()\n                    .logDebug(\"Sending 500 response for out of sequence message\");\n        SIPResponse sipResponse = sipRequest.createResponse(Response.SERVER_INTERNAL_ERROR);\n        sipResponse.setReasonPhrase(\"Request out of order\");\n        if (MessageFactoryImpl.getDefaultServerHeader() != null) {\n            ServerHeader serverHeader = MessageFactoryImpl.getDefaultServerHeader();\n            sipResponse.setHeader(serverHeader);\n        }\n\n        try {\n            RetryAfter retryAfter = new RetryAfter();\n            retryAfter.setRetryAfter(10);\n            sipResponse.setHeader(retryAfter);\n            sipStack.addTransactionPendingAck(transaction);\n            transaction.sendResponse(sipResponse);\n            transaction.releaseSem();\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Problem sending response\", ex);\n            transaction.releaseSem();\n            sipStack.removeTransaction(transaction);\n        }\n    }\n\n    /**\n     * Process a request. Check for various conditions in the dialog that can result in the\n     * message being dropped. Possibly return errors for these conditions.\n     * \n     * @exception SIPServerException is thrown when there is an error processing the request.\n     */\n    public void processRequest(SIPRequest sipRequest, MessageChannel incomingMessageChannel) {\n        // Generate the wrapper JAIN-SIP object.\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"PROCESSING INCOMING REQUEST \" + sipRequest + \" transactionChannel = \"\n                            + transactionChannel + \" listening point = \"\n                            + listeningPoint.getIPAddress() + \":\" + listeningPoint.getPort());\n        if (listeningPoint == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"Dropping message: No listening point registered!\");\n            return;\n        }\n\n        SipStackImpl sipStack = (SipStackImpl) transactionChannel.getSIPStack();\n\n        SipProviderImpl sipProvider = listeningPoint.getProvider();\n        if (sipProvider == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"No provider - dropping !!\");\n            return;\n        }\n\n        if (sipStack == null)\n            InternalErrorHandler.handleException(\"Egads! no sip stack!\");\n\n        // Look for the registered SIPListener for the message channel.\n\n        SIPServerTransaction transaction = (SIPServerTransaction) this.transactionChannel;\n        if (transaction != null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"transaction state = \" + transaction.getState());\n        }\n        String dialogId = sipRequest.getDialogId(true);\n        SIPDialog dialog = sipStack.getDialog(dialogId);\n        /*\n         * Check if we got this request on the contact address of the dialog If not the dialog\n         * does not belong to this request. We check this condition if a contact address has been\n         * assigned to the dialog. Forgive the sins of B2BUA's that like to record route ACK's\n         */\n        if (dialog != null && sipProvider != dialog.getSipProvider()) {\n            Contact contact = dialog.getMyContactHeader();\n            if (contact != null) {\n                SipUri contactUri = (SipUri) (contact.getAddress().getURI());\n                String ipAddress = contactUri.getHost();\n                int contactPort = contactUri.getPort();\n                String contactTransport = contactUri.getTransportParam();\n                if (contactTransport == null)\n                    contactTransport = \"udp\";\n                if (contactPort == -1) {\n                    if (contactTransport.equals(\"udp\") || contactTransport.equals(\"tcp\"))\n                        contactPort = 5060;\n                    else\n                        contactPort = 5061;\n                }\n                // Check if the dialog contact is the same as the provider on\n                // which we got the request. Otherwise, dont assign this\n                // dialog to the request.\n                if (ipAddress != null\n                        && (!ipAddress.equals(listeningPoint.getIPAddress()) || contactPort != listeningPoint\n                                .getPort())) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"nulling dialog -- listening point mismatch!  \" + contactPort\n                                        + \"  lp port = \" + listeningPoint.getPort());\n\n                    }\n                    dialog = null;\n                }\n\n            }\n        }\n\n        /*\n         * RFC 3261 8.2.2.2 Merged requests: If the request has no tag in the To header field, the\n         * UAS core MUST check the request against ongoing transactions. If the From tag, Call-ID,\n         * and CSeq exactly match those associated with an ongoing transaction, but the request\n         * does not match that transaction (based on the matching rules in Section 17.2.3), the\n         * UAS core SHOULD generate a 482 (Loop Detected) response and pass it to the server\n         * transaction. This support is only enabled when the stack has been instructed to\n         * function with Automatic Dialog Support.\n         */\n        if (sipProvider.isAutomaticDialogSupportEnabled()\n                && sipProvider.isDialogErrorsAutomaticallyHandled()\n                && sipRequest.getToTag() == null) {\n            SIPServerTransaction sipServerTransaction = sipStack\n                    .findMergedTransaction(sipRequest);\n            if (sipServerTransaction != null) {\n                this.sendLoopDetectedResponse(sipRequest, transaction);\n                return;\n            }\n        }\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"dialogId = \" + dialogId);\n            sipStack.getStackLogger().logDebug(\"dialog = \" + dialog);\n        }\n\n        /*\n         * RFC 3261 Section 16.4 If the first value in the Route header field indicates this\n         * proxy,the proxy MUST remove that value from the request .\n         */\n\n        // If the message is being processed\n        // by a Proxy, then the proxy will take care of stripping the\n        // Route header. If the request is being processed by an\n        // endpoint, then the stack strips off the route header.\n        if (sipRequest.getHeader(Route.NAME) != null && transaction.getDialog() != null) {\n            RouteList routes = sipRequest.getRouteHeaders();\n            Route route = (Route) routes.getFirst();\n            SipUri uri = (SipUri) route.getAddress().getURI();\n            int port;\n            if (uri.getHostPort().hasPort()) {\n                port = uri.getHostPort().getPort();\n            } else {\n                if (listeningPoint.getTransport().equalsIgnoreCase(\"TLS\"))\n                    port = 5061;\n                else\n                    port = 5060;\n            }\n            String host = uri.getHost();\n            if ((host.equals(listeningPoint.getIPAddress()) || host\n                    .equalsIgnoreCase(listeningPoint.getSentBy()))\n                    && port == listeningPoint.getPort()) {\n                if (routes.size() == 1)\n                    sipRequest.removeHeader(Route.NAME);\n                else\n                    routes.removeFirst();\n            }\n        }\n\n        if (sipRequest.getMethod().equals(Request.REFER) && dialog != null\n                && sipProvider.isDialogErrorsAutomaticallyHandled()) {\n            /*\n             * An agent responding to a REFER method MUST return a 400 (Bad Request) if the\n             * request contained zero or more than one Refer-To header field values.\n             */\n            ReferToHeader sipHeader = (ReferToHeader) sipRequest.getHeader(ReferTo.NAME);\n            if (sipHeader == null) {\n                this\n                        .sendBadRequestResponse(sipRequest, transaction,\n                                \"Refer-To header is missing\");\n                return;\n\n            }\n\n            /*\n             * A refer cannot be processed until we have either sent or received an ACK.\n             */\n            SIPTransaction lastTransaction = ((SIPDialog) dialog).getLastTransaction();\n            if (lastTransaction != null  && sipProvider.isDialogErrorsAutomaticallyHandled()) {\n                SIPRequest lastRequest = (SIPRequest) lastTransaction.getRequest();\n                if (lastTransaction instanceof SIPServerTransaction) {\n                    if (!((SIPDialog) dialog).isAckSeen()   \n                            && lastRequest.getMethod().equals(Request.INVITE)) {\n                        this.sendRequestPendingResponse(sipRequest, transaction);\n                        return;\n                    }\n                } else if (lastTransaction instanceof SIPClientTransaction) {\n                    long cseqno = lastRequest.getCSeqHeader().getSeqNumber();\n                    String method = lastRequest.getMethod();\n                    if (method.equals(Request.INVITE) && !dialog.isAckSent(cseqno)) {\n                        this.sendRequestPendingResponse(sipRequest, transaction);\n                        return;\n                    }\n                }\n            }\n\n        } else if (sipRequest.getMethod().equals(Request.UPDATE)) {\n            /*\n             * Got an UPDATE method and the user dialog does not exist and the user wants to be a\n             * User agent.\n             * \n             */\n            if (sipProvider.isAutomaticDialogSupportEnabled() && dialog == null) {\n                this.sendCallOrTransactionDoesNotExistResponse(sipRequest, transaction);\n                return;\n            }\n        } else if (sipRequest.getMethod().equals(Request.ACK)) {\n\n            if (transaction != null && transaction.isInviteTransaction()) {\n                // This is an ack for a 3xx-6xx response. Just let the tx laer\n                // take care of it.\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"Processing ACK for INVITE Tx \");\n\n            } else {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"Processing ACK for dialog \" + dialog);\n\n                if (dialog == null) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Dialog does not exist \" + sipRequest.getFirstLine()\n                                        + \" isServerTransaction = \" + true);\n\n                    }\n                    SIPServerTransaction st = sipStack\n                            .getRetransmissionAlertTransaction(dialogId);\n                    if (st != null && st.isRetransmissionAlertEnabled()) {\n                        st.disableRetransmissionAlerts();\n\n                    }\n                    /*\n                     * JvB: must never drop ACKs that dont match a transaction! One cannot be sure\n                     * if it isn't an ACK for a 2xx response\n                     * \n                     */\n                    SIPServerTransaction ackTransaction = sipStack\n                            .findTransactionPendingAck(sipRequest);\n                    /*\n                     * Found a transaction ( that we generated ) which is waiting for ACK. So ACK\n                     * it and return.\n                     */\n                    if (ackTransaction != null) {\n                        if (sipStack.isLoggingEnabled())\n                            sipStack.getStackLogger().logDebug(\"Found Tx pending ACK\");\n                        try {\n                            ackTransaction.setAckSeen();\n                            sipStack.removeTransaction(ackTransaction);\n                            sipStack.removeTransactionPendingAck(ackTransaction);\n                        } catch (Exception ex) {\n                            if (sipStack.isLoggingEnabled()) {\n                                sipStack.getStackLogger().logError(\n                                        \"Problem terminating transaction\", ex);\n                            }\n                        }\n                        return;\n                    }\n\n                } else {\n                    if (!dialog.handleAck(transaction)) {\n                        if (!dialog.isSequnceNumberValidation()) {\n                            if (sipStack.isLoggingEnabled()) {\n                                sipStack.getStackLogger().logDebug(\n                                        \"Dialog exists with loose dialog validation \"\n                                                + sipRequest.getFirstLine()\n                                                + \" isServerTransaction = \" + true + \" dialog = \"\n                                                + dialog.getDialogId());\n\n                            }\n                            SIPServerTransaction st = sipStack\n                                    .getRetransmissionAlertTransaction(dialogId);\n                            if (st != null && st.isRetransmissionAlertEnabled()) {\n                                st.disableRetransmissionAlerts();\n\n                            }\n                        } else {\n                            if (sipStack.isLoggingEnabled()) {\n                                sipStack.getStackLogger().logDebug(\n                                        \"Dropping ACK - cannot find a transaction or dialog\");\n                            }\n                            SIPServerTransaction ackTransaction = sipStack\n                                    .findTransactionPendingAck(sipRequest);\n                            if (ackTransaction != null) {\n                                if (sipStack.isLoggingEnabled())\n                                    sipStack.getStackLogger().logDebug(\"Found Tx pending ACK\");\n                                try {\n                                    ackTransaction.setAckSeen();\n                                    sipStack.removeTransaction(ackTransaction);\n                                    sipStack.removeTransactionPendingAck(ackTransaction);\n                                } catch (Exception ex) {\n                                    if (sipStack.isLoggingEnabled()) {\n                                        sipStack.getStackLogger().logError(\n                                                \"Problem terminating transaction\", ex);\n                                    }\n                                }\n                            }\n                            return;\n                        }\n                    } else {\n                        transaction.passToListener();\n                        dialog.addTransaction(transaction);\n                        dialog.addRoute(sipRequest);\n                        transaction.setDialog(dialog, dialogId);\n                        if (sipRequest.getMethod().equals(Request.INVITE)\n                                && sipProvider.isDialogErrorsAutomaticallyHandled()) {\n                            sipStack.putInMergeTable(transaction, sipRequest);\n                        }\n                        /*\n                         * Note that ACK is a pseudo transaction. It is never added to the stack\n                         * and you do not get transaction terminated events on ACK.\n                         */\n\n                        if (sipStack.deliverTerminatedEventForAck) {\n                            try {\n                                sipStack.addTransaction(transaction);\n                                transaction.scheduleAckRemoval();\n                            } catch (IOException ex) {\n\n                            }\n                        } else {\n                            transaction.setMapped(true);\n                        }\n\n                    }\n                }\n            }\n        } else if (sipRequest.getMethod().equals(Request.PRACK)) {\n\n            /*\n             * RFC 3262: A matching PRACK is defined as one within the same dialog as the\n             * response, and whose method, CSeq-num, and response-num in the RAck header field\n             * match, respectively, the method from the CSeq, the sequence number from the CSeq,\n             * and the sequence number from the RSeq of the reliable provisional response.\n             */\n\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Processing PRACK for dialog \" + dialog);\n\n            if (dialog == null && sipProvider.isAutomaticDialogSupportEnabled()) {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"Dialog does not exist \" + sipRequest.getFirstLine()\n                                    + \" isServerTransaction = \" + true);\n\n                }\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack\n                            .getStackLogger()\n                            .logDebug(\n                                    \"Sending 481 for PRACK - automatic dialog support is enabled -- cant find dialog!\");\n                }\n                SIPResponse notExist = sipRequest\n                        .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);\n\n                try {\n                    sipProvider.sendResponse(notExist);\n                } catch (SipException e) {\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger().logError(\"error sending response\", e);\n                }\n                if (transaction != null) {\n                    sipStack.removeTransaction(transaction);\n                    transaction.releaseSem();\n                }\n                return;\n\n            } else if (dialog != null) {\n                if (!dialog.handlePrack(sipRequest)) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\"Dropping out of sequence PRACK \");\n                    if (transaction != null) {\n                        sipStack.removeTransaction(transaction);\n                        transaction.releaseSem();\n                    }\n                    return;\n                } else {\n                    try {\n                        sipStack.addTransaction(transaction);\n                        dialog.addTransaction(transaction);\n                        dialog.addRoute(sipRequest);\n                        transaction.setDialog(dialog, dialogId);\n                    } catch (Exception ex) {\n                        InternalErrorHandler.handleException(ex);\n                    }\n                }\n            } else {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"Processing PRACK without a DIALOG -- this must be a proxy element\");\n            }\n\n        } else if (sipRequest.getMethod().equals(Request.BYE)) {\n            // Check for correct sequence numbering of the BYE\n            if (dialog != null && !dialog.isRequestConsumable(sipRequest)) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"Dropping out of sequence BYE \" + dialog.getRemoteSeqNumber() + \" \"\n                                    + sipRequest.getCSeq().getSeqNumber());\n\n                if (dialog.getRemoteSeqNumber() >= sipRequest.getCSeq().getSeqNumber()\n                        && transaction.getState() == TransactionState.TRYING) {\n\n                    this.sendServerInternalErrorResponse(sipRequest, transaction);\n\n                }\n                // If the stack knows about the tx, then remove it.\n                if (transaction != null)\n                    sipStack.removeTransaction(transaction);\n                return;\n\n            } else if (dialog == null && sipProvider.isAutomaticDialogSupportEnabled()) {\n                // Drop bye's with 481 if dialog does not exist.\n                // If dialog support is enabled then\n                // there must be a dialog associated with the bye\n                // No dialog could be found and requests on this\n                // provider. Must act like a user agent -- so drop the request.\n                // NOTE: if Automatic dialog support is not enabled,\n                // then it is the application's responsibility to\n                // take care of this error condition possibly.\n\n                SIPResponse response = sipRequest\n                        .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);\n                response.setReasonPhrase(\"Dialog Not Found\");\n\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"dropping request -- automatic dialog \"\n                                    + \"support enabled and dialog does not exist!\");\n                try {\n                    transaction.sendResponse(response);\n                } catch (SipException ex) {\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger().logError(\"Error in sending response\", ex);\n                }\n                // If the stack knows about the tx, then remove it.\n                if (transaction != null) {\n                    sipStack.removeTransaction(transaction);\n                    transaction.releaseSem();\n                    transaction = null;\n                }\n                return;\n\n            }\n\n            // note that the transaction may be null (which\n            // happens when no dialog for the bye was found.\n            // and automatic dialog support is disabled (i.e. the app wants\n            // to manage its own dialog layer.\n            if (transaction != null && dialog != null) {\n                try {\n                    if (sipProvider == dialog.getSipProvider()) {\n                        sipStack.addTransaction(transaction);\n                        dialog.addTransaction(transaction);\n                        transaction.setDialog(dialog, dialogId);\n                    }\n\n                } catch (IOException ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n            }\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"BYE Tx = \" + transaction + \" isMapped =\"\n                                + transaction.isTransactionMapped());\n            }\n\n        } else if (sipRequest.getMethod().equals(Request.CANCEL)) {\n\n            SIPServerTransaction st = (SIPServerTransaction) sipStack.findCancelTransaction(\n                    sipRequest, true);\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"Got a CANCEL, InviteServerTx = \" + st + \" cancel Server Tx ID = \"\n                                + transaction + \" isMapped = \"\n                                + transaction.isTransactionMapped());\n\n            }\n            // Processing incoming CANCEL.\n            // Check if we can process the CANCEL request.\n            if (sipRequest.getMethod().equals(Request.CANCEL)) {\n                // If the CANCEL comes in too late, there's not\n                // much that the Listener can do so just do the\n                // default action and avoid bothering the listener.\n                if (st != null && st.getState() == SIPTransaction.TERMINATED_STATE) {\n                    // If transaction already exists but it is\n                    // too late to cancel the transaction then\n                    // just respond OK to the CANCEL and bail.\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\"Too late to cancel Transaction\");\n                    // send OK and just ignore the CANCEL.\n                    try {\n\n                        transaction.sendResponse(sipRequest.createResponse(Response.OK));\n                    } catch (Exception ex) {\n                        if (ex.getCause() != null && ex.getCause() instanceof IOException) {\n                            st.raiseIOExceptionEvent();\n                        }\n                    }\n                    return;\n                }\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"Cancel transaction = \" + st);\n\n            }\n            if (transaction != null && st != null && st.getDialog() != null) {\n                // Found an invite tx corresponding to the CANCEL.\n                // Set up the client tx and pass up to listener.\n                transaction.setDialog((SIPDialog) st.getDialog(), dialogId);\n                dialog = (SIPDialog) st.getDialog();\n            } else if (st == null && sipProvider.isAutomaticDialogSupportEnabled()\n                    && transaction != null) {\n                // Could not find a invite tx corresponding to the CANCEL.\n                // Automatic dialog support is enabled so I must behave like\n                // an endpoint on this provider.\n                // Send the error response for the cancel.\n\n                SIPResponse response = sipRequest\n                        .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"dropping request -- automatic dialog support \"\n                                    + \"enabled and INVITE ST does not exist!\");\n                }\n                try {\n                    sipProvider.sendResponse(response);\n                } catch (SipException ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n                if (transaction != null) {\n                    sipStack.removeTransaction(transaction);\n                    transaction.releaseSem();\n                }\n                return;\n\n            }\n\n            // INVITE was handled statefully so the CANCEL must also be\n            // statefully handled.\n            if (st != null) {\n                try {\n                    if (transaction != null) {\n                        sipStack.addTransaction(transaction);\n                        transaction.setPassToListener();\n                        transaction.setInviteTransaction(st);\n                        // Dont let the INVITE and CANCEL be concurrently\n                        // processed.\n                        st.acquireSem();\n\n                    }\n\n                } catch (Exception ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n            }\n        } else if (sipRequest.getMethod().equals(Request.INVITE)) {\n            SIPTransaction lastTransaction = dialog == null ? null : dialog\n                    .getInviteTransaction();\n\n            /*\n             * RFC 3261 Chapter 14. A UAS that receives a second INVITE before it sends the final\n             * response to a first INVITE with a lower CSeq sequence number on the same dialog\n             * MUST return a 500 (Server Internal Error) response to the second INVITE and MUST\n             * include a Retry-After header field with a randomly chosen value of between 0 and 10\n             * seconds.\n             */\n\n            if (dialog != null && transaction != null && lastTransaction != null\n                    && sipRequest.getCSeq().getSeqNumber() > dialog.getRemoteSeqNumber()\n                    && lastTransaction instanceof SIPServerTransaction\n                    && sipProvider.isDialogErrorsAutomaticallyHandled()\n                    && dialog.isSequnceNumberValidation()\n                    && lastTransaction.isInviteTransaction()\n                    && lastTransaction.getState() != TransactionState.COMPLETED\n                    && lastTransaction.getState() != TransactionState.TERMINATED\n                    && lastTransaction.getState() != TransactionState.CONFIRMED) {\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"Sending 500 response for out of sequence message\");\n                }\n                this.sendServerInternalErrorResponse(sipRequest, transaction);\n                return;\n\n            }\n\n            /*\n             * Saw an interleaved invite before ACK was sent. RFC 3261 Chapter 14. A UAS that\n             * receives an INVITE on a dialog while an INVITE it had sent on that dialog is in\n             * progress MUST return a 491 (Request Pending) response to the received INVITE.\n             */\n            lastTransaction = (dialog == null ? null : dialog.getLastTransaction());\n\n            if (dialog != null\n                    && sipProvider.isDialogErrorsAutomaticallyHandled()\n                    && lastTransaction != null\n                    && lastTransaction.isInviteTransaction()\n                    && lastTransaction instanceof ClientTransaction\n                    && lastTransaction.getLastResponse() != null\n                    && lastTransaction.getLastResponse().getStatusCode() == 200\n                    && !dialog.isAckSent(lastTransaction.getLastResponse().getCSeq()\n                            .getSeqNumber())) {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"Sending 491 response for client Dialog ACK not sent.\");\n                }\n                this.sendRequestPendingResponse(sipRequest, transaction);\n                return;\n            }\n\n            if (dialog != null && lastTransaction != null\n                    && sipProvider.isDialogErrorsAutomaticallyHandled()\n                    && lastTransaction.isInviteTransaction()\n                    && lastTransaction instanceof ServerTransaction && !dialog.isAckSeen()) {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"Sending 491 response for server Dialog ACK not seen.\");\n                }\n                this.sendRequestPendingResponse(sipRequest, transaction);\n                return;\n\n            }\n        }\n\n        // Sequence numbers are supposed to be incremented\n        // sequentially within a dialog for RFC 3261\n        // Note BYE, CANCEL and ACK is handled above - so no check here.\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"CHECK FOR OUT OF SEQ MESSAGE \" + dialog + \" transaction \" + transaction);\n        }\n\n        if (dialog != null && transaction != null && !sipRequest.getMethod().equals(Request.BYE)\n                && !sipRequest.getMethod().equals(Request.CANCEL)\n                && !sipRequest.getMethod().equals(Request.ACK)\n                && !sipRequest.getMethod().equals(Request.PRACK)) {\n\n            if (!dialog.isRequestConsumable(sipRequest)) {\n\n                /*\n                 * RFC 3261: \"UAS Behavior\" section (12.2.2): If the remote sequence number was\n                 * not empty, but the sequence number of the request is lower than the remote\n                 * sequence number, the request is out of order and MUST be rejected with a 500\n                 * (Server Internal Error) response.\n                 */\n\n                // Drop the request\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"Dropping out of sequence message \" + dialog.getRemoteSeqNumber()\n                                    + \" \" + sipRequest.getCSeq());\n                }\n\n                // send error when stricly higher, ignore when ==\n                // (likely still processing, error would interrupt that)\n\n                if (dialog.getRemoteSeqNumber() >= sipRequest.getCSeq().getSeqNumber()\n                        && sipProvider.isDialogErrorsAutomaticallyHandled()\n                        && (transaction.getState() == TransactionState.TRYING || transaction\n                                .getState() == TransactionState.PROCEEDING)) {\n                    this.sendServerInternalErrorResponse(sipRequest, transaction);\n\n                }\n                return;\n            }\n\n            try {\n                if (sipProvider == dialog.getSipProvider()) {\n                    sipStack.addTransaction(transaction);\n                    // This will set the remote sequence number.\n                    dialog.addTransaction(transaction);\n                    dialog.addRoute(sipRequest);\n                    transaction.setDialog(dialog, dialogId);\n\n                }\n            } catch (IOException ex) {\n                transaction.raiseIOExceptionEvent();\n                sipStack.removeTransaction(transaction);\n                return;\n            }\n\n        }\n\n        RequestEvent sipEvent;\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    sipRequest.getMethod() + \" transaction.isMapped = \"\n                            + transaction.isTransactionMapped());\n        }\n\n        /*\n         * RFC 3265: Each event package MUST specify whether forked SUBSCRIBE requests are allowed\n         * to install multiple subscriptions. If such behavior is not allowed, the first potential\n         * dialog- establishing message will create a dialog. All subsequent NOTIFY messages which\n         * correspond to the SUBSCRIBE message (i.e., match \"To\", \"From\", \"From\" header \"tag\"\n         * parameter, \"Call-ID\", \"CSeq\", \"Event\", and \"Event\" header \"id\" parameter) but which do\n         * not match the dialog would be rejected with a 481 response. Note that the 200-class\n         * response to the SUBSCRIBE can arrive after a matching NOTIFY has been received; such\n         * responses might not correlate to the same dialog established by the NOTIFY. Except as\n         * required to complete the SUBSCRIBE transaction, such non-matching 200-class responses\n         * are ignored.\n         */\n\n        if (dialog == null && sipRequest.getMethod().equals(Request.NOTIFY)) {\n\n            SIPClientTransaction pendingSubscribeClientTx = sipStack.findSubscribeTransaction(\n                    sipRequest, listeningPoint);\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"PROCESSING NOTIFY  DIALOG == null \" + pendingSubscribeClientTx);\n            }\n\n            /*\n             * RFC 3265: Upon receiving a NOTIFY request, the subscriber should check that it\n             * matches at least one of its outstanding subscriptions; if not, it MUST return a\n             * \"481 Subscription does not exist\" response unless another 400- or -class response\n             * is more appropriate.\n             */\n            if (sipProvider.isAutomaticDialogSupportEnabled() && pendingSubscribeClientTx == null\n                    && !sipStack.deliverUnsolicitedNotify) {\n                /*\n                 * This is the case of the UAC receiving a Stray NOTIFY for which it has not\n                 * previously sent out a SUBSCRIBE and for which it does not have an established\n                 * dialog.\n                 */\n                try {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Could not find Subscription for Notify Tx.\");\n                    }\n                    Response errorResponse = sipRequest\n                            .createResponse(Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST);\n                    errorResponse.setReasonPhrase(\"Subscription does not exist\");\n                    sipProvider.sendResponse(errorResponse);\n                    return;\n\n                } catch (Exception ex) {\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger().logError(\n                            \"Exception while sending error response statelessly\", ex);\n                    return;\n                }\n\n            }\n\n            // If the server transaction cannot be found or if it\n            // aleady has a dialog attached to it then just assign the\n            // notify to this dialog and pass it up.\n            if (pendingSubscribeClientTx != null) {\n                // The response to the pending subscribe tx can try to create\n                // a dialog at the same time that the notify is trying to\n                // create a dialog. Thus we cannot process both at the\n                // same time.\n\n                transaction.setPendingSubscribe(pendingSubscribeClientTx);\n                // The transaction gets assigned to the dialog from the\n                // outgoing subscribe. First see if anybody claimed the\n                // default Dialog for the outgoing Subscribe request.\n                SIPDialog subscriptionDialog = (SIPDialog) pendingSubscribeClientTx\n                        .getDefaultDialog();\n\n                // TODO -- refactor this. Can probably be written far cleaner.\n                if (subscriptionDialog == null || subscriptionDialog.getDialogId() == null\n                        || !subscriptionDialog.getDialogId().equals(dialogId)) {\n                    // Notify came in before you could assign a response to\n                    // the subscribe.\n                    // grab the default dialog and assign it to the tags in\n                    // the notify.\n                    if (subscriptionDialog != null && subscriptionDialog.getDialogId() == null) {\n                        subscriptionDialog.setDialogId(dialogId);\n\n                    } else {\n                        subscriptionDialog = pendingSubscribeClientTx.getDialog(dialogId);\n                    }\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"PROCESSING NOTIFY Subscribe DIALOG \" + subscriptionDialog);\n                    }\n\n                    // The user could have createed a dialog before sending out\n                    // the SUBSCRIBE on the subscribe tx.\n                    if (subscriptionDialog == null\n                            && (sipProvider.isAutomaticDialogSupportEnabled() || pendingSubscribeClientTx\n                                    .getDefaultDialog() != null)) {\n                        Event event = (Event) sipRequest.getHeader(EventHeader.NAME);\n                        if (sipStack.isEventForked(event.getEventType())) {\n\n                            subscriptionDialog = SIPDialog.createFromNOTIFY(\n                                    pendingSubscribeClientTx, transaction);\n\n                        }\n\n                    }\n                    if (subscriptionDialog != null) {\n                        transaction.setDialog(subscriptionDialog, dialogId);\n                        subscriptionDialog.setState(DialogState.CONFIRMED.getValue());\n                        sipStack.putDialog(subscriptionDialog);\n                        pendingSubscribeClientTx.setDialog(subscriptionDialog, dialogId);\n                        if (!transaction.isTransactionMapped()) {\n                            this.sipStack.mapTransaction(transaction);\n                            // Let the listener see it if it just got\n                            // created.\n                            // otherwise, we have already processed the tx\n                            // so\n                            // we dont want the listener to see it.\n                            transaction.setPassToListener();\n                            try {\n                                this.sipStack.addTransaction(transaction);\n                            } catch (Exception ex) {\n                            }\n                        }\n                    }\n                } else {\n                    // The subscription default dialog is our dialog.\n                    // Found a subscrbe dialog for the NOTIFY\n                    // So map the tx.\n                    transaction.setDialog(subscriptionDialog, dialogId);\n                    dialog = subscriptionDialog;\n                    if (!transaction.isTransactionMapped()) {\n                        this.sipStack.mapTransaction(transaction);\n                        // Let the listener see it if it just got created.\n                        // otherwise, we have already processed the tx so\n                        // we dont want the listener to see it.\n                        transaction.setPassToListener();\n                        try {\n                            this.sipStack.addTransaction(transaction);\n                        } catch (Exception ex) {\n                        }\n                    }\n                    sipStack.putDialog(subscriptionDialog);\n                    if (pendingSubscribeClientTx != null) {\n                        subscriptionDialog.addTransaction(pendingSubscribeClientTx);\n                        pendingSubscribeClientTx.setDialog(subscriptionDialog, dialogId);\n\n                    }\n                }\n                if (transaction != null\n                        && ((SIPServerTransaction) transaction).isTransactionMapped()) {\n                    // Shadow transaction has been created and the stack\n                    // knows\n                    // about it.\n                    sipEvent = new RequestEvent((SipProvider) sipProvider,\n                            (ServerTransaction) transaction, subscriptionDialog,\n                            (Request) sipRequest);\n                } else {\n                    // Shadow transaction has been created but the stack\n                    // does\n                    // not know\n                    // about it.\n                    sipEvent = new RequestEvent((SipProvider) sipProvider, null,\n                            subscriptionDialog, (Request) sipRequest);\n                }\n\n            } else {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\"could not find subscribe tx\");\n                }\n\n                // Got a notify out of the blue - just pass it up\n                // for stateless handling by the application.\n                sipEvent = new RequestEvent(sipProvider, null, null, (Request) sipRequest);\n            }\n\n        } else {\n\n            // For a dialog creating event - set the transaction to null.\n            // The listener can create the dialog if needed.\n            if (transaction != null\n                    && (((SIPServerTransaction) transaction).isTransactionMapped())) {\n                sipEvent = new RequestEvent(sipProvider, (ServerTransaction) transaction, dialog,\n                        (Request) sipRequest);\n            } else {\n                sipEvent = new RequestEvent(sipProvider, null, dialog, (Request) sipRequest);\n            }\n        }\n        sipProvider.handleEvent(sipEvent, transaction);\n\n    }\n\n    /**\n     * Process the response.\n     * \n     * @exception SIPServerException is thrown when there is an error processing the response\n     * @param incomingMessageChannel -- message channel on which the response is received.\n     */\n    public void processResponse(SIPResponse response, MessageChannel incomingMessageChannel,\n            SIPDialog dialog) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"PROCESSING INCOMING RESPONSE\" + response.encodeMessage());\n        }\n        if (listeningPoint == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logError(\n                        \"Dropping message: No listening point\" + \" registered!\");\n            return;\n        }\n\n        if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(response)) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack\n                        .getStackLogger()\n                        .logError(\n                                \"Dropping response - topmost VIA header does not originate from this stack\");\n            }\n            return;\n        }\n\n        SipProviderImpl sipProvider = listeningPoint.getProvider();\n        if (sipProvider == null) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logError(\"Dropping message:  no provider\");\n            }\n            return;\n        }\n        if (sipProvider.getSipListener() == null) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logError(\"No listener -- dropping response!\");\n            }\n            return;\n        }\n\n        SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel;\n        SipStackImpl sipStackImpl = sipProvider.sipStack;\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStackImpl.getStackLogger().logDebug(\"Transaction = \" + transaction);\n        }\n\n        if (transaction == null) {\n            // Transaction is null but the dialog is not null. This means that\n            // the transaction has been removed by the stack.\n            // If the dialog exists, then it may need to retransmit ACK so\n            // we cannot drop the response.\n            if (dialog != null) {\n                if (response.getStatusCode() / 100 != 2) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack\n                                .getStackLogger()\n                                .logDebug(\n                                        \"Response is not a final response and dialog is found for response -- dropping response!\");\n                    }\n                    return;\n                } else if (dialog.getState() == DialogState.TERMINATED) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Dialog is terminated -- dropping response!\");\n                    }\n                    return;\n                } else {\n                    boolean ackAlreadySent = false;\n                    if (dialog.isAckSeen() && dialog.getLastAckSent() != null) {\n                        if (dialog.getLastAckSent().getCSeq().getSeqNumber() == response\n                                .getCSeq().getSeqNumber()) {\n                            // the last ack sent corresponded to this 200\n                            ackAlreadySent = true;\n                        }\n                    }\n                    // 200 retransmission for the final response.\n                    if (ackAlreadySent\n                            && response.getCSeq().getMethod().equals(dialog.getMethod())) {\n                        try {\n                            // Found the dialog - resend the ACK and\n                            // dont pass up the null transaction\n                            if (sipStack.isLoggingEnabled()) {\n                                sipStack.getStackLogger().logDebug(\n                                        \"Retransmission of OK detected: Resending last ACK\");\n                            }\n                            dialog.resendAck();\n                            return;\n                        } catch (SipException ex) {\n                            // What to do here ?? kill the dialog?\n                            if (sipStack.isLoggingEnabled())\n                            \tsipStack.getStackLogger().logError(\"could not resend ack\", ex);\n                        }\n                    }\n                }\n            }\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"could not find tx, handling statelessly Dialog =  \" + dialog);\n            }\n            // Pass the response up to the application layer to handle\n            // statelessly.\n\n            ResponseEventExt sipEvent = new ResponseEventExt(sipProvider, transaction, dialog,\n                    (Response) response);\n\n            if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) {\n                SIPClientTransaction forked = this.sipStack.getForkedTransaction(response\n                        .getTransactionId());\n                sipEvent.setOriginalTransaction(forked);\n            }\n\n            sipProvider.handleEvent(sipEvent, transaction);\n            return;\n        }\n\n        ResponseEventExt responseEvent = null;\n\n        // Here if there is an assigned dialog\n        responseEvent = new ResponseEventExt(sipProvider, (ClientTransactionExt) transaction,\n                dialog, (Response) response);\n        if (response.getCSeqHeader().getMethod().equals(Request.INVITE)) {\n            SIPClientTransaction forked = this.sipStack.getForkedTransaction(response\n                    .getTransactionId());\n            responseEvent.setOriginalTransaction(forked);\n        }\n\n        // Set the Dialog for the response.\n        if (dialog != null && response.getStatusCode() != 100) {\n            // set the last response for the dialog.\n            dialog.setLastResponse(transaction, response);\n            transaction.setDialog(dialog, dialog.getDialogId());\n        }\n\n        sipProvider.handleEvent(responseEvent, transaction);\n\n    }\n\n    /**\n     * Just a placeholder. This is called from the stack for message logging. Auxiliary processing\n     * information can be passed back to be written into the log file.\n     * \n     * @return auxiliary information that we may have generated during the message processing\n     *         which is retrieved by the message logger.\n     */\n    public String getProcessingInfo() {\n        return null;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.stack.ServerResponseInterface#processResponse(gov2.nist.javax2.sip.message.SIPResponse,\n     *      gov2.nist.javax2.sip.stack.MessageChannel)\n     */\n    public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) {\n        String dialogID = sipResponse.getDialogId(false);\n        SIPDialog sipDialog = this.sipStack.getDialog(dialogID);\n\n        String method = sipResponse.getCSeq().getMethod();\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"PROCESSING INCOMING RESPONSE: \" + sipResponse.encodeMessage());\n        }\n\n        if (sipStack.checkBranchId() && !Utils.getInstance().responseBelongsToUs(sipResponse)) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logError(\"Detected stray response -- dropping\");\n            }\n            return;\n        }\n\n        if (listeningPoint == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"Dropping message: No listening point\" + \" registered!\");\n            return;\n        }\n\n        SipProviderImpl sipProvider = listeningPoint.getProvider();\n        if (sipProvider == null) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"Dropping message:  no provider\");\n            }\n            return;\n        }\n\n        if (sipProvider.getSipListener() == null) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"Dropping message:  no sipListener registered!\");\n            }\n            return;\n        }\n\n        SIPClientTransaction transaction = (SIPClientTransaction) this.transactionChannel;\n        // This may be a dialog creating method for which the ACK has not yet\n        // been sent\n        // but the dialog has already been assigned ( happens this way for\n        // 3PCC).\n        if (sipDialog == null && transaction != null) {\n            sipDialog = transaction.getDialog(dialogID);\n            if (sipDialog != null && sipDialog.getState() == DialogState.TERMINATED)\n                sipDialog = null;\n        }\n\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"Transaction = \" + transaction + \" sipDialog = \" + sipDialog);\n\n        if (this.transactionChannel != null) {\n            String originalFrom = ((SIPRequest) this.transactionChannel.getRequest())\n                    .getFromTag();\n            if (originalFrom == null ^ sipResponse.getFrom().getTag() == null) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"From tag mismatch -- dropping response\");\n                return;\n            }\n            if (originalFrom != null\n                    && !originalFrom.equalsIgnoreCase(sipResponse.getFrom().getTag())) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"From tag mismatch -- dropping response\");\n                return;\n            }\n\n        }\n        if (sipStack.isDialogCreated(method) && sipResponse.getStatusCode() != 100\n                && sipResponse.getFrom().getTag() != null && sipResponse.getTo().getTag() != null\n                && sipDialog == null) {\n            if (sipProvider.isAutomaticDialogSupportEnabled()) {\n                if (this.transactionChannel != null) {\n                    if (sipDialog == null) {\n                        // There could be an existing dialog for this response.\n                        sipDialog = sipStack.createDialog(\n                                (SIPClientTransaction) this.transactionChannel, sipResponse);\n\n                        this.transactionChannel.setDialog(sipDialog, sipResponse\n                                .getDialogId(false));\n                    }\n                } else {\n                    sipDialog = this.sipStack.createDialog(sipProvider, sipResponse);\n                }\n            }\n\n        } else {\n            // Have a dialog but could not find transaction.\n            if (sipDialog != null && transaction == null\n                    && sipDialog.getState() != DialogState.TERMINATED) {\n                if (sipResponse.getStatusCode() / 100 != 2) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\n                                \"status code != 200 ; statusCode = \"\n                                        + sipResponse.getStatusCode());\n                } else if (sipDialog.getState() == DialogState.TERMINATED) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Dialog is terminated -- dropping response!\");\n                    }\n                    // Dialog exists but was terminated - just create and send an ACK for the OK.\n                    // It could be late arriving.\n                    if (sipResponse.getStatusCode() / 100 == 2\n                            && sipResponse.getCSeq().getMethod().equals(Request.INVITE)) {\n                        try {\n                            Request ackRequest = sipDialog.createAck(sipResponse.getCSeq()\n                                    .getSeqNumber());\n                            sipDialog.sendAck(ackRequest);\n                        } catch (Exception ex) {\n                            sipStack.getStackLogger().logError(\"Error creating ack\", ex);\n                        }\n                    }\n                    return;\n                } else {\n                    boolean ackAlreadySent = false;\n                    if (sipDialog.isAckSeen() && sipDialog.getLastAckSent() != null) {\n                        if (sipDialog.getLastAckSent().getCSeq().getSeqNumber() == sipResponse\n                                .getCSeq().getSeqNumber()\n                                && sipResponse.getDialogId(false).equals(\n                                        sipDialog.getLastAckSent().getDialogId(false))) {\n                            // the last ack sent corresponded to this 200\n                            ackAlreadySent = true;\n                        }\n                    }\n                    // 200 retransmission for the final response.\n                    if (ackAlreadySent\n                            && sipResponse.getCSeq().getMethod().equals(sipDialog.getMethod())) {\n                        try {\n                            // Found the dialog - resend the ACK and\n                            // dont pass up the null transaction\n                            if (sipStack.isLoggingEnabled())\n                                sipStack.getStackLogger().logDebug(\"resending ACK\");\n\n                            sipDialog.resendAck();\n                            return;\n                        } catch (SipException ex) {\n                            // What to do here ?? kill the dialog?\n                        }\n                    }\n                }\n            }\n            // Pass the response up to the application layer to handle\n            // statelessly.\n\n        }\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"sending response to TU for processing \");\n\n        if (sipDialog != null && sipResponse.getStatusCode() != 100\n                && sipResponse.getTo().getTag() != null) {\n            sipDialog.setLastResponse(transaction, sipResponse);\n        }\n\n        ResponseEventExt responseEvent = new ResponseEventExt(sipProvider,\n                (ClientTransactionExt) transaction, sipDialog, (Response) sipResponse);\n\n        if (sipResponse.getCSeq().getMethod().equals(Request.INVITE)) {\n            ClientTransactionExt originalTx = this.sipStack.getForkedTransaction(sipResponse\n                    .getTransactionId());\n            responseEvent.setOriginalTransaction(originalTx);\n        }\n\n        sipProvider.handleEvent(responseEvent, transaction);\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/DialogTimeoutEvent.java",
    "content": "/*\n * This source code has been contributed to the public domain by Mobicents\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.javax2.sip;\n\nimport java.util.EventObject;\n\nimport javax2.sip.Dialog;\n\n/**\n * \n * DialogAckTimeoutEvent is delivered to the Listener when the\n * dialog does not receive or send an ACK. \n *\n * \n * @author jean deruelle\n * @since v2.0\n *\n */\npublic class DialogTimeoutEvent extends EventObject {\n\tprivate static final long serialVersionUID = -2514000059989311925L;\n\tpublic enum Reason {AckNotReceived, AckNotSent,ReInviteTimeout};\t    \n\t/**\n     * Constructs a DialogTerminatedEvent to indicate a dialog\n     * timeout.\n     *\n     * @param source - the source of TimeoutEvent. \n     * @param dialog - the dialog that timed out.\n     */\n     public DialogTimeoutEvent(Object source, Dialog dialog, Reason reason) {\n         super(source);\n         m_dialog = dialog;\n         m_reason = reason;\n      \n    }\n\n    /**\n     * Gets the Dialog associated with the event. This \n     * enables application developers to access the dialog associated to this \n     * event. \n     * \n     * @return the dialog associated with the response event or null if there is no dialog.\n     * @since v1.2\n     */\n    public Dialog getDialog() {\n        return m_dialog;\n    }    \n    \n    /**\n     * The reason for the Dialog Timeout Event being delivered to the application.\n     * \n     * @return the reason for the timeout event.\n     */\n    public Reason getReason() {\n    \treturn m_reason;\n    }\n     \n    // internal variables\n    private Dialog m_dialog = null;    \n    private Reason m_reason = null;\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/EventScanner.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip;\n\nimport java.util.*;\n\nimport javax2.sip.*;\nimport javax2.sip.message.*;\n\nimport gov2.nist.core.ThreadAuditor;\nimport gov2.nist.javax2.sip.message.*;\nimport gov2.nist.javax2.sip.stack.*;\n\n/* bug fixes SIPQuest communications and Shu-Lin Chen. */\n\n/**\n * Event Scanner to deliver events to the Listener.\n *\n * @version 1.2 $Revision: 1.41 $ $Date: 2009/11/18 02:35:17 $\n *\n * @author M. Ranganathan <br/>\n *\n *\n */\nclass EventScanner implements Runnable {\n\n    private boolean isStopped;\n\n    private int refCount;\n\n    // SIPquest: Fix for deadlocks\n    private LinkedList pendingEvents = new LinkedList();\n\n    private int[] eventMutex = { 0 };\n\n    private SipStackImpl sipStack;\n\n    public void incrementRefcount() {\n        synchronized (eventMutex) {\n            this.refCount++;\n        }\n    }\n\n    public EventScanner(SipStackImpl sipStackImpl) {\n        this.pendingEvents = new LinkedList();\n        Thread myThread = new Thread(this);\n        // This needs to be set to false else the\n        // main thread mysteriously exits.\n        myThread.setDaemon(false);\n\n        this.sipStack = sipStackImpl;\n\n        myThread.setName(\"EventScannerThread\");\n\n        myThread.start();\n\n    }\n\n    public void addEvent(EventWrapper eventWrapper) {\n    \tif (sipStack.isLoggingEnabled())\n    \t\tsipStack.getStackLogger().logDebug(\"addEvent \" + eventWrapper);\n        synchronized (this.eventMutex) {\n\n            pendingEvents.add(eventWrapper);\n\n            // Add the event into the pending events list\n\n            eventMutex.notify();\n        }\n\n    }\n\n    /**\n     * Stop the event scanner. Decrement the reference count and exit the\n     * scanner thread if the ref count goes to 0.\n     */\n\n    public void stop() {\n        synchronized (eventMutex) {\n\n            if (this.refCount > 0)\n                this.refCount--;\n\n            if (this.refCount == 0) {\n                isStopped = true;\n                eventMutex.notify();\n\n            }\n        }\n    }\n\n    /**\n     * Brutally stop the event scanner. This does not wait for the refcount to\n     * go to 0.\n     *\n     */\n    public void forceStop() {\n        synchronized (this.eventMutex) {\n            this.isStopped = true;\n            this.refCount = 0;\n            this.eventMutex.notify();\n        }\n\n    }\n\n    public void deliverEvent(EventWrapper eventWrapper) {\n        EventObject sipEvent = eventWrapper.sipEvent;\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"sipEvent = \" + sipEvent + \"source = \"\n                            + sipEvent.getSource());\n        SipListener sipListener = null;\n\n        if (!(sipEvent instanceof IOExceptionEvent)) {\n            sipListener = ((SipProviderImpl) sipEvent.getSource()).getSipListener();\n        } else {\n            sipListener = sipStack.getSipListener();\n        }\n\n        if (sipEvent instanceof RequestEvent) {\n            try {\n                // Check if this request has already created a\n                // transaction\n                SIPRequest sipRequest = (SIPRequest) ((RequestEvent) sipEvent)\n                        .getRequest();\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"deliverEvent : \"\n                                    + sipRequest.getFirstLine()\n                                    + \" transaction \"\n                                    + eventWrapper.transaction\n                                    + \" sipEvent.serverTx = \"\n                                    + ((RequestEvent) sipEvent)\n                                            .getServerTransaction());\n                }\n\n                // Discard the duplicate request if a\n                // transaction already exists. If the listener chose\n                // to handle the request statelessly, then the listener\n                // will see the retransmission.\n                // Note that in both of these two cases, JAIN SIP will allow\n                // you to handle the request statefully or statelessly.\n                // An example of the latter case is REGISTER and an example\n                // of the former case is INVITE.\n\n                SIPServerTransaction tx = (SIPServerTransaction) sipStack\n                        .findTransaction(sipRequest, true);\n\n                if (tx != null && !tx.passToListener()) {\n\n                    // JvB: make an exception for a very rare case: some\n                    // (broken) UACs use\n                    // the same branch parameter for an ACK. Such an ACK should\n                    // be passed\n                    // to the listener (tx == INVITE ST, terminated upon sending\n                    // 2xx but\n                    // lingering to catch retransmitted INVITEs)\n                    if (sipRequest.getMethod().equals(Request.ACK)\n                            && tx.isInviteTransaction() &&\n                            ( tx.getLastResponse().getStatusCode()/100 == 2 ||\n                                sipStack.isNon2XXAckPassedToListener())) {\n\n                        if (sipStack.isLoggingEnabled())\n                            sipStack\n                                    .getStackLogger()\n                                    .logDebug(\n                                            \"Detected broken client sending ACK with same branch! Passing...\");\n                    } else {\n                        if (sipStack.isLoggingEnabled())\n                            sipStack.getStackLogger().logDebug(\n                                    \"transaction already exists! \" + tx);\n                        return;\n                    }\n                } else if (sipStack.findPendingTransaction(sipRequest) != null) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\n                                \"transaction already exists!!\");\n\n                    return;\n                } else {\n                    // Put it in the pending list so that if a repeat\n                    // request comes along it will not get assigned a\n                    // new transaction\n                    SIPServerTransaction st = (SIPServerTransaction) eventWrapper.transaction;\n                    sipStack.putPendingTransaction(st);\n                }\n\n                // Set up a pointer to the transaction.\n                sipRequest.setTransaction(eventWrapper.transaction);\n                // Change made by SIPquest\n                try {\n\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger()\n                                .logDebug(\n                                        \"Calling listener \"\n                                                + sipRequest.getFirstLine());\n                        sipStack.getStackLogger().logDebug(\n                                \"Calling listener \" + eventWrapper.transaction);\n                    }\n                    if (sipListener != null)\n                        sipListener.processRequest((RequestEvent) sipEvent);\n\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Done processing Message \"\n                                        + sipRequest.getFirstLine());\n                    }\n                    if (eventWrapper.transaction != null) {\n\n                        SIPDialog dialog = (SIPDialog) eventWrapper.transaction\n                                .getDialog();\n                        if (dialog != null)\n                            dialog.requestConsumed();\n\n                    }\n                } catch (Exception ex) {\n                    // We cannot let this thread die under any\n                    // circumstances. Protect ourselves by logging\n                    // errors to the console but continue.\n                    sipStack.getStackLogger().logException(ex);\n                }\n            } finally {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"Done processing Message \"\n                                    + ((SIPRequest) (((RequestEvent) sipEvent)\n                                            .getRequest())).getFirstLine());\n                }\n                if (eventWrapper.transaction != null\n                        && ((SIPServerTransaction) eventWrapper.transaction)\n                                .passToListener()) {\n                    ((SIPServerTransaction) eventWrapper.transaction)\n                            .releaseSem();\n                }\n\n                if (eventWrapper.transaction != null)\n                    sipStack\n                            .removePendingTransaction((SIPServerTransaction) eventWrapper.transaction);\n                if (eventWrapper.transaction.getOriginalRequest().getMethod()\n                        .equals(Request.ACK)) {\n                    // Set the tx state to terminated so it is removed from the\n                    // stack\n                    // if the user configured to get notification on ACK\n                    // termination\n                    eventWrapper.transaction\n                            .setState(TransactionState.TERMINATED);\n                }\n            }\n\n        } else if (sipEvent instanceof ResponseEvent) {\n            try {\n                ResponseEvent responseEvent = (ResponseEvent) sipEvent;\n                SIPResponse sipResponse = (SIPResponse) responseEvent\n                        .getResponse();\n                SIPDialog sipDialog = ((SIPDialog) responseEvent.getDialog());\n                try {\n                    if (sipStack.isLoggingEnabled()) {\n\n                        sipStack.getStackLogger().logDebug(\n                                \"Calling listener for \"\n                                        + sipResponse.getFirstLine());\n                    }\n                    if (sipListener != null) {\n                        SIPTransaction tx = eventWrapper.transaction;\n                        if (tx != null) {\n                            tx.setPassToListener();\n                        }\n                        sipListener.processResponse((ResponseEvent) sipEvent);\n                    }\n\n                    /*\n                     * If the response for a request within a dialog is a 481\n                     * (Call/Transaction Does Not Exist) or a 408 (Request\n                     * Timeout), the UAC SHOULD terminate the dialog.\n                     */\n                    if ((sipDialog != null && (sipDialog.getState() == null || !sipDialog\n                            .getState().equals(DialogState.TERMINATED)))\n                            && (sipResponse.getStatusCode() == Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST || sipResponse\n                                    .getStatusCode() == Response.REQUEST_TIMEOUT)) {\n                        if (sipStack.isLoggingEnabled()) {\n                            sipStack.getStackLogger().logDebug(\n                                    \"Removing dialog on 408 or 481 response\");\n                        }\n                        sipDialog.doDeferredDelete();\n                    }\n\n                    /*\n                     * The Client tx disappears after the first 2xx response\n                     * However, additional 2xx responses may arrive later for\n                     * example in the following scenario:\n                     *\n                     * Multiple 2xx responses may arrive at the UAC for a single\n                     * INVITE request due to a forking proxy. Each response is\n                     * distinguished by the tag parameter in the To header\n                     * field, and each represents a distinct dialog, with a\n                     * distinct dialog identifier.\n                     *\n                     * If the Listener does not ACK the 200 then we assume he\n                     * does not care about the dialog and gc the dialog after\n                     * some time. However, this is really an application bug.\n                     * This garbage collects unacknowledged dialogs.\n                     *\n                     */\n                    if (sipResponse.getCSeq().getMethod()\n                            .equals(Request.INVITE)\n                            && sipDialog != null\n                            && sipResponse.getStatusCode() == 200) {\n                        if (sipStack.isLoggingEnabled()) {\n                            sipStack.getStackLogger().logDebug(\n                                    \"Warning! unacknowledged dialog. \" + sipDialog.getState());\n                        }\n                        /*\n                         * If we dont see an ACK in 32 seconds, we want to tear down the dialog.\n                         */\n                        sipDialog.doDeferredDeleteIfNoAckSent(sipResponse.getCSeq().getSeqNumber());\n                    }\n                } catch (Exception ex) {\n                    // We cannot let this thread die under any\n                    // circumstances. Protect ourselves by logging\n                    // errors to the console but continue.\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger().logException(ex);\n                }\n                // The original request is not needed except for INVITE\n                // transactions -- null the pointers to the transactions so\n                // that state may be released.\n                SIPClientTransaction ct = (SIPClientTransaction) eventWrapper.transaction;\n                if (ct != null\n                        && TransactionState.COMPLETED == ct.getState()\n                        && ct.getOriginalRequest() != null\n                        && !ct.getOriginalRequest().getMethod().equals(\n                                Request.INVITE)) {\n                    // reduce the state to minimum\n                    // This assumes that the application will not need\n                    // to access the request once the transaction is\n                    // completed.\n                    ct.clearState();\n                }\n                // mark no longer in the event queue.\n            } finally {\n                if (eventWrapper.transaction != null\n                        && eventWrapper.transaction.passToListener()) {\n                    eventWrapper.transaction.releaseSem();\n                }\n            }\n\n        } else if (sipEvent instanceof TimeoutEvent) {\n            // Change made by SIPquest\n            try {\n                // Check for null as listener could be removed.\n                if (sipListener != null)\n                    sipListener.processTimeout((TimeoutEvent) sipEvent);\n            } catch (Exception ex) {\n                // We cannot let this thread die under any\n                // circumstances. Protect ourselves by logging\n                // errors to the console but continue.\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logException(ex);\n            }\n\n        } else if (sipEvent instanceof DialogTimeoutEvent) {\n            try {\n                // Check for null as listener could be removed.\n                if (sipListener != null && sipListener instanceof SipListenerExt) {\n                    ((SipListenerExt)sipListener).processDialogTimeout((DialogTimeoutEvent) sipEvent);                    \n                }\n            } catch (Exception ex) {\n                // We cannot let this thread die under any\n                // circumstances. Protect ourselves by logging\n                // errors to the console but continue.\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logException(ex);\n            }\n\n        } else if (sipEvent instanceof IOExceptionEvent) {\n            try {\n                if (sipListener != null)\n                    sipListener.processIOException((IOExceptionEvent) sipEvent);\n            } catch (Exception ex) {\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logException(ex);\n            }\n        } else if (sipEvent instanceof TransactionTerminatedEvent) {\n            try {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"About to deliver transactionTerminatedEvent\");\n                    sipStack.getStackLogger().logDebug(\n                            \"tx = \"\n                                    + ((TransactionTerminatedEvent) sipEvent)\n                                            .getClientTransaction());\n                    sipStack.getStackLogger().logDebug(\n                            \"tx = \"\n                                    + ((TransactionTerminatedEvent) sipEvent)\n                                            .getServerTransaction());\n\n                }\n                if (sipListener != null)\n                    sipListener\n                            .processTransactionTerminated((TransactionTerminatedEvent) sipEvent);\n            } catch (AbstractMethodError ame) {\n                // JvB: for backwards compatibility, accept this\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack\n                        .getStackLogger()\n                        .logWarning(\n                                \"Unable to call sipListener.processTransactionTerminated\");\n            } catch (Exception ex) {\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logException(ex);\n            }\n        } else if (sipEvent instanceof DialogTerminatedEvent) {\n            try {\n                if (sipListener != null)\n                    sipListener\n                            .processDialogTerminated((DialogTerminatedEvent) sipEvent);\n            } catch (AbstractMethodError ame) {\n                // JvB: for backwards compatibility, accept this\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logWarning(\n                        \"Unable to call sipListener.processDialogTerminated\");\n            } catch (Exception ex) {\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logException(ex);\n            }\n        } else {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logFatalError(\"bad event\" + sipEvent);\n        }\n\n    }\n\n    /**\n     * For the non-re-entrant listener this delivers the events to the listener\n     * from a single queue. If the listener is re-entrant, then the stack just\n     * calls the deliverEvent method above.\n     */\n\n    public void run() {\n        try {\n            // Ask the auditor to monitor this thread\n            ThreadAuditor.ThreadHandle threadHandle = sipStack.getThreadAuditor().addCurrentThread();\n\n            while (true) {\n                EventWrapper eventWrapper = null;\n\n                LinkedList eventsToDeliver;\n                synchronized (this.eventMutex) {\n                    // First, wait for some events to become available.\n                    while (pendingEvents.isEmpty()) {\n                        // There's nothing in the list, check to make sure we\n                        // haven't\n                        // been stopped. If we have, then let the thread die.\n                        if (this.isStopped) {\n                            if (sipStack.isLoggingEnabled())\n                                sipStack.getStackLogger().logDebug(\n                                        \"Stopped event scanner!!\");\n                            return;\n                        }\n\n                        // We haven't been stopped, and the event list is indeed\n                        // rather empty. Wait for some events to come along.\n                        try {\n                            // Send a heartbeat to the thread auditor\n                            threadHandle.ping();\n\n                            // Wait for events (with a timeout)\n                            eventMutex.wait(threadHandle.getPingIntervalInMillisecs());\n                        } catch (InterruptedException ex) {\n                            // Let the thread die a normal death\n                        \tif (sipStack.isLoggingEnabled())\n                        \t\tsipStack.getStackLogger().logDebug(\"Interrupted!\");\n                            return;\n                        }\n                    }\n\n                    // There are events in the 'pending events list' that need\n                    // processing. Hold onto the old 'pending Events' list, but\n                    // make a new one for the other methods to operate on. This\n                    // tap-dancing is to avoid deadlocks and also to ensure that\n                    // the list is not modified while we are iterating over it.\n                    eventsToDeliver = pendingEvents;\n                    pendingEvents = new LinkedList();\n                }\n                ListIterator iterator = eventsToDeliver.listIterator();\n                while (iterator.hasNext()) {\n                    eventWrapper = (EventWrapper) iterator.next();\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Processing \" + eventWrapper + \"nevents \"\n                                        + eventsToDeliver.size());\n                    }\n                    try {\n                        deliverEvent(eventWrapper);\n                    } catch (Exception e) {\n                        if (sipStack.isLoggingEnabled()) {\n                            sipStack.getStackLogger().logError(\n                                    \"Unexpected exception caught while delivering event -- carrying on bravely\", e);\n                        }\n                    }\n                }\n            } // end While\n        } finally {\n            if (sipStack.isLoggingEnabled()) {\n                if (!this.isStopped) {\n                    sipStack.getStackLogger().logFatalError(\"Event scanner exited abnormally\");\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/EventWrapper.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.javax2.sip.stack.*;\n\nimport  java.util.*;\n\n/**\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:19 $\n */\nclass EventWrapper {\n\n    protected EventObject sipEvent;\n    protected SIPTransaction transaction;\n\n    EventWrapper(EventObject sipEvent, SIPTransaction transaction) {\n        this.sipEvent = sipEvent;\n        this.transaction = transaction;\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/ListeningPointExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport java.io.IOException;\n\nimport javax2.sip.ListeningPoint;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ViaHeader;\n\npublic interface ListeningPointExt extends ListeningPoint {\n\n    /**\n     * Create a contact for this listening point.\n     *\n     * @return a contact header corresponding to this listening point.\n     *\n     * @since 2.0\n     *\n     */\n\n    ContactHeader createContactHeader() ;\n\n    /**\n     * Send a heartbeat to the specified Ip address and port\n     * via this listening point. This method can be used to send out a period\n     * CR-LF for NAT keepalive.\n     *\n     * @since 2.0\n     */\n    public void sendHeartbeat(String ipAddress, int port) throws IOException ;\n    \n    /**\n     * Create a Via header for this listening point.\n     * \n     * @return a via header corresponding to this listening point. Branch ID is set to NULL.\n     * \n     * @since 2.0\n     */\n    public ViaHeader createViaHeader();\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/ListeningPointImpl.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.text.ParseException;\n\nimport javax2.sip.*;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ViaHeader;\n\nimport gov2.nist.core.Host;\nimport gov2.nist.core.HostPort;\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.header.Contact;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.stack.*;\n\n/**\n * Implementation of the ListeningPoint interface\n *\n * @version 1.2 $Revision: 1.15 $ $Date: 2009/11/19 05:26:58 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ListeningPointImpl implements javax2.sip.ListeningPoint, gov2.nist.javax2.sip.ListeningPointExt {\n\n\n    protected String transport;\n\n    /** My port. (same thing as in the message processor) */\n\n    int port;\n\n    /**\n     * Pointer to the imbedded mesage processor.\n     */\n    protected MessageProcessor messageProcessor;\n\n    /**\n     * Provider back pointer\n     */\n    protected SipProviderImpl sipProvider;\n\n    /**\n     * Our stack\n     */\n    protected SipStackImpl sipStack;\n\n\n\n\n    /**\n     * Construct a key to refer to this structure from the SIP stack\n     * @param host host string\n     * @param port port\n     * @param transport transport\n     * @return a string that is used as a key\n     */\n    public static String makeKey(String host, int port, String transport) {\n        return new StringBuffer(host)\n            .append(\":\")\n            .append(port)\n            .append(\"/\")\n            .append(transport)\n            .toString()\n            .toLowerCase();\n    }\n\n    /**\n     * Get the key for this strucut\n     * @return  get the host\n     */\n    protected String getKey() {\n        return makeKey(this.getIPAddress(), port, transport);\n    }\n\n    /**\n     * Set the sip provider for this structure.\n     * @param sipProvider provider to set\n     */\n    protected void setSipProvider(SipProviderImpl sipProviderImpl) {\n        this.sipProvider = sipProviderImpl;\n    }\n\n    /**\n     * Remove the sip provider from this listening point.\n     */\n    protected void removeSipProvider() {\n        this.sipProvider = null;\n    }\n\n    /**\n     * Constructor\n     * @param sipStack Our sip stack\n     */\n    protected ListeningPointImpl(\n        SipStack sipStack,\n        int port,\n        String transport) {\n        this.sipStack = (SipStackImpl) sipStack;\n\n        this.port = port;\n        this.transport = transport;\n\n    }\n\n    /**\n     * Clone this listening point. Note that a message Processor is not\n     * started. The transport is set to null.\n     * @return cloned listening point.\n     */\n    public Object clone() {\n        ListeningPointImpl lip =\n            new ListeningPointImpl(this.sipStack, this.port, null);\n        lip.sipStack = this.sipStack;\n        return lip;\n    }\n\n\n\n    /**\n     * Gets the port of the ListeningPoint. The default port of a ListeningPoint\n     * is dependent on the scheme and transport.  For example:\n     * <ul>\n     * <li>The default port is 5060 if the transport UDP the scheme is <i>sip:</i>.\n     * <li>The default port is 5060 if the transport is TCP the scheme is <i>sip:</i>.\n     * <li>The default port is 5060 if the transport is SCTP the scheme is <i>sip:</i>.\n     * <li>The default port is 5061 if the transport is TLS over TCP the scheme is <i>sip:</i>.\n     * <li>The default port is 5061 if the transport is TCP the scheme is <i>sips:</i>.\n     * </ul>\n     *\n     * @return port of ListeningPoint\n     */\n    public int getPort() {\n        return messageProcessor.getPort();\n    }\n\n    /**\n     * Gets transport of the ListeningPoint.\n     *\n     * @return transport of ListeningPoint\n     */\n    public String getTransport() {\n        return messageProcessor.getTransport();\n    }\n\n    /**\n     * Get the provider.\n     *\n     * @return the provider.\n     */\n    public SipProviderImpl getProvider() {\n        return this.sipProvider;\n    }\n\n    /* (non-Javadoc)\n     * @see javax2.sip.ListeningPoint#getIPAddress()\n     */\n    public String getIPAddress() {\n\n        return this.messageProcessor.getIpAddress().getHostAddress();\n    }\n\n\n\n    /* (non-Javadoc)\n     * @see javax2.sip.ListeningPoint#setSentBy(java.lang.String)\n     */\n    public void setSentBy(String sentBy) throws ParseException {\n        this.messageProcessor.setSentBy(sentBy);\n\n    }\n\n    /* (non-Javadoc)\n     * @see javax2.sip.ListeningPoint#getSentBy()\n     */\n    public String getSentBy() {\n\n        return this.messageProcessor.getSentBy();\n    }\n\n    public boolean isSentBySet() {\n        return this.messageProcessor.isSentBySet();\n    }\n    public Via getViaHeader() {\n        return this.messageProcessor.getViaHeader();\n     }\n\n    public MessageProcessor getMessageProcessor() {\n        return this.messageProcessor;\n    }\n\n    public ContactHeader createContactHeader() {\n        try {\n            String ipAddress = this.getIPAddress();\n            int port = this.getPort();\n            SipURI sipURI = new SipUri();\n            sipURI.setHost(ipAddress);\n            sipURI.setPort(port);\n            sipURI.setTransportParam(this.transport);\n            Contact contact = new Contact();\n            AddressImpl address = new AddressImpl();\n            address.setURI(sipURI);\n            contact.setAddress(address);\n            \n            return contact;\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(\"Unexpected exception\",sipStack.getStackLogger());\n            return null;\n        }\n    }\n\n\n    public void sendHeartbeat(String ipAddress, int port) throws IOException {\n\n        HostPort targetHostPort  = new HostPort();\n        targetHostPort.setHost(new Host( ipAddress));\n        targetHostPort.setPort(port);\n        MessageChannel messageChannel = this.messageProcessor.createMessageChannel(targetHostPort);\n        SIPRequest siprequest = new SIPRequest();\n        siprequest.setNullRequest();\n        messageChannel.sendMessage(siprequest);\n\n    }\n\n    \n    public ViaHeader createViaHeader() {\n           return this.getViaHeader();\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/LogRecord.java",
    "content": "package gov2.nist.javax2.sip;\n\n/**\n * The interface for a log record. The log records are generated by calling the\n * LogReocrdFactory instance that is registered with the stack.\n *\n * @author M. Ranganathan\n *\n */\npublic interface LogRecord {\n\n    public abstract boolean equals(Object other);\n\n    /**\n     * Get an XML String for this message\n     */\n\n    public abstract String toString();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/LogRecordFactory.java",
    "content": "package gov2.nist.javax2.sip;\n\n\n/**\n * The stack calls the message log factory to create logging records. The default implementatation\n * of this interface can be replaced using the gov2.nist.javax2.sip.LOG_RECORD_FACTORY property.\n * This override is provided to allow applications to log axuiliary information (such as environment\n * conditions etc) when messages are logged in the stack.\n *\n * @author M. Ranganathan\n *\n */\npublic interface LogRecordFactory {\n\n    /**\n     * Create a log record.\n     *\n     * @param message  -- the message to be logged.\n     * @param source   -- host:port of the source of the message.\n     * @param destination -- host:port of the destination of the message.\n     * @param timeStamp  -- The time at which this message was seen by the stack or sent out by\n     *                      the stack.\n     * @param isSender   -- true if we are sending the message false otherwise.\n     * @param firstLine  -- the first line of the message to be logged.\n     * @param tid -- the transaction id\n     * @param callId -- the call id\n     * @param timestampVal -- the timestamp header value of the incoming message.\n     *\n     * @return -- a log record with the appropriate fields set.\n     */\n\n\n    public LogRecord createLogRecord(String message, String source,\n            String destination, long timeStamp, boolean isSender,\n            String firstLine, String tid, String callId, long timestampVal);\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/NistSipMessageFactoryImpl.java",
    "content": "/*\n* Conditions Of Use \n* \n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n* \n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n* \n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*  \n* .\n* \n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\n\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.javax2.sip.message.*;\nimport gov2.nist.javax2.sip.stack.*;\n\nimport javax2.sip.*;\n\n/**\n * Implements all the support classes that are necessary for the nist-sip stack\n * on which the jain-sip stack has been based. This is a mapping class to map\n * from the NIST-SIP abstractions to the JAIN abstractions. (i.e. It is the glue\n * code that ties the NIST-SIP event model and the JAIN-SIP event model\n * together. When a SIP Request or SIP Response is read from the corresponding\n * messageChannel, the NIST-SIP stack calls the SIPStackMessageFactory\n * implementation that has been registered with it to process the request.)\n * \n * @version 1.2 $Revision: 1.14 $ $Date: 2009/07/29 20:38:17 $\n * \n * @author M. Ranganathan <br/>\n * \n *  \n */\nclass NistSipMessageFactoryImpl implements StackMessageFactory {\n\n    private SipStackImpl sipStack;\n\n    /**\n     * Construct a new SIP Server Request.\n     * \n     * @param sipRequest\n     *            is the SIPRequest from which the SIPServerRequest is to be\n     *            constructed.\n     * @param messageChannel\n     *            is the MessageChannel abstraction for this SIPServerRequest.\n     */\n    public ServerRequestInterface newSIPServerRequest(SIPRequest sipRequest,\n            MessageChannel messageChannel) {\n\n        if (messageChannel == null || sipRequest == null) {\n            throw new IllegalArgumentException(\"Null Arg!\");\n        }\n\n        SipStackImpl theStack = (SipStackImpl) messageChannel.getSIPStack();\n        DialogFilter retval = new DialogFilter(\n                theStack);\n        if (messageChannel instanceof SIPTransaction) {\n            // If the transaction has already been created\n            // then set the transaction channel.\n            retval.transactionChannel = (SIPTransaction) messageChannel;\n        }\n        retval.listeningPoint = messageChannel.getMessageProcessor()\n                .getListeningPoint();\n        if (retval.listeningPoint == null)\n            return null;\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"Returning request interface for \"\n                            + sipRequest.getFirstLine() + \" \" + retval\n                            + \" messageChannel = \" + messageChannel);\n        return retval;\n    }\n\n    /**\n     * Generate a new server response for the stack.\n     * \n     * @param sipResponse\n     *            is the SIPRequest from which the SIPServerRequest is to be\n     *            constructed.\n     * @param messageChannel\n     *            is the MessageChannel abstraction for this SIPServerResponse\n     */\n    public ServerResponseInterface newSIPServerResponse(\n            SIPResponse sipResponse, MessageChannel messageChannel) {\n        SIPTransactionStack theStack = (SIPTransactionStack) messageChannel\n                .getSIPStack();\n        // Tr is null if a transaction is not mapped.\n        SIPTransaction tr = (SIPTransaction) ((SIPTransactionStack) theStack)\n                .findTransaction(sipResponse, false);\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"Found Transaction \" + tr + \" for \" + sipResponse);\n\n        if (tr != null) {\n            // Prune unhealthy responses early if handling statefully.\n            // If the state has not yet been assigned then this is a\n            // spurious response. This was moved up from the transaction\n            // layer for efficiency.\n            if (tr.getState() == null) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"Dropping response - null transaction state\");\n                return null;\n                // Ignore 1xx\n            } else if (TransactionState.COMPLETED == tr.getState()\n                    && sipResponse.getStatusCode() / 100 == 1) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"Dropping response - late arriving \"\n                                    + sipResponse.getStatusCode());\n                return null;\n            }\n        }\n\n        DialogFilter retval = new DialogFilter(\n                sipStack);\n\n        retval.transactionChannel = tr;\n\n        retval.listeningPoint = messageChannel.getMessageProcessor()\n                .getListeningPoint();\n        return retval;\n    }\n\n    public NistSipMessageFactoryImpl(SipStackImpl sipStackImpl) {\n        this.sipStack = sipStackImpl;\n\n    }\n\n}"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/ResponseEventExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.Dialog;\nimport javax2.sip.ResponseEvent;\nimport javax2.sip.message.Response;\n\n/**\n * Extension for ResponseEvent. \n * \n * @since v2.0\n */\npublic class ResponseEventExt extends ResponseEvent {\n    private ClientTransactionExt  m_originalTransaction;\n    public ResponseEventExt(Object source, ClientTransactionExt clientTransaction, \n            Dialog dialog,  Response response) {\n        super(source,clientTransaction,dialog,response);\n        m_originalTransaction = clientTransaction;\n    }\n    \n    /**\n     * Return true if this is a forked response.\n     * \n     * @return true if the response event is for a forked response.\n     */\n    public boolean isForkedResponse() {\n        return super.getClientTransaction() == null && m_originalTransaction != null;\n    }\n    \n    /**\n     * Set the original transaction for a forked response.\n     * \n     * @param originalTransaction - the original transaction for which this response event is a fork.\n     */\n    public void setOriginalTransaction(ClientTransactionExt originalTransaction ) {\n        m_originalTransaction = originalTransaction;\n    }\n    \n    /**\n     * Get the original transaction for which this is a forked response.\n     * Note that this transaction can be in a TERMINATED state.\n     * \n     * @return the original clientTx for which this is a forked response.\n     */\n    public ClientTransactionExt getOriginalTransaction() {\n        return this.m_originalTransaction;\n    }\n    \n    \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/SIPConstants.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n*******************************************************************************/\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * Default constants for SIP.\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:20 $\n */\npublic interface SIPConstants\n    extends\n        SIPHeaderNames,\n        gov2.nist.javax2.sip.address.ParameterNames,\n        gov2.nist.javax2.sip.header.ParameterNames {\n    public static final int DEFAULT_PORT = 5060;\n\n    // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n    public static final int DEFAULT_TLS_PORT = 5061;\n\n    /**\n     * Prefix for the branch parameter that identifies\n     * BIS 09 compatible branch strings. This indicates\n     * that the branch may be as a global identifier for\n     * identifying transactions.\n     */\n    public static final String BRANCH_MAGIC_COOKIE = \"z9hG4bK\";\n\n    public static final String BRANCH_MAGIC_COOKIE_LOWER_CASE = \"z9hg4bk\";\n\n    public static final String BRANCH_MAGIC_COOKIE_UPPER_CASE = \"Z9HG4BK\";\n\n    /**\n     * constant SIP_VERSION_STRING\n     */\n    public static final String SIP_VERSION_STRING = \"SIP/2.0\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/ServerTransactionExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport javax2.sip.ServerTransaction;\n\n\npublic interface ServerTransactionExt extends ServerTransaction, TransactionExt {\n    /**\n     * Return the canceled Invite transaction corresponding to an\n     * incoming CANCEL server transaction.\n     *\n     * @return -- the canceled Invite transaction.\n     *\n     */\n    public ServerTransaction getCanceledInviteTransaction();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/SipListenerExt.java",
    "content": "/*\n * This source code has been contributed to the public domain by Mobicents\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.javax2.sip;\n\nimport javax2.sip.Dialog;\nimport javax2.sip.SipListener;\n\n/**\n * This interface extends the {@link SipListener} interface and adds the following events to it :\n * <ul>\n * <li>{@link DialogTimeoutEvent}- these are timeout notifications emitted as events by the\n * SipProvider. Timeout events represent timers expiring in the underlying SipProvider dialog\n * state machine. These timeout's events notify the application that a dialog has timed out.</li>\n * </ul>\n * \n * @author jean.deruelle@gmail.com\n * \n */\npublic interface SipListenerExt extends SipListener {\n\n    /**\n     * Processes an expiration Timeout of an underlying {@link Dialog} handled by this\n     * SipListener. This Event notifies the application that a dialog Timer expired in the\n     * Dialog's state machine. Such a condition can occur when the application fails to send an\n     * ACK after receiving an OK response or if an ACK is not received after an OK is sent. The\n     * DialogTimeoutEvent encapsulates the specific timeout type and the dialog identifier. The\n     * type of Timeout can by determined by:\n     * <code>timeoutType = timeoutEvent.getTimeout().getValue();</code>\n     * \n     * Applications implementing this method should take care of sending the BYE or terminating\n     * the dialog to avoid any dialog leaks.\n     * \n     * @param timeoutEvent - the timeoutEvent received indicating the dialog timed out.\n     */\n    public void processDialogTimeout(DialogTimeoutEvent timeoutEvent);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/SipProviderExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport javax2.sip.SipProvider;\n\n/**\n * Extensions to SipProvider under consideration for Version 2.0.\n * \n * @since 2.0\n */\n\npublic interface SipProviderExt extends SipProvider {\n    /**\n     * Sets a flag that indicates that automatic error handling is enabled for this dialog (the\n     * default when automatic dialog support is enabled). This flag is set by default to TRUE when\n     * the Dialog is automatically created by the provider ( automatic dialog support is true) and\n     * set to FALSE by default when the Dialog is created under program control ( automatic dialog\n     * support is false). When this flag is set to true, the stack will automatically send the\n     * following errors :\n     * \n     * <ul>\n     * <li> <b>500 Request Out of Order </b> for in-dialog requests that arrive out of order.\n     * <li> <b>482 Loop Detected </b> When a loop is detected for merged INVITE requests.\n     * <li> <b>400 Bad request </b> when a REFER is sent without a matching refer-to dialog.\n     * </ul>\n     * If this flag is set to false, the stack will not drop out of sequence ACKs but will pass\n     * these up to the application for handling.\n     * \n     * This flag is automatically set to true if any of the the following conditions is true:\n     * <ul>\n     * <li>The Back To Back User Agent flag is enabled for the Dialog.</li>\n     * <li>The Automatic Dialog Support flag is enabled for the Dialog </li>\n     * </ul>\n     * \n     * This flag should only be set at the time of Dialog creation ( before the Dialog has seen its first\n     * request or response). If set subsequently, the behavior of the flag is undefined.\n     * \n     * @since 2.0\n     */\n    public void setDialogErrorsAutomaticallyHandled();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/SipProviderImpl.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.DialogTimeoutEvent.Reason;\nimport gov2.nist.javax2.sip.address.RouterExt;\nimport gov2.nist.javax2.sip.header.CallID;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\nimport gov2.nist.javax2.sip.stack.HopImpl;\nimport gov2.nist.javax2.sip.stack.MessageChannel;\nimport gov2.nist.javax2.sip.stack.SIPClientTransaction;\nimport gov2.nist.javax2.sip.stack.SIPDialog;\nimport gov2.nist.javax2.sip.stack.SIPDialogErrorEvent;\nimport gov2.nist.javax2.sip.stack.SIPDialogEventListener;\nimport gov2.nist.javax2.sip.stack.SIPServerTransaction;\nimport gov2.nist.javax2.sip.stack.SIPTransaction;\nimport gov2.nist.javax2.sip.stack.SIPTransactionErrorEvent;\nimport gov2.nist.javax2.sip.stack.SIPTransactionEventListener;\n\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.util.EventObject;\nimport java.util.Iterator;\nimport java.util.TooManyListenersException;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.Dialog;\nimport javax2.sip.DialogState;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.ListeningPoint;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.RequestEvent;\nimport javax2.sip.ResponseEvent;\nimport javax2.sip.ServerTransaction;\nimport javax2.sip.SipException;\nimport javax2.sip.SipListener;\nimport javax2.sip.SipStack;\nimport javax2.sip.Timeout;\nimport javax2.sip.TimeoutEvent;\nimport javax2.sip.Transaction;\nimport javax2.sip.TransactionAlreadyExistsException;\nimport javax2.sip.TransactionState;\nimport javax2.sip.TransactionUnavailableException;\nimport javax2.sip.address.Hop;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/*\n * Contributions (bug fixes) made by: Daniel J. Martinez Manzano, Hagai Sela.\n * Bug reports by Shanti Kadiyala, Rhys Ulerich,Victor Hugo\n */\n/**\n * Implementation of the JAIN-SIP provider interface.\n *\n * @version 1.2 $Revision: 1.82 $ $Date: 2009/11/24 17:16:59 $\n *\n * @author M. Ranganathan <br/>\n *\n *\n */\n\npublic class SipProviderImpl implements javax2.sip.SipProvider, gov2.nist.javax2.sip.SipProviderExt,\n        SIPTransactionEventListener, SIPDialogEventListener {\n\n    private SipListener sipListener;\n\n    protected SipStackImpl sipStack;\n\n    /*\n     * A set of listening points associated with the provider At most one LP per\n     * transport\n     */\n    private ConcurrentHashMap listeningPoints;\n\n    private EventScanner eventScanner;\n\n    private String address;\n\n    private int port;\n\n    private boolean automaticDialogSupportEnabled ; \n    /**\n     * A string containing the 0.0.0.0 IPv4 ANY address.\n     */\n    private String IN_ADDR_ANY = \"0.0.0.0\";\n\n    /**\n     * A string containing the ::0 IPv6 ANY address.\n     */\n    private String IN6_ADDR_ANY = \"::0\";\n\n    private boolean dialogErrorsAutomaticallyHandled = true;\n    \n    private SipProviderImpl() {\n    \t\n    }\n\n    /**\n     * Stop processing messages for this provider. Post an empty message to our\n     * message processing queue that signals us to quit.\n     */\n    protected void stop() {\n        // Put an empty event in the queue and post ourselves a message.\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"Exiting provider\");\n        for (Iterator it = listeningPoints.values().iterator(); it.hasNext();) {\n            ListeningPointImpl listeningPoint = (ListeningPointImpl) it.next();\n            listeningPoint.removeSipProvider();\n        }\n        this.eventScanner.stop();\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getListeningPoint(java.lang.String)\n     */\n    public ListeningPoint getListeningPoint(String transport) {\n        if (transport == null)\n            throw new NullPointerException(\"Null transport param\");\n        return (ListeningPoint) this.listeningPoints.get(transport\n                .toUpperCase());\n    }\n\n    /**\n     * Handle the SIP event - because we have only one listener and we are\n     * already in the context of a separate thread, we dont need to enque the\n     * event and signal another thread.\n     *\n     * @param sipEvent\n     *            is the event to process.\n     *\n     */\n\n    public void handleEvent(EventObject sipEvent, SIPTransaction transaction) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"handleEvent \" + sipEvent + \"currentTransaction = \"\n                            + transaction + \"this.sipListener = \"\n                            + this.getSipListener() + \"sipEvent.source = \"\n                            + sipEvent.getSource());\n            if (sipEvent instanceof RequestEvent) {\n                Dialog dialog = ((RequestEvent) sipEvent).getDialog();\n                if ( sipStack.isLoggingEnabled())  sipStack.getStackLogger().logDebug(\"Dialog = \" + dialog);\n            } else if (sipEvent instanceof ResponseEvent) {\n                Dialog dialog = ((ResponseEvent) sipEvent).getDialog();\n                if (sipStack.isLoggingEnabled() ) sipStack.getStackLogger().logDebug(\"Dialog = \" + dialog);\n            }\n            sipStack.getStackLogger().logStackTrace();\n        }\n\n        EventWrapper eventWrapper = new EventWrapper(sipEvent, transaction);\n\n        if (!sipStack.reEntrantListener) {\n            // Run the event in the context of a single thread.\n            this.eventScanner.addEvent(eventWrapper);\n        } else {\n            // just call the delivery method\n            this.eventScanner.deliverEvent(eventWrapper);\n        }\n    }\n\n    /** Creates a new instance of SipProviderImpl */\n    protected SipProviderImpl(SipStackImpl sipStack) {\n        this.eventScanner = sipStack.getEventScanner(); // for quick access.\n        this.sipStack = sipStack;\n        this.eventScanner.incrementRefcount();\n        this.listeningPoints = new ConcurrentHashMap<String,ListeningPointImpl>();\n        this.automaticDialogSupportEnabled = this.sipStack\n                .isAutomaticDialogSupportEnabled();\n        this.dialogErrorsAutomaticallyHandled = this.sipStack.isAutomaticDialogErrorHandlingEnabled();\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see java.lang.Object#clone()\n     */\n    protected Object clone() throws java.lang.CloneNotSupportedException {\n        throw new java.lang.CloneNotSupportedException();\n    }\n\n    \n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#addSipListener(javax2.sip.SipListener)\n     */\n    public void addSipListener(SipListener sipListener)\n            throws TooManyListenersException {\n\n        if (sipStack.sipListener == null) {\n            sipStack.sipListener = sipListener;\n        } else if (sipStack.sipListener != sipListener) {\n            throw new TooManyListenersException(\n                    \"Stack already has a listener. Only one listener per stack allowed\");\n        }\n\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"add SipListener \" + sipListener);\n        this.sipListener = sipListener;\n\n    }\n\n    /*\n     * This method is deprecated (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getListeningPoint()\n     */\n\n    public ListeningPoint getListeningPoint() {\n        if (this.listeningPoints.size() > 0)\n            return (ListeningPoint) this.listeningPoints.values().iterator()\n                    .next();\n        else\n            return null;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getNewCallId()\n     */\n    public CallIdHeader getNewCallId() {\n        String callId = Utils.getInstance().generateCallIdentifier(this.getListeningPoint()\n                .getIPAddress());\n        CallID callid = new CallID();\n        try {\n            callid.setCallId(callId);\n        } catch (java.text.ParseException ex) {\n        }\n        return callid;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getNewClientTransaction(javax2.sip.message.Request)\n     */\n    public ClientTransaction getNewClientTransaction(Request request)\n            throws TransactionUnavailableException {\n        if (request == null)\n            throw new NullPointerException(\"null request\");\n        if (!sipStack.isAlive())\n            throw new TransactionUnavailableException(\"Stack is stopped\");\n\n        SIPRequest sipRequest = (SIPRequest) request;\n        if (sipRequest.getTransaction() != null)\n            throw new TransactionUnavailableException(\n                    \"Transaction already assigned to request\");\n        if ( sipRequest.getMethod().equals(Request.ACK)) {\n            throw new TransactionUnavailableException (\"Cannot create client transaction for  \" + Request.ACK);\n        }\n        // Be kind and assign a via header for this provider if the user is\n        // sloppy\n        if (sipRequest.getTopmostVia() == null) {\n            ListeningPointImpl lp = (ListeningPointImpl) this\n                    .getListeningPoint(\"udp\");\n            Via via = lp.getViaHeader();\n            request.setHeader(via);\n        }\n        // Give the request a quick check to see if all headers are assigned.\n        try {\n            sipRequest.checkHeaders();\n        } catch (ParseException ex) {\n            throw new TransactionUnavailableException(ex.getMessage(), ex);\n        }\n\n        /*\n         * User decided to give us his own via header branch. Lets see if it\n         * results in a clash. If so reject the request.\n         */\n        if (sipRequest.getTopmostVia().getBranch() != null\n                && sipRequest.getTopmostVia().getBranch().startsWith(\n                        SIPConstants.BRANCH_MAGIC_COOKIE)\n                && sipStack.findTransaction((SIPRequest) request, false) != null) {\n            throw new TransactionUnavailableException(\n                    \"Transaction already exists!\");\n        }\n\n\n\n\n        if (request.getMethod().equalsIgnoreCase(Request.CANCEL)) {\n            SIPClientTransaction ct = (SIPClientTransaction) sipStack\n                    .findCancelTransaction((SIPRequest) request, false);\n            if (ct != null) {\n                ClientTransaction retval = sipStack.createClientTransaction(\n                        (SIPRequest) request, ct.getMessageChannel());\n\n                ((SIPTransaction) retval).addEventListener(this);\n                sipStack.addTransaction((SIPClientTransaction) retval);\n                if (ct.getDialog() != null) {\n                    ((SIPClientTransaction) retval).setDialog((SIPDialog) ct\n                            .getDialog(), sipRequest.getDialogId(false));\n\n                }\n                return retval;\n            }\n\n        }\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"could not find existing transaction for \"\n                            + ((SIPRequest) request).getFirstLine()\n                            + \" creating a new one \");\n\n        // Could not find a dialog or the route is not set in dialog.\n\n        Hop hop = null;\n        try {\n            hop = sipStack.getNextHop((SIPRequest) request);\n            if (hop == null)\n                throw new TransactionUnavailableException(\n                        \"Cannot resolve next hop -- transaction unavailable\");\n        } catch (SipException ex) {\n            throw new TransactionUnavailableException(\n                    \"Cannot resolve next hop -- transaction unavailable\", ex);\n        }\n        String transport = hop.getTransport();\n        ListeningPointImpl listeningPoint = (ListeningPointImpl) this\n                .getListeningPoint(transport);\n\n        String dialogId = sipRequest.getDialogId(false);\n        SIPDialog dialog = sipStack.getDialog(dialogId);\n        if (dialog != null && dialog.getState() == DialogState.TERMINATED) {\n\n            // throw new TransactionUnavailableException\n            // (\"Found a terminated dialog -- possible re-use of old tag\n            // parameters\");\n            sipStack.removeDialog(dialog);\n\n        }\n\n        // An out of dialog route was found. Assign this to the\n        // client transaction.\n\n        try {\n            // Set the brannch id before you ask for a tx.\n            // If the user has set his own branch Id and the\n            // branch id starts with a valid prefix, then take it.\n            // otherwise, generate one. If branch ID checking has \n            // been requested, set the branch ID.\n            String branchId = null;\n            if (sipRequest.getTopmostVia().getBranch() == null\n                    || !sipRequest.getTopmostVia().getBranch().startsWith(\n                            SIPConstants.BRANCH_MAGIC_COOKIE)\n                            || sipStack.checkBranchId() ) {\n                branchId = Utils.getInstance().generateBranchId();\n\n                sipRequest.getTopmostVia().setBranch(branchId);\n            }\n            Via topmostVia = sipRequest.getTopmostVia();\n\n            //set port and transport if user hasn't already done this.\n            if(topmostVia.getTransport() == null)\n                topmostVia.setTransport(transport);\n\n            if(topmostVia.getPort() == -1)\n                topmostVia.setPort(listeningPoint.getPort());\n            branchId = sipRequest.getTopmostVia().getBranch();\n\n            SIPClientTransaction ct = (SIPClientTransaction) sipStack\n                    .createMessageChannel(sipRequest, listeningPoint\n                            .getMessageProcessor(), hop);\n            if (ct == null)\n                throw new TransactionUnavailableException(\"Cound not create tx\");\n            ct.setNextHop(hop);\n            ct.setOriginalRequest(sipRequest);\n            ct.setBranch(branchId);\n            // if the stack supports dialogs then\n            if (sipStack.isDialogCreated(request.getMethod())) {\n                // create a new dialog to contain this transaction\n                // provided this is necessary.\n                // This could be a re-invite\n                // in which case the dialog is re-used.\n                // (but noticed by Brad Templeton)\n                if (dialog != null)\n                    ct.setDialog(dialog, sipRequest.getDialogId(false));\n                else if (this.isAutomaticDialogSupportEnabled()) {\n                    SIPDialog sipDialog = sipStack.createDialog(ct);\n                    ct.setDialog(sipDialog, sipRequest.getDialogId(false));\n                }\n            } else {\n                if (dialog != null) {\n                    ct.setDialog(dialog, sipRequest.getDialogId(false));\n                }\n\n            }\n\n            // The provider is the event listener for all transactions.\n            ct.addEventListener(this);\n            return (ClientTransaction) ct;\n        } catch (IOException ex) {\n\n            throw new TransactionUnavailableException(\n                    \"Could not resolve next hop or listening point unavailable! \",\n                    ex);\n\n        } catch (java.text.ParseException ex) {\n            InternalErrorHandler.handleException(ex);\n            throw new TransactionUnavailableException(\n                    \"Unexpected Exception FIXME! \", ex);\n        } catch (InvalidArgumentException ex) {\n            InternalErrorHandler.handleException(ex);\n            throw new TransactionUnavailableException(\n                    \"Unexpected Exception FIXME! \", ex);\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getNewServerTransaction(javax2.sip.message.Request)\n     */\n    public ServerTransaction getNewServerTransaction(Request request)\n            throws TransactionAlreadyExistsException,\n            TransactionUnavailableException {\n\n        if (!sipStack.isAlive())\n            throw new TransactionUnavailableException(\"Stack is stopped\");\n        SIPServerTransaction transaction = null;\n        SIPRequest sipRequest = (SIPRequest) request;\n        try {\n            sipRequest.checkHeaders();\n        } catch (ParseException ex) {\n            throw new TransactionUnavailableException(ex.getMessage(), ex);\n        }\n\n        if ( request.getMethod().equals(Request.ACK)) {\n            if ( sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logError(\"Creating server transaction for ACK -- makes no sense!\");\n            throw new TransactionUnavailableException(\"Cannot create Server transaction for ACK \");\n        }\n        /*\n         * Got a notify.\n         */\n        if (sipRequest.getMethod().equals(Request.NOTIFY)\n                && sipRequest.getFromTag() != null\n                && sipRequest.getToTag() == null) {\n\n            SIPClientTransaction ct = sipStack.findSubscribeTransaction(\n                    sipRequest, (ListeningPointImpl) this.getListeningPoint());\n            /* Issue 104 */\n            if (ct == null && ! sipStack.deliverUnsolicitedNotify) {\n                throw new TransactionUnavailableException(\n                        \"Cannot find matching Subscription (and gov2.nist.javax2.sip.DELIVER_UNSOLICITED_NOTIFY not set)\");\n            }\n        }\n        if ( !sipStack.acquireSem()) {\n            throw new TransactionUnavailableException(\n            \"Transaction not available -- could not acquire stack lock\");\n        }\n        try {\n            if (sipStack.isDialogCreated(sipRequest.getMethod())) {\n                if (sipStack.findTransaction((SIPRequest) request, true) != null)\n                    throw new TransactionAlreadyExistsException(\n                    \"server transaction already exists!\");\n\n                transaction = (SIPServerTransaction) ((SIPRequest) request)\n                .getTransaction();\n                if (transaction == null)\n                    throw new TransactionUnavailableException(\n                    \"Transaction not available\");\n                if (transaction.getOriginalRequest() == null)\n                    transaction.setOriginalRequest(sipRequest);\n                try {\n                    sipStack.addTransaction(transaction);\n                } catch (IOException ex) {\n                    throw new TransactionUnavailableException(\n                    \"Error sending provisional response\");\n                }\n                // So I can handle timeouts.\n                transaction.addEventListener(this);\n                if (isAutomaticDialogSupportEnabled()) {\n                    // If automatic dialog support is enabled then\n                    // this tx gets his own dialog.\n                    String dialogId = sipRequest.getDialogId(true);\n                    SIPDialog dialog = sipStack.getDialog(dialogId);\n                    if (dialog == null) {\n                        dialog = sipStack.createDialog(transaction);\n\n                    }\n                    transaction.setDialog(dialog, sipRequest.getDialogId(true));\n                    if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) {\n                        sipStack.putInMergeTable(transaction, sipRequest);\n                    }\n                    dialog.addRoute(sipRequest);\n                    if (dialog.getRemoteTag() != null\n                            && dialog.getLocalTag() != null) {\n                        this.sipStack.putDialog(dialog);\n                    }\n                }\n\n            } else {\n                if (isAutomaticDialogSupportEnabled()) {\n                    /*\n                     * Under automatic dialog support, dialog is tied into a transaction. You cannot\n                     * create a server tx except for dialog creating transactions. After that, all\n                     * subsequent transactions are created for you by the stack.\n                     */\n                    transaction = (SIPServerTransaction) sipStack.findTransaction(\n                            (SIPRequest) request, true);\n                    if (transaction != null)\n                        throw new TransactionAlreadyExistsException(\n                        \"Transaction exists! \");\n                    transaction = (SIPServerTransaction) ((SIPRequest) request)\n                    .getTransaction();\n                    if (transaction == null)\n                        throw new TransactionUnavailableException(\n                        \"Transaction not available!\");\n                    if (transaction.getOriginalRequest() == null)\n                        transaction.setOriginalRequest(sipRequest);\n                    // Map the transaction.\n                    try {\n                        sipStack.addTransaction(transaction);\n                    } catch (IOException ex) {\n                        throw new TransactionUnavailableException(\n                        \"Could not send back provisional response!\");\n                    }\n\n                    // If there is a dialog already assigned then just update the\n                    // dialog state.\n                    String dialogId = sipRequest.getDialogId(true);\n                    SIPDialog dialog = sipStack.getDialog(dialogId);\n                    if (dialog != null) {\n                        dialog.addTransaction(transaction);\n                        dialog.addRoute(sipRequest);\n                        transaction.setDialog(dialog, sipRequest.getDialogId(true));\n                    }\n\n                } else {\n                    transaction = (SIPServerTransaction) sipStack.findTransaction(\n                            (SIPRequest) request, true);\n                    if (transaction != null)\n                        throw new TransactionAlreadyExistsException(\n                        \"Transaction exists! \");\n                    transaction = (SIPServerTransaction) ((SIPRequest) request)\n                    .getTransaction();\n                    if (transaction != null) {\n                        if (transaction.getOriginalRequest() == null)\n                            transaction.setOriginalRequest(sipRequest);\n                        // Map the transaction.\n                        sipStack.mapTransaction(transaction);\n\n                        // If there is a dialog already assigned then just\n                        // assign the dialog to the transaction.\n                        String dialogId = sipRequest.getDialogId(true);\n                        SIPDialog dialog = sipStack.getDialog(dialogId);\n                        if (dialog != null) {\n                            dialog.addTransaction(transaction);\n                            dialog.addRoute(sipRequest);\n                            transaction.setDialog(dialog, sipRequest\n                                    .getDialogId(true));\n                        }\n\n                        return transaction;\n                    } else {\n                        // tx does not exist so create the tx.\n\n                        MessageChannel mc = (MessageChannel) sipRequest\n                        .getMessageChannel();\n                        transaction = sipStack.createServerTransaction(mc);\n                        if (transaction == null)\n                            throw new TransactionUnavailableException(\n                            \"Transaction unavailable -- too many servrer transactions\");\n\n                        transaction.setOriginalRequest(sipRequest);\n                        sipStack.mapTransaction(transaction);\n\n                        // If there is a dialog already assigned then just\n                        // assign the dialog to the transaction.\n                        String dialogId = sipRequest.getDialogId(true);\n                        SIPDialog dialog = sipStack.getDialog(dialogId);\n                        if (dialog != null) {\n                            dialog.addTransaction(transaction);\n                            dialog.addRoute(sipRequest);\n                            transaction.setDialog(dialog, sipRequest\n                                    .getDialogId(true));\n                        }\n\n                        return transaction;\n                    }\n                }\n\n            }\n            return transaction;\n        } finally {\n            sipStack.releaseSem();\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getSipStack()\n     */\n    public SipStack getSipStack() {\n        return (SipStack) this.sipStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#removeSipListener(javax2.sip.SipListener)\n     */\n    public void removeSipListener(SipListener sipListener) {\n        if (sipListener == this.getSipListener()) {\n            this.sipListener = null;\n        }\n\n        boolean found = false;\n\n        for (Iterator<SipProviderImpl> it = sipStack.getSipProviders(); it.hasNext();) {\n            SipProviderImpl nextProvider = (SipProviderImpl) it.next();\n            if (nextProvider.getSipListener() != null)\n                found = true;\n        }\n        if (!found) {\n            sipStack.sipListener = null;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#sendRequest(javax2.sip.message.Request)\n     */\n    public void sendRequest(Request request) throws SipException {\n        if (!sipStack.isAlive())\n            throw new SipException(\"Stack is stopped.\");\n\n        // mranga: added check to ensure we are not sending empty (keepalive)\n        // message.\n        if (((SIPRequest) request).getRequestLine() != null\n                && request.getMethod().equals(Request.ACK)) {\n            Dialog dialog = sipStack.getDialog(((SIPRequest) request)\n                    .getDialogId(false));\n            if (dialog != null && dialog.getState() != null) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logWarning(\n                        \"Dialog exists -- you may want to use Dialog.sendAck() \"\n                                + dialog.getState());\n            }\n        }\n        Hop hop = sipStack.getRouter((SIPRequest) request).getNextHop(request);\n        if (hop == null)\n            throw new SipException(\"could not determine next hop!\");\n        SIPRequest sipRequest = (SIPRequest) request;\n        // Check if we have a valid via.\n        // Null request is used to send default proxy keepalive messages.\n        if ((!sipRequest.isNullRequest()) && sipRequest.getTopmostVia() == null)\n            throw new SipException(\"Invalid SipRequest -- no via header!\");\n\n        try {\n            /*\n             * JvB: Via branch should already be OK, dont touch it here? Some\n             * apps forward statelessly, and then it's not set. So set only when\n             * not set already, dont overwrite CANCEL branch here..\n             */\n            if (!sipRequest.isNullRequest()) {\n                Via via = sipRequest.getTopmostVia();\n                String branch = via.getBranch();\n                if (branch == null || branch.length() == 0) {\n                    via.setBranch(sipRequest.getTransactionId());\n                }\n            }\n            MessageChannel messageChannel = null;\n            if (this.listeningPoints.containsKey(hop.getTransport()\n                    .toUpperCase()))\n                messageChannel = sipStack.createRawMessageChannel(\n                        this.getListeningPoint(hop.getTransport()).getIPAddress(),\n                        this.getListeningPoint(hop.getTransport()).getPort(), hop);\n            if (messageChannel != null) {\n                messageChannel.sendMessage((SIPMessage) sipRequest,hop);\n            } else {\n                throw new SipException(\n                        \"Could not create a message channel for \"\n                                + hop.toString());\n            }\n        } catch (IOException ex) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logException(ex);\n            }\n\n            throw new SipException(\n                    \"IO Exception occured while Sending Request\", ex);\n\n        } catch (ParseException ex1) {\n            InternalErrorHandler.handleException(ex1);\n        } finally {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"done sending \" + request.getMethod() + \" to hop \"\n                                + hop);\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#sendResponse(javax2.sip.message.Response)\n     */\n    public void sendResponse(Response response) throws SipException {\n        if (!sipStack.isAlive())\n            throw new SipException(\"Stack is stopped\");\n        SIPResponse sipResponse = (SIPResponse) response;\n        Via via = sipResponse.getTopmostVia();\n        if (via == null)\n            throw new SipException(\"No via header in response!\");\n        SIPServerTransaction st = (SIPServerTransaction) sipStack.findTransaction((SIPMessage)response, true);\n        if ( st != null   && st.getState() != TransactionState.TERMINATED && this.isAutomaticDialogSupportEnabled()) {\n            throw new SipException(\"Transaction exists -- cannot send response statelessly\");\n        }\n        String transport = via.getTransport();\n\n        // check to see if Via has \"received paramaeter\". If so\n        // set the host to the via parameter. Else set it to the\n        // Via host.\n        String host = via.getReceived();\n\n        if (host == null)\n            host = via.getHost();\n\n        // Symmetric nat support\n        int port = via.getRPort();\n        if (port == -1) {\n            port = via.getPort();\n            if (port == -1) {\n                if (transport.equalsIgnoreCase(\"TLS\"))\n                    port = 5061;\n                else\n                    port = 5060;\n            }\n        }\n\n        // for correct management of IPv6 addresses.\n        if (host.indexOf(\":\") > 0)\n            if (host.indexOf(\"[\") < 0)\n                host = \"[\" + host + \"]\";\n\n        Hop hop = sipStack.getAddressResolver().resolveAddress(\n                new HopImpl(host, port, transport));\n\n        try {\n            ListeningPointImpl listeningPoint = (ListeningPointImpl) this\n                    .getListeningPoint(transport);\n            if (listeningPoint == null)\n                throw new SipException(\n                        \"whoopsa daisy! no listening point found for transport \"\n                                + transport);\n            MessageChannel messageChannel = sipStack.createRawMessageChannel(\n                    this.getListeningPoint(hop.getTransport()).getIPAddress(),\n                    listeningPoint.port, hop);\n            messageChannel.sendMessage(sipResponse);\n        } catch (IOException ex) {\n            throw new SipException(ex.getMessage());\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#setListeningPoint(javax2.sip.ListeningPoint)\n     */\n    public synchronized void setListeningPoint(ListeningPoint listeningPoint) {\n        if (listeningPoint == null)\n            throw new NullPointerException(\"Null listening point\");\n        ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;\n        lp.sipProvider = this;\n        String transport = lp.getTransport().toUpperCase();\n        this.address = listeningPoint.getIPAddress();\n        this.port = listeningPoint.getPort();\n        // This is the first listening point.\n        this.listeningPoints.clear();\n        this.listeningPoints.put(transport, listeningPoint);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getNewDialog(javax2.sip.Transaction)\n     */\n\n    public Dialog getNewDialog(Transaction transaction) throws SipException {\n        if (transaction == null)\n            throw new NullPointerException(\"Null transaction!\");\n\n        if (!sipStack.isAlive())\n            throw new SipException(\"Stack is stopped.\");\n\n        if (isAutomaticDialogSupportEnabled())\n            throw new SipException(\" Error - AUTOMATIC_DIALOG_SUPPORT is on\");\n\n        if (!sipStack.isDialogCreated(transaction.getRequest().getMethod()))\n            throw new SipException(\"Dialog cannot be created for this method \"\n                    + transaction.getRequest().getMethod());\n\n        SIPDialog dialog = null;\n        SIPTransaction sipTransaction = (SIPTransaction) transaction;\n\n        if (transaction instanceof ServerTransaction) {\n            SIPServerTransaction st = (SIPServerTransaction) transaction;\n            Response response = st.getLastResponse();\n            if (response != null) {\n                if (response.getStatusCode() != 100)\n                    throw new SipException(\n                            \"Cannot set dialog after response has been sent\");\n            }\n            SIPRequest sipRequest = (SIPRequest) transaction.getRequest();\n            String dialogId = sipRequest.getDialogId(true);\n            dialog = sipStack.getDialog(dialogId);\n            if (dialog == null) {\n                dialog = sipStack.createDialog((SIPTransaction) transaction);\n                // create and register the dialog and add the inital route set.\n                dialog.addTransaction(sipTransaction);\n                dialog.addRoute(sipRequest);\n                sipTransaction.setDialog(dialog, null);\n\n            } else {\n                sipTransaction.setDialog(dialog, sipRequest.getDialogId(true));\n            }\n            if (sipRequest.getMethod().equals(Request.INVITE) && this.isDialogErrorsAutomaticallyHandled()) {\n                sipStack.putInMergeTable(st, sipRequest);\n            }\n        } else {\n\n            SIPClientTransaction sipClientTx = (SIPClientTransaction) transaction;\n\n            SIPResponse response = sipClientTx.getLastResponse();\n\n            if (response == null) {\n                // A response has not yet been received, then set this up as the\n                // default dialog.\n                SIPRequest request = (SIPRequest) sipClientTx.getRequest();\n\n                String dialogId = request.getDialogId(false);\n                dialog = sipStack.getDialog(dialogId);\n                if (dialog != null) {\n                    throw new SipException(\"Dialog already exists!\");\n                } else {\n                    dialog = sipStack.createDialog(sipTransaction);\n                }\n                sipClientTx.setDialog(dialog, null);\n\n            } else {\n                throw new SipException(\n                        \"Cannot call this method after response is received!\");\n            }\n        }\n        dialog.addEventListener(this);\n        return dialog;\n\n    }\n\n    /**\n     * Invoked when an error has ocurred with a transaction. Propagate up to the\n     * listeners.\n     *\n     * @param transactionErrorEvent\n     *            Error event.\n     */\n    public void transactionErrorEvent(\n            SIPTransactionErrorEvent transactionErrorEvent) {\n        SIPTransaction transaction = (SIPTransaction) transactionErrorEvent\n                .getSource();\n\n        if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {\n            // There must be a way to inform the TU here!!\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"TransportError occured on \" + transaction);\n            }\n            // Treat this like a timeout event. (Suggestion from Christophe).\n            Object errorObject = transactionErrorEvent.getSource();\n            Timeout timeout = Timeout.TRANSACTION;\n            TimeoutEvent ev = null;\n\n            if (errorObject instanceof SIPServerTransaction) {\n                ev = new TimeoutEvent(this, (ServerTransaction) errorObject,\n                        timeout);\n            } else {\n                SIPClientTransaction clientTx = (SIPClientTransaction) errorObject;\n                Hop hop = clientTx.getNextHop();\n                if ( sipStack.getRouter() instanceof RouterExt ) {\n                    ((RouterExt) sipStack.getRouter()).transactionTimeout(hop);\n                }\n                ev = new TimeoutEvent(this, (ClientTransaction) errorObject,\n                        timeout);\n            }\n            // Handling transport error like timeout\n            this.handleEvent(ev, (SIPTransaction) errorObject);\n        } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_ERROR) {\n            // This is a timeout event.\n            Object errorObject = transactionErrorEvent.getSource();\n            Timeout timeout = Timeout.TRANSACTION;\n            TimeoutEvent ev = null;\n\n            if (errorObject instanceof SIPServerTransaction) {\n                ev = new TimeoutEvent(this, (ServerTransaction) errorObject,\n                        timeout);\n            } else {\n                SIPClientTransaction clientTx = (SIPClientTransaction) errorObject;\n                Hop hop = clientTx.getNextHop();\n                if ( sipStack.getRouter() instanceof RouterExt ) {\n                    ((RouterExt) sipStack.getRouter()).transactionTimeout(hop);\n                }\n\n                ev = new TimeoutEvent(this, (ClientTransaction) errorObject,\n                        timeout);\n            }\n            this.handleEvent(ev, (SIPTransaction) errorObject);\n\n        } else if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) {\n            // This is a timeout retransmit event.\n            // We should never get this if retransmit filter is\n            // enabled (ie. in that case the stack should handle.\n            // all retransmits.\n            Object errorObject = transactionErrorEvent.getSource();\n            Transaction tx = (Transaction) errorObject;\n\n            if (tx.getDialog() != null)\n                InternalErrorHandler.handleException(\"Unexpected event !\",\n                        this.sipStack.getStackLogger());\n\n            Timeout timeout = Timeout.RETRANSMIT;\n            TimeoutEvent ev = null;\n\n            if (errorObject instanceof SIPServerTransaction) {\n                ev = new TimeoutEvent(this, (ServerTransaction) errorObject,\n                        timeout);\n            } else {\n                ev = new TimeoutEvent(this, (ClientTransaction) errorObject,\n                        timeout);\n            }\n            this.handleEvent(ev, (SIPTransaction) errorObject);\n        }\n    }\n    \n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov2.nist.javax2.sip.stack.SIPDialogErrorEvent)\n     */\n    public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) {\n        SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource();\n        Reason reason = Reason.AckNotReceived;\n        if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT) {\n        \treason= Reason.AckNotSent;\n        } else if (dialogErrorEvent.getErrorID() == SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT) {\n            reason = Reason.ReInviteTimeout;\n        }\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"Dialog TimeoutError occured on \" + sipDialog);\n        }\n        DialogTimeoutEvent ev = new DialogTimeoutEvent(this, sipDialog, reason);\n        // Handling transport error like timeout\n        this.handleEvent(ev, null);\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#getListeningPoints()\n     */\n    public synchronized ListeningPoint[] getListeningPoints() {\n\n        ListeningPoint[] retval = new ListeningPointImpl[this.listeningPoints\n                .size()];\n        this.listeningPoints.values().toArray(retval);\n        return retval;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#addListeningPoint(javax2.sip.ListeningPoint)\n     */\n    public synchronized void addListeningPoint(ListeningPoint listeningPoint)\n            throws ObjectInUseException {\n        ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;\n        if (lp.sipProvider != null && lp.sipProvider != this)\n            throw new ObjectInUseException(\n                    \"Listening point assigned to another provider\");\n        String transport = lp.getTransport().toUpperCase();\n        if (this.listeningPoints.isEmpty()) {\n            // first one -- record the IP address/port of the LP\n\n            this.address = listeningPoint.getIPAddress();\n            this.port = listeningPoint.getPort();\n        } else {\n            if ((!this.address.equals(listeningPoint.getIPAddress()))\n                    || this.port != listeningPoint.getPort())\n                throw new ObjectInUseException(\n                        \"Provider already has different IP Address associated\");\n\n        }\n        if (this.listeningPoints.containsKey(transport)\n                && this.listeningPoints.get(transport) != listeningPoint)\n            throw new ObjectInUseException(\n                    \"Listening point already assigned for transport!\");\n\n        // This is for backwards compatibility.\n        lp.sipProvider = this;\n\n        this.listeningPoints.put(transport, lp);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#removeListeningPoint(javax2.sip.ListeningPoint)\n     */\n    public synchronized void removeListeningPoint(ListeningPoint listeningPoint)\n            throws ObjectInUseException {\n        ListeningPointImpl lp = (ListeningPointImpl) listeningPoint;\n        if (lp.messageProcessor.inUse())\n            throw new ObjectInUseException(\"Object is in use\");\n        this.listeningPoints.remove(lp.getTransport().toUpperCase());\n\n    }\n\n    /**\n     * Remove all the listening points for this sip provider. This is called\n     * when the stack removes the Provider\n     */\n    public synchronized void removeListeningPoints() {\n        for (Iterator it = this.listeningPoints.values().iterator(); it\n                .hasNext();) {\n            ListeningPointImpl lp = (ListeningPointImpl) it.next();\n            lp.messageProcessor.stop();\n            it.remove();\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipProvider#setAutomaticDialogSupportEnabled(boolean)\n     */\n    public void setAutomaticDialogSupportEnabled(\n            boolean automaticDialogSupportEnabled) {\n        this.automaticDialogSupportEnabled = automaticDialogSupportEnabled;\n        if ( this.automaticDialogSupportEnabled ) {\n            this.dialogErrorsAutomaticallyHandled = true;\n        }\n    }\n\n    /**\n     * @return Returns the automaticDialogSupportEnabled.\n     */\n    public boolean isAutomaticDialogSupportEnabled() {\n        return automaticDialogSupportEnabled;\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.SipProviderExt#setDialogErrorsAutomaticallyHandled()\n     */\n    public void setDialogErrorsAutomaticallyHandled() {\n        this.dialogErrorsAutomaticallyHandled = true;\n    }\n    \n    public boolean isDialogErrorsAutomaticallyHandled() {\n        return this.dialogErrorsAutomaticallyHandled;\n    }\n\n\n    /**\n     * @return the sipListener\n     */\n    public SipListener getSipListener() {\n        return sipListener;\n    }\n\n   \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/SipStackExt.java",
    "content": "package gov2.nist.javax2.sip;\n\nimport gov2.nist.core.net.AddressResolver;\nimport gov2.nist.javax2.sip.clientauthutils.AccountManager;\nimport gov2.nist.javax2.sip.clientauthutils.AuthenticationHelper;\nimport gov2.nist.javax2.sip.clientauthutils.SecureAccountManager;\nimport gov2.nist.javax2.sip.header.extensions.JoinHeader;\nimport gov2.nist.javax2.sip.header.extensions.ReplacesHeader;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.SocketAddress;\nimport java.util.Collection;\n\nimport javax2.sip.Dialog;\nimport javax2.sip.SipStack;\nimport javax2.sip.header.HeaderFactory;\n\n/**\n * SIP Stack extensions to be added to the next spec revision. Only these may be safely used in\n * the interim between now and the next release. SipStackImpl implements this interface.\n * \n * The following new stack initialization flags are defined (not the gov2.nist prefix will be\n * dropped when the spec is updated):\n * \n * <ul>\n *<li>gov2.nist.javax2.sip.AUTOMATIC_DIALOG_ERROR_HANDLING\n *<li>gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT\n *<li>gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG\n *<li>gov2.nist.javax2.sip.MAX_FORK_TIME_SECONDS \n * </ul>\n * @author M. Ranganathan\n * \n */\npublic interface SipStackExt extends SipStack {\n\n    /**\n     * Get the collection of dialogs currently in the Dialog table. This is useful for debugging\n     * purposes.\n     *\n     */\n    public Collection<Dialog> getDialogs();\n\n    /**\n     * Get the ReferedTo dialog in the Replaces header.\n     *\n     * @return Dialog object matching the Replaces header, provided it is in an appropriate state\n     *         to be replaced, <code>null</code> otherwise\n     *\n     * @since 2.0\n     */\n    public Dialog getReplacesDialog(ReplacesHeader replacesHeader);\n\n    /**\n     * Get the authentication helper.\n     *\n     *\n     * @param accountManager -- account manager (for fetching credentials).\n     * @param headerFactory -- header factory.\n     *\n     * @return - the authentication helper which can be used for generating the appropriate\n     *         headers for handling authentication challenges for user agents.\n     *\n     * @since 2.0\n     */\n    public AuthenticationHelper getAuthenticationHelper(AccountManager accountManager,\n            HeaderFactory headerFactory);\n    \n    /**\n     * Get the authentication helper.\n     *\n     *\n     * @param accountManager -- account manager (for fetching credentials).\n     * @param headerFactory -- header factory.\n     *\n     * @return - the authentication helper which can be used for generating the appropriate\n     *         headers for handling authentication challenges for user agents.\n     *\n     * @since 2.0\n     */\n    public AuthenticationHelper getSecureAuthenticationHelper(SecureAccountManager accountManager,\n            HeaderFactory headerFactory);\n\n    /**\n     * Set the address resolution interface. The address resolver allows you to register custom\n     * lookup schemes ( for example DNS SRV lookup ) that are not directly supported by the JDK.\n     *\n     * @param addressResolver -- the address resolver to set.\n     *\n     * @since 2.0\n     */\n    public void setAddressResolver(AddressResolver addressResolver);\n\n    /**\n     * Get the dialog in the Join header.\n     *\n     * @return Dialog object matching the Join header, provided it is in an appropriate state to\n     *         be replaced, <code>null</code> otherwise\n     *\n     * @since 2.0\n     */\n    public Dialog getJoinDialog(JoinHeader joinHeader);\n\n    /**\n     * Set the list of cipher suites supported by the stack. A stack can have only one set of\n     * suites. These are not validated against the supported cipher suites of the java runtime, so\n     * specifying a cipher here does not guarantee that it will work.<br>\n     * The stack has a default cipher suite of:\n     * <ul>\n     * <li> TLS_RSA_WITH_AES_128_CBC_SHA </li>\n     * <li> SSL_RSA_WITH_3DES_EDE_CBC_SHA </li>\n     * <li> TLS_DH_anon_WITH_AES_128_CBC_SHA </li>\n     * <li> SSL_DH_anon_WITH_3DES_EDE_CBC_SHA </li>\n     * </ul>\n     *\n     * <b>NOTE: This function must be called before adding a TLS listener</b>\n     *\n     * @since 2.0\n     * @param newCipherSuites -- The new set of ciphers to support.\n     *\n     */\n    public void setEnabledCipherSuites(String[] newCipherSuites);\n\n    /**\n     * Creates and binds, if necessary, a TCP socket connected to the specified\n     * destination address and port and then returns its local address.\n     *\n     * @param dst the destination address that the socket would need to connect\n     *            to.\n     * @param dstPort the port number that the connection would be established\n     * with.\n     * @param localAddress the address that we would like to bind on\n     * (null for the \"any\" address).\n     * @param localPort the port that we'd like our socket to bind to (0 for a\n     * random port).\n     *\n     * @return the SocketAddress that this handler would use when connecting to\n     * the specified destination address and port.\n     *\n     * @throws IOException\n     */\n    public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort,\n                    InetAddress localAddress, int localPort)\n        throws IOException;\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/SipStackImpl.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.core.ServerLogger;\nimport gov2.nist.core.StackLogger;\nimport gov2.nist.core.net.AddressResolver;\nimport gov2.nist.core.net.NetworkLayer;\nimport gov2.nist.core.net.SslNetworkLayer;\nimport gov2.nist.javax2.sip.clientauthutils.AccountManager;\nimport gov2.nist.javax2.sip.clientauthutils.AuthenticationHelper;\nimport gov2.nist.javax2.sip.clientauthutils.AuthenticationHelperImpl;\nimport gov2.nist.javax2.sip.clientauthutils.SecureAccountManager;\nimport gov2.nist.javax2.sip.parser.StringMsgParser;\nimport gov2.nist.javax2.sip.stack.DefaultMessageLogFactory;\nimport gov2.nist.javax2.sip.stack.DefaultRouter;\nimport gov2.nist.javax2.sip.stack.MessageProcessor;\nimport gov2.nist.javax2.sip.stack.SIPTransactionStack;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.net.InetAddress;\nimport java.util.Hashtable;\nimport java.util.LinkedList;\nimport java.util.Properties;\nimport java.util.StringTokenizer;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.ListeningPoint;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.PeerUnavailableException;\nimport javax2.sip.ProviderDoesNotExistException;\nimport javax2.sip.SipException;\nimport javax2.sip.SipListener;\nimport javax2.sip.SipProvider;\nimport javax2.sip.SipStack;\nimport javax2.sip.TransportNotSupportedException;\nimport javax2.sip.address.Router;\nimport javax2.sip.header.HeaderFactory;\nimport javax2.sip.message.Request;\n\n/**\n * Implementation of SipStack.\n * \n * The JAIN-SIP stack is initialized by a set of properties (see the JAIN SIP\n * documentation for an explanation of these properties\n * {@link javax2.sip.SipStack} ). In addition to these, the following are\n * meaningful properties for the NIST SIP stack (specify these in the property\n * array when you create the JAIN-SIP statck):\n * <ul>\n * \n * <li><b>gov2.nist.javax2.sip.TRACE_LEVEL = integer </b><br/>\n * <b> Use of this property is still supported but deprecated. Please use\n * gov2.nist.javax2.sip.STACK_LOGGER and gov2.nist.javax2.sip.SERVER_LOGGER for\n * integration with logging frameworks and for custom formatting of log records.\n * </b> This property is used by the built in log4j based logger. You can use\n * the standard log4j level names here (i.e. ERROR, INFO, WARNING, OFF, DEBUG,\n * TRACE) If this is set to INFO or above, then incoming valid messages are\n * logged in SERVER_LOG. If you set this to 32 and specify a DEBUG_LOG then vast\n * amounts of trace information will be dumped in to the specified DEBUG_LOG.\n * The server log accumulates the signaling trace. <a href=\"{@docRoot}\n * /tools/tracesviewer/tracesviewer.html\"> This can be viewed using the trace\n * viewer tool .</a> Please send us both the server log and debug log when\n * reporting non-obvious problems. You can also use the strings DEBUG or INFO\n * for level 32 and 16 respectively. If the value of this property is set to\n * LOG4J, then the effective log levels are determined from the log4j settings\n * file (e.g. log4j.properties). The logger name for the stack is specified\n * using the gov2.nist.javax2.sip.LOG4J_LOGGER_NAME property. By default log4j\n * logger name for the stack is the same as the stack name. For example, <code>\n * properties.setProperty(\"gov2.nist.javax2.sip.TRACE_LEVEL\", \"LOG4J\");\n * properties.setProperty(\"gov2.nist.javax2.sip.LOG4J_LOGGER_NAME\", \"SIPStackLogger\");\n * </code> allows you to now control logging in the stack entirely using log4j\n * facilities.</li>\n * \n * <li><b>gov2.nist.javax2.sip.LOG_FACTORY = classpath </b> <b> Use of this\n * property is still supported but deprecated. Please use\n * gov2.nist.javax2.sip.STACK_LOGGER and gov2.nist.javax2.sip.SERVER_LOGGER for\n * integration with logging frameworks and for custom formatting of log records.\n * </b> <br/>\n * The fully qualified classpath for an implementation of the MessageLogFactory.\n * The stack calls the MessageLogFactory functions to format the log for\n * messages that are received or sent. This function allows you to log auxiliary\n * information related to the application or environmental conditions into the\n * log stream. The log factory must have a default constructor.</li>\n * \n * <li><b>gov2.nist.javax2.sip.SERVER_LOG = fileName </b><br/>\n * <b> Use of this property is still supported but deprecated. Please use\n * gov2.nist.javax2.sip.STACK_LOGGER and gov2.nist.javax2.sip.SERVER_LOGGER for\n * integration with logging frameworks and for custom formatting of log records.\n * </b> Log valid incoming messages here. If this is left null AND the\n * TRACE_LEVEL is above INFO (or TRACE) then the messages are printed to stdout.\n * Otherwise messages are logged in a format that can later be viewed using the\n * trace viewer application which is located in the tools/tracesviewer\n * directory. <font color=red> Mail this to us with bug reports. </font></li>\n * \n * <li><b>gov2.nist.javax2.sip.DEBUG_LOG = fileName </b> <b> Use of this property\n * is still supported but deprecated. Please use gov2.nist.javax2.sip.STACK_LOGGER\n * and gov2.nist.javax2.sip.SERVER_LOGGER for integration with logging frameworks\n * and for custom formatting of log records. </b> <br/>\n * Where the debug log goes. <font color=red> Mail this to us with bug reports.\n * </font></li>\n * \n * <li><b>gov2.nist.javax2.sip.LOG_MESSAGE_CONTENT = true|false </b><br/>\n * Set true if you want to capture content into the log. Default is false. A bad\n * idea to log content if you are using SIP to push a lot of bytes through TCP.</li>\n * \n * <li><b>gov2.nist.javax2.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND = true|false </b><br/>\n * Set true if you want to to log a stack trace at INFO level for each message\n * send. This is really handy for debugging.</li>\n * \n * <li><b>gov2.nist.javax2.sip.STACK_LOGGER = full path name to the class\n * implementing gov2.nist.core.StackLogger interface</b><br/>\n * If this property is defined the sip stack will try to instantiate it through\n * a no arg constructor. This allows to use different logging implementations\n * than the ones provided by default to log what happens within the stack while\n * processing SIP messages. If this property is not defined, the default sip\n * stack LogWriter will be used for logging</li>\n * \n * <li><b>gov2.nist.javax2.sip.SERVER_LOGGER = full path name to the class\n * implementing gov2.nist.core.ServerLogger interface</b><br/>\n * If this property is defined the sip stack will try to instantiate it through\n * a no arg constructor. This allows to use different logging implementations\n * than the ones provided by default to log sent/received messages by the sip\n * stack. If this property is not defined, the default sip stack ServerLog will\n * be used for logging</li>\n * \n * <li><b>gov2.nist.javax2.sip.AUTOMATIC_DIALOG_ERROR_HANDLING = [true|false] </b>\n * <br/>\n * Default is <it>true</it>. This is also settable on a per-provider basis. This\n * flag is set to true by default. When set\n * to <it>false</it> the following behaviors are enabled:\n * \n * \n * <li>Turn off Merged requests Loop Detection: The following behavior is turned off\n * : If the request has no tag in the To header field, the UAS core MUST check\n * the request against ongoing transactions. If the From tag, Call-ID, and CSeq\n * exactly match those associated with an ongoing transaction, but the request\n * does not match that transaction (based on the matching rules in Section\n * 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and pass\n * it to the server transaction.\n * \n * </ul>\n * \n * <li><b>gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT = [true|false] </b> <br/>\n * Default is <it>false</it> This property controls a setting on the Dialog\n * objects that the stack manages. Pure B2BUA applications should set this flag\n * to <it>true</it>. This property can also be set on a per-dialog basis.\n * Setting this to <it>true</it> imposes serialization on re-INVITE and makes\n * the sending of re-INVITEs asynchronous. The sending of re-INVITE is\n * controlled as follows : If the previous in-DIALOG request was an invite\n * ClientTransaction then the next re-INVITEs that uses the dialog will wait\n * till an ACK has been sent before admitting the new re-INVITE. If the previous\n * in-DIALOG transaction was a INVITE ServerTransaction then Dialog waits for\n * ACK before re-INVITE is allowed to be sent. If a dialog is not ACKed within\n * 32 seconds, then the dialog is torn down and a BYE sent to the peer.</li>\n * <li><b>gov2.nist.javax2.sip.MAX_MESSAGE_SIZE = integer</b> <br/>\n * Maximum size of content that a TCP connection can read. Must be at least 4K.\n * Default is \"infinity\" -- ie. no limit. This is to prevent DOS attacks\n * launched by writing to a TCP connection until the server chokes.</li>\n * \n * <li><b>gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG = [true|false] </b><br/>\n * If set to false (the default), the application does NOT get notified when a Dialog in the\n * NULL state is terminated. ( Dialogs in the NULL state are not associated with an actual SIP Dialog.\n * They are a programming convenience. A Dialog is in the NULL state before the first response for the \n * Dialog forming Transaction). If set to true, the SipListener will get a DialogTerminatedEvent\n * when a Dialog in the NULL state is terminated. \n * </li>\n * \n * <li><b>gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS = [true|false] </b> <br/>\n * Default value is true. Setting this to false makes the Stack close the server\n * socket after a Server Transaction goes to the TERMINATED state. This allows a\n * server to protectect against TCP based Denial of Service attacks launched by\n * clients (ie. initiate hundreds of client transactions). If true (default\n * action), the stack will keep the socket open so as to maximize performance at\n * the expense of Thread and memory resources - leaving itself open to DOS\n * attacks.</li>\n * \n * \n * <li><b>gov2.nist.javax2.sip.CACHE_CLIENT_CONNECTIONS = [true|false] </b> <br/>\n * Default value is true. Setting this to false makes the Stack close the server\n * socket after a Client Transaction goes to the TERMINATED state. This allows a\n * client release any buffers threads and socket connections associated with a\n * client transaction after the transaction has terminated at the expense of\n * performance.</li>\n * \n * <li><b>gov2.nist.javax2.sip.THREAD_POOL_SIZE = integer </b> <br/>\n * Concurrency control for number of simultaneous active threads. If\n * unspecificed, the default is \"infinity\". This feature is useful if you are\n * trying to build a container.\n * <ul>\n * <li>\n * <li>If this is not specified, <b> and the listener is re-entrant</b>, each\n * event delivered to the listener is run in the context of a new thread.</li>\n * <li>If this is specified and the listener is re-entrant, then the stack will\n * run the listener using a thread from the thread pool. This allows you to\n * manage the level of concurrency to a fixed maximum. Threads are pre-allocated\n * when the stack is instantiated.</li>\n * <li>If this is specified and the listener is not re-entrant, then the stack\n * will use the thread pool thread from this pool to parse and manage the state\n * machine but will run the listener in its own thread.</li>\n * </ul>\n * \n * <li><b>gov2.nist.javax2.sip.REENTRANT_LISTENER = true|false </b> <br/>\n * Default is false. Set to true if the listener is re-entrant. If the listener\n * is re-entrant then the stack manages a thread pool and synchronously calls\n * the listener from the same thread which read the message. Multiple\n * transactions may concurrently receive messages and this will result in\n * multiple threads being active in the listener at the same time. The listener\n * has to be written with this in mind. <b> If you want good performance on a\n * multithreaded machine write your listener to be re-entrant and set this\n * property to be true </b></li>\n * \n * <li><b>gov2.nist.javax2.sip.MAX_CONNECTIONS = integer </b> <br/>\n * Max number of simultaneous TCP connections handled by stack.</li>\n * \n * <li><b>gov2.nist.javax2.sip.MAX_SERVER_TRANSACTIONS = integer </b> <br/>\n * Maximum size of server transaction table. The low water mark is 80% of the\n * high water mark. Requests are selectively dropped in the lowater mark to\n * highwater mark range. Requests are unconditionally accepted if the table is\n * smaller than the low water mark. The default highwater mark is 5000</li>\n * \n * <li><b>gov2.nist.javax2.sip.MAX_CLIENT_TRANSACTIONS = integer </b> <br/>\n * Max number of active client transactions before the caller blocks and waits\n * for the number to drop below a threshold. Default is unlimited, i.e. the\n * caller never blocks and waits for a client transaction to become available\n * (i.e. it does its own resource management in the application).</li>\n * \n * <li><b>gov2.nist.javax2.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER = true|false\n * </b> <br/>\n * If true then the listener will see the ACK for non-2xx responses for server\n * transactions. This is not standard behavior per RFC 3261 (INVITE server\n * transaction state machine) but this is a useful flag for testing. The TCK\n * uses this flag for example.</li>\n * \n * <li><b>gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME = Integer </b> <br/>\n * Max time (seconds) before sending a response to a server transaction. If a\n * response is not sent within this time period, the transaction will be deleted\n * by the stack. Default time is \"infinity\" - i.e. if the listener never\n * responds, the stack will hang on to a reference for the transaction and\n * result in a memory leak.\n * \n * <li><b>gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_ACK = [true|false]</b>\n * <br/>\n * Default is <it>false</it>. ACK Server Transaction is a Pseuedo-transaction.\n * If you want termination notification on ACK transactions (so all server\n * transactions can be handled uniformly in user code during cleanup), then set\n * this flag to <it>true</it>.</li>\n * \n * <li><b>gov2.nist.javax2.sip.READ_TIMEOUT = integer </b> <br/>\n * This is relevant for incoming TCP connections to prevent starvation at the\n * server. This defines the timeout in miliseconds between successive reads\n * after the first byte of a SIP message is read by the stack. All the sip\n * headers must be delivered in this interval and each successive buffer must be\n * of the content delivered in this interval. Default value is -1 (ie. the stack\n * is wide open to starvation attacks) and the client can be as slow as it wants\n * to be.</li>\n * \n * <li><b>gov2.nist.javax2.sip.NETWORK_LAYER = classpath </b> <br/>\n * This is an EXPERIMENTAL property (still under active devlopment). Defines a\n * network layer that allows a client to have control over socket allocations\n * and monitoring of socket activity. A network layer should implement\n * gov2.nist.core.net.NetworkLayer. The default implementation simply acts as a\n * wrapper for the standard java.net socket layer. This functionality is still\n * under active development (may be extended to support security and other\n * features).</li>\n * \n * <li><b>gov2.nist.javax2.sip.ADDRESS_RESOLVER = classpath </b><br/>\n * The fully qualified class path for an implementation of the AddressResolver\n * interface. The AddressResolver allows you to support lookup schemes for\n * addresses that are not directly resolvable to IP adresses using\n * getHostByName. Specifying your own address resolver allows you to customize\n * address lookup. The default address resolver is a pass-through address\n * resolver (i.e. just returns the input string without doing a resolution). See\n * gov2.nist.javax2.sip.DefaultAddressResolver.</li>\n * \n * <li><b>gov2.nist.javax2.sip.AUTO_GENERATE_TIMESTAMP= [true| false] </b><br/>\n * (default is false) Automatically generate a getTimeOfDay timestamp for a\n * retransmitted request if the original request contained a timestamp. This is\n * useful for profiling.</li>\n * \n * <li><b>gov2.nist.javax2.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS = long </b> <br/>\n * Defines how often the application intends to audit the SIP Stack about the\n * health of its internal threads (the property specifies the time in\n * miliseconds between successive audits). The audit allows the application to\n * detect catastrophic failures like an internal thread terminating because of\n * an exception or getting stuck in a deadlock condition. Events like these will\n * make the stack inoperable and therefore require immediate action from the\n * application layer (e.g., alarms, traps, reboot, failover, etc.) Thread audits\n * are disabled by default. If this property is not specified, audits will\n * remain disabled. An example of how to use this property is in\n * src/examples/threadaudit.</li>\n * \n * \n * \n * <li><b>gov2.nist.javax2.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY =\n * [true|false] </b> <br/>\n * Default is <it>false</it> If set to <it>true</it>, when you are creating a\n * message from a <it>String</it>, the MessageFactory will compute the content\n * length from the message content and ignore the provided content length\n * parameter in the Message. Otherwise, it will use the content length supplied\n * and generate a parse exception if the content is truncated.\n * \n * <li><b>gov2.nist.javax2.sip.CANCEL_CLIENT_TRANSACTION_CHECKED = [true|false]\n * </b> <br/>\n * Default is <it>true</it>. This flag is added in support of load balancers or\n * failover managers where you may want to cancel ongoing transactions from a\n * different stack than the original stack. If set to <it>false</it> then the\n * CANCEL client transaction is not checked for the existence of the INVITE or\n * the state of INVITE when you send the CANCEL request. Hence you can CANCEL an\n * INVITE from a different stack than the INVITE. You can also create a CANCEL\n * client transaction late and send it out after the INVITE server transaction\n * has been Terminated. Clearly this will result in protocol errors. Setting the\n * flag to true ( default ) enables you to avoid common protocol errors.</li>\n * \n * <li><b>gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT = [true|false] </b> <br/>\n * Default is <it>false</it> This property controls a setting on the Dialog\n * objects that the stack manages. Pure B2BUA applications should set this flag\n * to <it>true</it>. This property can also be set on a per-dialog basis.\n * Setting this to <it>true</it> imposes serialization on re-INVITE and makes\n * the sending of re-INVITEs asynchronous. The sending of re-INVITE is\n * controlled as follows : If the previous in-DIALOG request was an invite\n * ClientTransaction then the next re-INVITEs that uses the dialog will wait\n * till an ACK has been sent before admitting the new re-INVITE. If the previous\n * in-DIALOG transaction was a INVITE ServerTransaction then Dialog waits for\n * ACK before re-INVITE is allowed to be sent. If a dialog is not ACKed within\n * 32 seconds, then the dialog is torn down and a BYE sent to the peer.</li>\n * \n * \n * <li><b>gov2.nist.javax2.sip.RECEIVE_UDP_BUFFER_SIZE = int </b> <br/>\n * Default is <it>8*1024</it>. This property control the size of the UDP buffer\n * used for SIP messages. Under load, if the buffer capacity is overflown the\n * messages are dropped causing retransmissions, further increasing the load and\n * causing even more retransmissions. Good values to this property for servers\n * is a big number in the order of 8*8*1024.</li>\n * \n * <li><b>gov2.nist.javax2.sip.SEND_UDP_BUFFER_SIZE = int </b> <br/>\n * Default is <it>8*1024</it>. This property control the size of the UDP buffer\n * used for SIP messages. Under load, if the buffer capacity is overflown the\n * messages are dropped causing retransmissions, further increasing the load and\n * causing even more retransmissions. Good values to this property for servers\n * is a big number in the order of 8*8*1024 or higher.</li>\n * \n * <li><b>gov2.nist.javax2.sip.CONGESTION_CONTROL_ENABLED = boolean </b> Defailt\n * is true. If set to true stack will enforce queue length limitation for UDP.\n * The Max queue size is 5000 messages. The minimum queue size is 2500 messages.\n * </li>\n * \n * <li><b>gov2.nist.javax2.sip.DELIVER_UNSOLICITED_NOTIFY = [true|false] </b> <br/>\n * Default is <it>false</it>. This flag is added to allow Sip Listeners to\n * receive all NOTIFY requests including those that are not part of a valid\n * dialog.</li>\n * \n * <li><b>gov2.nist.javax2.sip.REJECT_STRAY_RESPONSES = [true|false] </b> Default\n * is <it>false</it> A flag that checks responses to test whether the response\n * corresponds to a via header that was previously generated by us. Note that\n * setting this flag implies that the stack will take control over setting the\n * VIA header for Sip Requests sent through the stack. The stack will attach a\n * suffix to the VIA header branch and check any response arriving at the stack\n * to see if that response suffix is present. If it is not present, then the\n * stack will silently drop the response.</li>\n * \n * <li><b>gov2.nist.javax2.sip.MAX_FORK_TIME_SECONDS = integer </b> Maximum time for which the original \n * transaction for which a forked response is received is tracked. This property\n * is only relevant to Dialog Stateful applications ( User Agents or B2BUA).\n * When a forked response is received in this time interval from when the original\n * INVITE client transaction was sent, the stack will place the original INVITE\n * client transction in the ResponseEventExt and deliver that to the application.\n * The event handler can get the original transaction from this event. </li>\n * \n *  * <li><b>gov2.nist.javax2.sip.TLS_CLIENT_PROTOCOLS = String </b>\n *  Comma-separated list of protocols to use when creating outgoing TLS connections.\n *  The default is \"SSLv3, SSLv2Hello, TLSv1\".\n *  Some servers do not support SSLv2Hello, so override to \"SSLv3, TLSv1\". \n * </li>\n\n * <li><b>javax2.net.ssl.keyStore = fileName </b> <br/>\n * Default is <it>NULL</it>. If left undefined the keyStore and trustStore will\n * be left to the java runtime defaults. If defined, any TLS sockets created\n * (client and server) will use the key store provided in the fileName. The\n * trust store will default to the same store file. A password must be provided\n * to access the keyStore using the following property: <br>\n * <code>\n * properties.setProperty(\"javax2.net.ssl.keyStorePassword\", \"&lt;password&gt;\");\n * </code> <br>\n * The trust store can be changed, to a separate file with the following\n * setting: <br>\n * <code>\n * properties.setProperty(\"javax2.net.ssl.trustStore\", \"&lt;trustStoreFileName location&gt;\");\n * </code> <br>\n * If the trust store property is provided the password on the trust store must\n * be the same as the key store. <br>\n * <br>\n * <b> Note that the stack supports the extensions that are defined in\n * SipStackExt. These will be supported in the next release of JAIN-SIP. You\n * should only use the extensions that are defined in this class. </b>\n * \n * \n * @version 1.2 $Revision: 1.115 $ $Date: 2010/01/10 00:13:14 $\n * \n * @author M. Ranganathan <br/>\n * \n * \n * \n * \n */\npublic class SipStackImpl extends SIPTransactionStack implements\n\t\tjavax2.sip.SipStack, SipStackExt {\n\n\tprivate EventScanner eventScanner;\n\n\tprivate Hashtable<String, ListeningPointImpl> listeningPoints;\n\n\tprivate LinkedList<SipProviderImpl> sipProviders;\n\n\t/**\n\t * Max datagram size.\n\t */\n\tpublic static final Integer MAX_DATAGRAM_SIZE = 8 * 1024;\n\n\t// Flag to indicate that the listener is re-entrant and hence\n\t// Use this flag with caution.\n\tboolean reEntrantListener;\n\n\tSipListener sipListener;\n\n\t// If set to true then a transaction terminated event is\n\t// delivered for ACK transactions.\n\tboolean deliverTerminatedEventForAck = false;\n\n\t// If set to true then the application want to receive\n\t// unsolicited NOTIFYs, ie NOTIFYs that don't match any dialog\n\tboolean deliverUnsolicitedNotify = false;\n\n\t// Stack semaphore (global lock).\n\tprivate Semaphore stackSemaphore = new Semaphore(1);\n\n\t// RFC3261: TLS_RSA_WITH_AES_128_CBC_SHA MUST be supported\n\t// RFC3261: TLS_RSA_WITH_3DES_EDE_CBC_SHA SHOULD be supported for backwards\n\t// compat\n\tprivate String[] cipherSuites = {\n\t\t\t\"TLS_RSA_WITH_AES_128_CBC_SHA\", // AES difficult to get with\n\t\t\t\t\t\t\t\t\t\t\t// c++/Windows\n\t\t\t// \"TLS_RSA_WITH_3DES_EDE_CBC_SHA\", // Unsupported by Sun impl,\n\t\t\t\"SSL_RSA_WITH_3DES_EDE_CBC_SHA\", // For backwards comp., C++\n\n\t\t\t// JvB: patch from Sebastien Mazy, issue with mismatching\n\t\t\t// ciphersuites\n                        // Below ciphersuites are not supported anymore with Android 6.0\n                        //\"TLS_DH_anon_WITH_AES_128_CBC_SHA\",\n                        //\"SSL_DH_anon_WITH_3DES_EDE_CBC_SHA\",\n        };\n\n\t// Supported protocols for TLS client: can be overridden by application\n\tprivate String[] enabledProtocols = {\n\t\t\t\"SSLv3\",\n\t\t\t\"SSLv2Hello\",\n\t\t\t\"TLSv1\"\n\t};\n\n\t/**\n\t * Creates a new instance of SipStackImpl.\n\t */\n\n\tprotected SipStackImpl() {\n\t\tsuper();\n\t\tNistSipMessageFactoryImpl msgFactory = new NistSipMessageFactoryImpl(\n\t\t\t\tthis);\n\t\tsuper.setMessageFactory(msgFactory);\n\t\tthis.eventScanner = new EventScanner(this);\n\t\tthis.listeningPoints = new Hashtable<String, ListeningPointImpl>();\n\t\tthis.sipProviders = new LinkedList<SipProviderImpl>();\n\n\t}\n\n\t/**\n\t * ReInitialize the stack instance.\n\t */\n\tprivate void reInitialize() {\n\t\tsuper.reInit();\n\t\tthis.eventScanner = new EventScanner(this);\n\t\tthis.listeningPoints = new Hashtable<String, ListeningPointImpl>();\n\t\tthis.sipProviders = new LinkedList<SipProviderImpl>();\n\t\tthis.sipListener = null;\n\n\t}\n\n\t/**\n\t * Return true if automatic dialog support is enabled for this stack.\n\t * \n\t * @return boolean, true if automatic dialog support is enabled for this\n\t *         stack\n\t */\n\tboolean isAutomaticDialogSupportEnabled() {\n\t\treturn super.isAutomaticDialogSupportEnabled;\n\t}\n\n\t/**\n\t * Constructor for the stack.\n\t * \n\t * @param configurationProperties\n\t *            -- stack configuration properties including NIST-specific\n\t *            extensions.\n\t * @throws PeerUnavailableException\n\t */\n\tpublic SipStackImpl(Properties configurationProperties)\n\t\t\tthrows PeerUnavailableException {\n\t\tthis();\n\t\tString address = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.IP_ADDRESS\");\n\t\ttry {\n\t\t\t/** Retrieve the stack IP address */\n\t\t\tif (address != null) {\n\t\t\t\t// In version 1.2 of the spec the IP address is\n\t\t\t\t// associated with the listening point and\n\t\t\t\t// is not madatory.\n\t\t\t\tsuper.setHostAddress(address);\n\n\t\t\t}\n\t\t} catch (java.net.UnknownHostException ex) {\n\t\t\tthrow new PeerUnavailableException(\"bad address \" + address);\n\t\t}\n\n\t\t/** Retrieve the stack name */\n\t\tString name = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.STACK_NAME\");\n\t\tif (name == null)\n\t\t\tthrow new PeerUnavailableException(\"stack name is missing\");\n\t\tsuper.setStackName(name);\n\t\tString stackLoggerClassName = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.STACK_LOGGER\");\n\t\t// To log debug messages.\n\t\tif (stackLoggerClassName == null)\n\t\t\tstackLoggerClassName = \"gov2.nist.core.LogWriter\";\n\t\t\ttry {\n\t\t\t\tClass<?> stackLoggerClass = Class.forName(stackLoggerClassName);\n\t\t\t\tClass<?>[] constructorArgs = new Class[0];\n\t\t\t\tConstructor<?> cons = stackLoggerClass\n\t\t\t\t\t\t.getConstructor(constructorArgs);\n\t\t\t\tObject[] args = new Object[0];\n\t\t\t\tStackLogger stackLogger = (StackLogger) cons.newInstance(args);\n\t\t\t\tstackLogger.setStackProperties(configurationProperties);\n\t\t\t\tsuper.setStackLogger(stackLogger);\n\t\t\t} catch (InvocationTargetException ex1) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Cound not instantiate stack logger \"\n\t\t\t\t\t\t\t\t+ stackLoggerClassName\n\t\t\t\t\t\t\t\t+ \"- check that it is present on the classpath and that there is a no-args constructor defined\",\n\t\t\t\t\t\tex1);\n\t\t\t} catch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Cound not instantiate stack logger \"\n\t\t\t\t\t\t\t\t+ stackLoggerClassName\n\t\t\t\t\t\t\t\t+ \"- check that it is present on the classpath and that there is a no-args constructor defined\",\n\t\t\t\t\t\tex);\n\t\t\t}\n\n\t\tString serverLoggerClassName = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.SERVER_LOGGER\");\n\t\t// To log debug messages.\n\t\tif (serverLoggerClassName == null)\n\t\t\tserverLoggerClassName = \"gov2.nist.javax2.sip.stack.ServerLog\";\n\t\t\ttry {\n\t\t\t\tClass<?> serverLoggerClass = Class\n\t\t\t\t\t\t.forName(serverLoggerClassName);\n\t\t\t\tClass<?>[] constructorArgs = new Class[0];\n\t\t\t\tConstructor<?> cons = serverLoggerClass\n\t\t\t\t\t\t.getConstructor(constructorArgs);\n\t\t\t\tObject[] args = new Object[0];\n\t\t\t\tthis.serverLogger = (ServerLogger) cons.newInstance(args);\n\t\t\t\tserverLogger.setSipStack(this);\n\t\t\t\tserverLogger.setStackProperties(configurationProperties);\n\t\t\t} catch (InvocationTargetException ex1) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Cound not instantiate server logger \"\n\t\t\t\t\t\t\t\t+ stackLoggerClassName\n\t\t\t\t\t\t\t\t+ \"- check that it is present on the classpath and that there is a no-args constructor defined\",\n\t\t\t\t\t\tex1);\n\t\t\t} catch (Exception ex) {\n\t\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\t\t\"Cound not instantiate server logger \"\n\t\t\t\t\t\t\t\t+ stackLoggerClassName\n\t\t\t\t\t\t\t\t+ \"- check that it is present on the classpath and that there is a no-args constructor defined\",\n\t\t\t\t\t\tex);\n\t\t\t}\n\n\t\t// Default router -- use this for routing SIP URIs.\n\t\t// Our router does not do DNS lookups.\n\t\tthis.outboundProxy = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.OUTBOUND_PROXY\");\n\n\t\tthis.defaultRouter = new DefaultRouter(this, outboundProxy);\n\n\t\t/** Retrieve the router path */\n\t\tString routerPath = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.ROUTER_PATH\");\n\t\tif (routerPath == null)\n\t\t\trouterPath = \"gov2.nist.javax2.sip.stack.DefaultRouter\";\n\n\t\ttry {\n\t\t\tClass<?> routerClass = Class.forName(routerPath);\n\t\t\tClass<?>[] constructorArgs = new Class[2];\n\t\t\tconstructorArgs[0] = javax2.sip.SipStack.class;\n\t\t\tconstructorArgs[1] = String.class;\n\t\t\tConstructor<?> cons = routerClass.getConstructor(constructorArgs);\n\t\t\tObject[] args = new Object[2];\n\t\t\targs[0] = (SipStack) this;\n\t\t\targs[1] = outboundProxy;\n\t\t\tRouter router = (Router) cons.newInstance(args);\n\t\t\tsuper.setRouter(router);\n\t\t} catch (InvocationTargetException ex1) {\n\t\t\tgetStackLogger()\n\t\t\t\t\t.logError(\n\t\t\t\t\t\t\t\"could not instantiate router -- invocation target problem\",\n\t\t\t\t\t\t\t(Exception) ex1.getCause());\n\t\t\tthrow new PeerUnavailableException(\n\t\t\t\t\t\"Cound not instantiate router - check constructor\", ex1);\n\t\t} catch (Exception ex) {\n\t\t\tgetStackLogger().logError(\"could not instantiate router\",\n\t\t\t\t\t(Exception) ex.getCause());\n\t\t\tthrow new PeerUnavailableException(\"Could not instantiate router\",\n\t\t\t\t\tex);\n\t\t}\n\n\t\t// The flag that indicates that the default router is to be ignored.\n\t\tString useRouterForAll = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.USE_ROUTER_FOR_ALL_URIS\");\n\t\tthis.useRouterForAll = true;\n\t\tif (useRouterForAll != null) {\n\t\t\tthis.useRouterForAll = \"true\".equalsIgnoreCase(useRouterForAll);\n\t\t}\n\n\t\t/*\n\t\t * Retrieve the EXTENSION Methods. These are used for instantiation of\n\t\t * Dialogs.\n\t\t */\n\t\tString extensionMethods = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.EXTENSION_METHODS\");\n\n\t\tif (extensionMethods != null) {\n\t\t\tjava.util.StringTokenizer st = new java.util.StringTokenizer(\n\t\t\t\t\textensionMethods);\n\t\t\twhile (st.hasMoreTokens()) {\n\t\t\t\tString em = st.nextToken(\":\");\n\t\t\t\tif (em.equalsIgnoreCase(Request.BYE)\n\t\t\t\t\t\t|| em.equalsIgnoreCase(Request.INVITE)\n\t\t\t\t\t\t|| em.equalsIgnoreCase(Request.SUBSCRIBE)\n\t\t\t\t\t\t|| em.equalsIgnoreCase(Request.NOTIFY)\n\t\t\t\t\t\t|| em.equalsIgnoreCase(Request.ACK)\n\t\t\t\t\t\t|| em.equalsIgnoreCase(Request.OPTIONS))\n\t\t\t\t\tthrow new PeerUnavailableException(\"Bad extension method \"\n\t\t\t\t\t\t\t+ em);\n\t\t\t\telse\n\t\t\t\t\tthis.addExtensionMethod(em);\n\t\t\t}\n\t\t}\n\t\tString keyStoreFile = configurationProperties\n\t\t\t\t.getProperty(\"javax2.net.ssl.keyStore\");\n\t\tString trustStoreFile = configurationProperties\n\t\t\t\t.getProperty(\"javax2.net.ssl.trustStore\");\n\t\tif (keyStoreFile != null) {\n\t\t\tif (trustStoreFile == null) {\n\t\t\t\ttrustStoreFile = keyStoreFile;\n\t\t\t}\n\t\t\tString keyStorePassword = configurationProperties\n\t\t\t\t\t.getProperty(\"javax2.net.ssl.keyStorePassword\");\n\t\t\ttry {\n\t\t\t\tthis.networkLayer = new SslNetworkLayer(trustStoreFile,\n\t\t\t\t\t\tkeyStoreFile, keyStorePassword.toCharArray(),\n\t\t\t\t\t\tconfigurationProperties\n\t\t\t\t\t\t\t\t.getProperty(\"javax2.net.ssl.keyStoreType\"));\n\t\t\t} catch (Exception e1) {\n\t\t\t\tgetStackLogger().logError(\n\t\t\t\t\t\t\"could not instantiate SSL networking\", e1);\n\t\t\t}\n\t\t}\n\n\t\t// Set the auto dialog support flag.\n\t\tsuper.isAutomaticDialogSupportEnabled = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.AUTOMATIC_DIALOG_SUPPORT\", \"on\")\n\t\t\t\t.equalsIgnoreCase(\"on\");\n\n\t\tsuper.isAutomaticDialogErrorHandlingEnabled = configurationProperties\n\t\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.AUTOMATIC_DIALOG_ERROR_HANDLING\",\"true\")\n\t\t\t\t\t.equals(Boolean.TRUE.toString());\n\t\tif ( super.isAutomaticDialogSupportEnabled ) {\n\t\t\tsuper.isAutomaticDialogErrorHandlingEnabled = true;\n\t\t}\n\t\n\t\tif (configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME\") != null) {\n\t\t\tsuper.maxListenerResponseTime = Integer\n\t\t\t\t\t.parseInt(configurationProperties\n\t\t\t\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME\"));\n\t\t\tif (super.maxListenerResponseTime <= 0)\n\t\t\t\tthrow new PeerUnavailableException(\n\t\t\t\t\t\t\"Bad configuration parameter gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME : should be positive\");\n\t\t} else {\n\t\t\tsuper.maxListenerResponseTime = -1;\n\t\t}\n\n\t\t\n\n\t\tthis.deliverTerminatedEventForAck = configurationProperties\n\t\t\t\t.getProperty(\n\t\t\t\t\t\t\"gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_ACK\",\n\t\t\t\t\t\t\"false\").equalsIgnoreCase(\"true\");\n\n\t\tthis.deliverUnsolicitedNotify = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.DELIVER_UNSOLICITED_NOTIFY\", \"false\")\n\t\t\t\t.equalsIgnoreCase(\"true\");\n\n\t\tString forkedSubscriptions = configurationProperties\n\t\t\t\t.getProperty(\"javax2.sip.FORKABLE_EVENTS\");\n\t\tif (forkedSubscriptions != null) {\n\t\t\tStringTokenizer st = new StringTokenizer(forkedSubscriptions);\n\t\t\twhile (st.hasMoreTokens()) {\n\t\t\t\tString nextEvent = st.nextToken();\n\t\t\t\tthis.forkedEvents.add(nextEvent);\n\t\t\t}\n\t\t}\n\n\t\t// The following features are unique to the NIST implementation.\n\n\t\t/*\n\t\t * gets the NetworkLayer implementation, if any. Note that this is a\n\t\t * NIST only feature.\n\t\t */\n\n\t\tfinal String NETWORK_LAYER_KEY = \"gov2.nist.javax2.sip.NETWORK_LAYER\";\n\n\t\tif (configurationProperties.containsKey(NETWORK_LAYER_KEY)) {\n\t\t\tString path = configurationProperties\n\t\t\t\t\t.getProperty(NETWORK_LAYER_KEY);\n\t\t\ttry {\n\t\t\t\tClass<?> clazz = Class.forName(path);\n\t\t\t\tConstructor<?> c = clazz.getConstructor(new Class[0]);\n\t\t\t\tnetworkLayer = (NetworkLayer) c.newInstance(new Object[0]);\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new PeerUnavailableException(\n\t\t\t\t\t\t\"can't find or instantiate NetworkLayer implementation: \"\n\t\t\t\t\t\t\t\t+ path);\n\t\t\t}\n\t\t}\n\n\t\tfinal String ADDRESS_RESOLVER_KEY = \"gov2.nist.javax2.sip.ADDRESS_RESOLVER\";\n\n\t\tif (configurationProperties.containsKey(ADDRESS_RESOLVER_KEY)) {\n\t\t\tString path = configurationProperties\n\t\t\t\t\t.getProperty(ADDRESS_RESOLVER_KEY);\n\t\t\ttry {\n\t\t\t\tClass<?> clazz = Class.forName(path);\n\t\t\t\tConstructor<?> c = clazz.getConstructor(new Class[0]);\n\t\t\t\tthis.addressResolver = (AddressResolver) c\n\t\t\t\t\t\t.newInstance(new Object[0]);\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new PeerUnavailableException(\n\t\t\t\t\t\t\"can't find or instantiate AddressResolver implementation: \"\n\t\t\t\t\t\t\t\t+ path);\n\t\t\t}\n\t\t}\n\n\t\tString maxConnections = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.MAX_CONNECTIONS\");\n\t\tif (maxConnections != null) {\n\t\t\ttry {\n\t\t\t\tthis.maxConnections = new Integer(maxConnections).intValue();\n\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tgetStackLogger().logError(\n\t\t\t\t\t\t\"max connections - bad value \" + ex.getMessage());\n\t\t\t}\n\t\t}\n\n\t\tString threadPoolSize = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.THREAD_POOL_SIZE\");\n\t\tif (threadPoolSize != null) {\n\t\t\ttry {\n\t\t\t\tthis.threadPoolSize = new Integer(threadPoolSize).intValue();\n\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tthis.getStackLogger().logError(\n\t\t\t\t\t\t\"thread pool size - bad value \" + ex.getMessage());\n\t\t\t}\n\t\t}\n\n\t\tString serverTransactionTableSize = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.MAX_SERVER_TRANSACTIONS\");\n\t\tif (serverTransactionTableSize != null) {\n\t\t\ttry {\n\t\t\t\tthis.serverTransactionTableHighwaterMark = new Integer(\n\t\t\t\t\t\tserverTransactionTableSize).intValue();\n\t\t\t\tthis.serverTransactionTableLowaterMark = this.serverTransactionTableHighwaterMark * 80 / 100;\n\t\t\t\t// Lowater is 80% of highwater\n\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tthis.getStackLogger()\n\t\t\t\t\t\t.logError(\n\t\t\t\t\t\t\t\t\"transaction table size - bad value \"\n\t\t\t\t\t\t\t\t\t\t+ ex.getMessage());\n\t\t\t}\n\t\t} else {\n\t\t\t// Issue 256 : consistent with MAX_CLIENT_TRANSACTIONS, if the MAX_SERVER_TRANSACTIONS is not set\n\t\t\t// we assume the transaction table size can grow unlimited\n\t\t\tthis.unlimitedServerTransactionTableSize = true;\n\t\t}\n\n\t\tString clientTransactionTableSize = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.MAX_CLIENT_TRANSACTIONS\");\n\t\tif (clientTransactionTableSize != null) {\n\t\t\ttry {\n\t\t\t\tthis.clientTransactionTableHiwaterMark = new Integer(\n\t\t\t\t\t\tclientTransactionTableSize).intValue();\n\t\t\t\tthis.clientTransactionTableLowaterMark = this.clientTransactionTableLowaterMark * 80 / 100;\n\t\t\t\t// Lowater is 80% of highwater\n\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tthis.getStackLogger()\n\t\t\t\t\t\t.logError(\n\t\t\t\t\t\t\t\t\"transaction table size - bad value \"\n\t\t\t\t\t\t\t\t\t\t+ ex.getMessage());\n\t\t\t}\n\t\t} else {\n\t\t\tthis.unlimitedClientTransactionTableSize = true;\n\t\t}\n\n\t\tsuper.cacheServerConnections = true;\n\t\tString flag = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS\");\n\n\t\tif (flag != null && \"false\".equalsIgnoreCase(flag.trim())) {\n\t\t\tsuper.cacheServerConnections = false;\n\t\t}\n\n\t\tsuper.cacheClientConnections = true;\n\t\tString cacheflag = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.CACHE_CLIENT_CONNECTIONS\");\n\n\t\tif (cacheflag != null && \"false\".equalsIgnoreCase(cacheflag.trim())) {\n\t\t\tsuper.cacheClientConnections = false;\n\t\t}\n\n\t\tString readTimeout = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.READ_TIMEOUT\");\n\t\tif (readTimeout != null) {\n\t\t\ttry {\n\n\t\t\t\tint rt = Integer.parseInt(readTimeout);\n\t\t\t\tif (rt >= 100) {\n\t\t\t\t\tsuper.readTimeout = rt;\n\t\t\t\t} else {\n\t\t\t\t\tSystem.err.println(\"Value too low \" + readTimeout);\n\t\t\t\t}\n\t\t\t} catch (NumberFormatException nfe) {\n\t\t\t\t// Ignore.\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tgetStackLogger().logError(\"Bad read timeout \" + readTimeout);\n\t\t\t}\n\t\t}\n\n\t\t// Get the address of the stun server.\n\n\t\tString stunAddr = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.STUN_SERVER\");\n\n\t\tif (stunAddr != null)\n\t\t\tif (isLoggingEnabled())\n\t\t\t\tthis.getStackLogger().logWarning(\n\t\t\t\t\t\"Ignoring obsolete property \"\n\t\t\t\t\t\t\t+ \"gov2.nist.javax2.sip.STUN_SERVER\");\n\n\t\tString maxMsgSize = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.MAX_MESSAGE_SIZE\");\n\n\t\ttry {\n\t\t\tif (maxMsgSize != null) {\n\t\t\t\tsuper.maxMessageSize = new Integer(maxMsgSize).intValue();\n\t\t\t\tif (super.maxMessageSize < 4096)\n\t\t\t\t\tsuper.maxMessageSize = 4096;\n\t\t\t} else {\n\t\t\t\t// Allow for \"infinite\" size of message\n\t\t\t\tsuper.maxMessageSize = 0;\n\t\t\t}\n\t\t} catch (NumberFormatException ex) {\n\t\t\tif (isLoggingEnabled())\n\t\t\t\tgetStackLogger().logError(\n\t\t\t\t\t\"maxMessageSize - bad value \" + ex.getMessage());\n\t\t}\n\n\t\tString rel = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.REENTRANT_LISTENER\");\n\t\tthis.reEntrantListener = (rel != null && \"true\".equalsIgnoreCase(rel));\n\n\t\t// Check if a thread audit interval is specified\n\t\tString interval = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS\");\n\t\tif (interval != null) {\n\t\t\ttry {\n\t\t\t\t// Make the monitored threads ping the auditor twice as fast as\n\t\t\t\t// the audits\n\t\t\t\tgetThreadAuditor().setPingIntervalInMillisecs(\n\t\t\t\t\t\tLong.valueOf(interval).longValue() / 2);\n\t\t\t} catch (NumberFormatException ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tgetStackLogger().logError(\n\t\t\t\t\t\t\"THREAD_AUDIT_INTERVAL_IN_MILLISECS - bad value [\"\n\t\t\t\t\t\t\t\t+ interval + \"] \" + ex.getMessage());\n\t\t\t}\n\t\t}\n\n\t\t// JvB: added property for testing\n\t\tthis\n\t\t\t\t.setNon2XXAckPassedToListener(Boolean\n\t\t\t\t\t\t.valueOf(\n\t\t\t\t\t\t\t\tconfigurationProperties\n\t\t\t\t\t\t\t\t\t\t.getProperty(\n\t\t\t\t\t\t\t\t\t\t\t\t\"gov2.nist.javax2.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"false\")).booleanValue());\n\n\t\tthis.generateTimeStampHeader = Boolean.valueOf(\n\t\t\t\tconfigurationProperties.getProperty(\n\t\t\t\t\t\t\"gov2.nist.javax2.sip.AUTO_GENERATE_TIMESTAMP\", \"false\"))\n\t\t\t\t.booleanValue();\n\n\t\tString messageLogFactoryClasspath = configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.LOG_FACTORY\");\n\t\tif (messageLogFactoryClasspath != null) {\n\t\t\ttry {\n\t\t\t\tClass<?> clazz = Class.forName(messageLogFactoryClasspath);\n\t\t\t\tConstructor<?> c = clazz.getConstructor(new Class[0]);\n\t\t\t\tthis.logRecordFactory = (LogRecordFactory) c\n\t\t\t\t\t\t.newInstance(new Object[0]);\n\t\t\t} catch (Exception ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tgetStackLogger()\n\t\t\t\t\t\t.logError(\n\t\t\t\t\t\t\t\t\"Bad configuration value for LOG_FACTORY -- using default logger\");\n\t\t\t\tthis.logRecordFactory = new DefaultMessageLogFactory();\n\t\t\t}\n\n\t\t} else {\n\t\t\tthis.logRecordFactory = new DefaultMessageLogFactory();\n\t\t}\n\n\t\tboolean computeContentLength = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY\",\n\t\t\t\t\"false\").equalsIgnoreCase(\"true\");\n\t\tStringMsgParser\n\t\t\t\t.setComputeContentLengthFromMessage(computeContentLength);\n\n\t\tString tlsClientProtocols = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.TLS_CLIENT_PROTOCOLS\");\n\t\tif (tlsClientProtocols != null)\n\t\t{\n\t\t\tStringTokenizer st = new StringTokenizer(tlsClientProtocols, \" ,\");\n\t\t\tString[] protocols = new String[st.countTokens()];\n\t\t\t\n\t\t\tint i=0;\n\t\t\twhile (st.hasMoreTokens()) {\n\t\t\t\tprotocols[i++] = st.nextToken();\n\t\t\t}\n\t\t\tthis.enabledProtocols = protocols;\n\t\t}\n\n\t\tsuper.rfc2543Supported = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.RFC_2543_SUPPORT_ENABLED\", \"true\")\n\t\t\t\t.equalsIgnoreCase(\"true\");\n\n\t\tsuper.cancelClientTransactionChecked = configurationProperties\n\t\t\t\t.getProperty(\n\t\t\t\t\t\t\"gov2.nist.javax2.sip.CANCEL_CLIENT_TRANSACTION_CHECKED\",\n\t\t\t\t\t\t\"true\").equalsIgnoreCase(\"true\");\n\t\tsuper.logStackTraceOnMessageSend = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND\", \"false\")\n\t\t\t\t.equalsIgnoreCase(\"true\");\n\t\tif (isLoggingEnabled())\n\t\t\tgetStackLogger().logDebug(\n\t\t\t\t\"created Sip stack. Properties = \" + configurationProperties);\n\t\tInputStream in = getClass().getResourceAsStream(\"/TIMESTAMP\");\n\t\tif (in != null) {\n\t\t\tBufferedReader streamReader = new BufferedReader(\n\t\t\t\t\tnew InputStreamReader(in));\n\n\t\t\ttry {\n\t\t\t\tString buildTimeStamp = streamReader.readLine();\n\t\t\t\tif (in != null) {\n\t\t\t\t\tin.close();\n\t\t\t\t}\n\t\t\t\tgetStackLogger().setBuildTimeStamp(buildTimeStamp);\n\t\t\t} catch (IOException ex) {\n\t\t\t\tgetStackLogger().logError(\"Could not open build timestamp.\");\n\t\t\t}\n\t\t}\n\n\t\tString bufferSize = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.RECEIVE_UDP_BUFFER_SIZE\", MAX_DATAGRAM_SIZE\n\t\t\t\t\t\t.toString());\n\t\tint bufferSizeInteger = new Integer(bufferSize).intValue();\n\t\tsuper.setReceiveUdpBufferSize(bufferSizeInteger);\n\n\t\tbufferSize = configurationProperties.getProperty(\n\t\t\t\t\"gov2.nist.javax2.sip.SEND_UDP_BUFFER_SIZE\", MAX_DATAGRAM_SIZE\n\t\t\t\t\t\t.toString());\n\t\tbufferSizeInteger = new Integer(bufferSize).intValue();\n\t\tsuper.setSendUdpBufferSize(bufferSizeInteger);\n\n\t\tboolean congetstionControlEnabled = Boolean\n\t\t\t\t.parseBoolean(configurationProperties.getProperty(\n\t\t\t\t\t\t\"gov2.nist.javax2.sip.CONGESTION_CONTROL_ENABLED\",\n\t\t\t\t\t\tBoolean.TRUE.toString()));\n\t\tsuper.stackDoesCongestionControl = congetstionControlEnabled;\n\n\t\tsuper.isBackToBackUserAgent = Boolean\n\t\t\t\t.parseBoolean(configurationProperties.getProperty(\n\t\t\t\t\t\t\"gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT\",\n\t\t\t\t\t\tBoolean.FALSE.toString()));\n\t\tsuper.checkBranchId = Boolean.parseBoolean(configurationProperties\n\t\t\t\t.getProperty(\"gov2.nist.javax2.sip.REJECT_STRAY_RESPONSES\",\n\t\t\t\t\t\tBoolean.FALSE.toString()));\n\t\t\n\t\tsuper.isDialogTerminatedEventDeliveredForNullDialog = (Boolean.parseBoolean(configurationProperties.getProperty(\"gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG\",\n\t\t        Boolean.FALSE.toString())));\n\t\t\n\t\t\n\t\tsuper.maxForkTime = Integer.parseInt(\n\t\t        configurationProperties.getProperty(\"gov2.nist.javax2.sip.MAX_FORK_TIME_SECONDS\",\"0\"));\n\t\t\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#createListeningPoint(java.lang.String, int,\n\t * java.lang.String)\n\t */\n\tpublic synchronized ListeningPoint createListeningPoint(String address,\n\t\t\tint port, String transport) throws TransportNotSupportedException,\n\t\t\tInvalidArgumentException {\n\t\tif (isLoggingEnabled())\n\t\t\tgetStackLogger().logDebug(\n\t\t\t\t\"createListeningPoint : address = \" + address + \" port = \"\n\t\t\t\t\t\t+ port + \" transport = \" + transport);\n\n\t\tif (address == null)\n\t\t\tthrow new NullPointerException(\n\t\t\t\t\t\"Address for listening point is null!\");\n\t\tif (transport == null)\n\t\t\tthrow new NullPointerException(\"null transport\");\n\t\tif (port <= 0)\n\t\t\tthrow new InvalidArgumentException(\"bad port\");\n\n\t\tif (!transport.equalsIgnoreCase(\"UDP\")\n\t\t\t\t&& !transport.equalsIgnoreCase(\"TLS\")\n\t\t\t\t&& !transport.equalsIgnoreCase(\"TCP\")\n\t\t\t\t&& !transport.equalsIgnoreCase(\"SCTP\"))\n\t\t\tthrow new TransportNotSupportedException(\"bad transport \"\n\t\t\t\t\t+ transport);\n\n\t\t/** Reusing an old stack instance */\n\t\tif (!this.isAlive()) {\n\t\t\tthis.toExit = false;\n\t\t\tthis.reInitialize();\n\t\t}\n\n\t\tString key = ListeningPointImpl.makeKey(address, port, transport);\n\n\t\tListeningPointImpl lip = listeningPoints.get(key);\n\t\tif (lip != null) {\n\t\t\treturn lip;\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tInetAddress inetAddr = InetAddress.getByName(address);\n\t\t\t\tMessageProcessor messageProcessor = this\n\t\t\t\t\t\t.createMessageProcessor(inetAddr, port, transport);\n\t\t\t\tif (this.isLoggingEnabled()) {\n\t\t\t\t\tthis.getStackLogger().logDebug(\n\t\t\t\t\t\t\t\"Created Message Processor: \" + address\n\t\t\t\t\t\t\t\t\t+ \" port = \" + port + \" transport = \"\n\t\t\t\t\t\t\t\t\t+ transport);\n\t\t\t\t}\n\t\t\t\tlip = new ListeningPointImpl(this, port, transport);\n\t\t\t\tlip.messageProcessor = messageProcessor;\n\t\t\t\tmessageProcessor.setListeningPoint(lip);\n\t\t\t\tthis.listeningPoints.put(key, lip);\n\t\t\t\t// start processing messages.\n\t\t\t\tmessageProcessor.start();\n\t\t\t\treturn (ListeningPoint) lip;\n\t\t\t} catch (java.io.IOException ex) {\n\t\t\t\tif (isLoggingEnabled())\n\t\t\t\t\tgetStackLogger().logError(\n\t\t\t\t\t\t\"Invalid argument address = \" + address + \" port = \"\n\t\t\t\t\t\t\t\t+ port + \" transport = \" + transport);\n\t\t\t\tthrow new InvalidArgumentException(ex.getMessage(), ex);\n\t\t\t}\n\t\t}\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#createSipProvider(javax2.sip.ListeningPoint)\n\t */\n\tpublic SipProvider createSipProvider(ListeningPoint listeningPoint)\n\t\t\tthrows ObjectInUseException {\n\t\tif (listeningPoint == null)\n\t\t\tthrow new NullPointerException(\"null listeningPoint\");\n\t\tif (this.isLoggingEnabled())\n\t\t\tthis.getStackLogger().logDebug(\n\t\t\t\t\t\"createSipProvider: \" + listeningPoint);\n\t\tListeningPointImpl listeningPointImpl = (ListeningPointImpl) listeningPoint;\n\t\tif (listeningPointImpl.sipProvider != null)\n\t\t\tthrow new ObjectInUseException(\"Provider already attached!\");\n\n\t\tSipProviderImpl provider = new SipProviderImpl(this);\n\n\t\tprovider.setListeningPoint(listeningPointImpl);\n\t\tlisteningPointImpl.sipProvider = provider;\n\t\tthis.sipProviders.add(provider);\n\t\treturn provider;\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#deleteListeningPoint(javax2.sip.ListeningPoint)\n\t */\n\tpublic void deleteListeningPoint(ListeningPoint listeningPoint)\n\t\t\tthrows ObjectInUseException {\n\t\tif (listeningPoint == null)\n\t\t\tthrow new NullPointerException(\"null listeningPoint arg\");\n\t\tListeningPointImpl lip = (ListeningPointImpl) listeningPoint;\n\t\t// Stop the message processing thread in the listening point.\n\t\tsuper.removeMessageProcessor(lip.messageProcessor);\n\t\tString key = lip.getKey();\n\t\tthis.listeningPoints.remove(key);\n\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#deleteSipProvider(javax2.sip.SipProvider)\n\t */\n\tpublic void deleteSipProvider(SipProvider sipProvider)\n\t\t\tthrows ObjectInUseException {\n\n\t\tif (sipProvider == null)\n\t\t\tthrow new NullPointerException(\"null provider arg\");\n\t\tSipProviderImpl sipProviderImpl = (SipProviderImpl) sipProvider;\n\n\t\t// JvB: API doc is not clear, but in_use ==\n\t\t// sipProviderImpl.sipListener!=null\n\t\t// so we should throw if app did not call removeSipListener\n\t\t// sipProviderImpl.sipListener = null;\n\t\tif (sipProviderImpl.getSipListener() != null) {\n\t\t\tthrow new ObjectInUseException(\n\t\t\t\t\t\"SipProvider still has an associated SipListener!\");\n\t\t}\n\n\t\tsipProviderImpl.removeListeningPoints();\n\n\t\t// Bug reported by Rafael Barriuso\n\t\tsipProviderImpl.stop();\n\t\tsipProviders.remove(sipProvider);\n\t\tif (sipProviders.isEmpty()) {\n\t\t\tthis.stopStack();\n\t\t}\n\t}\n\n\t/**\n\t * Get the IP Address of the stack.\n\t * \n\t * @see javax2.sip.SipStack#getIPAddress()\n\t * @deprecated\n\t */\n\tpublic String getIPAddress() {\n\t\treturn super.getHostAddress();\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#getListeningPoints()\n\t */\n\tpublic java.util.Iterator<ListeningPointImpl> getListeningPoints() {\n\t\treturn this.listeningPoints.values().iterator();\n\t}\n\n\t/**\n\t * Return true if retransmission filter is active.\n\t * \n\t * @see javax2.sip.SipStack#isRetransmissionFilterActive()\n\t * @deprecated\n\t */\n\tpublic boolean isRetransmissionFilterActive() {\n\t\treturn true;\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#getSipProviders()\n\t */\n\tpublic java.util.Iterator<SipProviderImpl> getSipProviders() {\n\t\treturn this.sipProviders.iterator();\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#getStackName()\n\t */\n\tpublic String getStackName() {\n\t\treturn this.stackName;\n\t}\n\n\t/**\n\t * Finalization -- stop the stack on finalization. Exit the transaction\n\t * scanner and release all resources.\n\t * \n\t * @see java.lang.Object#finalize()\n\t */\n\tprotected void finalize() {\n\t\tthis.stopStack();\n\t}\n\n\t/**\n\t * This uses the default stack address to create a listening point.\n\t * \n\t * @see javax2.sip.SipStack#createListeningPoint(java.lang.String, int,\n\t *      java.lang.String)\n\t * @deprecated\n\t */\n\tpublic ListeningPoint createListeningPoint(int port, String transport)\n\t\t\tthrows TransportNotSupportedException, InvalidArgumentException {\n\t\tif (super.stackAddress == null)\n\t\t\tthrow new NullPointerException(\n\t\t\t\t\t\"Stack does not have a default IP Address!\");\n\t\treturn this.createListeningPoint(super.stackAddress, port, transport);\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#stop()\n\t */\n\tpublic void stop() {\n\t\tif (isLoggingEnabled()) {\n\t\t\tgetStackLogger().logDebug(\"stopStack -- stoppping the stack\");\n\t\t}\n\t\tthis.stopStack();\n\t\tthis.sipProviders = new LinkedList<SipProviderImpl>();\n\t\tthis.listeningPoints = new Hashtable<String, ListeningPointImpl>();\n\t\t/*\n\t\t * Check for presence of an event scanner ( may happen if stack is\n\t\t * stopped before listener is attached ).\n\t\t */\n\t\tif (this.eventScanner != null)\n\t\t\tthis.eventScanner.forceStop();\n\t\tthis.eventScanner = null;\n\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see javax2.sip.SipStack#start()\n\t */\n\tpublic void start() throws ProviderDoesNotExistException, SipException {\n\t\t// Start a new event scanner if one does not exist.\n\t\tif (this.eventScanner == null) {\n\t\t\tthis.eventScanner = new EventScanner(this);\n\t\t}\n\n\t}\n\n\t/**\n\t * Get the listener for the stack. A stack can have only one listener. To\n\t * get an event from a provider, the listener has to be registered with the\n\t * provider. The SipListener is application code.\n\t * \n\t * @return -- the stack SipListener\n\t * \n\t */\n\tpublic SipListener getSipListener() {\n\t\treturn this.sipListener;\n\t}\n\n\t/**\n\t * Get the message log factory registered with the stack.\n\t * \n\t * @return -- the messageLogFactory of the stack.\n\t */\n\tpublic LogRecordFactory getLogRecordFactory() {\n\t\treturn super.logRecordFactory;\n\t}\n\n\t/**\n\t * Set the log appender ( this is useful if you want to specify a particular\n\t * log format or log to something other than a file for example). This method\n\t * is will be removed May 11, 2010 or shortly there after.\n\t * \n\t * @param Appender\n\t *            - the log4j appender to add.\n\t * @deprecated TODO: remove this method May 11, 2010.\n\t */\n        // BEGIN android-deleted\n\t/*\n        @Deprecated\n\tpublic void addLogAppender(org.apache.log4j.Appender appender) {\n\t\tif (this.getStackLogger() instanceof gov2.nist.core.LogWriter) {\n\t\t\t((gov2.nist.core.LogWriter) this.getStackLogger()).addAppender(appender);\n\t\t}\n\t}\n        */\n        // END android-deleted\n\n\t/**\n\t * Get the log4j logger ( for log stream integration ).\n\t * This method will be removed May 11, 2010 or shortly there after.\n\t * \n\t * @return  the log4j logger.\n\t * @deprecated TODO: This method will be removed May 11, 2010.\n\t */\n\t@Deprecated\n        // BEGIN andoird-deleted\n        /*\n\tpublic org.apache.log4j.Logger getLogger() {\n\t\tif (this.getStackLogger() instanceof gov2.nist.core.LogWriter) {\n\t\t\treturn ((gov2.nist.core.LogWriter) this.getStackLogger()).getLogger();\n\t\t}\n\t\treturn null;\n\t}\n        */\n        // END android-deleted\n\n\tpublic EventScanner getEventScanner() {\n\t\treturn eventScanner;\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see\n\t * gov2.nist.javax2.sip.SipStackExt#getAuthenticationHelper(gov2.nist.javax2\n\t * .sip.clientauthutils.AccountManager, javax2.sip.header.HeaderFactory)\n\t */\n\tpublic AuthenticationHelper getAuthenticationHelper(\n\t\t\tAccountManager accountManager, HeaderFactory headerFactory) {\n\t\treturn new AuthenticationHelperImpl(this, accountManager, headerFactory);\n\t}\n\n\t/*\n\t * (non-Javadoc)\n\t * \n\t * @see\n\t * gov2.nist.javax2.sip.SipStackExt#getAuthenticationHelper(gov2.nist.javax2\n\t * .sip.clientauthutils.AccountManager, javax2.sip.header.HeaderFactory)\n\t */\n\tpublic AuthenticationHelper getSecureAuthenticationHelper(\n\t\t\tSecureAccountManager accountManager, HeaderFactory headerFactory) {\n\t\treturn new AuthenticationHelperImpl(this, accountManager, headerFactory);\n\t}\n\n\t/**\n\t * Set the list of cipher suites supported by the stack. A stack can have\n\t * only one set of suites. These are not validated against the supported\n\t * cipher suites of the java runtime, so specifying a cipher here does not\n\t * guarantee that it will work.<br>\n\t * The stack has a default cipher suite of:\n\t * <ul>\n\t * <li>TLS_RSA_WITH_AES_128_CBC_SHA</li>\n\t * <li>SSL_RSA_WITH_3DES_EDE_CBC_SHA</li>\n\t * <li>TLS_DH_anon_WITH_AES_128_CBC_SHA</li>\n\t * <li>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</li>\n\t * </ul>\n\t * \n\t * <b>NOTE: This function must be called before adding a TLS listener</b>\n\t * \n\t * @param String\n\t *            [] The new set of ciphers to support.\n\t * @return\n\t * \n\t */\n\tpublic void setEnabledCipherSuites(String[] newCipherSuites) {\n\t\tcipherSuites = newCipherSuites;\n\t}\n\n\t/**\n\t * Return the currently enabled cipher suites of the Stack.\n\t * \n\t * @return The currently enabled cipher suites.\n\t */\n\tpublic String[] getEnabledCipherSuites() {\n\t\treturn cipherSuites;\n\t}\n\n\t/**\n\t * Set the list of protocols supported by the stack for outgoing TLS connections.\n\t * A stack can have only one set of protocols.\n\t * These are not validated against the supported\n\t * protocols of the java runtime, so specifying a protocol here does not\n\t * guarantee that it will work.<br>\n\t * The stack has a default protocol suite of:\n\t * <ul>\n\t * <li>SSLv3</li>\n\t * <li>SSLv2Hello</li>\n\t * <li>TLSv1</li>\n\t * </ul>\n\t * \n\t * <b>NOTE: This function must be called before creating a TLSMessageChannel.</b>\n\t * \n\t * @param String\n\t *            [] The new set of protocols to use for outgoing TLS connections.\n\t * @return\n\t * \n\t */\n\tpublic void setEnabledProtocols(String[] newProtocols) {\n\t\tenabledProtocols = newProtocols;\n\t}\n\n\t/**\n\t * Return the currently enabled protocols to use when creating TLS connection.\n\t * \n\t * @return The currently enabled protocols.\n\t */\n\tpublic String[] getEnabledProtocols() {\n\t\treturn enabledProtocols;\n\t}\n\n\t/**\n\t * Set the \"back to back User Agent\" flag.\n\t * \n\t * @param flag\n\t *            - boolean flag to set.\n\t * \n\t */\n\tpublic void setIsBackToBackUserAgent(boolean flag) {\n\t\tsuper.isBackToBackUserAgent = flag;\n\t}\n\t\n\t/**\n\t * Get the \"back to back User Agent\" flag.\n\t * \n\t * return the value of the flag\n\t * \n\t */\n\tpublic boolean isBackToBackUserAgent() {\n\t\treturn super.isBackToBackUserAgent;\n\t}\n\n\tpublic boolean isAutomaticDialogErrorHandlingEnabled() {\n\t\treturn super.isAutomaticDialogErrorHandlingEnabled;\n\t}\n\n    public boolean acquireSem() {\n        try {\n            return this.stackSemaphore.tryAcquire(10, TimeUnit.SECONDS);\n        } catch ( InterruptedException ex) {\n            return false;\n        }\n    }\n    \n    public void releaseSem() {\n        this.stackSemaphore.release();\n    }\n\n\n    \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/TransactionExt.java",
    "content": "\npackage gov2.nist.javax2.sip;\n\nimport java.security.cert.Certificate;\n\nimport javax.net.ssl.SSLPeerUnverifiedException;\nimport javax2.sip.SipProvider;\nimport javax2.sip.Transaction;\n\npublic interface TransactionExt extends Transaction {\n\n    /**\n     * Get the Sip Provider associated with this transaction\n     */\n    public SipProvider getSipProvider();\n\n    /**\n     * Returns the IP address of the upstream/downstream hop from which this message was initially received\n     * @return the IP address of the upstream/downstream hop from which this message was initially received\n     * @since 2.0\n     */\n    public String getPeerAddress();\n    /**\n     * Returns the port of the upstream/downstream hop from which this message was initially received\n     * @return the port of the upstream/downstream hop from which this message was initially received\n     * @since 2.0\n     */\n    public int getPeerPort();\n    /**\n     * Returns the name of the protocol with which this message was initially received\n     * @return the name of the protocol with which this message was initially received\n     * @since 2.0\n     */\n    public String getTransport();\n\n    /**\n     * return the ip address on which this message was initially received\n     * @return the ip address on which this message was initially received\n     */\n    public String getHost();\n    /**\n     * return the port on which this message was initially received\n     * @return the port on which this message was initially received\n     */\n    public int getPort();\n    \n    /**\n     * Return the Cipher Suite that was used for the SSL handshake. \n     * \n     * @return     Returns the cipher suite in use by the session which was produced by the handshake.\n     * @throw UnsupportedOperationException if this is not a secure client transaction.\n     */\n    public String getCipherSuite() throws UnsupportedOperationException;\n    \n    /**\n     * Get the certificate(s) that were sent to the peer during handshaking.\n     *@return the certificate(s) that were sent to the peer during handshaking.\n     *@throw UnsupportedOperationException if this is not a secure client transaction.\n     * \n     */\n   Certificate[] getLocalCertificates() throws UnsupportedOperationException;\n    \n    /**\n     * @return the identity of the peer which was identified as part of defining the session.\n     * @throws SSLPeerUnverifiedException \n     * @throw UnsupportedOperationException if this is not a secure client transaction.\n     */\n   Certificate[]  getPeerCertificates() throws SSLPeerUnverifiedException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/Utils.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n *******************************************************************************/\npackage gov2.nist.javax2.sip;\n\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.security.MessageDigest;\nimport java.util.HashSet;\n\n/**\n * A few utilities that are used in various places by the stack. This is used to\n * convert byte arrays to hex strings etc. Generate tags and branch identifiers\n * and odds and ends.\n *\n * @author mranga\n * @version 1.2 $Revision: 1.21 $ $Date: 2009/10/18 13:46:37 $\n */\npublic class Utils implements UtilsExt {\n\n    private static MessageDigest digester;\n   \n    private static java.util.Random rand;\n   \n    private static long counter = 0;\n\n    private static int callIDCounter;\n\n    private static String signature ;\n    \n    private static Utils instance = new Utils();\n\n    \n    /**\n     * to hex converter\n     */\n    private static final char[] toHex = { '0', '1', '2', '3', '4', '5', '6',\n            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\n    static {\n        try {\n            digester = MessageDigest.getInstance(\"MD5\");\n        } catch (Exception ex) {\n            throw new RuntimeException(\"Could not intialize Digester \", ex);\n        }\n        rand = new java.util.Random();\n        signature = toHexString(Integer.toString(Math.abs( rand.nextInt() % 1000 )).getBytes());\n    }\n\n   \n    public static Utils getInstance() {\n        return instance;\n    }\n   \n    /**\n     * convert an array of bytes to an hexadecimal string\n     *\n     * @return a string\n     * @param b\n     *            bytes array to convert to a hexadecimal string\n     */\n\n    public static String toHexString(byte b[]) {\n        int pos = 0;\n        char[] c = new char[b.length * 2];\n        for (int i = 0; i < b.length; i++) {\n            c[pos++] = toHex[(b[i] >> 4) & 0x0F];\n            c[pos++] = toHex[b[i] & 0x0f];\n        }\n        return new String(c);\n    }\n\n    /**\n     * Put quotes around a string and return it.\n     * Any \" characters appearing in str are escaped\n     *\n     * @return a quoted string\n     * @param str\n     *            string to be quoted\n     */\n    public static String getQuotedString(String str) {\n        return '\"' + str.replace( \"\\\"\", \"\\\\\\\"\" ) + '\"';\n    }\n\n    /**\n     * Squeeze out all white space from a string and return the reduced string.\n     *\n     * @param input\n     *            input string to sqeeze.\n     * @return String a reduced string.\n     */\n    protected static String reduceString(String input) {\n        String newString = input.toLowerCase();\n        int len = newString.length();\n        String retval = \"\";\n        for (int i = 0; i < len; i++) {\n            if (newString.charAt(i) == ' ' || newString.charAt(i) == '\\t')\n                continue;\n            else\n                retval += newString.charAt(i);\n        }\n        return retval;\n    }\n\n    /**\n     * Generate a call identifier. This is useful when we want to generate a\n     * call identifier in advance of generating a message.\n     */\n    public synchronized String generateCallIdentifier(String address) {\n\n            String date = Long.toString(System.currentTimeMillis() + callIDCounter++\n                    + rand.nextLong());\n            byte cid[] = digester.digest(date.getBytes());\n\n            String cidString = Utils.toHexString(cid);\n            return cidString + \"@\" + address;\n\n    }\n\n    /**\n     * Generate a tag for a FROM header or TO header. Just return a random 4\n     * digit integer (should be enough to avoid any clashes!) Tags only need to\n     * be unique within a call.\n     *\n     * @return a string that can be used as a tag parameter.\n     *\n     * synchronized: needed for access to 'rand', else risk to generate same tag\n     * twice\n     */\n    public synchronized String generateTag() {\n\n            return Integer.toHexString(rand.nextInt());\n\n    }\n\n    /**\n     * Generate a cryptographically random identifier that can be used to\n     * generate a branch identifier.\n     *\n     * @return a cryptographically random gloablly unique string that can be\n     *         used as a branch identifier.\n     */\n    public synchronized String generateBranchId() {\n        //\n\n\n            long num = rand.nextLong() + Utils.counter++  + System.currentTimeMillis();\n\n            byte bid[] = digester.digest(Long.toString(num).getBytes());\n            // prepend with a magic cookie to indicate we are bis09 compatible.\n            return SIPConstants.BRANCH_MAGIC_COOKIE + Utils.toHexString(bid) + this.signature;\n\n\n    }\n    \n    public boolean responseBelongsToUs(SIPResponse response) {\n        Via topmostVia = response.getTopmostVia();\n        String branch = topmostVia.getBranch();\n        return branch != null && branch.endsWith(this.signature);\n    }\n    \n    public static String getSignature() {\n        return signature;\n    }\n\n    public static void main(String[] args) {\n        HashSet branchIds = new HashSet();\n        for (int b = 0; b < 100000; b++) {\n            String bid = Utils.getInstance().generateBranchId();\n            if (branchIds.contains(bid)) {\n                throw new RuntimeException(\"Duplicate Branch ID\");\n            } else {\n                branchIds.add(bid);\n            }\n        }\n        System.out.println(\"Done!!\");\n\n    }\n\n  \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/UtilsExt.java",
    "content": "/*\n * JBoss, Home of Professional Open Source\n * This code has been contributed to the public domain.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.javax2.sip;\n\n/**\n * @author jean.deruelle@gmail.com\n *\n */\npublic interface UtilsExt {\n\n    /**\n     * Generate a call identifier. This is useful when we want to generate a\n     * call identifier in advance of generating a message.\n     * @since 2.0\n     */\n    public String generateCallIdentifier(String address);\n\n    /**\n     * Generate a tag for a FROM header or TO header. Just return a random 4\n     * digit integer (should be enough to avoid any clashes!) Tags only need to\n     * be unique within a call.\n     *\n     * @return a string that can be used as a tag parameter.\n     *\n     * synchronized: needed for access to 'rand', else risk to generate same tag\n     * twice\n     * @since 2.0\n     */\n    public String generateTag();\n    /**\n     * Generate a cryptographically random identifier that can be used to\n     * generate a branch identifier.\n     *\n     * @return a cryptographically random gloablly unique string that can be\n     *         used as a branch identifier.\n     * @since 2.0\n     */\n    public String generateBranchId();\n    \n    \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/AddressFactoryImpl.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.address;\n\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.address.*;\n\n/**\n * Implementation of the JAIN-SIP address factory.\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/10/22 10:25:56 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>\n * Network Research Team (http://www-r2.u-strasbg.fr))<br/>\n * Louis Pasteur University - Strasbourg - France<br/>\n *\n */\npublic class AddressFactoryImpl implements javax2.sip.address.AddressFactory {\n\n    /** Creates a new instance of AddressFactoryImpl\n     */\n    public AddressFactoryImpl() {\n    }\n\n\n    /**\n     *\n     *Create an empty address object.\n     *\n     *SPEC_REVISION\n     */\n\n    public javax2.sip.address.Address createAddress() {\n        return new AddressImpl();\n    }\n    /**\n     * Creates an Address with the new display name and URI attribute\n     * values.\n     *\n     * @param displayName - the new string value of the display name of the\n     * address. A <code>null</code> value does not set the display name.\n     * @param uri - the new URI value of the address.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the displayName value.\n     */\n    public javax2.sip.address.Address createAddress(\n        String displayName,\n        javax2.sip.address.URI uri) {\n        if (uri == null)\n            throw new NullPointerException(\"null  URI\");\n        AddressImpl addressImpl = new AddressImpl();\n        if (displayName != null)\n            addressImpl.setDisplayName(displayName);\n        addressImpl.setURI(uri);\n        return addressImpl;\n\n    }\n\n    /** create a sip uri.\n     *\n     *@param uri -- the uri to parse.\n     */\n    public javax2.sip.address.SipURI createSipURI(String uri)\n    //  throws java.net.URISyntaxException {\n    throws ParseException {\n        if (uri == null)\n            throw new NullPointerException(\"null URI\");\n        try {\n            StringMsgParser smp = new StringMsgParser();\n            SipUri sipUri = smp.parseSIPUrl(uri);\n            return (SipURI) sipUri;\n        } catch (ParseException ex) {\n            //  throw new java.net.URISyntaxException(uri, ex.getMessage());\n            throw new ParseException(ex.getMessage(), 0);\n        }\n\n    }\n\n    /** Create a SipURI\n     *\n     *@param user -- the user\n     *@param host -- the host.\n     */\n    public javax2.sip.address.SipURI createSipURI(String user, String host)\n        throws ParseException {\n        if (host == null)\n            throw new NullPointerException(\"null host\");\n\n        StringBuffer uriString = new StringBuffer(\"sip:\");\n        if (user != null) {\n            uriString.append(user);\n            uriString.append(\"@\");\n        }\n\n        //if host is an IPv6 string we should enclose it in sq brackets\n        if (host.indexOf(':') != host.lastIndexOf(':')\n            && host.trim().charAt(0) != '[')\n            host = '[' + host + ']';\n\n        uriString.append(host);\n\n        StringMsgParser smp = new StringMsgParser();\n        try {\n\n            SipUri sipUri = smp.parseSIPUrl(uriString.toString());\n            return sipUri;\n        } catch (ParseException ex) {\n            throw new ParseException(ex.getMessage(), 0);\n        }\n    }\n\n    /**\n     * Creates a TelURL based on given URI string. The scheme or '+' should\n     * not be included in the phoneNumber string argument.\n     *\n     * @param uri - the new string value of the phoneNumber.\n     * @throws URISyntaxException if the URI string is malformed.\n     */\n    public javax2.sip.address.TelURL createTelURL(String uri)\n        throws ParseException {\n        if (uri == null)\n            throw new NullPointerException(\"null url\");\n        String telUrl = \"tel:\" + uri;\n        try {\n            StringMsgParser smp = new StringMsgParser();\n            TelURLImpl timp = (TelURLImpl) smp.parseUrl(telUrl);\n            return (TelURL) timp;\n        } catch (ParseException ex) {\n            throw new ParseException(ex.getMessage(), 0);\n        }\n    }\n\n    public javax2.sip.address.Address createAddress(javax2.sip.address.URI uri) {\n        if (uri == null)\n            throw new NullPointerException(\"null address\");\n        AddressImpl addressImpl = new AddressImpl();\n        addressImpl.setURI(uri);\n        return addressImpl;\n    }\n\n    /**\n     * Creates an Address with the new address string value. The address\n     * string is parsed in order to create the new Address instance. Create\n     * with a String value of \"*\" creates a wildcard address. The wildcard\n     * can be determined if\n     * <code>((SipURI)Address.getURI).getUser() == *;</code>.\n     *\n     * @param address - the new string value of the address.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the address value.\n     */\n    public javax2.sip.address.Address createAddress(String address)\n        throws java.text.ParseException {\n        if (address == null)\n            throw new NullPointerException(\"null address\");\n\n        if (address.equals(\"*\")) {\n            AddressImpl addressImpl = new AddressImpl();\n            addressImpl.setAddressType(AddressImpl.WILD_CARD);\n            SipURI uri = new SipUri();\n            uri.setUser(\"*\");\n            addressImpl.setURI( uri );\n            return addressImpl;\n        } else {\n            StringMsgParser smp = new StringMsgParser();\n            return smp.parseAddress(address);\n        }\n    }\n\n    /**\n     * Creates a URI based on given URI string. The URI string is parsed in\n     * order to create the new URI instance. Depending on the scheme the\n     * returned may or may not be a SipURI or TelURL cast as a URI.\n     *\n     * @param uri - the new string value of the URI.\n     * @throws URISyntaxException if the URI string is malformed.\n     */\n\n    public javax2.sip.address.URI createURI(String uri) throws ParseException {\n        if (uri == null)\n            throw new NullPointerException(\"null arg\");\n        try {\n            URLParser urlParser = new URLParser(uri);\n            String scheme = urlParser.peekScheme();\n            if (scheme == null)\n                throw new ParseException(\"bad scheme\", 0);\n            if (scheme.equalsIgnoreCase(\"sip\")) {\n                return (javax2.sip.address.URI) urlParser.sipURL(true);\n            } else if (scheme.equalsIgnoreCase(\"sips\")) {\n                return (javax2.sip.address.URI) urlParser.sipURL(true);\n            } else if (scheme.equalsIgnoreCase(\"tel\")) {\n                return (javax2.sip.address.URI) urlParser.telURL(true);\n            }\n        } catch (ParseException ex) {\n            throw new ParseException(ex.getMessage(), 0);\n        }\n        return new gov2.nist.javax2.sip.address.GenericURI(uri);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/AddressImpl.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.address;\n\nimport gov2.nist.core.*;\n\nimport javax2.sip.address.*;\n\n/*\n * BUG Fix from Antonis Kadris.\n */\n/**\n * Address structure. Imbeds a URI and adds a display name.\n *\n * @author M. Ranganathan <br/>\n *\n *\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:21 $\n *\n */\npublic final class AddressImpl extends NetObject implements javax2.sip.address.Address {\n\n\tprivate static final long serialVersionUID = 429592779568617259L;\n\n\t/**\n\t * Constant field.\n\t */\n\tpublic static final int NAME_ADDR = 1;\n\n\t/**\n\t * constant field.\n\t */\n\tpublic static final int ADDRESS_SPEC = 2;\n\n\t/**\n\t * Constant field.\n\t */\n\tpublic static final int WILD_CARD = 3;\n\n\tprotected int addressType;\n\n\t/**\n\t * displayName field\n\t */\n\tprotected String displayName;\n\n\t/**\n\t * address field\n\t */\n\tprotected GenericURI address;\n\n\t/**\n\t * Match on the address only. Dont care about the display name.\n\t */\n\n\tpublic boolean match(Object other) {\n\t\t// TODO -- add the matcher;\n\t\tif (other == null)\n\t\t\treturn true;\n\t\tif (!(other instanceof Address))\n\t\t\treturn false;\n\t\telse {\n\t\t\tAddressImpl that = (AddressImpl) other;\n\t\t\tif (that.getMatcher() != null)\n\t\t\t\treturn that.getMatcher().match(this.encode());\n\t\t\telse if (that.displayName != null && this.displayName == null)\n\t\t\t\treturn false;\n\t\t\telse if (that.displayName == null)\n\t\t\t\treturn address.match(that.address);\n\t\t\telse\n\t\t\t\treturn displayName.equalsIgnoreCase(that.displayName) && address.match(that.address);\n\t\t}\n\n\t}\n\n\t/**\n\t * Get the host port portion of the address spec.\n\t *\n\t * @return host:port in a HostPort structure.\n\t */\n\tpublic HostPort getHostPort() {\n\t\tif (!(address instanceof SipUri))\n\t\t\tthrow new RuntimeException(\"address is not a SipUri\");\n\t\tSipUri uri = (SipUri) address;\n\t\treturn uri.getHostPort();\n\t}\n\n\t/**\n\t * Get the port from the imbedded URI. This assumes that a SIP URL is encapsulated in this address object.\n\t *\n\t * @return the port from the address.\n\t *\n\t */\n\tpublic int getPort() {\n\t\tif (!(address instanceof SipUri))\n\t\t\tthrow new RuntimeException(\"address is not a SipUri\");\n\t\tSipUri uri = (SipUri) address;\n\t\treturn uri.getHostPort().getPort();\n\t}\n\t\n\t/**\n\t * Set the port part of ContactHeader to the newly supplied <code>port</code> parameter.\n\t *\n\t * @param port\n\t *            - the Integer.valueOf value of the port of this ContactHeader\n\t */\n\tpublic void setPort(int port) {\n\t\tif (!(address instanceof SipUri))\n\t\t\tthrow new RuntimeException(\"address is not a SipUri\");\n\t\tSipUri uri = (SipUri) address;\n\t\turi.setPort(port);\n\t}\n\n\t/**\n\t * Get the user@host:port for the address field. This assumes that the encapsulated object is a SipUri.\n\t *\n\t *\n\t * @return string containing user@host:port.\n\t */\n\tpublic String getUserAtHostPort() {\n\t\tif (address instanceof SipUri) {\n\t\t\tSipUri uri = (SipUri) address;\n\t\t\treturn uri.getUserAtHostPort();\n\t\t} else\n\t\t\treturn address.toString();\n\t}\n\n\t/**\n\t * Get the host name from the address.\n\t *\n\t * @return the host name.\n\t */\n\tpublic String getHost() {\n\t\tif (!(address instanceof SipUri))\n\t\t\tthrow new RuntimeException(\"address is not a SipUri\");\n\t\tSipUri uri = (SipUri) address;\n\t\treturn uri.getHostPort().getHost().getHostname();\n\t}\n\n\t/**\n\t * Remove a parameter from the address.\n\t *\n\t * @param parameterName\n\t *            is the name of the parameter to remove.\n\t */\n\tpublic void removeParameter(String parameterName) {\n\t\tif (!(address instanceof SipUri))\n\t\t\tthrow new RuntimeException(\"address is not a SipUri\");\n\t\tSipUri uri = (SipUri) address;\n\t\turi.removeParameter(parameterName);\n\t}\n\n\t/**\n\t * Encode the address as a string and return it.\n\t * \n\t * @return String canonical encoded version of this address.\n\t */\n\tpublic String encode() {\n\t\treturn encode(new StringBuffer()).toString();\n\t}\n\n\tpublic StringBuffer encode(StringBuffer buffer) {\n\t\tif (this.addressType == WILD_CARD) {\n\t\t\tbuffer.append('*');\n\t\t} else {\n\t\t\tif (displayName != null) {\n\t\t\t\tbuffer.append(DOUBLE_QUOTE).append(displayName).append(DOUBLE_QUOTE).append(SP);\n\t\t\t}\n\t\t\tif (address != null) {\n\t\t\t\tif (addressType == NAME_ADDR || displayName != null)\n\t\t\t\t\tbuffer.append(LESS_THAN);\n\t\t\t\taddress.encode(buffer);\n\t\t\t\tif (addressType == NAME_ADDR || displayName != null)\n\t\t\t\t\tbuffer.append(GREATER_THAN);\n\t\t\t}\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tpublic AddressImpl() {\n\t\tthis.addressType = NAME_ADDR;\n\t}\n\n\t/**\n\t * Get the address type;\n\t * \n\t * @return int\n\t */\n\tpublic int getAddressType() {\n\t\treturn addressType;\n\t}\n\n\t/**\n\t * Set the address type. The address can be NAME_ADDR, ADDR_SPEC or WILD_CARD\n\t *\n\t * @param atype\n\t *            int to set\n\t *\n\t */\n\tpublic void setAddressType(int atype) {\n\t\taddressType = atype;\n\t}\n\n\t/**\n\t * get the display name\n\t *\n\t * @return String\n\t *\n\t */\n\tpublic String getDisplayName() {\n\t\treturn displayName;\n\t}\n\n\t/**\n\t * Set the displayName member\n\t *\n\t * @param displayName\n\t *            String to set\n\t *\n\t */\n\tpublic void setDisplayName(String displayName) {\n\t\tthis.displayName = displayName;\n\t\tthis.addressType = NAME_ADDR;\n\t}\n\n\t/**\n\t * Set the address field\n\t *\n\t * @param address\n\t *            SipUri to set\n\t *\n\t */\n\tpublic void setAddess(javax2.sip.address.URI address) {\n\t\tthis.address = (GenericURI) address;\n\t}\n\n\t/**\n\t * hashCode impelmentation\n\t *\n\t */\n\tpublic int hashCode() {\n\t\treturn this.address.hashCode();\n\t}\n\n\t/**\n\t * Compare two address specs for equality.\n\t *\n\t * @param other\n\t *            Object to compare this this address\n\t *\n\t * @return boolean\n\t *\n\t */\n\tpublic boolean equals(Object other) {\n\n\t\tif (this == other)\n\t\t\treturn true;\n\n\t\tif (other instanceof Address) {\n\t\t\tfinal Address o = (Address) other;\n\n\t\t\t// Don't compare display name (?)\n\t\t\treturn this.getURI().equals(o.getURI());\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * return true if DisplayName exist.\n\t *\n\t * @return boolean\n\t */\n\tpublic boolean hasDisplayName() {\n\t\treturn (displayName != null);\n\t}\n\n\t/**\n\t * remove the displayName field\n\t */\n\tpublic void removeDisplayName() {\n\t\tdisplayName = null;\n\t}\n\n\t/**\n\t * Return true if the imbedded URI is a sip URI.\n\t *\n\t * @return true if the imbedded URI is a SIP URI.\n\t *\n\t */\n\tpublic boolean isSIPAddress() {\n\t\treturn address instanceof SipUri;\n\t}\n\n\t/**\n\t * Returns the URI address of this Address. The type of URI can be determined by the scheme.\n\t *\n\t * @return address parmater of the Address object\n\t */\n\tpublic URI getURI() {\n\t\treturn this.address;\n\t}\n\n\t/**\n\t * This determines if this address is a wildcard address. That is <code>Address.getAddress.getUserInfo() == *;</code>\n\t *\n\t * @return true if this name address is a wildcard, false otherwise.\n\t */\n\tpublic boolean isWildcard() {\n\t\treturn this.addressType == WILD_CARD;\n\t}\n\n\t/**\n\t * Sets the URI address of this Address. The URI can be either a TelURL or a SipURI.\n\t *\n\t * @param address\n\t *            - the new URI address value of this NameAddress.\n\t */\n\tpublic void setURI(URI address) {\n\t\tthis.address = (GenericURI) address;\n\t}\n\n\t/**\n\t * Set the user name for the imbedded URI.\n\t *\n\t * @param user\n\t *            -- user name to set for the imbedded URI.\n\t */\n\tpublic void setUser(String user) {\n\t\t((SipUri) this.address).setUser(user);\n\t}\n\n\t/**\n\t * Mark this a wild card address type. Also set the SIP URI to a special wild card address.\n\t */\n\tpublic void setWildCardFlag() {\n\t\tthis.addressType = WILD_CARD;\n\t\tthis.address = new SipUri();\n\t\t((SipUri) this.address).setUser(\"*\");\n\t}\n\n\tpublic Object clone() {\n\t\tAddressImpl retval = (AddressImpl) super.clone();\n\t\tif (this.address != null)\n\t\t\tretval.address = (GenericURI) this.address.clone();\n\t\treturn retval;\n\t}\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/Authority.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.address;\nimport gov2.nist.core.*;\n\n/**\n * Authority part of a URI structure. Section 3.2.2 RFC2396\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/12/16 14:48:33 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class Authority extends NetObject {\n\n    private static final long serialVersionUID = -3570349777347017894L;\n\n    /** hostport field\n     */\n    protected HostPort hostPort;\n\n    /** userInfo field\n     */\n    protected UserInfo userInfo;\n\n    /**\n     * Return the host name in encoded form.\n     * @return encoded string (does the same thing as toString)\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (userInfo != null) {\n            userInfo.encode(buffer);\n            buffer.append(AT);\n            hostPort.encode(buffer);\n        } else {\n            hostPort.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /** retruns true if the two Objects are equals , false otherwise.\n     * @param other Object to test.\n     * @return boolean\n     */\n    @Override\n    public boolean equals(Object other) {\n        if (other == null) return false;\n        if (other.getClass() != getClass()) {\n            return false;\n        }\n        Authority otherAuth = (Authority) other;\n        if (!this.hostPort.equals(otherAuth.hostPort)) {\n            return false;\n        }\n        if (this.userInfo != null && otherAuth.userInfo != null) {\n            if (!this.userInfo.equals(otherAuth.userInfo)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * get the hostPort member.\n     * @return HostPort\n     */\n    public HostPort getHostPort() {\n        return hostPort;\n    }\n\n    /**\n     * get the userInfo memnber.\n     * @return UserInfo\n     */\n    public UserInfo getUserInfo() {\n        return userInfo;\n    }\n\n    /**\n         * Get password from the user info.\n         * @return String\n         */\n    public String getPassword() {\n        if (userInfo == null)\n            return null;\n        else\n            return userInfo.password;\n    }\n\n    /**\n     * Get the user name if it exists.\n     * @return String user or null if not set.\n     */\n    public String getUser() {\n        return userInfo != null ? userInfo.user : null;\n    }\n\n    /**\n     * Get the host name.\n     * @return Host (null if not set)\n     */\n    public Host getHost() {\n        if (hostPort == null)\n            return null;\n        else\n            return hostPort.getHost();\n    }\n\n    /**\n     * Get the port.\n     * @return int port (-1) if port is not set.\n     */\n    public int getPort() {\n        if (hostPort == null)\n            return -1;\n        else\n            return hostPort.getPort();\n    }\n\n    /** remove the port.\n     */\n    public void removePort() {\n        if (hostPort != null)\n            hostPort.removePort();\n    }\n\n    /**\n     * set the password.\n     * @param passwd String to set\n     */\n    public void setPassword(String passwd) {\n        if (userInfo == null)\n            userInfo = new UserInfo();\n        userInfo.setPassword(passwd);\n    }\n\n    /**\n     * Set the user name of the userInfo member.\n     * @param user String to set\n     */\n    public void setUser(String user) {\n        if (userInfo == null)\n            userInfo = new UserInfo();\n        this.userInfo.setUser(user);\n    }\n\n    /**\n     * set the host.\n     * @param host Host to set\n     */\n    public void setHost(Host host) {\n        if (hostPort == null)\n            hostPort = new HostPort();\n        hostPort.setHost(host);\n    }\n\n    /**\n     * Set the port.\n     * @param port int to set\n     */\n    public void setPort(int port) {\n        if (hostPort == null)\n            hostPort = new HostPort();\n        hostPort.setPort(port);\n    }\n\n    /**\n         * Set the hostPort member\n         * @param h HostPort to set\n         */\n    public void setHostPort(HostPort h) {\n        hostPort = h;\n    }\n\n    /**\n         * Set the userInfo member\n         * @param u UserInfo to set\n         */\n    public void setUserInfo(UserInfo u) {\n        userInfo = u;\n    }\n\n    /** Remove the user Infor.\n    *\n    */\n    public void removeUserInfo() {\n        this.userInfo = null;\n    }\n\n    public Object clone() {\n        Authority retval = (Authority) super.clone();\n        if (this.hostPort != null)\n            retval.hostPort = (HostPort) this.hostPort.clone();\n        if (this.userInfo != null)\n            retval.userInfo = (UserInfo) this.userInfo.clone();\n        return retval;\n    }\n    \n    @Override\n    public int hashCode() {\n        if ( this.hostPort == null ) throw new UnsupportedOperationException(\"Null hostPort cannot compute hashcode\");\n        return this.hostPort.encode().hashCode();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/GenericURI.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.address;\nimport java.text.ParseException;\n\nimport javax2.sip.address.URI;\n\n/**\n * Implementation of the URI class. This relies on the 1.4 URI class.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/15 19:50:45 $\n *\n *\n */\npublic class GenericURI extends NetObject implements javax2.sip.address.URI {\n    /**\n     *\n     */\n    private static final long serialVersionUID = 3237685256878068790L;\n    public static final String SIP = ParameterNames.SIP_URI_SCHEME;\n    public static final String SIPS = ParameterNames.SIPS_URI_SCHEME;\n    public static final String TEL = ParameterNames.TEL_URI_SCHEME;\n    public static final String POSTDIAL = ParameterNames.POSTDIAL;\n    public static final String PHONE_CONTEXT_TAG =\n        ParameterNames.PHONE_CONTEXT_TAG;\n    public static final String ISUB = ParameterNames.ISUB;\n    public static final String PROVIDER_TAG = ParameterNames.PROVIDER_TAG;\n\n    /** Imbedded URI\n     */\n    protected String uriString;\n\n    /**\n     * The URI Scheme.\n     */\n    protected String scheme;\n\n    /** Consturctor\n     */\n    protected GenericURI() {\n    }\n\n    /** Constructor given the URI string\n     * @param uriString The imbedded URI string.\n     * @throws java.net.URISyntaxException When there is a syntaz error in the imbedded URI.\n     */\n    public GenericURI(String uriString) throws ParseException {\n        try {\n            this.uriString = uriString;\n            int i = uriString.indexOf(\":\");\n            scheme = uriString.substring(0, i);\n        } catch (Exception e) {\n            throw new ParseException(\"GenericURI, Bad URI format\", 0);\n        }\n    }\n\n    /** Encode the URI.\n     * @return The encoded URI\n     */\n    public String encode() {\n        return uriString;\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        return buffer.append(uriString);\n    }\n\n    /** Encode this URI.\n     * @return The encoded URI\n     */\n    public String toString() {\n        return this.encode();\n\n    }\n\n    /** Returns the value of the \"scheme\" of\n     * this URI, for example \"sip\", \"sips\" or \"tel\".\n     *\n     * @return the scheme paramter of the URI\n     */\n    public String getScheme() {\n        return scheme;\n    }\n\n    /** This method determines if this is a URI with a scheme of\n     * \"sip\" or \"sips\".\n     *\n     * @return true if the scheme is \"sip\" or \"sips\", false otherwise.\n     */\n    public boolean isSipURI() {\n        return this instanceof SipUri;\n    }\n\n    // @Override\n    public boolean equals(Object that) {\n        if (this==that) return true;\n        else if (that instanceof URI) {\n            final URI o = (URI) that;\n\n            // This is not sufficient for equality; revert to String equality...\n            // return this.getScheme().equalsIgnoreCase( o.getScheme() )\n            return this.toString().equalsIgnoreCase( o.toString() );\n        }\n        return false;\n    }\n\n    public int hashCode() {\n        return this.toString().hashCode();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/NetObject.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.address;\n\nimport gov2.nist.core.*;\n\nimport java.lang.reflect.*;\n\n/**\n * Root object for all objects in this package.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:22 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic abstract class NetObject extends GenericObject {\n\n    protected static final String CORE_PACKAGE = PackageNames.CORE_PACKAGE;\n    protected static final String NET_PACKAGE = PackageNames.NET_PACKAGE;\n    protected static final String PARSER_PACKAGE = PackageNames.PARSER_PACKAGE;\n    protected static final String UDP = \"udp\";\n    protected static final String TCP = \"tcp\";\n    protected static final String TRANSPORT = \"transport\";\n    protected static final String METHOD = \"method\";\n    protected static final String USER = \"user\";\n    protected static final String PHONE = \"phone\";\n    protected static final String MADDR = \"maddr\";\n    protected static final String TTL = \"ttl\";\n    protected static final String LR = \"lr\";\n    protected static final String SIP = \"sip\";\n    protected static final String SIPS = \"sips\";\n\n    // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n    protected static final String TLS = \"tls\";\n\n    // Added by Peter Musgrave <pmusgrave@newheights.com>\n    // params for outbound and gruu drafts\n    protected static final String GRUU = \"gr\";\n\n\n    /** Default constructor\n     */\n    public NetObject() {\n        super();\n    }\n\n    /**\n     * An introspection based equality predicate for SIPObjects.\n     *@param that is the other object to test against.\n     */\n    public boolean equals(Object that) {\n        if (!this.getClass().equals(that.getClass()))\n            return false;\n        Class<?> myclass = this.getClass();\n        Class<?> hisclass = that.getClass();\n        while (true) {\n            Field[] fields = myclass.getDeclaredFields();\n            Field[] hisfields = hisclass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                Field g = hisfields[i];\n                // Only print protected and public members.\n                int modifier = f.getModifiers();\n                if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                    continue;\n                Class<?> fieldType = f.getType();\n                String fieldName = f.getName();\n                if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                    continue;\n                }\n                if (fieldName.compareTo(\"indentation\") == 0) {\n                    continue;\n                }\n                try {\n                    // Primitive fields are printed with type: value\n                    if (fieldType.isPrimitive()) {\n                        String fname = fieldType.toString();\n                        if (fname.compareTo(\"int\") == 0) {\n                            if (f.getInt(this) != g.getInt(that))\n                                return false;\n                        } else if (fname.compareTo(\"short\") == 0) {\n                            if (f.getShort(this) != g.getShort(that))\n                                return false;\n                        } else if (fname.compareTo(\"char\") == 0) {\n                            if (f.getChar(this) != g.getChar(that))\n                                return false;\n                        } else if (fname.compareTo(\"long\") == 0) {\n                            if (f.getLong(this) != g.getLong(that))\n                                return false;\n                        } else if (fname.compareTo(\"boolean\") == 0) {\n                            if (f.getBoolean(this) != g.getBoolean(that))\n                                return false;\n                        } else if (fname.compareTo(\"double\") == 0) {\n                            if (f.getDouble(this) != g.getDouble(that))\n                                return false;\n                        } else if (fname.compareTo(\"float\") == 0) {\n                            if (f.getFloat(this) != g.getFloat(that))\n                                return false;\n                        }\n                    } else if (g.get(that) == f.get(this))\n                        continue;\n                    else if (f.get(this) == null && g.get(that) != null)\n                        return false;\n                    else if (g.get(that) == null && f.get(that) != null)\n                        return false;\n                    else if (!f.get(this).equals(g.get(that)))\n                        return false;\n                } catch (IllegalAccessException ex1) {\n                    InternalErrorHandler.handleException(ex1);\n                }\n            }\n            if (myclass.equals(NetObject.class))\n                break;\n            else {\n                myclass = myclass.getSuperclass();\n                hisclass = hisclass.getSuperclass();\n            }\n        }\n        return true;\n    }\n\n\n\n\n    /** An introspection based predicate matching using a template\n     * object. Allows for partial match of two protocl Objects.\n     *@param other the match pattern to test against. The match object\n     * has to be of the same type (class). Primitive types\n     * and non-sip fields that are non null are matched for equality.\n     * Null in any field  matches anything. Some book-keeping fields\n     * are ignored when making the comparison.\n     *@return true if match succeeds false otherwise.\n     */\n\n    public boolean match(Object other) {\n        if (other == null)\n            return true;\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        GenericObject that = (GenericObject) other;\n        // System.out.println(\"Comparing \" + that.encode());\n        // System.out.println(\"this = \" + this.encode());\n\n        Class<?> hisclass = other.getClass();\n        Class<?> myclass = this.getClass();\n        while (true) {\n            Field[] fields = myclass.getDeclaredFields();\n            Field[] hisfields = hisclass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                Field g = hisfields[i];\n                // Only print protected and public members.\n                int modifier = f.getModifiers();\n                if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                    continue;\n                Class<?> fieldType = f.getType();\n                String fieldName = f.getName();\n                if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                    continue;\n                }\n                if (fieldName.compareTo(\"indentation\") == 0) {\n                    continue;\n                }\n                try {\n                    // Primitive fields are printed with type: value\n                    if (fieldType.isPrimitive()) {\n                        String fname = fieldType.toString();\n                        if (fname.compareTo(\"int\") == 0) {\n                            if (f.getInt(this) != g.getInt(that))\n                                return false;\n                        } else if (fname.compareTo(\"short\") == 0) {\n                            if (f.getShort(this) != g.getShort(that))\n                                return false;\n                        } else if (fname.compareTo(\"char\") == 0) {\n                            if (f.getChar(this) != g.getChar(that))\n                                return false;\n                        } else if (fname.compareTo(\"long\") == 0) {\n                            if (f.getLong(this) != g.getLong(that))\n                                return false;\n                        } else if (fname.compareTo(\"boolean\") == 0) {\n                            if (f.getBoolean(this) != g.getBoolean(that))\n                                return false;\n                        } else if (fname.compareTo(\"double\") == 0) {\n                            if (f.getDouble(this) != g.getDouble(that))\n                                return false;\n                        } else if (fname.compareTo(\"float\") == 0) {\n                            if (f.getFloat(this) != g.getFloat(that))\n                                return false;\n                        }\n                    } else {\n                        Object myObj = f.get(this);\n                        Object hisObj = g.get(that);\n                        if (hisObj != null && myObj == null)\n                            return false;\n                        else if (hisObj == null && myObj != null)\n                            continue;\n                        else if (hisObj == null && myObj == null)\n                            continue;\n                        else if (\n                            hisObj instanceof java.lang.String\n                                && myObj instanceof java.lang.String) {\n                            if (((String) hisObj).equals(\"\"))\n                                continue;\n                            if (((String) myObj)\n                                .compareToIgnoreCase((String) hisObj)\n                                != 0)\n                                return false;\n                        } else if (\n                            GenericObject.isMySubclass(myObj.getClass())\n                                && GenericObject.isMySubclass(hisObj.getClass())\n                                && myObj.getClass().equals(hisObj.getClass())\n                                && ((GenericObject) hisObj).getMatcher()\n                                    != null) {\n                            String myObjEncoded =\n                                ((GenericObject) myObj).encode();\n                            boolean retval =\n                                ((GenericObject) hisObj).getMatcher().match(\n                                    myObjEncoded);\n                            if (!retval)\n                                return false;\n                        } else if (\n                            GenericObject.isMySubclass(myObj.getClass())\n                                && !((GenericObject) myObj).match(hisObj))\n                            return false;\n                        else if (\n                            GenericObjectList.isMySubclass(myObj.getClass())\n                                && !((GenericObjectList) myObj).match(hisObj))\n                            return false;\n                    }\n                } catch (IllegalAccessException ex1) {\n                    InternalErrorHandler.handleException(ex1);\n                }\n            }\n            if (myclass.equals(NetObject.class))\n                break;\n            else {\n                myclass = myclass.getSuperclass();\n                hisclass = hisclass.getSuperclass();\n            }\n        }\n        return true;\n    }\n\n    /**\n     * An introspection based string formatting method. We need this because\n     * in this package (although it is an exact duplicate of the one in\n     * the superclass) because it needs to access the protected members\n     * of the other objects in this class.\n     * @return String\n     */\n    public String debugDump() {\n        stringRepresentation = \"\";\n        Class<?> myclass = getClass();\n        sprint(myclass.getName());\n        sprint(\"{\");\n        Field[] fields = myclass.getDeclaredFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field f = fields[i];\n            // Only print protected and public members.\n            int modifier = f.getModifiers();\n            if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                continue;\n            Class<?> fieldType = f.getType();\n            String fieldName = f.getName();\n            if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                // avoid nasty recursions...\n                continue;\n            }\n            if (fieldName.compareTo(\"indentation\") == 0) {\n                // formatting stuff - not relevant here.\n                continue;\n            }\n            sprint(fieldName + \":\");\n            try {\n                // Primitive fields are printed with type: value\n                if (fieldType.isPrimitive()) {\n                    String fname = fieldType.toString();\n                    sprint(fname + \":\");\n                    if (fname.compareTo(\"int\") == 0) {\n                        int intfield = f.getInt(this);\n                        sprint(intfield);\n                    } else if (fname.compareTo(\"short\") == 0) {\n                        short shortField = f.getShort(this);\n                        sprint(shortField);\n                    } else if (fname.compareTo(\"char\") == 0) {\n                        char charField = f.getChar(this);\n                        sprint(charField);\n                    } else if (fname.compareTo(\"long\") == 0) {\n                        long longField = f.getLong(this);\n                        sprint(longField);\n                    } else if (fname.compareTo(\"boolean\") == 0) {\n                        boolean booleanField = f.getBoolean(this);\n                        sprint(booleanField);\n                    } else if (fname.compareTo(\"double\") == 0) {\n                        double doubleField = f.getDouble(this);\n                        sprint(doubleField);\n                    } else if (fname.compareTo(\"float\") == 0) {\n                        float floatField = f.getFloat(this);\n                        sprint(floatField);\n                    }\n                } else if (GenericObject.class.isAssignableFrom(fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObject) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else if (\n                    GenericObjectList.class.isAssignableFrom(fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObjectList) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else {\n                    // Dont do recursion on things that are not\n                    // of our header type...\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).getClass().getName() + \":\");\n                    } else {\n                        sprint(fieldType.getName() + \":\");\n                    }\n\n                    sprint(\"{\");\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).toString());\n                    } else {\n                        sprint(\"<null>\");\n                    }\n                    sprint(\"}\");\n                }\n            } catch (IllegalAccessException ex1) {\n                continue; // we are accessing a private field...\n            }\n        }\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n\n\n\n    /**\n     * Formatter with a given starting indentation (for nested structs).\n     * @param indent int to set\n     * @return String\n     */\n    public String debugDump(int indent) {\n        int save = indentation;\n        indentation = indent;\n        String retval = this.debugDump();\n        indentation = save;\n        return retval;\n    }\n\n    /** Encode this to a string.\n     *\n     *@return string representation for this object.\n     */\n    public String toString() {\n        return this.encode();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/NetObjectList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.address;\nimport gov2.nist.core.*;\n\nimport java.util.ListIterator;\nimport java.util.LinkedList;\nimport java.util.Iterator;\nimport java.lang.reflect.*;\n\n/**\n* Root class for all the collection objects in this list:\n* a wrapper class on the GenericObjectList class for lists of objects\n* that can appear in NetObjects.\n* IMPORTANT NOTE: NetObjectList cannot derive from NetObject as this\n* will screw up the way in which we attach objects to headers.\n*\n*@version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:22 $\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\npublic class NetObjectList extends GenericObjectList {\n\n\n    /**\n     *\n     */\n    private static final long serialVersionUID = -1551780600806959023L;\n\n    /**\n     * Construct a NetObject List given a list name.\n     * @param lname String to set\n     */\n    public NetObjectList(String lname) {\n        super(lname);\n    }\n\n    /**\n     * Construct a NetObject List given a list name and a class for\n     * the objects that go into the list.\n     * @param lname String to set\n     * @param cname Class to set\n     */\n    public NetObjectList(String lname, Class<?> cname) {\n        super(lname, cname);\n    }\n\n\n\n    /**\n     * Construct an empty NetObjectList.\n     */\n    public NetObjectList() {\n        super();\n    }\n\n    /**\n     * Add a new object to the list.\n     * @param obj NetObject to set\n     */\n    public void add(NetObject obj) {\n        super.add(obj);\n    }\n\n    /** concatenate the two Lists\n     * @param net_obj_list NetObjectList to set\n     */\n    public void concatenate(NetObjectList net_obj_list) {\n        super.concatenate(net_obj_list);\n    }\n\n\n\n    /** returns the first element\n     * @return GenericObject\n     */\n    public GenericObject first() {\n        return (NetObject) super.first();\n    }\n\n\n\n    /** returns the next element\n     * @return GenericObject\n     */\n    public GenericObject next() {\n        return (NetObject) super.next();\n    }\n\n    /** returns the next element\n     * @param li ListIterator to set\n     * @return GenericObject\n     */\n    public GenericObject next(ListIterator li) {\n        return (NetObject) super.next(li);\n    }\n\n\n\n    /** set the class\n     * @param cl Class to set\n     */\n    public void setMyClass(Class cl) {\n        super.setMyClass(cl);\n    }\n\n    /**\n     * Convert to a string given an indentation(for pretty printing).\n     * @param indent int to set\n     * @return String\n     */\n    public String debugDump(int indent) {\n        return super.debugDump(indent);\n    }\n\n    /**\n    * Encode this to a string.\n    *\n    *@return a string representation for this object.\n    */\n    public String toString() {\n        return this.encode();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/ParameterNames.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.address;\n\n/**\n * Common parameter names.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:22 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic interface ParameterNames {\n    public static final String SIP_URI_SCHEME = \"sip\";\n    public static final String SIPS_URI_SCHEME = \"sips\";\n    public static final String TEL_URI_SCHEME = \"tel\";\n    public static final String POSTDIAL = \"postdial\";\n    public static final String PHONE_CONTEXT_TAG = \"context-tag\";\n    public static final String ISUB = \"isub\";\n    public static final String PROVIDER_TAG = \"provider-tag\";\n    public static final String UDP = GenericURI.UDP;\n    public static final String TCP = GenericURI.TCP;\n    public static final String TLS = GenericURI.TLS;\n}\n/*\n * $Log: ParameterNames.java,v $\n * Revision 1.6  2009/07/17 18:57:22  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.5  2006/07/13 09:02:30  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:29  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:34  mranga\n *\n * Import\n *\n *\n * Revision 1.3  2004/10/28 19:02:49  mranga\n * Submitted by:  Daniel Martinez\n * Reviewed by:   M. Ranganathan\n *\n * Added changes for TLS support contributed by Daniel Martinez\n *\n * Revision 1.2  2004/01/22 13:26:28  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/RFC2396UrlDecoder.java",
    "content": "/*\n* Conditions Of Use \n* \n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n* \n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n* \n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*  \n* .\n* \n*/\npackage gov2.nist.javax2.sip.address;\n\nimport java.io.UnsupportedEncodingException;\n\n/**\n * Copied from Apache Excalibur project.\n * Source code available at http://www.google.com/codesearch?hl=en&q=+excalibur+decodePath+show:sK_gDY0W5Rw:OTjCHAiSuF0:th3BdHtpX20&sa=N&cd=1&ct=rc&cs_p=http://apache.edgescape.com/excalibur/excalibur-sourceresolve/source/excalibur-sourceresolve-1.1-src.zip&cs_f=excalibur-sourceresolve-1.1/src/java/org/apache/excalibur/source/SourceUtil.java\n * @author <A HREF=\"mailto:jean.deruelle@gmail.com\">Jean Deruelle</A> \n *\n */\npublic class RFC2396UrlDecoder {\n\n    /**\n     * Decode a path.\n     *\n     * <p>Interprets %XX (where XX is hexadecimal number) as UTF-8 encoded bytes.\n     * <p>The validity of the input path is not checked (i.e. characters that\n     * were not encoded will not be reported as errors).\n     * <p>This method differs from URLDecoder.decode in that it always uses UTF-8\n     * (while URLDecoder uses the platform default encoding, often ISO-8859-1),\n     * and doesn't translate + characters to spaces.\n     *\n     * @param uri the path to decode\n     * @return the decoded path\n     */\n    public static String decode(String uri) {\n        StringBuffer translatedUri = new StringBuffer(uri.length());\n        byte[] encodedchars = new byte[uri.length() / 3];\n        int i = 0;\n        int length = uri.length();\n        int encodedcharsLength = 0;\n        while (i < length) {\n            if (uri.charAt(i) == '%') {\n                //we must process all consecutive %-encoded characters in one go, because they represent\n                //an UTF-8 encoded string, and in UTF-8 one character can be encoded as multiple bytes\n                while (i < length && uri.charAt(i) == '%') {\n                    if (i + 2 < length) {\n                        try {\n                            byte x = (byte)Integer.parseInt(uri.substring(i + 1, i + 3), 16);\n                            encodedchars[encodedcharsLength] = x;\n                        } catch (NumberFormatException e) {\n                            throw new IllegalArgumentException(\"Illegal hex characters in pattern %\" + uri.substring(i + 1, i + 3));\n                        }\n                        encodedcharsLength++;\n                        i += 3;\n                    } else {\n                        throw new IllegalArgumentException(\"% character should be followed by 2 hexadecimal characters.\");\n                    }\n                }\n                try {\n                    String translatedPart = new String(encodedchars, 0, encodedcharsLength, \"UTF-8\");\n                    translatedUri.append(translatedPart);\n                } catch (UnsupportedEncodingException e) {\n                    //the situation that UTF-8 is not supported is quite theoretical, so throw a runtime exception\n                    throw new RuntimeException(\"Problem in decodePath: UTF-8 encoding not supported.\");\n                }\n                encodedcharsLength = 0;\n            } else {\n                //a normal character\n                translatedUri.append(uri.charAt(i));\n                i++;\n            }\n        }\n        return translatedUri.toString();\n    }\n}"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/RouterExt.java",
    "content": "/*\n* Conditions Of Use \n* \n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n* \n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n* \n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*  \n*\n*/\n\npackage gov2.nist.javax2.sip.address;\n\nimport javax2.sip.address.Hop;\nimport javax2.sip.address.Router;\n\n/**\n * \n */\npublic interface RouterExt extends Router {\n    \n    /**\n     * Record that a transaction failure occured for the given hop.\n     * \n     */\n    public void transactionTimeout(Hop hop);\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/SipURIExt.java",
    "content": "package gov2.nist.javax2.sip.address;\n\nimport javax2.sip.address.SipURI;\n\n/**\n * URI Interface extensions that will be added to version 2.0 of the JSR 32 spec.\n *\n * @author mranga\n *\n * @since 2.0\n *\n */\npublic interface SipURIExt extends SipURI {\n\n    /**\n     * Strip the headers that are tacked to the URI.\n     *\n     * @since 2.0\n     */\n    public void removeHeaders();\n\n    /**\n     * Strip a specific header tacked to the URI.\n     *\n     * @param headerName -- the name of the header.\n     *\n     * @since 2.0\n     */\n    public void removeHeader(String headerName);\n\n    /**\n     * Returns whether the <code>gr</code> parameter is set.\n     *\n     * @since 2.0\n     */\n    public boolean hasGrParam();\n\n    /**\n     * Sets the <code>gr</code> parameter.\n     *\n     * @param value -- the GRUU param value.\n     *\n     * @since 2.0\n     */\n    public void setGrParam(String value);\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/SipUri.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.address;\n\n/*\n *Bug fix contributions\n *Daniel J. Martinez Manzano <dani@dif.um.es>\n *Stefan Marx.\n *pmusgrave@newheights.com (Additions for gruu and outbound drafts)\n *Jeroen van Bemmel ( additions for SCTP transport )\n */\nimport gov2.nist.core.*;\n\nimport java.util.*;\nimport java.text.ParseException;\n\nimport javax2.sip.PeerUnavailableException;\nimport javax2.sip.SipFactory;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderFactory;\n\n\n/**\n * Implementation of the SipURI interface.\n *\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.22 $ $Date: 2009/11/15 19:50:45 $\n *\n *\n *\n */\npublic class SipUri extends GenericURI implements javax2.sip.address.SipURI , SipURIExt{\n\n \n    private static final long serialVersionUID = 7749781076218987044L;\n\n    /** Authority for the uri.\n     */\n\n    protected Authority authority;\n\n    /** uriParms list\n     */\n    protected NameValueList uriParms;\n\n    /** qheaders list\n     */\n    protected NameValueList qheaders;\n\n    /** telephoneSubscriber field\n     */\n    protected TelephoneNumber telephoneSubscriber;\n\n    public SipUri() {\n        this.scheme = SIP;\n        this.uriParms = new NameValueList();\n        this.qheaders = new NameValueList();\n        this.qheaders.setSeparator(\"&\");\n    }\n\n    /** Constructor given the scheme.\n    * The scheme must be either Sip or Sips\n    */\n    public void setScheme(String scheme) {\n        if (scheme.compareToIgnoreCase(SIP) != 0\n            && scheme.compareToIgnoreCase(SIPS) != 0)\n            throw new IllegalArgumentException(\"bad scheme \" + scheme);\n        this.scheme = scheme.toLowerCase();\n    }\n\n    /** Get the scheme.\n     */\n    public String getScheme() {\n        return scheme;\n    }\n\n    /**\n     * clear all URI Parameters.\n     * @since v1.0\n     */\n    public void clearUriParms() {\n        uriParms = new NameValueList();\n    }\n    /**\n    *Clear the password from the user part if it exists.\n    */\n    public void clearPassword() {\n        if (this.authority != null) {\n            UserInfo userInfo = authority.getUserInfo();\n            if (userInfo != null)\n                userInfo.clearPassword();\n        }\n    }\n\n    /** Get the authority.\n    */\n    public Authority getAuthority() {\n        return this.authority;\n    }\n\n    /**\n     * Clear all Qheaders.\n     */\n    public void clearQheaders() {\n        qheaders = new NameValueList();\n    }\n\n    /**\n     * Compare two URIs and return true if they are equal.\n     * @param that the object to compare to.\n     * @return true if the object is equal to this object.\n     *\n     * JvB: Updated to define equality in terms of API methods, according to the rules\n     * in RFC3261 section 19.1.4\n     *\n     * Jean Deruelle: Updated to define equality of API methods, according to the rules\n     * in RFC3261 section 19.1.4 convert potential ie :\n     *    %HEX HEX encoding parts of the URI before comparing them\n     *    transport param added in comparison\n     *    header equality enforced in comparison\n     *\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public boolean equals(Object that) {\n\n        // Shortcut for same object\n        if (that==this) return true;\n\n        if (that instanceof SipURI) {\n            final SipURI a = this;\n            final SipURI b = (SipURI) that;\n\n            // A SIP and SIPS URI are never equivalent\n            if ( a.isSecure() ^ b.isSecure() ) return false;\n\n            // For two URIs to be equal, the user, password, host, and port\n            // components must match; comparison of userinfo is case-sensitive\n            if (a.getUser()==null ^ b.getUser()==null) return false;\n            if (a.getUserPassword()==null ^ b.getUserPassword()==null) return false;\n\n            if (a.getUser()!=null && !RFC2396UrlDecoder.decode(a.getUser()).equals(RFC2396UrlDecoder.decode(b.getUser()))) return false;\n            if (a.getUserPassword()!=null && !RFC2396UrlDecoder.decode(a.getUserPassword()).equals(RFC2396UrlDecoder.decode(b.getUserPassword()))) return false;\n            if (a.getHost() == null ^ b.getHost() == null) return false;\n            if (a.getHost() != null && !a.getHost().equalsIgnoreCase(b.getHost())) return false;\n            if (a.getPort() != b.getPort()) return false;\n\n            // URI parameters\n            for (Iterator i = a.getParameterNames(); i.hasNext();) {\n                String pname = (String) i.next();\n\n                String p1 = a.getParameter(pname);\n                String p2 = b.getParameter(pname);\n\n                // those present in both must match (case-insensitive)\n                if (p1!=null && p2!=null && !RFC2396UrlDecoder.decode(p1).equalsIgnoreCase(RFC2396UrlDecoder.decode(p2))) return false;\n            }\n\n            // transport, user, ttl or method must match when present in either\n            if (a.getTransportParam()==null ^ b.getTransportParam()==null) return false;\n            if (a.getUserParam()==null ^ b.getUserParam()==null) return false;\n            if (a.getTTLParam()==-1 ^ b.getTTLParam()==-1) return false;\n            if (a.getMethodParam()==null ^ b.getMethodParam()==null) return false;\n            if (a.getMAddrParam()==null ^ b.getMAddrParam()==null) return false;\n\n            // Headers: must match according to their definition.\n            if(a.getHeaderNames().hasNext() && !b.getHeaderNames().hasNext()) return false;\n            if(!a.getHeaderNames().hasNext() && b.getHeaderNames().hasNext()) return false;\n\n            if(a.getHeaderNames().hasNext() && b.getHeaderNames().hasNext()) {\n                HeaderFactory headerFactory = null;\n                try {\n                    headerFactory = SipFactory.getInstance().createHeaderFactory();\n                } catch (PeerUnavailableException e) {\n                    Debug.logError(\"Cannot get the header factory to parse the header of the sip uris to compare\", e);\n                    return false;\n                }\n                for (Iterator i = a.getHeaderNames(); i.hasNext();) {\n                    String hname = (String) i.next();\n\n                    String h1 = a.getHeader(hname);\n                    String h2 = b.getHeader(hname);\n\n                    if(h1 == null && h2 != null) return false;\n                    if(h2 == null && h1 != null) return false;\n                    // The following check should not be needed but we add it for findbugs.\n                    if(h1 == null && h2 == null) continue; \n                    try {\n                        Header header1 = headerFactory.createHeader(hname, RFC2396UrlDecoder.decode(h1));\n                        Header header2 = headerFactory.createHeader(hname, RFC2396UrlDecoder.decode(h2));\n                        // those present in both must match according to the equals method of the corresponding header\n                        if (!header1.equals(header2)) return false;\n                    } catch (ParseException e) {\n                        Debug.logError(\"Cannot parse one of the header of the sip uris to compare \" + a + \" \" + b, e);\n                        return false;\n                    }\n                }\n            }\n\n            // Finally, we can conclude that they are indeed equal\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Construct a URL from the parsed structure.\n     * @return String\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        buffer.append(scheme).append(COLON);\n        if (authority != null)\n            authority.encode(buffer);\n        if (!uriParms.isEmpty()) {\n            buffer.append(SEMICOLON);\n            uriParms.encode(buffer);\n        }\n        if (!qheaders.isEmpty()) {\n            buffer.append(QUESTION);\n            qheaders.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /** Return a string representation.\n    *\n    *@return the String representation of this URI.\n    *\n    */\n    public String toString() {\n        return this.encode();\n    }\n\n    /**\n     * getUser@host\n     * @return user@host portion of the uri (null if none exists).\n     *\n     * Peter Musgrave - handle null user\n     */\n    public String getUserAtHost() {\n        String user = \"\";\n        if (authority.getUserInfo() != null)\n            user = authority.getUserInfo().getUser();\n\n        String host = authority.getHost().encode();\n        StringBuffer s = null;\n        if (user.equals(\"\")) {\n            s = new StringBuffer();\n        } else {\n            s = new StringBuffer(user).append(AT);\n        }\n        return s.append(host).toString();\n    }\n\n    /**\n     * getUser@host\n     * @return user@host portion of the uri (null if none exists).\n     */\n    public String getUserAtHostPort() {\n        String user = \"\";\n        if (authority.getUserInfo() != null)\n            user = authority.getUserInfo().getUser();\n\n        String host = authority.getHost().encode();\n        int port = authority.getPort();\n        // If port not set assign the default.\n        StringBuffer s = null;\n        if (user.equals(\"\")) {\n            s = new StringBuffer();\n        } else {\n            s = new StringBuffer(user).append(AT);\n        }\n        if (port != -1) {\n            return s.append(host).append(COLON).append(port).toString();\n        } else\n            return s.append(host).toString();\n\n    }\n\n    /**\n     * get the parameter (do a name lookup) and return null if none exists.\n     * @param parmname Name of the parameter to get.\n     * @return Parameter of the given name (null if none exists).\n     */\n    public Object getParm(String parmname) {\n        Object obj = uriParms.getValue(parmname);\n        return obj;\n    }\n\n    /**\n     * Get the method parameter.\n     * @return Method parameter.\n     */\n    public String getMethod() {\n        return (String) getParm(METHOD);\n    }\n\n    /**\n     * Accessor for URI parameters\n     * @return A name-value list containing the parameters.\n     */\n    public NameValueList getParameters() {\n        return uriParms;\n    }\n\n    /** Remove the URI parameters.\n    *\n    */\n    public void removeParameters() {\n        this.uriParms = new NameValueList();\n    }\n\n    /**\n     * Accessor forSIPObjects\n     * @return Get the query headers (that appear after the ? in\n     * the URL)\n     */\n    public NameValueList getQheaders() {\n        return qheaders;\n    }\n\n    /**\n     * Get the urse parameter.\n     * @return User parameter (user= phone or user=ip).\n     */\n    public String getUserType() {\n        return (String) uriParms.getValue(USER);\n    }\n\n    /**\n     * Get the password of the user.\n     * @return User password when it embedded as part of the uri\n     * ( a very bad idea).\n     */\n    public String getUserPassword() {\n        if (authority == null)\n            return null;\n        return authority.getPassword();\n    }\n\n    /** Set the user password.\n     *@param password - password to set.\n     */\n    public void setUserPassword(String password) {\n        if (this.authority == null)\n            this.authority = new Authority();\n        authority.setPassword(password);\n    }\n\n    /**\n     * Returns the stucture corresponding to the telephone number\n     * provided that the user is a telephone subscriber.\n     * @return TelephoneNumber part of the url (only makes sense\n     * when user = phone is specified)\n     */\n    public TelephoneNumber getTelephoneSubscriber() {\n        if (telephoneSubscriber == null) {\n\n            telephoneSubscriber = new TelephoneNumber();\n        }\n        return telephoneSubscriber;\n    }\n\n    /**\n     * Get the host and port of the server.\n     * @return get the host:port part of the url parsed into a\n     * structure.\n     */\n    public HostPort getHostPort() {\n\n        if (authority == null || authority.getHost() == null )\n            return null;\n        else {\n            return authority.getHostPort();\n        }\n    }\n\n    /** Get the port from the authority field.\n    *\n    *@return the port from the authority field.\n    */\n    public int getPort() {\n        HostPort hp = this.getHostPort();\n        if (hp == null)\n            return -1;\n        return hp.getPort();\n    }\n\n    /** Get the host protion of the URI.\n    * @return the host portion of the url.\n    */\n    public String getHost() {\n        if ( authority == null) return null;\n        else if (authority.getHost() == null ) return null;\n        else return authority.getHost().encode();\n    }\n\n    /**\n     * returns true if the user is a telephone subscriber.\n     *  If the host is an Internet telephony\n     * gateway, a telephone-subscriber field MAY be used instead\n     * of a user field. The telephone-subscriber field uses the\n     * notation of RFC 2806 [19]. Any characters of the un-escaped\n     * \"telephone-subscriber\" that are not either in the set\n     * \"unreserved\" or \"user-unreserved\" MUST be escaped. The set\n     * of characters not reserved in the RFC 2806 description of\n     * telephone-subscriber contains a number of characters in\n     * various syntax elements that need to be escaped when used\n     * in SIP URLs, for example quotation marks (%22), hash (%23),\n     * colon (%3a), at-sign (%40) and the \"unwise\" characters,\n     * i.e., punctuation of %5b and above.\n     *\n     * The telephone number is a special case of a user name and\n     * cannot be distinguished by a BNF. Thus, a URL parameter,\n     * user, is added to distinguish telephone numbers from user\n     * names.\n     *\n     * The user parameter value \"phone\" indicates that the user\n     * part contains a telephone number. Even without this\n     * parameter, recipients of SIP URLs MAY interpret the pre-@\n     * part as a telephone number if local restrictions on the\n     * @return true if the user is a telephone subscriber.\n     */\n    public boolean isUserTelephoneSubscriber() {\n        String usrtype = (String) uriParms.getValue(USER);\n        if (usrtype == null)\n            return false;\n        return usrtype.equalsIgnoreCase(PHONE);\n    }\n\n    /**\n     *remove the ttl value from the parameter list if it exists.\n     */\n    public void removeTTL() {\n        if (uriParms != null)\n            uriParms.delete(TTL);\n    }\n\n    /**\n     *Remove the maddr param if it exists.\n     */\n    public void removeMAddr() {\n        if (uriParms != null)\n            uriParms.delete(MADDR);\n    }\n\n    /**\n     *Delete the transport string.\n     */\n    public void removeTransport() {\n        if (uriParms != null)\n            uriParms.delete(TRANSPORT);\n    }\n\n    /** Remove a header given its name (provided it exists).\n     * @param name name of the header to remove.\n     */\n    public void removeHeader(String name) {\n        if (qheaders != null)\n            qheaders.delete(name);\n    }\n\n    /** Remove all headers.\n     */\n    public void removeHeaders() {\n        qheaders = new NameValueList();\n    }\n\n    /**\n     * Set the user type.\n     */\n    public void removeUserType() {\n        if (uriParms != null)\n            uriParms.delete(USER);\n    }\n\n    /**\n     *remove the port setting.\n     */\n    public void removePort() {\n        authority.removePort();\n    }\n\n    /**\n     * remove the Method.\n     */\n    public void removeMethod() {\n        if (uriParms != null)\n            uriParms.delete(METHOD);\n    }\n\n    /** Sets the user of SipURI. The identifier of a particular resource at\n     * the host being addressed. The user and the user password including the\n     * \"at\" sign make up the user-info.\n     *\n     * @param uname The new String value of the user.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the user value.\n     */\n    public void setUser(String uname) {\n        if (this.authority == null) {\n            this.authority = new Authority();\n        }\n\n        this.authority.setUser(uname);\n    }\n\n    /** Remove the user.\n     */\n    public void removeUser() {\n        this.authority.removeUserInfo();\n    }\n\n    /** Set the default parameters for this URI.\n     * Do nothing if the parameter is already set to some value.\n     * Otherwise set it to the given value.\n     * @param name Name of the parameter to set.\n     * @param value value of the parameter to set.\n     */\n    public void setDefaultParm(String name, Object value) {\n        if (uriParms.getValue(name) == null) {\n            NameValue nv = new NameValue(name, value);\n            uriParms.set(nv);\n        }\n    }\n\n    /** Set the authority member\n     * @param authority Authority to set.\n     */\n    public void setAuthority(Authority authority) {\n        this.authority = authority;\n    }\n\n    /** Set the host for this URI.\n     * @param h host to set.\n     */\n    public void setHost(Host h) {\n        if (this.authority == null)\n            this.authority = new Authority();\n        this.authority.setHost(h);\n    }\n\n    /** Set the uriParms member\n     * @param parms URI parameters to set.\n     */\n    public void setUriParms(NameValueList parms) {\n        uriParms = parms;\n    }\n\n    /**\n     * Set a given URI parameter. Note - parameter must be properly\n    *  encoded before the function is called.\n     * @param name Name of the parameter to set.\n     * @param value value of the parameter to set.\n     */\n    public void setUriParm(String name, Object value) {\n        NameValue nv = new NameValue(name, value);\n        uriParms.set(nv);\n    }\n\n    /** Set the qheaders member\n     * @param parms query headers to set.\n     */\n    public void setQheaders(NameValueList parms) {\n        qheaders = parms;\n    }\n\n    /**\n     * Set the MADDR parameter .\n     * @param mAddr Host Name to set\n     */\n    public void setMAddr(String mAddr) {\n        NameValue nameValue = uriParms.getNameValue(MADDR);\n        Host host = new Host();\n        host.setAddress(mAddr);\n        if (nameValue != null)\n            nameValue.setValueAsObject(host);\n        else {\n            nameValue = new NameValue(MADDR, host);\n            uriParms.set(nameValue);\n        }\n    }\n\n    /** Sets the value of the user parameter. The user URI parameter exists to\n     * distinguish telephone numbers from user names that happen to look like\n     * telephone numbers.  This is equivalent to setParameter(\"user\", user).\n     *\n     * @param usertype New value String value of the method parameter\n     */\n    public void setUserParam(String usertype) {\n        uriParms.set(USER, usertype);\n    }\n\n    /**\n     * Set the Method\n     * @param method method parameter\n     */\n    public void setMethod(String method) {\n        uriParms.set(METHOD, method);\n    }\n\n    /**\n    * Sets ISDN subaddress of SipURL\n    * @param isdnSubAddress ISDN subaddress\n    */\n    public void setIsdnSubAddress(String isdnSubAddress) {\n        if (telephoneSubscriber == null)\n            telephoneSubscriber = new TelephoneNumber();\n        telephoneSubscriber.setIsdnSubaddress(isdnSubAddress);\n    }\n\n    /**\n     * Set the telephone subscriber field.\n     * @param tel Telephone subscriber field to set.\n     */\n    public void setTelephoneSubscriber(TelephoneNumber tel) {\n        telephoneSubscriber = tel;\n    }\n\n    /** set the port to a given value.\n     * @param p Port to set.\n     */\n    public void setPort(int p) {\n        if (authority == null)\n            authority = new Authority();\n        authority.setPort(p);\n    }\n\n    /**\n     * Boolean to check if a parameter of a given name exists.\n     * @param name Name of the parameter to check on.\n     * @return a boolean indicating whether the parameter exists.\n     */\n    public boolean hasParameter(String name) {\n\n        return uriParms.getValue(name) != null;\n    }\n\n    /**\n     * Set the query header when provided as a name-value pair.\n     * @param nameValue qeuery header provided as a name,value pair.\n     */\n    public void setQHeader(NameValue nameValue) {\n        this.qheaders.set(nameValue);\n    }\n\n    /** Set the parameter as given.\n     *@param nameValue - parameter to set.\n     */\n    public void setUriParameter(NameValue nameValue) {\n        this.uriParms.set(nameValue);\n    }\n\n    /** Return true if the transport parameter is defined.\n     * @return true if transport appears as a parameter and false otherwise.\n     */\n    public boolean hasTransport() {\n        return hasParameter(TRANSPORT);\n    }\n\n    /**\n     * Remove a parameter given its name\n     * @param name -- name of the parameter to remove.\n     */\n    public void removeParameter(String name) {\n        uriParms.delete(name);\n    }\n\n    /** Set the hostPort field of the imbedded authority field.\n     *@param hostPort is the hostPort to set.\n     */\n    public void setHostPort(HostPort hostPort) {\n        if (this.authority == null) {\n            this.authority = new Authority();\n        }\n        authority.setHostPort(hostPort);\n    }\n\n    /** clone this.\n     */\n    public Object clone() {\n        SipUri retval = (SipUri) super.clone();\n        if (this.authority != null)\n            retval.authority = (Authority) this.authority.clone();\n        if (this.uriParms != null)\n            retval.uriParms = (NameValueList) this.uriParms.clone();\n        if (this.qheaders != null)\n            retval.qheaders = (NameValueList) this.qheaders.clone();\n        if (this.telephoneSubscriber != null)\n            retval.telephoneSubscriber = (TelephoneNumber) this.telephoneSubscriber.clone();\n        return retval;\n    }\n\n    /**\n     * Returns the value of the named header, or null if it is not set.\n     * SIP/SIPS URIs may specify headers. As an example, the URI\n     * sip:joe@jcp.org?priority=urgent has a header \"priority\" whose\n     * value is \"urgent\".\n     *\n     * @param name name of header to retrieve\n     * @return the value of specified header\n     */\n    public String getHeader(String name) {\n        return this.qheaders.getValue(name) != null\n            ? this.qheaders.getValue(name).toString()\n            : null;\n\n    }\n\n    /**\n     * Returns an Iterator over the names (Strings) of all headers present\n     * in this SipURI.\n     *\n     * @return an Iterator over all the header names\n     */\n    public Iterator<String> getHeaderNames() {\n        return this.qheaders.getNames();\n\n    }\n\n    /** Returns the value of the <code>lr</code> parameter, or null if this\n     * is not set. This is equivalent to getParameter(\"lr\").\n     *\n     * @return the value of the <code>lr</code> parameter\n     */\n    public String getLrParam() {\n        boolean haslr = this.hasParameter(LR);\n        return haslr ? \"true\" : null;\n    }\n\n    /** Returns the value of the <code>maddr</code> parameter, or null if this\n     * is not set. This is equivalent to getParameter(\"maddr\").\n     *\n     * @return the value of the <code>maddr</code> parameter\n     */\n    public String getMAddrParam() {\n        NameValue maddr = uriParms.getNameValue(MADDR);\n        if (maddr == null)\n            return null;\n        String host = (String) maddr.getValueAsObject();\n        return host;\n    }\n\n    /**\n     * Returns the value of the <code>method</code> parameter, or null if this\n     * is not set. This is equivalent to getParameter(\"method\").\n     *\n     * @return  the value of the <code>method</code> parameter\n     */\n    public String getMethodParam() {\n        return this.getParameter(METHOD);\n    }\n\n    /**\n     * Returns the value of the named parameter, or null if it is not set. A\n     * zero-length String indicates flag parameter.\n     *\n     * @param name name of parameter to retrieve\n     * @return the value of specified parameter\n     */\n    public String getParameter(String name) {\n        Object val = uriParms.getValue(name);\n        if (val == null)\n            return null;\n        if (val instanceof GenericObject)\n            return ((GenericObject) val).encode();\n        else\n            return val.toString();\n    }\n\n    /**\n     * Returns an Iterator over the names (Strings) of all parameters present\n     *\n     * in this ParametersHeader.\n     *\n     *\n     *\n     * @return an Iterator over all the parameter names\n     *\n     */\n    public Iterator<String> getParameterNames() {\n        return this.uriParms.getNames();\n    }\n\n    /** Returns the value of the \"ttl\" parameter, or -1 if this is not set.\n     * This method is equivalent to getParameter(\"ttl\").\n     *\n     * @return the value of the <code>ttl</code> parameter\n     */\n    public int getTTLParam() {\n        Integer ttl = (Integer) uriParms.getValue(\"ttl\");\n        if (ttl != null)\n            return ttl.intValue();\n        else\n            return -1;\n    }\n\n    /** Returns the value of the \"transport\" parameter, or null if this is not\n     * set. This is equivalent to getParameter(\"transport\").\n     *\n     * @return the transport paramter of the SipURI\n     */\n    public String getTransportParam() {\n        if (uriParms != null) {\n            return (String) uriParms.getValue(TRANSPORT);\n        } else\n            return null;\n    }\n\n    /** Returns the value of the <code>userParam</code>,\n     *or null if this is not set.\n     * <p>\n     * This is equivalent to getParameter(\"user\").\n     *\n     * @return the value of the <code>userParam</code> of the SipURI\n     */\n    public String getUser() {\n        return authority.getUser();\n    }\n\n    /** Returns true if this SipURI is secure i.e. if this SipURI represents a\n     * sips URI. A sip URI returns false.\n     *\n     * @return  <code>true</code> if this SipURI represents a sips URI, and\n     * <code>false</code> if it represents a sip URI.\n     */\n    public boolean isSecure() {\n        return this.getScheme().equalsIgnoreCase(SIPS);\n    }\n\n    /** This method determines if this is a URI with a scheme of \"sip\" or \"sips\".\n     *\n     * @return true if the scheme is \"sip\" or \"sips\", false otherwise.\n     */\n    public boolean isSipURI() {\n        return true;\n    }\n\n    /** Sets the value of the specified header fields to be included in a\n     * request constructed from the URI. If the header already had a value it\n     * will be overwritten.\n     *\n     * @param name - a String specifying the header name\n     * @param value - a String specifying the header value\n     */\n    public void setHeader(String name, String value) {\n        NameValue nv = new NameValue(name, value);\n        qheaders.set(nv);\n\n    }\n\n    /**\n     * Set the host portion of the SipURI\n     *\n     * @param host host to set.\n     */\n    public void setHost(String host) throws ParseException {\n        Host h = new Host(host);\n        this.setHost(h);\n    }\n\n    /** Sets the value of the <code>lr</code> parameter of this SipURI. The lr\n     * parameter, when present, indicates that the element responsible for\n     * this resource implements the routing mechanisms specified in RFC 3261.\n     * This parameter will be used in the URIs proxies place in the\n     * Record-Route header field values, and may appear in the URIs in a\n     * pre-existing route set.\n     */\n    public void setLrParam() {\n        this.uriParms.set(\"lr\",null);   // JvB: fixed to not add duplicates\n    }\n\n    /**\n     * Sets the value of the <code>maddr</code> parameter of this SipURI. The\n     * maddr parameter indicates the server address to be contacted for this\n     * user, overriding any address derived from the host field. This is\n     * equivalent to setParameter(\"maddr\", maddr).\n     *\n     * @param  maddr New value of the <code>maddr</code> parameter\n     */\n    public void setMAddrParam(String maddr) throws ParseException {\n        if (maddr == null)\n            throw new NullPointerException(\"bad maddr\");\n        setParameter(\"maddr\", maddr);\n    }\n\n    /** Sets the value of the <code>method</code> parameter. This specifies\n     * which SIP method to use in requests directed at this URI. This is\n     * equivalent to setParameter(\"method\", method).\n     *\n     * @param  method - new value String value of the method parameter\n     */\n    public void setMethodParam(String method) throws ParseException {\n        setParameter(\"method\", method);\n    }\n\n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten. A zero-length String indicates flag\n     *\n     * parameter.\n     *\n     *\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - a String specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    public void setParameter(String name, String value) throws ParseException {\n        if (name.equalsIgnoreCase(\"ttl\")) {\n            try {\n                Integer.parseInt(value);\n            } catch (NumberFormatException ex) {\n                throw new ParseException(\"bad parameter \" + value, 0);\n            }\n        }\n        uriParms.set(name,value);\n    }\n\n    /** Sets the scheme of this URI to sip or sips depending on whether the\n     * argument is true or false. The default value is false.\n     *\n     * @param secure - the boolean value indicating if the SipURI is secure.\n     */\n    public void setSecure(boolean secure) {\n        if (secure)\n            this.scheme = SIPS;\n        else\n            this.scheme = SIP;\n    }\n\n    /** Sets the value of the <code>ttl</code> parameter. The ttl parameter\n     * specifies the time-to-live value when packets are sent using UDP\n     * multicast. This is equivalent to setParameter(\"ttl\", ttl).\n     *\n     * @param ttl - new value of the <code>ttl</code> parameter\n     */\n    public void setTTLParam(int ttl) {\n        if (ttl <= 0)\n            throw new IllegalArgumentException(\"Bad ttl value\");\n        if (uriParms != null) {\n            NameValue nv = new NameValue(\"ttl\", Integer.valueOf(ttl));\n            uriParms.set(nv);\n        }\n    }\n\n    /** Sets the value of the \"transport\" parameter. This parameter specifies\n     * which transport protocol to use for sending requests and responses to\n     * this entity. The following values are defined: \"udp\", \"tcp\", \"sctp\",\n     * \"tls\", but other values may be used also. This method is equivalent to\n     * setParameter(\"transport\", transport). Transport parameter constants\n     * are defined in the {@link javax2.sip.ListeningPoint}.\n     *\n     * @param transport - new value for the \"transport\" parameter\n     * @see javax2.sip.ListeningPoint\n     */\n    public void setTransportParam(String transport) throws ParseException {\n        if (transport == null)\n            throw new NullPointerException(\"null arg\");\n        if (transport.compareToIgnoreCase(\"UDP\") == 0\n            || transport.compareToIgnoreCase(\"TLS\") == 0\n            || transport.compareToIgnoreCase(\"TCP\") == 0\n            || transport.compareToIgnoreCase(\"SCTP\") == 0) {\n            NameValue nv = new NameValue(TRANSPORT, transport.toLowerCase());\n            uriParms.set(nv);\n        } else\n            throw new ParseException(\"bad transport \" + transport, 0);\n    }\n\n    /** Returns the user part of this SipURI, or null if it is not set.\n     *\n     * @return  the user part of this SipURI\n     */\n    public String getUserParam() {\n        return getParameter(\"user\");\n\n    }\n\n    /** Returns whether the the <code>lr</code> parameter is set. This is\n     * equivalent to hasParameter(\"lr\"). This interface has no getLrParam as\n     * RFC3261 does not specify any values for the \"lr\" paramater.\n     *\n     * @return true if the \"lr\" parameter is set, false otherwise.\n     */\n    public boolean hasLrParam() {\n        return uriParms.getNameValue(\"lr\") != null;\n    }\n\n  \n    /**\n     * Returns whether the <code>gr</code> parameter is set.\n     *\n     * Not part on the interface since gruu is not part of the base RFC3261.\n     */\n    public boolean hasGrParam() {\n        return uriParms.getNameValue(GRUU) != null;\n    }\n\n    /**\n     * Sets the <code>gr</code> parameter.\n     *\n     * Not part on the interface since gruu is not part of the base RFC3261.\n     */\n    public void setGrParam(String value) {\n            this.uriParms.set(GRUU, value); // JvB: fixed to not add duplicates\n    }\n\n    /**\n     * Sets the <code>gr</code> parameter.\n     *\n     * Not part on the interface since gruu is not part of the base RFC3261.\n     */\n    public String getGrParam() {\n            return (String) this.uriParms.getValue(GRUU);   // JvB: fixed to not add duplicates\n    }\n\n\t@Override\n\tpublic void setParameter(NameValue nameValue) throws ParseException {\n\t\t// Not used\n\t}\n\n    /**\n     *remove the +sip-instance value from the parameter list if it exists.\n     */\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/TelURLImpl.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.address;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.NameValueList;\n\nimport java.text.ParseException;\nimport java.util.Iterator;\n\n/**\n * Implementation of the TelURL interface.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/15 19:50:45 $\n *\n * @author M. Ranganathan\n *\n */\npublic class TelURLImpl\n    extends GenericURI\n    implements javax2.sip.address.TelURL {\n\n\n    private static final long serialVersionUID = 5873527320305915954L;\n\n    protected TelephoneNumber telephoneNumber;\n\n    /** Creates a new instance of TelURLImpl */\n    public TelURLImpl() {\n        this.scheme = \"tel\";\n    }\n\n    /** Set the telephone number.\n     *@param telephoneNumber -- telephone number to set.\n     */\n\n    public void setTelephoneNumber(TelephoneNumber telephoneNumber) {\n        this.telephoneNumber = telephoneNumber;\n    }\n\n    /** Returns the value of the <code>isdnSubAddress</code> parameter, or null\n     * if it is not set.\n     *\n     * @return  the value of the <code>isdnSubAddress</code> parameter\n     */\n    public String getIsdnSubAddress() {\n        return telephoneNumber.getIsdnSubaddress();\n    }\n\n    /** Returns the value of the <code>postDial</code> parameter, or null if it\n     * is not set.\n     *\n     * @return  the value of the <code>postDial</code> parameter\n     */\n    public String getPostDial() {\n        return telephoneNumber.getPostDial();\n    }\n\n    /** Returns the value of the \"scheme\" of this URI, for example \"sip\", \"sips\"\n     * or \"tel\".\n     *\n     * @return the scheme paramter of the URI\n     */\n    public String getScheme() {\n        return this.scheme;\n    }\n\n    /** Returns <code>true</code> if this TelURL is global i.e. if the TelURI\n     * has a global phone user.\n     *\n     * @return <code>true</code> if this TelURL represents a global phone user,\n     * and <code>false</code> otherwise.\n     */\n    public boolean isGlobal() {\n        return telephoneNumber.isGlobal();\n    }\n\n    /** This method determines if this is a URI with a scheme of \"sip\" or \"sips\".\n     *\n     * @return true if the scheme is \"sip\" or \"sips\", false otherwise.\n     */\n    public boolean isSipURI() {\n        return false;\n    }\n\n    /** Sets phone user of this TelURL to be either global or local. The default\n     * value is false, hence the TelURL is defaulted to local.\n     *\n     * @param global - the boolean value indicating if the TelURL has a global\n     * phone user.\n     */\n    public void setGlobal(boolean global) {\n        this.telephoneNumber.setGlobal(global);\n    }\n\n    /** Sets ISDN subaddress of this TelURL. If a subaddress is present, it is\n     * appended to the phone number after \";isub=\".\n     *\n     * @param isdnSubAddress - new value of the <code>isdnSubAddress</code>\n     * parameter\n     */\n    public void setIsdnSubAddress(String isdnSubAddress) {\n        this.telephoneNumber.setIsdnSubaddress(isdnSubAddress);\n    }\n\n    /** Sets post dial of this TelURL. The post-dial sequence describes what and\n     * when the local entity should send to the phone line.\n     *\n     * @param postDial - new value of the <code>postDial</code> parameter\n     */\n    public void setPostDial(String postDial) {\n        this.telephoneNumber.setPostDial(postDial);\n    }\n\n    /**\n     * Set the telephone number.\n     * @param telephoneNumber long phone number to set.\n     */\n    public void setPhoneNumber(String telephoneNumber) {\n        this.telephoneNumber.setPhoneNumber(telephoneNumber);\n    }\n\n    /** Get the telephone number.\n     *\n     *@return -- the telephone number.\n     */\n    public String getPhoneNumber() {\n        return this.telephoneNumber.getPhoneNumber();\n    }\n\n    /** Return the string encoding.\n     *\n     *@return -- the string encoding.\n     */\n    public String toString() {\n        return this.scheme + \":\" + telephoneNumber.encode();\n    }\n\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        buffer.append(this.scheme).append(':');\n        telephoneNumber.encode(buffer);\n        return buffer;\n    }\n\n    /** Deep copy clone operation.\n    *\n    *@return -- a cloned version of this telephone number.\n    */\n    public Object clone() {\n        TelURLImpl retval = (TelURLImpl) super.clone();\n        if (this.telephoneNumber != null)\n            retval.telephoneNumber = (TelephoneNumber) this.telephoneNumber.clone();\n        return retval;\n    }\n\n    public String getParameter(String parameterName) {\n        return telephoneNumber.getParameter(parameterName);\n    }\n\n    public void setParameter(String name, String value) {\n        telephoneNumber.setParameter(name, value);\n    }\n\n    public Iterator<String> getParameterNames() {\n        return telephoneNumber.getParameterNames();\n    }\n\n    public NameValueList getParameters() {\n        return telephoneNumber.getParameters();\n    }\n\n    public void removeParameter(String name) {\n        telephoneNumber.removeParameter(name);\n    }\n\n    /* (non-Javadoc)\n     * @see javax2.sip.address.TelURL#setPhoneContext(java.lang.String)\n     */\n    public void setPhoneContext(String phoneContext) throws ParseException {\n\n        // JvB: set (null) should be interpreted as 'remove'\n        if (phoneContext==null) {\n            this.removeParameter(\"phone-context\");\n        } else {\n            this.setParameter(\"phone-context\",phoneContext);\n        }\n    }\n\n    /* (non-Javadoc)\n     * @see javax2.sip.address.TelURL#getPhoneContext()\n     */\n    public String getPhoneContext() {\n\n        return this.getParameter(\"phone-context\");\n    }\n\n\t@Override\n\tpublic void setParameter(NameValue nameValue) throws ParseException {\n\t\t// Not used\n\t}\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/TelephoneNumber.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.address;\n\nimport gov2.nist.core.*;\n\nimport java.util.Iterator;\n\n/**\n * Telephone number class.\n * @version 1.2\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:23 $\n *\n * @author M. Ranganathan\n *\n */\npublic class TelephoneNumber extends NetObject {\n    public static final String POSTDIAL = ParameterNames.POSTDIAL;\n    public static final String PHONE_CONTEXT_TAG =\n        ParameterNames.PHONE_CONTEXT_TAG;\n    public static final String ISUB = ParameterNames.ISUB;\n    public static final String PROVIDER_TAG = ParameterNames.PROVIDER_TAG;\n\n    /** isglobal field\n     */\n    protected boolean isglobal;\n\n    /** phoneNumber field\n     */\n    protected String phoneNumber;\n\n    /** parmeters list\n     */\n    protected NameValueList parameters;\n\n    /** Creates new TelephoneNumber */\n    public TelephoneNumber() {\n        parameters = new NameValueList();\n    }\n\n    /** delete the specified parameter.\n     * @param name String to set\n     */\n    public void deleteParm(String name) {\n        parameters.delete(name);\n    }\n\n    /** get the PhoneNumber field\n     * @return String\n     */\n    public String getPhoneNumber() {\n        return phoneNumber;\n    }\n\n    /** get the PostDial field\n     * @return String\n     */\n    public String getPostDial() {\n        return (String) parameters.getValue(POSTDIAL);\n    }\n\n    /**\n     * Get the isdn subaddress for this number.\n     * @return String\n     */\n    public String getIsdnSubaddress() {\n        return (String) parameters.getValue(ISUB);\n    }\n\n    /** returns true if th PostDial field exists\n     * @return boolean\n     */\n    public boolean hasPostDial() {\n        return parameters.getValue(POSTDIAL) != null;\n    }\n\n    /** return true if this header has parameters.\n     * @param pname String to set\n     * @return boolean\n     */\n    public boolean hasParm(String pname) {\n        return parameters.hasNameValue(pname);\n    }\n\n    /**\n     * return true if the isdn subaddress exists.\n     * @return boolean\n     */\n    public boolean hasIsdnSubaddress() {\n        return hasParm(ISUB);\n    }\n\n    /**\n     * is a global telephone number.\n     * @return boolean\n     */\n    public boolean isGlobal() {\n        return isglobal;\n    }\n\n    /** remove the PostDial field\n     */\n    public void removePostDial() {\n        parameters.delete(POSTDIAL);\n    }\n\n    /**\n     * Remove the isdn subaddress (if it exists).\n     */\n    public void removeIsdnSubaddress() {\n        deleteParm(ISUB);\n    }\n\n    /**\n     * Set the list of parameters.\n     * @param p NameValueList to set\n     */\n    public void setParameters(NameValueList p) {\n        parameters = p;\n    }\n\n    /** set the Global field\n     * @param g boolean to set\n     */\n    public void setGlobal(boolean g) {\n        isglobal = g;\n    }\n\n    /** set the PostDial field\n     * @param p String to set\n     */\n    public void setPostDial(String p) {\n        NameValue nv = new NameValue(POSTDIAL, p);\n        parameters.set(nv);\n    }\n\n    /** set the specified parameter\n     * @param name String to set\n     * @param value Object to set\n     */\n    public void setParm(String name, Object value) {\n        NameValue nv = new NameValue(name, value);\n        parameters.set(nv);\n    }\n\n    /**\n     * set the isdn subaddress for this structure.\n     * @param isub String to set\n     */\n    public void setIsdnSubaddress(String isub) {\n        setParm(ISUB, isub);\n    }\n\n    /** set the PhoneNumber field\n     * @param num String to set\n     */\n    public void setPhoneNumber(String num) {\n        phoneNumber = num;\n    }\n\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (isglobal)\n            buffer.append('+');\n        buffer.append(phoneNumber);\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /**\n     * Returns the value of the named parameter, or null if it is not set. A\n     * zero-length String indicates flag parameter.\n     *\n     * @param name name of parameter to retrieve\n     *\n     * @return the value of specified parameter\n     *\n     */\n    public String getParameter(String name) {\n        Object val = parameters.getValue(name);\n        if (val == null)\n            return null;\n        if (val instanceof GenericObject)\n            return ((GenericObject) val).encode();\n        else\n            return val.toString();\n    }\n\n    /**\n     *\n     * Returns an Iterator over the names (Strings) of all parameters.\n     *\n     * @return an Iterator over all the parameter names\n     *\n     */\n    public Iterator<String> getParameterNames() {\n        return this.parameters.getNames();\n    }\n\n    public void removeParameter(String parameter) {\n        this.parameters.delete(parameter);\n    }\n\n    public void setParameter(String name, String value) {\n        NameValue nv = new NameValue(name, value);\n        this.parameters.set(nv);\n    }\n\n    public Object clone() {\n        TelephoneNumber retval = (TelephoneNumber) super.clone();\n        if (this.parameters != null)\n            retval.parameters = (NameValueList) this.parameters.clone();\n        return retval;\n    }\n\n    public NameValueList getParameters() {\n        return this.parameters;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/address/UserInfo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*\n * Acknowledgement -- Lamine Brahimi\n * Submitted a bug fix for a this class.\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.address;\n\n/**\n * User information part of a URL.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:23 $\n * @author M. Ranganathan   <br/>\n *\n */\npublic final class UserInfo extends NetObject {\n\n\n    private static final long serialVersionUID = 7268593273924256144L;\n\n    /** user field\n     */\n    protected String user;\n\n    /** password field\n     */\n    protected String password;\n\n    /** userType field\n         */\n    protected int userType;\n\n    /** Constant field\n     */\n    public final static int TELEPHONE_SUBSCRIBER = 1;\n\n    /** constant field\n     */\n    public final static int USER = 2;\n\n    /** Default constructor\n     */\n    public UserInfo() {\n        super();\n    }\n\n    /**\n     * Compare for equality.\n     * @param obj Object to set\n     * @return true if the two headers are equals, false otherwise.\n     */\n    public boolean equals(Object obj) {\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        UserInfo other = (UserInfo) obj;\n        if (this.userType != other.userType) {\n            return false;\n        }\n        if (!this.user.equalsIgnoreCase(other.user)) {\n            return false;\n        }\n        if (this.password != null && other.password == null)\n            return false;\n\n        if (other.password != null && this.password == null)\n            return false;\n\n        if (this.password == other.password)\n            return true;\n\n        return (this.password.equals(other.password));\n    }\n\n    /**\n     * Encode the user information as a string.\n     * @return String\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (password != null)\n            buffer.append(user).append(COLON).append(password);\n        else\n            buffer.append(user);\n\n        return buffer;\n    }\n\n    /** Clear the password field.\n    */\n    public void clearPassword() {\n        this.password = null;\n    }\n\n    /**\n     * Gets the user type (which can be set to TELEPHONE_SUBSCRIBER or USER)\n     * @return the type of user.\n     */\n    public int getUserType() {\n        return userType;\n    }\n\n    /** get the user field.\n     * @return String\n     */\n    public String getUser() {\n        return user;\n    }\n\n    /** get the password field.\n     * @return String\n     */\n    public String getPassword() {\n        return password;\n    }\n\n    /**\n     * Set the user member\n     * @param user String to set\n     */\n    public void setUser(String user) {\n        this.user = user;\n        // BUG Fix submitted by Lamine Brahimi\n        // add this (taken form sip_messageParser)\n        // otherwise comparison of two SipUrl will fail because this\n        // parameter is not set (whereas it is set in sip_messageParser).\n        if (user != null\n            && (user.indexOf(POUND) >= 0 || user.indexOf(SEMICOLON) >= 0)) {\n            setUserType(TELEPHONE_SUBSCRIBER);\n        } else {\n            setUserType(USER);\n        }\n    }\n\n    /**\n     * Set the password member\n     * @param p String to set\n     */\n    public void setPassword(String p) {\n        password = p;\n    }\n\n    /**\n     * Set the user type (to TELEPHONE_SUBSCRIBER or USER).\n     * @param type int to set\n     * @throws IllegalArgumentException if type is not in range.\n     */\n    public void setUserType(int type) throws IllegalArgumentException {\n        if (type != TELEPHONE_SUBSCRIBER && type != USER) {\n            throw new IllegalArgumentException(\"Parameter not in range\");\n        }\n        userType = type;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/AccountManager.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\nimport javax2.sip.ClientTransaction;\n\npublic interface AccountManager {\n\n    /**\n     * Returns the user credentials for a given SIP Domain.\n     * You can implement any desired method (such as popping up a dialog for example )\n     * to retrieve the credentials.\n     *\n     * @param challengedTransaction - the transaction that is being challenged.\n     * @param realm - the realm that is being challenged for which a credential should be\n     *         returned.\n     * @return -- the user credentials associated with the domain.\n     */\n\n    UserCredentials getCredentials(ClientTransaction challengedTransaction, String realm);\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/AuthenticationHelper.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\nimport java.text.ParseException;\nimport java.util.Collection;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.SipException;\nimport javax2.sip.SipProvider;\nimport javax2.sip.header.AuthorizationHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/**\n * A helper interface that provides useful functionality for clients that need to authenticate\n * with servers.\n *\n * @author Emil Ivov\n * @author Jeroen van Bemmel\n * @author M. Ranganathan\n *\n * @since 2.0\n *\n *\n */\npublic interface AuthenticationHelper {\n\n    /**\n     * Uses securityAuthority to determinie a set of valid user credentials for\n     * the specified Response (Challenge) and appends it to the challenged\n     * request so that it could be retransmitted.\n     *\n     *\n     *\n     * @param challenge\n     *            the 401/407 challenge response\n     * @param challengedTransaction\n     *            the transaction established by the challenged request\n     * @param transactionCreator\n     *            the JAIN SipProvider that we should use to create the new\n     *            transaction.\n     * @param cacheTime The amount of time (seconds ) for which the authentication helper\n     *      will keep a reference to the generated credentials in a cache.\n     *      If you specify -1, then the authentication credentials are cached\n     *      until you remove them from the cache. If you choose this option, make sure\n     *      you remove the cached headers or you will have a memory leak.\n     *\n     * @return a transaction containing a re-originated request with the\n     *         necessary authorization header.\n     * @throws SipException\n     *             if we get an exception white creating the new transaction\n     * @throws NullPointerException\n     *             if an argument or a header is null.\n     */\n    public abstract ClientTransaction handleChallenge(Response challenge,\n            ClientTransaction challengedTransaction,\n            SipProvider transactionCreator, int cacheTime ) throws SipException,\n             NullPointerException;\n\n    /**\n     * Attach authentication headers to the given request. This looks up\n     * the credential cache and picks up any stored authentication headers\n     * for the given call ID and attaches it to the request.\n     * @param request - the request for which we attach the authentication headers.\n     */\n    public abstract void setAuthenticationHeaders(Request request) ;\n\n    /**\n     * Remove cached entry.\n     *\n     * @param callId -- the call Id for which we want to remove the cached headers.\n     *\n     */\n    public abstract void removeCachedAuthenticationHeaders(String callId);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/AuthenticationHelperImpl.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\n/*\n *\n * This code has been contributed with permission from:\n *\n * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client but has been significantly changed.\n * It is donated to the JAIN-SIP project as it is common code that many sip clients\n * need to perform class and others will consitute a set of utility functions\n * that will implement common operations that ease the life of the developer.\n *\n * Acknowledgements:\n * ----------------\n *\n * Fredrik Wickstrom reported that dialog cseq counters are not incremented\n * when resending requests. He later uncovered additional problems and\n * proposed a way to fix them (his proposition was taken into account).\n */\n\nimport gov2.nist.javax2.sip.SipStackImpl;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.stack.SIPClientTransaction;\nimport gov2.nist.javax2.sip.stack.SIPTransactionStack;\n\nimport java.text.ParseException;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.ListIterator;\nimport java.util.Timer;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.DialogState;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.SipException;\nimport javax2.sip.SipProvider;\nimport javax2.sip.address.Hop;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.address.URI;\nimport javax2.sip.header.AuthorizationHeader;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderFactory;\nimport javax2.sip.header.ProxyAuthenticateHeader;\nimport javax2.sip.header.ProxyAuthorizationHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.header.WWWAuthenticateHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/**\n * The class handles authentication challenges, caches user credentials and takes care (through\n * the SecurityAuthority interface) about retrieving passwords.\n *\n *\n * @author Emil Ivov\n * @author Jeroen van Bemmel\n * @author M. Ranganathan\n *\n * @since 2.0\n */\n\npublic class AuthenticationHelperImpl implements AuthenticationHelper {\n\n    /**\n     * Credentials cached so far.\n     */\n    private CredentialsCache cachedCredentials;\n\n    /**\n     * The account manager for the system. Stores user credentials.\n     */\n    private Object accountManager = null;\n\n    /*\n     * Header factory for this security manager.\n     */\n    private HeaderFactory headerFactory;\n\n    private SipStackImpl sipStack;\n\n    Timer timer;\n\n    /**\n     * Default constructor for the security manager. There is one Account manager. There is one\n     * SipSecurity manager for every user name,\n     *\n     * @param sipStack -- our stack.\n     * @param accountManager -- an implementation of the AccountManager interface.\n     * @param headerFactory -- header factory.\n     */\n    public AuthenticationHelperImpl(SipStackImpl sipStack, AccountManager accountManager,\n            HeaderFactory headerFactory) {\n        this.accountManager = accountManager;\n        this.headerFactory = headerFactory;\n        this.sipStack = sipStack;\n\n        this.cachedCredentials = new CredentialsCache(((SIPTransactionStack) sipStack).getTimer());\n    }\n    \n    /**\n     * Default constructor for the security manager. There is one Account manager. There is one\n     * SipSecurity manager for every user name,\n     *\n     * @param sipStack -- our stack.\n     * @param accountManager -- an implementation of the AccountManager interface.\n     * @param headerFactory -- header factory.\n     */\n    public AuthenticationHelperImpl(SipStackImpl sipStack, SecureAccountManager accountManager,\n            HeaderFactory headerFactory) {\n        this.accountManager = accountManager;\n        this.headerFactory = headerFactory;\n        this.sipStack = sipStack;\n\n        this.cachedCredentials = new CredentialsCache(((SIPTransactionStack) sipStack).getTimer());\n    }\n    \n\n    /*\n     * (non-Javadoc)\n     *\n     * @see gov2.nist.javax2.sip.clientauthutils.AuthenticationHelper#handleChallenge(javax2.sip.message.Response,\n     *      javax2.sip.ClientTransaction, javax2.sip.SipProvider)\n     */\n    public ClientTransaction handleChallenge(Response challenge,\n            ClientTransaction challengedTransaction, SipProvider transactionCreator, int cacheTime)\n            throws SipException, NullPointerException {\n        try {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"handleChallenge: \" + challenge);\n            }\n\n            SIPRequest challengedRequest = ((SIPRequest) challengedTransaction.getRequest());\n\n            Request reoriginatedRequest = null;\n            /*\n             * If the challenged request is part of a Dialog and the\n             * Dialog is confirmed the re-originated request should be\n             * generated as an in-Dialog request.\n             */\n            if (  challengedRequest.getToTag() != null  ||\n                    challengedTransaction.getDialog() == null ||\n                    challengedTransaction.getDialog().getState() != DialogState.CONFIRMED)  {\n                reoriginatedRequest = (Request) challengedRequest.clone();\n            } else {\n                /*\n                 * Re-originate the request by consulting the dialog. In particular\n                 * the route set could change between the original request and the \n                 * in-dialog challenge.\n                 */\n                reoriginatedRequest =\n                    challengedTransaction.getDialog().createRequest(challengedRequest.getMethod());\n                Iterator<String> headerNames = challengedRequest.getHeaderNames();\n                while (headerNames.hasNext()) {\n                    String headerName = headerNames.next();\n                    if ( reoriginatedRequest.getHeader(headerName) != null) {\n                        ListIterator<Header> iterator = reoriginatedRequest.getHeaders(headerName);\n                        while (iterator.hasNext()) {\n                            reoriginatedRequest.addHeader(iterator.next());\n                        }\n                    }\n                }\n            }\n\n\n\n            // remove the branch id so that we could use the request in a new\n            // transaction\n            removeBranchID(reoriginatedRequest);\n\n            if (challenge == null || reoriginatedRequest == null) {\n                throw new NullPointerException(\"A null argument was passed to handle challenge.\");\n            }\n\n            ListIterator authHeaders = null;\n\n            if (challenge.getStatusCode() == Response.UNAUTHORIZED) {\n                authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME);\n            } else if (challenge.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) {\n                authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME);\n            } else {\n                throw new IllegalArgumentException(\"Unexpected status code \");\n            }\n\n            if (authHeaders == null) {\n                throw new IllegalArgumentException(\n                        \"Could not find WWWAuthenticate or ProxyAuthenticate headers\");\n            }\n\n            // Remove all authorization headers from the request (we'll re-add them\n            // from cache)\n            reoriginatedRequest.removeHeader(AuthorizationHeader.NAME);\n            reoriginatedRequest.removeHeader(ProxyAuthorizationHeader.NAME);\n\n            // rfc 3261 says that the cseq header should be augmented for the new\n            // request. do it here so that the new dialog (created together with\n            // the new client transaction) takes it into account.\n            // Bug report - Fredrik Wickstrom\n            CSeqHeader cSeq = (CSeqHeader) reoriginatedRequest.getHeader((CSeqHeader.NAME));\n            try {\n                cSeq.setSeqNumber(cSeq.getSeqNumber() + 1l);\n            } catch (InvalidArgumentException ex) {\n                throw new SipException(\"Invalid CSeq -- could not increment : \"\n                        + cSeq.getSeqNumber());\n            }\n\n\n            /* Resolve this to the next hop based on the previous lookup. If we are not using\n             * lose routing (RFC2543) then just attach hop as a maddr param.\n             */\n            if ( challengedRequest.getRouteHeaders() == null ) {\n                Hop hop   = ((SIPClientTransaction) challengedTransaction).getNextHop();\n                SipURI sipUri = (SipURI) reoriginatedRequest.getRequestURI();\n                sipUri.setMAddrParam(hop.getHost());\n                if ( hop.getPort() != -1 ) sipUri.setPort(hop.getPort());\n            }\n            ClientTransaction retryTran = transactionCreator\n            .getNewClientTransaction(reoriginatedRequest);\n\n            WWWAuthenticateHeader authHeader = null;\n            SipURI requestUri = (SipURI) challengedTransaction.getRequest().getRequestURI();\n            while (authHeaders.hasNext()) {\n                authHeader = (WWWAuthenticateHeader) authHeaders.next();\n                String realm = authHeader.getRealm();\n                AuthorizationHeader authorization = null;\n                String sipDomain;\n                if ( this.accountManager instanceof SecureAccountManager ) {\n                    UserCredentialHash credHash =\n                        ((SecureAccountManager)this.accountManager).getCredentialHash(challengedTransaction,realm);\n                    URI uri = reoriginatedRequest.getRequestURI();\n                    sipDomain = credHash.getSipDomain();\n                    authorization = this.getAuthorization(reoriginatedRequest\n                            .getMethod(), uri.toString(),\n                            (reoriginatedRequest.getContent() == null) ? \"\" : new String(\n                            reoriginatedRequest.getRawContent()), authHeader, credHash);\n                } else {\n                    UserCredentials userCreds = ((AccountManager) this.accountManager).getCredentials(challengedTransaction, realm);\n                    sipDomain = userCreds.getSipDomain();\n                    if (userCreds == null)\n                         throw new SipException(\n                            \"Cannot find user creds for the given user name and realm\");\n\n                    // we haven't yet authenticated this realm since we were\n                    // started.\n\n                       authorization = this.getAuthorization(reoriginatedRequest\n                                .getMethod(), reoriginatedRequest.getRequestURI().toString(),\n                                (reoriginatedRequest.getContent() == null) ? \"\" : new String(\n                                reoriginatedRequest.getRawContent()), authHeader, userCreds);\n                }\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logDebug(\n                        \"Created authorization header: \" + authorization.toString());\n\n                if (cacheTime != 0)\n                    cachedCredentials.cacheAuthorizationHeader(sipDomain,\n                            authorization, cacheTime);\n\n                reoriginatedRequest.addHeader(authorization);\n            }\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"Returning authorization transaction.\" + retryTran);\n            }\n            return retryTran;\n        } catch (SipException ex) {\n            throw ex;\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled()) {\n            \tsipStack.getStackLogger().logError(\"Unexpected exception \", ex);\n            }\n            throw new SipException(\"Unexpected exception \", ex);\n        }\n    }\n    \n    \n   \n\n    /**\n     * Generates an authorisation header in response to wwwAuthHeader.\n     *\n     * @param method method of the request being authenticated\n     * @param uri digest-uri\n     * @param requestBody the body of the request.\n     * @param authHeader the challenge that we should respond to\n     * @param userCredentials username and pass\n     *\n     * @return an authorisation header in response to authHeader.\n     *\n     * @throws OperationFailedException if auth header was malformated.\n     */\n    private AuthorizationHeader getAuthorization(String method, String uri, String requestBody,\n            WWWAuthenticateHeader authHeader, UserCredentials userCredentials) {\n        String response = null;\n\n        // JvB: authHeader.getQop() is a quoted _list_ of qop values\n        // (e.g. \"auth,auth-int\") Client is supposed to pick one\n        String qopList = authHeader.getQop();\n        String qop = (qopList != null) ? \"auth\" : null;\n        String nc_value = \"00000001\";\n        String cnonce = \"xyz\";\n\n        response = MessageDigestAlgorithm.calculateResponse(authHeader.getAlgorithm(),\n                userCredentials.getUserName(), authHeader.getRealm(), userCredentials\n                        .getPassword(), authHeader.getNonce(), nc_value, // JvB added\n                cnonce, // JvB added\n                method, uri, requestBody, qop,sipStack.getStackLogger());// jvb changed\n\n        AuthorizationHeader authorization = null;\n        try {\n            if (authHeader instanceof ProxyAuthenticateHeader) {\n                authorization = headerFactory.createProxyAuthorizationHeader(authHeader\n                        .getScheme());\n            } else {\n                authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme());\n            }\n\n            authorization.setUsername(userCredentials.getUserName());\n            authorization.setRealm(authHeader.getRealm());\n            authorization.setNonce(authHeader.getNonce());\n            authorization.setParameter(\"uri\", uri);\n            authorization.setResponse(response);\n            if (authHeader.getAlgorithm() != null) {\n                authorization.setAlgorithm(authHeader.getAlgorithm());\n            }\n\n            if (authHeader.getOpaque() != null) {\n                authorization.setOpaque(authHeader.getOpaque());\n            }\n\n            // jvb added\n            if (qop != null) {\n                authorization.setQop(qop);\n                authorization.setCNonce(cnonce);\n                authorization.setNonceCount(Integer.parseInt(nc_value));\n            }\n\n            authorization.setResponse(response);\n\n        } catch (ParseException ex) {\n            throw new RuntimeException(\"Failed to create an authorization header!\");\n        }\n\n        return authorization;\n    }\n    /**\n     * Generates an authorisation header in response to wwwAuthHeader.\n     *\n     * @param method method of the request being authenticated\n     * @param uri digest-uri\n     * @param requestBody the body of the request.\n     * @param authHeader the challenge that we should respond to\n     * @param userCredentials username and pass\n     *\n     * @return an authorisation header in response to authHeader.\n     *\n     * @throws OperationFailedException if auth header was malformated.\n     */\n    private AuthorizationHeader getAuthorization(String method, String uri, String requestBody,\n            WWWAuthenticateHeader authHeader, UserCredentialHash userCredentials) {\n        String response = null;\n\n        // JvB: authHeader.getQop() is a quoted _list_ of qop values\n        // (e.g. \"auth,auth-int\") Client is supposed to pick one\n        String qopList = authHeader.getQop();\n        String qop = (qopList != null) ? \"auth\" : null;\n        String nc_value = \"00000001\";\n        String cnonce = \"xyz\";\n\n        response = MessageDigestAlgorithm.calculateResponse(authHeader.getAlgorithm(),\n              userCredentials.getHashUserDomainPassword(), authHeader.getNonce(), nc_value, // JvB added\n                cnonce, // JvB added\n                method, uri, requestBody, qop,sipStack.getStackLogger());// jvb changed\n\n        AuthorizationHeader authorization = null;\n        try {\n            if (authHeader instanceof ProxyAuthenticateHeader) {\n                authorization = headerFactory.createProxyAuthorizationHeader(authHeader\n                        .getScheme());\n            } else {\n                authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme());\n            }\n\n            authorization.setUsername(userCredentials.getUserName());\n            authorization.setRealm(authHeader.getRealm());\n            authorization.setNonce(authHeader.getNonce());\n            authorization.setParameter(\"uri\", uri);\n            authorization.setResponse(response);\n            if (authHeader.getAlgorithm() != null) {\n                authorization.setAlgorithm(authHeader.getAlgorithm());\n            }\n\n            if (authHeader.getOpaque() != null) {\n                authorization.setOpaque(authHeader.getOpaque());\n            }\n\n            // jvb added\n            if (qop != null) {\n                authorization.setQop(qop);\n                authorization.setCNonce(cnonce);\n                authorization.setNonceCount(Integer.parseInt(nc_value));\n            }\n\n            authorization.setResponse(response);\n\n        } catch (ParseException ex) {\n            throw new RuntimeException(\"Failed to create an authorization header!\");\n        }\n\n        return authorization;\n    }\n    /**\n     * Removes all via headers from <tt>request</tt> and replaces them with a new one, equal to\n     * the one that was top most.\n     *\n     * @param request the Request whose branchID we'd like to remove.\n     *\n     */\n    private void removeBranchID(Request request) {\n\n        ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);\n\n        viaHeader.removeParameter(\"branch\");\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see gov2.nist.javax2.sip.clientauthutils.AuthenticationHelper#attachAuthenticationHeaders(javax2.sip.message.Request)\n     */\n    public void setAuthenticationHeaders(Request request) {\n        SIPRequest sipRequest = (SIPRequest) request;\n\n        String callId = sipRequest.getCallId().getCallId();\n\n        request.removeHeader(AuthorizationHeader.NAME);\n        Collection<AuthorizationHeader> authHeaders = this.cachedCredentials\n                .getCachedAuthorizationHeaders(callId);\n        if (authHeaders == null) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logDebug(\n                    \"Could not find authentication headers for \" + callId);\n            return;\n        }\n\n        for (AuthorizationHeader authHeader : authHeaders) {\n            request.addHeader(authHeader);\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see gov2.nist.javax2.sip.clientauthutils.AuthenticationHelper#removeCachedAuthenticationHeaders(java.lang.String)\n     */\n    public void removeCachedAuthenticationHeaders(String callId) {\n        if (callId == null)\n            throw new NullPointerException(\"Null callId argument \");\n        this.cachedCredentials.removeAuthenticationHeader(callId);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/CredentialsCache.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport javax2.sip.*;\nimport javax2.sip.address.*;\nimport javax2.sip.header.*;\nimport javax2.sip.message.*;\n\n/**\n * A cache of authorization headers to be used for subsequent processing when we\n * set up calls. We cache credentials on a per proxy domain per user basis.\n *\n */\n\nclass CredentialsCache {\n\n\n    /**\n     * The key for this map is the proxy domain name. A given proxy authorizes a\n     * user for a number of domains. The Hashtable value of the mapping is a\n     * mapping of user names to AuthorizationHeader list for that proxy domain.\n     */\n    private ConcurrentHashMap<String, List<AuthorizationHeader>> authorizationHeaders =\n            new ConcurrentHashMap<String, List<AuthorizationHeader>>();\n    private Timer timer;\n\n    class TimeoutTask extends TimerTask {\n        String callId;\n        String userName;\n\n        public TimeoutTask(String userName, String proxyDomain) {\n            this.callId = proxyDomain;\n            this.userName = userName;\n        }\n\n        @Override\n        public void run() {\n            authorizationHeaders.remove(callId);\n\n        }\n\n    }\n\n\n\n    CredentialsCache (Timer timer) {\n        this.timer = timer;\n    }\n\n    /**\n     * Cache the bindings of proxyDomain and authorization header.\n     *\n     * @param callid\n     *            the id of the call that the <tt>authorization</tt> header\n     *            belongs to.\n     * @param authorization\n     *            the authorization header that we'd like to cache.\n     */\n    void cacheAuthorizationHeader(String callId,\n            AuthorizationHeader authorization, int cacheTime) {\n        String user = authorization.getUsername();\n        if ( callId == null) throw new NullPointerException(\"Call ID is null!\");\n        if ( authorization == null) throw new NullPointerException(\"Null authorization domain\");\n\n        List<AuthorizationHeader> authHeaders = authorizationHeaders.get(callId);\n        if (authHeaders == null) {\n            authHeaders = new LinkedList<AuthorizationHeader>();\n            authorizationHeaders.put(callId, authHeaders);\n        } else {\n            String realm = authorization.getRealm();\n            for (ListIterator<AuthorizationHeader> li = authHeaders.listIterator(); li.hasNext();) {\n                AuthorizationHeader authHeader = (AuthorizationHeader) li.next();\n                if ( realm.equals(authHeader.getRealm()) ) {\n                    li.remove();\n                }\n            }\n        }\n\n        authHeaders.add(authorization);\n\n        TimeoutTask timeoutTask  = new TimeoutTask( callId,user);\n        if ( cacheTime != -1)\n            this.timer.schedule(timeoutTask, cacheTime*1000);\n\n\n    }\n\n    /**\n     * Returns an authorization header cached for the specified call id and null\n     * if no authorization header has been previously cached for this call.\n     *\n     * @param callid\n     *            the call id that we'd like to retrive a cached authorization\n     *            header for.\n     *\n     * @return authorization header corresponding to that user for the given\n     *         proxy domain.\n     */\n    Collection<AuthorizationHeader> getCachedAuthorizationHeaders(\n            String callid) {\n        if (callid == null)\n            throw new NullPointerException(\"Null arg!\");\n        return this.authorizationHeaders.get(callid);\n\n    }\n\n    /**\n     * Remove a cached authorization header.\n     *\n     * @param callId\n     */\n    public void removeAuthenticationHeader(String callId) {\n        this.authorizationHeaders.remove(callId);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/MessageDigestAlgorithm.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\nimport gov2.nist.core.StackLogger;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * The class takes standard Http Authentication details and returns a response according to the\n * MD5 algorithm\n * \n * @author Emil Ivov\n */\n\npublic class MessageDigestAlgorithm {\n    /**\n     * Calculates an http authentication response in accordance with rfc2617.\n     * <p>\n     * \n     * @param algorithm a string indicating a pair of algorithms (MD5 (default), or MD5-sess) used\n     *        to produce the digest and a checksum.\n     * @param hashUserNameRealmPasswd MD5 hash of (username:realm:password)\n     * @param nonce_value A server-specified data string provided in the challenge.\n     * @param cnonce_value an optional client-chosen value whose purpose is to foil chosen\n     *        plaintext attacks.\n     * @param method the SIP method of the request being challenged.\n     * @param digest_uri_value the value of the \"uri\" directive on the Authorization header in the\n     *        request.\n     * @param entity_body the entity-body\n     * @param qop_value Indicates what \"quality of protection\" the client has applied to the\n     *        message.\n     * @param nc_value the hexadecimal count of the number of requests (including the current\n     *        request) that the client has sent with the nonce value in this request.\n     * @return a digest response as defined in rfc2617\n     * @throws NullPointerException in case of incorrectly null parameters.\n     */\n    \n    static String calculateResponse(String algorithm, String hashUserNameRealmPasswd,\n            String nonce_value, String nc_value, String cnonce_value,\n            String method, String digest_uri_value, String entity_body, String qop_value,\n            StackLogger stackLogger)  {\n    \t// Changed by Deutsche Telekom\n        if (stackLogger!=null && stackLogger.isLoggingEnabled()) {\n            stackLogger.logDebug(\"trying to authenticate using : \" + algorithm + \", \"+\n                    hashUserNameRealmPasswd + \", \" + nonce_value + \", \"\n                    + nc_value + \", \" + cnonce_value + \", \" + method + \", \" + digest_uri_value\n                    + \", \" + entity_body + \", \" + qop_value);\n        }\n        \n        if (hashUserNameRealmPasswd == null || method == null\n                || digest_uri_value == null || nonce_value == null)\n            throw new NullPointerException(\n                    \"Null parameter to MessageDigestAlgorithm.calculateResponse()\");\n\n        // The following follows closely the algorithm for generating a response\n        // digest as specified by rfc2617\n        \n        if (cnonce_value == null || cnonce_value.length() == 0)\n                throw new NullPointerException(\n                        \"cnonce_value may not be absent for MD5-Sess algorithm.\");\n\n     \n        String A2 = null;\n        if (qop_value == null || qop_value.trim().length() == 0\n                || qop_value.trim().equalsIgnoreCase(\"auth\")) {\n            A2 = method + \":\" + digest_uri_value;\n        } else {\n            if (entity_body == null)\n                entity_body = \"\";\n            A2 = method + \":\" + digest_uri_value + \":\" + H(entity_body);\n        }\n\n        String request_digest = null;\n\n        if (cnonce_value != null && qop_value != null && nc_value != null\n                && (qop_value.equalsIgnoreCase(\"auth\") || qop_value.equalsIgnoreCase(\"auth-int\")))\n\n        {\n            request_digest = KD(hashUserNameRealmPasswd, nonce_value + \":\" + nc_value + \":\" + cnonce_value + \":\"\n                    + qop_value + \":\" + H(A2));\n\n        } else {\n            request_digest = KD(hashUserNameRealmPasswd, nonce_value + \":\" + H(A2));\n        }\n\n        return request_digest;\n        \n        \n    }\n\n    /**\n     * Calculates an http authentication response in accordance with rfc2617.\n     * <p>\n     * \n     * @param algorithm a string indicating a pair of algorithms (MD5 (default), or MD5-sess) used\n     *        to produce the digest and a checksum.\n     * @param username_value username_value (see rfc2617)\n     * @param realm_value A string that has been displayed to the user in order to determine the\n     *        context of the username and password to use.\n     * @param passwd the password to encode in the challenge response.\n     * @param nonce_value A server-specified data string provided in the challenge.\n     * @param cnonce_value an optional client-chosen value whose purpose is to foil chosen\n     *        plaintext attacks.\n     * @param method the SIP method of the request being challenged.\n     * @param digest_uri_value the value of the \"uri\" directive on the Authorization header in the\n     *        request.\n     * @param entity_body the entity-body\n     * @param qop_value Indicates what \"quality of protection\" the client has applied to the\n     *        message.\n     * @param nc_value the hexadecimal count of the number of requests (including the current\n     *        request) that the client has sent with the nonce value in this request.\n     * @return a digest response as defined in rfc2617\n     * @throws NullPointerException in case of incorrectly null parameters.\n     */\n    static String calculateResponse(String algorithm, String username_value, String realm_value,\n            String passwd, String nonce_value, String nc_value, String cnonce_value,\n            String method, String digest_uri_value, String entity_body, String qop_value,\n            StackLogger stackLogger) {\n    \t// Changed by Deutsche Telekom\n        if (stackLogger!=null && stackLogger.isLoggingEnabled()) {\n            stackLogger.logDebug(\"trying to authenticate using : \" + algorithm + \", \"\n                    + username_value + \", \" + realm_value + \", \"\n                    + (passwd != null && passwd.trim().length() > 0) + \", \" + nonce_value + \", \"\n                    + nc_value + \", \" + cnonce_value + \", \" + method + \", \" + digest_uri_value\n                    + \", \" + entity_body + \", \" + qop_value);\n        }\n\n        if (username_value == null || realm_value == null || passwd == null || method == null\n                || digest_uri_value == null || nonce_value == null)\n            throw new NullPointerException(\n                    \"Null parameter to MessageDigestAlgorithm.calculateResponse()\");\n\n        // The following follows closely the algorithm for generating a response\n        // digest as specified by rfc2617\n        String A1 = null;\n\n        if (algorithm == null || algorithm.trim().length() == 0\n                || algorithm.trim().equalsIgnoreCase(\"MD5\")) {\n            A1 = username_value + \":\" + realm_value + \":\" + passwd;\n        } else {\n            if (cnonce_value == null || cnonce_value.length() == 0)\n                throw new NullPointerException(\n                        \"cnonce_value may not be absent for MD5-Sess algorithm.\");\n\n            A1 = H(username_value + \":\" + realm_value + \":\" + passwd) + \":\" + nonce_value + \":\"\n                    + cnonce_value;\n        }\n\n        String A2 = null;\n        if (qop_value == null || qop_value.trim().length() == 0\n                || qop_value.trim().equalsIgnoreCase(\"auth\")) {\n            A2 = method + \":\" + digest_uri_value;\n        } else {\n            if (entity_body == null)\n                entity_body = \"\";\n            A2 = method + \":\" + digest_uri_value + \":\" + H(entity_body);\n        }\n\n        String request_digest = null;\n\n        if (cnonce_value != null && qop_value != null && nc_value != null\n                && (qop_value.equalsIgnoreCase(\"auth\") || qop_value.equalsIgnoreCase(\"auth-int\")))\n\n        {\n            request_digest = KD(H(A1), nonce_value + \":\" + nc_value + \":\" + cnonce_value + \":\"\n                    + qop_value + \":\" + H(A2));\n\n        } else {\n            request_digest = KD(H(A1), nonce_value + \":\" + H(A2));\n        }\n\n        return request_digest;\n    }\n\n    /**\n     * Defined in rfc 2617 as H(data) = MD5(data);\n     * \n     * @param data data\n     * @return MD5(data)\n     */\n    private static String H(String data) {\n        try {\n            MessageDigest digest = MessageDigest.getInstance(\"MD5\");\n\n            return toHexString(digest.digest(data.getBytes()));\n        } catch (NoSuchAlgorithmException ex) {\n            // shouldn't happen\n            throw new RuntimeException(\"Failed to instantiate an MD5 algorithm\", ex);\n        }\n    }\n\n    /**\n     * Defined in rfc 2617 as KD(secret, data) = H(concat(secret, \":\", data))\n     * \n     * @param data data\n     * @param secret secret\n     * @return H(concat(secret, \":\", data));\n     */\n    private static String KD(String secret, String data) {\n        return H(secret + \":\" + data);\n    }\n\n    // the following code was copied from the NIST-SIP instant\n    // messenger (its author is Olivier Deruelle). Thanks for making it public!\n    /**\n     * to hex converter\n     */\n    private static final char[] toHex = {\n        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\n    };\n\n    /**\n     * Converts b[] to hex string.\n     * \n     * @param b the bte array to convert\n     * @return a Hex representation of b.\n     */\n    private static String toHexString(byte b[]) {\n        int pos = 0;\n        char[] c = new char[b.length * 2];\n        for (int i = 0; i < b.length; i++) {\n            c[pos++] = toHex[(b[i] >> 4) & 0x0F];\n            c[pos++] = toHex[b[i] & 0x0f];\n        }\n        return new String(c);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/SecureAccountManager.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\nimport javax2.sip.ClientTransaction;\n\npublic interface SecureAccountManager  {\n    /**\n     * Returns the user credentials for a given SIP Domain.\n     * You can implement any desired method (such as popping up a dialog for example )\n     * to retrieve the credentials.\n     *\n     * @param challengedTransaction - the transaction that is being challenged.\n     * @param realm - the realm that is being challenged for which a credential should be\n     *         returned.\n     * @return -- the user credentials associated with the domain.\n     */\n\n    UserCredentialHash getCredentialHash(ClientTransaction challengedTransaction, String realm);\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/UserCredentialHash.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\n/**\n * Interface for those clients that only supply \n * hash(user:domain:password). This is more secure than simply supplying\n * password because the password cannot be extracted. Implementations\n * tend to prefer to store information in user accounts using such a\n * hash rather than plain text passwords because it offers better security.\n * \n */\npublic interface UserCredentialHash {\n    \n    /**\n     * Get the user name.\n     * \n     * @return userName\n     */\n    public String getUserName();\n    \n    \n    /**\n     * Get the SipDomain.\n     * \n     * @return the SIP Domain.\n     */\n    public String getSipDomain();\n    \n    \n    /**\n     * Get the MD5(userName:sipdomain:password)\n     * \n     * @return the MD5 hash of userName:sipDomain:password.\n     */\n    public String getHashUserDomainPassword();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/clientauthutils/UserCredentials.java",
    "content": "package gov2.nist.javax2.sip.clientauthutils;\n\n/**\n* The class is used whenever user credentials for a particular realm (site\n* server or service) are necessary\n* @author Emil Ivov <emcho@dev.java.net>\n* @author M. Ranganathan <mranga@dev.java.net>\n* @version 1.0\n*/\n\npublic interface UserCredentials\n{\n   \n\n   /**\n    * Returns the name of the user that these credentials relate to.\n    * @return the user name.\n    */\n   public String getUserName();\n   \n\n   /**\n    * Returns a password associated with this set of credentials.\n    *\n    * @return a password associated with this set of credentials.\n    */\n   public String getPassword();\n   \n   \n   /**\n    * Returns the SIP Domain for this username password combination.\n    * \n    * @return the sip domain\n    */\n   public String getSipDomain();\n   \n   \n  \n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Accept.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * Accept header : The top level header is actually AcceptList which is a list of\n * Accept headers.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:24 $\n *\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic final class Accept\n    extends ParametersHeader\n    implements javax2.sip.header.AcceptHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -7866187924308658151L;\n\n    /** mediaRange field\n     */\n    protected MediaRange mediaRange;\n\n    /** default constructor\n     */\n    public Accept() {\n        super(NAME);\n    }\n\n    /** returns true if this header allows all ContentTypes,\n      * false otherwise.\n      * @return Boolean\n      */\n    public boolean allowsAllContentTypes() {\n        if (mediaRange == null)\n            return false;\n        else\n            return mediaRange.type.compareTo(STAR) == 0;\n    }\n\n    /**\n     * returns true if this header allows all ContentSubTypes,\n     * false otherwise.\n     * @return boolean\n     */\n    public boolean allowsAllContentSubTypes() {\n        if (mediaRange == null) {\n            return false;\n        } else\n            return mediaRange.getSubtype().compareTo(STAR) == 0;\n    }\n\n    /** Encode the value of this header into cannonical form.\n    *@return encoded value of the header as a string.\n    */\n    protected String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (mediaRange != null)\n            mediaRange.encode(buffer);\n        if (parameters != null && !parameters.isEmpty()) {\n            buffer.append(';');\n            parameters.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /** get the MediaRange field\n     * @return MediaRange\n     */\n    public MediaRange getMediaRange() {\n        return mediaRange;\n    }\n\n    /** get the contentType field\n     * @return String\n     */\n    public String getContentType() {\n        if (mediaRange == null)\n            return null;\n        else\n            return mediaRange.getType();\n    }\n\n    /** get the ContentSubType fiels\n     * @return String\n     */\n    public String getContentSubType() {\n        if (mediaRange == null)\n            return null;\n        else\n            return mediaRange.getSubtype();\n    }\n\n    /**\n     * Get the q value.\n     * @return float\n     */\n    public float getQValue() {\n        return getParameterAsFloat(ParameterNames.Q);\n    }\n\n    /**\n     * Return true if the q value has been set.\n     * @return boolean\n     */\n    public boolean hasQValue() {\n        return super.hasParameter(ParameterNames.Q);\n\n    }\n\n    /**\n     *Remove the q value.\n     */\n    public void removeQValue() {\n        super.removeParameter(ParameterNames.Q);\n    }\n\n    /** set the ContentSubType field\n     * @param subtype String to set\n     */\n    public void setContentSubType(String subtype) {\n        if (mediaRange == null)\n            mediaRange = new MediaRange();\n        mediaRange.setSubtype(subtype);\n    }\n\n    /** set the ContentType field\n     * @param type String to set\n     */\n    public void setContentType(String type) {\n        if (mediaRange == null)\n            mediaRange = new MediaRange();\n        mediaRange.setType(type);\n    }\n\n    /**\n     * Set the q value\n     * @param qValue float to set\n     * @throws IllegalArgumentException if qValue is <0.0 or >1.0\n     */\n    public void setQValue(float qValue) throws InvalidArgumentException {\n        if (qValue == -1)\n            super.removeParameter(ParameterNames.Q);\n        super.setParameter(ParameterNames.Q, qValue);\n\n    }\n\n    /**\n         * Set the mediaRange member\n         * @param m MediaRange field\n         */\n    public void setMediaRange(MediaRange m) {\n        mediaRange = m;\n    }\n\n    public Object clone() {\n        Accept retval = (Accept) super.clone();\n        if (this.mediaRange != null)\n            retval.mediaRange = (MediaRange) this.mediaRange.clone();\n        return retval;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AcceptEncoding.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Accept-Encoding SIP (HTTP) Header.\n *\n * @author M. Ranganathan\n * @author Olivier Deruelle <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:24 $\n * @since 1.1\n *\n * <pre>\n *  From HTTP RFC 2616\n *\n *\n *    The Accept-Encoding request-header field is similar to Accept, but\n *    restricts the content-codings (section 3.5) that are acceptable in\n *    the response.\n *\n *\n *        Accept-Encoding  = &quot;Accept-Encoding&quot; &quot;:&quot;\n *\n *\n *                           1#( codings [ &quot;;&quot; &quot;q&quot; &quot;=&quot; qvalue ] )\n *        codings          = ( content-coding | &quot;*&quot; )\n *\n *    Examples of its use are:\n *\n *        Accept-Encoding: compress, gzip\n *        Accept-Encoding:\n *        Accept-Encoding: *\n *        Accept-Encoding: compress;q=0.5, gzip;q=1.0\n *        Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0\n * </pre>\n *\n */\npublic final class AcceptEncoding extends ParametersHeader implements\n        AcceptEncodingHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -1476807565552873525L;\n\n    /**\n     * contentEncoding field\n     */\n    protected String contentCoding;\n\n    /**\n     * default constructor\n     */\n    public AcceptEncoding() {\n        super(NAME);\n    }\n\n    /**\n     * Encode the value of this header.\n     *\n     * @return the value of this header encoded into a string.\n     */\n    protected String encodeBody() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (contentCoding != null) {\n            buffer.append(contentCoding);\n        }\n        if (parameters != null && !parameters.isEmpty()) {\n            buffer.append(SEMICOLON).append(parameters.encode());\n        }\n        return buffer;\n    }\n\n    /**\n     * get QValue field\n     *\n     * @return float\n     */\n    public float getQValue() {\n        return getParameterAsFloat(\"q\");\n    }\n\n    /**\n     * get ContentEncoding field\n     *\n     * @return String\n     */\n    public String getEncoding() {\n        return contentCoding;\n    }\n\n    /**\n     * Set the qvalue member\n     *\n     * @param q\n     *            double to set\n     */\n    public void setQValue(float q) throws InvalidArgumentException {\n        if (q < 0.0 || q > 1.0)\n            throw new InvalidArgumentException(\"qvalue out of range!\");\n        super.setParameter(\"q\", q);\n    }\n\n    /**\n     * Sets the encoding of an EncodingHeader.\n     *\n     * @param encoding -\n     *            the new string value defining the encoding.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the encoding value.\n     */\n\n    public void setEncoding(String encoding) throws ParseException {\n        if (encoding == null)\n            throw new NullPointerException(\" encoding parameter is null\");\n        contentCoding = encoding;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AcceptEncodingList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * AcceptEncodingList of AccepEncoding headers.\n *\n *@author M. Ranganathan\n *@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:25 $\n *@since 1.1\n *\n *\n */\npublic class AcceptEncodingList extends SIPHeaderList<AcceptEncoding>{\n\n    @Override\n    public Object clone() {\n        AcceptEncodingList retval = new AcceptEncodingList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** default constructor\n     */\n    public AcceptEncodingList() {\n        super(AcceptEncoding.class, AcceptEncodingHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AcceptLanguage.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n /****************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).    *\n ****************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.core.*;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.AcceptLanguageHeader;\n\nimport java.util.Locale;\n\n/**\n * Accept Language body.\n *\n * @author M. Ranganathan\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/18 13:46:32 $\n * @since 1.1\n *\n *\n * <pre>\n * HTTP RFC 2616 Section 14.4\n * Accept-Language = \"Accept-Language\" \":\"\n *                         1#( language-range [ \";\" \"q\" \"=\" qvalue ] )\n *       language-range  = ( ( 1*8ALPHA *( \"-\" 1*8ALPHA ) ) | \"*\" )\n *\n * </pre>\n *\n * @see AcceptLanguageList\n */\npublic final class AcceptLanguage\n    extends ParametersHeader\n    implements AcceptLanguageHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -4473982069737324919L;\n    /** languageRange field\n     */\n    protected String languageRange;\n\n    /** default constructor\n     */\n    public AcceptLanguage() {\n        super(NAME);\n    }\n\n    /** Encode the value of this header to a string.\n     *@return  encoded header as a string.\n     */\n    protected String encodeBody() {\n        StringBuffer encoding = new StringBuffer();\n        if (languageRange != null) {\n            encoding.append(languageRange);\n        }\n        if (!parameters.isEmpty()) {\n            encoding.append(SEMICOLON).append(parameters.encode());\n        }\n        return encoding.toString();\n    }\n\n    /** get the LanguageRange field\n     * @return String\n     */\n    public String getLanguageRange() {\n        return languageRange;\n    }\n\n    /** get the QValue field. Return -1 if the parameter has not been\n     * set.\n     * @return float\n     */\n\n    public float getQValue() {\n        if (!hasParameter(\"q\"))\n            return -1;\n        return ((Float) parameters.getValue(\"q\")).floatValue();\n    }\n\n    /**\n     * Return true if the q value has been set.\n     * @since 1.0\n     * @return boolean\n     */\n    public boolean hasQValue() {\n        return hasParameter(\"q\");\n    }\n\n    /**\n     * Remove the q value.\n     * @since 1.0\n     */\n    public void removeQValue() {\n        removeParameter(\"q\");\n    }\n\n    /**\n     * Set the languageRange.\n     *\n     * @param languageRange is the language range to set.\n     *\n     */\n    public void setLanguageRange(String languageRange) {\n        this.languageRange = languageRange.trim();\n    }\n\n    /**\n     * Sets q-value for media-range in AcceptLanguageHeader. Q-values allow the\n     *\n     * user to indicate the relative degree of preference for that media-range,\n     *\n     * using the qvalue scale from 0 to 1. If no q-value is present, the\n     *\n     * media-range should be treated as having a q-value of 1.\n     *\n     *\n     *\n     * @param q The new float value of the q-value, a value of -1 resets\n     * the qValue.\n     *\n     * @throws InvalidArgumentException if the q parameter value is not\n     *\n     * <code>-1</code> or between <code>0 and 1</code>.\n     *\n     */\n    public void setQValue(float q) throws InvalidArgumentException {\n        if (q < 0.0 || q > 1.0)\n            throw new InvalidArgumentException(\"qvalue out of range!\");\n        if (q == -1)\n            this.removeParameter(\"q\");\n        else\n            this.setParameter(new NameValue(\"q\", Float.valueOf(q)));\n    }\n\n    /**\n     * Gets the language value of the AcceptLanguageHeader.\n     *\n     *\n     *\n     * @return the language Locale value of this AcceptLanguageHeader\n     *\n     */\n    public Locale getAcceptLanguage() {\n        if (this.languageRange == null)\n            return null;\n        else {\n            int dash = languageRange.indexOf('-');\n            if (dash>=0) {\n                return new Locale( languageRange.substring(0,dash), languageRange.substring(dash+1) );\n            } else return new Locale( this.languageRange );\n        }\n    }\n\n    /**\n     * Sets the language parameter of this AcceptLanguageHeader.\n     *\n     *\n     *\n     * @param language - the new Locale value of the language of\n     *\n     * AcceptLanguageHeader\n     *\n     *\n     */\n    public void setAcceptLanguage(Locale language) {\n        // JvB: need to take sub-tag into account\n        if ( \"\".equals(language.getCountry())) {\n            this.languageRange = language.getLanguage();\n        } else {\n            this.languageRange = language.getLanguage() + '-' + language.getCountry();\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AcceptLanguageList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * AcceptLanguageList: Strings together a list of AcceptLanguage SIPHeaders.\n * @author M. Ranganathan\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:25 $\n * @since 1.1\n *\n *\n */\npublic class AcceptLanguageList extends SIPHeaderList<AcceptLanguage>  {\n\n\n    private static final long serialVersionUID = -3289606805203488840L;\n\n    @Override\n    public Object clone() {\n        AcceptLanguageList retval = new AcceptLanguageList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    public AcceptLanguageList() {\n        super(AcceptLanguage.class, AcceptLanguageHeader.NAME);\n    }\n\n    public AcceptLanguage getFirst() {\n        AcceptLanguage retval = (AcceptLanguage) super.getFirst();\n        if (retval != null)\n            return retval;\n        else\n            return new AcceptLanguage();\n    }\n\n    public AcceptLanguage getLast() {\n        AcceptLanguage retval = (AcceptLanguage) super.getLast();\n        if (retval != null)\n            return retval;\n        else\n            return new AcceptLanguage();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AcceptList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * Accept List of  SIP headers.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:25 $\n *\n * @since 1.1\n *\n * @see Accept\n */\npublic class AcceptList extends SIPHeaderList<Accept> {\n\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -1800813338560484831L;\n\n    @Override\n    public Object clone() {\n        AcceptList retval = new AcceptList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    /**\n     * Default constructor\n     */\n    public AcceptList() {\n        super(Accept.class, AcceptHeader.NAME);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AddressParameters.java",
    "content": "package gov2.nist.javax2.sip.header;\n\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport javax2.sip.address.Address;\nimport javax2.sip.header.Parameters;\n\npublic interface AddressParameters extends Parameters {\n\n    /**\n     * get the Address field\n     * @return the imbedded  Address\n     */\n    public abstract Address getAddress();\n\n    /**\n     * set the Address field\n     * @param address Address to set\n     */\n    public abstract void setAddress(Address address);\n\n    /**\n     * Get the parameters map.\n     *\n     */\n    public abstract Map<String,Entry<String,String>> getParameters();\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AddressParametersHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.address.*;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\nimport gov2.nist.javax2.sip.address.*;\n\n/** An abstract class for headers that take an address and parameters.\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:25 $\n *\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n *\n */\npublic abstract class AddressParametersHeader extends ParametersHeader implements  Parameters {\n\n    protected AddressImpl address;\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AddressParameters#getAddress()\n     */\n    public Address getAddress() {\n        return address;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AddressParameters#setAddress(javax2.sip.address.Address)\n     */\n    public void setAddress(Address address) {\n        this.address = (AddressImpl) address;\n    }\n\n    /**\n     * Constructor given the name of the header.\n     */\n    protected AddressParametersHeader(String name) {\n        super(name);\n    }\n\n    /**\n     * Constructor given a synch flag.\n     *\n     * @param name\n     * @param sync\n     */\n\n    protected AddressParametersHeader(String name, boolean sync) {\n        super(name,sync);\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AddressParameters#clone()\n     */\n    public Object clone() {\n        AddressParametersHeader retval = (AddressParametersHeader) super.clone();\n        if (this.address != null)\n            retval.address = (AddressImpl) this.address.clone();\n        return retval;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AddressParameters#equals(java.lang.Object)\n     */\n    public boolean equals(Object other) {\n        if (this==other) return true;\n\n\n\n        if (other instanceof HeaderAddress && other instanceof Parameters) {\n            final HeaderAddress o = (HeaderAddress) other;\n            return this.getAddress().equals( o.getAddress() ) && this.equalParameters( (Parameters) o );\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AlertInfo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.address.*;\n\nimport javax2.sip.address.*;\n\n/**\n * AlertInfo SIP Header.\n *\n * @author M. Ranganathan   <br/>\n *\n * @since 1.1\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:25 $\n *\n *\n */\npublic final class AlertInfo\n    extends ParametersHeader\n    implements javax2.sip.header.AlertInfoHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 4159657362051508719L;\n    /** URI field\n     */\n    protected GenericURI uri;\n    /** String field\n     */\n    protected String string;\n\n    /** Constructor\n     */\n    public AlertInfo() {\n        super(NAME);\n    }\n\n    /**\n     * Return value encoding in canonical form.\n     * @return The value of the header in canonical encoding.\n     */\n    protected String encodeBody() {\n        StringBuffer encoding = new StringBuffer();\n        if (uri != null) {\n            encoding.append(LESS_THAN).append(uri.encode()).append(GREATER_THAN);\n        } else if (string != null) {\n            encoding.append(string);\n        }\n        if (!parameters.isEmpty()) {\n            encoding.append(SEMICOLON).append(parameters.encode());\n        }\n        return encoding.toString();\n    }\n\n    /**\n     * Set the uri member\n     * @param uri URI to set\n     */\n    public void setAlertInfo(URI uri) {\n        this.uri = (GenericURI) uri;\n    }\n\n    /**\n     * Set the string member\n     * @param string String to set\n     */\n    public void setAlertInfo(String string) {\n        this.string = string;\n    }\n\n    /**\n     * Returns the AlertInfo value of this AlertInfoHeader.\n     * @return the URI representing the AlertInfo.\n     */\n    public URI getAlertInfo() {\n        URI alertInfoUri = null;\n\n        if (this.uri != null) {\n            alertInfoUri = (URI) this.uri;\n        } else {\n            try {\n                alertInfoUri = (URI) new GenericURI(string);\n            } catch (ParseException e) {\n                ;  // Eat the exception.\n            }\n        }\n\n        return alertInfoUri;\n    }\n\n    public Object clone() {\n        AlertInfo retval = (AlertInfo) super.clone();\n        if (this.uri != null) {\n            retval.uri = (GenericURI) this.uri.clone();\n        } else if (this.string != null) {\n            retval.string = this.string;\n        }\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AlertInfoList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n* AlertInfo SIPHeader - there can be several AlertInfo headers.\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\npublic class AlertInfoList extends SIPHeaderList<AlertInfo> {\n\n\n\n    private static final long serialVersionUID = 1L;\n\n\n    public Object clone() {\n        AlertInfoList retval = new AlertInfoList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n\n        /** default constructor\n         */\n    public AlertInfoList() {\n        super( AlertInfo.class,AlertInfoHeader.NAME);\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Allow.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\n/**\n * Allow SIPHeader.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:26 $\n * @since 1.1\n *\n *\n */\npublic final class Allow extends\n    SIPHeader implements javax2.sip.header.AllowHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3105079479020693930L;\n    /** method field\n     */\n    protected String method;\n\n    /** default constructor\n     */\n    public Allow() {\n        super(ALLOW);\n    }\n\n    /** constructor\n     * @param m String to set\n     */\n    public Allow(String m) {\n        super(ALLOW);\n        method = m;\n    }\n\n    /** get the method field\n     * @return String\n     */\n    public String getMethod() {\n        return method;\n    }\n\n    /**\n     * Set the method member\n     * @param method method to set.\n     */\n    public void setMethod(String method) throws ParseException {\n        if (method == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception\"\n                    + \", Allow, setMethod(), the method parameter is null.\");\n        this.method = method;\n    }\n\n    /** Return body encoded in canonical form.\n     * @return body encoded as a string.\n     */\n    protected String encodeBody() {\n        return method;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AllowEvents.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\n/**\n * AllowEvents SIPHeader.\n *\n * @author M. Ranganathan  NIST/ITL ANTD. <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:26 $\n * @since 1.1\n */\npublic final class AllowEvents\n    extends SIPHeader\n    implements javax2.sip.header.AllowEventsHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 617962431813193114L;\n    /** method field\n     */\n    protected String eventType;\n\n    /** default constructor\n     */\n    public AllowEvents() {\n        super(ALLOW_EVENTS);\n    }\n\n    /** constructor\n     * @param m String to set\n     */\n    public AllowEvents(String m) {\n        super(ALLOW_EVENTS);\n        eventType = m;\n    }\n\n    /**\n     * Sets the eventType defined in this AllowEventsHeader.\n     *\n     * @param eventType - the String defining the method supported\n     * in this AllowEventsHeader\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the Strings defining the eventType supported\n     */\n    public void setEventType(String eventType) throws ParseException {\n        if (eventType == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception,\"\n                    + \"AllowEvents, setEventType(), the eventType parameter is null\");\n        this.eventType = eventType;\n    }\n\n    /**\n     * Gets the eventType of the AllowEventsHeader.\n     *\n     * @return the String object identifing the eventTypes of AllowEventsHeader.\n     */\n    public String getEventType() {\n        return eventType;\n    }\n\n    /** Return body encoded in canonical form.\n        * @return body encoded as a string.\n        */\n    protected String encodeBody() {\n        return eventType;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AllowEventsList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.*;\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * List of AllowEvents headers.\n * The sip message can have multiple AllowEvents headers which are strung\n * together in a list.\n *\n * @author M. Ranganathan  <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:26 $\n * @since 1.1\n *\n */\npublic class AllowEventsList extends SIPHeaderList<AllowEvents>  {\n\n    private static final long serialVersionUID = -684763195336212992L;\n\n    public Object clone() {\n        AllowEventsList retval = new AllowEventsList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n\n    /** default constructor\n     */\n    public AllowEventsList() {\n        super(AllowEvents.class, AllowEventsHeader.NAME);\n    }\n\n    /**\n     * Gets an Iterator of all the methods of the AllowEventsHeader. Returns an empty\n     *\n     * Iterator if no methods are defined in this AllowEvents Header.\n     *\n     *\n     *\n     * @return Iterator of String objects each identifing the methods of\n     *\n     * AllowEventsHeader.\n     *\n     *\n     */\n    public ListIterator<String> getMethods() {\n        ListIterator<AllowEvents> li = super.hlist.listIterator();\n        LinkedList<String>  ll = new LinkedList<String> ();\n        while (li.hasNext()) {\n            AllowEvents allowEvents = (AllowEvents) li.next();\n            ll.add(allowEvents.getEventType());\n        }\n        return ll.listIterator();\n    }\n\n    /**\n     * Sets the methods supported defined by this AllowEventsHeader.\n     *\n     *\n     *\n     * @param methods - the Iterator of Strings defining the methods supported\n     *\n     * in this AllowEventsHeader\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the Strings defining the methods supported.\n     *\n     *\n     */\n    public void setMethods(List<String> methods) throws ParseException {\n        ListIterator<String> it = methods.listIterator();\n        while (it.hasNext()) {\n            AllowEvents allowEvents = new AllowEvents();\n            allowEvents.setEventType((String) it.next());\n            this.add(allowEvents);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AllowList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.*;\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * List of ALLOW headers. The sip message can have multiple Allow headers\n *\n * @author M. Ranganathan  <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:26 $\n * @since 1.1\n *\n */\npublic class AllowList extends SIPHeaderList<Allow> {\n\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -4699795429662562358L;\n\n\n    public Object clone() {\n        AllowList retval = new AllowList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n\n    /** default constructor\n     */\n    public AllowList() {\n        super(Allow.class, AllowHeader.NAME);\n    }\n\n    /**\n     * Gets an Iterator of all the methods of the AllowHeader. Returns an empty\n     *\n     * Iterator if no methods are defined in this Allow Header.\n     *\n     *\n     *\n     * @return Iterator of String objects each identifing the methods of\n     *\n     * AllowHeader.\n     *\n     *\n     */\n    public ListIterator<String> getMethods() {\n\n        LinkedList<String> ll = new LinkedList<String> ();\n\n        for ( Iterator<Allow> it = this.hlist.iterator(); it.hasNext();) {\n            Allow a = (Allow)it.next();\n            ll.add(a.getMethod());\n        }\n\n        return ll.listIterator();\n    }\n\n    /**\n     * Sets the methods supported defined by this AllowHeader.\n     *\n     *\n     *\n     * @param methods - the Iterator of Strings defining the methods supported\n     *\n     * in this AllowHeader\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the Strings defining the methods supported.\n     *\n     *\n     */\n    public void setMethods(List<String> methods) throws ParseException {\n        ListIterator<String> it = methods.listIterator();\n        while (it.hasNext()) {\n            Allow allow = new Allow();\n            allow.setMethod((String) it.next());\n            this.add(allow);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AuthenticationHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*****************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).     *\n******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\n\nimport java.text.ParseException;\n /*\n * 2005/06/12: geir.hedemark@telio.no: Changed behaviour of qop parameter in\n *           Authorization header - removed quoting of string according to\n *          RFC3261, BNF element \"message-qop\" (as opposed to \"qop-options\",\n *           which is quoted.\n */\n\n/**\n * The generic AuthenticationHeader\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan <br/>\n * @since 1.1\n * @version 1.2 $Revision: 1.13 $ $Date: 2009/10/18 13:46:32 $\n *\n *\n */\npublic abstract class AuthenticationHeader extends ParametersHeader {\n\n    public static final String DOMAIN = ParameterNames.DOMAIN;\n\n    public static final String REALM = ParameterNames.REALM;\n\n    public static final String OPAQUE = ParameterNames.OPAQUE;\n\n    public static final String ALGORITHM = ParameterNames.ALGORITHM;\n\n    public static final String QOP = ParameterNames.QOP;\n\n    public static final String STALE = ParameterNames.STALE;\n\n    public static final String SIGNATURE = ParameterNames.SIGNATURE;\n\n    public static final String RESPONSE = ParameterNames.RESPONSE;\n\n    public static final String SIGNED_BY = ParameterNames.SIGNED_BY;\n\n    public static final String NC = ParameterNames.NC;\n\n    public static final String URI = ParameterNames.URI;\n\n    public static final String USERNAME = ParameterNames.USERNAME;\n\n    public static final String CNONCE = ParameterNames.CNONCE;\n\n    public static final String NONCE = ParameterNames.NONCE;\n\n    public static final String IK = ParameterNamesIms.IK;\n    public static final String CK = ParameterNamesIms.CK;\n    public static final String INTEGRITY_PROTECTED = ParameterNamesIms.INTEGRITY_PROTECTED;\n\n    protected String scheme;\n\n    public AuthenticationHeader(String name) {\n        super(name);\n        parameters.setSeparator(Separators.COMMA); // oddball\n        this.scheme = ParameterNames.DIGEST;\n    }\n\n    public AuthenticationHeader() {\n        super();\n        parameters.setSeparator(Separators.COMMA);\n    }\n\n    /**\n     * set the specified parameter. Bug reported by Dominic Sparks.\n     *\n     * @param name --\n     *            name of the parameter\n     * @param value --\n     *            value of the parameter.\n     */\n    public void setParameter(String name, String value) throws ParseException {\n        NameValue nv = super.parameters.getNameValue(name.toLowerCase());\n        if (nv == null) {\n            nv = new NameValue(name, value);\n            if (name.equalsIgnoreCase(ParameterNames.QOP)\n                    || name.equalsIgnoreCase(ParameterNames.REALM)\n                    || name.equalsIgnoreCase(ParameterNames.CNONCE)\n                    || name.equalsIgnoreCase(ParameterNames.NONCE)\n                    || name.equalsIgnoreCase(ParameterNames.USERNAME)\n                    || name.equalsIgnoreCase(ParameterNames.DOMAIN)\n                    || name.equalsIgnoreCase(ParameterNames.OPAQUE)\n                    || name.equalsIgnoreCase(ParameterNames.NEXT_NONCE)\n                    || name.equalsIgnoreCase(ParameterNames.URI)\n                    || name.equalsIgnoreCase(ParameterNames.RESPONSE )\n                    ||name.equalsIgnoreCase(ParameterNamesIms.IK)\n                    || name.equalsIgnoreCase(ParameterNamesIms.CK)\n                    || name.equalsIgnoreCase(ParameterNamesIms.INTEGRITY_PROTECTED)) {\n                if (((this instanceof Authorization) || (this instanceof ProxyAuthorization))\n                        && name.equalsIgnoreCase(ParameterNames.QOP)) {\n                    // NOP, QOP not quoted in authorization headers\n                } else {\n                    nv.setQuotedValue();\n                }\n                if (value == null)\n                    throw new NullPointerException(\"null value\");\n                if (value.startsWith(Separators.DOUBLE_QUOTE))\n                    throw new ParseException(value\n                            + \" : Unexpected DOUBLE_QUOTE\", 0);\n            }\n            super.setParameter(nv);\n        } else\n            nv.setValueAsObject(value);\n\n    }\n\n    /**\n     * This is only used for the parser interface.\n     *\n     * @param challenge --\n     *            the challenge from which the parameters are extracted.\n     */\n    public void setChallenge(Challenge challenge) {\n        this.scheme = challenge.scheme;\n        super.parameters = challenge.authParams;\n    }\n\n    /**\n     * Encode in canonical form.\n     *\n     * @return canonical string.\n     */\n    public String encodeBody() {\n        this.parameters.setSeparator(Separators.COMMA);\n        return this.scheme + SP + parameters.encode();\n    }\n\n    /**\n     * Sets the scheme of the challenge information for this\n     * AuthenticationHeaderHeader. For example, Digest.\n     *\n     * @param scheme -\n     *            the new string value that identifies the challenge information\n     *            scheme.\n     */\n    public void setScheme(String scheme) {\n        this.scheme = scheme;\n    }\n\n    /**\n     * Returns the scheme of the challenge information for this\n     * AuthenticationHeaderHeader.\n     *\n     * @return the string value of the challenge information.\n     */\n    public String getScheme() {\n        return scheme;\n    }\n\n    /**\n     * Sets the Realm of the WWWAuthenicateHeader to the <var>realm</var>\n     * parameter value. Realm strings MUST be globally unique. It is RECOMMENDED\n     * that a realm string contain a hostname or domain name. Realm strings\n     * SHOULD present a human-readable identifier that can be rendered to a\n     * user.\n     *\n     * @param realm\n     *            the new Realm String of this WWWAuthenicateHeader.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the realm.\n     */\n    public void setRealm(String realm) throws ParseException {\n        if (realm == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \" AuthenticationHeader, setRealm(), The realm parameter is null\");\n        setParameter(ParameterNames.REALM, realm);\n    }\n\n    /**\n     * Returns the Realm value of this WWWAuthenicateHeader. This convenience\n     * method returns only the realm of the complete Challenge.\n     *\n     * @return the String representing the Realm information, null if value is\n     *         not set.\n     * @since v1.1\n     */\n    public String getRealm() {\n        return getParameter(ParameterNames.REALM);\n    }\n\n    /**\n     * Sets the Nonce of the WWWAuthenicateHeader to the <var>nonce</var>\n     * parameter value.\n     *\n     * @param nonce -\n     *            the new nonce String of this WWWAuthenicateHeader.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the nonce value.\n     * @since v1.1\n     */\n    public void setNonce(String nonce) throws ParseException {\n        if (nonce == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \" AuthenticationHeader, setNonce(), The nonce parameter is null\");\n        setParameter(NONCE, nonce);\n    }\n\n    /**\n     * Returns the Nonce value of this WWWAuthenicateHeader.\n     *\n     * @return the String representing the nonce information, null if value is\n     *         not set.\n     * @since v1.1\n     */\n    public String getNonce() {\n        return getParameter(ParameterNames.NONCE);\n    }\n\n    /**\n     * Sets the URI of the WWWAuthenicateHeader to the <var>uri</var> parameter\n     * value.\n     *\n     * @param uri -\n     *            the new URI of this AuthenicationHeader.\n     * @since v1.1\n     *\n     * Note that since 1.2 this is no longer applicable to the WWW-Authenticate\n     * and Proxy-Authenticate headers\n     */\n    public void setURI(javax2.sip.address.URI uri) {\n        if (uri != null) {\n            NameValue nv = new NameValue(ParameterNames.URI, uri);\n            nv.setQuotedValue();\n            super.parameters.set(nv);\n        } else {\n            throw new NullPointerException(\"Null URI\");\n        }\n    }\n\n    /**\n     * Returns the URI value of this WWWAuthenicateHeader, for example\n     * DigestURI.\n     *\n     * @return the URI representing the URI information, null if value is not\n     *         set.\n     * @since v1.1\n     *\n     * Note that since 1.2 this is no longer applicable to the WWW-Authenticate\n     * and Proxy-Authenticate headers\n     */\n    public javax2.sip.address.URI getURI() {\n        return getParameterAsURI(ParameterNames.URI);\n    }\n\n    /**\n     * Sets the Algorithm of the WWWAuthenicateHeader to the new <var>algorithm</var>\n     * parameter value.\n     *\n     * @param algorithm -\n     *            the new algorithm String of this WWWAuthenicateHeader.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the algorithm value.\n     * @since v1.1\n     */\n    public void setAlgorithm(String algorithm) throws ParseException {\n        if (algorithm == null)\n            throw new NullPointerException(\"null arg\");\n        setParameter(ParameterNames.ALGORITHM, algorithm);\n    }\n\n    /**\n     * Returns the Algorithm value of this WWWAuthenicateHeader.\n     *\n     * @return the String representing the Algorithm information, null if the\n     *         value is not set.\n     * @since v1.1\n     */\n    public String getAlgorithm() {\n        return getParameter(ParameterNames.ALGORITHM);\n    }\n\n    /**\n     * Sets the Qop value of the WWWAuthenicateHeader to the new <var>qop</var>\n     * parameter value.\n     *\n     * @param qop -\n     *            the new Qop string of this WWWAuthenicateHeader.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the Qop value.\n     * @since v1.1\n     */\n    public void setQop(String qop) throws ParseException {\n        if (qop == null)\n            throw new NullPointerException(\"null arg\");\n        setParameter(ParameterNames.QOP, qop);\n    }\n\n    /**\n     * Returns the Qop value of this WWWAuthenicateHeader.\n     *\n     * @return the string representing the Qop information, null if the value is\n     *         not set.\n     * @since v1.1\n     */\n    public String getQop() {\n        return getParameter(ParameterNames.QOP);\n    }\n\n    /**\n     * Sets the Opaque value of the WWWAuthenicateHeader to the new <var>opaque</var>\n     * parameter value.\n     *\n     * @param opaque -\n     *            the new Opaque string of this WWWAuthenicateHeader.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the opaque value.\n     * @since v1.1\n     */\n    public void setOpaque(String opaque) throws ParseException {\n        if (opaque == null)\n            throw new NullPointerException(\"null arg\");\n        setParameter(ParameterNames.OPAQUE, opaque);\n    }\n\n    /**\n     * Returns the Opaque value of this WWWAuthenicateHeader.\n     *\n     * @return the String representing the Opaque information, null if the value\n     *         is not set.\n     * @since v1.1\n     */\n    public String getOpaque() {\n        return getParameter(ParameterNames.OPAQUE);\n    }\n\n    /**\n     * Sets the Domain of the WWWAuthenicateHeader to the <var>domain</var>\n     * parameter value.\n     *\n     * @param domain -\n     *            the new Domain string of this WWWAuthenicateHeader.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the domain.\n     * @since v1.1\n     */\n    public void setDomain(String domain) throws ParseException {\n        if (domain == null)\n            throw new NullPointerException(\"null arg\");\n        setParameter(ParameterNames.DOMAIN, domain);\n    }\n\n    /**\n     * Returns the Domain value of this WWWAuthenicateHeader.\n     *\n     * @return the String representing the Domain information, null if value is\n     *         not set.\n     * @since v1.1\n     */\n    public String getDomain() {\n        return getParameter(ParameterNames.DOMAIN);\n    }\n\n    /**\n     * Sets the value of the stale parameter of the WWWAuthenicateHeader to the\n     * <var>stale</var> parameter value.\n     *\n     * @param stale -\n     *            the Boolean.valueOf value of the stale parameter.\n     * @since v1.1\n     */\n    public void setStale(boolean stale) {\n        setParameter(new NameValue(ParameterNames.STALE, Boolean.valueOf(stale)));\n    }\n\n    /**\n     * Returns the boolean value of the state paramater of this\n     * WWWAuthenicateHeader.\n     *\n     * @return the boolean representing if the challenge is stale.\n     * @since v1.1\n     */\n    public boolean isStale() {\n        return this.getParameterAsBoolean(ParameterNames.STALE);\n    }\n\n    /**\n     * Set the CNonce.\n     *\n     * @param cnonce --\n     *            a nonce string.\n     */\n    public void setCNonce(String cnonce) throws ParseException {\n        this.setParameter(ParameterNames.CNONCE, cnonce);\n    }\n\n    /**\n     * Get the CNonce.\n     *\n     * @return the cnonce value.\n     */\n    public String getCNonce() {\n        return getParameter(ParameterNames.CNONCE);\n    }\n\n    public int getNonceCount() {\n        return this.getParameterAsHexInt(ParameterNames.NC);\n\n    }\n\n    /**\n     * Set the nonce count pakrameter. Bug fix sent in by Andreas Bystr�m\n     */\n\n    public void setNonceCount(int param) throws java.text.ParseException {\n        if (param < 0)\n            throw new ParseException(\"bad value\", 0);\n\n        String nc = Integer.toHexString(param);\n\n        String base = \"00000000\";\n        nc = base.substring(0, 8 - nc.length()) + nc;\n        this.setParameter(ParameterNames.NC, nc);\n\n    }\n\n    /**\n     * Get the RESPONSE value (or null if it does not exist).\n     *\n     * @return String response parameter value.\n     */\n    public String getResponse() {\n        return (String) getParameterValue(ParameterNames.RESPONSE);\n    }\n\n    /**\n     * Set the Response.\n     *\n     * @param response\n     *            to set.\n     */\n    public void setResponse(String response) throws ParseException {\n        if (response == null)\n            throw new NullPointerException(\"Null parameter\");\n        // Bug fix from Andreas Bystr�m\n        this.setParameter(RESPONSE, response);\n    }\n\n    /**\n     * Returns the Username value of this AuthorizationHeader. This convenience\n     * method returns only the username of the complete Response.\n     *\n     * @return the String representing the Username information, null if value\n     *         is not set.\n     *\n     *\n     *\n     */\n    public String getUsername() {\n        return (String) getParameter(ParameterNames.USERNAME);\n    }\n\n    /**\n     * Sets the Username of the AuthorizationHeader to the <var>username</var>\n     * parameter value.\n     *\n     * @param username\n     *            the new Username String of this AuthorizationHeader.\n     *\n     * @throws ParseException\n     *             which signals that an error has been reached\n     *\n     * unexpectedly while parsing the username.\n     *\n     *\n     *\n     */\n    public void setUsername(String username) throws ParseException {\n        this.setParameter(ParameterNames.USERNAME, username);\n    }\n\n    public void setIK(String ik) throws ParseException {\n        if (ik == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \" AuthenticationHeader, setIk(), The auth-param IK parameter is null\");\n        setParameter(IK, ik);\n    }\n\n    public String getIK() {\n        return getParameter(ParameterNamesIms.IK);\n    }\n\n    public void setCK(String ck) throws ParseException {\n        if (ck == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \" AuthenticationHeader, setCk(), The auth-param CK parameter is null\");\n        setParameter(CK, ck);\n    }\n\n    public String getCK() {\n        return getParameter(ParameterNamesIms.CK);\n    }\n\n\n    public void setIntegrityProtected(String integrityProtected) throws ParseException\n    {\n        if (integrityProtected == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \" AuthenticationHeader, setIntegrityProtected(), The integrity-protected parameter is null\");\n\n        setParameter(INTEGRITY_PROTECTED, integrityProtected);\n    }\n\n\n\n    public String getIntegrityProtected() {\n        return getParameter(ParameterNamesIms.INTEGRITY_PROTECTED);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AuthenticationInfo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.*;\n\nimport java.text.ParseException;\n\n/**\n * Authentication info SIP Header.\n *\n * @author M. Ranganathan   NIST/ITL/ANTD\n * @since 1.1\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:27 $\n *\n *\n */\npublic final class AuthenticationInfo\n    extends ParametersHeader\n    implements javax2.sip.header.AuthenticationInfoHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -4371927900917127057L;\n\n    /** Default contstructor.\n     */\n    public AuthenticationInfo() {\n        super(NAME);\n        parameters.setSeparator(COMMA); // Odd ball.\n    }\n\n    public void add(NameValue nv) {\n        parameters.set(nv);\n    }\n\n    /** Value of header encoded in canonical form.\n     */\n\n    protected String encodeBody() {\n        return parameters.encode();\n\n    }\n\n    /** Get the name value pair for a given authentication info parameter.\n     *\n     *@param name is the name for which we want to retrieve the name value\n     *  list.\n     */\n\n    public NameValue getAuthInfo(String name) {\n        return parameters.getNameValue(name);\n    }\n\n    /**\n     * Returns the AuthenticationInfo value of this AuthenticationInfoHeader.\n     *\n     *\n     *\n     * @return the String representing the AuthenticationInfo\n     *\n     *\n     *\n     */\n    public String getAuthenticationInfo() {\n        return this.encodeBody();\n    }\n\n    /** Returns the CNonce value of this AuthenticationInfoHeader.\n     *\n     * @return the String representing the cNonce information, null if value is\n     * not set.\n     * @since v1.1\n     */\n    public String getCNonce() {\n        return this.getParameter(ParameterNames.CNONCE);\n    }\n\n    /** Returns the nextNonce value of this AuthenticationInfoHeader.\n     *\n     * @return the String representing the nextNonce\n     * information, null if value is not set.\n     * @since v1.1\n     */\n    public String getNextNonce() {\n        return this.getParameter(ParameterNames.NEXT_NONCE);\n    }\n\n    /** Returns the Nonce Count value of this AuthenticationInfoHeader.\n     *\n     * @return the integer representing the nonceCount information, -1 if value is\n     * not set.\n     * @since v1.1\n     */\n    public int getNonceCount() {\n        return this.getParameterAsInt(ParameterNames.NONCE_COUNT);\n    }\n\n    /** Returns the messageQop value of this AuthenticationInfoHeader.\n     *\n     * @return the string representing the messageQop information, null if the\n     * value is not set.\n     * @since v1.1\n     */\n    public String getQop() {\n        return this.getParameter(ParameterNames.QOP);\n    }\n\n    /** Returns the Response value of this AuthenticationInfoHeader.\n     *\n     * @return the String representing the Response information.\n     * @since v1.1\n     */\n    public String getResponse() {\n        return this.getParameter(ParameterNames.RESPONSE_AUTH);\n    }\n\n    /** Sets the CNonce of the AuthenticationInfoHeader to the <var>cNonce</var>\n     * parameter value.\n     *\n     * @param cNonce - the new cNonce String of this AuthenticationInfoHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the cNonce value.\n     * @since v1.1\n     */\n    public void setCNonce(String cNonce) throws ParseException {\n        this.setParameter(ParameterNames.CNONCE, cNonce);\n    }\n\n    /** Sets the NextNonce of the AuthenticationInfoHeader to the <var>nextNonce</var>\n     * parameter value.\n     *\n     * @param nextNonce - the new nextNonce String of this AuthenticationInfoHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the nextNonce value.\n     * @since v1.1\n     */\n    public void setNextNonce(String nextNonce) throws ParseException {\n        this.setParameter(ParameterNames.NEXT_NONCE, nextNonce);\n    }\n\n    /** Sets the Nonce Count of the AuthenticationInfoHeader to the <var>nonceCount</var>\n     * parameter value.\n     *\n     * @param nonceCount - the new nonceCount integer of this AuthenticationInfoHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the nonceCount value.\n     * @since v1.1\n     */\n    public void setNonceCount(int nonceCount) throws ParseException {\n        if (nonceCount < 0)\n            throw new ParseException(\"bad value\", 0);\n        String nc = Integer.toHexString(nonceCount);\n\n        String base = \"00000000\";\n        nc = base.substring(0, 8 - nc.length()) + nc;\n        this.setParameter(ParameterNames.NC, nc);\n    }\n\n    /** Sets the Qop value of the AuthenticationInfoHeader to the new\n     * <var>qop</var> parameter value.\n     *\n     * @param qop - the new Qop string of this AuthenticationInfoHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the Qop value.\n     * @since v1.1\n     */\n    public void setQop(String qop) throws ParseException {\n        this.setParameter(ParameterNames.QOP, qop);\n    }\n\n    /** Sets the Response of the\n     * AuthenticationInfoHeader to the new <var>response</var>\n     * parameter value.\n     *\n     * @param response - the new response String of this\n     * AuthenticationInfoHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the Response.\n     * @since v1.1\n     */\n    public void setResponse(String response) throws ParseException {\n        this.setParameter(ParameterNames.RESPONSE_AUTH, response);\n    }\n\n    public void setParameter(String name, String value) throws ParseException {\n        if (name == null)\n            throw new NullPointerException(\"null name\");\n        NameValue nv = super.parameters.getNameValue(name.toLowerCase());\n        if (nv == null) {\n            nv = new NameValue(name, value);\n            if (name.equalsIgnoreCase(ParameterNames.QOP)\n                || name.equalsIgnoreCase(ParameterNames.NEXT_NONCE)\n                || name.equalsIgnoreCase(ParameterNames.REALM)\n                || name.equalsIgnoreCase(ParameterNames.CNONCE)\n                || name.equalsIgnoreCase(ParameterNames.NONCE)\n                || name.equalsIgnoreCase(ParameterNames.OPAQUE)\n                || name.equalsIgnoreCase(ParameterNames.USERNAME)\n                || name.equalsIgnoreCase(ParameterNames.DOMAIN)\n                || name.equalsIgnoreCase(ParameterNames.NEXT_NONCE)\n                || name.equalsIgnoreCase(ParameterNames.RESPONSE_AUTH)) {\n                if (value == null)\n                    throw new NullPointerException(\"null value\");\n                if (value.startsWith(Separators.DOUBLE_QUOTE))\n                    throw new ParseException(\n                        value + \" : Unexpected DOUBLE_QUOTE\",\n                        0);\n                nv.setQuotedValue();\n            }\n            super.setParameter(nv);\n        } else\n            nv.setValueAsObject(value);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AuthenticationInfoList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n\n/**\n* A list of AuthenticationInfo headers (there can be multiple in a message).\n*\n*@author M. Ranganathan   <br/>\n*\n*/\npublic class AuthenticationInfoList extends SIPHeaderList<AuthenticationInfo> {\n\n    private static final long serialVersionUID = 1L;\n\n\n    public Object clone() {\n        AuthenticationInfoList retval = new AuthenticationInfoList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n\n    /** Creates a new instance of AuthenticationList */\n    public AuthenticationInfoList() {\n        super( AuthenticationInfo.class, AuthenticationInfoHeader.NAME);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Authorization.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.header.ims.AuthorizationHeaderIms;\n\nimport javax2.sip.header.*;\n\n/**\n * Authorization SIP header.\n *\n * @see ProxyAuthorization\n *\n * @author M. Ranganathan   NIST/ITL/ANTD <br/>\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:27 $\n *\n *\n */\npublic class Authorization\n    extends gov2.nist.javax2.sip.header.AuthenticationHeader\n    implements javax2.sip.header.AuthorizationHeader, AuthorizationHeaderIms {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -8897770321892281348L;\n\n    /** Default constructor.\n     */\n    public Authorization() {\n        super(AuthorizationHeader.NAME);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/AuthorizationList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n/**\n * WWWAuthenticate SIPHeader (of which there can be several?)\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:27 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class AuthorizationList extends SIPHeaderList<Authorization> {\n\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1L;\n\n\n    public Object clone() {\n        AuthorizationList retval = new AuthorizationList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    /**\n     * constructor.\n     */\n    public AuthorizationList() {\n        super(Authorization.class, Authorization.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/CSeq.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.message.SIPRequest;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.CSeqHeader;\n\nimport java.text.ParseException;\n\n/**\n *  CSeq SIP Header.\n *\n * @author M. Ranganathan    <br/>\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/10/18 13:46:33 $\n * @since 1.1\n *\n */\n\npublic class CSeq extends SIPHeader implements javax2.sip.header.CSeqHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -5405798080040422910L;\n\n    /**\n     * seqno field\n     */\n    protected Long seqno;\n\n    /**\n     * method field\n     */\n    protected String method;\n\n    /**\n     * Constructor.\n     */\n    public CSeq() {\n        super(CSEQ);\n    }\n\n    /**\n     * Constructor given the sequence number and method.\n     *\n     * @param seqno is the sequence number to assign.\n     * @param method is the method string.\n     */\n    public CSeq(long seqno, String method) {\n        this();\n        this.seqno = Long.valueOf(seqno);\n        this.method = SIPRequest.getCannonicalName(method);\n    }\n\n    /**\n     * Compare two cseq headers for equality.\n     * @param other Object to compare against.\n     * @return true if the two cseq headers are equals, false\n     * otherwise.\n     */\n    public boolean equals(Object other) {\n\n        if (other instanceof CSeqHeader) {\n            final CSeqHeader o = (CSeqHeader) other;\n            return this.getSeqNumber() == o.getSeqNumber()\n                && this.getMethod().equals( o.getMethod() );\n        }\n        return false;\n    }\n\n    /**\n     * Return canonical encoded header.\n     * @return String with canonical encoded header.\n     */\n    public String encode() {\n        return headerName + COLON + SP + encodeBody() + NEWLINE;\n    }\n\n    /**\n     * Return canonical header content. (encoded header except headerName:)\n     *\n     * @return encoded string.\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        return buffer.append(seqno).append(SP).append(method.toUpperCase());\n    }\n\n    /**\n     * Get the method.\n     * @return String the method.\n     */\n    public String getMethod() {\n        return method;\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see javax2.sip.header.CSeqHeader#setSequenceNumber(long)\n     */\n    public void setSeqNumber(long sequenceNumber)\n        throws InvalidArgumentException {\n        if (sequenceNumber < 0 )\n            throw new InvalidArgumentException(\n                \"JAIN-SIP Exception, CSeq, setSequenceNumber(), \"\n                    + \"the sequence number parameter is < 0 : \" + sequenceNumber);\n        else if ( sequenceNumber >  ((long)1)<<32 - 1)\n            throw new InvalidArgumentException(\n                    \"JAIN-SIP Exception, CSeq, setSequenceNumber(), \"\n                        + \"the sequence number parameter is too large : \" + sequenceNumber);\n\n        seqno = Long.valueOf(sequenceNumber);\n    }\n\n    /**\n     * For backwards compatibility\n     */\n    public void setSequenceNumber(int sequenceNumber) throws InvalidArgumentException {\n        this.setSeqNumber( (long) sequenceNumber );\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see javax2.sip.header.CSeqHeader#setMethod(java.lang.String)\n     */\n    public void setMethod(String meth) throws ParseException {\n        if (meth == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, CSeq\"\n                    + \", setMethod(), the meth parameter is null\");\n        this.method = SIPRequest.getCannonicalName(meth);\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see javax2.sip.header.CSeqHeader#getSequenceNumber()\n     */\n    public int getSequenceNumber() {\n        if (this.seqno == null)\n            return 0;\n        else\n            return this.seqno.intValue();\n    }\n\n\n\n\n    public long getSeqNumber() {\n        return this.seqno.longValue();\n    }\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/CallID.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.CallIdHeader;\n\nimport java.text.ParseException;\n\n/**\n * Call ID SIPHeader.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:27 $\n * @since 1.1\n */\npublic class CallID\n    extends SIPHeader\n    implements javax2.sip.header.CallIdHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6463630258703731156L;\n    /**\n     * callIdentifier field\n     */\n    protected CallIdentifier callIdentifier;\n\n    /**\n     * Default constructor\n     */\n    public CallID() {\n        super(NAME);\n    }\n\n    /* (non-Javadoc)\n     * @see java.lang.Object#equals(java.lang.Object)\n     *\n     * CallIDs are compared case-insensitively\n     */\n    public boolean equals( Object other ) {\n\n        if (this==other) return true;\n\n        if (other instanceof CallIdHeader) {\n            final CallIdHeader o = (CallIdHeader) other;\n            return this.getCallId().equalsIgnoreCase( o.getCallId() );\n        }\n        return false;\n    }\n\n\n    /**\n     * Encode the body part of this header (i.e. leave out the hdrName).\n     *@return String encoded body part of the header.\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (callIdentifier != null)\n            callIdentifier.encode(buffer);\n\n        return buffer;\n    }\n\n    /**\n     * get the CallId field. This does the same thing as\n     * encodeBody\n     * @return String the encoded body part of the\n     */\n    public String getCallId() {\n        return encodeBody();\n    }\n\n    /**\n     * get the call Identifer member.\n     * @return CallIdentifier\n     */\n    public CallIdentifier getCallIdentifer() {\n        return callIdentifier;\n    }\n\n    /**\n     * set the CallId field\n     * @param cid String to set. This is the body part of the Call-Id\n     *  header. It must have the form localId@host or localId.\n     * @throws IllegalArgumentException if cid is null, not a token, or is\n     * not a token@token.\n     */\n    public void setCallId(String cid) throws ParseException {\n        try {\n            callIdentifier = new CallIdentifier(cid);\n        } catch (IllegalArgumentException ex) {\n            throw new ParseException(cid, 0);\n        }\n    }\n\n    /**\n     * Set the callIdentifier member.\n     * @param cid CallIdentifier to set (localId@host).\n     */\n    public void setCallIdentifier(CallIdentifier cid) {\n        callIdentifier = cid;\n    }\n\n    /** Constructor given the call Identifier.\n     *@param callId string call identifier (should be localid@host)\n     *@throws IllegalArgumentException if call identifier is bad.\n     */\n    public CallID(String callId) throws IllegalArgumentException {\n        super(NAME);\n        this.callIdentifier = new CallIdentifier(callId);\n    }\n\n    public Object clone() {\n        CallID retval = (CallID) super.clone();\n        if (this.callIdentifier != null)\n            retval.callIdentifier = (CallIdentifier) this.callIdentifier.clone();\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/CallIdentifier.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n/**\n * The call identifer that goes into a callID header and a in-reply-to header.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/12/16 02:38:35 $\n * @see CallID\n * @see InReplyTo\n * @since 1.1\n */\npublic final class CallIdentifier extends SIPObject {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 7314773655675451377L;\n\n    /**\n     * localId field\n     */\n    protected String localId;\n\n    /**\n     * host field\n     */\n    protected String host;\n\n    /**\n     * Default constructor\n     */\n    public CallIdentifier() {\n    }\n\n    /**\n     * Constructor\n     * @param localId id is the local id.\n     * @param host is the host.\n     */\n    public CallIdentifier(String localId, String host) {\n        this.localId = localId;\n        this.host = host;\n    }\n\n    /**\n     * constructor\n     * @param cid String to set\n     * @throws IllegalArgumentException if cid is null or is not a token,\n     * or token@token\n     */\n    public CallIdentifier(String cid) throws IllegalArgumentException {\n        setCallID(cid);\n    }\n\n    /**\n     * Get the encoded version of this id.\n     * @return String to set\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        buffer.append(localId);\n        if (host != null) {\n            buffer.append(AT).append(host);\n        }\n        return buffer;\n    }\n\n    /**\n     * Compare two call identifiers for equality.\n     * @param other Object to set\n     * @return true if the two call identifiers are equals, false\n     * otherwise\n     */\n    public boolean equals(Object other) {\n        if (other == null ) return false;\n        if (!other.getClass().equals(this.getClass())) {\n            return false;\n        }\n        CallIdentifier that = (CallIdentifier) other;\n        if (this.localId.compareTo(that.localId) != 0) {\n            return false;\n        }\n        if (this.host == that.host)\n            return true;\n        if ((this.host == null && that.host != null)\n            || (this.host != null && that.host == null))\n            return false;\n        if (host.compareToIgnoreCase(that.host) != 0) {\n            return false;\n        }\n        return true;\n    }\n    \n    @Override\n    public int hashCode() {\n        if (this.localId  == null ) {\n             throw new UnsupportedOperationException(\"Hash code called before id is set\");\n        }\n        return this.localId.hashCode();\n    }\n\n    /** get the LocalId field\n     * @return String\n     */\n    public String getLocalId() {\n        return localId;\n    }\n\n    /** get the host field\n     * @return host member String\n     */\n    public String getHost() {\n        return host;\n    }\n\n    /**\n     * Set the localId member\n     * @param localId String to set\n     */\n    public void setLocalId(String localId) {\n        this.localId = localId;\n    }\n\n    /** set the callId field\n     * @param cid Strimg to set\n     * @throws IllegalArgumentException if cid is null or is not a token or\n     * token@token\n     */\n    public void setCallID(String cid) throws IllegalArgumentException {\n        if (cid == null)\n            throw new IllegalArgumentException(\"NULL!\");\n        int index = cid.indexOf('@');\n        if (index == -1) {\n            localId = cid;\n            host = null;\n        } else {\n            localId = cid.substring(0, index);\n            host = cid.substring(index + 1, cid.length());\n            if (localId == null || host == null) {\n                throw new IllegalArgumentException(\"CallID  must be token@token or token\");\n            }\n        }\n    }\n\n    /**\n     * Set the host member\n     * @param host String to set\n     */\n    public void setHost(String host) {\n        this.host = host;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/CallInfo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.javax2.sip.address.*;\n\nimport java.text.ParseException;\n\n/**\n * CallInfo SIPHeader.\n *\n *\n * @author \"M. Ranganathan\"  <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:28 $\n * @since 1.1\n */\npublic final class CallInfo\n    extends ParametersHeader\n    implements javax2.sip.header.CallInfoHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -8179246487696752928L;\n\n    protected GenericURI info;\n\n    /**\n     * Default constructor\n     */\n    public CallInfo() {\n        super(CALL_INFO);\n    }\n\n    /**\n     * Return canonical representation.\n     * @return String\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        buffer.append(LESS_THAN);\n        info.encode(buffer);\n        buffer.append(GREATER_THAN);\n\n        if (parameters != null && !parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n\n        return buffer;\n    }\n\n    /**\n     * get the purpose field\n     * @return String\n     */\n    public String getPurpose() {\n        return this.getParameter(\"purpose\");\n    }\n\n    /**\n     * get the URI field\n     * @return URI\n     */\n    public javax2.sip.address.URI getInfo() {\n        return info;\n    }\n\n    /**\n     * set the purpose field\n     * @param purpose is the purpose field.\n     */\n    public void setPurpose(String purpose) {\n        if (purpose == null)\n            throw new NullPointerException(\"null arg\");\n        try {\n            this.setParameter(\"purpose\", purpose);\n        } catch (ParseException ex) {\n        }\n    }\n\n    /**\n     * set the URI field\n     * @param info is the URI to set.\n     */\n    public void setInfo(javax2.sip.address.URI info) {\n        this.info = (GenericURI) info;\n    }\n\n    public Object clone() {\n        CallInfo retval = (CallInfo) super.clone();\n        if (this.info != null)\n            retval.info = (GenericURI) this.info.clone();\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/CallInfoList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * A list of CallInfo headers (there can be multiple in a message).\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:28 $\n * @since 1.1\n *\n */\npublic class CallInfoList extends SIPHeaderList<CallInfo> {\n\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -4949850334388806423L;\n\n    public Object clone() {\n        CallInfoList retval = new CallInfoList ();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    /**\n     * Default constructor\n     */\n    public CallInfoList() {\n        super(CallInfo.class, CallInfoHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Challenge.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.*;\n\n/**\n * Challenge part of the Auth header. This is only used by the parser interface\n *\n * @author M. Ranganathan    <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:28 $\n * @since 1.1\n *\n*/\npublic class Challenge extends SIPObject {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 5944455875924336L;\n\n    private static String DOMAIN = ParameterNames.DOMAIN;\n    private static String REALM = ParameterNames.REALM;\n    private static String OPAQUE = ParameterNames.OPAQUE;\n    private static String ALGORITHM = ParameterNames.ALGORITHM;\n    private static String QOP = ParameterNames.QOP;\n    private static String STALE = ParameterNames.STALE;\n    private static String SIGNATURE = ParameterNames.SIGNATURE;\n    private static String RESPONSE = ParameterNames.RESPONSE;\n    private static String SIGNED_BY = ParameterNames.SIGNED_BY;\n    private static String URI = ParameterNames.URI;\n\n    /**\n     * scheme field\n     */\n    protected String scheme;\n\n    /**\n     * authParms list\n     */\n    protected NameValueList authParams;\n\n    /**\n     * Default constructor\n     */\n    public Challenge() {\n        authParams = new NameValueList();\n        authParams.setSeparator(COMMA);\n    }\n\n    /**\n     * Encode the challenge in canonical form.\n     * @return String\n     */\n    public String encode() {\n        return new StringBuffer(scheme)\n            .append(SP)\n            .append(authParams.encode())\n            .toString();\n    }\n\n    /**\n     * get the scheme field\n     * @return String\n     */\n    public String getScheme() {\n        return scheme;\n    }\n\n    /**\n     * get AuthParms list.\n     * @return NameValueList\n     */\n    public NameValueList getAuthParams() {\n        return authParams;\n    }\n\n    /**\n     * get the domain\n     * @return String\n     */\n    public String getDomain() {\n        return (String) authParams.getValue(DOMAIN);\n    }\n\n    /**\n     * get the URI field\n     * @return String\n     */\n    public String getURI() {\n        return (String) authParams.getValue(URI);\n    }\n\n    /**\n     * get the Opaque field\n     * @return String\n     */\n    public String getOpaque() {\n        return (String) authParams.getValue(OPAQUE);\n    }\n\n    /**\n     * get QOP value\n     * @return String\n     */\n    public String getQOP() {\n        return (String) authParams.getValue(QOP);\n    }\n\n    /**\n     * get the Algorithm value.\n     * @return String\n     */\n    public String getAlgorithm() {\n        return (String) authParams.getValue(ALGORITHM);\n    }\n\n    /**\n     * get the State value.\n     * @return String\n     */\n    public String getStale() {\n        return (String) authParams.getValue(STALE);\n    }\n\n    /**\n     * get the Signature value.\n     * @return String\n     */\n    public String getSignature() {\n        return (String) authParams.getValue(SIGNATURE);\n    }\n\n    /**\n     * get the signedBy value.\n     * @return String\n     */\n    public String getSignedBy() {\n        return (String) authParams.getValue(SIGNED_BY);\n    }\n\n    /**\n     * get the Response value.\n     * @return String\n     */\n    public String getResponse() {\n        return (String) authParams.getValue(RESPONSE);\n    }\n\n    /**\n     * get the realm value.\n     * @return String.\n     */\n    public String getRealm() {\n        return (String) authParams.getValue(REALM);\n    }\n\n    /**\n     * get the specified parameter\n     * @param name String to set\n     * @return String to set\n     */\n    public String getParameter(String name) {\n        return (String) authParams.getValue(name);\n    }\n\n    /**\n     * boolean function\n     * @param name String to set\n     * @return true if this header has the specified parameter, false otherwise.\n     */\n    public boolean hasParameter(String name) {\n        return authParams.getNameValue(name) != null;\n    }\n\n    /**\n     * Boolean function\n     * @return true if this header has some parameters.\n     */\n    public boolean hasParameters() {\n        return authParams.size() != 0;\n    }\n\n    /**\n     * delete the specified parameter\n     * @param name String\n     * @return true if the specified parameter has been removed, false\n     * otherwise.\n     */\n    public boolean removeParameter(String name) {\n        return authParams.delete(name);\n    }\n\n    /**\n     * remove all parameters\n     */\n    public void removeParameters() {\n        authParams = new NameValueList();\n    }\n\n    /**\n     * set the specified parameter\n     * @param nv NameValue to set\n     */\n    public void setParameter(NameValue nv) {\n        authParams.set(nv);\n    }\n\n    /**\n     * Set the scheme member\n     * @param s String to set\n     */\n    public void setScheme(String s) {\n        scheme = s;\n    }\n\n    /**\n     * Set the authParams member\n     * @param a NameValueList to set\n     */\n    public void setAuthParams(NameValueList a) {\n        authParams = a;\n    }\n\n    public Object clone() {\n        Challenge retval = (Challenge) super.clone();\n        if (this.authParams != null)\n            retval.authParams = (NameValueList) this.authParams.clone();\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Contact.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*\n * Bug reports contributed by Joao Paulo, Stephen Jones,\n * John Zeng and Alstair Cole.\n *\n */\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.javax2.sip.address.AddressImpl;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ContactHeader;\n\nimport java.text.ParseException;\n\n/**\n * Contact Item.\n *\n * @see gov2.nist.javax2.sip.header.ContactList\n *\n * @author M. Ranganathan  <br/>\n * @version 1.2 $Revision: 1.13 $ $Date: 2009/10/18 13:46:31 $\n * @since 1.1\n *\n *\n */\npublic final  class Contact\n    extends AddressParametersHeader\n    implements javax2.sip.header.ContactHeader {\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1677294871695706288L;\n    public static final String ACTION = ParameterNames.ACTION;\n    public static final String PROXY = ParameterNames.PROXY;\n    public static final String REDIRECT = ParameterNames.REDIRECT;\n    public static final String EXPIRES = ParameterNames.EXPIRES;\n    public static final String Q = ParameterNames.Q;\n\n    // This must be private or the toString will go for a loop!\n    private ContactList contactList;\n\n    /** wildCardFlag field.\n     */\n    protected boolean wildCardFlag;\n\n    /** Default constructor.\n     */\n    public Contact() {\n        super(NAME);\n    }\n\n    /** Set a parameter.\n    */\n    public void setParameter(String name, String value) throws ParseException {\n        NameValue nv = parameters.getNameValue(name);\n        if (nv != null) {\n            nv.setValueAsObject(value);\n        } else {\n            nv = new NameValue(name, value);\n            if (name.equalsIgnoreCase(\"methods\"))\n                nv.setQuotedValue();\n            this.parameters.set(nv);\n        }\n    }\n\n    /**\n     * Encode body of the header into a cannonical String.\n     * @return string encoding of the header value.\n     */\n    protected String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (wildCardFlag) {\n            buffer.append('*');\n        }\n        else {\n            // Bug report by Joao Paulo\n            if (address.getAddressType() == AddressImpl.NAME_ADDR) {\n                address.encode(buffer);\n            } else {\n                // Encoding in canonical form must have <> around address.\n                buffer.append('<');\n                address.encode(buffer);\n                buffer.append('>');\n            }\n            if (!parameters.isEmpty()) {\n                buffer.append(SEMICOLON);\n                parameters.encode(buffer);\n            }\n        }\n\n        return buffer;\n    }\n\n    /** get the Contact list.\n     * @return ContactList\n     */\n    public ContactList getContactList() {\n        return contactList;\n    }\n\n    /** get the WildCardFlag field\n     * @return boolean\n     */\n    public boolean getWildCardFlag() {\n        return wildCardFlag;\n    }\n\n    /** get the address field.\n     * @return Address\n     */\n    public javax2.sip.address.Address getAddress() {\n        // JAIN-SIP stores the wild card as an address!\n        return address;\n    }\n\n    /** get the parameters List\n     * @return NameValueList\n     */\n    public NameValueList getContactParms() {\n        return parameters;\n    }\n\n    /** get Expires parameter.\n     * @return the Expires parameter.\n     */\n    public int getExpires() {\n        return getParameterAsInt(EXPIRES);\n    }\n\n    /** Set the expiry time in seconds.\n    *@param expiryDeltaSeconds exipry time.\n    */\n\n    public void setExpires(int expiryDeltaSeconds) {\n        Integer deltaSeconds = Integer.valueOf(expiryDeltaSeconds);\n        this.parameters.set(EXPIRES, deltaSeconds);\n    }\n\n    /** get the Q-value\n     * @return float\n     */\n    public float getQValue() {\n        return getParameterAsFloat(Q);\n    }\n\n    /** set the Contact List\n     * @param cl ContactList to set\n     */\n    public void setContactList(ContactList cl) {\n        contactList = cl;\n    }\n\n    /**\n     * Set the wildCardFlag member\n     * @param w boolean to set\n     */\n    public void setWildCardFlag(boolean w) {\n        this.wildCardFlag = true;\n        this.address = new AddressImpl();\n        this.address.setWildCardFlag();\n    }\n\n    /**\n     * Set the address member\n     *\n     * @param address Address to set\n     */\n    public void setAddress(javax2.sip.address.Address address) {\n        // Canonical form must have <> around the address.\n        if (address == null)\n            throw new NullPointerException(\"null address\");\n        this.address = (AddressImpl) address;\n        this.wildCardFlag = false;\n    }\n\n    /**\n     * set the Q-value parameter\n     * @param qValue float to set\n     */\n    public void setQValue(float qValue) throws InvalidArgumentException {\n        if (qValue != -1 && (qValue < 0 || qValue > 1))\n            throw new InvalidArgumentException(\n                \"JAIN-SIP Exception, Contact, setQValue(), \"\n                    + \"the qValue is not between 0 and 1\");\n        this.parameters.set(Q, Float.valueOf(qValue));\n    }\n\n    public Object clone() {\n        Contact retval = (Contact) super.clone();\n        if (this.contactList != null)\n            retval.contactList = (ContactList) this.contactList.clone();\n        return retval;\n    }\n\n    /* (non-Javadoc)\n     * @see javax2.sip.header.ContactHeader#setWildCard()\n     */\n    public void setWildCard() {\n       this.setWildCardFlag(true);\n\n    }\n\n    /* (non-Javadoc)\n     * @see javax2.sip.header.ContactHeader#isWildCard()\n     */\n    public boolean isWildCard() {\n\n        return this.address.isWildcard();\n    }\n\n    public boolean equals(Object other) {\n        return (other instanceof ContactHeader) && super.equals(other);\n    }\n\n    public void removeSipInstanceParam() {\n        if (parameters != null)\n            parameters.delete(ParameterNames.SIP_INSTANCE);\n    }\n\n    public String getSipInstanceParam() {\n        return (String) parameters.getValue(ParameterNames.SIP_INSTANCE);\n    }\n\n    public void setSipInstanceParam(String value) {\n        this.parameters.set(ParameterNames.SIP_INSTANCE, value);\n    }\n\n    /**\n     *remove the pub-gruu value from the parameter list if it exists.\n     */\n    public void removePubGruuParam() {\n        if (parameters != null)\n            parameters.delete(ParameterNames.PUB_GRUU);\n    }\n\n    public String getPubGruuParam() {\n        return (String) parameters.getValue(ParameterNames.PUB_GRUU);\n    }\n\n    public void setPubGruuParam(String value)\n    {\n        this.parameters.set(ParameterNames.PUB_GRUU, value);\n    }\n\n    /**\n     *remove the pub-gruu value from the parameter list if it exists.\n     */\n    public void removeTempGruuParam() {\n        if (parameters != null)\n            parameters.delete(ParameterNames.TEMP_GRUU);\n    }\n\n    public String getTempGruuParam() {\n        return (String) parameters.getValue(ParameterNames.TEMP_GRUU);\n    }\n\n    public void setTempGruuParam(String value)\n    {\n        this.parameters.set(ParameterNames.TEMP_GRUU, value);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContactList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.util.ListIterator;\n\n/**\n * List of contact headers.ContactLists are also maintained in a hashtable\n * for quick lookup.\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:28 $\n * @since 1.1\n */\npublic class ContactList extends SIPHeaderList<Contact>  {\n\n    private static final long serialVersionUID = 1224806837758986814L;\n\n    public Object clone() {\n        ContactList retval = new ContactList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    /**\n     * Constructor.\n     */\n    public ContactList() {\n        super(Contact.class, ContactHeader.NAME);\n\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentDisposition.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.*;\n\n/**\n * Content Dispositon SIP Header.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:29 $\n * @since 1.1\n *\n */\npublic final class ContentDisposition\n    extends ParametersHeader\n    implements javax2.sip.header.ContentDispositionHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 835596496276127003L;\n    /**\n     * DispositionType field.\n     */\n    protected String dispositionType;\n\n    /**\n     * Default constructor.\n     */\n    public ContentDisposition() {\n        super(NAME);\n    }\n\n    /**\n     * Encode value of header into canonical string.\n     * @return encoded value of header.\n     *\n     */\n    public String encodeBody() {\n        StringBuffer encoding = new StringBuffer(dispositionType);\n        if (!this.parameters.isEmpty()) {\n            encoding.append(SEMICOLON).append(parameters.encode());\n        }\n        return encoding.toString();\n    }\n\n    /**\n     * Set the disposition type.\n     * @param dispositionType type.\n     */\n    public void setDispositionType(String dispositionType)\n        throws ParseException {\n        if (dispositionType == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception\"\n                    + \", ContentDisposition, setDispositionType(), the dispositionType parameter is null\");\n        this.dispositionType = dispositionType;\n    }\n\n    /**\n     * Get the disposition type.\n     * @return Disposition Type\n     */\n    public String getDispositionType() {\n        return this.dispositionType;\n    }\n\n    /**\n     * Get the dispositionType field.\n     * @return String\n     */\n    public String getHandling() {\n        return this.getParameter(\"handling\");\n    }\n\n    /** set the dispositionType field.\n     * @param handling String to set.\n     */\n    public void setHandling(String handling) throws ParseException {\n        if (handling == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception\"\n                    + \", ContentDisposition, setHandling(), the handling parameter is null\");\n        this.setParameter(\"handling\", handling);\n    }\n\n    /**\n     * Gets the interpretation of the message body or message body part of\n     * this ContentDispositionHeader.\n     *\n     * @return interpretation of the message body or message body part\n     */\n    public String getContentDisposition() {\n        return this.encodeBody();\n    }\n}\n/*\n * $Log: ContentDisposition.java,v $\n * Revision 1.5  2009/07/17 18:57:29  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:06  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:34  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentEncoding.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\n/**\n * Content encoding part of a content encoding header list.\n * @see ContentEncodingList\n *<pre>\n * From HTTP RFC 2616\n *14.11 Content-Encoding\n *\n *   The Content-Encoding entity-header field is used as a modifier to the\n *   media-type. When present, its value indicates what additional content\n *   codings have been applied to the entity-body, and thus what decoding\n *   mechanisms must be applied in order to obtain the media-type\n *   referenced by the Content-Type header field. Content-Encoding is\n *   primarily used to allow a document to be compressed without losing\n *   the identity of its underlying media type.\n *\n *       Content-Encoding  = \"Content-Encoding\" \":\" 1#content-coding\n *\n *   Content codings are defined in section 3.5. An example of its use is\n *\n *       Content-Encoding: gzip\n *\n *   The content-coding is a characteristic of the entity identified by\n *   the Request-URI. Typically, the entity-body is stored with this\n *   encoding and is only decoded before rendering or analogous usage.\n *   However, a non-transparent proxy MAY modify the content-coding if the\n *   new coding is known to be acceptable to the recipient, unless the\n *   \"no-transform\" cache-control directive is present in the message.\n *\n *   If the content-coding of an entity is not \"identity\", then the\n *   response MUST include a Content-Encoding entity-header (section\n *   14.11) that lists the non-identity content-coding(s) used.\n *\n *   If the content-coding of an entity in a request message is not\n *   acceptable to the origin server, the server SHOULD respond with a\n *   status code of 415 (Unsupported Media Type).\n *\n *   If multiple encodings have been applied to an entity, the content\n *   codings MUST be listed in the order in which they were applied.\n *   Additional information about the encoding parameters MAY be provided\n *   by other entity-header fields not defined by this specification.\n *</pre>\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:29 $\n * @since 1.1\n */\npublic class ContentEncoding\n    extends SIPHeader\n    implements javax2.sip.header.ContentEncodingHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 2034230276579558857L;\n    /**\n     * ContentEncoding field.\n     */\n    protected String contentEncoding;\n\n    /**\n     * Default constructor.\n     */\n    public ContentEncoding() {\n        super(CONTENT_ENCODING);\n    }\n\n    /**\n     * Constructor.\n     * @param enc String to set.\n     */\n    public ContentEncoding(String enc) {\n        super(CONTENT_ENCODING);\n        contentEncoding = enc;\n    }\n\n    /**\n     * Canonical encoding of body of the header.\n     * @return  encoded body of the header.\n     */\n    public String encodeBody() {\n        return contentEncoding;\n    }\n\n    /**\n     * Get the ContentEncoding field.\n     * @return String\n     */\n    public String getEncoding() {\n        return contentEncoding;\n    }\n\n    /**\n     * Set the ConentEncoding field.\n     * @param encoding String to set\n     */\n    public void setEncoding(String encoding) throws ParseException {\n        if (encoding == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \" + \" encoding is null\");\n        contentEncoding = encoding;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentEncodingList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n*  Content Encoding SIP header List. Keeps a list of ContentEncoding headers.\n*\n*@author M. Rangananthan\n*@version 1.2\n*@since 1.1\n*/\npublic final class ContentEncodingList extends SIPHeaderList<ContentEncoding> {\n\n    private static final long serialVersionUID = 7365216146576273970L;\n\n\n    public Object clone() {\n        ContentEncodingList retval = new ContentEncodingList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n\n        /** Default constructor.\n         */\n    public ContentEncodingList () {\n        super( ContentEncoding.class,\n            ContentEncodingHeader.NAME);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentLanguage.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.Locale;\n\n/**\n* ContentLanguage header\n* <pre>\n*Fielding, et al.            Standards Track                   [Page 118]\f\n*RFC 2616                        HTTP/1.1                       June 1999\n*\n*  14.12 Content-Language\n*\n*   The Content-Language entity-header field describes the natural\n*   language(s) of the intended audience for the enclosed entity. Note\n*   that this might not be equivalent to all the languages used within\n*   the entity-body.\n*\n*       Content-Language  = \"Content-Language\" \":\" 1#language-tag\n*\n*   Language tags are defined in section 3.10. The primary purpose of\n*   Content-Language is to allow a user to identify and differentiate\n*   entities according to the user's own preferred language. Thus, if the\n*   body content is intended only for a Danish-literate audience, the\n*   appropriate field is\n*\n*       Content-Language: da\n*\n*   If no Content-Language is specified, the default is that the content\n*   is intended for all language audiences. This might mean that the\n*   sender does not consider it to be specific to any natural language,\n*   or that the sender does not know for which language it is intended.\n*\n*   Multiple languages MAY be listed for content that is intended for\n*   multiple audiences. For example, a rendition of the \"Treaty of\n*   Waitangi,\" presented simultaneously in the original Maori and English\n*   versions, would call for\n*\n*       Content-Language: mi, en\n*\n*   However, just because multiple languages are present within an entity\n*   does not mean that it is intended for multiple linguistic audiences.\n*   An example would be a beginner's language primer, such as \"A First\n*   Lesson in Latin,\" which is clearly intended to be used by an\n*   English-literate audience. In this case, the Content-Language would\n*   properly only include \"en\".\n*\n*   Content-Language MAY be applied to any media type -- it is not\n*   limited to textual documents.\n*</pre>\n* @author M. Ranganathan\n* @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:29 $\n* @since 1.1\n*/\npublic class ContentLanguage\n    extends SIPHeader\n    implements javax2.sip.header.ContentLanguageHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -5195728427134181070L;\n    /** languageTag field.\n     */\n    protected Locale locale;\n\n    public ContentLanguage() {\n        super(CONTENT_LANGUAGE);\n    }\n\n    /**\n     * Default constructor.\n     * @param languageTag String to set\n     */\n    public ContentLanguage(String languageTag) {\n        super(CONTENT_LANGUAGE);\n        this.setLanguageTag( languageTag );\n    }\n\n    /**\n     * Canonical encoding of the  value of the header.\n     * @return encoded body of header.\n     */\n    public String encodeBody() {\n        return this.getLanguageTag();\n    }\n\n    /** get the languageTag field.\n     * @return String\n     */\n    public String getLanguageTag() {\n        // JvB: Need to take sub-tags into account\n        if ( \"\".equals(locale.getCountry())) {\n            return locale.getLanguage();\n        } else {\n            return locale.getLanguage() + '-' + locale.getCountry();\n        }\n    }\n\n    /** set the languageTag field\n     * @param languageTag -- language tag to set.\n     */\n    public void setLanguageTag(String languageTag) {\n\n        final int slash = languageTag.indexOf('-');\n        if (slash>=0) {\n            this.locale = new Locale(languageTag.substring(0,slash), languageTag.substring(slash+1) );\n        } else {\n            this.locale = new Locale(languageTag);\n        }\n    }\n\n    /**\n     * Gets the language value of the ContentLanguageHeader.\n     *\n     *\n     *\n     * @return the Locale value of this ContentLanguageHeader\n     *\n     */\n    public Locale getContentLanguage() {\n        return locale;\n    }\n\n    /**\n     * Sets the language parameter of this ContentLanguageHeader.\n     *\n     * @param language - the new Locale value of the language of\n     *\n     * ContentLanguageHeader\n     *\n     */\n    public void setContentLanguage(Locale language) {\n        this.locale = language;\n    }\n\n    public Object clone() {\n        ContentLanguage retval = (ContentLanguage) super.clone();\n        if (this.locale != null)\n            retval.locale = (Locale) this.locale.clone();\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentLanguageList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n* ContentLanguage list of headers.\n*\n*@since 1.1\n*@version 1.2\n*@author M. Ranganathan\n*/\npublic final class ContentLanguageList extends SIPHeaderList<ContentLanguage> {\n\n    private static final long serialVersionUID = -5302265987802886465L;\n    public Object clone() {\n        ContentLanguageList retval = new ContentLanguageList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n        /** Default constructor\n         */\n    public ContentLanguageList () {\n        super(ContentLanguage.class,\n            ContentLanguageHeader.NAME);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentLength.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.*;\nimport javax2.sip.header.ContentLengthHeader;\n\n/**\n* ContentLength SIPHeader (of which there can be only one in a SIPMessage).\n*<pre>\n*Fielding, et al.            Standards Track                   [Page 119]\f\n*RFC 2616                        HTTP/1.1                       June 1999\n*\n*\n*      14.13 Content-Length\n*\n*   The Content-Length entity-header field indicates the size of the\n*   entity-body, in decimal number of OCTETs, sent to the recipient or,\n*   in the case of the HEAD method, the size of the entity-body that\n*   would have been sent had the request been a GET.\n*\n*       Content-Length    = \"Content-Length\" \":\" 1*DIGIT\n*\n*   An example is\n*\n*       Content-Length: 3495\n*\n*   Applications SHOULD use this field to indicate the transfer-length of\n*   the message-body, unless this is prohibited by the rules in section\n*   4.4.\n*\n*   Any Content-Length greater than or equal to zero is a valid value.\n*   Section 4.4 describes how to determine the length of a message-body\n*   if a Content-Length is not given.\n*\n*   Note that the meaning of this field is significantly different from\n*   the corresponding definition in MIME, where it is an optional field\n*   used within the \"message/external-body\" content-type. In HTTP, it\n*   SHOULD be sent whenever the message's length can be determined prior\n*   to being transferred, unless this is prohibited by the rules in\n*   section 4.4.\n* </pre>\n*\n*@author M. Ranganathan   <br/>\n*@author Olivier Deruelle <br/>\n*@version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:34 $\n*@since 1.1\n*/\npublic class ContentLength\n    extends SIPHeader\n    implements javax2.sip.header.ContentLengthHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1187190542411037027L;\n    /**\n     * contentLength field.\n     */\n    protected Integer contentLength;\n\n    /**\n     * Default constructor.\n     */\n    public ContentLength() {\n        super(NAME);\n    }\n\n    /**\n     * Constructor given a length.\n     */\n    public ContentLength(int length) {\n        super(NAME);\n        this.contentLength = Integer.valueOf(length);\n    }\n\n    /**\n     * get the ContentLength field.\n     * @return int\n     */\n    public int getContentLength() {\n        return contentLength.intValue();\n    }\n\n    /**\n     * Set the contentLength member\n     * @param contentLength int to set\n     */\n    public void setContentLength(int contentLength)\n        throws InvalidArgumentException {\n        if (contentLength < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP Exception\"\n                    + \", ContentLength, setContentLength(), the contentLength parameter is <0\");\n        this.contentLength = Integer.valueOf(contentLength);\n    }\n\n    /**\n     * Encode into a canonical string.\n     * @return String\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (contentLength == null)\n            buffer.append(\"0\");\n        else\n            buffer.append(contentLength.toString());\n        return buffer;\n    }\n\n    /**\n     * Pattern matcher ignores content length.\n     */\n    public boolean match(Object other) {\n        if (other instanceof ContentLength)\n            return true;\n        else\n            return false;\n    }\n\n    public boolean equals(Object other) {\n        if (other instanceof ContentLengthHeader) {\n            final ContentLengthHeader o = (ContentLengthHeader) other;\n            return this.getContentLength() == o.getContentLength();\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ContentType.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.ContentTypeHeader;\n\nimport java.text.ParseException;\n\n/**\n*  ContentType SIP Header\n* <pre>\n*14.17 Content-Type\n*\n*   The Content-Type entity-header field indicates the media type of the\n*   entity-body sent to the recipient or, in the case of the HEAD method,\n*   the media type that would have been sent had the request been a GET.\n*\n*   Content-Type   = \"Content-Type\" \":\" media-type\n*\n*   Media types are defined in section 3.7. An example of the field is\n*\n*       Content-Type: text/html; charset=ISO-8859-4\n*\n*   Further discussion of methods for identifying the media type of an\n*   entity is provided in section 7.2.1.\n*\n* From  HTTP RFC 2616\n* </pre>\n*\n*\n*@version 1.2\n*\n*@author M. Ranganathan   <br/>\n*@author Olivier Deruelle <br/>\n*@version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:29 $\n*@since 1.1\n*\n*/\npublic class ContentType\n    extends ParametersHeader\n    implements javax2.sip.header.ContentTypeHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 8475682204373446610L;\n    /** mediaRange field.\n     */\n    protected MediaRange mediaRange;\n\n    /** Default constructor.\n     */\n    public ContentType() {\n        super(CONTENT_TYPE);\n    }\n\n    /** Constructor given a content type and subtype.\n    *@param contentType is the content type.\n    *@param contentSubtype is the content subtype\n    */\n    public ContentType(String contentType, String contentSubtype) {\n        this();\n        this.setContentType(contentType, contentSubtype);\n    }\n\n    /** compare two MediaRange headers.\n     * @param media String to set\n     * @return int.\n     */\n    public int compareMediaRange(String media) {\n        return (\n            mediaRange.type + \"/\" + mediaRange.subtype).compareToIgnoreCase(\n            media);\n    }\n\n    /**\n     * Encode into a canonical string.\n     * @return String.\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        mediaRange.encode(buffer);\n        if (hasParameters()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /** get the mediaRange field.\n     * @return MediaRange.\n     */\n    public MediaRange getMediaRange() {\n        return mediaRange;\n    }\n\n    /** get the Media Type.\n     * @return String.\n     */\n    public String getMediaType() {\n        return mediaRange.type;\n    }\n\n    /** get the MediaSubType field.\n     * @return String.\n     */\n    public String getMediaSubType() {\n        return mediaRange.subtype;\n    }\n\n    /** Get the content subtype.\n    *@return the content subtype string (or null if not set).\n    */\n    public String getContentSubType() {\n        return mediaRange == null ? null : mediaRange.getSubtype();\n    }\n\n    /** Get the content subtype.\n    *@return the content tyep string (or null if not set).\n    */\n\n    public String getContentType() {\n        return mediaRange == null ? null : mediaRange.getType();\n    }\n\n    /** Get the charset parameter.\n    */\n    public String getCharset() {\n        return this.getParameter(\"charset\");\n    }\n\n    /**\n     * Set the mediaRange member\n     * @param m mediaRange field.\n     */\n    public void setMediaRange(MediaRange m) {\n        mediaRange = m;\n    }\n\n    /**\n    * set the content type and subtype.\n    *@param contentType Content type string.\n    *@param contentSubType content subtype string\n    */\n    public void setContentType(String contentType, String contentSubType) {\n        if (mediaRange == null)\n            mediaRange = new MediaRange();\n        mediaRange.setType(contentType);\n        mediaRange.setSubtype(contentSubType);\n    }\n\n    /**\n    * set the content type.\n    *@param contentType Content type string.\n    */\n\n    public void setContentType(String contentType) throws ParseException {\n        if (contentType == null)\n            throw new NullPointerException(\"null arg\");\n        if (mediaRange == null)\n            mediaRange = new MediaRange();\n        mediaRange.setType(contentType);\n\n    }\n\n    /** Set the content subtype.\n         * @param contentType String to set\n         */\n    public void setContentSubType(String contentType) throws ParseException {\n        if (contentType == null)\n            throw new NullPointerException(\"null arg\");\n        if (mediaRange == null)\n            mediaRange = new MediaRange();\n        mediaRange.setSubtype(contentType);\n    }\n\n    public Object clone() {\n        ContentType retval = (ContentType) super.clone();\n        if (this.mediaRange != null)\n            retval.mediaRange = (MediaRange) this.mediaRange.clone();\n        return retval;\n    }\n\n    public boolean equals(Object other) {\n        if (other instanceof ContentTypeHeader) {\n            final ContentTypeHeader o = (ContentTypeHeader) other;\n            return this.getContentType().equalsIgnoreCase( o.getContentType() )\n                && this.getContentSubType().equalsIgnoreCase( o.getContentSubType() )\n                && equalParameters( o );\n        }\n        return false;\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Credentials.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.core.*;\n\n/**\n * Credentials  that are used in authentication and authorization headers.\n * @author M. Ranganathan\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:30 $\n * @since 1.1\n */\npublic class Credentials extends SIPObject {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6335592791505451524L;\n\n    private static String DOMAIN = ParameterNames.DOMAIN;\n    private static String REALM = ParameterNames.REALM;\n    private static String OPAQUE = ParameterNames.OPAQUE;\n    private static String RESPONSE = ParameterNames.RESPONSE;\n    private static String URI = ParameterNames.URI;\n    private static String NONCE = ParameterNames.NONCE;\n    private static String CNONCE = ParameterNames.CNONCE;\n    private static String USERNAME = ParameterNames.USERNAME;\n\n    protected String scheme;\n\n    /**\n     * parameters list.\n     */\n    protected NameValueList parameters;\n\n    /**\n     * Default constructor\n     */\n    public Credentials() {\n        parameters = new NameValueList();\n        parameters.setSeparator(COMMA);\n    }\n\n    /**\n     * get the parameters list.\n     * @return NameValueList\n     */\n    public NameValueList getCredentials() {\n        return parameters;\n    }\n\n    /**\n     * get the scheme field.\n     * @return String.\n     */\n    public String getScheme() {\n        return scheme;\n    }\n\n    /**\n     * Set the scheme member\n     * @param s String to set\n     */\n    public void setScheme(String s) {\n        scheme = s;\n    }\n\n    /**\n     * Set the parameters member\n     * @param c NameValueList to set.\n     */\n    public void setCredentials(NameValueList c) {\n        parameters = c;\n    }\n\n    public String encode() {\n        String retval = scheme;\n        if (!parameters.isEmpty()) {\n            retval += SP + parameters.encode();\n        }\n        return retval;\n    }\n\n    /*public void setCredential(NameValue nameValue) {\n        if (nameValue.getName().compareToIgnoreCase(URI) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(NONCE) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(REALM) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(CNONCE) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(RESPONSE) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(OPAQUE) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(USERNAME) == 0)\n            nameValue.setQuotedValue();\n        else if (nameValue.getName().compareToIgnoreCase(DOMAIN) == 0)\n            nameValue.setQuotedValue();\n        parameters.set(nameValue);\n    }*/\n\n    public Object clone() {\n        Credentials retval = (Credentials) super.clone();\n        if (this.parameters != null)\n            retval.parameters = (NameValueList) this.parameters.clone();\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ErrorInfo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.address.*;\n\nimport javax2.sip.address.*;\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * ErrorInfo SIP Header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:30 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n */\npublic final class ErrorInfo\n    extends ParametersHeader\n    implements ErrorInfoHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6347702901964436362L;\n\n    protected GenericURI errorInfo;\n\n    /**\n     * Default constructor.\n     */\n    public ErrorInfo() {\n        super(NAME);\n    }\n\n    /**\n     * Constructor given the error info\n     * @param errorInfo -- the error information to set.\n     */\n    public ErrorInfo(GenericURI errorInfo) {\n        this();\n        this.errorInfo = errorInfo;\n    }\n\n    /**\n     * Encode into canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        StringBuffer retval =\n            new StringBuffer(LESS_THAN).append(errorInfo.toString()).append(\n                GREATER_THAN);\n        if (!parameters.isEmpty()) {\n            retval.append(SEMICOLON).append(parameters.encode());\n        }\n        return retval.toString();\n    }\n\n    /**\n     * Sets the ErrorInfo of the ErrorInfoHeader to the <var>errorInfo</var>\n     * parameter value.\n     *\n     * @param errorInfo the new ErrorInfo of this ErrorInfoHeader.\n     */\n    public void setErrorInfo(javax2.sip.address.URI errorInfo) {\n        this.errorInfo = (GenericURI) errorInfo;\n\n    }\n\n    /**\n     * Returns the ErrorInfo value of this ErrorInfoHeader. This message\n     * may return null if a String message identifies the ErrorInfo.\n     *\n     * @return the URI representing the ErrorInfo.\n     */\n    public URI getErrorInfo() {\n        return errorInfo;\n    }\n\n    /**\n     * Sets the Error information message to the new <var>message</var> value\n     * supplied to this method.\n     *\n     * @param message - the new string value that represents the error message.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the error message.\n     */\n    public void setErrorMessage(String message) throws ParseException {\n        if (message == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception \"\n                    + \", ErrorInfoHeader, setErrorMessage(), the message parameter is null\");\n        setParameter(\"message\", message);\n    }\n\n    /**\n     * Get the Error information message of this ErrorInfoHeader.\n     *\n     * @return the stringified version of the ErrorInfo header.\n     */\n    public String getErrorMessage() {\n        return getParameter(\"message\");\n    }\n\n    public Object clone() {\n        ErrorInfo retval = (ErrorInfo) super.clone();\n        if (this.errorInfo != null)\n            retval.errorInfo = (GenericURI) this.errorInfo.clone();\n        return retval;\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ErrorInfoList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\n/**\n* Error Info sip header.\n*\n*@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:30 $\n*\n*@author M. Ranganathan   <br/>\n*@since 1.1\n*@see ErrorInfoList\n*<pre>\n*\n* 6.24 Error-Info\n*\n*   The Error-Info response header provides a pointer to additional\n*   information about the error status response. This header field is\n*   only contained in 3xx, 4xx, 5xx and 6xx responses.\n*\n*\n*\n*       Error-Info  =  \"Error-Info\" \":\" # ( \"<\" URI \">\" *( \";\" generic-param ))\n*</pre>\n*\n*/\npublic class ErrorInfoList extends SIPHeaderList<ErrorInfo>{\n\n    /**\n     *\n     */\n    private static final long serialVersionUID = 1L;\n\n    public Object clone() {\n        ErrorInfoList retval = new ErrorInfoList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    /**\n     * Default constructor.\n     */\n    public ErrorInfoList() {\n        super(ErrorInfo.class, ErrorInfoHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Event.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n* Event SIP Header.\n*\n*@version 1.2 $Revision: 1.7 $ $Date: 2007/06/28 15:08:42 $\n*@since 1.1\n*\n*@author M. Ranganathan   <br/>\n*@author Olivier Deruelle <br/>\n*\n*\n*/\npublic class Event extends ParametersHeader implements EventHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6458387810431874841L;\n\n    protected String eventType;\n\n    /**\n     * Creates a new instance of Event\n     */\n    public Event() {\n        super(EVENT);\n    }\n\n    /**\n    * Sets the eventType to the newly supplied eventType string.\n    *\n    * @param eventType - the  new string defining the eventType supported\n    * in this EventHeader\n    * @throws ParseException which signals that an error has been reached\n    * unexpectedly while parsing the eventType value.\n    */\n    public void setEventType(String eventType) throws ParseException {\n        if (eventType == null)\n            throw new NullPointerException(\" the eventType is null\");\n        this.eventType = eventType;\n    }\n\n    /**\n     * Gets the eventType of the EventHeader.\n     *\n     * @return the string object identifing the eventType of EventHeader.\n     */\n    public String getEventType() {\n        return eventType;\n    }\n\n    /**\n     * Sets the id to the newly supplied <var>eventId</var> string.\n     *\n     * @param eventId - the new string defining the eventId of this EventHeader\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the eventId value.\n     */\n    public void setEventId(String eventId) throws ParseException {\n        if (eventId == null)\n            throw new NullPointerException(\" the eventId parameter is null\");\n        setParameter(ParameterNames.ID, eventId);\n    }\n\n    /**\n     * Gets the id of the EventHeader. This method may return null if the\n     * \"eventId\" is not set.\n     * @return the string object identifing the eventId of EventHeader.\n     */\n    public String getEventId() {\n        return getParameter(ParameterNames.ID);\n    }\n\n    /**\n     * Encode in canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (eventType != null)\n            buffer.append(eventType);\n\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            this.parameters.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /**\n     *  Return true if the given event header matches the supplied one.\n     *\n     * @param matchTarget -- event header to match against.\n     */\n    public boolean match(Event matchTarget) {\n        if (matchTarget.eventType == null && this.eventType != null)\n            return false;\n        else if (matchTarget.eventType != null && this.eventType == null)\n            return false;\n        else if (this.eventType == null && matchTarget.eventType == null)\n            return false;\n        else if (getEventId() == null && matchTarget.getEventId() != null)\n            return false;\n        else if (getEventId() != null && matchTarget.getEventId() == null)\n            return false;\n        return matchTarget.eventType.equalsIgnoreCase(this.eventType)\n            && ((this.getEventId() == matchTarget.getEventId())\n                || this.getEventId().equalsIgnoreCase(matchTarget.getEventId()));\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Expires.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.*;\n\n/**\n * Expires SIP Header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:30 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class Expires\n    extends SIPHeader\n    implements javax2.sip.header.ExpiresHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 3134344915465784267L;\n\n    /** expires field\n     */\n    protected int expires;\n\n    /** default constructor\n     */\n    public Expires() {\n        super(NAME);\n    }\n\n    /**\n     * Return canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        return buffer.append(expires);\n    }\n\n    /**\n     * Gets the expires value of the ExpiresHeader. This expires value is\n     *\n     * relative time.\n     *\n     *\n     *\n     * @return the expires value of the ExpiresHeader.\n     *\n     *\n     */\n    public int getExpires() {\n        return expires;\n    }\n\n    /**\n     * Sets the relative expires value of the ExpiresHeader.\n     * The expires value MUST be greater than zero and MUST be\n     * less than 2**31.\n     *\n     * @param expires - the new expires value of this ExpiresHeader\n     *\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     *\n     *\n     */\n    public void setExpires(int expires) throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad argument \" + expires);\n        this.expires = expires;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ExtensionHeaderImpl.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n/**\n * A generic extension header for the stack.\n * The input text of the header gets recorded here.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:30 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ExtensionHeaderImpl\n    extends SIPHeader\n    implements javax2.sip.header.ExtensionHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -8693922839612081849L;\n\n    protected String value;\n\n    /**\n     * This was added to allow for automatic cloning of headers.\n     */\n    public ExtensionHeaderImpl() {\n    }\n\n    public ExtensionHeaderImpl(String headerName) {\n        super(headerName);\n    }\n\n    /**\n     * Set the name of the header.\n     * @param headerName is the name of the header to set.\n     */\n\n    public void setName(String headerName) {\n        this.headerName = headerName;\n    }\n\n    /**\n     * Set the value of the header.\n     */\n    public void setValue(String value) {\n        this.value = value;\n    }\n\n    /**\n     * Get the value of the extension header.\n     * @return the value of the extension header.\n     */\n    public String getHeaderValue() {\n        if (this.value != null) {\n            return this.value;\n        } else {\n            String encodedHdr = null;\n            try {\n                // Bug fix submitted by Lamine Brahimi\n                encodedHdr = this.encode();\n            } catch (Exception ex) {\n                return null;\n            }\n            StringBuffer buffer = new StringBuffer(encodedHdr);\n            while (buffer.length() > 0 && buffer.charAt(0) != ':') {\n                buffer.deleteCharAt(0);\n            }\n            buffer.deleteCharAt(0);\n            this.value = buffer.toString().trim();\n            return this.value;\n        }\n    }\n\n    /**\n     * Return the canonical encoding of this header.\n     */\n    public String encode() {\n        return new StringBuffer(this.headerName)\n            .append(COLON)\n            .append(SP)\n            .append(this.value)\n            .append(NEWLINE)\n            .toString();\n    }\n\n    /**\n     * Return just the body of this header encoded (leaving out the\n     * name and the CRLF at the end).\n     */\n    public String encodeBody() {\n        return this.getHeaderValue();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ExtensionHeaderList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.ListIterator;\n\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Header;\n\n/**\n * A generic extension header list.\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:30 $\n * @since 1.1\n */\npublic class ExtensionHeaderList extends SIPHeaderList<ExtensionHeaderImpl> {\n\n\n\n    private static final long serialVersionUID = 4681326807149890197L;\n\n\n    public Object clone() {\n        ExtensionHeaderList retval = new ExtensionHeaderList(headerName);\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    public ExtensionHeaderList(String hName) {\n        super( ExtensionHeaderImpl.class, hName);\n    }\n\n    public ExtensionHeaderList() {\n        super(ExtensionHeaderImpl.class,null);\n    }\n\n\n    public String encode() {\n        StringBuffer retval = new StringBuffer();\n        ListIterator<ExtensionHeaderImpl> it = this.listIterator();\n        while(it.hasNext()) {\n           ExtensionHeaderImpl eh = (ExtensionHeaderImpl) it.next();\n           retval.append(eh.encode());\n        }\n        return retval.toString();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/From.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.HostPort;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.parser.Parser;\n\nimport javax2.sip.header.FromHeader;\n\nimport java.text.ParseException;\n\n/**\n * From SIP Header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:31 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic final class From\n    extends AddressParametersHeader\n    implements javax2.sip.header.FromHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6312727234330643892L;\n\n    /** Default constructor\n     */\n    public From() {\n        super(NAME);\n    }\n\n    /** Generate a FROM header from a TO header\n     */\n    public From(To to) {\n        super(NAME);\n        address = to.address;\n        parameters = to.parameters;\n    }\n\n    /**\n     * Encode the header content into a String.\n     *\n     * @return String\n     */\n    protected String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            buffer.append(LESS_THAN);\n        }\n        address.encode(buffer);\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            buffer.append(GREATER_THAN);\n        }\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n        return buffer;\n    }\n\n    /**\n     * Conveniance accessor function to get the hostPort field from the address.\n     * Warning -- this assumes that the embedded URI is a SipURL.\n     *\n     * @return hostport field\n     */\n    public HostPort getHostPort() {\n        return address.getHostPort();\n    }\n\n    /**\n     * Get the display name from the address.\n     * @return Display name\n     */\n    public String getDisplayName() {\n        return address.getDisplayName();\n    }\n\n    /**\n     * Get the tag parameter from the address parm list.\n     * @return tag field\n     */\n    public String getTag() {\n        if (parameters == null)\n            return null;\n        return getParameter(ParameterNames.TAG);\n    }\n\n    /** Boolean function\n     * @return true if the Tag exist\n     */\n    public boolean hasTag() {\n        return hasParameter(ParameterNames.TAG);\n    }\n\n    /** remove Tag member\n     */\n    public void removeTag() {\n        parameters.delete(ParameterNames.TAG);\n    }\n\n    /**\n     * Set the address member\n     * @param address Address to set\n     */\n    public void setAddress(javax2.sip.address.Address address) {\n        this.address = (AddressImpl) address;\n    }\n\n    /**\n     * Set the tag member\n     * @param t tag to set. From tags are mandatory.\n     */\n    public void setTag(String t) throws ParseException {\n        // JvB: check that it is a valid token\n        Parser.checkToken(t);\n        this.setParameter(ParameterNames.TAG, t);\n    }\n\n    /** Get the user@host port string.\n     */\n    public String getUserAtHostPort() {\n        return address.getUserAtHostPort();\n    }\n\n    public boolean equals(Object other) {\n        return (other instanceof FromHeader) && super.equals(other);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/HeaderExt.java",
    "content": "/*\n * JBoss, Home of Professional Open Source\n * This code has been contributed to the public domain by the author.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.Header;\n\n/**\n * Extensions to the Header interface supported by the implementation and \n * will be included in the next spec release.\n * \n * @author jean.deruelle@gmail.com\n *\n */\npublic interface HeaderExt extends  Header {\n\n    /**\n     * Gets the header value (i.e. what follows the name:) as a string\n     * @return the header value (i.e. what follows the name:)\n     * @since 2.0\n     */\n    public String getValue();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/HeaderFactoryExt.java",
    "content": "package gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.extensions.JoinHeader;\nimport gov2.nist.javax2.sip.header.extensions.ReferredByHeader;\nimport gov2.nist.javax2.sip.header.extensions.ReplacesHeader;\nimport gov2.nist.javax2.sip.header.extensions.SessionExpiresHeader;\nimport gov2.nist.javax2.sip.header.ims.PAccessNetworkInfoHeader;\nimport gov2.nist.javax2.sip.header.ims.PAssertedIdentityHeader;\nimport gov2.nist.javax2.sip.header.ims.PAssertedServiceHeader;\nimport gov2.nist.javax2.sip.header.ims.PAssociatedURIHeader;\nimport gov2.nist.javax2.sip.header.ims.PCalledPartyIDHeader;\nimport gov2.nist.javax2.sip.header.ims.PChargingFunctionAddressesHeader;\nimport gov2.nist.javax2.sip.header.ims.PChargingVectorHeader;\nimport gov2.nist.javax2.sip.header.ims.PMediaAuthorizationHeader;\nimport gov2.nist.javax2.sip.header.ims.PPreferredIdentityHeader;\nimport gov2.nist.javax2.sip.header.ims.PPreferredServiceHeader;\nimport gov2.nist.javax2.sip.header.ims.PProfileKeyHeader;\nimport gov2.nist.javax2.sip.header.ims.PServedUserHeader;\nimport gov2.nist.javax2.sip.header.ims.PUserDatabaseHeader;\nimport gov2.nist.javax2.sip.header.ims.PVisitedNetworkIDHeader;\nimport gov2.nist.javax2.sip.header.ims.PathHeader;\nimport gov2.nist.javax2.sip.header.ims.PrivacyHeader;\nimport gov2.nist.javax2.sip.header.ims.SecurityClientHeader;\nimport gov2.nist.javax2.sip.header.ims.SecurityServerHeader;\nimport gov2.nist.javax2.sip.header.ims.SecurityVerifyHeader;\nimport gov2.nist.javax2.sip.header.ims.ServiceRouteHeader;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.address.Address;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderFactory;\n\n/**\n * Header factory extensions. These will be included in the next release of\n * JAIN-SIP.\n * \n * @since 2.0\n *\n */\npublic interface HeaderFactoryExt extends HeaderFactory {\n    \n    /**\n     * Create a RequestLine from a String\n     * @throws ParseException \n     */\n    public SipRequestLine createRequestLine(String requestLine) throws ParseException;\n    \n    \n    /**\n     * Create a StatusLine from a String.\n     */\n    public SipStatusLine createStatusLine(String statusLine) throws ParseException;\n    \n    \n    /**\n     * Create a ReferredBy Header.\n     *\n     * @param address --\n     *            address for the header.\n     *\n     */\n    public ReferredByHeader createReferredByHeader(Address address);\n\n    /**\n     *\n     * Create a Replaces header with a call Id, to and from tag.\n     *\n     * @param callId -\n     *            the call id to use.\n     * @param toTag -\n     *            the to tag to use.\n     * @param fromTag -\n     *            the fromTag to use.\n     *\n     */\n    public ReplacesHeader createReplacesHeader(String callId, String toTag,\n            String fromTag) throws ParseException;\n\n    /**\n     * creates a P-Access-Network-Info header.\n     *\n     * @return newly created P-Access-Network-Info header\n     */\n    public PAccessNetworkInfoHeader createPAccessNetworkInfoHeader();\n\n    /**\n     * P-Asserted-Identity header\n     *\n     * @param address -\n     *            Address\n     * @return newly created P-Asserted-Identity header\n     * @throws ParseException\n     * @throws NullPointerException\n     */\n    public PAssertedIdentityHeader createPAssertedIdentityHeader(Address address)\n            throws NullPointerException, ParseException;\n\n    /**\n     * Creates a new P-Associated-URI header based on the supplied address\n     *\n     * @param assocURI -\n     *            Address\n     * @return newly created P-Associated-URI header\n     * @throws NullPointerException\n     *             if the supplied address is null\n     * @throws ParseException\n     */\n    public PAssociatedURIHeader createPAssociatedURIHeader(Address assocURI);\n\n    /**\n     * P-Called-Party-ID header\n     *\n     * @param address -\n     *            Address\n     * @return newly created P-Called-Party-ID header\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public PCalledPartyIDHeader createPCalledPartyIDHeader(Address address);\n\n    /**\n     * P-Charging-Function-Addresses header\n     *\n     * @return newly created P-Charging-Function-Addresses header\n     */\n    public PChargingFunctionAddressesHeader createPChargingFunctionAddressesHeader();\n\n    /**\n     * P-Charging-Vector header\n     *\n     * @param icid -\n     *            icid string\n     * @return newly created P-Charging-Vector header\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public PChargingVectorHeader createChargingVectorHeader(String icid) throws ParseException;\n\n     /**\n     * P-Media-Authorization header\n     * @param token - token string\n     * @return newly created P-Media-Authorizarion header\n     * @throws InvalidArgumentException\n     * @throws ParseException\n     */\n    public PMediaAuthorizationHeader createPMediaAuthorizationHeader(String token)\n        throws InvalidArgumentException, ParseException;\n\n    /**\n     * P-Preferred-Identity header\n     * @param address - Address\n     * @return newly created P-Preferred-Identity header\n     * @throws NullPointerException\n     */\n    public PPreferredIdentityHeader createPPreferredIdentityHeader(Address address);\n\n    /**\n     * P-Visited-Network-ID header\n     * @return newly created P-Visited-Network-ID header\n     */\n    public PVisitedNetworkIDHeader createPVisitedNetworkIDHeader();\n\n    /**\n     * PATH header\n     * @param address - Address\n     * @return newly created Path header\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public PathHeader createPathHeader(Address address);\n\n    /**\n     * Privacy header\n     * @param privacyType - privacy type string\n     * @return newly created Privacy header\n     * @throws NullPointerException\n     */\n    public PrivacyHeader createPrivacyHeader(String privacyType);\n\n\n    /**\n     * Service-Route header\n     * @param address - Address\n     * @return newly created Service-Route header\n     * @throws NullPointerException\n     */\n    public ServiceRouteHeader createServiceRouteHeader(Address address);\n\n    /**\n     * Security-Server header\n     * @return newly created Security-Server header\n     */\n    public SecurityServerHeader createSecurityServerHeader();\n\n    /**\n     * Security-Client header\n     * @return newly created Security-Client header\n     */\n    public SecurityClientHeader createSecurityClientHeader();\n\n\n    /**\n     * Security-Verify header\n     * @return newly created Security-Verify header\n     */\n    public SecurityVerifyHeader createSecurityVerifyHeader();\n\n\n    /**\n     * Creates a new SessionExpiresHeader based on the newly supplied expires value.\n     *\n     * @param expires - the new integer value of the expires.\n     * @throws InvalidArgumentException if supplied expires is less\n     * than zero.\n     * @return the newly created SessionExpiresHeader object.\n     *\n     */\n    public SessionExpiresHeader createSessionExpiresHeader(int expires) throws InvalidArgumentException ;\n\n    /**\n     *\n     * Create a Join header with a call Id, to and from tag.\n     *\n     * @param callId -\n     *            the call id to use.\n     * @param toTag -\n     *            the to tag to use.\n     * @param fromTag -\n     *            the fromTag to use.\n     *\n     */\n    public JoinHeader createJoinHeader(String callId, String toTag,\n            String fromTag) throws ParseException;\n\n    /**\n     *\n     * @return the newly created P-User-Database header\n     * @param the database name, that may be an IP:port or a domain name.\n     */\n    public PUserDatabaseHeader createPUserDatabaseHeader(String databaseName);\n\n\n    /**\n     *\n     * @param address\n     * @return The newly created P-Profile-Key header\n     */\n    public PProfileKeyHeader createPProfileKeyHeader(Address address);\n\n    /**\n     * @param address of the served user.\n     * @return The newly created P-Served-User Header.\n     */\n    public PServedUserHeader createPServedUserHeader(Address address);\n\n    /**\n     *\n     * @return The newly created P-Preferred-Service Header.\n     */\n    public PPreferredServiceHeader createPPreferredServiceHeader();\n\n    /**\n     *\n     * @return The newly created P-Asserted-Service Header.\n     */\n    public PAssertedServiceHeader createPAssertedServiceHeader();\n    \n    /**\n     * Create a header from a string. The string is assumed to be in the \n     * name:value format. The trailing CRLF (if any ) will be stripped\n     * before parsing this. The header should be a singleton.\n     */\n    public Header createHeader(String header) throws ParseException;\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/HeaderFactoryImpl.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.address.*;\nimport javax2.sip.header.*;\n\nimport java.util.*;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.header.ims.*;\nimport gov2.nist.javax2.sip.parser.*;\nimport gov2.nist.javax2.sip.parser.extensions.ReferencesParser;\n\n/*\n* This file contains enhancements contributed by Alexandre Silva Santos\n* (PT-Inovacao) and Miguel Freitas\n*/\n\n/** Implementation of the JAIN SIP  HeaderFactory\n*\n* @version 1.2 $Revision: 1.22 $ $Date: 2010/01/12 18:58:48 $\n* @since 1.1\n*\n*@author M. Ranganathan   <br/>\n*@author Olivier Deruelle <br/>\n*\n*\n*/\npublic class HeaderFactoryImpl implements HeaderFactory , HeaderFactoryExt {\n\n    /**\n     * Determines whether or not we should tolerate and strip address scope\n     * zones from IPv6 addresses. Address scope zones are sometimes returned\n     * at the end of IPv6 addresses generated by InetAddress.getHostAddress().\n     * They are however not part of the SIP semantics so basically this method\n     * determines whether or not the parser should be stripping them (as\n     * opposed simply being blunt and throwing an exception).\n     */\n    private boolean stripAddressScopeZones = false;\n\n    /**\n     * Set pretty encoding on / off.\n     * This splits up via headers into multiple lines for readability ( better for\n     * debugging ).\n     *\n     */\n    public void setPrettyEncoding(boolean flag) {\n        SIPHeaderList.setPrettyEncode(flag);\n    }\n\n    /**\n    * Creates a new AcceptEncodingHeader based on the newly supplied encoding\n    * value.\n    *\n    * @param encoding - the new string containing the encoding value.\n    * @throws ParseException which signals that an error has been reached\n    * unexpectedly while parsing the encoding value.\n    * @return the newly created AcceptEncodingHeader object.\n    */\n    public AcceptEncodingHeader createAcceptEncodingHeader(String encoding)\n        throws ParseException {\n        if (encoding == null)\n            throw new NullPointerException(\"the encoding parameter is null\");\n        AcceptEncoding acceptEncoding = new AcceptEncoding();\n        acceptEncoding.setEncoding(encoding);\n        return acceptEncoding;\n    }\n\n    /**\n     * Creates a new AcceptHeader based on the newly supplied contentType and\n     * contentSubType values.\n     *\n     * @param contentType The new string content type value.\n     * @param contentSubType The new string content sub-type value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the content type or content subtype value.\n     * @return the newly created AcceptHeader object.\n     */\n    public AcceptHeader createAcceptHeader(\n        String contentType,\n        String contentSubType)\n        throws ParseException {\n        if (contentType == null || contentSubType == null)\n            throw new NullPointerException(\"contentType or subtype is null \");\n        Accept accept = new Accept();\n        accept.setContentType(contentType);\n        accept.setContentSubType(contentSubType);\n\n        return accept;\n    }\n\n    /**\n     * Creates a new AcceptLanguageHeader based on the newly supplied\n     * language value.\n     *\n     * @param language - the new Locale value of the language\n     * @return the newly created AcceptLanguageHeader object.\n     */\n    public AcceptLanguageHeader createAcceptLanguageHeader(Locale language) {\n        if (language == null)\n            throw new NullPointerException(\"null arg\");\n        AcceptLanguage acceptLanguage = new AcceptLanguage();\n        acceptLanguage.setAcceptLanguage(language);\n\n        return acceptLanguage;\n    }\n\n    /**\n     * Creates a new AlertInfoHeader based on the newly supplied alertInfo value.\n     *\n     * @param alertInfo - the new URI value of the alertInfo\n     * @return the newly created AlertInfoHeader object.\n     * @since v1.1\n     */\n    public AlertInfoHeader createAlertInfoHeader(URI alertInfo) {\n        if (alertInfo == null)\n            throw new NullPointerException(\"null arg alertInfo\");\n        AlertInfo a = new AlertInfo();\n        a.setAlertInfo(alertInfo);\n        return a;\n    }\n\n    /**\n     * Creates a new AllowEventsHeader based on the newly supplied event type\n     * value.\n     *\n     * @param eventType - the new string containing the eventType value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the eventType value.\n     * @return the newly created AllowEventsHeader object.\n     * @since v1.1\n     */\n    public AllowEventsHeader createAllowEventsHeader(String eventType)\n        throws ParseException {\n        if (eventType == null)\n            throw new NullPointerException(\"null arg eventType\");\n        AllowEvents allowEvents = new AllowEvents();\n        allowEvents.setEventType(eventType);\n        return allowEvents;\n    }\n\n    /**\n     * Creates a new AllowHeader based on the newly supplied method value.\n     *\n     * @param method - the new string containing the method value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the method value.\n     * @return the newly created AllowHeader object.\n     */\n    public AllowHeader createAllowHeader(String method) throws ParseException {\n        if (method == null)\n            throw new NullPointerException(\"null arg method\");\n        Allow allow = new Allow();\n        allow.setMethod(method);\n\n        return allow;\n    }\n\n    /**\n     * Creates a new AuthenticationInfoHeader based on the newly supplied\n     * response value.\n     *\n     * @param response - the new string value of the response.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the response value.\n     * @return the newly created AuthenticationInfoHeader object.\n     * @since v1.1\n     */\n    public AuthenticationInfoHeader createAuthenticationInfoHeader(String response)\n        throws ParseException {\n        if (response == null)\n            throw new NullPointerException(\"null arg response\");\n        AuthenticationInfo auth = new AuthenticationInfo();\n        auth.setResponse(response);\n\n        return auth;\n    }\n\n    /**\n     * Creates a new AuthorizationHeader based on the newly supplied\n     * scheme value.\n     *\n     * @param scheme - the new string value of the scheme.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the scheme value.\n     * @return the newly created AuthorizationHeader object.\n     */\n    public AuthorizationHeader createAuthorizationHeader(String scheme)\n        throws ParseException {\n        if (scheme == null)\n            throw new NullPointerException(\"null arg scheme \");\n        Authorization auth = new Authorization();\n        auth.setScheme(scheme);\n\n        return auth;\n    }\n\n    /**\n     * Creates a new CSeqHeader based on the newly supplied sequence number and\n     * method values.\n     *\n     * @param sequenceNumber - the new integer value of the sequence number.\n     * @param method - the new string value of the method.\n     * @throws InvalidArgumentException if supplied sequence number is less\n     * than zero.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the method value.\n     * @return the newly created CSeqHeader object.\n     */\n    public CSeqHeader createCSeqHeader( long sequenceNumber, String method)\n        throws ParseException, InvalidArgumentException {\n        if (sequenceNumber < 0)\n            throw new InvalidArgumentException(\"bad arg \" + sequenceNumber);\n        if (method == null)\n            throw new NullPointerException(\"null arg method\");\n        CSeq cseq = new CSeq();\n        cseq.setMethod(method);\n        cseq.setSeqNumber(sequenceNumber);\n\n        return cseq;\n    }\n\n    /**\n     * For backwards compatibility, also accept int\n     * @deprecated\n     */\n    public CSeqHeader createCSeqHeader( int sequenceNumber, String method)\n        throws ParseException, InvalidArgumentException {\n        return this.createCSeqHeader( (long) sequenceNumber, method );\n    }\n\n    /**\n     * Creates a new CallIdHeader based on the newly supplied callId value.\n     *\n     * @param callId - the new string value of the call-id.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the callId value.\n     * @return the newly created CallIdHeader object.\n     */\n    public CallIdHeader createCallIdHeader(String callId)\n        throws ParseException {\n        if (callId == null)\n            throw new NullPointerException(\"null arg callId\");\n        CallID c = new CallID();\n        c.setCallId(callId);\n        return c;\n    }\n\n    /**\n     * Creates a new CallInfoHeader based on the newly supplied callInfo value.\n     *\n     * @param callInfo The new string value of the callInfo.\n     * @return the newly created CallInfoHeader object.\n     */\n    public CallInfoHeader createCallInfoHeader(URI callInfo) {\n        if (callInfo == null)\n            throw new NullPointerException(\"null arg callInfo\");\n\n        CallInfo c = new CallInfo();\n        c.setInfo(callInfo);\n        return c;\n    }\n\n    /**\n     * Creates a new ContactHeader based on the newly supplied address value.\n     *\n     * @param address - the new Address value of the address.\n     * @return the newly created ContactHeader object.\n     */\n    public ContactHeader createContactHeader(Address address) {\n        if (address == null)\n            throw new NullPointerException(\"null arg address\");\n        Contact contact = new Contact();\n        contact.setAddress(address);\n\n        return contact;\n    }\n\n    /**\n    * Creates a new wildcard ContactHeader. This is used in Register requests\n    * to indicate to the server that it should remove all locations the\n    * at which the user is currently available. This implies that the\n    * following conditions are met:\n    * <ul>\n    * <li><code>ContactHeader.getAddress.getAddress.getUserInfo() == *;</code>\n    * <li><code>ContactHeader.getAddress.getAddress.isWildCard() == true;</code>\n    * <li><code>ContactHeader.getExpires() == 0;</code>\n    * </ul>\n    *\n    * @return the newly created wildcard ContactHeader.\n    */\n    public ContactHeader createContactHeader() {\n        Contact contact = new Contact();\n        contact.setWildCardFlag(true);\n        contact.setExpires(0);\n\n        return contact;\n    }\n\n    /**\n     * Creates a new ContentDispositionHeader based on the newly supplied\n     * contentDisposition value.\n     *\n     * @param contentDisposition - the new string value of the contentDisposition.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the contentDisposition value.\n     * @return the newly created ContentDispositionHeader object.\n     * @since v1.1\n     */\n    public ContentDispositionHeader createContentDispositionHeader(String contentDisposition)\n        throws ParseException {\n        if (contentDisposition == null)\n            throw new NullPointerException(\"null arg contentDisposition\");\n        ContentDisposition c = new ContentDisposition();\n        c.setDispositionType(contentDisposition);\n\n        return c;\n    }\n\n    /**\n    * Creates a new ContentEncodingHeader based on the newly supplied encoding\n    * value.\n    *\n    * @param encoding - the new string containing the encoding value.\n    * @throws ParseException which signals that an error has been reached\n    * unexpectedly while parsing the encoding value.\n    * @return the newly created ContentEncodingHeader object.\n    */\n    public ContentEncodingHeader createContentEncodingHeader(String encoding)\n        throws ParseException {\n        if (encoding == null)\n            throw new NullPointerException(\"null encoding\");\n        ContentEncoding c = new ContentEncoding();\n        c.setEncoding(encoding);\n\n        return c;\n    }\n\n    /**\n     * Creates a new ContentLanguageHeader based on the newly supplied\n     * contentLanguage value.\n     *\n     * @param contentLanguage - the new Locale value of the contentLanguage.\n     * @return the newly created ContentLanguageHeader object.\n     * @since v1.1\n     */\n    public ContentLanguageHeader createContentLanguageHeader(Locale contentLanguage) {\n        if (contentLanguage == null)\n            throw new NullPointerException(\"null arg contentLanguage\");\n        ContentLanguage c = new ContentLanguage();\n        c.setContentLanguage(contentLanguage);\n\n        return c;\n    }\n\n    /**\n     * Creates a new CSeqHeader based on the newly supplied contentLength value.\n     *\n     * @param contentLength - the new integer value of the contentLength.\n     * @throws InvalidArgumentException if supplied contentLength is less\n     * than zero.\n     * @return the newly created ContentLengthHeader object.\n     */\n    public ContentLengthHeader createContentLengthHeader(int contentLength)\n        throws InvalidArgumentException {\n        if (contentLength < 0)\n            throw new InvalidArgumentException(\"bad contentLength\");\n        ContentLength c = new ContentLength();\n        c.setContentLength(contentLength);\n\n        return c;\n    }\n\n    /**\n     * Creates a new ContentTypeHeader based on the newly supplied contentType and\n     * contentSubType values.\n     *\n     * @param contentType - the new string content type value.\n     * @param contentSubType - the new string content sub-type value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the content type or content subtype value.\n     * @return the newly created ContentTypeHeader object.\n     */\n    public ContentTypeHeader createContentTypeHeader(\n        String contentType,\n        String contentSubType)\n        throws ParseException {\n        if (contentType == null || contentSubType == null)\n            throw new NullPointerException(\"null contentType or subType\");\n        ContentType c = new ContentType();\n        c.setContentType(contentType);\n        c.setContentSubType(contentSubType);\n        return c;\n    }\n\n    /**\n    * Creates a new DateHeader based on the newly supplied date value.\n    *\n    * @param date - the new Calender value of the date.\n    * @return the newly created DateHeader object.\n    */\n    public DateHeader createDateHeader(Calendar date) {\n        SIPDateHeader d = new SIPDateHeader();\n        if (date == null)\n            throw new NullPointerException(\"null date\");\n        d.setDate(date);\n\n        return d;\n    }\n\n    /**\n     * Creates a new EventHeader based on the newly supplied eventType value.\n     *\n     * @param eventType - the new string value of the eventType.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the eventType value.\n     * @return the newly created EventHeader object.\n     * @since v1.1\n     */\n    public EventHeader createEventHeader(String eventType)\n        throws ParseException {\n        if (eventType == null)\n            throw new NullPointerException(\"null eventType\");\n        Event event = new Event();\n        event.setEventType(eventType);\n\n        return event;\n    }\n\n    /**\n     * Creates a new ExpiresHeader based on the newly supplied expires value.\n     *\n     * @param expires - the new integer value of the expires.\n     * @throws InvalidArgumentException if supplied expires is less\n     * than zero.\n     * @return the newly created ExpiresHeader object.\n     */\n    public ExpiresHeader createExpiresHeader(int expires)\n        throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad value \" + expires);\n        Expires e = new Expires();\n        e.setExpires(expires);\n\n        return e;\n    }\n\n    /**\n     * Creates a new ExtensionHeader based on the newly supplied name and\n     * value values.\n     *\n     * @param name - the new string name of the ExtensionHeader value.\n     * @param value - the new string value of the ExtensionHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the name or value values.\n     * @return the newly created ExtensionHeader object.\n     */\n    public javax2.sip.header.ExtensionHeader createExtensionHeader(\n        String name,\n        String value)\n        throws ParseException {\n        if (name == null)\n            throw new NullPointerException(\"bad name\");\n\n        gov2.nist.javax2.sip.header.ExtensionHeaderImpl ext =\n            new gov2.nist.javax2.sip.header.ExtensionHeaderImpl();\n        ext.setName(name);\n        ext.setValue(value);\n\n        return ext;\n    }\n\n    /**\n     * Creates a new FromHeader based on the newly supplied address and\n     * tag values.\n     *\n     * @param address - the new Address object of the address.\n     * @param tag - the new string value of the tag.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the tag value.\n     * @return the newly created FromHeader object.\n     */\n    public FromHeader createFromHeader(Address address, String tag)\n        throws ParseException {\n        if (address == null)\n            throw new NullPointerException(\"null address arg\");\n        From from = new From();\n        from.setAddress(address);\n        if (tag != null)\n            from.setTag(tag);\n\n        return from;\n    }\n\n    /**\n     * Creates a new InReplyToHeader based on the newly supplied callId\n     * value.\n     *\n     * @param callId - the new string containing the callId value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the callId value.\n     * @return the newly created InReplyToHeader object.\n     * @since v1.1\n     */\n    public InReplyToHeader createInReplyToHeader(String callId)\n        throws ParseException {\n        if (callId == null)\n            throw new NullPointerException(\"null callId arg\");\n        InReplyTo inReplyTo = new InReplyTo();\n        inReplyTo.setCallId(callId);\n\n        return inReplyTo;\n    }\n    /**\n    * Creates a new MaxForwardsHeader based on the newly\n    * supplied maxForwards value.\n    *\n    * @param maxForwards The new integer value of the maxForwards.\n    * @throws InvalidArgumentException if supplied maxForwards is less\n    * than zero or greater than 255.\n    * @return the newly created MaxForwardsHeader object.\n    */\n    public MaxForwardsHeader createMaxForwardsHeader(int maxForwards)\n        throws InvalidArgumentException {\n        if (maxForwards < 0 || maxForwards > 255)\n            throw new InvalidArgumentException(\n                \"bad maxForwards arg \" + maxForwards);\n        MaxForwards m = new MaxForwards();\n        m.setMaxForwards(maxForwards);\n\n        return m;\n    }\n\n    /**\n     * Creates a new MimeVersionHeader based on the newly\n     * supplied mimeVersion value.\n     *\n     * @param majorVersion - the new integer value of the majorVersion.\n     * @param minorVersion - the new integer value of the minorVersion.\n     * @throws InvalidArgumentException if supplied mimeVersion is less\n     * than zero.\n     * @return the newly created MimeVersionHeader object.\n     * @since v1.1\n     */\n    public MimeVersionHeader createMimeVersionHeader(\n        int majorVersion,\n        int minorVersion)\n        throws InvalidArgumentException {\n        if (majorVersion < 0 || minorVersion < 0)\n            throw new javax2.sip.InvalidArgumentException(\n                \"bad major/minor version\");\n        MimeVersion m = new MimeVersion();\n        m.setMajorVersion(majorVersion);\n        m.setMinorVersion(minorVersion);\n\n        return m;\n    }\n\n    /**\n     * Creates a new MinExpiresHeader based on the newly supplied minExpires value.\n     *\n     * @param minExpires - the new integer value of the minExpires.\n     * @throws InvalidArgumentException if supplied minExpires is less\n     * than zero.\n     * @return the newly created MinExpiresHeader object.\n     * @since v1.1\n     */\n    public MinExpiresHeader createMinExpiresHeader(int minExpires)\n        throws InvalidArgumentException {\n        if (minExpires < 0)\n            throw new InvalidArgumentException(\"bad minExpires \" + minExpires);\n        MinExpires min = new MinExpires();\n        min.setExpires(minExpires);\n\n        return min;\n    }\n\n    /**\n     * Creates a new MinSEHeader based on the newly supplied expires value.\n     *\n     * @param expires - the new integer value of the expires.\n     * @throws InvalidArgumentException if supplied expires is less\n     * than zero.\n     * @return the newly created ExpiresHeader object.\n     *\n     * TODO: Once interfaces are in javax2, change the type to MinSEHeader\n     * and add to HeaderFactory. - pmusgrave\n     *\n     * pmusgrave\n     */\n    public ExtensionHeader createMinSEHeader(int expires)\n        throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad value \" + expires);\n        MinSE e = new MinSE();\n        e.setExpires(expires);\n\n        return e;\n    }\n\n    /**\n     * Creates a new OrganizationHeader based on the newly supplied\n     * organization value.\n     *\n     * @param organization - the new string value of the organization.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the organization value.\n     * @return the newly created OrganizationHeader object.\n     */\n    public OrganizationHeader createOrganizationHeader(String organization)\n        throws ParseException {\n        if (organization == null)\n            throw new NullPointerException(\"bad organization arg\");\n        Organization o = new Organization();\n        o.setOrganization(organization);\n\n        return o;\n    }\n\n    /**\n     * Creates a new PriorityHeader based on the newly supplied priority value.\n     *\n     * @param priority - the new string value of the priority.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the priority value.\n     * @return the newly created PriorityHeader object.\n     */\n    public PriorityHeader createPriorityHeader(String priority)\n        throws ParseException {\n        if (priority == null)\n            throw new NullPointerException(\"bad priority arg\");\n        Priority p = new Priority();\n        p.setPriority(priority);\n\n        return p;\n    }\n\n    /**\n     * Creates a new ProxyAuthenticateHeader based on the newly supplied\n     * scheme value.\n     *\n     * @param scheme - the new string value of the scheme.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the scheme value.\n     * @return the newly created ProxyAuthenticateHeader object.\n     */\n    public ProxyAuthenticateHeader createProxyAuthenticateHeader(String scheme)\n        throws ParseException {\n        if (scheme == null)\n            throw new NullPointerException(\"bad scheme arg\");\n        ProxyAuthenticate p = new ProxyAuthenticate();\n        p.setScheme(scheme);\n\n        return p;\n    }\n\n    /**\n     * Creates a new ProxyAuthorizationHeader based on the newly supplied\n     * scheme value.\n     *\n     * @param scheme - the new string value of the scheme.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the scheme value.\n     * @return the newly created ProxyAuthorizationHeader object.\n     */\n    public ProxyAuthorizationHeader createProxyAuthorizationHeader(String scheme)\n        throws ParseException {\n        if (scheme == null)\n            throw new NullPointerException(\"bad scheme arg\");\n        ProxyAuthorization p = new ProxyAuthorization();\n        p.setScheme(scheme);\n\n        return p;\n    }\n\n    /**\n     * Creates a new ProxyRequireHeader based on the newly supplied optionTag\n     * value.\n     *\n     * @param optionTag - the new string OptionTag value.\n     * @return the newly created ProxyRequireHeader object.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the optionTag value.\n     */\n    public ProxyRequireHeader createProxyRequireHeader(String optionTag)\n        throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(\"bad optionTag arg\");\n        ProxyRequire p = new ProxyRequire();\n        p.setOptionTag(optionTag);\n\n        return p;\n    }\n\n    /**\n     * Creates a new RAckHeader based on the newly supplied rSeqNumber,\n     * cSeqNumber and method values.\n     *\n     * @param rSeqNumber - the new integer value of the rSeqNumber.\n     * @param cSeqNumber - the new integer value of the cSeqNumber.\n     * @param method - the new string value of the method.\n     * @throws InvalidArgumentException if supplied rSeqNumber or cSeqNumber is\n     * less than zero or greater than than 2**31-1.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the method value.\n     * @return the newly created RAckHeader object.\n     * @since v1.1\n     */\n    public RAckHeader createRAckHeader(\n        long rSeqNumber,\n        long cSeqNumber,\n        String method)\n        throws InvalidArgumentException, ParseException {\n        if (method == null)\n            throw new NullPointerException(\"Bad method\");\n        if (cSeqNumber < 0 || rSeqNumber < 0)\n            throw new InvalidArgumentException(\"bad cseq/rseq arg\");\n        RAck rack = new RAck();\n        rack.setMethod(method);\n        rack.setCSequenceNumber(cSeqNumber);\n        rack.setRSequenceNumber(rSeqNumber);\n\n        return rack;\n    }\n\n    /**\n     * @deprecated\n     * @see javax2.sip.header.HeaderFactory#createRAckHeader(int, int, java.lang.String)\n     */\n    public RAckHeader createRAckHeader(int rSeqNumber, int cSeqNumber, String method) throws InvalidArgumentException, ParseException {\n\n        return createRAckHeader((long)rSeqNumber, (long)cSeqNumber, method);\n    }\n\n\n    /**\n     * @deprecated\n     * @see javax2.sip.header.HeaderFactory#createRSeqHeader(int)\n     */\n    public RSeqHeader createRSeqHeader(int sequenceNumber) throws InvalidArgumentException {\n\n        return createRSeqHeader((long) sequenceNumber) ;\n    }\n\n    /**\n     * Creates a new RSeqHeader based on the newly supplied sequenceNumber value.\n     *\n     * @param sequenceNumber - the new integer value of the sequenceNumber.\n     * @throws InvalidArgumentException if supplied sequenceNumber is\n     * less than zero or greater than than 2**31-1.\n     * @return the newly created RSeqHeader object.\n     * @since v1.1\n     */\n    public RSeqHeader createRSeqHeader(long sequenceNumber)\n        throws InvalidArgumentException {\n        if (sequenceNumber < 0)\n            throw new InvalidArgumentException(\n                \"invalid sequenceNumber arg \" + sequenceNumber);\n        RSeq rseq = new RSeq();\n        rseq.setSeqNumber(sequenceNumber);\n\n        return rseq;\n    }\n\n    /**\n     * Creates a new ReasonHeader based on the newly supplied reason value.\n     *\n     * @param protocol - the new string value of the protocol.\n     * @param cause - the new integer value of the cause.\n     * @param text - the new string value of the text.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the protocol, cause or text value.\n     * @return the newly created ReasonHeader object.\n     * @since v1.1\n     */\n    public ReasonHeader createReasonHeader(\n        String protocol,\n        int cause,\n        String text)\n        throws InvalidArgumentException, ParseException {\n        if (protocol == null)\n            throw new NullPointerException(\"bad protocol arg\");\n        if (cause < 0)\n            throw new InvalidArgumentException(\"bad cause\");\n        Reason reason = new Reason();\n        reason.setProtocol(protocol);\n        reason.setCause(cause);\n        reason.setText(text);\n\n        return reason;\n    }\n\n    /**\n    * Creates a new RecordRouteHeader based on the newly supplied address value.\n    *\n    * @param address - the new Address object of the address.\n    * @return the newly created RecordRouteHeader object.\n    */\n    public RecordRouteHeader createRecordRouteHeader(Address address) {\n        if ( address == null) throw new NullPointerException(\"Null argument!\");\n        RecordRoute recordRoute = new RecordRoute();\n        recordRoute.setAddress(address);\n\n        return recordRoute;\n    }\n\n    /**\n    * Creates a new ReplyToHeader based on the newly supplied address value.\n    *\n    * @param address - the new Address object of the address.\n    * @return the newly created ReplyToHeader object.\n    * @since v1.1\n    */\n    public ReplyToHeader createReplyToHeader(Address address) {\n        if (address == null)\n            throw new NullPointerException(\"null address\");\n        ReplyTo replyTo = new ReplyTo();\n        replyTo.setAddress(address);\n\n        return replyTo;\n    }\n\n    /**\n     * Creates a new RequireHeader based on the newly supplied optionTag\n     * value.\n     *\n     * @param optionTag - the new string value containing the optionTag value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the List of optionTag value.\n     * @return the newly created RequireHeader object.\n     */\n    public RequireHeader createRequireHeader(String optionTag)\n        throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(\"null optionTag\");\n        Require require = new Require();\n        require.setOptionTag(optionTag);\n\n        return require;\n    }\n\n    /**\n     * Creates a new RetryAfterHeader based on the newly supplied retryAfter\n     * value.\n     *\n     * @param retryAfter - the new integer value of the retryAfter.\n     * @throws InvalidArgumentException if supplied retryAfter is less\n     * than zero.\n     * @return the newly created RetryAfterHeader object.\n     */\n    public RetryAfterHeader createRetryAfterHeader(int retryAfter)\n        throws InvalidArgumentException {\n        if (retryAfter < 0)\n            throw new InvalidArgumentException(\"bad retryAfter arg\");\n        RetryAfter r = new RetryAfter();\n        r.setRetryAfter(retryAfter);\n\n        return r;\n    }\n\n    /**\n     * Creates a new RouteHeader based on the newly supplied address value.\n     *\n     * @param address - the new Address object of the address.\n     * @return the newly created RouteHeader object.\n     */\n    public RouteHeader createRouteHeader(Address address) {\n        if (address == null)\n            throw new NullPointerException(\"null address arg\");\n        Route route = new Route();\n        route.setAddress(address);\n\n        return route;\n    }\n\n    /**\n     * Creates a new ServerHeader based on the newly supplied product value.\n     *\n     * @param product - the new list value of the product.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the product value.\n     * @return the newly created ServerHeader object.\n     */\n    public ServerHeader createServerHeader(List product)\n        throws ParseException {\n        if (product == null)\n            throw new NullPointerException(\"null productList arg\");\n        Server server = new Server();\n        server.setProduct(product);\n\n        return server;\n    }\n\n    /**\n     * Creates a new SubjectHeader based on the newly supplied subject value.\n     *\n     * @param subject - the new string value of the subject.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the subject value.\n     * @return the newly created SubjectHeader object.\n     */\n    public SubjectHeader createSubjectHeader(String subject)\n        throws ParseException {\n        if (subject == null)\n            throw new NullPointerException(\"null subject arg\");\n        Subject s = new Subject();\n        s.setSubject(subject);\n\n        return s;\n    }\n\n    /**\n     * Creates a new SubscriptionStateHeader based on the newly supplied\n     * subscriptionState value.\n     *\n     * @param subscriptionState - the new string value of the subscriptionState.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the subscriptionState value.\n     * @return the newly created SubscriptionStateHeader object.\n     * @since v1.1\n     */\n    public SubscriptionStateHeader createSubscriptionStateHeader(String subscriptionState)\n        throws ParseException {\n        if (subscriptionState == null)\n            throw new NullPointerException(\"null subscriptionState arg\");\n        SubscriptionState s = new SubscriptionState();\n        s.setState(subscriptionState);\n\n        return s;\n    }\n\n    /**\n     * Creates a new SupportedHeader based on the newly supplied optionTag\n     * value.\n     *\n     * @param optionTag - the new string containing the optionTag value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the optionTag value.\n     * @return the newly created SupportedHeader object.\n     */\n    public SupportedHeader createSupportedHeader(String optionTag)\n        throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(\"null optionTag arg\");\n        Supported supported = new Supported();\n        supported.setOptionTag(optionTag);\n\n        return supported;\n    }\n\n    /**\n     * Creates a new TimeStampHeader based on the newly supplied timeStamp value.\n     *\n     * @param timeStamp - the new float value of the timeStamp.\n     * @throws InvalidArgumentException if supplied timeStamp is less\n     * than zero.\n     * @return the newly created TimeStampHeader object.\n     */\n    public TimeStampHeader createTimeStampHeader(float timeStamp)\n        throws InvalidArgumentException {\n        if (timeStamp < 0)\n            throw new IllegalArgumentException(\"illegal timeStamp\");\n        TimeStamp t = new TimeStamp();\n        t.setTimeStamp(timeStamp);\n\n        return t;\n    }\n\n    /**\n     * Creates a new ToHeader based on the newly supplied address and\n     * tag values.\n     *\n     * @param address - the new Address object of the address.\n     * @param tag - the new string value of the tag.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the tag value.\n     * @return the newly created ToHeader object.\n     */\n    public ToHeader createToHeader(Address address, String tag)\n        throws ParseException {\n        if (address == null)\n            throw new NullPointerException(\"null address\");\n        To to = new To();\n        to.setAddress(address);\n        if (tag != null)\n            to.setTag(tag);\n\n        return to;\n    }\n\n    /**\n     * Creates a new UnsupportedHeader based on the newly supplied optionTag\n     * value.\n     *\n     * @param optionTag - the new string containing the optionTag value.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the List of optionTag value.\n     * @return the newly created UnsupportedHeader object.\n     */\n    public UnsupportedHeader createUnsupportedHeader(String optionTag)\n        throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(optionTag);\n        Unsupported unsupported = new Unsupported();\n        unsupported.setOptionTag(optionTag);\n\n        return unsupported;\n    }\n\n    /**\n     * Creates a new UserAgentHeader based on the newly supplied product value.\n     *\n     * @param product - the new list value of the product.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the product value.\n     * @return the newly created UserAgentHeader object.\n     */\n    public UserAgentHeader createUserAgentHeader(List product)\n        throws ParseException {\n\n        if (product == null)\n            throw new NullPointerException(\"null user agent\");\n        UserAgent userAgent = new UserAgent();\n        userAgent.setProduct(product);\n\n        return userAgent;\n    }\n\n    /**\n     * Creates a new ViaHeader based on the newly supplied uri and branch values.\n     *\n     * @param host the new host value of uri.\n     * @param port the new port value of uri.\n     * @param transport the new transport value of uri.\n     * @param branch the new string value of the branch.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the branch value.\n     * @return the newly created ViaHeader object.\n     */\n    public ViaHeader createViaHeader(\n        String host,\n        int port,\n        String transport,\n        String branch)\n        throws ParseException, InvalidArgumentException {\n        // This should be changed.\n        if (host == null || transport == null)\n            throw new NullPointerException(\"null arg\");\n        Via via = new Via();\n        if (branch != null)\n            via.setBranch(branch);\n\n        // for supporting IPv6 addresses\n        if(host.indexOf(':') >= 0\n            && host.indexOf('[') < 0)\n        {\n            //strip address scope zones if any\n            if(stripAddressScopeZones)\n            {\n                int zoneStart = host.indexOf('%');\n                if(zoneStart != -1)\n                    host = host.substring(0, zoneStart);\n            }\n            host = '[' + host + ']';\n        }\n\n        via.setHost(host);\n        via.setPort(port);\n        via.setTransport(transport);\n\n        return via;\n    }\n\n    /**\n     * Creates a new WWWAuthenticateHeader based on the newly supplied\n     * scheme value.\n     *\n     * @param scheme - the new string value of the scheme.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the scheme values.\n     * @return the newly created WWWAuthenticateHeader object.\n     */\n    public WWWAuthenticateHeader createWWWAuthenticateHeader(String scheme)\n        throws ParseException {\n        if (scheme == null)\n            throw new NullPointerException(\"null scheme\");\n        WWWAuthenticate www = new WWWAuthenticate();\n        www.setScheme(scheme);\n\n        return www;\n    }\n\n    /**\n     * Creates a new WarningHeader based on the newly supplied\n     * agent, code and comment values.\n     *\n     * @param agent - the new string value of the agent.\n     * @param code - the new boolean integer of the code.\n     * @param comment - the new string value of the comment.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the agent or comment values.\n     * @throws InvalidArgumentException if an invalid integer code is given for\n     * the WarningHeader.\n     * @return the newly created WarningHeader object.\n     */\n    public WarningHeader createWarningHeader(\n        String agent,\n        int code,\n        String comment)\n        throws ParseException, InvalidArgumentException {\n        if (agent == null)\n            throw new NullPointerException(\"null arg\");\n        Warning warning = new Warning();\n        warning.setAgent(agent);\n        warning.setCode(code);\n        warning.setText(comment);\n\n        return warning;\n    }\n\n    /** Creates a new ErrorInfoHeader based on the newly\n     * supplied errorInfo value.\n     *\n     * @param errorInfo - the new URI value of the errorInfo.\n     * @return the newly created ErrorInfoHeader object.\n     */\n    public ErrorInfoHeader createErrorInfoHeader(URI errorInfo) {\n        if (errorInfo == null)\n            throw new NullPointerException(\"null arg\");\n        return new ErrorInfo((GenericURI) errorInfo);\n    }\n    \n    /**\n     * Create a header from the given header text.\n     * Header should not have the trailng crlf.\n     * @throws ParseException \n     */\n    public javax2.sip.header.Header createHeader(String headerText) throws ParseException {\n        StringMsgParser smp = new StringMsgParser();\n        SIPHeader sipHeader = smp.parseSIPHeader(headerText.trim());\n        if (sipHeader instanceof SIPHeaderList) {\n            if (((SIPHeaderList) sipHeader).size() > 1) {\n                throw new ParseException(\n                    \"Only singleton allowed \" + headerText,\n                    0);\n            } else if (((SIPHeaderList) sipHeader).size() == 0) {\n                try {\n                    return (Header) ((SIPHeaderList) sipHeader)\n                        .getMyClass()\n                        .newInstance();\n                } catch (InstantiationException ex) {\n                    ex.printStackTrace();\n                    return null;\n                } catch (IllegalAccessException ex) {\n                    ex.printStackTrace();\n                    return null;\n                }\n            } else {\n                return (Header) ((SIPHeaderList) sipHeader).getFirst();\n            }\n        } else {\n            return (Header) sipHeader;\n        }\n        \n    }\n\n    /** Create and parse a header.\n     *\n     * @param headerName -- header name for the header to parse.\n     * @param headerValue -- header value for the header to parse.\n     * @throws ParseException\n     * @return  the parsed sip header\n     */\n    public javax2.sip.header.Header createHeader(\n        String headerName,\n        String headerValue)\n        throws java.text.ParseException {\n        if (headerName == null)\n            throw new NullPointerException(\"header name is null\");\n        String hdrText =\n            new StringBuffer()\n                .append(headerName)\n                .append(\":\")\n                .append(headerValue)\n                .toString();\n        return createHeader(hdrText);\n        \n    }\n\n    /** Create and return a list of headers.\n     *@param headers -- list of headers.\n     *@throws ParseException -- if a parse exception occurs or a List\n     * of that type of header is not alowed.\n     *@return a List containing the headers.\n     */\n    public java.util.List createHeaders(String headers)\n        throws java.text.ParseException {\n        if (headers == null)\n            throw new NullPointerException(\"null arg!\");\n        StringMsgParser smp = new StringMsgParser();\n        SIPHeader shdr = smp.parseSIPHeader(headers);\n        if (shdr instanceof SIPHeaderList)\n            return (SIPHeaderList) shdr;\n        else\n            throw new ParseException(\n                \"List of headers of this type is not allowed in a message\",\n                0);\n    }\n\n    /** Create a ReferTo Header.\n     *@param address -- address for the header.\n     */\n    public ReferToHeader createReferToHeader(Address address) {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n        ReferTo referTo = new ReferTo();\n        referTo.setAddress(address);\n        return referTo;\n    }\n\n    /** Create a ReferredBy Header.\n     *\n     *  pmusgrave\n     *\n     *@param address -- address for the header.\n     *\n     * TODO: Once interfaces are in javax2, change the type to MinSEHeader\n     * and add to HeaderFactory. - pmusgrave\n\n     */\n    public ReferredByHeader createReferredByHeader(Address address) {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n        ReferredBy referredBy = new ReferredBy();\n        referredBy.setAddress(address);\n        return referredBy;\n    }\n\n    /**\n     * Create a Replaces header with a call Id, to and from tag.\n     *\n     * TODO: Once interfaces are in javax2, change the type to MinSEHeader\n     * and add to HeaderFactory. - pmusgrave\n     * pmusgrave\n     */\n    public ReplacesHeader createReplacesHeader(String callId, String toTag,\n                String fromTag) throws ParseException\n    {\n        Replaces replaces = new Replaces();\n        replaces.setCallId(callId);\n        replaces.setFromTag(fromTag);\n        replaces.setToTag(toTag);\n\n        return replaces;\n    }\n\n    /**\n     * Create a Join header with a call Id, to and from tag.\n     *\n     */\n    public JoinHeader createJoinHeader(String callId, String toTag,\n                String fromTag) throws ParseException\n    {\n        Join join = new Join();\n        join.setCallId(callId);\n        join.setFromTag(fromTag);\n        join.setToTag(toTag);\n\n        return join;\n    }\n\n\n    /*\n     * (non-Javadoc)\n     * @see javax2.sip.header.HeaderFactory#createSIPETagHeader(java.lang.String)\n     */\n    public SIPETagHeader createSIPETagHeader(String etag) throws ParseException {\n        return new SIPETag(etag);\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see javax2.sip.header.HeaderFactory#createSIPIfMatchHeader(java.lang.String)\n     */\n    public SIPIfMatchHeader createSIPIfMatchHeader(String etag) throws ParseException {\n        return new SIPIfMatch(etag);\n    }\n\n    //////////////////////////////////////////////////////////////////////////\n    // The following headers are not part of the JSIP spec.\n    // They are IMS headers\n    // (contributed by Miguel Freitas - PT Inovacao and Telecommunications Institute)\n    ///////////////////////////////////////////////////////////////////////////\n\n    /**\n     * creates a P-Access-Network-Info header\n     * @return newly created P-Access-Network-Info header\n     */\n    public PAccessNetworkInfoHeader createPAccessNetworkInfoHeader()\n    {\n        PAccessNetworkInfo accessNetworkInfo = new PAccessNetworkInfo();\n\n        return accessNetworkInfo;\n    }\n\n\n    /**\n     * P-Asserted-Identity header\n     * @param address - Address\n     * @return newly created P-Asserted-Identity header\n     * @throws ParseException\n     * @throws NullPointerException\n     */\n    public PAssertedIdentityHeader createPAssertedIdentityHeader(Address address)\n        throws NullPointerException, ParseException\n    {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n\n        PAssertedIdentity assertedIdentity = new PAssertedIdentity();\n        assertedIdentity.setAddress(address);\n\n        return assertedIdentity;\n\n\n    }\n\n\n    /**\n     * Creates a new P-Associated-URI header based on the supplied address\n     * @param assocURI - Address\n     * @return newly created P-Associated-URI header\n     * @throws NullPointerException if the supplied address is null\n     * @throws ParseException\n     */\n    public PAssociatedURIHeader createPAssociatedURIHeader(Address assocURI)\n    {\n        if (assocURI == null)\n        throw new NullPointerException(\"null associatedURI!\");\n\n        PAssociatedURI associatedURI = new PAssociatedURI();\n        associatedURI.setAddress(assocURI);\n\n        return associatedURI;\n    }\n\n\n\n\n    /**\n     * P-Called-Party-ID header\n     * @param address - Address\n     * @return newly created P-Called-Party-ID header\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public PCalledPartyIDHeader createPCalledPartyIDHeader(Address address)\n    {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n\n        PCalledPartyID calledPartyID = new PCalledPartyID();\n        calledPartyID.setAddress(address);\n\n        return calledPartyID;\n    }\n\n\n\n    /**\n     * P-Charging-Function-Addresses header\n     * @return newly created P-Charging-Function-Addresses header\n     */\n    public PChargingFunctionAddressesHeader createPChargingFunctionAddressesHeader()\n    {\n        PChargingFunctionAddresses cfa = new PChargingFunctionAddresses();\n\n        return cfa;\n    }\n\n\n    /**\n     * P-Charging-Vector header\n     * @param icid - icid string\n     * @return newly created P-Charging-Vector header\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public PChargingVectorHeader createChargingVectorHeader(String icid)\n        throws ParseException\n    {\n        if (icid == null)\n        throw new NullPointerException(\"null icid arg!\");\n\n        PChargingVector chargingVector = new PChargingVector();\n        chargingVector.setICID(icid);\n\n        return chargingVector;\n\n    }\n\n\n    /**\n     * P-Media-Authorization header\n     * @param token - token string\n     * @return newly created P-Media-Authorizarion header\n     * @throws InvalidArgumentException\n     * @throws ParseException\n     */\n    public PMediaAuthorizationHeader createPMediaAuthorizationHeader(String token)\n        throws InvalidArgumentException, ParseException\n    {\n        if (token == null || token == \"\")\n            throw new InvalidArgumentException(\"The Media-Authorization-Token parameter is null or empty\");\n\n\n        PMediaAuthorization mediaAuthorization = new PMediaAuthorization();\n        mediaAuthorization.setMediaAuthorizationToken(token);\n\n        return mediaAuthorization;\n    }\n\n\n    /**\n     * P-Preferred-Identity header\n     * @param address - Address\n     * @return newly created P-Preferred-Identity header\n     * @throws NullPointerException\n     */\n    public PPreferredIdentityHeader createPPreferredIdentityHeader(Address address)\n    {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n\n        PPreferredIdentity preferredIdentity = new PPreferredIdentity();\n        preferredIdentity.setAddress(address);\n\n        return preferredIdentity;\n\n    }\n\n    /**\n     * P-Visited-Network-ID header\n     * @return newly created P-Visited-Network-ID header\n     */\n    public PVisitedNetworkIDHeader createPVisitedNetworkIDHeader()\n    {\n        PVisitedNetworkID visitedNetworkID = new PVisitedNetworkID();\n\n        return visitedNetworkID;\n    }\n\n\n\n    /**\n     * PATH header\n     * @param address - Address\n     * @return newly created Path header\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public PathHeader createPathHeader(Address address)\n    {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n\n\n        Path path = new Path();\n        path.setAddress(address);\n\n        return path;\n    }\n\n\n    /**\n     * Privacy header\n     * @param privacyType - privacy type string\n     * @return newly created Privacy header\n     * @throws NullPointerException\n     */\n    public PrivacyHeader createPrivacyHeader(String privacyType)\n    {\n        if (privacyType == null)\n            throw new NullPointerException(\"null privacyType arg\");\n\n        Privacy privacy = new Privacy(privacyType);\n\n        return privacy;\n\n    }\n\n\n    /**\n     * Service-Route header\n     * @param address - Address\n     * @return newly created Service-Route header\n     * @throws NullPointerException\n     */\n    public ServiceRouteHeader createServiceRouteHeader(Address address)\n    {\n        if (address == null)\n            throw new NullPointerException(\"null address!\");\n\n        ServiceRoute serviceRoute = new ServiceRoute();\n        serviceRoute.setAddress(address);\n\n        return serviceRoute;\n\n    }\n\n    /**\n     * Security-Server header\n     * @return newly created Security-Server header\n     */\n    public SecurityServerHeader createSecurityServerHeader()\n    {\n        SecurityServer secServer = new SecurityServer();\n        return secServer;\n    }\n\n    /**\n     * Security-Client header\n     * @return newly created Security-Client header\n     */\n    public SecurityClientHeader createSecurityClientHeader()\n    {\n        SecurityClient secClient = new SecurityClient();\n        return secClient;\n    }\n\n    /**\n     * Security-Verify header\n     * @return newly created Security-Verify header\n     */\n    public SecurityVerifyHeader createSecurityVerifyHeader()\n    {\n        SecurityVerify secVerify = new SecurityVerify();\n        return secVerify;\n    }\n\n    /**\n     * @return the newly create P-User-Database header.\n     * Please note that this is not a SIP/TEL uri. It is a\n     * DIAMETER AAA URI.\n     */\n    public PUserDatabaseHeader createPUserDatabaseHeader(String databaseName)\n    {\n        if((databaseName ==null)||(databaseName.equals(\" \")))\n            throw new NullPointerException(\"Database name is null\");\n\n        PUserDatabase pUserDatabase = new PUserDatabase();\n        pUserDatabase.setDatabaseName(databaseName);\n\n        return pUserDatabase;\n    }\n\n\n    /**\n     * \n     * @return The newly created P-Profile-Key header.\n     *\n     */\n    public PProfileKeyHeader createPProfileKeyHeader(Address address)\n    {\n        if (address ==null)\n            throw new NullPointerException(\"Address is null\");\n        PProfileKey pProfileKey = new PProfileKey();\n        pProfileKey.setAddress(address);\n\n        return pProfileKey;\n    }\n\n    /**\n     * \n     * @return The newly created P-Served-User header.\n     */\n    public PServedUserHeader createPServedUserHeader(Address address)\n    {\n        if(address==null)\n            throw new NullPointerException(\"Address is null\");\n        PServedUser psu = new PServedUser();\n        psu.setAddress(address);\n\n        return psu;\n    }\n    /**\n     * @return The newly created P-Preferred-Service header.\n     */\n    public PPreferredServiceHeader createPPreferredServiceHeader()\n    {\n        PPreferredService pps = new PPreferredService();\n        return pps;\n    }\n\n    /**\n     *\n     * @return The newly created P-Asserted-Service header.\n     */\n    public PAssertedServiceHeader createPAssertedServiceHeader()\n    {\n        PAssertedService pas = new PAssertedService();\n        return pas;\n    }\n\n    /**\n     * Creates a new SessionExpiresHeader based on the newly supplied expires value.\n     *\n     * @param expires - the new integer value of the expires.\n     * @throws InvalidArgumentException if supplied expires is less\n     * than zero.\n     * @return the newly created SessionExpiresHeader object.\n     *\n     */\n    public SessionExpiresHeader createSessionExpiresHeader(int expires)\n        throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad value \" + expires);\n        SessionExpires s = new SessionExpires();\n        s.setExpires(expires);\n\n        return s;\n    }\n    \n    \n    /**\n     * Create a new Request Line from a String.\n     * \n     */\n    public SipRequestLine createRequestLine(String requestLine)  throws ParseException {\n        \n        RequestLineParser requestLineParser = new RequestLineParser(requestLine);\n        return (SipRequestLine) requestLineParser.parse();\n    }\n    \n    /**\n     * Create a new StatusLine from a String.\n     */\n    public SipStatusLine createStatusLine(String statusLine) throws ParseException {\n        StatusLineParser statusLineParser = new StatusLineParser(statusLine);\n        return (SipStatusLine) statusLineParser.parse();\n    }\n\n\n    \n    /**\n     * Create and return a references header.\n     * \n     * @param callId\n     * @param rel\n     * @return\n     * @throws ParseException\n     */\n\n    public ReferencesHeader createReferencesHeader(String callId, String rel) throws ParseException {\n        ReferencesHeader retval = new References();\n        retval.setCallId(callId);\n        retval.setRel(rel);\n        return retval;\n    }\n    \n    \n\n\n    //////////////////////////////////////////////////////////\n    // Constructor\n    //////////////////////////////////////////////////////////\n    /**\n     * Default constructor.\n     */\n    public HeaderFactoryImpl() {\n        stripAddressScopeZones\n            = Boolean.getBoolean(\"gov2.nist.core.STRIP_ADDR_SCOPES\");\n    }\n\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/InReplyTo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * InReplyTo SIP Header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:31 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n */\npublic class InReplyTo extends SIPHeader implements InReplyToHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1682602905733508890L;\n\n    protected CallIdentifier callId;\n\n    /** Default constructor\n     */\n    public InReplyTo() {\n        super(IN_REPLY_TO);\n    }\n\n    /** constructor\n     * @param cid CallIdentifier to set\n     */\n    public InReplyTo(CallIdentifier cid) {\n        super(IN_REPLY_TO);\n        callId = cid;\n    }\n\n    /**\n     * Sets the Call-Id of the InReplyToHeader. The CallId parameter uniquely\n     * identifies a serious of messages within a dialogue.\n     *\n     * @param callId - the string value of the Call-Id of this InReplyToHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the callId value.\n     */\n    public void setCallId(String callId) throws ParseException {\n        try {\n            this.callId = new CallIdentifier(callId);\n        } catch (Exception e) {\n            throw new ParseException(e.getMessage(), 0);\n        }\n    }\n\n    /**\n     * Returns the Call-Id of InReplyToHeader. The CallId parameter uniquely\n     * identifies a series of messages within a dialogue.\n     *\n     * @return the String value of the Call-Id of this InReplyToHeader\n     */\n    public String getCallId() {\n        if (callId == null)\n            return null;\n        return callId.encode();\n    }\n\n    /**\n         * Generate canonical form of the header.\n         * @return String\n         */\n    public String encodeBody() {\n        return callId.encode();\n    }\n\n    public Object clone() {\n        InReplyTo retval = (InReplyTo) super.clone();\n        if (this.callId != null)\n            retval.callId = (CallIdentifier) this.callId.clone();\n        return retval;\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/InReplyToList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n* In-Reply-To SIP header. Keeps a list of InReplyToHeader\n*\n* @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:31 $\n* @since 1.1\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*/\npublic final class InReplyToList extends SIPHeaderList<InReplyTo>  {\n\n\n    private static final long serialVersionUID = -7993498496830999237L;\n\n    public Object clone() {\n        InReplyToList retval = new InReplyToList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default constructor\n     */\n    public InReplyToList() {\n        super(InReplyTo.class, InReplyToHeader.NAME);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Indentation.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n/**\n * Internal utility class for pretty printing and header formatting.\n *\n * @author M. Ranganathan\n * @author O. Deruelle\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:31 $\n */\nclass Indentation {\n\n    private int indentation;\n\n    /**\n     * Default constructor\n     */\n    protected Indentation() {\n        indentation = 0;\n    }\n\n    /**\n     * Constructor\n     *\n     * @param initval\n     *            int to set\n     */\n    protected Indentation(int initval) {\n        indentation = initval;\n    }\n\n    /**\n     * set the indentation field\n     *\n     * @param initval\n     *            int to set\n     */\n    protected void setIndentation(int initval) {\n        indentation = initval;\n    }\n\n    /**\n     * get the number of indentation.\n     *\n     * @return int\n     */\n    protected int getCount() {\n        return indentation;\n    }\n\n    /**\n     * increment the indentation field\n     */\n    protected void increment() {\n        indentation++;\n    }\n\n    /**\n     * decrement the indentation field\n     */\n    protected void decrement() {\n        indentation--;\n    }\n\n    /**\n     * get the indentation\n     *\n     * @return String\n     */\n    protected String getIndentation() {\n        char[] chars = new char[indentation];\n        java.util.Arrays.fill(chars, ' ');\n        return new String(chars);\n    }\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/MaxForwards.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.*;\n\n/**\n * MaxForwards SIPHeader\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:32 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n */\npublic class MaxForwards extends SIPHeader implements MaxForwardsHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3096874323347175943L;\n    /** maxForwards field.\n     */\n    protected int maxForwards;\n\n    /** Default constructor.\n     */\n    public MaxForwards() {\n        super(NAME);\n    }\n\n  public MaxForwards( int m ) throws InvalidArgumentException {\n        super(NAME);\n        this.setMaxForwards( m );\n    }\n\n    /** get the MaxForwards field.\n     * @return the maxForwards member.\n     */\n    public int getMaxForwards() {\n        return maxForwards;\n    }\n\n    /**\n         * Set the maxForwards member\n         * @param maxForwards maxForwards parameter to set\n         */\n    public void setMaxForwards(int maxForwards)\n        throws InvalidArgumentException {\n        if (maxForwards < 0 || maxForwards > 255)\n            throw new InvalidArgumentException(\n                \"bad max forwards value \" + maxForwards);\n        this.maxForwards = maxForwards;\n    }\n\n    /**\n         * Encode into a string.\n         * @return encoded string.\n         *\n         */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        return buffer.append(maxForwards);\n    }\n\n    /** Boolean function\n     * @return true if MaxForwards field reached zero.\n     */\n    public boolean hasReachedZero() {\n        return maxForwards == 0;\n    }\n\n    /** decrement MaxForwards field one by one.\n     */\n    public void decrementMaxForwards() throws TooManyHopsException {\n        if (maxForwards > 0)\n            maxForwards--;\n        else throw new TooManyHopsException (\"has already reached 0!\");\n    }\n\n    public boolean equals(Object other) {\n        if (this==other) return true;\n        if (other instanceof MaxForwardsHeader) {\n            final MaxForwardsHeader o = (MaxForwardsHeader) other;\n            return this.getMaxForwards() == o.getMaxForwards();\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/MediaRange.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n* See ../../../../doc/uncopyright.html for conditions of use.                  *\n* Author: M. Ranganathan (mranga@nist.gov)                                     *\n* Modified By:  O. Deruelle (deruelle@nist.gov)                                *\n* Questions/Comments: nist-sip-dev@antd.nist.gov                               *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n/**\n*   Media Range\n* @see Accept\n* @since 0.9\n* @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:32 $\n* <pre>\n* Revisions:\n*\n* Version 1.0\n*    1. Added encode method.\n*\n* media-range    = ( \"STAR/STAR\"\n*                        | ( type \"/\" STAR )\n*                        | ( type \"/\" subtype )\n*                        ) *( \";\" parameter )\n*\n* HTTP RFC 2616 Section 14.1\n* </pre>\n*/\npublic class MediaRange extends SIPObject {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6297125815438079210L;\n\n    /** type field\n     */\n    protected String type;\n\n    /** subtype field\n     */\n    protected String subtype;\n\n    /** Default constructor\n     */\n    public MediaRange() {\n    }\n\n    /** get type field\n     * @return String\n     */\n    public String getType() {\n        return type;\n    }\n\n    /** get the subType field.\n     * @return String\n     */\n    public String getSubtype() {\n        return subtype;\n    }\n\n    /**\n     * Set the type member\n     * @param t String to set\n     */\n    public void setType(String t) {\n        type = t;\n    }\n\n    /**\n     * Set the subtype member\n     * @param s String to set\n     */\n    public void setSubtype(String s) {\n        subtype = s;\n    }\n\n    /**\n     * Encode the object.\n     * @return String\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        return buffer.append(type)\n                .append(SLASH)\n                .append(subtype);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/MimeVersion.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.*;\n\n/**\n * MimeVersion SIP Header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/10/18 13:46:35 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n */\npublic class MimeVersion extends SIPHeader implements MimeVersionHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -7951589626435082068L;\n\n    /**\n     * mimeVersion field\n     */\n    protected int minorVersion;\n\n    /**\n     * majorVersion field\n     */\n    protected int majorVersion;\n\n    /**\n     * Default constructor\n     */\n    public MimeVersion() {\n        super(MIME_VERSION);\n    }\n\n    /**\n     * Gets the Minor version value of this MimeVersionHeader.\n     *\n     * @return the Minor version of this MimeVersionHeader\n     */\n    public int getMinorVersion() {\n        return minorVersion;\n    }\n\n    /**\n    * Gets the Major version value of this MimeVersionHeader.\n    *\n    * @return the Major version of this MimeVersionHeader\n    */\n    public int getMajorVersion() {\n        return majorVersion;\n    }\n\n    /**\n     * Sets the Minor-Version argument of this MimeVersionHeader to the supplied\n     * <var>minorVersion</var> value.\n     *\n     * @param minorVersion - the new integer Minor version\n     * @throws InvalidArgumentException\n     */\n    public void setMinorVersion(int minorVersion)\n        throws InvalidArgumentException {\n        if (minorVersion < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP Exception\"\n                    + \", MimeVersion, setMinorVersion(), the minorVersion parameter is null\");\n        this.minorVersion = minorVersion;\n    }\n\n    /**\n     * Sets the Major-Version argument of this MimeVersionHeader to the supplied\n     * <var>majorVersion</var> value.\n     *\n     * @param majorVersion - the new integer Major version\n     * @throws InvalidArgumentException\n     */\n    public void setMajorVersion(int majorVersion)\n        throws InvalidArgumentException {\n        if (majorVersion < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP Exception\"\n                    + \", MimeVersion, setMajorVersion(), the majorVersion parameter is null\");\n        this.majorVersion = majorVersion;\n    }\n\n    /**\n     * Return canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return Integer.toString(majorVersion)\n            + DOT\n            + Integer.toString(minorVersion);\n    }\n\n}\n/*\n * $Log: MimeVersion.java,v $\n * Revision 1.6  2009/10/18 13:46:35  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.5  2009/07/17 18:57:32  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:33  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:34  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/MinExpires.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.*;\nimport javax2.sip.header.*;\n\n/**\n * MinExpires SIP Header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/10/18 13:46:35 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class MinExpires extends SIPHeader implements MinExpiresHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 7001828209606095801L;\n    /** expires field\n     */\n    protected int expires;\n\n    /** default constructor\n     */\n    public MinExpires() {\n        super(NAME);\n    }\n\n    /**\n     * Return canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return Integer.toString(expires);\n    }\n\n    /**\n     * Gets the expires value of the ExpiresHeader. This expires value is\n     * relative time.\n     *\n     * @return the expires value of the ExpiresHeader.\n     *\n     */\n    public int getExpires() {\n        return expires;\n    }\n\n    /**\n     * Sets the relative expires value of the ExpiresHeader.\n     * The expires value MUST be greater than zero and MUST be\n     * less than 2**31.\n     *\n     * @param expires - the new expires value of this ExpiresHeader\n     *\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     *\n     *\n     *\n     */\n    public void setExpires(int expires) throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad argument \" + expires);\n        this.expires = expires;\n    }\n\n}\n/*\n * $Log: MinExpires.java,v $\n * Revision 1.6  2009/10/18 13:46:35  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.5  2009/07/17 18:57:32  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:20  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:34  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/NameMap.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.ims.*;\n\nimport java.util.Hashtable;\n\n/**\n * A mapping class that returns the SIPHeader for a given header name.\n * Add new classes to this map if you are implementing new header types if\n * you want some of the introspection based methods to work.\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:32 $\n * @since 1.1\n */\npublic class NameMap implements SIPHeaderNames, PackageNames {\n    static Hashtable nameMap;\n    static {\n        initializeNameMap();\n    }\n\n    protected static void putNameMap(String headerName, String className) {\n        nameMap.put(\n            headerName.toLowerCase(),\n            className);\n    }\n\n    public static Class getClassFromName(String headerName) {\n        String className = (String) nameMap.get(headerName.toLowerCase());\n        if (className == null)\n            return null;\n        else {\n            try {\n                return Class.forName(className);\n            } catch (ClassNotFoundException ex) {\n                return null;\n            }\n        }\n    }\n\n    /** add an extension header to this map.\n    *@param headerName is the extension header name.\n    *@param className is the fully qualified class name that implements\n    * the header (does not have to belong to the nist-sip package).\n    * Use this if you want to use the introspection-based methods.\n    */\n\n    public static void addExtensionHeader(\n        String headerName,\n        String className) {\n        nameMap.put(headerName.toLowerCase(), className);\n    }\n\n    private static void initializeNameMap() {\n        nameMap = new Hashtable();\n        putNameMap(MinExpires.NAME, MinExpires.class.getName()); // 1\n\n        putNameMap(ErrorInfo.NAME, ErrorInfo.class.getName()); // 2\n\n        putNameMap(MimeVersion.NAME, MimeVersion.class.getName()); // 3\n\n        putNameMap(InReplyTo.NAME, InReplyTo.class.getName()); // 4\n\n        putNameMap(Allow.NAME, Allow.class.getName()); // 5\n\n        putNameMap(ContentLanguage.NAME, ContentLanguage.class.getName()); // 6\n\n        putNameMap(CALL_INFO, CallInfo.class.getName()); //7\n\n        putNameMap(CSEQ, CSeq.class.getName()); //8\n\n        putNameMap(ALERT_INFO, AlertInfo.class.getName()); //9\n\n        putNameMap(ACCEPT_ENCODING, AcceptEncoding.class.getName()); //10\n\n        putNameMap(ACCEPT, Accept.class.getName()); //11\n\n        putNameMap(ACCEPT_LANGUAGE, AcceptLanguage.class.getName()); //12\n\n        putNameMap(RECORD_ROUTE, RecordRoute.class.getName()); //13\n\n        putNameMap(TIMESTAMP, TimeStamp.class.getName()); //14\n\n        putNameMap(TO, To.class.getName()); //15\n\n        putNameMap(VIA, Via.class.getName()); //16\n\n        putNameMap(FROM, From.class.getName()); //17\n\n        putNameMap(CALL_ID, CallID.class.getName()); //18\n\n        putNameMap(AUTHORIZATION, Authorization.class.getName()); //19\n\n        putNameMap(PROXY_AUTHENTICATE, ProxyAuthenticate.class.getName()); //20\n\n        putNameMap(SERVER, Server.class.getName()); //21\n\n        putNameMap(UNSUPPORTED, Unsupported.class.getName()); //22\n\n        putNameMap(RETRY_AFTER, RetryAfter.class.getName()); //23\n\n        putNameMap(CONTENT_TYPE, ContentType.class.getName()); //24\n\n        putNameMap(CONTENT_ENCODING, ContentEncoding.class.getName()); //25\n\n        putNameMap(CONTENT_LENGTH, ContentLength.class.getName()); //26\n\n        putNameMap(ROUTE, Route.class.getName()); //27\n\n        putNameMap(CONTACT, Contact.class.getName()); //28\n\n        putNameMap(WWW_AUTHENTICATE, WWWAuthenticate.class.getName()); //29\n\n        putNameMap(MAX_FORWARDS, MaxForwards.class.getName()); //30\n\n        putNameMap(ORGANIZATION, Organization.class.getName()); //31\n\n        putNameMap(PROXY_AUTHORIZATION, ProxyAuthorization.class.getName()); //32\n\n        putNameMap(PROXY_REQUIRE, ProxyRequire.class.getName()); //33\n\n        putNameMap(REQUIRE, Require.class.getName()); //34\n\n        putNameMap(CONTENT_DISPOSITION, ContentDisposition.class.getName()); //35\n\n        putNameMap(SUBJECT, Subject.class.getName()); //36\n\n        putNameMap(USER_AGENT, UserAgent.class.getName()); //37\n\n        putNameMap(WARNING, Warning.class.getName()); //38\n\n        putNameMap(PRIORITY, Priority.class.getName()); //39\n\n        putNameMap(DATE, SIPDateHeader.class.getName()); //40\n\n        putNameMap(EXPIRES, Expires.class.getName()); //41\n\n        putNameMap(SUPPORTED, Supported.class.getName()); //42\n\n        putNameMap(REPLY_TO, ReplyTo.class.getName()); // 43\n\n        putNameMap(SUBSCRIPTION_STATE, SubscriptionState.class.getName()); //44\n\n        putNameMap(EVENT, Event.class.getName()); //45\n\n        putNameMap(ALLOW_EVENTS, AllowEvents.class.getName()); //46\n\n\n        // pmusgrave - extensions\n        putNameMap(REFERRED_BY, \"ReferredBy\");\n        putNameMap(SESSION_EXPIRES, \"SessionExpires\");\n        putNameMap(MIN_SE, \"MinSE\");\n        putNameMap(REPLACES, \"Replaces\");\n        // jean deruelle\n        putNameMap(JOIN, \"Join\");\n\n\n        // IMS Specific headers.\n\n        putNameMap(PAccessNetworkInfoHeader.NAME, PAccessNetworkInfo.class.getName());\n\n        putNameMap(PAssertedIdentityHeader.NAME, PAssertedIdentity.class.getName());\n\n        putNameMap(PAssociatedURIHeader.NAME, PAssociatedURI.class.getName());\n\n        putNameMap(PCalledPartyIDHeader.NAME, PCalledPartyID.class.getName());\n\n        putNameMap(PChargingFunctionAddressesHeader.NAME,  PChargingFunctionAddresses.class.getName());\n\n        putNameMap(PChargingVectorHeader.NAME,PChargingVector.class.getName());\n\n        putNameMap(PMediaAuthorizationHeader.NAME,PMediaAuthorization.class.getName());\n\n        putNameMap(Path.NAME, Path.class.getName());\n\n        putNameMap(PPreferredIdentity.NAME, PPreferredIdentity.class.getName());\n\n        putNameMap(Privacy.NAME,Privacy.class.getName());\n\n        putNameMap(ServiceRoute.NAME, ServiceRoute.class.getName());\n\n        putNameMap(PVisitedNetworkID.NAME, PVisitedNetworkID.class.getName());\n\n\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Organization.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * Organization SIP Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:32 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class Organization extends SIPHeader implements OrganizationHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -2775003113740192712L;\n    /**\n     * Organization field\n     */\n    protected String organization;\n\n    /**\n     * Return encoding of value of the header.\n     * @return String\n     */\n    public String encodeBody() {\n        return organization;\n    }\n\n    /**\n     * Default constructor\n     */\n    public Organization() {\n        super(ORGANIZATION);\n    }\n\n    /**\n     * Get the organization field.\n     * @return String\n     */\n    public String getOrganization() {\n        return organization;\n    }\n\n    /**\n     * Set the organization member\n     * @param o String to set\n     */\n    public void setOrganization(String o) throws ParseException {\n        if (o == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception,\"\n                    + \" Organization, setOrganization(), the organization parameter is null\");\n        organization = o;\n    }\n}\n/*\n * $Log: Organization.java,v $\n * Revision 1.5  2009/07/17 18:57:32  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:15  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:34  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ParameterNames.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\npackage gov2.nist.javax2.sip.header;\n\n/**\n * A list of commonly occuring parameter names. These are for conveniance so as\n * to avoid typo's\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:33 $\n * @since 1.1\n *\n * @author M. Ranganathan <br/>\n *\n *\n *\n */\npublic interface ParameterNames {\n    // Issue reported by larryb\n    public static final String NEXT_NONCE = \"nextnonce\";\n\n    public static final String TAG = \"tag\";\n\n    public static final String USERNAME = \"username\";\n\n    public static final String URI = \"uri\";\n\n    public static final String DOMAIN = \"domain\";\n\n    public static final String CNONCE = \"cnonce\";\n\n    public static final String PASSWORD = \"password\";\n\n    public static final String RESPONSE = \"response\";\n\n    public static final String RESPONSE_AUTH = \"rspauth\";\n\n    public static final String OPAQUE = \"opaque\";\n\n    public static final String ALGORITHM = \"algorithm\";\n\n    public static final String DIGEST = \"Digest\";\n\n    public static final String SIGNED_BY = \"signed-by\";\n\n    public static final String SIGNATURE = \"signature\";\n\n    public static final String NONCE = \"nonce\";\n\n    // Issue reported by larryb\n    public static final String NONCE_COUNT = \"nc\";\n\n    public static final String PUBKEY = \"pubkey\";\n\n    public static final String COOKIE = \"cookie\";\n\n    public static final String REALM = \"realm\";\n\n    public static final String VERSION = \"version\";\n\n    public static final String STALE = \"stale\";\n\n    public static final String QOP = \"qop\";\n\n    public static final String NC = \"nc\";\n\n    public static final String PURPOSE = \"purpose\";\n\n    public static final String CARD = \"card\";\n\n    public static final String INFO = \"info\";\n\n    public static final String ACTION = \"action\";\n\n    public static final String PROXY = \"proxy\";\n\n    public static final String REDIRECT = \"redirect\";\n\n    public static final String EXPIRES = \"expires\";\n\n    public static final String Q = \"q\";\n\n    public static final String RENDER = \"render\";\n\n    public static final String SESSION = \"session\";\n\n    public static final String ICON = \"icon\";\n\n    public static final String ALERT = \"alert\";\n\n    public static final String HANDLING = \"handling\";\n\n    public static final String REQUIRED = \"required\";\n\n    public static final String OPTIONAL = \"optional\";\n\n    public static final String EMERGENCY = \"emergency\";\n\n    public static final String URGENT = \"urgent\";\n\n    public static final String NORMAL = \"normal\";\n\n    public static final String NON_URGENT = \"non-urgent\";\n\n    public static final String DURATION = \"duration\";\n\n    public static final String BRANCH = \"branch\";\n\n    public static final String HIDDEN = \"hidden\";\n\n    public static final String RECEIVED = \"received\";\n\n    public static final String MADDR = \"maddr\";\n\n    public static final String TTL = \"ttl\";\n\n    public static final String TRANSPORT = \"transport\";\n\n    public static final String TEXT = \"text\";\n\n    public static final String CAUSE = \"cause\";\n\n    public static final String ID = \"id\";\n\n    // @@@ hagai\n    public static final String RPORT = \"rport\";\n\n    // Added pmusgrave (Replaces support)\n    public static final String TO_TAG = \"to-tag\";\n    public static final String FROM_TAG = \"from-tag\";\n\n    // pmusgrave (outbound and gruu)\n    // draft-sip-outbouund-08\n    // draft-sip-gruu-12\n    public static final String SIP_INSTANCE = \"+sip.instance\";\n    public static final String PUB_GRUU = \"pub-gruu\";\n    public static final String TEMP_GRUU = \"temp-gruu\";\n    public static final String GRUU = \"gruu\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ParametersHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/**************************************************************************/\n/* Product of NIST Advanced Networking Technologies Division  */\n/**************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.core.DuplicateNameValueList;\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.javax2.sip.address.GenericURI;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\nimport java.util.Iterator;\n\nimport javax2.sip.header.Parameters;\n\n/**\n * Parameters header. Suitable for extension by headers that have parameters.\n *\n * @author M. Ranganathan   <br/>\n *\n *\n * @version 1.2 $Revision: 1.15 $ $Date: 2010/01/12 00:05:27 $\n *\n */\npublic abstract class ParametersHeader\n    extends SIPHeader\n    implements javax2.sip.header.Parameters, Serializable {\n    protected NameValueList parameters;\n    \n    protected DuplicateNameValueList duplicates;\n    \n    protected ParametersHeader() {\n        this.parameters = new NameValueList();\n        this.duplicates = new DuplicateNameValueList();\n    }\n\n    protected ParametersHeader(String hdrName) {\n        super(hdrName);\n        this.parameters = new NameValueList();\n        this.duplicates = new DuplicateNameValueList();\n    }\n\n    protected ParametersHeader(String hdrName, boolean sync) {\n        super(hdrName);\n        this.parameters = new NameValueList(sync);\n        this.duplicates = new DuplicateNameValueList();\n    }\n\n    /**\n     * Returns the value of the named parameter, or null if it is not set. A\n     * zero-length String indicates flag parameter.\n     *\n     * @param name name of parameter to retrieve\n     * @return the value of specified parameter\n     */\n\n    public String getParameter(String name) {\n        return this.parameters.getParameter(name);\n\n    }\n\n    /**\n     * Return the parameter as an object (dont convert to string).\n     *\n     * @param name is the name of the parameter to get.\n     * @return the object associated with the name.\n     */\n    public Object getParameterValue(String name) {\n        return this.parameters.getValue(name);\n    }\n\n    /**\n     * Returns an Iterator over the names (Strings) of all parameters present\n     * in this ParametersHeader.\n     *\n     * @return an Iterator over all the parameter names\n     */\n\n    public Iterator<String> getParameterNames() {\n        return parameters.getNames();\n    }\n\n    /** Return true if you have a parameter and false otherwise.\n     *\n     *@return true if the parameters list is non-empty.\n     */\n\n    public boolean hasParameters() {\n        return parameters != null && !parameters.isEmpty();\n    }\n\n    /**\n    * Removes the specified parameter from Parameters of this ParametersHeader.\n    * This method returns silently if the parameter is not part of the\n    * ParametersHeader.\n    *\n    * @param name - a String specifying the parameter name\n    */\n\n    public void removeParameter(String name) {\n        this.parameters.delete(name);\n    }\n\n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten. A zero-length String indicates flag\n     *\n     * parameter.\n     *\n     *\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - a String specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    public void setParameter(String name, String value) throws ParseException {\n        NameValue nv = parameters.getNameValue(name);\n        if (nv != null) {\n            nv.setValueAsObject(value);\n        } else {\n            nv = new NameValue(name, value);\n            this.parameters.set(nv);\n        }\n    }\n    \n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten. A zero-length String indicates flag\n     *\n     * parameter.\n     *\n     *\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - a String specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    public void setQuotedParameter(String name, String value)\n        throws ParseException {\n        NameValue nv = parameters.getNameValue(name);\n        if (nv != null) {\n            nv.setValueAsObject(value);\n            nv.setQuotedValue();\n        } else {\n            nv = new NameValue(name, value);\n            nv.setQuotedValue();\n            this.parameters.set(nv);\n        }\n    }\n\n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten.\n     *\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - an int specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    protected void setParameter(String name, int value) {\n        Integer val = Integer.valueOf(value);\n        this.parameters.set(name,val);\n\n    }\n\n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten.\n     *\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - a boolean specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    protected void setParameter(String name, boolean value) {\n        Boolean val = Boolean.valueOf(value);\n        this.parameters.set(name,val);\n    }\n\n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten.\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - a boolean specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    protected void setParameter(String name, float value) {\n        Float val = Float.valueOf(value);\n        NameValue nv = parameters.getNameValue(name);\n        if (nv != null) {\n            nv.setValueAsObject(val);\n        } else {\n            nv = new NameValue(name, val);\n            this.parameters.set(nv);\n        }\n    }\n\n    /**\n     * Sets the value of the specified parameter. If the parameter already had\n     *\n     * a value it will be overwritten. A zero-length String indicates flag\n     *\n     * parameter.\n     *\n     *\n     *\n     * @param name - a String specifying the parameter name\n     *\n     * @param value - a String specifying the parameter value\n     *\n     * @throws ParseException which signals that an error has been reached\n     *\n     * unexpectedly while parsing the parameter name or value.\n     *\n     */\n    protected void setParameter(String name, Object value) {\n        this.parameters.set(name,value);\n    }\n\n    /**\n     * Return true if has a parameter.\n     *\n     * @param parameterName is the name of the parameter.\n     *\n     * @return true if the parameter exists and false if not.\n     */\n    public boolean hasParameter(String parameterName) {\n        return this.parameters.hasNameValue(parameterName);\n    }\n\n    /**\n     *Remove all parameters.\n     */\n    public void removeParameters() {\n        this.parameters = new NameValueList();\n    }\n\n    /**\n     * get the parameter list.\n     * @return parameter list\n     */\n    public NameValueList getParameters() {\n        return parameters;\n    }\n\n    /** Set the parameter given a name and value.\n     *\n     * @param nameValue - the name value of the parameter to set.\n     */\n    public void setParameter(NameValue nameValue) {\n        this.parameters.set(nameValue);\n    }\n\n    /**\n     * Set the parameter list.\n     *\n     * @param parameters The name value list to set as the parameter list.\n     */\n    public void setParameters(NameValueList parameters) {\n        this.parameters = parameters;\n    }\n\n    /**\n     * Get the parameter as an integer value.\n     *\n     * @param parameterName -- the parameter name to fetch.\n     *\n     * @return -1 if the parameter is not defined in the header.\n     */\n    protected int getParameterAsInt(String parameterName) {\n        if (this.getParameterValue(parameterName) != null) {\n            try {\n                if (this.getParameterValue(parameterName) instanceof String) {\n                    return Integer.parseInt(this.getParameter(parameterName));\n                } else {\n                    return ((Integer) getParameterValue(parameterName))\n                        .intValue();\n                }\n            } catch (NumberFormatException ex) {\n                return -1;\n            }\n        } else\n            return -1;\n    }\n\n    /** Get the parameter as an integer when it is entered as a hex.\n     *\n     *@param parameterName -- The parameter name to fetch.\n     *\n     *@return -1 if the parameter is not defined in the header.\n     */\n    protected int getParameterAsHexInt(String parameterName) {\n        if (this.getParameterValue(parameterName) != null) {\n            try {\n                if (this.getParameterValue(parameterName) instanceof String) {\n                    return Integer.parseInt(\n                        this.getParameter(parameterName),\n                        16);\n                } else {\n                    return ((Integer) getParameterValue(parameterName))\n                        .intValue();\n                }\n            } catch (NumberFormatException ex) {\n                return -1;\n            }\n        } else\n            return -1;\n    }\n\n    /** Get the parameter as a float value.\n     *\n     *@param parameterName -- the parameter name to fetch\n     *\n     *@return -1 if the parameter is not defined or the parameter as a float.\n     */\n    protected float getParameterAsFloat(String parameterName) {\n\n        if (this.getParameterValue(parameterName) != null) {\n            try {\n                if (this.getParameterValue(parameterName) instanceof String) {\n                    return Float.parseFloat(this.getParameter(parameterName));\n                } else {\n                    return ((Float) getParameterValue(parameterName))\n                        .floatValue();\n                }\n            } catch (NumberFormatException ex) {\n                return -1;\n            }\n        } else\n            return -1;\n    }\n\n    /**\n     * Get the parameter as a long value.\n     *\n     * @param parameterName -- the parameter name to fetch.\n     *\n     * @return -1 if the parameter is not defined or the parameter as a long.\n     */\n    protected long getParameterAsLong(String parameterName) {\n        if (this.getParameterValue(parameterName) != null) {\n            try {\n                if (this.getParameterValue(parameterName) instanceof String) {\n                    return Long.parseLong(this.getParameter(parameterName));\n                } else {\n                    return ((Long) getParameterValue(parameterName))\n                        .longValue();\n                }\n            } catch (NumberFormatException ex) {\n                return -1;\n            }\n        } else\n            return -1;\n    }\n\n    /**\n     * Get the parameter value as a URI.\n     *\n     * @param parameterName -- the parameter name\n     *\n     * @return value of the parameter as a URI or null if the parameter\n     *  not present.\n     */\n    protected GenericURI getParameterAsURI(String parameterName) {\n        Object val = getParameterValue(parameterName);\n        if (val instanceof GenericURI)\n            return (GenericURI) val;\n        else {\n            try {\n                return new GenericURI((String) val);\n            } catch (ParseException ex) {\n                //catch ( URISyntaxException ex) {\n                return null;\n            }\n        }\n    }\n\n    /**\n     * Get the parameter value as a boolean.\n     *\n     * @param parameterName -- the parameter name\n     * @return boolean value of the parameter.\n     */\n    protected boolean getParameterAsBoolean(String parameterName) {\n        Object val = getParameterValue(parameterName);\n        if (val == null) {\n            return false;\n        } else if (val instanceof Boolean) {\n            return ((Boolean) val).booleanValue();\n        } else if (val instanceof String) {\n            return Boolean.valueOf((String) val).booleanValue();\n        } else\n            return false;\n    }\n\n    /**\n     * This is for the benifit of the TCK.\n     *\n     * @return the name value pair for the given parameter name.\n     */\n    public NameValue getNameValue(String parameterName) {\n        return parameters.getNameValue(parameterName);\n    }\n\n \n    public Object clone() {\n        ParametersHeader retval = (ParametersHeader) super.clone();\n        if (this.parameters != null)\n            retval.parameters = (NameValueList) this.parameters.clone();\n        return retval;\n    }\n\n    //-------------------------\n    /**\n     * Introduced specifically for the P-Charging-Function-Addresses Header and \n     * all other headers that may have multiple header parameters of the same name, but \n     * with multiple possible values.\n     * \n     * Example: P-Charging-Function-Addresses: ccf=[5555::b99:c88:d77:e66]; ccf=[5555::a55:b44:c33:d22]; \n     *                                         ecf=[5555::1ff:2ee:3dd:4cc]; ecf=[5555::6aa:7bb:8cc:9dd]\n     * @param name of the parameter\n     * @param value of the parameter\n     */\n    public void setMultiParameter(String name, String value)\n    {\n    \tNameValue nv = new NameValue();\n    \tnv.setName(name);\n    \tnv.setValue(value);\n    \tduplicates.set(nv);\n    }\n    \n    /** Set the parameter given a name and value.\n    *\n    * @param nameValue - the name value of the parameter to set.\n    */\n   public void setMultiParameter(NameValue nameValue) {\n       this.duplicates.set(nameValue);\n   }\n    \n    /**\n     * Returns the parameter name\n     * @param name\n     * @return\n     */\n    public String getMultiParameter(String name) {\n        return this.duplicates.getParameter(name);\n\n    }\n    \n\n    public DuplicateNameValueList getMultiParameters() {\n        return duplicates;\n    }\n    \n    \n    /**\n     * Return the parameter as an object (dont convert to string).\n     *\n     * @param name is the name of the parameter to get.\n     * @return the object associated with the name.\n     */\n    public Object getMultiParameterValue(String name) {\n        return this.duplicates.getValue(name);\n    }\n\n    /**\n     * Returns an Iterator over the names (Strings) of all parameters present\n     * in this ParametersHeader.\n     *\n     * @return an Iterator over all the parameter names\n     */\n\n    public Iterator<String> getMultiParameterNames() {\n        return duplicates.getNames();\n    }\n\n    /** Return true if you have a parameter and false otherwise.\n     *\n     *@return true if the parameters list is non-empty.\n     */\n\n    public boolean hasMultiParameters() {\n        return duplicates != null && !duplicates.isEmpty();\n    }\n\n    /**\n    * Removes the specified parameter from Parameters of this ParametersHeader.\n    * This method returns silently if the parameter is not part of the\n    * ParametersHeader.\n    *\n    * @param name - a String specifying the parameter name\n    */\n\n    public void removeMultiParameter(String name) {\n        this.duplicates.delete(name);\n    }\n    \n    /**\n     * Return true if has a parameter.\n     *\n     * @param parameterName is the name of the parameter.\n     *\n     * @return true if the parameter exists and false if not.\n     */\n    public boolean hasMultiParameter(String parameterName) {\n        return this.duplicates.hasNameValue(parameterName);\n    }\n\n    /**\n     *Remove all parameters.\n     */\n    public void removeMultiParameters() {\n        this.duplicates = new DuplicateNameValueList();\n    }\n\n    //-------------------------------\n    \n    @SuppressWarnings(\"unchecked\")\n    protected final boolean equalParameters( Parameters other ) {\n        if (this==other) return true;\n\n        for ( Iterator i = this.getParameterNames(); i.hasNext();) {\n            String pname = (String) i.next();\n\n            String p1 = this.getParameter( pname );\n            String p2 = other.getParameter( pname );\n\n            // getting them based on this.getParameterNames. Note that p1 may be null\n            // if this is a name-only parameter like rport or lr.\n            if (p1 == null ^ p2 == null) return false;\n            else if (p1 != null && !p1.equalsIgnoreCase(p2) ) return false;\n        }\n\n        // Also compare other's parameters; some duplicate testing here...\n        for ( Iterator i = other.getParameterNames(); i.hasNext();) {\n            String pname = (String) i.next();\n\n            String p1 = other.getParameter( pname );\n            String p2 = this.getParameter( pname );\n\n                // assert( p1 != null );\n            // if ( p1 == null ) throw new RuntimeException(\"Assertion check failed!\");\n            // if (p2==null) return false;\n\n            // getting them based on this.getParameterNames. Note that p1 may be null\n            // if this is a name-only parameter like rport or lr.\n\n            if (p1 == null ^ p2 == null) return false;\n            else if (p1 != null && !p1.equalsIgnoreCase(p2) ) return false;\n        }\n\n        return true;\n    }\n    \n    \n    // ----------- Abstract methods --------------\n    protected abstract String encodeBody();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Priority.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * the Priority header.\n *\n * @author Olivier Deruelle <br/>\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:33 $\n *\n *\n *\n */\npublic class Priority extends SIPHeader implements PriorityHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 3837543366074322106L;\n\n    /** constant EMERGENCY field\n    */\n    public static final String EMERGENCY = ParameterNames.EMERGENCY;\n\n    /** constant URGENT field\n     */\n    public static final String URGENT = ParameterNames.URGENT;\n\n    /** constant NORMAL field\n     */\n    public static final String NORMAL = ParameterNames.NORMAL;\n\n    /** constant NON_URGENT field\n     */\n    public static final String NON_URGENT = ParameterNames.NON_URGENT;\n    /** priority field\n     */\n    protected String priority;\n\n    /** Default constructor\n     */\n    public Priority() {\n        super(NAME);\n    }\n\n    /**\n     * Encode into canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return priority;\n    }\n\n    /**\n     * get the priority value.\n     * @return String\n     */\n    public String getPriority() {\n        return priority;\n    }\n\n    /**\n     * Set the priority member\n     * @param p String to set\n     */\n    public void setPriority(String p) throws ParseException {\n        if (p == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception,\"\n                    + \"Priority, setPriority(), the priority parameter is null\");\n        priority = p;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Protocol.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\n/**\n *  Protocol name and version.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:33 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class Protocol extends SIPObject {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 2216758055974073280L;\n\n    /** protocolName field\n     */\n    protected String protocolName;\n\n    /** protocolVersion field\n     */\n    protected String protocolVersion;\n\n    /** transport field\n     */\n    protected String transport;\n\n    /**\n     * Return canonical form.\n     * @return String\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        buffer.append(protocolName.toUpperCase())\n                .append(SLASH)\n                .append(protocolVersion)\n                .append(SLASH)\n                .append(transport.toUpperCase());\n\n        return buffer;\n    }\n\n    /** get the protocol name\n     * @return String\n     */\n    public String getProtocolName() {\n        return protocolName;\n    }\n\n    /** get the protocol version\n     * @return String\n     */\n    public String getProtocolVersion() {\n        return protocolVersion;\n    }\n\n    /**\n     * Get the protocol name + version\n     * JvB: This is what is returned in the ViaHeader interface for 'getProtocol()'\n     *\n     * @return String : protocolname + '/' + version\n     */\n    public String getProtocol() {\n        return protocolName + '/' + protocolVersion;\n    }\n\n    public void setProtocol( String name_and_version ) throws ParseException {\n        int slash = name_and_version.indexOf('/');\n        if (slash>0) {\n            this.protocolName = name_and_version.substring(0,slash);\n            this.protocolVersion = name_and_version.substring( slash+1 );\n        } else throw new ParseException( \"Missing '/' in protocol\", 0 );\n    }\n\n    /** get the transport\n     * @return String\n     */\n    public String getTransport() {\n        return transport;\n    }\n\n    /**\n         * Set the protocolName member\n         * @param p String to set\n         */\n    public void setProtocolName(String p) {\n        protocolName = p;\n    }\n\n    /**\n         * Set the protocolVersion member\n         * @param p String to set\n         */\n    public void setProtocolVersion(String p) {\n        protocolVersion = p;\n    }\n\n    /**\n         * Set the transport member\n         * @param t String to set\n         */\n    public void setTransport(String t) {\n        transport = t;\n    }\n\n    /**\n    * Default constructor.\n    */\n    public Protocol() {\n        protocolName = \"SIP\";\n        protocolVersion = \"2.0\";\n        transport = \"UDP\";\n    }\n}\n/*\n * $Log: Protocol.java,v $\n * Revision 1.8  2009/07/17 18:57:33  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2007/02/12 15:19:23  belangery\n * Changed the encode() and encodeBody() methods of SIP headers and basic classes to make them use the same StringBuffer instance during the encoding phase.\n *\n * Revision 1.6  2006/07/13 09:01:24  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2005/10/09 18:47:53  jeroen\n * defined equals() in terms of API calls\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ProxyAuthenticate.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.address.URI;\nimport javax2.sip.header.*;\n/**\n * Proxy Authenticate SIP (HTTP ) header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:33 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class ProxyAuthenticate\n    extends AuthenticationHeader\n    implements ProxyAuthenticateHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 3826145955463251116L;\n\n    /**\n     * Default Constructor\n     */\n    public ProxyAuthenticate() {\n        super(NAME);\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AuthenticationHeader#getURI()\n     *\n     * @since 1.2 this method is deprecated, uri is not a valid paramter for this header\n     * Fail silently for backwards compatibility\n     */\n    public URI getURI() {\n        return null;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AuthenticationHeader#setURI(javax2.sip.address.URI)\n     *\n     * @since 1.2 this method is deprecated, uri is not a valid paramter for this header\n     * Fail silently for backwards compatibility\n     */\n    public void setURI(URI uri) {\n        // empty, fail silently\n    }\n\n}\n/*\n * $Log: ProxyAuthenticate.java,v $\n * Revision 1.5  2009/07/17 18:57:33  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:19  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2005/10/09 10:50:06  jeroen\n * get/setURI is deprecated for WWW-Authenticate and Proxy-Authenticate,\n * but not for other AAA related headers\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ProxyAuthenticateList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\n/**\n * List of ProxyAuthenticate headers.\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:34 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ProxyAuthenticateList extends SIPHeaderList<ProxyAuthenticate> {\n\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1L;\n\n    public Object clone() {\n        ProxyAuthenticateList retval = new ProxyAuthenticateList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default constructor\n     */\n    public ProxyAuthenticateList() {\n        super(ProxyAuthenticate.class, ProxyAuthenticateHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ProxyAuthorization.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\n/**\n * ProxyAuthorization Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:34 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class ProxyAuthorization\n    extends AuthenticationHeader\n    implements ProxyAuthorizationHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6374966905199799098L;\n\n    /** default constructor\n     */\n    public ProxyAuthorization() {\n        super(PROXY_AUTHORIZATION);\n    }\n\n}\n/*\n * $Log: ProxyAuthorization.java,v $\n * Revision 1.5  2009/07/17 18:57:34  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:46  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ProxyAuthorizationList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\n/**\n * List of ProxyAuthorization headers.\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:34 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ProxyAuthorizationList extends SIPHeaderList<ProxyAuthorization>{\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -1L;\n\n    public Object clone() {\n        ProxyAuthorizationList retval = new ProxyAuthorizationList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default constructor\n     */\n    public ProxyAuthorizationList() {\n        super(ProxyAuthorization.class, ProxyAuthorizationHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ProxyRequire.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * ProxyRequire Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:34 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class ProxyRequire extends SIPHeader implements ProxyRequireHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3269274234851067893L;\n    /**\n     * Optiontag field\n     */\n    protected String optionTag;\n\n    /**\n     * Default  Constructor\n     */\n    public ProxyRequire() {\n        super(PROXY_REQUIRE);\n    }\n\n    /** Constructor\n     * @param s String to set\n     */\n    public ProxyRequire(String s) {\n        super(PROXY_REQUIRE);\n        optionTag = s;\n    }\n\n    /**\n     * Encode in canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return optionTag;\n    }\n\n    /**\n     * Sets the option tag value to the new supplied <var>optionTag</var>\n     * parameter.\n     *\n     * @param optionTag - the new string value of the option tag.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the optionTag value.\n     */\n    public void setOptionTag(String optionTag) throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(\"JAIN-SIP Exception, ProxyRequire, setOptionTag(), the optionTag parameter is null\");\n        this.optionTag = optionTag;\n    }\n\n    /**\n     * Gets the option tag of this OptionTag class.\n     *\n     * @return the string that identifies the option tag value.\n     */\n    public String getOptionTag() {\n        return optionTag;\n    }\n}\n/*\n * $Log: ProxyRequire.java,v $\n * Revision 1.5  2009/07/17 18:57:34  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:26  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ProxyRequireList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * Proxy Require SIPSIPObject (list of option tags)\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:34 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ProxyRequireList extends SIPHeaderList<ProxyRequire> {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 5648630649476486042L;\n\n    public Object clone() {\n        ProxyRequireList retval = new ProxyRequireList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default Constructor\n     */\n    public ProxyRequireList() {\n        super(ProxyRequire.class, ProxyRequireHeader.NAME);\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RAck.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\nimport java.text.ParseException;\n\n/**\n * RAck SIP Header implementation\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:34 $\n *\n * @author M. Ranganathan <br/>\n *\n *\n */\npublic class RAck extends SIPHeader implements javax2.sip.header.RAckHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 743999286077404118L;\n\n    protected long cSeqNumber;\n\n    protected long rSeqNumber;\n\n    protected String method;\n\n    /** Creates a new instance of RAck */\n    public RAck() {\n        super(NAME);\n    }\n\n    /**\n     * Encode the body of this header (the stuff that follows headerName). A.K.A\n     * headerValue.\n     *\n     */\n    protected String encodeBody() {\n        // Bug reported by Bruno Konik - was encoded in\n        // the wrong order.\n        return new StringBuffer().append(rSeqNumber).append(SP).append(\n                cSeqNumber).append(SP).append(method).toString();\n\n    }\n\n    /**\n     * Gets the CSeq sequence number of this RAckHeader.\n     *\n     * @deprecated\n     * @return the integer value of the cSeq number of the RAckHeader\n     */\n    public int getCSeqNumber() {\n        return (int) cSeqNumber;\n    }\n\n    /**\n     * Gets the CSeq sequence number of this RAckHeader.\n     *\n     * @return the integer value of the cSeq number of the RAckHeader\n     */\n    public long getCSeqNumberLong() {\n        return cSeqNumber;\n    }\n\n    /**\n     * Gets the method of RAckHeader\n     *\n     * @return method of RAckHeader\n     */\n    public String getMethod() {\n        return this.method;\n    }\n\n    /**\n     * Gets the RSeq sequence number of this RAckHeader.\n     *\n     * @deprecated\n     * @return the integer value of the RSeq number of the RAckHeader\n     */\n    public int getRSeqNumber() {\n        return (int) rSeqNumber;\n    }\n\n    /**\n     * @deprecated\n     * @see javax2.sip.header.RAckHeader#setCSeqNumber(int)\n     */\n    public void setCSeqNumber(int cSeqNumber) throws InvalidArgumentException {\n        this.setCSequenceNumber(cSeqNumber);\n    }\n\n    public void setMethod(String method) throws ParseException {\n        this.method = method;\n    }\n\n\n    public long getCSequenceNumber() {\n        return this.cSeqNumber;\n    }\n\n    public long getRSequenceNumber() {\n        return this.rSeqNumber;\n    }\n\n    public void setCSequenceNumber(long cSeqNumber)\n            throws InvalidArgumentException {\n        if (cSeqNumber <= 0 || cSeqNumber > ((long) 1) << 32 - 1)\n            throw new InvalidArgumentException(\"Bad CSeq # \" + cSeqNumber);\n        this.cSeqNumber = cSeqNumber;\n\n    }\n\n    /**\n     *@deprecated\n     * @see javax2.sip.header.RAckHeader#setRSeqNumber(int)\n     */\n    public void setRSeqNumber(int rSeqNumber) throws InvalidArgumentException {\n        this.setRSequenceNumber(rSeqNumber);\n    }\n\n\n    public void setRSequenceNumber(long rSeqNumber)\n            throws InvalidArgumentException {\n        if (rSeqNumber <= 0 || cSeqNumber > ((long) 1) << 32 - 1)\n            throw new InvalidArgumentException(\"Bad rSeq # \" + rSeqNumber);\n        this.rSeqNumber = rSeqNumber;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RSeq.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:35 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class RSeq extends SIPHeader implements javax2.sip.header.RSeqHeader {\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 8765762413224043394L;\n    protected long sequenceNumber;\n\n    /** Creates a new instance of RSeq */\n    public RSeq() {\n        super(NAME);\n    }\n\n    /** Gets the sequence number of this RSeqHeader.\n     * @deprecated\n     * @return the integer value of the Sequence number of the RSeqHeader\n     */\n    public int getSequenceNumber() {\n        return (int)this.sequenceNumber;\n    }\n\n\n    /** Encode the body of this header (the stuff that follows headerName).\n     * A.K.A headerValue.\n     */\n    protected String encodeBody() {\n        return Long.toString(this.sequenceNumber);\n    }\n\n    public long getSeqNumber() {\n        return this.sequenceNumber;\n    }\n\n    public void setSeqNumber(long sequenceNumber) throws InvalidArgumentException {\n\n            if (sequenceNumber <= 0 ||sequenceNumber > ((long)1)<<32 - 1)\n                throw new InvalidArgumentException(\n                    \"Bad seq number \" + sequenceNumber);\n            this.sequenceNumber = sequenceNumber;\n\n    }\n\n    /**\n     * @deprecated\n     * @see javax2.sip.header.RSeqHeader#setSequenceNumber(int)\n     */\n    public void setSequenceNumber(int sequenceNumber) throws InvalidArgumentException {\n        this.setSeqNumber(sequenceNumber);\n\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Reason.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*\n * Reason.java\n * Reason            =  \"Reason\" HCOLON reason-value *(COMMA reason-value)\n * reason-value      =  protocol *(SEMI reason-params)\n * protocol          =  \"SIP\" / \"Q.850\" / token\n * reason-params     =  protocol-cause / reason-text\n *                     / reason-extension\n * protocol-cause    =  \"cause\" EQUAL cause\n * cause             =  1*DIGIT\n * reason-text       =  \"text\" EQUAL quoted-string\n * reason-extension  =  generic-param\n */\n\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.Utils;\n\nimport java.text.ParseException;\n\n/**\n * Definition of the Reason SIP Header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/18 13:46:34 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class Reason\n    extends ParametersHeader\n    implements javax2.sip.header.ReasonHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -8903376965568297388L;\n    public final String TEXT = ParameterNames.TEXT;\n    public final String CAUSE = ParameterNames.CAUSE;\n\n    protected String protocol;\n\n    /** Get the cause token.\n     *@return the cause code.\n     */\n    public int getCause() {\n        return getParameterAsInt(CAUSE);\n    }\n\n    /**\n     * Set the cause.\n     *\n     *@param cause - cause to set.\n     */\n    public void setCause(int cause) throws javax2.sip.InvalidArgumentException {\n        this.parameters.set(\"cause\", Integer.valueOf(cause));\n    }\n\n    /** Set the protocol\n     *\n     *@param protocol - protocol to set.\n     */\n\n    public void setProtocol(String protocol) throws ParseException {\n        this.protocol = protocol;\n    }\n\n    /** Return the protocol.\n     *\n     *@return the protocol.\n     */\n    public String getProtocol() {\n        return this.protocol;\n    }\n\n    /** Set the text.\n     *\n     *@param text -- string text to set.\n     */\n    public void setText(String text) throws ParseException {\n        // JvB: MUST be quoted\n        if ( text.charAt(0) != '\"' ) {\n            text = Utils.getQuotedString(text);\n        }\n        this.parameters.set(\"text\", text);\n    }\n\n    /** Get the text.\n     *\n     *@return text parameter.\n     *\n     */\n    public String getText() {\n        return this.parameters.getParameter(\"text\");\n    }\n\n    /** Set the cause.\n\n    /** Creates a new instance of Reason */\n    public Reason() {\n        super(NAME);\n    }\n\n    /** Gets the unique string name of this Header. A name constant is defined in\n     * each individual Header identifying each Header.\n     *\n     * @return the name of this specific Header\n     */\n    public String getName() {\n        return NAME;\n\n    }\n\n    /**\n     * Encode the body of this header (the stuff that follows headerName).\n     * A.K.A headerValue.\n     */\n    protected String encodeBody() {\n        StringBuffer s = new StringBuffer();\n        s.append(protocol);\n        if (parameters != null && !parameters.isEmpty())\n            s.append(SEMICOLON).append(parameters.encode());\n        return s.toString();\n    }\n\n}\n/*\n * $Log: Reason.java,v $\n * Revision 1.8  2009/10/18 13:46:34  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.7  2009/07/17 18:57:35  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2008/11/19 10:56:27  jbemmel\n * Ensure that reason text is quoted\n *\n * Revision 1.5  2006/11/01 02:22:56  mranga\n * Issue number:  83\n * Obtained from:\n * Submitted by:\n * Reviewed by:   mranga\n * fix thread safety issue in NameValueList and clean up some mess.\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/07/13 09:01:19  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ReasonList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.List;\n\nimport javax2.sip.header.*;\n\n/**\n * List of Reason headers.\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic final class ReasonList extends SIPHeaderList<Reason> {\n\n    private static final long serialVersionUID = 7459989997463160670L;\n\n    public Object clone() {\n        ReasonList retval = new ReasonList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default constructor\n     */\n    public ReasonList() {\n        super(Reason.class, ReasonHeader.NAME);\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RecordRoute.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.address.*;\n\n/**\n * The Request-Route header is added to a request by any proxy that insists on\n * being in the path of subsequent requests for the same call leg.\n *\n *@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $\n *\n *@author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class RecordRoute\n    extends AddressParametersHeader\n    implements javax2.sip.header.RecordRouteHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 2388023364181727205L;\n\n    /**\n     * constructor\n     * @param address address to set\n     */\n    public RecordRoute(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * default constructor\n     */\n    public RecordRoute() {\n        super(RECORD_ROUTE);\n\n    }\n\n    /** Encode into canonical form.\n     *@return String containing the canonicaly encoded header.\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            buffer.append(LESS_THAN);\n        }\n        address.encode(buffer);\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            buffer.append(GREATER_THAN);\n        }\n\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            this.parameters.encode(buffer);\n        }\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RecordRouteList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * RecordRoute List of SIP headers (a collection of Addresses)\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class RecordRouteList extends SIPHeaderList<RecordRoute>  {\n\n    private static final long serialVersionUID = 1724940469426766691L;\n    public Object clone() {\n        RecordRouteList retval = new RecordRouteList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n    /** Default constructor\n     */\n    public RecordRouteList() {\n        super(RecordRoute.class, RecordRouteHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ReferTo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.address.*;\n\n/**\n * ReferTo SIP Header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:35 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic final class ReferTo\n    extends AddressParametersHeader\n    implements javax2.sip.header.ReferToHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -1666700428440034851L;\n\n    /** default Constructor.\n     */\n    public ReferTo() {\n        super(NAME);\n    }\n\n    /**\n     * Encode the header content into a String.\n     * @return String\n     */\n    protected String encodeBody() {\n        if (address == null)\n            return null;\n        String retval = \"\";\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval += LESS_THAN;\n        }\n        retval += address.encode();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval += GREATER_THAN;\n        }\n\n        if (!parameters.isEmpty()) {\n            retval += SEMICOLON + parameters.encode();\n        }\n        return retval;\n    }\n}\n/*\n * $Log: ReferTo.java,v $\n * Revision 1.6  2009/07/17 18:57:35  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.5  2006/07/13 09:01:40  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.3  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ReplyTo.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.address.*;\n\nimport javax2.sip.header.*;\n\n/**\n * ReplyTo Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:36 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic final class ReplyTo\n    extends AddressParametersHeader\n    implements ReplyToHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -9103698729465531373L;\n\n    /** Default constructor\n     */\n    public ReplyTo() {\n        super(NAME);\n    }\n\n    /** Default constructor given an address.\n     *\n     *@param address -- address of this header.\n     *\n     */\n    public ReplyTo(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * Encode the header into a String.\n     * @return String\n     */\n    public String encode() {\n        return headerName + COLON + SP + encodeBody() + NEWLINE;\n    }\n\n    /**\n     * Encode the header content into a String.\n     * @return String\n     */\n    public String encodeBody() {\n        String retval = \"\";\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval += LESS_THAN;\n        }\n        retval += address.encode();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval += GREATER_THAN;\n        }\n        if (!parameters.isEmpty()) {\n            retval += SEMICOLON + parameters.encode();\n        }\n        return retval;\n    }\n\n    /**\n     * Conveniance accessor function to get the hostPort field from the address\n     * @return HostPort\n     */\n    public HostPort getHostPort() {\n        return address.getHostPort();\n    }\n\n    /**\n     * Get the display name from the address.\n     * @return String\n     */\n    public String getDisplayName() {\n        return address.getDisplayName();\n    }\n}\n/*\n * $Log: ReplyTo.java,v $\n * Revision 1.5  2009/07/17 18:57:36  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:31  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RequestLine.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.address.URI;\n\nimport gov2.nist.javax2.sip.address.*;\n\n/**\n * RequestLine of SIP Request.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/09/15 02:55:27 $\n * @author M. Ranganathan\n */\npublic class RequestLine extends SIPObject implements SipRequestLine {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3286426172326043129L;\n\n    /** uri field. Note that this can be a SIP URI or a generic URI\n    * like tel URI.\n     */\n    protected GenericURI uri;\n\n    /** method field.\n     */\n    protected String method;\n\n    /** sipVersion field\n     */\n    protected String sipVersion;\n\n    /** Default constructor\n     */\n    public RequestLine() {\n        sipVersion = \"SIP/2.0\";\n    }\n\n   \n    /** Encode the request line as a String.\n    *\n     * @return requestLine encoded as a string.\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (method != null) {\n            buffer.append(method);\n            buffer.append(SP);\n        }\n        if (uri != null) {\n            uri.encode(buffer);\n            buffer.append(SP);\n        }\n        buffer.append(sipVersion);\n        buffer.append(NEWLINE);\n        return buffer;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#getUri()\n     */\n    public GenericURI getUri() {\n        return uri;\n    }\n\n    /** Constructor given the request URI and the method.\n    */\n    public RequestLine(GenericURI requestURI, String method) {\n        this.uri = requestURI;\n        this.method = method;\n        this.sipVersion = \"SIP/2.0\";\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#getMethod()\n     */\n    public String getMethod() {\n        return method;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#getSipVersion()\n     */\n    public String getSipVersion() {\n        return sipVersion;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#setUri(gov2.nist.javax2.sip.address.GenericURI)\n     */\n    public void setUri(URI uri) {\n        this.uri = (GenericURI)uri;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#setMethod(java.lang.String)\n     */\n    public void setMethod(String method) {\n        this.method = method;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#setSipVersion(java.lang.String)\n     */\n    public void setSipVersion(String version) {\n        this.sipVersion = version;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#getVersionMajor()\n     */\n    public String getVersionMajor() {\n        if (sipVersion == null)\n            return null;\n        String major = null;\n        boolean slash = false;\n        for (int i = 0; i < sipVersion.length(); i++) {\n            if (sipVersion.charAt(i) == '.')\n                break;\n            if (slash) {\n                if (major == null)\n                    major = \"\" + sipVersion.charAt(i);\n                else\n                    major += sipVersion.charAt(i);\n            }\n            if (sipVersion.charAt(i) == '/')\n                slash = true;\n        }\n        return major;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipRequestLine#getVersionMinor()\n     */\n    public String getVersionMinor() {\n        if (sipVersion == null)\n            return null;\n        String minor = null;\n        boolean dot = false;\n        for (int i = 0; i < sipVersion.length(); i++) {\n            if (dot) {\n                if (minor == null)\n                    minor = \"\" + sipVersion.charAt(i);\n                else\n                    minor += sipVersion.charAt(i);\n            }\n            if (sipVersion.charAt(i) == '.')\n                dot = true;\n        }\n        return minor;\n    }\n\n    /**\n    * Compare for equality.\n    *\n    *@param other object to compare with. We assume that all fields\n    * are set.\n    */\n    public boolean equals(Object other) {\n        boolean retval;\n        if (!other.getClass().equals(this.getClass())) {\n            return false;\n        }\n        RequestLine that = (RequestLine) other;\n        try {\n            retval =\n                this.method.equals(that.method)\n                    && this.uri.equals(that.uri)\n                    && this.sipVersion.equals(that.sipVersion);\n        } catch (NullPointerException ex) {\n            retval = false;\n        }\n        return retval;\n    }\n\n    public Object clone() {\n        RequestLine retval = (RequestLine) super.clone();\n        if (this.uri != null)\n            retval.uri = (GenericURI) this.uri.clone();\n        return retval;\n    }\n}\n/*\n * $Log: RequestLine.java,v $\n * Revision 1.8  2009/09/15 02:55:27  mranga\n * Issue number:  222\n * Add HeaderFactoryExt.createStatusLine(String) and HeaderFactoryExt.createRequestLine(String)\n * Allows users to easily parse SipFrag bodies (for example NOTIFY bodies\n * during call transfer).\n *\n * Revision 1.7  2009/07/17 18:57:36  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2007/02/12 15:19:23  belangery\n * Changed the encode() and encodeBody() methods of SIP headers and basic classes to make them use the same StringBuffer instance during the encoding phase.\n *\n * Revision 1.5  2006/07/13 09:01:26  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.3  2005/04/16 20:38:50  dmuresan\n * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Require.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n/**\n * Require SIP Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:36 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n */\npublic class Require extends SIPHeader implements RequireHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3743425404884053281L;\n    /** optionTag field\n     */\n    protected String optionTag;\n\n    /**\n     * Default constructor\n     */\n    public Require() {\n        super(REQUIRE);\n    }\n\n    /** constructor\n     * @param s String to set\n     */\n    public Require(String s) {\n        super(REQUIRE);\n        optionTag = s;\n    }\n\n    /**\n     * Encode in canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return optionTag;\n    }\n\n    /**\n     * Sets the option tag value to the new supplied <var>optionTag</var>\n     * parameter.\n     *\n     * @param optionTag - the new string value of the option tag.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the optionTag value.\n     */\n    public void setOptionTag(String optionTag) throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, Require, \"\n                    + \"setOptionTag(), the optionTag parameter is null\");\n        this.optionTag = optionTag;\n    }\n\n    /**\n     * Gets the option tag of this OptionTag class.\n     *\n     * @return the string that identifies the option tag value.\n     */\n    public String getOptionTag() {\n        return optionTag;\n    }\n}\n/*\n * $Log: Require.java,v $\n * Revision 1.5  2009/07/17 18:57:36  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:22  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RequireList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\n/**\n * List of Require headers.\n * <pre>\n * Require  =  \"Require\" \":\" 1#option-tag\n * </pre>\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:36 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic final class RequireList extends SIPHeaderList<Require> {\n\n\n    private static final long serialVersionUID = -1760629092046963213L;\n\n    public Object clone() {\n        RequireList retval = new RequireList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default constructor\n     */\n    public RequireList() {\n        super(Require.class, RequireHeader.NAME);\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RetryAfter.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\nimport javax2.sip.header.*;\n\n/**\n * Retry-After SIP Header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/11/04 17:35:55 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n */\npublic class RetryAfter extends ParametersHeader implements RetryAfterHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -1029458515616146140L;\n\n    /** constant DURATION parameter.\n     */\n    public static final String DURATION = ParameterNames.DURATION;\n\n    /** duration field\n     */\n    protected Integer retryAfter = new Integer(0);\n\n    /** comment field\n     */\n    protected String comment;\n\n    /** Default constructor\n     */\n    public RetryAfter() {\n        super(NAME);\n    }\n\n    /** Encode body of this into cannonical form.\n     * @return encoded body\n     */\n    public String encodeBody() {\n        StringBuffer s = new StringBuffer();\n        \n        if (retryAfter != null)\n            s.append(retryAfter);\n\n        if (comment != null)\n            s.append(SP + LPAREN + comment + RPAREN);\n\n        if (!parameters.isEmpty()) {\n            s.append(SEMICOLON + parameters.encode());\n        }\n\n        return s.toString();\n    }\n\n    /** Boolean function\n     * @return true if comment exist, false otherwise\n     */\n    public boolean hasComment() {\n        return comment != null;\n    }\n\n    /** remove comment field\n     */\n    public void removeComment() {\n        comment = null;\n    }\n\n    /** remove duration field\n     */\n    public void removeDuration() {\n        super.removeParameter(DURATION);\n    }\n\n    /**\n     * Sets the retry after value of the RetryAfterHeader.\n     * The retry after value MUST be greater than zero and\n     * MUST be less than 2**31.\n     *\n     * @param retryAfter - the new retry after value of this RetryAfterHeader\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     *\n     */\n\n    public void setRetryAfter(int retryAfter) throws InvalidArgumentException {\n        if (retryAfter < 0)\n            throw new InvalidArgumentException(\n                \"invalid parameter \" + retryAfter);\n        this.retryAfter = Integer.valueOf(retryAfter);\n    }\n\n    /**\n     * Gets the retry after value of the RetryAfterHeader. This retry after\n     * value is relative time.\n     *\n     * @return the retry after value of the RetryAfterHeader.\n     *\n     */\n\n    public int getRetryAfter() {\n        return retryAfter.intValue();\n    }\n\n    /**\n     * Gets the comment of RetryAfterHeader.\n     *\n     * @return the comment of this RetryAfterHeader, return null if no comment\n     * is available.\n     */\n\n    public String getComment() {\n        return comment;\n    }\n\n    /**\n     * Sets the comment value of the RetryAfterHeader.\n     *\n     * @param comment - the new comment string value of the RetryAfterHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the comment.\n     */\n\n    public void setComment(String comment) throws ParseException {\n        if (comment == null)\n            throw new NullPointerException(\"the comment parameter is null\");\n        this.comment = comment;\n    }\n\n    /**\n     * Sets the duration value of the RetryAfterHeader. The retry after value\n     * MUST be greater than zero and MUST be less than 2**31.\n     *\n     * @param duration - the new duration value of this RetryAfterHeader\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     *\n     */\n\n    public void setDuration(int duration) throws InvalidArgumentException {\n        if (duration < 0)\n            throw new InvalidArgumentException(\"the duration parameter is <0\");\n        this.setParameter(DURATION, duration);\n    }\n\n    /**\n     * Gets the duration value of the RetryAfterHeader. This duration value\n     * is relative time.\n     *\n     * @return the duration value of the RetryAfterHeader, return zero if not\n     * set.\n     *\n     */\n\n    public int getDuration() {\n      if (this.getParameter(DURATION) == null) return -1;\n      else return super.getParameterAsInt(DURATION);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Route.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\n\nimport javax2.sip.header.RouteHeader;\n\n/**\n * Route  SIPHeader Object\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:36 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class Route\n    extends AddressParametersHeader\n    implements javax2.sip.header.RouteHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 5683577362998368846L;\n\n    /** Default constructor\n     */\n    public Route() {\n        super(NAME);\n    }\n\n    /** Default constructor given an address.\n     *\n     *@param address -- address of this header.\n     *\n     */\n\n    public Route(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * Hashcode so this header can be inserted into a set.\n     *\n     *@return the hashcode of the encoded address.\n     */\n    public int hashCode() {\n        return this.address.getHostPort().encode().toLowerCase().hashCode();\n    }\n\n    /**\n     * Encode into canonical form.\n     * Acknowledgement: contains a bug fix for a bug reported by\n     * Laurent Schwizer\n     *\n     *@return a canonical encoding of the header.\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        boolean addrFlag = address.getAddressType() == AddressImpl.NAME_ADDR;\n        if (!addrFlag) {\n            buffer.append('<');\n            address.encode(buffer);\n            buffer.append('>');\n        } else {\n            address.encode(buffer);\n        }\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n        return buffer;\n    }\n\n    public boolean equals(Object other) {\n        return (other instanceof RouteHeader) && super.equals(other);\n    }\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/RouteList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.util.*;\n\n/**\n * A list of Route Headers.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:36 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class RouteList extends SIPHeaderList<Route> {\n\n    private static final long serialVersionUID = 3407603519354809748L;\n\n\n    /** default constructor\n     */\n    public RouteList() {\n        super(Route.class, RouteHeader.NAME);\n\n    }\n\n    public Object clone() {\n        RouteList retval = new RouteList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    public String encode() {\n        if ( super.hlist.isEmpty()) return \"\";\n        else return super.encode();\n    }\n\n\n    /**\n    * Order is important when comparing route lists.\n    */\n    public boolean equals(Object other) {\n        if (!(other instanceof RouteList))\n            return false;\n        RouteList that = (RouteList) other;\n        if (this.size() != that.size())\n            return false;\n        ListIterator<Route> it = this.listIterator();\n        ListIterator<Route> it1 = that.listIterator();\n        while (it.hasNext()) {\n            Route route = (Route) it.next();\n            Route route1 = (Route) it1.next();\n            if (!route.equals(route1))\n                return false;\n        }\n        return true;\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPDate.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.core.*;\n\nimport java.util.Calendar;\nimport java.util.TimeZone;\nimport java.util.Locale;\nimport java.util.GregorianCalendar;\nimport java.io.Serializable;\nimport java.lang.IllegalArgumentException;\n\n/**\n* Implements a parser class for tracking expiration time\n* when specified as a Date value.\n*<pre>\n* From the HTTP 1.1 spec\n*14.18 Date\n*\n*   The Date general-header field represents the date and time at which\n*   the message was originated, having the same semantics as orig-date in\n*   RFC 822. The field value is an HTTP-date, as described in section\n*   3.3.1; it MUST be sent in RFC 1123 [8]-date format.\n\n*       Date  = \"Date\" \":\" HTTP-date\n*\n*   An example is\n*\n*       Date: Tue, 15 Nov 1994 08:12:31 GMT\n*</pre>\n*\n*@version 1.2 $Revision: 1.9 $ $Date: 2009/10/18 13:46:33 $\n*\n*@author M. Ranganathan   <br/>\n*\n*\n*\n*\n*/\n\npublic class SIPDate implements Cloneable,Serializable {\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 8544101899928346909L;\n    public static final String GMT = \"GMT\";\n    public static final String MON = \"Mon\";\n    public static final String TUE = \"Tue\";\n    public static final String WED = \"Wed\";\n    public static final String THU = \"Thu\";\n    public static final String FRI = \"Fri\";\n    public static final String SAT = \"Sat\";\n    public static final String SUN = \"Sun\";\n    public static final String JAN = \"Jan\";\n    public static final String FEB = \"Feb\";\n    public static final String MAR = \"Mar\";\n    public static final String APR = \"Apr\";\n    public static final String MAY = \"May\";\n    public static final String JUN = \"Jun\";\n    public static final String JUL = \"Jul\";\n    public static final String AUG = \"Aug\";\n    public static final String SEP = \"Sep\";\n    public static final String OCT = \"Oct\";\n    public static final String NOV = \"Nov\";\n    public static final String DEC = \"Dec\";\n\n    /** sipWkDay member\n     */\n    protected String sipWkDay;\n\n    /** sipMonth member\n    */\n    protected String sipMonth;\n\n    /** wkday member\n    */\n    protected int wkday;\n\n    /** day member\n    */\n    protected int day;\n\n    /** month member\n    */\n    protected int month;\n\n    /** year member\n    */\n    protected int year;\n\n    /** hour member\n    */\n    protected int hour;\n\n    /** minute member\n    */\n    protected int minute;\n\n    /** second member\n    */\n    protected int second;\n\n    /** javaCal member\n    */\n    private java.util.Calendar javaCal;\n\n    /** equality check.\n     *\n     *@return true if the two date fields are equals\n     */\n    public boolean equals(Object that){\n        if (that.getClass() != this.getClass())return false;\n        SIPDate other = (SIPDate)that;\n        return this.wkday == other.wkday &&\n        this.day == other.day &&\n        this.month == other.month &&\n        this.year == other.year &&\n        this.hour == other.hour &&\n        this.minute == other.minute &&\n        this.second == other.second;\n    }\n\n    /**\n     * Initializer, sets all the fields to invalid values.\n     */\n    public SIPDate() {\n        wkday = -1;\n        day = -1;\n        month = -1;\n        year = -1;\n        hour = -1;\n        minute = -1;\n        second = -1;\n        javaCal = null;\n    }\n\n    /**\n     * Construct a SIP date from the time offset given in miliseconds\n     * @param timeMillis long to set\n     */\n    public SIPDate(long timeMillis) {\n        javaCal =\n            new GregorianCalendar(\n                TimeZone.getTimeZone(\"GMT:0\"),\n                Locale.getDefault());\n        java.util.Date date = new java.util.Date(timeMillis);\n        javaCal.setTime(date);\n        wkday = javaCal.get(Calendar.DAY_OF_WEEK);\n        switch (wkday) {\n            case Calendar.MONDAY :\n                sipWkDay = MON;\n                break;\n            case Calendar.TUESDAY :\n                sipWkDay = TUE;\n                break;\n            case Calendar.WEDNESDAY :\n                sipWkDay = WED;\n                break;\n            case Calendar.THURSDAY :\n                sipWkDay = THU;\n                break;\n            case Calendar.FRIDAY :\n                sipWkDay = FRI;\n                break;\n            case Calendar.SATURDAY :\n                sipWkDay = SAT;\n                break;\n            case Calendar.SUNDAY :\n                sipWkDay = SUN;\n                break;\n            default :\n                InternalErrorHandler.handleException(\n                    \"No date map for wkday \" + wkday);\n        }\n\n        day = javaCal.get(Calendar.DAY_OF_MONTH);\n        month = javaCal.get(Calendar.MONTH);\n        switch (month) {\n            case Calendar.JANUARY :\n                sipMonth = JAN;\n                break;\n            case Calendar.FEBRUARY :\n                sipMonth = FEB;\n                break;\n            case Calendar.MARCH :\n                sipMonth = MAR;\n                break;\n            case Calendar.APRIL :\n                sipMonth = APR;\n                break;\n            case Calendar.MAY :\n                sipMonth = MAY;\n                break;\n            case Calendar.JUNE :\n                sipMonth = JUN;\n                break;\n            case Calendar.JULY :\n                sipMonth = JUL;\n                break;\n            case Calendar.AUGUST :\n                sipMonth = AUG;\n                break;\n            case Calendar.SEPTEMBER :\n                sipMonth = SEP;\n                break;\n            case Calendar.OCTOBER :\n                sipMonth = OCT;\n                break;\n            case Calendar.NOVEMBER :\n                sipMonth = NOV;\n                break;\n            case Calendar.DECEMBER :\n                sipMonth = DEC;\n                break;\n            default :\n                InternalErrorHandler.handleException(\n                    \"No date map for month \" + month);\n        }\n        year = javaCal.get(Calendar.YEAR);\n        // Bug report by Bruno Konik\n        hour = javaCal.get(Calendar.HOUR_OF_DAY);\n        minute = javaCal.get(Calendar.MINUTE);\n        second = javaCal.get(Calendar.SECOND);\n    }\n\n    /**\n     * Get canonical string representation.\n     * @return String\n     */\n    public String encode() {\n\n        String dayString;\n        if (day < 10) {\n            dayString = \"0\" + day;\n        } else\n            dayString = \"\" + day;\n\n        String hourString;\n        if (hour < 10) {\n            hourString = \"0\" + hour;\n        } else\n            hourString = \"\" + hour;\n\n        String minuteString;\n        if (minute < 10) {\n            minuteString = \"0\" + minute;\n        } else\n            minuteString = \"\" + minute;\n\n        String secondString;\n        if (second < 10) {\n            secondString = \"0\" + second;\n        } else\n            secondString = \"\" + second;\n\n        String encoding = \"\";\n\n        if (sipWkDay != null)\n            encoding += sipWkDay + Separators.COMMA + Separators.SP;\n\n        encoding += dayString + Separators.SP;\n\n        if (sipMonth != null)\n            encoding += sipMonth + Separators.SP;\n\n        encoding += year\n            + Separators.SP\n            + hourString\n            + Separators.COLON\n            + minuteString\n            + Separators.COLON\n            + secondString\n            + Separators.SP\n            + GMT;\n\n        return encoding;\n    }\n\n    /**\n     * The only accessor we allow is to the java calendar record.\n     * All other fields are for this package only.\n     * @return Calendar\n     */\n    public java.util.Calendar getJavaCal() {\n        if (javaCal == null)\n            setJavaCal();\n        return javaCal;\n    }\n\n    /** get the WkDay field\n     * @return String\n     */\n    public String getWkday() {\n        return sipWkDay;\n    }\n\n    /** get the month\n     * @return String\n     */\n    public String getMonth() {\n        return sipMonth;\n    }\n\n    /** get the hour\n     * @return int\n     */\n    public int getHour() {\n        return hour;\n    }\n\n    /** get the minute\n     * @return int\n     */\n    public int getMinute() {\n        return minute;\n    }\n\n    /** get the second\n     *  @return int\n     */\n    public int getSecond() {\n        return second;\n    }\n\n    /**\n     * convert the SIP Date of this structure to a Java Date.\n     * SIP Dates are forced to be GMT. Stores the converted time\n     * as a java Calendar class.\n     */\n    private void setJavaCal() {\n        javaCal =\n            new GregorianCalendar(\n                TimeZone.getTimeZone(\"GMT:0\"),\n                Locale.getDefault());\n        if (year != -1)\n            javaCal.set(Calendar.YEAR, year);\n        if (day != -1)\n            javaCal.set(Calendar.DAY_OF_MONTH, day);\n        if (month != -1)\n            javaCal.set(Calendar.MONTH, month);\n        if (wkday != -1)\n            javaCal.set(Calendar.DAY_OF_WEEK, wkday);\n        if (hour != -1)\n            javaCal.set(Calendar.HOUR, hour);\n        if (minute != -1)\n            javaCal.set(Calendar.MINUTE, minute);\n        if (second != -1)\n            javaCal.set(Calendar.SECOND, second);\n    }\n\n    /**\n     * Set the wkday member\n     * @param w String to set\n     * @throws IllegalArgumentException if w is not a valid day.\n     */\n    public void setWkday(String w) throws IllegalArgumentException {\n        sipWkDay = w;\n        if (sipWkDay.compareToIgnoreCase(MON) == 0) {\n            wkday = Calendar.MONDAY;\n        } else if (sipWkDay.compareToIgnoreCase(TUE) == 0) {\n            wkday = Calendar.TUESDAY;\n        } else if (sipWkDay.compareToIgnoreCase(WED) == 0) {\n            wkday = Calendar.WEDNESDAY;\n        } else if (sipWkDay.compareToIgnoreCase(THU) == 0) {\n            wkday = Calendar.THURSDAY;\n        } else if (sipWkDay.compareToIgnoreCase(FRI) == 0) {\n            wkday = Calendar.FRIDAY;\n        } else if (sipWkDay.compareToIgnoreCase(SAT) == 0) {\n            wkday = Calendar.SATURDAY;\n        } else if (sipWkDay.compareToIgnoreCase(SUN) == 0) {\n            wkday = Calendar.SUNDAY;\n        } else {\n            throw new IllegalArgumentException(\"Illegal Week day :\" + w);\n        }\n    }\n\n    /**\n     * Set the day member\n     * @param d int to set\n     * @throws IllegalArgumentException if d is not a valid day\n     */\n    public void setDay(int d) throws IllegalArgumentException {\n        if (d < 1 || d > 31)\n            throw new IllegalArgumentException(\n                \"Illegal Day of the month \" + Integer.toString(d));\n        day = d;\n    }\n\n    /**\n     * Set the month member\n     * @param m String to set.\n     * @throws IllegalArgumentException if m is not a valid month\n     */\n    public void setMonth(String m) throws IllegalArgumentException {\n        sipMonth = m;\n        if (sipMonth.compareToIgnoreCase(JAN) == 0) {\n            month = Calendar.JANUARY;\n        } else if (sipMonth.compareToIgnoreCase(FEB) == 0) {\n            month = Calendar.FEBRUARY;\n        } else if (sipMonth.compareToIgnoreCase(MAR) == 0) {\n            month = Calendar.MARCH;\n        } else if (sipMonth.compareToIgnoreCase(APR) == 0) {\n            month = Calendar.APRIL;\n        } else if (sipMonth.compareToIgnoreCase(MAY) == 0) {\n            month = Calendar.MAY;\n        } else if (sipMonth.compareToIgnoreCase(JUN) == 0) {\n            month = Calendar.JUNE;\n        } else if (sipMonth.compareToIgnoreCase(JUL) == 0) {\n            month = Calendar.JULY;\n        } else if (sipMonth.compareToIgnoreCase(AUG) == 0) {\n            month = Calendar.AUGUST;\n        } else if (sipMonth.compareToIgnoreCase(SEP) == 0) {\n            month = Calendar.SEPTEMBER;\n        } else if (sipMonth.compareToIgnoreCase(OCT) == 0) {\n            month = Calendar.OCTOBER;\n        } else if (sipMonth.compareToIgnoreCase(NOV) == 0) {\n            month = Calendar.NOVEMBER;\n        } else if (sipMonth.compareToIgnoreCase(DEC) == 0) {\n            month = Calendar.DECEMBER;\n        } else {\n            throw new IllegalArgumentException(\"Illegal Month :\" + m);\n        }\n    }\n\n    /**\n     * Set the year member\n     * @param y int to set\n     * @throws IllegalArgumentException if y is not a valid year.\n     */\n    public void setYear(int y) throws IllegalArgumentException {\n        if (y < 0)\n            throw new IllegalArgumentException(\"Illegal year : \" + y);\n        javaCal = null;\n        year = y;\n    }\n\n    /**\n    * Get the year member.\n    */\n    public int getYear() {\n        return year;\n    }\n\n    /**\n     * Set the hour member\n     * @param h int to set\n     * @throws IllegalArgumentException if h is not a valid hour.\n     */\n    public void setHour(int h) throws IllegalArgumentException {\n        if (h < 0 || h > 24)\n            throw new IllegalArgumentException(\"Illegal hour : \" + h);\n        javaCal = null;\n        hour = h;\n    }\n\n    /**\n     * Set the minute member\n     * @param m int to set\n     * @throws IllegalArgumentException if m is not a valid minute\n     */\n    public void setMinute(int m) throws IllegalArgumentException {\n        if (m < 0 || m >= 60)\n            throw new IllegalArgumentException(\n                \"Illegal minute : \" + (Integer.toString(m)));\n        javaCal = null;\n        minute = m;\n    }\n\n    /**\n     * Set the second member\n     * @param s int to set\n     * @throws IllegalArgumentException if s is not a valid second\n     */\n    public void setSecond(int s) throws IllegalArgumentException {\n        if (s < 0 || s >= 60)\n            throw new IllegalArgumentException(\n                \"Illegal second : \" + Integer.toString(s));\n        javaCal = null;\n        second = s;\n    }\n\n    /** Get the time offset from the current time.\n     *\n     *@return offset from the current time.\n     */\n    public int getDeltaSeconds() {\n        // long ctime = this.getJavaCal().getTimeInMillis();\n        long ctime = this.getJavaCal().getTime().getTime();\n        return (int) (ctime - System.currentTimeMillis()) / 1000;\n    }\n\n    public Object clone() {\n        SIPDate retval;\n        try {\n            retval = (SIPDate) super.clone();\n        } catch (CloneNotSupportedException e) {\n            throw new RuntimeException(\"Internal error\");\n        }\n        if (javaCal != null)\n            retval.javaCal = (java.util.Calendar) javaCal.clone();\n        return retval;\n    }\n}\n/*\n * $Log: SIPDate.java,v $\n * Revision 1.9  2009/10/18 13:46:33  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.8  2009/07/17 18:57:37  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:01:16  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2005/04/16 20:35:10  dmuresan\n * SIPDate made cloneable.\n *\n * Revision 1.4  2004/07/28 14:41:53  mranga\n * Submitted by:  mranga\n *\n * fixed equality check for SIPDate.\n *\n * Revision 1.3  2004/04/05 21:46:08  mranga\n * Submitted by:  Bruno Konik\n * Reviewed by:   mranga\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPDateHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.*;\n\nimport javax2.sip.header.*;\n\n/**\n* Date Header.\n*\n*@version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:37 $\n*\n*@author M. Ranganathan   <br/>\n*@author Olivier Deruelle <br/>\n*\n*\n*/\npublic class SIPDateHeader extends SIPHeader implements DateHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1734186339037274664L;\n    /** date field\n     */\n    protected SIPDate date;\n\n    /** Default constructor.\n     */\n    public SIPDateHeader() {\n        super(DATE);\n    }\n\n    /** Encode the header into a String.\n     * @return String\n     */\n    public String encodeBody() {\n        return date.encode();\n    }\n\n    /**\n     * Set the date member\n     * @param d SIPDate to set\n     */\n    public void setDate(SIPDate d) {\n        date = d;\n\n    }\n\n    /**\n     * Sets date of DateHeader. The date is repesented by the Calendar object.\n     *\n     * @param dat the Calendar object date of this header.\n     */\n    public void setDate(Calendar dat) {\n        if (dat != null)\n            date = new SIPDate(dat.getTime().getTime());\n    }\n\n    /**\n     * Gets the date of DateHeader. The date is repesented by the Calender\n     * object.\n     *\n     * @return the Calendar object representing the date of DateHeader\n     */\n    public Calendar getDate() {\n        if (date == null)\n            return null;\n        return date.getJavaCal();\n    }\n\n    public Object clone() {\n        SIPDateHeader retval = (SIPDateHeader) super.clone();\n        if (this.date != null)\n            retval.date = (SIPDate) this.date.clone();\n        return retval;\n    }\n}\n/*\n * $Log: SIPDateHeader.java,v $\n * Revision 1.6  2009/07/17 18:57:37  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.5  2006/07/13 09:01:23  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:26  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.3  2005/04/16 20:38:50  dmuresan\n * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPETag.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * the SIP-ETag header.\n *\n * @author Jeroen van Bemmel<br/>\n * @version 1.2 $Revision: 1.3 $ $Date: 2009/07/17 18:57:37 $\n * @since 1.2\n */\npublic class SIPETag extends SIPHeader implements SIPETagHeader , ExtensionHeader{\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 3837543366074322107L;\n\n    /**\n     * entity tag field\n     */\n    protected String entityTag;\n\n    /** Default constructor\n     */\n    public SIPETag() {\n        super(NAME);\n    }\n\n    public SIPETag( String tag ) throws ParseException {\n        this();\n        this.setETag( tag );\n    }\n\n\n    /**\n     * Encode into canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return entityTag;\n    }\n\n    /**\n     * get the priority value.\n     * @return String\n     */\n    public String getETag() {\n        return entityTag;\n    }\n\n    /**\n     * Set the priority member\n     * @param etag String to set\n     */\n    public void setETag(String etag) throws ParseException {\n        if (etag == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception,\"\n                    + \"SIP-ETag, setETag(), the etag parameter is null\");\n        this.entityTag = etag;\n    }\n\n    /**\n     * This method needs to be added for backwards compatibility to\n     * avoid ClassCast exception on V1.1 applications\n     *\n     * @see javax2.sip.header.ExtensionHeader#setValue(java.lang.String)\n     */\n    public void setValue(String value) throws ParseException {\n        this.setETag(value);\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\n/**\n * Root class from which all SIPHeader objects are subclassed.\n *\n * @author M. Ranganathan   <br/>\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:37 $\n *\n *\n */\npublic abstract class SIPHeader\n    extends SIPObject\n    implements SIPHeaderNames, javax2.sip.header.Header, HeaderExt {\n\n    /** name of this header\n     */\n    protected String headerName;\n\n    /** Value of the header.\n    */\n\n    /** Constructor\n     * @param hname String to set\n     */\n    protected SIPHeader(String hname) {\n        headerName = hname;\n    }\n\n    /** Default constructor\n     */\n    public SIPHeader() {\n    }\n\n    /**\n     * Name of the SIPHeader\n     * @return String\n     */\n    public String getHeaderName() {\n        return headerName;\n    }\n\n    /** Alias for getHaderName above.\n    *\n    *@return String headerName\n    *\n    */\n    public String getName() {\n        return this.headerName;\n    }\n\n    /**\n         * Set the name of the header .\n         * @param hdrname String to set\n         */\n    public void setHeaderName(String hdrname) {\n        headerName = hdrname;\n    }\n\n    /** Get the header value (i.e. what follows the name:).\n    * This merely goes through and lops off the portion that follows\n    * the headerName:\n    */\n    public String getHeaderValue() {\n        String encodedHdr = null;\n        try {\n            encodedHdr = this.encode();\n        } catch (Exception ex) {\n            return null;\n        }\n        StringBuffer buffer = new StringBuffer(encodedHdr);\n        while (buffer.length() > 0 && buffer.charAt(0) != ':') {\n            buffer.deleteCharAt(0);\n        }\n        if (buffer.length() > 0)\n            buffer.deleteCharAt(0);\n        return buffer.toString().trim();\n    }\n\n    /** Return false if this is not a header list\n    * (SIPHeaderList overrrides this method).\n    *@return false\n    */\n    public boolean isHeaderList() {\n        return false;\n    }\n\n    /** Encode this header into canonical form.\n    */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        buffer.append(this.headerName).append(COLON).append(SP);\n        this.encodeBody(buffer);\n        buffer.append(NEWLINE);\n        return buffer;\n    }\n\n    /** Encode the body of this header (the stuff that follows headerName).\n    * A.K.A headerValue.\n    */\n    protected abstract String encodeBody();\n\n    /** Encode the body of this header in the given buffer.\n     * Default implementation calls encodeBody();\n     */\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        return buffer.append(encodeBody());\n    }\n\n    /** Alias for getHeaderValue.\n     */\n    public String getValue() {\n        return this.getHeaderValue();\n    }\n\n    /**\n     * This is a pretty simple hashCode but satisfies requirements.\n     *\n     */\n    public int hashCode() {\n        return this.headerName.hashCode();\n    }\n\n    public final String toString() {\n        return this.encode();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPHeaderList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.GenericObject;\nimport gov2.nist.core.Separators;\nimport gov2.nist.javax2.sip.header.ims.PrivacyHeader;\n\nimport javax2.sip.header.Header;\n\nimport java.lang.reflect.Constructor;\nimport java.util.*;\n\n/**\n *\n * This is the root class for all lists of SIP headers. It imbeds a\n * SIPObjectList object and extends SIPHeader Lists of ContactSIPObjects etc.\n * derive from this class. This supports homogeneous lists (all elements in the\n * list are of the same class). We use this for building type homogeneous lists\n * of SIPObjects that appear in SIPHeaders\n *\n * @version 1.2 $Revision: 1.15 $ $Date: 2005/10/09 18:47:53\n */\npublic abstract class SIPHeaderList<HDR extends SIPHeader> extends SIPHeader implements java.util.List<HDR>, Header {\n\n    private static boolean prettyEncode = false;\n    /**\n     * hlist field.\n     */\n    protected List<HDR> hlist;\n\n    private Class<HDR> myClass;\n\n    public String getName() {\n        return this.headerName;\n    }\n\n\n    private SIPHeaderList() {\n        hlist = new LinkedList<HDR>();\n    }\n\n    /**\n     * Constructor\n     *\n     * @param objclass\n     *            Class to set\n     * @param hname\n     *            String to set\n     */\n    protected SIPHeaderList(Class<HDR> objclass, String hname) {\n        this();\n        this.headerName = hname;\n        this.myClass =  objclass;\n    }\n\n    /**\n     * Concatenate the list of stuff that we are keeping around and also the\n     * text corresponding to these structures (that we parsed).\n     *\n     * @param objectToAdd\n     */\n    public boolean add(HDR objectToAdd) {\n        hlist.add((HDR)objectToAdd);\n        return true;\n    }\n\n    /**\n     * Concatenate the list of stuff that we are keeping around and also the\n     * text corresponding to these structures (that we parsed).\n     *\n     * @param obj\n     *            Genericobject to set\n     */\n    public void addFirst(HDR obj) {\n        hlist.add(0,(HDR) obj);\n    }\n\n    /**\n     * Add to this list.\n     *\n     * @param sipheader\n     *            SIPHeader to add.\n     * @param top\n     *            is true if we want to add to the top of the list.\n     */\n    public void add(HDR sipheader, boolean top) {\n        if (top)\n            this.addFirst(sipheader);\n        else\n            this.add(sipheader);\n    }\n\n    /**\n     * Concatenate two compatible lists. This appends or prepends the new list\n     * to the end of this list.\n     *\n     * @param other\n     *            SIPHeaderList to set\n     * @param topFlag\n     *            flag which indicates which end to concatenate\n     *            the lists.\n     * @throws IllegalArgumentException\n     *             if the two lists are not compatible\n     */\n    public void concatenate(SIPHeaderList<HDR> other, boolean topFlag)\n            throws IllegalArgumentException {\n        if (!topFlag) {\n            this.addAll(other);\n        } else {\n            // add given items to the top end of the list.\n            this.addAll(0, other);\n        }\n\n    }\n\n\n\n    /**\n     * Encode a list of sip headers. Headers are returned in cannonical form.\n     *\n     * @return String encoded string representation of this list of headers.\n     *         (Contains string append of each encoded header).\n     */\n    public String encode() {\n        return encode(new StringBuffer()).toString();\n    }\n\n    public StringBuffer encode(StringBuffer buffer) {\n        if (hlist.isEmpty()) {\n            buffer.append(headerName).append(':').append(Separators.NEWLINE);\n        }\n        else {\n            // The following headers do not have comma separated forms for\n            // multiple headers. Thus, they must be encoded separately.\n            if (this.headerName.equals(SIPHeaderNames.WWW_AUTHENTICATE)\n                    || this.headerName.equals(SIPHeaderNames.PROXY_AUTHENTICATE)\n                    || this.headerName.equals(SIPHeaderNames.AUTHORIZATION)\n                    || this.headerName.equals(SIPHeaderNames.PROXY_AUTHORIZATION)\n                    || (prettyEncode &&\n                            (this.headerName.equals(SIPHeaderNames.VIA) || this.headerName.equals(SIPHeaderNames.ROUTE) || this.headerName.equals(SIPHeaderNames.RECORD_ROUTE))) // Less confusing to read\n                    || this.getClass().equals( ExtensionHeaderList.class) ) {\n                ListIterator<HDR> li = hlist.listIterator();\n                while (li.hasNext()) {\n                    HDR sipheader = (HDR) li.next();\n                    sipheader.encode(buffer);\n                }\n            } else {\n                // These can be concatenated together in an comma separated\n                // list.\n                buffer.append(headerName).append(Separators.COLON).append(Separators.SP);\n                this.encodeBody(buffer);\n                buffer.append(Separators.NEWLINE);\n            }\n        }\n        return buffer;\n    }\n\n    /**\n     * Return a list of encoded strings (one for each sipheader).\n     *\n     * @return LinkedList containing encoded strings in this header list. an\n     *         empty list is returned if this header list contains no sip\n     *         headers.\n     */\n\n    public List<String> getHeadersAsEncodedStrings() {\n        List<String> retval = new LinkedList<String>();\n\n        ListIterator<HDR> li = hlist.listIterator();\n        while (li.hasNext()) {\n            Header sipheader = li.next();\n            retval.add(sipheader.toString());\n\n        }\n\n        return retval;\n\n    }\n\n    /**\n     * Get the first element of this list.\n     *\n     * @return SIPHeader first element of the list.\n     */\n    public Header getFirst() {\n        if (hlist == null || hlist.isEmpty())\n            return null;\n        else\n            return  hlist.get(0);\n    }\n\n    /**\n     * Get the last element of this list.\n     *\n     * @return SIPHeader last element of the list.\n     */\n    public Header getLast() {\n        if (hlist == null || hlist.isEmpty())\n            return null;\n        return  hlist.get(hlist.size() - 1);\n    }\n\n    /**\n     * Get the class for the headers of this list.\n     *\n     * @return Class of header supported by this list.\n     */\n    public Class<HDR> getMyClass() {\n        return  this.myClass;\n    }\n\n    /**\n     * Empty check\n     *\n     * @return boolean true if list is empty\n     */\n    public boolean isEmpty() {\n        return hlist.isEmpty();\n    }\n\n    /**\n     * Get an initialized iterator for my imbedded list\n     *\n     * @return the generated ListIterator\n     */\n    public ListIterator<HDR> listIterator() {\n\n        return hlist.listIterator(0);\n    }\n\n    /**\n     * Get the imbedded linked list.\n     *\n     * @return the imedded linked list of SIP headers.\n     */\n    public List<HDR> getHeaderList() {\n        return this.hlist;\n    }\n\n    /**\n     * Get the list iterator for a given position.\n     *\n     * @param position\n     *            position for the list iterator to return\n     * @return the generated list iterator\n     */\n    public ListIterator<HDR> listIterator(int position) {\n        return hlist.listIterator(position);\n    }\n\n    /**\n     * Remove the first element of this list.\n     */\n    public void removeFirst() {\n        if (hlist.size() != 0)\n            hlist.remove(0);\n\n    }\n\n    /**\n     * Remove the last element of this list.\n     */\n    public void removeLast() {\n        if (hlist.size() != 0)\n            hlist.remove(hlist.size() - 1);\n    }\n\n    /**\n     * Remove a sip header from this list of sip headers.\n     *\n     * @param obj\n     *            SIPHeader to remove\n     * @return boolean\n     */\n    public boolean remove(HDR obj) {\n        if (hlist.size() == 0)\n            return false;\n        else\n            return hlist.remove(obj);\n    }\n\n    /**\n     * Set the root class for all objects inserted into my list (for assertion\n     * check)\n     *\n     * @param cl\n     *            class to set\n     */\n    protected void setMyClass(Class<HDR> cl) {\n        this.myClass = cl;\n    }\n\n    /**\n     * convert to a string representation (for printing).\n     *\n     * @param indentation\n     *            int to set\n     * @return String string representation of object (for printing).\n     */\n    public String debugDump(int indentation) {\n        stringRepresentation = \"\";\n        String indent = new Indentation(indentation).getIndentation();\n\n        String className = this.getClass().getName();\n        sprint(indent + className);\n        sprint(indent + \"{\");\n\n        for (Iterator<HDR> it = hlist.iterator(); it.hasNext();) {\n            HDR sipHeader = (HDR) it.next();\n            sprint(indent + sipHeader.debugDump());\n        }\n        sprint(indent + \"}\");\n        return stringRepresentation;\n    }\n\n    /**\n     * convert to a string representation\n     *\n     * @return String\n     */\n    public String debugDump() {\n        return debugDump(0);\n    }\n\n    /**\n     * Array conversion.\n     *\n     * @return SIPHeader []\n     */\n    public Object[] toArray() {\n        return hlist.toArray();\n\n    }\n\n    /**\n     * index of an element.\n     *\n     * @return index of the given element (-1) if element does not exist.\n     */\n    public int indexOf(GenericObject gobj) {\n        return hlist.indexOf(gobj);\n    }\n\n    /**\n     * insert at a location.\n     *\n     * @param index\n     *            location where to add the sipHeader.\n     * @param sipHeader\n     *            SIPHeader structure to add.\n     */\n\n    public void add(int index, HDR  sipHeader)\n            throws IndexOutOfBoundsException {\n        hlist.add(index, sipHeader);\n    }\n\n    /**\n     * Equality comparison operator.\n     *\n     * @param other\n     *            the other object to compare with. true is returned iff the\n     *            classes match and list of headers herein is equal to the list\n     *            of headers in the target (order of the headers is not\n     *            important).\n     */\n    @SuppressWarnings(\"unchecked\")\n    public boolean equals(Object other) {\n\n        if (other == this)\n            return true;\n\n        if (other instanceof SIPHeaderList) {\n            SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) other;\n            if (this.hlist == that.hlist)\n                return true;\n            else if (this.hlist == null)\n                return that.hlist == null || that.hlist.size() == 0;\n            return this.hlist.equals(that.hlist);\n        }\n        return false;\n    }\n\n    /**\n     * Template match against a template. null field in template indicates wild\n     * card match.\n     */\n    public boolean match(SIPHeaderList<?> template) {\n        if (template == null)\n            return true;\n        if (!this.getClass().equals(template.getClass()))\n            return false;\n        SIPHeaderList<SIPHeader> that = (SIPHeaderList<SIPHeader>) template;\n        if (this.hlist == that.hlist)\n            return true;\n        else if (this.hlist == null)\n            return false;\n        else {\n\n            for (Iterator<SIPHeader> it = that.hlist.iterator(); it.hasNext();) {\n                SIPHeader sipHeader = (SIPHeader) it.next();\n\n                boolean found = false;\n                for (Iterator<HDR> it1 = this.hlist.iterator(); it1.hasNext()\n                        && !found;) {\n                    SIPHeader sipHeader1 = (SIPHeader) it1.next();\n                    found = sipHeader1.match(sipHeader);\n                }\n                if (!found)\n                    return false;\n            }\n            return true;\n        }\n    }\n\n\n    /**\n     * make a clone of this header list.\n     *\n     * @return clone of this Header.\n     */\n    public Object clone() {\n        try {\n            Class<?> clazz = this.getClass();\n\n            Constructor<?> cons = clazz.getConstructor((Class[])null);\n            SIPHeaderList<HDR> retval = (SIPHeaderList<HDR>) cons.newInstance((Object[])null);\n            retval.headerName = this.headerName;\n            retval.myClass  = this.myClass;\n            return retval.clonehlist(this.hlist);\n        } catch (Exception ex) {\n            throw new RuntimeException(\"Could not clone!\", ex);\n        }\n    }\n\n    protected final SIPHeaderList<HDR> clonehlist(List<HDR> hlistToClone) {\n        if (hlistToClone != null) {\n            for (Iterator<HDR> it = (Iterator<HDR>) hlistToClone.iterator(); it.hasNext();) {\n                Header h = it.next();\n                this.hlist.add((HDR)h.clone());\n            }\n        }\n        return this;\n    }\n\n    /**\n     * Get the number of headers in the list.\n     */\n    public int size() {\n        return hlist.size();\n    }\n\n    /**\n     * Return true if this is a header list (overrides the base class method\n     * which returns false).\n     *\n     * @return true\n     */\n    public boolean isHeaderList() {\n        return true;\n    }\n\n    /**\n     * Encode the body of this header (the stuff that follows headerName). A.K.A\n     * headerValue. This will not give a reasonable result for WWW-Authenticate,\n     * Authorization, Proxy-Authenticate and Proxy-Authorization and hence this\n     * is protected.\n     */\n    protected String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        ListIterator<HDR> iterator = this.listIterator();\n        while (true) {\n            SIPHeader sipHeader = (SIPHeader) iterator.next();\n            if ( sipHeader == this ) throw new RuntimeException (\"Unexpected circularity in SipHeaderList\");\n            sipHeader.encodeBody(buffer);\n            // if (body.equals(\"\")) System.out.println(\"BODY == \");\n            if (iterator.hasNext()) {\n                if (!this.headerName.equals(PrivacyHeader.NAME))\n                    buffer.append(Separators.COMMA);\n                else\n                    buffer.append(Separators.SEMICOLON);\n                continue;\n            } else\n                break;\n\n        }\n        return buffer;\n    }\n\n    public boolean addAll(Collection<? extends HDR> collection) {\n        return this.hlist.addAll(collection);\n    }\n\n    public boolean addAll(int index, Collection<? extends HDR> collection) {\n        return this.hlist.addAll(index, collection);\n\n    }\n\n    public boolean containsAll(Collection<?> collection) {\n        return this.hlist.containsAll(collection);\n    }\n\n\n\n\n    public void clear() {\n        this.hlist.clear();\n    }\n\n    public boolean contains(Object header) {\n        return this.hlist.contains(header);\n    }\n\n\n    /**\n     * Get the object at the specified location.\n     *\n     * @param index --\n     *            location from which to get the object.\n     *\n     */\n    public HDR get(int index) {\n        return  this.hlist.get(index);\n    }\n\n    /**\n     * Return the index of a given object.\n     *\n     * @param obj --\n     *            object whose index to compute.\n     */\n    public int indexOf(Object obj) {\n        return this.hlist.indexOf(obj);\n    }\n\n    /**\n     * Return the iterator to the imbedded list.\n     *\n     * @return iterator to the imbedded list.\n     *\n     */\n\n    public java.util.Iterator<HDR> iterator() {\n        return this.hlist.listIterator();\n    }\n\n    /**\n     * Get the last index of the given object.\n     *\n     * @param obj --\n     *            object whose index to find.\n     */\n    public int lastIndexOf(Object obj) {\n\n        return this.hlist.lastIndexOf(obj);\n    }\n\n    /**\n     * Remove the given object.\n     *\n     * @param obj --\n     *            object to remove.\n     *\n     */\n\n    public boolean remove(Object obj) {\n\n        return this.hlist.remove(obj);\n    }\n\n    /**\n     * Remove the object at a given index.\n     *\n     * @param index --\n     *            index at which to remove the object\n     */\n\n    public HDR remove(int index) {\n        return this.hlist.remove(index);\n    }\n\n    /**\n     * Remove all the elements.\n     * @see List#removeAll(java.util.Collection)\n     */\n    public boolean removeAll(java.util.Collection<?> collection) {\n        return this.hlist.removeAll(collection);\n    }\n\n\n    /**\n     * @see List#retainAll(java.util.Collection)\n     * @param collection\n     */\n    public boolean retainAll(java.util.Collection<?> collection) {\n        return this.hlist.retainAll(collection);\n    }\n\n    /**\n     * Get a sublist of the list.\n     *\n     * @see List#subList(int, int)\n     */\n    public java.util.List<HDR> subList(int index1, int index2) {\n        return this.hlist.subList(index1, index2);\n\n    }\n\n    /**\n     * @see Object#hashCode()\n     * @return -- the computed hashcode.\n     */\n    public int hashCode() {\n\n        return this.headerName.hashCode();\n    }\n\n    /**\n     * Set a SIPHeader at a particular position in the list.\n     *\n     * @see List#set(int, java.lang.Object)\n     */\n    public HDR set(int position, HDR sipHeader) {\n\n        return hlist.set(position, sipHeader);\n\n    }\n\n\n    public static void setPrettyEncode(boolean flag) {\n        prettyEncode = flag;\n    }\n\n\n    public <T> T[] toArray(T[] array) {\n        return this.hlist.toArray(array);\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPHeaderNames.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\nimport gov2.nist.javax2.sip.header.extensions.*;\n\n/**\n * SIPHeader names that are supported by this parser\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:37 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic interface SIPHeaderNames {\n\n    public static final String MIN_EXPIRES = MinExpiresHeader.NAME; //1\n    public static final String ERROR_INFO = ErrorInfoHeader.NAME; //2\n    public static final String MIME_VERSION = MimeVersionHeader.NAME; //3\n    public static final String IN_REPLY_TO = InReplyToHeader.NAME; //4\n    public static final String ALLOW = AllowHeader.NAME; //5\n    public static final String CONTENT_LANGUAGE = ContentLanguageHeader.NAME;\n    //6\n    public static final String CALL_INFO = CallInfoHeader.NAME; //7\n    public static final String CSEQ = CSeqHeader.NAME; //8\n    public static final String ALERT_INFO = AlertInfoHeader.NAME; //9\n    public static final String ACCEPT_ENCODING = AcceptEncodingHeader.NAME;\n    //10\n    public static final String ACCEPT = AcceptHeader.NAME; //11\n    public static final String ACCEPT_LANGUAGE = AcceptLanguageHeader.NAME;\n    //12\n    public static final String RECORD_ROUTE = RecordRouteHeader.NAME; //13\n    public static final String TIMESTAMP = TimeStampHeader.NAME; //14\n    public static final String TO = ToHeader.NAME; //15\n    public static final String VIA = ViaHeader.NAME; //16\n    public static final String FROM = FromHeader.NAME; //17\n    public static final String CALL_ID = CallIdHeader.NAME; //18\n    public static final String AUTHORIZATION = AuthorizationHeader.NAME; //19\n    public static final String PROXY_AUTHENTICATE =\n        ProxyAuthenticateHeader.NAME;\n    //20\n    public static final String SERVER = ServerHeader.NAME; //21\n    public static final String UNSUPPORTED = UnsupportedHeader.NAME; //22\n    public static final String RETRY_AFTER = RetryAfterHeader.NAME; //23\n    public static final String CONTENT_TYPE = ContentTypeHeader.NAME; //24\n    public static final String CONTENT_ENCODING = ContentEncodingHeader.NAME;\n    //25\n    public static final String CONTENT_LENGTH = ContentLengthHeader.NAME; //26\n    public static final String ROUTE = RouteHeader.NAME; //27\n    public static final String CONTACT = ContactHeader.NAME; //28\n    public static final String WWW_AUTHENTICATE = WWWAuthenticateHeader.NAME;\n    //29\n    public static final String MAX_FORWARDS = MaxForwardsHeader.NAME; //30\n    public static final String ORGANIZATION = OrganizationHeader.NAME; //31\n    public static final String PROXY_AUTHORIZATION =\n        ProxyAuthorizationHeader.NAME;\n    //32\n    public static final String PROXY_REQUIRE = ProxyRequireHeader.NAME; //33\n    public static final String REQUIRE = RequireHeader.NAME; //34\n    public static final String CONTENT_DISPOSITION =\n        ContentDispositionHeader.NAME;\n    //35\n    public static final String SUBJECT = SubjectHeader.NAME; //36\n    public static final String USER_AGENT = UserAgentHeader.NAME; //37\n    public static final String WARNING = WarningHeader.NAME; //38\n    public static final String PRIORITY = PriorityHeader.NAME; //39\n    public static final String DATE = DateHeader.NAME; //40\n    public static final String EXPIRES = ExpiresHeader.NAME; //41\n    public static final String SUPPORTED = SupportedHeader.NAME; //42\n    public static final String AUTHENTICATION_INFO =\n        AuthenticationInfoHeader.NAME;\n    //43\n    public static final String REPLY_TO = ReplyToHeader.NAME; //44\n    public static final String RACK = RAckHeader.NAME; //45\n    public static final String RSEQ = RSeqHeader.NAME; //46\n    public static final String REASON = ReasonHeader.NAME; //47\n    public static final String SUBSCRIPTION_STATE =\n        SubscriptionStateHeader.NAME;\n    //48\n    public static final String EVENT = EventHeader.NAME; //44\n    public static final String ALLOW_EVENTS = AllowEventsHeader.NAME; //45\n\n    public static final String SIP_ETAG = SIPETagHeader.NAME; //46\n    public static final String SIP_IF_MATCH = SIPIfMatchHeader.NAME; //47\n\n    // NewHeights pmusgrave\n    public static final String REFERRED_BY = ReferredByHeader.NAME; //48\n    public static final String SESSION_EXPIRES = SessionExpiresHeader.NAME; //49\n    public static final String MIN_SE = MinSEHeader.NAME; //50\n    public static final String REPLACES = ReplacesHeader.NAME; //51\n    public static final String JOIN = JoinHeader.NAME; //52\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPHeaderNamesCache.java",
    "content": "package gov2.nist.javax2.sip.header;\n\nimport java.util.HashMap;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\n\n/**\n * @author yanick.belanger\n */\npublic abstract class SIPHeaderNamesCache\n{\n    private static final HashMap lowercaseMap = new HashMap();\n\n    static {\n        Field[] fields = SIPHeaderNames.class.getFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field field = fields[i];\n            if (field.getType().equals(String.class) && Modifier.isStatic(field.getModifiers())) {\n                try {\n                    String value = (String) field.get(null);\n                    String lowerCase = value.toLowerCase();\n                    lowercaseMap.put(value, lowerCase);\n                    lowercaseMap.put(lowerCase, lowerCase);\n                } catch (IllegalAccessException e) {\n                }\n            }\n        }\n    }\n\n    public static String toLowerCase(String headerName) {\n        String lowerCase = (String) lowercaseMap.get(headerName);\n        if (lowerCase == null) {\n            return headerName.toLowerCase();\n        }\n        else {\n            return lowerCase;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPIfMatch.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * the SIP-If-Match header.\n *\n * @author Jeroen van Bemmel<br/>\n * @version 1.2 $Revision: 1.3 $ $Date: 2009/07/17 18:57:38 $\n * @since 1.2\n */\npublic class SIPIfMatch extends SIPHeader implements SIPIfMatchHeader,ExtensionHeader {\n\n    /**\n     * unique serial id\n     */\n    private static final long serialVersionUID = 3833745477828359730L;\n\n    /**\n     * entity tag field\n     */\n    protected String entityTag;\n\n    /** Default constructor\n     */\n    public SIPIfMatch() {\n        super(NAME);\n    }\n\n    public SIPIfMatch(String etag) throws ParseException {\n        this();\n        this.setETag( etag );\n    }\n\n    /**\n     * Encode into canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        return entityTag;\n    }\n\n    /**\n     * get the priority value.\n     * @return String\n     */\n    public String getETag() {\n        return entityTag;\n    }\n\n    /**\n     * Set the priority member\n     * @param etag -- the entity tag to set.\n     */\n    public void setETag(String etag) throws ParseException {\n        if (etag == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception,\"\n                    + \"SIP-If-Match, setETag(), the etag parameter is null\");\n        this.entityTag = etag;\n    }\n\n    /**\n     * For v 1.1 backwards compatibility.\n     * @see javax2.sip.header.ExtensionHeader#setValue(java.lang.String)\n     */\n    public void setValue(String value) throws ParseException {\n        this.setETag(value);\n\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPObject.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).     *\n *****************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport gov2.nist.core.GenericObject;\nimport gov2.nist.core.GenericObjectList;\nimport gov2.nist.core.InternalErrorHandler;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\n\n/**\n * Root class for all singleton objects in this package:\n * specializes the gov2.nist.sip.header.GenericObject class for SIPHeader\n * related objects.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:57:38 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\n\npublic abstract class SIPObject extends GenericObject {\n\n    /** default Constructor\n     */\n    protected SIPObject() {\n        super();\n    }\n\n\n\n    /** Debug function\n     */\n    public void dbgPrint() {\n        super.dbgPrint();\n    }\n\n    /** Encode the header into a String.\n     * @return String\n     */\n    public abstract String encode();\n\n    /** Encode the header into the given StringBuffer.\n     * Default implemation calls encode().\n     */\n    public StringBuffer encode(StringBuffer buffer) {\n        return buffer.append(encode());\n    }\n\n    /**\n     * An introspection based equality predicate for SIPObjects.\n     *@param other the other object to test against.\n     */\n    public boolean equals(Object other) {\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        SIPObject that = (SIPObject) other;\n        Class myclass = this.getClass();\n        Class hisclass = other.getClass();\n        while (true) {\n            Field[] fields = myclass.getDeclaredFields();\n            if (!hisclass.equals(myclass))\n                return false;\n            Field[] hisfields = hisclass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                Field g = hisfields[i];\n                // Only print protected and public members.\n                int modifier = f.getModifiers();\n                if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                    continue;\n                Class fieldType = f.getType();\n                String fieldName = f.getName();\n                if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                    continue;\n                }\n                if (fieldName.compareTo(\"indentation\") == 0) {\n                    continue;\n                }\n                try {\n                    // Primitive fields are printed with type: value\n                    if (fieldType.isPrimitive()) {\n                        String fname = fieldType.toString();\n                        if (fname.compareTo(\"int\") == 0) {\n                            if (f.getInt(this) != g.getInt(that))\n                                return false;\n                        } else if (fname.compareTo(\"short\") == 0) {\n                            if (f.getShort(this) != g.getShort(that))\n                                return false;\n                        } else if (fname.compareTo(\"char\") == 0) {\n                            if (f.getChar(this) != g.getChar(that))\n                                return false;\n                        } else if (fname.compareTo(\"long\") == 0) {\n                            if (f.getLong(this) != g.getLong(that))\n                                return false;\n                        } else if (fname.compareTo(\"boolean\") == 0) {\n                            if (f.getBoolean(this) != g.getBoolean(that))\n                                return false;\n                        } else if (fname.compareTo(\"double\") == 0) {\n                            if (f.getDouble(this) != g.getDouble(that))\n                                return false;\n                        } else if (fname.compareTo(\"float\") == 0) {\n                            if (f.getFloat(this) != g.getFloat(that))\n                                return false;\n                        }\n                    } else if (g.get(that) == f.get(this))\n                        continue;\n                    else if (f.get(this) == null && g.get(that) != null)\n                        return false;\n                    else if (g.get(that) == null && f.get(this) != null)\n                        return false;\n                    else if (!f.get(this).equals(g.get(that)))\n                        return false;\n                } catch (IllegalAccessException ex1) {\n                    System.out.println(\"accessed field \" + fieldName);\n                    System.out.println(\"modifier  \" + modifier);\n                    System.out.println(\"modifier.private  \" + Modifier.PRIVATE);\n                    InternalErrorHandler.handleException(ex1);\n                }\n            }\n            if (myclass.equals(SIPObject.class))\n                break;\n            else {\n                myclass = myclass.getSuperclass();\n                hisclass = hisclass.getSuperclass();\n            }\n        }\n        return true;\n    }\n\n    /** An introspection based predicate matching using a template\n     * object. Allows for partial match of two protocl Objects.\n     * You can set a generalized matcher (using regular expressions\n     * for example) by implementing the Match interface and registering\n     * it with the template.\n     *@param other the match pattern to test against. The match object\n     * has to be of the same type (class). Primitive types\n     * and non-sip fields that are non null are matched for equality.\n     * Null in any field  matches anything. Some book-keeping fields\n     * are ignored when making the comparison.\n     *\n     */\n    public boolean match(Object other) {\n        if (other == null) {\n            return true;\n        }\n\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        GenericObject that = (GenericObject) other;\n        Class myclass = this.getClass();\n        Class hisclass = other.getClass();\n        while (true) {\n            Field[] fields = myclass.getDeclaredFields();\n            Field[] hisfields = hisclass.getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                Field g = hisfields[i];\n                // Only print protected and public members.\n                int modifier = f.getModifiers();\n                if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                    continue;\n                Class fieldType = f.getType();\n                String fieldName = f.getName();\n                if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                    continue;\n                }\n                if (fieldName.compareTo(\"indentation\") == 0) {\n                    continue;\n                }\n                try {\n                    if (fieldType.isPrimitive()) {\n                        String fname = fieldType.toString();\n                        if (fname.compareTo(\"int\") == 0) {\n                            if (f.getInt(this) != g.getInt(that))\n                                return false;\n                        } else if (fname.compareTo(\"short\") == 0) {\n                            if (f.getShort(this) != g.getShort(that))\n                                return false;\n                        } else if (fname.compareTo(\"char\") == 0) {\n                            if (f.getChar(this) != g.getChar(that))\n                                return false;\n                        } else if (fname.compareTo(\"long\") == 0) {\n                            if (f.getLong(this) != g.getLong(that))\n                                return false;\n                        } else if (fname.compareTo(\"boolean\") == 0) {\n                            if (f.getBoolean(this) != g.getBoolean(that))\n                                return false;\n                        } else if (fname.compareTo(\"double\") == 0) {\n                            if (f.getDouble(this) != g.getDouble(that))\n                                return false;\n                        } else if (fname.compareTo(\"float\") == 0) {\n                            if (f.getFloat(this) != g.getFloat(that))\n                                return false;\n                        } else {\n                            InternalErrorHandler.handleException(\n                                \"unknown type\");\n                        }\n                    } else {\n                        Object myObj = f.get(this);\n                        Object hisObj = g.get(that);\n                        if (hisObj != null && myObj == null)\n                            return false;\n                        else if (hisObj == null && myObj != null)\n                            continue;\n                        else if (hisObj == null && myObj == null)\n                            continue;\n                        else if (\n                            hisObj instanceof java.lang.String\n                                && myObj instanceof java.lang.String) {\n                            if ((((String) hisObj).trim()).equals(\"\"))\n                                continue;\n                            if (((String) myObj)\n                                .compareToIgnoreCase((String) hisObj)\n                                != 0)\n                                return false;\n                        } else if (\n                            hisObj != null\n                                && GenericObject.isMySubclass(myObj.getClass())\n                                && GenericObject.isMySubclass(hisObj.getClass())\n                                && myObj.getClass().equals(hisObj.getClass())\n                                && ((GenericObject) hisObj).getMatcher()\n                                    != null) {\n                            String myObjEncoded =\n                                ((GenericObject) myObj).encode();\n                            boolean retval =\n                                ((GenericObject) hisObj).getMatcher().match(\n                                    myObjEncoded);\n                            if (!retval)\n                                return false;\n                        } else if (\n                            GenericObject.isMySubclass(myObj.getClass())\n                                && !((GenericObject) myObj).match(hisObj))\n                            return false;\n                        else if (\n                            GenericObjectList.isMySubclass(myObj.getClass())\n                                && !((GenericObjectList) myObj).match(hisObj))\n                            return false;\n\n                    }\n                } catch (IllegalAccessException ex1) {\n                    InternalErrorHandler.handleException(ex1);\n                }\n            }\n            if (myclass.equals(SIPObject.class))\n                break;\n            else {\n                myclass = myclass.getSuperclass();\n                hisclass = hisclass.getSuperclass();\n            }\n        }\n        return true;\n    }\n\n    /**\n     * An introspection based string formatting method. We need this because\n     * in this package (although it is an exact duplicate of the one in\n     * the superclass) because it needs to access the protected members\n     * of the other objects in this class.\n     * @return String\n     */\n    public String debugDump() {\n        stringRepresentation = \"\";\n        Class myclass = getClass();\n        sprint(myclass.getName());\n        sprint(\"{\");\n        Field[] fields = myclass.getDeclaredFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field f = fields[i];\n            // Only print protected and public members.\n            int modifier = f.getModifiers();\n            if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE)\n                continue;\n            Class fieldType = f.getType();\n            String fieldName = f.getName();\n            if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                // avoid nasty recursions...\n                continue;\n            }\n            if (fieldName.compareTo(\"indentation\") == 0) {\n                // formatting stuff - not relevant here.\n                continue;\n            }\n            sprint(fieldName + \":\");\n            try {\n                // Primitive fields are printed with type: value\n                if (fieldType.isPrimitive()) {\n                    String fname = fieldType.toString();\n                    sprint(fname + \":\");\n                    if (fname.compareTo(\"int\") == 0) {\n                        int intfield = f.getInt(this);\n                        sprint(intfield);\n                    } else if (fname.compareTo(\"short\") == 0) {\n                        short shortField = f.getShort(this);\n                        sprint(shortField);\n                    } else if (fname.compareTo(\"char\") == 0) {\n                        char charField = f.getChar(this);\n                        sprint(charField);\n                    } else if (fname.compareTo(\"long\") == 0) {\n                        long longField = f.getLong(this);\n                        sprint(longField);\n                    } else if (fname.compareTo(\"boolean\") == 0) {\n                        boolean booleanField = f.getBoolean(this);\n                        sprint(booleanField);\n                    } else if (fname.compareTo(\"double\") == 0) {\n                        double doubleField = f.getDouble(this);\n                        sprint(doubleField);\n                    } else if (fname.compareTo(\"float\") == 0) {\n                        float floatField = f.getFloat(this);\n                        sprint(floatField);\n                    }\n                } else if (GenericObject.class.isAssignableFrom(fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObject) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else if (\n                    GenericObjectList.class.isAssignableFrom(fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObjectList) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else {\n                    // Dont do recursion on things that are not\n                    // of our header type...\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).getClass().getName() + \":\");\n                    } else {\n                        sprint(fieldType.getName() + \":\");\n                    }\n\n                    sprint(\"{\");\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).toString());\n                    } else {\n                        sprint(\"<null>\");\n                    }\n                    sprint(\"}\");\n                }\n            } catch (IllegalAccessException ex1) {\n                continue; // we are accessing a private field...\n            }\n        }\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n    /**\n     * Formatter with a given starting indentation (for nested structs).\n     * @param indent int to set\n     * @return String\n     */\n    public String debugDump(int indent) {\n        int save = indentation;\n        indentation = indent;\n        String retval = this.debugDump();\n        indentation = save;\n        return retval;\n    }\n\n\n    public String toString() {\n        return this.encode();\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SIPObjectList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport java.util.ListIterator;\nimport java.util.LinkedList;\nimport java.util.Iterator;\nimport java.lang.reflect.*;\n\nimport gov2.nist.core.*;\n\n/**\n * Root class for all the collection objects in this list:\n * a wrapper class on the GenericObjectList class for lists of objects\n * that can appear in SIPObjects.\n * IMPORTANT NOTE: SIPObjectList cannot derive from SIPObject.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:38 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class SIPObjectList extends GenericObjectList {\n\n\n    private static final long serialVersionUID = -3015154738977508905L;\n\n    /**\n     * Construct a SIPObject List given a list name.\n     * @param lname String to set\n     */\n    public SIPObjectList(String lname) {\n        super(lname);\n    }\n\n\n\n\n    /**\n     * Construct an empty SIPObjectList.\n     */\n    public SIPObjectList() {\n        super();\n    }\n\n\n\n\n    /**\n     * Do a merge of the GenericObjects contained in this list with the\n     * GenericObjects in the mergeList. Note that this does an inplace\n     * modification of the given list. This does an object by object\n     * merge of the given objects.\n     *\n     *@param mergeList is the list of Generic objects that we want to do\n     * an object by object merge with. Note that no new objects are\n     * added to this list.\n     *\n     */\n\n    public void mergeObjects(GenericObjectList mergeList) {\n        Iterator<GenericObject> it1 = this.listIterator();\n        Iterator<GenericObject> it2 = mergeList.listIterator();\n        while (it1.hasNext()) {\n            GenericObject outerObj = (GenericObject) it1.next();\n            while (it2.hasNext()) {\n                Object innerObj = it2.next();\n                outerObj.merge(innerObj);\n            }\n        }\n    }\n\n    /**\n     * Append a given list to the end of this list.\n     * @param otherList SIPObjectList to set\n     */\n    public void concatenate(SIPObjectList otherList) {\n        super.concatenate(otherList);\n    }\n\n    /**\n     * Append or prepend a given list to this list.\n     * @param otherList SIPObjectList to set\n     * @param topFlag boolean to set\n     */\n    public void concatenate(SIPObjectList otherList, boolean topFlag) {\n        super.concatenate(otherList, topFlag);\n    }\n\n    /**\n     * Get the first object of this list.\n     * @return GenericObject\n     */\n    public GenericObject first() {\n        return (SIPObject) super.first();\n    }\n\n\n    /**\n     * Get the next object of this list (assumes that first() has been\n     * called prior to calling this method.)\n     * @return GenericObject\n     */\n    public GenericObject next() {\n        return (SIPObject) super.next();\n    }\n\n\n\n\n\n    /**\n     * Convert to a string given an indentation(for pretty printing).\n     * This is useful for debugging the system in lieu of a debugger.\n     *\n     * @param indent int to set\n     * @return an indentation\n     */\n    public String debugDump(int indent) {\n        return super.debugDump(indent);\n    }\n\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Server.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\nimport java.util.*;\n\n/**\n * Supported SIP Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:38 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class Server extends SIPHeader implements ServerHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3587764149383342973L;\n    /** Product tokens.\n    */\n    protected List productTokens;\n\n    /**\n     * Return canonical form.\n     * @return String\n     */\n    private String encodeProduct() {\n        StringBuffer tokens = new StringBuffer();\n        ListIterator it = productTokens.listIterator();\n\n        while (it.hasNext()) {\n            tokens.append((String) it.next());\n            if (it.hasNext())\n                tokens.append('/');\n            else\n                break;\n        }\n        return tokens.toString();\n    }\n\n    /** set the productToken field\n     * @param pt String to set\n     */\n    public void addProductToken(String pt) {\n        productTokens.add(pt);\n    }\n\n    /**\n     * Constructor.\n     */\n    public Server() {\n        super(NAME);\n        productTokens = new LinkedList();\n    }\n\n    /** Encode only the body of this header.\n    *@return encoded value of the header.\n    */\n    public String encodeBody() {\n        return encodeProduct();\n    }\n\n    /**\n    * Returns the list value of the product parameter.\n    *\n    * @return the software of this UserAgentHeader\n    */\n    public ListIterator getProduct() {\n        if (productTokens == null || productTokens.isEmpty())\n            return null;\n        else\n            return productTokens.listIterator();\n    }\n\n    /**\n     * Sets the product value of the UserAgentHeader.\n     *\n     * @param product - a List specifying the product value\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the product value.\n     */\n    public void setProduct(List product) throws ParseException {\n        if (product == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, UserAgent, \"\n                    + \"setProduct(), the \"\n                    + \" product parameter is null\");\n        productTokens = product;\n    }\n}\n/*\n * $Log: Server.java,v $\n * Revision 1.5  2009/07/17 18:57:38  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:04  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SipRequestLine.java",
    "content": "package gov2.nist.javax2.sip.header;\n\nimport javax2.sip.address.URI;\n\n\n/**\n * The SIP Request Line.\n * \n * @since 2.0\n */\npublic interface SipRequestLine {\n\n    /** get the Request-URI.\n     *\n     * @return the request URI\n     */\n    public abstract URI getUri();\n\n    /**\n     * Get the Method\n     *\n     * @return method string.\n     */\n    public abstract String getMethod();\n\n    /**\n     * Get the SIP version.\n     *\n     * @return String\n     */\n    public abstract String getSipVersion();\n\n    /**\n     * Set the URI.\n     * \n     * @param uri URI to set.\n     */\n    public abstract void setUri(URI uri);\n\n    /**\n     * Set the method member\n     *\n     * @param method String to set\n     */\n    public abstract void setMethod(String method);\n\n    /**\n     * Set the sipVersion member\n     *\n     * @param s String to set\n     */\n    public abstract void setSipVersion(String version);\n\n    /**\n     * Get the major verrsion number.\n     *\n     *@return String major version number\n     */\n    public abstract String getVersionMajor();\n\n    /**\n     * Get the minor version number.\n     *\n     *@return String minor version number\n     *\n     */\n    public abstract String getVersionMinor();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SipStatusLine.java",
    "content": "package gov2.nist.javax2.sip.header;\n\n/**\n * The SIP Status line.\n * \n * @since 2.0\n */\npublic interface SipStatusLine {\n\n    /** get the Sip Version\n     * @return SipVersion\n     */\n    public abstract String getSipVersion();\n\n    /** get the Status Code\n     * @return StatusCode\n     */\n    public abstract int getStatusCode();\n\n    /** get the ReasonPhrase field\n     * @return  ReasonPhrase field\n     */\n    public abstract String getReasonPhrase();\n\n    /**\n     * Set the sipVersion member\n     * @param sipVersion String to set\n     */\n    public abstract void setSipVersion(String sipVersion);\n\n    /**\n     * Set the statusCode member\n     * @param statusCode int to set\n     */\n    public abstract void setStatusCode(int statusCode);\n\n    /**\n     * Set the reasonPhrase member\n     * @param reasonPhrase String to set\n     */\n    public abstract void setReasonPhrase(String reasonPhrase);\n\n    /**\n     * Get the major version number.\n     *@return String major version number\n     */\n    public abstract String getVersionMajor();\n\n    /**\n     * Get the minor version number.\n     *@return String minor version number\n     */\n    public abstract String getVersionMinor();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/StatusLine.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.SIPConstants;\n\n/**\n * Status Line (for SIPReply) messages.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:34 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic final class StatusLine extends SIPObject implements SipStatusLine {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -4738092215519950414L;\n\n    protected boolean matchStatusClass;\n\n    /** sipVersion field\n     */\n    protected String sipVersion;\n\n    /** status code field\n     */\n    protected int statusCode;\n\n    /** reasonPhrase field\n     */\n    protected String reasonPhrase;\n\n    /** Match with a template.\n     * Match only the response class if the last two digits of the\n     * match templates are 0's\n     */\n\n    public boolean match(Object matchObj) {\n        if (!(matchObj instanceof StatusLine))\n            return false;\n        StatusLine sl = (StatusLine) matchObj;\n        // A pattern matcher has been registered.\n        if (sl.matchExpression != null)\n            return sl.matchExpression.match(this.encode());\n        // no patter matcher has been registered..\n        if (sl.sipVersion != null && !sl.sipVersion.equals(sipVersion))\n            return false;\n        if (sl.statusCode != 0) {\n            if (matchStatusClass) {\n                int hiscode = sl.statusCode;\n                String codeString = Integer.toString(sl.statusCode);\n                String mycode = Integer.toString(statusCode);\n                if (codeString.charAt(0) != mycode.charAt(0))\n                    return false;\n            } else {\n                if (statusCode != sl.statusCode)\n                    return false;\n            }\n        }\n        if (sl.reasonPhrase == null || reasonPhrase == sl.reasonPhrase)\n            return true;\n        return reasonPhrase.equals(sl.reasonPhrase);\n\n    }\n\n    /** set the flag on a match template.\n     *If this set to true, then the whole status code is matched (default\n     * behavior) else only the class of the response is matched.\n     */\n    public void setMatchStatusClass(boolean flag) {\n        matchStatusClass = flag;\n    }\n\n    /** Default Constructor\n     */\n    public StatusLine() {\n        reasonPhrase = null;\n        sipVersion = SIPConstants.SIP_VERSION_STRING;\n    }\n\n    /**\n     * Encode into a canonical form.\n     * @return String\n     */\n    public String encode() {\n        String encoding = SIPConstants.SIP_VERSION_STRING + SP + statusCode;\n        if (reasonPhrase != null)\n            encoding += SP + reasonPhrase;\n        encoding += NEWLINE;\n        return encoding;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#getSipVersion()\n     */\n    public String getSipVersion() {\n        return sipVersion;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#getStatusCode()\n     */\n    public int getStatusCode() {\n        return statusCode;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#getReasonPhrase()\n     */\n    public String getReasonPhrase() {\n        return reasonPhrase;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#setSipVersion(java.lang.String)\n     */\n    public void setSipVersion(String s) {\n        sipVersion = s;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#setStatusCode(int)\n     */\n    public void setStatusCode(int statusCode) {\n        this.statusCode = statusCode;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#setReasonPhrase(java.lang.String)\n     */\n    public void setReasonPhrase(String reasonPhrase) {\n        this.reasonPhrase = reasonPhrase;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#getVersionMajor()\n     */\n    public String getVersionMajor() {\n        if (sipVersion == null)\n            return null;\n        String major = null;\n        boolean slash = false;\n        for (int i = 0; i < sipVersion.length(); i++) {\n            if (sipVersion.charAt(i) == '.')\n                slash = false;\n            if (slash) {\n                if (major == null)\n                    major = \"\" + sipVersion.charAt(i);\n                else\n                    major += sipVersion.charAt(i);\n            }\n            if (sipVersion.charAt(i) == '/')\n                slash = true;\n        }\n        return major;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.SipStatusLine#getVersionMinor()\n     */\n    public String getVersionMinor() {\n        if (sipVersion == null)\n            return null;\n        String minor = null;\n        boolean dot = false;\n        for (int i = 0; i < sipVersion.length(); i++) {\n            if (dot) {\n                if (minor == null)\n                    minor = \"\" + sipVersion.charAt(i);\n                else\n                    minor += sipVersion.charAt(i);\n            }\n            if (sipVersion.charAt(i) == '.')\n                dot = true;\n        }\n        return minor;\n    }\n}\n/*\n * $Log: StatusLine.java,v $\n * Revision 1.7  2009/10/18 13:46:34  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.6  2009/09/15 02:55:26  mranga\n * Issue number:  222\n * Add HeaderFactoryExt.createStatusLine(String) and HeaderFactoryExt.createRequestLine(String)\n * Allows users to easily parse SipFrag bodies (for example NOTIFY bodies\n * during call transfer).\n *\n * Revision 1.5  2009/07/17 18:57:38  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:48  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Subject.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * Supported SIP Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:39 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class Subject extends SIPHeader implements SubjectHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6479220126758862528L;\n    /** subject field\n     */\n    protected String subject;\n\n    /** Default Constructor.\n     */\n    public Subject() {\n        super(SUBJECT);\n    }\n\n    /**\n     * Generate the canonical form.\n     * @return String.\n     */\n    public String encodeBody() {\n        if (subject != null) {\n            return subject;\n        } else {\n            return \"\";\n        }\n    }\n\n    /**\n     * Sets the subject value of the SubjectHeader to the supplied string\n     * subject value.\n     *\n     * @param subject - the new subject value of this header\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the subject value.\n     */\n    public void setSubject(String subject) throws ParseException {\n        if (subject == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \" Subject, setSubject(), the subject parameter is null\");\n        this.subject = subject;\n    }\n\n    /**\n     * Gets the subject value of SubjectHeader\n     *\n     * @return subject of SubjectHeader\n     */\n    public String getSubject() {\n        return subject;\n    }\n\n}\n/*\n * $Log: Subject.java,v $\n * Revision 1.5  2009/07/17 18:57:39  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:21  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SubscriptionState.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.SubscriptionStateHeader;\n\nimport java.text.ParseException;\n\n/**\n *SubscriptionState header\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:39 $\n *\n * @author Olivier Deruelle <br/>\n *\n *\n */\npublic class SubscriptionState\n    extends ParametersHeader\n    implements SubscriptionStateHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6673833053927258745L;\n    protected int expires;\n    protected int retryAfter;\n    protected String reasonCode;\n    protected String state;\n\n    /** Creates a new instance of SubscriptionState */\n    public SubscriptionState() {\n        super(SIPHeaderNames.SUBSCRIPTION_STATE);\n        expires = -1;\n        retryAfter = -1;\n    }\n\n    /**\n    * Sets the relative expires value of the SubscriptionStateHeader. The\n    * expires value MUST be greater than zero and MUST be less than 2**31.\n    *\n    * @param expires - the new expires value of this SubscriptionStateHeader.\n    * @throws InvalidArgumentException if supplied value is less than zero.\n    */\n    public void setExpires(int expires) throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SubscriptionState, setExpires(), the expires parameter is  < 0\");\n        this.expires = expires;\n    }\n\n    /**\n     * Gets the expires value of the SubscriptionStateHeader. This expires value is\n     * relative time.\n     *\n     * @return the expires value of the SubscriptionStateHeader.\n     */\n    public int getExpires() {\n        return expires;\n    }\n\n    /**\n     * Sets the retry after value of the SubscriptionStateHeader. The retry after value\n     * MUST be greater than zero and MUST be less than 2**31.\n     *\n     * @param retryAfter - the new retry after value of this SubscriptionStateHeader\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     */\n    public void setRetryAfter(int retryAfter) throws InvalidArgumentException {\n        if (retryAfter <= 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SubscriptionState, setRetryAfter(), the retryAfter parameter is <=0\");\n        this.retryAfter = retryAfter;\n    }\n\n    /**\n     * Gets the retry after value of the SubscriptionStateHeader. This retry after\n     * value is relative time.\n     *\n     * @return the retry after value of the SubscriptionStateHeader.\n     */\n    public int getRetryAfter() {\n        return retryAfter;\n    }\n\n    /**\n     * Gets the reason code of SubscriptionStateHeader.\n     *\n     * @return the comment of this SubscriptionStateHeader, return null if no reason code\n     * is available.\n     */\n    public String getReasonCode() {\n        return reasonCode;\n    }\n\n    /**\n     * Sets the reason code value of the SubscriptionStateHeader.\n     *\n     * @param reasonCode - the new reason code string value of the SubscriptionStateHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the reason code.\n     */\n    public void setReasonCode(String reasonCode) throws ParseException {\n        if (reasonCode == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SubscriptionState, setReasonCode(), the reasonCode parameter is null\");\n        this.reasonCode = reasonCode;\n    }\n\n    /**\n     * Gets the state of SubscriptionStateHeader.\n     *\n     * @return the state of this SubscriptionStateHeader.\n     */\n    public String getState() {\n        return state;\n    }\n\n    /**\n     * Sets the state value of the SubscriptionStateHeader.\n     *\n     * @param state - the new state string value of the SubscriptionStateHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the state.\n     */\n    public void setState(String state) throws ParseException {\n        if (state == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SubscriptionState, setState(), the state parameter is null\");\n        this.state = state;\n    }\n\n    /** Just the encoded body of the header.\n     * @return the string encoded header body.\n     */\n    public String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (state != null)\n            buffer.append(state);\n        if (reasonCode != null)\n            buffer.append(\";reason=\").append(reasonCode);\n        if (expires != -1)\n            buffer.append(\";expires=\").append(expires);\n        if (retryAfter != -1)\n            buffer.append(\";retry-after=\").append(retryAfter);\n\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n        return buffer;\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Supported.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * Supported SIP Header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:39 $\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class Supported extends SIPHeader implements SupportedHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -7679667592702854542L;\n    /* the Option field\n     */\n    protected String optionTag;\n\n    /**\n     * default constructor\n     */\n    public Supported() {\n        super(SIPHeaderNames.SUPPORTED);\n        optionTag = null;\n    }\n\n    /**\n     * Constructor\n     * @param option_tag String to set\n     */\n    public Supported(String option_tag) {\n        super(SIPHeaderNames.SUPPORTED);\n        optionTag = option_tag;\n    }\n\n    /**\n     * Return canonical form of the header.\n     * @return encoded header.\n     */\n    public String encode() {\n        String retval = headerName + COLON;\n        if (optionTag != null)\n            retval += SP + optionTag;\n        retval += NEWLINE;\n        return retval;\n    }\n\n    /**\n     * Just the encoded body of the header.\n     * @return the string encoded header body.\n     */\n    public String encodeBody() {\n        return optionTag != null ? optionTag : \"\";\n    }\n\n    /**\n     * Sets the option tag value to the new supplied <var>optionTag</var>\n     * parameter.\n     *\n     * @param optionTag - the new string value of the option tag.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the optionTag value.\n     */\n    public void setOptionTag(String optionTag) throws ParseException {\n        if (optionTag == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, Supported, \"\n                    + \"setOptionTag(), the optionTag parameter is null\");\n        this.optionTag = optionTag;\n    }\n\n    /**\n     * Gets the option tag of this OptionTag class.\n     *\n     * @return the string that identifies the option tag value.\n     */\n    public String getOptionTag() {\n        return optionTag;\n    }\n}\n/*\n * $Log: Supported.java,v $\n * Revision 1.5  2009/07/17 18:57:39  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:27  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:30  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/SupportedList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * A list of supported headers.\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:39 $\n * @see Supported\n */\npublic class SupportedList extends SIPHeaderList<Supported>{\n\n    /**\n     *\n     */\n    private static final long serialVersionUID = -4539299544895602367L;\n\n    public Object clone() {\n        SupportedList retval = new SupportedList();\n        retval.clonehlist(this.hlist);\n        return retval;\n    }\n\n    /** Default Constructor\n     */\n    public SupportedList() {\n        super(Supported.class, SupportedHeader.NAME);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/TimeStamp.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\n\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.*;\n\n/**\n * TimeStamp SIP Header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/10/18 13:46:31 $\n *\n * @author M. Ranganathan <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class TimeStamp extends SIPHeader implements TimeStampHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3711322366481232720L;\n\n    /**\n     * timeStamp field\n     */\n    protected long timeStamp = -1;\n\n    /**\n     * delay field\n     */\n    protected int delay = -1;\n\n    protected float delayFloat = -1;\n\n    private float timeStampFloat = -1;\n\n    /**\n     * Default Constructor\n     */\n    public TimeStamp() {\n        super(TIMESTAMP);\n        delay = -1;\n    }\n\n    private String getTimeStampAsString() {\n        if (timeStamp == -1 && timeStampFloat == -1)\n            return \"\";\n        else if (timeStamp != -1)\n            return Long.toString(timeStamp);\n        else\n            return Float.toString(timeStampFloat);\n    }\n\n    private String getDelayAsString() {\n        if (delay == -1 && delayFloat == -1)\n            return \"\";\n        else if (delay != -1)\n            return Integer.toString(delay);\n        else\n            return Float.toString(delayFloat);\n    }\n\n    /**\n     * Return canonical form of the header.\n     *\n     * @return String\n     */\n    public String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n        String s1 = getTimeStampAsString();\n        String s2 = getDelayAsString();\n        if (s1.equals(\"\") && s2.equals(\"\"))\n            return \"\";\n        if (!s1.equals(\"\"))\n            retval.append(s1);\n        if (!s2.equals(\"\"))\n            retval.append(\" \").append(s2);\n        return retval.toString();\n\n    }\n\n    /**\n     * return true if delay exists\n     *\n     * @return boolean\n     */\n    public boolean hasDelay() {\n        return delay != -1;\n    }\n\n    /*\n     * remove the Delay field\n     */\n    public void removeDelay() {\n        delay = -1;\n    }\n\n\n\n    public void setTimeStamp(float timeStamp) throws InvalidArgumentException {\n        if (timeStamp < 0)\n            throw new InvalidArgumentException(\n                    \"JAIN-SIP Exception, TimeStamp, \"\n                            + \"setTimeStamp(), the timeStamp parameter is <0\");\n        this.timeStamp = -1;\n        this.timeStampFloat = timeStamp;\n    }\n\n\n    public float getTimeStamp() {\n        return this.timeStampFloat == -1 ? Float.valueOf(timeStamp).floatValue()\n                : this.timeStampFloat;\n    }\n\n\n\n    public float getDelay() {\n        return delayFloat == -1 ? Float.valueOf(delay).floatValue() : delayFloat;\n    }\n\n    /**\n     * Sets the new delay value of the TimestampHeader to the delay paramter\n     * passed to this method\n     *\n     * @param delay -\n     *            the Float.valueOf delay value\n     * @throws InvalidArgumentException\n     *             if the delay value argumenmt is a negative value other than\n     *             <code>-1</code>.\n     */\n\n    public void setDelay(float delay) throws InvalidArgumentException {\n        if (delay < 0 && delay != -1)\n            throw new InvalidArgumentException(\n                    \"JAIN-SIP Exception, TimeStamp, \"\n                            + \"setDelay(), the delay parameter is <0\");\n        this.delayFloat = delay;\n        this.delay = -1;\n    }\n\n    public long getTime() {\n        return this.timeStamp == -1 ? (long) timeStampFloat : timeStamp;\n    }\n\n    public int getTimeDelay() {\n        return this.delay == -1 ? (int) delayFloat : delay;\n\n    }\n\n    public void setTime(long timeStamp) throws InvalidArgumentException {\n        if (timeStamp < -1)\n            throw new InvalidArgumentException(\"Illegal timestamp\");\n        this.timeStamp = timeStamp;\n        this.timeStampFloat = -1;\n\n    }\n\n    public void setTimeDelay(int delay) throws InvalidArgumentException {\n        if (delay < -1)\n            throw new InvalidArgumentException(\"Value out of range \" + delay);\n        this.delay = delay;\n        this.delayFloat = -1;\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/To.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.HostPort;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.parser.Parser;\n\nimport javax2.sip.header.ToHeader;\n\nimport java.text.ParseException;\n\n/**\n * To SIP Header.\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:39 $\n *\n * @author M. Ranganathan <br/>\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\n\npublic final class To extends AddressParametersHeader implements\n        javax2.sip.header.ToHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -4057413800584586316L;\n\n    /**\n     * default Constructor.\n     */\n    public To() {\n        super(TO,true);\n    }\n\n    /**\n     * Generate a TO header from a FROM header\n     */\n    public To(From from) {\n        super(TO);\n        setAddress(from.address);\n        setParameters(from.parameters);\n    }\n\n    /**\n     * Encode the header into a String.\n     *\n     * @since 1.0\n     * @return String\n     */\n    public String encode() {\n        return headerName + COLON + SP + encodeBody() + NEWLINE;\n    }\n\n    /**\n     * Encode the header content into a String.\n     *\n     * @return String\n     */\n    protected String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        if (address != null) {\n            if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n                buffer.append(LESS_THAN);\n            }\n            address.encode(buffer);\n            if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n                buffer.append(GREATER_THAN);\n            }\n\n            if (!parameters.isEmpty()) {\n                buffer.append(SEMICOLON);\n                parameters.encode(buffer);\n            }\n        }\n        return buffer;\n    }\n\n    /**\n     * Conveniance accessor function to get the hostPort field from the address.\n     * Warning -- this assumes that the embedded URI is a SipURL.\n     *\n     * @return hostport field\n     */\n    public HostPort getHostPort() {\n        if (address == null)\n            return null;\n        return address.getHostPort();\n    }\n\n    /**\n     * Get the display name from the address.\n     *\n     * @return Display name\n     */\n    public String getDisplayName() {\n        if (address == null)\n            return null;\n        return address.getDisplayName();\n    }\n\n    /**\n     * Get the tag parameter from the address parm list.\n     *\n     * @return tag field\n     */\n    public String getTag() {\n        if (parameters == null)\n            return null;\n        return getParameter(ParameterNames.TAG);\n\n    }\n\n    /**\n     * Boolean function\n     *\n     * @return true if the Tag exist\n     */\n    public boolean hasTag() {\n        if (parameters == null)\n            return false;\n        return hasParameter(ParameterNames.TAG);\n\n    }\n\n    /**\n     * remove Tag member\n     */\n    public void removeTag() {\n            if (parameters != null)\n                parameters.delete(ParameterNames.TAG);\n\n    }\n\n    /**\n     * Set the tag member. This should remain empty for the initial request in\n     * a dialog.\n     *\n     * @param t - tag String to set.\n     */\n    public void setTag(String t) throws ParseException {\n        // JvB: check that it is a valid token\n        Parser.checkToken(t);\n        this.setParameter(ParameterNames.TAG, t);\n    }\n\n    /**\n     * Get the user@host port string.\n     */\n    public String getUserAtHostPort() {\n        if (address == null)\n            return null;\n        return address.getUserAtHostPort();\n    }\n\n    public boolean equals(Object other) {\n        return (other instanceof ToHeader) && super.equals(other);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Unsupported.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.text.ParseException;\n\n/**\n * the Unsupported header.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:57:40 $\n * @author Olivier Deruelle <br/>\n *\n *\n *\n */\npublic class Unsupported\n    extends SIPHeader\n    implements javax2.sip.header.UnsupportedHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -2479414149440236199L;\n    /** option-Tag field.\n     */\n    protected String optionTag;\n\n    /** Default Constructor.\n     */\n    public Unsupported() {\n        super(NAME);\n    }\n\n    /** Constructor\n     * @param ot String to set\n     */\n    public Unsupported(String ot) {\n        super(NAME);\n        optionTag = ot;\n    }\n\n    /**\n     * Return a canonical value.\n     * @return String.\n     */\n    public String encodeBody() {\n        return optionTag;\n    }\n\n    /** get the option tag field\n     * @return option Tag field\n     */\n    public String getOptionTag() {\n        return optionTag;\n    }\n\n    /**\n     * Set the option member\n     * @param o String to set\n     */\n    public void setOptionTag(String o) throws ParseException {\n        if (o == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \" Unsupported, setOptionTag(), The option tag parameter is null\");\n        optionTag = o;\n    }\n}\n/*\n * $Log: Unsupported.java,v $\n * Revision 1.5  2009/07/17 18:57:40  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.4  2006/07/13 09:01:34  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.2  2004/01/22 13:26:30  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/UnsupportedList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport java.util.Iterator;\n\nimport javax2.sip.header.*;\n\n/**\n * List of Unsupported headers.\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:40 $\n * @author M. Ranganathan\n */\npublic class UnsupportedList extends SIPHeaderList<Unsupported> {\n\n\n    private static final long serialVersionUID = -4052610269407058661L;\n\n\n    /** Default Constructor\n     */\n    public UnsupportedList() {\n        super(Unsupported.class, UnsupportedHeader.NAME);\n    }\n\n\n    public Object clone() {\n        UnsupportedList retval = new UnsupportedList();\n        return retval.clonehlist(this.hlist);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/UserAgent.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport java.util.*;\nimport java.text.ParseException;\n\nimport javax2.sip.header.*;\n\n/**\n * the UserAgent SIPObject.\n *\n * @author Olivier Deruelle <br/>\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:40 $\n *\n *\n *\n */\npublic class UserAgent extends SIPHeader implements UserAgentHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 4561239179796364295L;\n    /** Product tokens.\n    */\n    protected List productTokens;\n\n    /**\n     * Return canonical form.\n     * pmusgrave - put a space between products (preserves format of header)\n     * @return String\n     */\n    private String encodeProduct() {\n        StringBuffer tokens = new StringBuffer();\n        ListIterator it = productTokens.listIterator();\n\n        while (it.hasNext()) {\n            tokens.append((String) it.next());\n\n        }\n        return tokens.toString();\n    }\n\n    /** set the productToken field\n     * @param pt String to set\n     */\n    public void addProductToken(String pt) {\n        productTokens.add(pt);\n    }\n\n    /**\n     * Constructor.\n     */\n    public UserAgent() {\n        super(NAME);\n        productTokens = new LinkedList();\n    }\n\n    /** Encode only the body of this header.\n    *@return encoded value of the header.\n    */\n    public String encodeBody() {\n        return encodeProduct();\n    }\n\n    /**\n    * Returns the list value of the product parameter.\n    *\n    * @return the software of this UserAgentHeader\n    */\n    public ListIterator getProduct() {\n        if (productTokens == null || productTokens.isEmpty())\n            return null;\n        else\n            return productTokens.listIterator();\n    }\n\n    /**\n     * Sets the product value of the UserAgentHeader.\n     *\n     * @param product - a List specifying the product value\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the product value.\n     */\n    public void setProduct(List product) throws ParseException {\n        if (product == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, UserAgent, \"\n                    + \"setProduct(), the \"\n                    + \" product parameter is null\");\n        productTokens = product;\n    }\n\n    public Object clone() {\n        UserAgent retval = (UserAgent) super.clone();\n        if (productTokens != null)\n            retval.productTokens = new LinkedList (productTokens);\n        return retval;\n    }\n\n}\n/*\n * $Log: UserAgent.java,v $\n * Revision 1.8  2009/07/17 18:57:40  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2008/07/30 14:36:06  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Fix minor issue in encoding of user-agent header.\n *\n * Revision 1.6  2006/10/12 11:57:55  pmusgrave\n * Issue number:  79, 80\n * Submitted by:  pmusgrave@newheights.com\n * Reviewed by:   mranga\n *\n * Revision 1.5  2006/07/13 09:01:48  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.3  2005/04/16 20:38:51  dmuresan\n * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies\n *\n * Revision 1.2  2004/01/22 13:26:30  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Via.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.core.Host;\nimport gov2.nist.core.HostPort;\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.javax2.sip.stack.HopImpl;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.address.Hop;\nimport javax2.sip.header.ViaHeader;\n\nimport java.text.ParseException;\n\n/**\n * Via SIPHeader (these are strung together in a ViaList).\n *\n * @see ViaList\n *\n * @version 1.2 $Revision: 1.17 $ $Date: 2009/10/18 13:46:33 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class Via\n    extends ParametersHeader\n    implements javax2.sip.header.ViaHeader, ViaHeaderExt {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 5281728373401351378L;\n\n    /** The branch parameter is included by every forking proxy.\n    */\n    public static final String BRANCH = ParameterNames.BRANCH;\n\n    /** The \"received\" parameter is added only for receiver-added Via Fields.\n     */\n    public static final String RECEIVED = ParameterNames.RECEIVED;\n\n    /** The \"maddr\" paramter is designating the multicast address.\n     */\n    public static final String MADDR = ParameterNames.MADDR;\n\n    /** The \"TTL\" parameter is designating the time-to-live value.\n     */\n    public static final String TTL = ParameterNames.TTL;\n\n    /** The RPORT parameter.\n    */\n    public static final String RPORT = ParameterNames.RPORT;\n\n    /** sentProtocol field.\n     */\n    protected Protocol sentProtocol;\n\n    /** sentBy field.\n     */\n    protected HostPort sentBy;\n\n    /**\n     * comment field\n     *\n     * JvB note: RFC3261 does not allow a comment to appear in Via headers, and this\n     * is not accessible through the API. Suggest removal\n     */\n    protected String comment;\n\n    private boolean rPortFlag = false;\n\n    /** Default constructor\n    */\n    public Via() {\n        super(NAME);\n        sentProtocol = new Protocol();\n    }\n\n    public boolean equals(Object other) {\n\n        if (other==this) return true;\n\n        if (other instanceof ViaHeader) {\n            final ViaHeader o = (ViaHeader) other;\n            return getProtocol().equalsIgnoreCase( o.getProtocol() )\n                && getTransport().equalsIgnoreCase( o.getTransport() )\n                && getHost().equalsIgnoreCase( o.getHost() )\n                && getPort() == o.getPort()\n                && equalParameters( o );\n        }\n        return false;\n    }\n\n\n    /** get the Protocol Version\n     * @return String\n     */\n    public String getProtocolVersion() {\n        if (sentProtocol == null)\n            return null;\n        else\n            return sentProtocol.getProtocolVersion();\n    }\n\n    /**\n     * Accessor for the sentProtocol field.\n     * @return Protocol field\n     */\n    public Protocol getSentProtocol() {\n\n        return sentProtocol;\n    }\n\n    /**\n     * Accessor for the sentBy field\n     *@return SentBy field\n     */\n    public HostPort getSentBy() {\n        return sentBy;\n    }\n\n    /**\n     * Get the host, port and transport as a Hop. This is\n     * useful for the stack to avoid duplication of code.\n     *\n     */\n    public Hop getHop() {\n        HopImpl hop = new HopImpl(sentBy.getHost().getHostname(),\n                sentBy.getPort(),sentProtocol.getTransport());\n        return hop;\n    }\n\n    /**\n     * Accessor for the parameters field\n     * @return parameters field\n     */\n    public NameValueList getViaParms() {\n        return parameters;\n    }\n\n    /**\n     * Accessor for the comment field.\n     * @return comment field.\n     * @deprecated RFC 2543 support feature.\n     */\n    public String getComment() {\n        return comment;\n    }\n\n\n\n    /** port of the Via Header.\n     * @return true if Port exists.\n     */\n    public boolean hasPort() {\n        return (getSentBy()).hasPort();\n    }\n\n    /** comment of the Via Header.\n     *\n     * @return false if comment does not exist and true otherwise.\n     */\n    public boolean hasComment() {\n        return comment != null;\n    }\n\n    /** remove the port.\n     */\n    public void removePort() {\n        sentBy.removePort();\n    }\n\n    /** remove the comment field.\n     */\n    public void removeComment() {\n        comment = null;\n    }\n\n    /** set the Protocol Version\n     * @param protocolVersion String to set\n     */\n    public void setProtocolVersion(String protocolVersion) {\n        if (sentProtocol == null)\n            sentProtocol = new Protocol();\n        sentProtocol.setProtocolVersion(protocolVersion);\n    }\n\n    /** set the Host of the Via Header\n         * @param host String to set\n         */\n    public void setHost(Host host) {\n        if (sentBy == null) {\n            sentBy = new HostPort();\n        }\n        sentBy.setHost(host);\n    }\n\n    /**\n     * Set the sentProtocol member\n     * @param s Protocol to set.\n     */\n    public void setSentProtocol(Protocol s) {\n        sentProtocol = s;\n    }\n\n    /**\n     * Set the sentBy member\n     * @param s HostPort to set.\n     */\n    public void setSentBy(HostPort s) {\n        sentBy = s;\n    }\n\n    /**\n     * Set the comment member\n     * @param c String to set.\n     * @deprecated This is an RFC 2543 feature.\n     */\n    public void setComment(String c) {\n        comment = c;\n    }\n\n    /** Encode the body of this header (the stuff that follows headerName).\n     * A.K.A headerValue.\n     */\n    protected String encodeBody() {\n        return encodeBody(new StringBuffer()).toString();\n    }\n\n    protected StringBuffer encodeBody(StringBuffer buffer) {\n        sentProtocol.encode(buffer);\n        buffer.append(SP);\n        sentBy.encode(buffer);\n        if (!parameters.isEmpty()) {\n            buffer.append(SEMICOLON);\n            parameters.encode(buffer);\n        }\n        if (comment != null) {\n            buffer.append(SP).append(LPAREN).append(comment).append(RPAREN);\n        }\n        if (rPortFlag) buffer.append(\";rport\");\n        return buffer;\n    }\n\n    /**\n     * Set the host part of this ViaHeader to the newly supplied <code>host</code>\n     * parameter.\n     *\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the host value.\n     */\n    public void setHost(String host) throws ParseException {\n        if (sentBy == null)\n            sentBy = new HostPort();\n        try {\n            Host h = new Host(host);\n            sentBy.setHost(h);\n        } catch (Exception e) {\n            throw new NullPointerException(\" host parameter is null\");\n        }\n    }\n\n    /**\n    * Returns the host part of this ViaHeader.\n    *\n    * @return  the string value of the host\n    */\n    public String getHost() {\n        if (sentBy == null)\n            return null;\n        else {\n            Host host = sentBy.getHost();\n            if (host == null)\n                return null;\n            else\n                return host.getHostname();\n        }\n    }\n\n    /**\n     * Set the port part of this ViaHeader to the newly supplied <code>port</code>\n     * parameter.\n     *\n     * @param port - the Integer.valueOf value of the port of this ViaHeader\n     */\n    public void setPort(int port) throws InvalidArgumentException {\n\n        if ( port!=-1 && (port<1 || port>65535)) {\n            throw new InvalidArgumentException( \"Port value out of range -1, [1..65535]\" );\n        }\n\n        if (sentBy == null)\n            sentBy = new HostPort();\n        sentBy.setPort(port);\n    }\n\n    /**\n     * Set the RPort flag parameter\n     */\n    public void setRPort(){\n        rPortFlag = true;\n    }\n\n    /**\n     * Returns the port part of this ViaHeader.\n     *\n     * @return the integer value of the port\n     */\n    public int getPort() {\n        if (sentBy == null)\n            return -1;\n        return sentBy.getPort();\n    }\n\n\n    /**\n    * Return the rport parameter.\n    *\n    *@return the rport parameter or -1.\n    */\n       public int getRPort() {\n         String strRport = getParameter(ParameterNames.RPORT);\n         if (strRport != null && ! strRport.equals(\"\"))\n            return Integer.valueOf(strRport).intValue();\n         else\n            return -1;\n         }\n\n\n    /**\n     * Returns the value of the transport parameter.\n     *\n     * @return the string value of the transport paramter of the ViaHeader\n     */\n    public String getTransport() {\n        if (sentProtocol == null)\n            return null;\n        return sentProtocol.getTransport();\n    }\n\n    /**\n     * Sets the value of the transport. This parameter specifies\n     * which transport protocol to use for sending requests and responses to\n     * this entity. The following values are defined: \"udp\", \"tcp\", \"sctp\",\n     * \"tls\", but other values may be used also.\n     *\n     * @param transport - new value for the transport parameter\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the transport value.\n     */\n    public void setTransport(String transport) throws ParseException {\n        if (transport == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"Via, setTransport(), the transport parameter is null.\");\n        if (sentProtocol == null)\n            sentProtocol = new Protocol();\n        sentProtocol.setTransport(transport);\n    }\n\n    /**\n     * Returns the value of the protocol used.\n     *\n     * @return the string value of the protocol paramter of the ViaHeader\n     */\n    public String getProtocol() {\n        if (sentProtocol == null)\n            return null;\n        return sentProtocol.getProtocol();// JvB: Return name ~and~ version\n    }\n\n    /**\n     * Sets the value of the protocol parameter. This parameter specifies\n     * which protocol is used, for example \"SIP/2.0\".\n     *\n     * @param protocol - new value for the protocol parameter\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the protocol value.\n     */\n    public void setProtocol(String protocol) throws ParseException {\n        if (protocol == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"Via, setProtocol(), the protocol parameter is null.\");\n\n        if (sentProtocol == null)\n            sentProtocol = new Protocol();\n\n        sentProtocol.setProtocol(protocol);\n    }\n\n    /**\n     * Returns the value of the ttl parameter, or -1 if this is not set.\n     *\n     * @return the integer value of the <code>ttl</code> parameter\n     */\n    public int getTTL() {\n        int ttl = getParameterAsInt(ParameterNames.TTL);\n        return ttl;\n    }\n\n    /**\n     * Sets the value of the ttl parameter. The ttl parameter specifies the\n     * time-to-live value when packets are sent using UDP multicast.\n     *\n     * @param ttl - new value of the ttl parameter\n     * @throws InvalidArgumentException if supplied value is less than zero or\n     * greater than 255, excluding -1 the default not set value.\n     */\n    public void setTTL(int ttl) throws InvalidArgumentException {\n        if (ttl < 0 && ttl != -1)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP Exception\"\n                    + \", Via, setTTL(), the ttl parameter is < 0\");\n        setParameter(new NameValue(ParameterNames.TTL, Integer.valueOf(ttl)));\n    }\n\n    /**\n     * Returns the value of the <code>maddr</code> parameter, or null if this\n     * is not set.\n     *\n     * @return the string value of the maddr parameter\n     */\n    public String getMAddr() {\n        return getParameter(ParameterNames.MADDR);\n    }\n\n    /**\n     * Sets the value of the <code>maddr</code> parameter of this ViaHeader. The\n     * maddr parameter indicates the server address to be contacted for this\n     * user, overriding any address derived from the host field.\n     *\n     * @param  mAddr new value of the <code>maddr</code> parameter\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the mAddr value.\n     */\n    public void setMAddr(String mAddr) throws ParseException {\n        if (mAddr == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"Via, setMAddr(), the mAddr parameter is null.\");\n\n        Host host = new Host();\n        host.setAddress(mAddr);\n        NameValue nameValue = new NameValue(ParameterNames.MADDR, host);\n        setParameter(nameValue);\n\n    }\n\n    /**\n     * Gets the received paramater of the ViaHeader. Returns null if received\n     * does not exist.\n     *\n     * @return the string received value of ViaHeader\n     */\n    public String getReceived() {\n        return getParameter(ParameterNames.RECEIVED);\n    }\n\n    /**\n     * Sets the received parameter of ViaHeader.\n     *\n     * @param received - the newly supplied received parameter.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the received value.\n     */\n    public void setReceived(String received) throws ParseException {\n        if (received == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"Via, setReceived(), the received parameter is null.\");\n\n        setParameter(ParameterNames.RECEIVED, received);\n\n    }\n\n    /**\n     * Gets the branch paramater of the ViaHeader. Returns null if branch\n     * does not exist.\n     *\n     * @return the string branch value of ViaHeader\n     */\n    public String getBranch() {\n        return getParameter(ParameterNames.BRANCH);\n    }\n\n    /**\n     * Sets the branch parameter of the ViaHeader to the newly supplied\n     * branch value.\n     *\n     * @param branch - the new string branch parmameter of the ViaHeader.\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the branch value.\n     */\n    public void setBranch(String branch) throws ParseException {\n        if (branch == null || branch.length()==0)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"Via, setBranch(), the branch parameter is null or length 0.\");\n\n        setParameter(ParameterNames.BRANCH, branch);\n    }\n\n    public Object clone() {\n        Via retval = (Via) super.clone();\n        if (this.sentProtocol != null)\n            retval.sentProtocol = (Protocol) this.sentProtocol.clone();\n        if (this.sentBy != null)\n            retval.sentBy = (HostPort) this.sentBy.clone();\n        if ( this.getRPort() != -1)\n            retval.setParameter(RPORT,this.getRPort());\n        return retval;\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.ViaHeaderExt#getSentByField()\n     */\n    public String getSentByField() {\n        if(sentBy != null)\n            return sentBy.encode();\n        return null;\n    }\n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.ViaHeaderExt#getSentProtocolField()\n     */\n    public String getSentProtocolField() {\n        if(sentProtocol != null)\n            return sentProtocol.encode();\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ViaHeaderExt.java",
    "content": "/*\n * This code has been contributed by the authors to the public domain.\n */\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.ViaHeader;\n\n\n/**\n * @author jean.deruelle@gmail.com\n *\n */\npublic interface ViaHeaderExt extends ViaHeader {\n    /**\n     * Returns hostname:port as a string equivalent to the \"sent-by\" field\n     * @return \"sent-by\" field\n     * @since 2.0\n     */\n    public String getSentByField();\n    /**\n     * Returns transport to the \"sent-protocol\" field\n     * @return \"sent-protocol\" field\n     * @since 2.0\n     */\n    public String getSentProtocolField();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ViaList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\nimport java.util.Iterator;\n\n/**\n * Keeps a list and a hashtable of via header functions.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:41 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic final class ViaList extends SIPHeaderList<Via> {\n\n    private static final long serialVersionUID = 3899679374556152313L;\n\n    public Object clone() {\n        ViaList retval = new ViaList();\n        return retval.clonehlist(this.hlist);\n    }\n    /**\n     * Default Constructor.\n     */\n    public ViaList() {\n        super(Via.class, ViaHeader.NAME);\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/WWWAuthenticate.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport gov2.nist.javax2.sip.header.ims.WWWAuthenticateHeaderIms;\n\nimport javax2.sip.address.URI;\nimport javax2.sip.header.*;\n\n/**\n * The WWWAuthenticate SIP header.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:41 $\n *\n *\n *\n * @see WWWAuthenticateList SIPHeader which strings these together.\n */\n\npublic class WWWAuthenticate\n    extends AuthenticationHeader\n    implements WWWAuthenticateHeader, WWWAuthenticateHeaderIms {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 115378648697363486L;\n\n    /**\n     * Default Constructor.\n     */\n    public WWWAuthenticate() {\n        super(NAME);\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AuthenticationHeader#getURI()\n     *\n     * @since 1.2 this method is deprecated, uri is not a valid paramter for this header\n     * Fail silently for backwards compatibility\n     */\n    public URI getURI() {\n        return null;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.AuthenticationHeader#setURI(javax2.sip.address.URI)\n     *\n     * @since 1.2 this method is deprecated, uri is not a valid paramter for this header\n     * Fail silently for backwards compatibility\n     */\n    public void setURI(URI uri) {\n        // empty, fail silently\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/WWWAuthenticateList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport javax2.sip.header.*;\n\n/**\n * WWWAuthenticate SIPHeader (of which there can be several?)\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:41 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class WWWAuthenticateList extends SIPHeaderList<WWWAuthenticate> {\n\n\n    private static final long serialVersionUID = -6978902284285501346L;\n\n\n    public Object clone() {\n        WWWAuthenticateList retval = new WWWAuthenticateList();\n        return retval.clonehlist(this.hlist);\n    }\n    /**\n     * constructor.\n     */\n    public WWWAuthenticateList() {\n        super(WWWAuthenticate.class, WWWAuthenticateHeader.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/Warning.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.*;\n\n/**\n * the WarningValue SIPObject.\n *\n * @author M. Ranganathan   <br/>\n * @author Olivier Deruelle <br/>\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/18 13:46:33 $\n *\n *\n *\n * @see WarningList SIPHeader which strings these together.\n */\npublic class Warning extends SIPHeader implements WarningHeader {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -3433328864230783899L;\n\n    /** warn code field, the warn code consists of three digits.\n     */\n    protected int code;\n\n    /** the name or pseudonym of the server adding\n     * the Warning header, for use in debugging\n     */\n    protected String agent;\n\n    /** warn-text field\n     */\n    protected String text;\n\n    /**\n     * constructor.\n     */\n    public Warning() {\n        super(WARNING);\n    }\n\n    /** Encode the body of the header (return the stuff following name:).\n     *@return the string encoding of the header value.\n     */\n    public String encodeBody() {\n        return text != null\n            ? Integer.toString(code)\n                + SP\n                + agent\n                + SP\n                + DOUBLE_QUOTE\n                + text\n                + DOUBLE_QUOTE\n            : Integer.toString(code) + SP + agent;\n    }\n\n    /**\n    * Gets code of WarningHeader\n    * @return code of WarningHeader\n    */\n    public int getCode() {\n        return code;\n    }\n\n    /**\n    * Gets agent host of WarningHeader\n    * @return agent host of WarningHeader\n    */\n    public String getAgent() {\n        return agent;\n    }\n\n    /**\n    * Gets text of WarningHeader\n    * @return text of WarningHeader\n    */\n    public String getText() {\n        return text;\n    }\n\n    /**\n     * Sets code of WarningHeader\n     * @param code int to set\n     * @throws SipParseException if code is not accepted by implementation\n     */\n    public void setCode(int code) throws InvalidArgumentException {\n        if (code >99  && code < 1000) { // check this is a 3DIGIT code\n            this.code = code;\n        } else\n            throw new InvalidArgumentException(\n                \"Code parameter in the Warning header is invalid: code=\"\n                    + code);\n    }\n\n    /**\n     * Sets host of WarningHeader\n     * @param host String to set\n     * @throws ParseException if host is not accepted by implementation\n     */\n    public void setAgent(String host) throws ParseException {\n        if (host == null)\n            throw new NullPointerException(\"the host parameter in the Warning header is null\");\n        else {\n            this.agent = host;\n        }\n    }\n\n    /**\n     * Sets text of WarningHeader\n     * @param text String to set\n     * @throws ParseException if text is not accepted by implementation\n     */\n    public void setText(String text) throws ParseException {\n        if (text == null) {\n            throw new ParseException(\n                \"The text parameter in the Warning header is null\",\n                0);\n        } else\n            this.text = text;\n    }\n}\n/*\n * $Log: Warning.java,v $\n * Revision 1.8  2009/10/18 13:46:33  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.7  2009/07/17 18:57:41  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:01:44  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/04/22 22:51:16  mranga\n * Submitted by:  Thomas Froment\n * Reviewed by:   mranga\n *\n * Fixed corner cases.\n *\n * Revision 1.2  2004/01/22 13:26:30  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/WarningList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header;\n\nimport javax2.sip.header.*;\n\n/**\n * A list of Warning headers.\n *\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:41 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class WarningList extends SIPHeaderList<Warning> {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -1423278728898430175L;\n\n    public Object clone() {\n        WarningList retval = new WarningList();\n        return retval.clonehlist(this.hlist);\n    }\n    /**\n     * Constructor.\n     */\n    public WarningList() {\n        super(Warning.class, Warning.NAME);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/Join.java",
    "content": "/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header.extensions;\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n * Join SIPHeader.\n *\n * @author jean.deruelle@gmail.com  <br/>\n *\n * @version JAIN-SIP-1.2\n *\n *\n */\n\npublic class Join\n    extends ParametersHeader implements ExtensionHeader, JoinHeader {\n\n    /**\n     *\n     */\n    private static final long serialVersionUID = -840116548918120056L;\n\n    public static final String NAME = \"Join\";\n\n    /**\n     * callIdentifier field\n     */\n    public CallIdentifier callIdentifier;\n    public String callId;\n\n    /**\n     * Default constructor\n     */\n    public Join() {\n        super(NAME);\n    }\n\n    /** Constructor given the call Identifier.\n     *@param callId string call identifier (should be localid@host)\n     *@throws IllegalArgumentException if call identifier is bad.\n     */\n    public Join(String callId) throws IllegalArgumentException {\n        super(NAME);\n        this.callIdentifier = new CallIdentifier(callId);\n    }\n\n    /**\n     * Encode the body part of this header (i.e. leave out the hdrName).\n     * @return String encoded body part of the header.\n     */\n    public String encodeBody() {\n        if (callId == null)\n            return null;\n        else {\n            String retVal = callId;\n            if (!parameters.isEmpty()) {\n                retVal += SEMICOLON + parameters.encode();\n            }\n            return retVal;\n        }\n    }\n\n    /**\n     * get the CallId field. This does the same thing as encodeBody\n     *\n     * @return String the encoded body part of the\n     */\n    public String getCallId() {\n        return callId;\n    }\n\n    /**\n     * get the call Identifer member.\n     * @return CallIdentifier\n     */\n    public CallIdentifier getCallIdentifer() {\n        return callIdentifier;\n    }\n\n    /**\n     * set the CallId field\n     * @param cid String to set. This is the body part of the Call-Id\n     *  header. It must have the form localId@host or localId.\n     * @throws IllegalArgumentException if cid is null, not a token, or is\n     * not a token@token.\n     */\n    public void setCallId(String cid) {\n        callId = cid;\n    }\n\n    /**\n     * Set the callIdentifier member.\n     * @param cid CallIdentifier to set (localId@host).\n     */\n    public void setCallIdentifier(CallIdentifier cid) {\n        callIdentifier = cid;\n    }\n\n    /**\n     * Get the to-tag parameter from the address parm list.\n     * @return tag field\n     */\n    public String getToTag() {\n        if (parameters == null)\n            return null;\n        return getParameter(ParameterNames.TO_TAG);\n    }\n    /**\n     * Set the to-tag member\n     * @param t tag to set. From tags are mandatory.\n     */\n    public void setToTag(String t) throws ParseException {\n        if (t == null)\n            throw new NullPointerException(\"null tag \");\n        else if (t.trim().equals(\"\"))\n            throw new ParseException(\"bad tag\", 0);\n        this.setParameter(ParameterNames.TO_TAG, t);\n    }\n    /** Boolean function\n     * @return true if the Tag exist\n     */\n    public boolean hasToTag() {\n        return hasParameter(ParameterNames.TO_TAG);\n    }\n\n    /** remove Tag member\n     */\n    public void removeToTag() {\n        parameters.delete(ParameterNames.TO_TAG);\n    }\n    /**\n     * Get the from-tag parameter from the address parm list.\n     * @return tag field\n     */\n    public String getFromTag() {\n        if (parameters == null)\n            return null;\n        return getParameter(ParameterNames.FROM_TAG);\n    }\n    /**\n     * Set the to-tag member\n     * @param t tag to set. From tags are mandatory.\n     */\n    public void setFromTag(String t) throws ParseException {\n        if (t == null)\n            throw new NullPointerException(\"null tag \");\n        else if (t.trim().equals(\"\"))\n            throw new ParseException(\"bad tag\", 0);\n        this.setParameter(ParameterNames.FROM_TAG, t);\n    }\n    /** Boolean function\n     * @return true if the Tag exist\n     */\n    public boolean hasFromTag() {\n        return hasParameter(ParameterNames.FROM_TAG);\n    }\n\n    /** remove Tag member\n     */\n    public void removeFromTag() {\n        parameters.delete(ParameterNames.FROM_TAG);\n    }\n\n\n\n    public void setValue(String value) throws ParseException {\n        // not implemented.\n        throw new ParseException(value,0);\n\n    }\n\n//  public Object clone() {\n//      CallID retval = (CallID) super.clone();\n//      if (this.callIdentifier != null)\n//      retval.setCallIdentifier( (CallIdentifier) this.callIdentifier.clone() );\n//      return retval;\n//  }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/JoinHeader.java",
    "content": "/*\n * Conditions Of Use \n * \n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n * \n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *  \n * .\n * \n */\npackage gov2.nist.javax2.sip.header.extensions;\n\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n\n\n/**\n * The From header field indicates the logical identity of the initiator\n\n * of the request, possibly the user's address-of-record. This may be different\n\n * from the initiator of the dialog.  Requests sent by the callee to the caller\n\n * use the callee's address in the From header field.\n\n * <p>\n\n * Like the To header field, it contains a URI and optionally a display name,\n\n * encapsulated in a {@link javax2.sip.address.Address}.  It is used by SIP\n\n * elements to determine which processing rules to apply to a request (for\n\n * example, automatic call rejection). As such, it is very important that the\n\n * From URI not contain IP addresses or the FQDN of the host on which the UA is\n\n * running, since these are not logical names.\n\n * <p>\n\n * The From header field allows for a display name.  A UAC SHOULD use\n\n * the display name \"Anonymous\", along with a syntactically correct, but\n\n * otherwise meaningless URI (like sip:thisis@anonymous.invalid), if the\n\n * identity of the client is to remain hidden.\n\n * <p>\n\n * Usually, the value that populates the From header field in requests\n\n * generated by a particular UA is pre-provisioned by the user or by the\n\n * administrators of the user's local domain.  If a particular UA is used by\n\n * multiple users, it might have switchable profiles that include a URI\n\n * corresponding to the identity of the profiled user. Recipients of requests\n\n * can authenticate the originator of a request in order to ascertain that\n\n * they are who their From header field claims they are.\n\n * <p>\n\n * Two From header fields are equivalent if their URIs match, and their\n\n * parameters match. Extension parameters in one header field, not present in\n\n * the other are ignored for the purposes of comparison. This means that the\n\n * display name and presence or absence of angle brackets do not affect\n\n * matching.\n\n * <ul>\n\n * <li> The \"Tag\" parameter - is used in the To and From header fields of SIP\n\n * messages.  It serves as a general mechanism to identify a dialog, which is\n\n * the combination of the Call-ID along with two tags, one from each\n\n * participant in the dialog.  When a User Agent sends a request outside of a dialog,\n\n * it contains a From tag only, providing \"half\" of the dialog ID. The dialog\n\n * is completed from the response(s), each of which contributes the second half\n\n * in the To header field. When a tag is generated by a User Agent for insertion into\n\n * a request or response, it MUST be globally unique and cryptographically\n\n * random with at least 32 bits of randomness. Besides the requirement for\n\n * global uniqueness, the algorithm for generating a tag is implementation\n\n * specific.  Tags are helpful in fault tolerant systems, where a dialog is to\n\n * be recovered on an alternate server after a failure.  A UAS can select the\n\n * tag in such a way that a backup can recognize a request as part of a dialog\n\n * on the failed server, and therefore determine that it should attempt to\n\n * recover the dialog and any other state associated with it.\n\n * </ul>\n * For Example:<br>\n * <code>From: \"Bob\" sips:bob@biloxi.com ;tag=a48s<br>\n * From: sip:+12125551212@phone2net.com;tag=887s<br>\n * From: Anonymous sip:c8oqz84zk7z@privacy.org;tag=hyh8</code>\n *\n * @version 1.1\n * @author jean.deruelle@gmail.com\n */\npublic interface JoinHeader extends Parameters, Header {\n\n\n\n    /**\n\n     * Sets the tag parameter of the FromHeader. The tag in the From field of a\n     * request identifies the peer of the dialog. When a UA sends a request\n     * outside of a dialog, it contains a From tag only, providing \"half\" of\n     * the dialog Identifier.\n     * <p>\n     * The From Header MUST contain a new \"tag\" parameter, chosen by the UAC \n     * applicaton. Once the initial From \"tag\" is assigned it should not be \n     * manipulated by the application. That is on the client side for outbound \n     * requests the application is responsible for Tag assigmennment, after \n     * dialog establishment the stack will take care of Tag assignment.\n     *\n     * @param tag - the new tag of the FromHeader\n     * @throws ParseException which signals that an error has been reached\n     * unexpectedly while parsing the Tag value.\n     */\n    public void setToTag(String tag) throws ParseException;\n    public void setFromTag(String tag) throws ParseException;\n\n\n\n\n\n    /**\n\n     * Gets the tag of FromHeader. The Tag parameter identified the Peer of the\n\n     * dialogue and must always be present.\n\n     *\n\n     * @return the tag parameter of the FromHeader.\n\n     */\n\n    public String getToTag();\n    public String getFromTag();\n\n\n    /**\n\n     * Sets the Call-Id of the CallIdHeader. The CallId parameter uniquely\n\n     * identifies a serious of messages within a dialogue.\n\n     *\n\n     * @param callId - the string value of the Call-Id of this CallIdHeader.\n\n     * @throws ParseException which signals that an error has been reached\n\n     * unexpectedly while parsing the callId value.\n\n     */\n\n    public void setCallId(String callId) throws ParseException;\n\n\n\n    /**\n\n     * Returns the Call-Id of CallIdHeader. The CallId parameter uniquely\n\n     * identifies a series of messages within a dialogue.\n\n     *\n\n     * @return the String value of the Call-Id of this CallIdHeader\n\n     */\n\n    public String getCallId();\n\n\n\n    /**\n\n     * Name of JoinHeader\n\n     */\n\n    public final static String NAME = \"Join\";\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/MinSE.java",
    "content": "/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n/*\n* This code has been contributed by the author to the public domain.\n*/\npackage gov2.nist.javax2.sip.header.extensions;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport javax2.sip.*;\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n * MinSE SIP Header.\n *\n * (Created by modifying Expires.java)\n *\n * @version JAIN-SIP-1.1 $Revision: 1.4 $ $Date: 2009/10/18 13:46:36 $\n *\n * @author P. Musgrave <pmusgrave@newheights.com>  <br/>\n *\n */\npublic class MinSE\n    extends ParametersHeader implements ExtensionHeader, MinSEHeader {\n\n    // TODO: When the MinSEHeader is added to javax2 - move this there...pmusgrave\n    public static final String NAME = \"Min-SE\";\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 3134344915465784267L;\n\n    /** expires field\n     */\n    public int expires;\n\n    /** default constructor\n     */\n    public MinSE() {\n        super(NAME);\n    }\n\n    /**\n     * Return canonical form.\n     * @return String\n     */\n    public String encodeBody() {\n        String retval = Integer.toString(expires); // seems overkill - but Expires did this.\n\n        if (!parameters.isEmpty()) {\n            retval += SEMICOLON + parameters.encode();\n        }\n        return retval;\n    }\n\n    public void setValue(String value) throws ParseException {\n        // not implemented.\n        throw new ParseException(value,0);\n\n    }\n\n    /**\n     * Gets the expires value of the ExpiresHeader. This expires value is\n     *\n     * relative time.\n     *\n     *\n     *\n     * @return the expires value of the ExpiresHeader.\n     *\n     * @since JAIN SIP v1.1\n     *\n     */\n    public int getExpires() {\n        return expires;\n    }\n\n    /**\n     * Sets the relative expires value of the ExpiresHeader.\n     * The expires value MUST be greater than zero and MUST be\n     * less than 2**31.\n     *\n     * @param expires - the new expires value of this ExpiresHeader\n     *\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     *\n     * @since JAIN SIP v1.2\n     *\n     */\n    public void setExpires(int expires) throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad argument \" + expires);\n        this.expires = expires;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/MinSEHeader.java",
    "content": "package gov2.nist.javax2.sip.header.extensions;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\npublic interface MinSEHeader extends  Parameters, Header {\n\n    public final static String NAME = \"Min-SE\";\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/References.java",
    "content": "package gov2.nist.javax2.sip.header.extensions;\n\nimport gov2.nist.javax2.sip.header.ParametersHeader;\n\nimport java.text.ParseException;\nimport java.util.Iterator;\n\nimport javax2.sip.header.ExtensionHeader;\n\npublic class References extends ParametersHeader  implements ReferencesHeader,ExtensionHeader  {\n\n    private static final long serialVersionUID = 8536961681006637622L;\n    \n    \n    private String callId;\n    \n    public References() {\n        super(ReferencesHeader.NAME);\n    }\n  \n   \n\n  \n    public String getCallId() {\n       return callId;\n    }\n\n  \n   \n    public String getRel() {\n        return this.getParameter(REL);\n    }\n\n   \n\n\n    public void setCallId(String callId) {\n        this.callId = callId;\n    }\n\n       \n    public void setRel(String rel) throws ParseException{\n      if ( rel != null ) {\n          this.setParameter(REL,rel);\n      }\n    }\n\n  \n    public String getParameter(String name) {\n        return super.getParameter(name);\n    }\n\n    \n    public Iterator getParameterNames() {\n        return super.getParameterNames();\n    }\n\n   \n    public void removeParameter(String name) {\n       super.removeParameter(name);\n    }\n\n    \n    public void setParameter(String name, String value) throws ParseException {\n       super.setParameter(name,value); \n    }\n\n \n    public String getName() {\n        return ReferencesHeader.NAME;\n    }\n\n   \n    protected String encodeBody() {\n        if ( super.parameters.isEmpty()) {\n            return callId ;\n        } else {\n            return callId + \";\" + super.parameters.encode();\n        }\n    }\n\n   \n    public void setValue(String value) throws ParseException {\n        throw new UnsupportedOperationException(\"operation not supported\");\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/ReferencesHeader.java",
    "content": "package gov2.nist.javax2.sip.header.extensions;\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n/**\n * References header: See http://tools.ietf.org/html/draft-worley-references-05\n */\npublic interface ReferencesHeader extends Parameters, Header {\n    \n    public static final String NAME = \"References\";\n    \n    public static final String CHAIN = \"chain\";\n    \n    public static final String INQUIRY =  \"inquiry\";\n    \n    public static final String REFER = \"refer\" ;\n    \n    public static final String SEQUEL = \"sequel\";\n    \n    public static final String XFER =  \"xfer\";\n      \n    public static final String REL = \"rel\";\n    \n    public static final String SERVICE = \"service\";\n    \n    public void setCallId(String callId) throws ParseException;\n       \n    public String getCallId();\n       \n    public void setRel (String rel) throws ParseException;\n    \n    public String getRel();\n        \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/ReferredBy.java",
    "content": "\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header.extensions;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * ReferredBy SIP Header. RFC 3892\n *\n * @version JAIN-SIP-1.2\n *\n * @author Peter Musgrave.\n *\n *\n */\npublic final class ReferredBy\n    extends AddressParametersHeader implements ExtensionHeader, ReferredByHeader {\n\n    // TODO: Need a unique UID\n    private static final long serialVersionUID = 3134344915465784267L;\n\n    // TODO: When the MinSEHeader is added to javax2 - move this there...pmusgrave\n    public static final String NAME = \"Referred-By\";\n\n    /** default Constructor.\n     */\n    public ReferredBy() {\n        super(NAME);\n    }\n\n    public void setValue(String value) throws ParseException {\n        // not implemented.\n        throw new ParseException(value,0);\n\n    }\n\n    /**\n     * Encode the header content into a String.\n     * @return String\n     */\n    protected String encodeBody() {\n        if (address == null)\n            return null;\n        String retval = \"\";\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval += LESS_THAN;\n        }\n        retval += address.encode();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval += GREATER_THAN;\n        }\n\n        if (!parameters.isEmpty()) {\n            retval += SEMICOLON + parameters.encode();\n        }\n        return retval;\n    }\n}\n/*\n * $Log: ReferredBy.java,v $\n * Revision 1.3  2009/07/17 18:57:42  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.2  2006/10/27 20:58:31  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:\n * Reviewed by:   mranga\n * doc fixups\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.1  2006/10/12 11:57:52  pmusgrave\n * Issue number:  79, 80\n * Submitted by:  pmusgrave@newheights.com\n * Reviewed by:   mranga\n *\n * Revision 1.2  2006/03/20 20:52:03  pmusgrave\n * Add RefferedBy to header factory\n * Correct implements statement in ReferredBy\n *\n * Revision 1.1.1.1  2006/03/15 16:00:07  pmusgrave\n * Source with additions\n *\n * Revision 1.3  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/ReferredByHeader.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage gov2.nist.javax2.sip.header.extensions;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\npublic interface ReferredByHeader extends Header, HeaderAddress, Parameters {\n\n    String NAME = \"Referred-By\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/Replaces.java",
    "content": "/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.header.extensions;\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n * Replaces SIPHeader.\n * ToDo: add support for early-only flag.\n *\n * @author P, Musgrave <pmusgrave@mkcnetworks.com>  <br/>\n *\n * @version JAIN-SIP-1.2\n *\n *\n */\n\npublic class Replaces\n    extends ParametersHeader implements ExtensionHeader, ReplacesHeader {\n\n    // TODO: Need a unique UID\n    private static final long serialVersionUID = 8765762413224043300L;\n\n    // TODO: When the MinSEHeader is added to javax2 - move this there...pmusgrave\n    public static final String NAME = \"Replaces\";\n\n    /**\n     * callIdentifier field\n     */\n    public CallIdentifier callIdentifier;\n    public String callId;\n\n    /**\n     * Default constructor\n     */\n    public Replaces() {\n        super(NAME);\n    }\n\n    /** Constructor given the call Identifier.\n     *@param callId string call identifier (should be localid@host)\n     *@throws IllegalArgumentException if call identifier is bad.\n     */\n    public Replaces(String callId) throws IllegalArgumentException {\n        super(NAME);\n        this.callIdentifier = new CallIdentifier(callId);\n    }\n\n    /**\n     * Encode the body part of this header (i.e. leave out the hdrName).\n     * @return String encoded body part of the header.\n     */\n    public String encodeBody() {\n        if (callId == null)\n            return null;\n        else {\n            String retVal = callId;\n            if (!parameters.isEmpty()) {\n                retVal += SEMICOLON + parameters.encode();\n            }\n            return retVal;\n        }\n    }\n\n    /**\n     * get the CallId field. This does the same thing as encodeBody\n     *\n     * @return String the encoded body part of the\n     */\n    public String getCallId() {\n        return callId;\n    }\n\n    /**\n     * get the call Identifer member.\n     * @return CallIdentifier\n     */\n    public CallIdentifier getCallIdentifer() {\n        return callIdentifier;\n    }\n\n    /**\n     * set the CallId field\n     * @param cid String to set. This is the body part of the Call-Id\n     *  header. It must have the form localId@host or localId.\n     * @throws IllegalArgumentException if cid is null, not a token, or is\n     * not a token@token.\n     */\n    public void setCallId(String cid) {\n        callId = cid;\n    }\n\n    /**\n     * Set the callIdentifier member.\n     * @param cid CallIdentifier to set (localId@host).\n     */\n    public void setCallIdentifier(CallIdentifier cid) {\n        callIdentifier = cid;\n    }\n\n    /**\n     * Get the to-tag parameter from the address parm list.\n     * @return tag field\n     */\n    public String getToTag() {\n        if (parameters == null)\n            return null;\n        return getParameter(ParameterNames.TO_TAG);\n    }\n    /**\n     * Set the to-tag member\n     * @param t tag to set. From tags are mandatory.\n     */\n    public void setToTag(String t) throws ParseException {\n        if (t == null)\n            throw new NullPointerException(\"null tag \");\n        else if (t.trim().equals(\"\"))\n            throw new ParseException(\"bad tag\", 0);\n        this.setParameter(ParameterNames.TO_TAG, t);\n    }\n    /** Boolean function\n     * @return true if the Tag exist\n     */\n    public boolean hasToTag() {\n        return hasParameter(ParameterNames.TO_TAG);\n    }\n\n    /** remove Tag member\n     */\n    public void removeToTag() {\n        parameters.delete(ParameterNames.TO_TAG);\n    }\n    /**\n     * Get the from-tag parameter from the address parm list.\n     * @return tag field\n     */\n    public String getFromTag() {\n        if (parameters == null)\n            return null;\n        return getParameter(ParameterNames.FROM_TAG);\n    }\n    /**\n     * Set the to-tag member\n     * @param t tag to set. From tags are mandatory.\n     */\n    public void setFromTag(String t) throws ParseException {\n        if (t == null)\n            throw new NullPointerException(\"null tag \");\n        else if (t.trim().equals(\"\"))\n            throw new ParseException(\"bad tag\", 0);\n        this.setParameter(ParameterNames.FROM_TAG, t);\n    }\n    /** Boolean function\n     * @return true if the Tag exist\n     */\n    public boolean hasFromTag() {\n        return hasParameter(ParameterNames.FROM_TAG);\n    }\n\n    /** remove Tag member\n     */\n    public void removeFromTag() {\n        parameters.delete(ParameterNames.FROM_TAG);\n    }\n\n\n\n    public void setValue(String value) throws ParseException {\n        // not implemented.\n        throw new ParseException(value,0);\n\n    }\n\n//  public Object clone() {\n//      CallID retval = (CallID) super.clone();\n//      if (this.callIdentifier != null)\n//          retval.setCallIdentifier( (CallIdentifier) this.callIdentifier.clone() );\n//      return retval;\n//  }\n}\n/*\n * $Log: Replaces.java,v $\n * Revision 1.3  2009/07/17 18:57:42  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.2  2006/10/27 20:58:31  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:\n * Reviewed by:   mranga\n * doc fixups\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.1  2006/10/12 11:57:51  pmusgrave\n * Issue number:  79, 80\n * Submitted by:  pmusgrave@newheights.com\n * Reviewed by:   mranga\n *\n * Revision 1.3  2006/07/19 15:05:20  pmusgrave\n * Modify encodeBody so it uses callId and not CallIdentifier\n *\n * Revision 1.2  2006/04/17 23:41:31  pmusgrave\n * Add Session Timer and Replaces headers\n *\n * Revision 1.1.1.1  2006/03/15 16:00:07  pmusgrave\n * Source with additions\n *\n * Revision 1.3  2005/04/16 20:38:48  dmuresan\n * Canonical clone() implementations for the GenericObject and GenericObjectList hierarchies\n *\n * Revision 1.2  2004/01/22 13:26:29  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/ReplacesHeader.java",
    "content": "/*\n * Copyright (C) 2010 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage gov2.nist.javax2.sip.header.extensions;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\npublic interface ReplacesHeader extends Header, Parameters {\n\n    String NAME = \"Replaces\";\n    String getToTag();\n    void setToTag(String tag) throws ParseException;\n    String getFromTag();\n    void setFromTag(String tag) throws ParseException;\n    String getCallId();\n    void setCallId(String callId) throws ParseException;\n}"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/SessionExpires.java",
    "content": "\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.header.extensions;\n\nimport gov2.nist.javax2.sip.header.ParametersHeader;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n * ReferredBy SIP Header.\n *\n * @version JAIN-SIP-1.1 $Revision: 1.5 $ $Date: 2009/10/18 13:46:36 $\n *\n * @author Peter Musgrave.\n *\n */\npublic final class SessionExpires\n    extends ParametersHeader implements ExtensionHeader, SessionExpiresHeader {\n\n    // TODO: Need a unique UID\n    private static final long serialVersionUID = 8765762413224043300L;\n\n    // TODO: When the MinSEHeader is added to javax2 - move this there...pmusgrave\n    public static final String NAME = \"Session-Expires\";\n\n    public int expires;\n\n    public static final String REFRESHER = \"refresher\";\n    /** default Constructor.\n     */\n    public SessionExpires() {\n        super(NAME);\n    }\n\n    /**\n     * Gets the expires value of the SessionExpiresHeader. This expires value is\n     * relative time.\n     *\n     *\n     *\n     * @return the expires value of the ExpiresHeader.\n     *\n     * @since JAIN SIP v1.1\n     *\n     */\n    public int getExpires() {\n        return expires;\n    }\n\n    /**\n     * Sets the relative expires value of the SessionExpiresHeader.\n     * The expires value MUST be greater than zero and MUST be\n     * less than 2**31.\n     *\n     * @param expires - the new expires value\n     *\n     * @throws InvalidArgumentException if supplied value is less than zero.\n     *\n     * @since JAIN SIP v1.1\n     *\n     */\n    public void setExpires(int expires) throws InvalidArgumentException {\n        if (expires < 0)\n            throw new InvalidArgumentException(\"bad argument \" + expires);\n        this.expires = expires;\n    }\n\n    public void setValue(String value) throws ParseException {\n        // not implemented.\n        throw new ParseException(value,0);\n\n    }\n\n    /**\n     * Encode the header content into a String.\n     * @return String\n     */\n    protected String encodeBody() {\n\n        String retval = Integer.toString(expires);\n\n        if (!parameters.isEmpty()) {\n            retval += SEMICOLON + parameters.encode();\n        }\n        return retval;\n    }\n\n    public String getRefresher() {\n       return parameters.getParameter(REFRESHER);\n    }\n\n    public void setRefresher(String refresher) {\n        this.parameters.set(REFRESHER,refresher);\n    }\n}\n\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/extensions/SessionExpiresHeader.java",
    "content": "package gov2.nist.javax2.sip.header.extensions;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.*;\n\n/*\n * Extension for SessionTimer RFC 4028\n *\n *\n */\n\n\npublic interface SessionExpiresHeader extends Parameters, Header, ExtensionHeader{\n\n    public final static String NAME = \"Session-Expires\";\n\n    public int getExpires();\n\n    public void setExpires(int expires) throws InvalidArgumentException;\n\n    public String getRefresher() ;\n\n    public void setRefresher(String refresher);\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/AddressHeaderIms.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVAO - EST DEPARTMENT   *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.address.Address;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\n/**\n * AddressHeader base class.\n * @author ALEXANDRE MIGUEL SILVA SANTOS (PT Innovacau)\n */\n\npublic abstract class AddressHeaderIms extends SIPHeader {\n\n    protected AddressImpl address;\n\n    /**\n     * get the Address field\n     * @return the imbedded  Address\n     */\n    public Address getAddress() {\n        return address;\n    }\n\n    /**\n     * set the Address field\n     * @param address Address to set\n     */\n    public void setAddress(Address address) {\n        this.address = (AddressImpl) address;\n    }\n\n    public abstract String encodeBody();\n    //protected abstract String encodeBody();\n\n\n    /**\n     * Constructor given the name of the header.\n     */\n    public AddressHeaderIms(String name) {\n    //protected AddressHeader(String name) {\n        super(name);\n    }\n\n    public Object clone() {\n        AddressHeaderIms retval = (AddressHeaderIms) super.clone();\n        if (this.address != null)\n            retval.address = (AddressImpl) this.address.clone();\n        return retval;\n    }\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/AuthorizationHeaderIms.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.AuthorizationHeader;\n\n\n/**\n *\n * Extension to Authorization header (3GPP TS 24299-5d0)\n *\n * This extension defines a new auth-param for the Authorization header used\n * in REGISTER requests.\n * For more information, see RFC 2617 [21] subclause 3.2.2.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\npublic interface AuthorizationHeaderIms extends AuthorizationHeader\n{\n\n    // issued by Miguel Freitas (IT) PT-Inovacao\n    public static final String YES  = \"yes\";\n    public static final String NO   = \"no\";\n\n\n\n    /**\n     * @param integrityProtected\n     * @throws ParseException\n     */\n    public void setIntegrityProtected(String integrityProtected) throws InvalidArgumentException, ParseException;\n\n\n    public String getIntegrityProtected();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAccessNetworkInfo.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government,\n * and others.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.header.ParametersHeader;\n\n/**\n * <p>P-Access-Network-Info SIP Private Header</p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n *\n * @since 1.2\n */\n\npublic class PAccessNetworkInfo\n    extends ParametersHeader\n    implements PAccessNetworkInfoHeader, ExtensionHeader {\n\n    // TODO: serialVersionUID\n\n    private String accessType;\n\n    private Object extendAccessInfo;\n\n    /**\n     * Public constructor.\n     */\n    public PAccessNetworkInfo() {\n        super(PAccessNetworkInfoHeader.NAME);\n        parameters.setSeparator(SEMICOLON);\n    }\n\n    /**\n     * Constructor.\n     */\n    public PAccessNetworkInfo(String accessTypeVal) {\n        this();\n        setAccessType(accessTypeVal);\n    }\n\n    /**\n     * Set the accessTpe\n     *\n     * @param accessTypeVal - access type\n     * @throws NullPointerException\n     */\n    public void setAccessType(String accessTypeVal) {\n        if (accessTypeVal == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Access-Network-Info, setAccessType(), the accessType parameter is null.\");\n\n        this.accessType = accessTypeVal;\n    }\n\n    /**\n     * @return String access type\n     */\n    public String getAccessType() {\n        return accessType;\n    }\n\n    /**\n     *\n     * @param cgi -- String CGI value\n     * @throws NullPointerException -- if null argument passed in\n     * @throws ParseException -- if bad argument passed in.\n     */\n    public void setCGI3GPP(String cgi) throws ParseException {\n\n        if (cgi == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Access-Network-Info, setCGI3GPP(), the cgi parameter is null.\");\n\n        setParameter(ParameterNamesIms.CGI_3GPP, cgi);\n\n    }\n\n    /**\n     *\n     * @return String CGI value\n     */\n    public String getCGI3GPP() {\n        return getParameter(ParameterNamesIms.CGI_3GPP);\n    }\n\n    /**\n     * Set the UtranCellID field.\n     *\n     * @param  utranCellID -- String UTRAN Cell ID value\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public void setUtranCellID3GPP(String utranCellID) throws ParseException {\n\n        if (utranCellID == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Access-Network-Info, setUtranCellID3GPP(), the utranCellID parameter is null.\");\n\n        setParameter(ParameterNamesIms.UTRAN_CELL_ID_3GPP, utranCellID);\n\n    }\n\n    /**\n     *\n     * @return String UTRAN Cell ID value\n     */\n    public String getUtranCellID3GPP() {\n        return getParameter(ParameterNamesIms.UTRAN_CELL_ID_3GPP);\n    }\n\n    /**\n     *\n     * @param dslLocation - String with the DSL location value\n     * @throws NullPointerException\n     * @throws ParseException\n     */\n    public void setDSLLocation(String dslLocation) throws ParseException {\n\n        if (dslLocation == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Access-Network-Info, setDSLLocation(), the dslLocation parameter is null.\");\n\n        setParameter(ParameterNamesIms.DSL_LOCATION, dslLocation);\n\n    }\n\n    /**\n     *\n     * @return String DSL location value\n     */\n    public String getDSLLocation() {\n        return getParameter(ParameterNamesIms.DSL_LOCATION);\n    }\n\n    /**\n     *\n     * @param ci3Gpp2 -- String CI 3GPP2 value\n     * @throws NullPointerException -- if arg is null\n     * @throws ParseException -- if arg is bad.\n     */\n    public void setCI3GPP2(String ci3Gpp2) throws ParseException {\n        if (ci3Gpp2 == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Access-Network-Info, setCI3GPP2(), the ci3Gpp2 parameter is null.\");\n\n        setParameter(ParameterNamesIms.CI_3GPP2, ci3Gpp2);\n    }\n\n    /**\n     *\n     * @return String CI 3GPP2 value\n     */\n    public String getCI3GPP2() {\n        return getParameter(ParameterNamesIms.CI_3GPP2);\n    }\n\n    /**\n     *\n     * @param name --\n     *            parameter name\n     * @param value --\n     *            value of parameter\n     */\n    public void setParameter(String name, Object value) {\n        /**\n         * @todo ParametersHeader needs to be fix!? missing \"throws\n         *       ParseException\" in setParameter(String, Object)\n         */\n\n        if (name.equalsIgnoreCase(ParameterNamesIms.CGI_3GPP)\n                || name.equalsIgnoreCase(ParameterNamesIms.UTRAN_CELL_ID_3GPP)\n                || name.equalsIgnoreCase(ParameterNamesIms.DSL_LOCATION)\n                || name.equalsIgnoreCase(ParameterNamesIms.CI_3GPP2)) {\n            try {\n                super.setQuotedParameter(name, value.toString());\n            } catch (ParseException e) {\n\n            }\n\n        } else {\n            // value can be token either than a quoted-string\n            super.setParameter(name, value);\n\n        }\n\n    }\n\n    /**\n     * extension-access-info = gen-value gen-value = token / host /\n     * quoted-string\n     *\n     * @param extendAccessInfo - extended Access Information\n     */\n    public void setExtensionAccessInfo(Object extendAccessInfo)\n            throws ParseException {\n\n        if (extendAccessInfo == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Access-Network-Info, setExtendAccessInfo(), the extendAccessInfo parameter is null.\");\n\n        // or -> setParameter(\"\", extendAccessInfo);\n\n        this.extendAccessInfo = extendAccessInfo;\n\n    }\n\n    public Object getExtensionAccessInfo() {\n        return this.extendAccessInfo;\n    }\n\n    protected String encodeBody() {\n\n        StringBuffer encoding = new StringBuffer();\n\n        if (getAccessType() != null)\n            encoding.append(getAccessType());\n\n        if (!parameters.isEmpty()) {\n            encoding.append(SEMICOLON + SP + this.parameters.encode());\n        }\n        // else if (getExtendAccessInfo() != null) // stack deve limitar, de\n        // acordo com a especificação ?\n        if (getExtensionAccessInfo() != null) {\n            encoding.append(SEMICOLON + SP\n                    + getExtensionAccessInfo().toString());\n        }\n\n        return encoding.toString();\n\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value, 0);\n\n    }\n\n\n    public boolean equals(Object other) {\n        return (other instanceof PAccessNetworkInfoHeader) && super.equals(other);\n    }\n\n    /*\n     * Makes a deep clone. (ParametersHeader)\n     */\n    public Object clone() {\n        PAccessNetworkInfo retval = (PAccessNetworkInfo) super.clone();\n        return retval;\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAccessNetworkInfoHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n\n/**\n * <p>P-Access-Network-Info SIP P-Header </p>\n * <p>This header carries information relating to the access network between\n * the UAC and its serving proxy in the home network.</p>\n *\n * <p>IETF RFC3455 + 3GPP TS 24.229-720 (2005-12)</p>\n * <p>Sintax: </p>\n * <pre>\n * P-Access-Network-Info  = \"P-Access-Network-Info\": access-type *(; access-info)\n *\n * access-type    = \"IEEE-802.11a\" / \"IEEE-802.11b\" / \"3GPP-GERAN\" / \"3GPP-UTRAN-FDD\" /\n *                   \"3GPP-UTRAN-TDD\" / \"ADSL\" / \"ADSL2\" / \"ADSL2+\" / \"RADSL\" / \"SDSL\" /\n *                   \"HDSL\" / \"HDSL2\" / \"G.SHDSL\" / \"VDSL\" / \"IDSL\" / \"3GPP2-1X\" /\n *                   \"3GPP2-1XHRPD\" /token\n *\n * access-info            = cgi-3gpp / utran-cell-id-3gpp / dsl-location /\n *                          ci-3gpp2 / extension-access-info\n * cgi-3gpp               = \"cgi-3gpp\" EQUAL (token / quoted-string)\n * utran-cell-id-3gpp     = \"utran-cell-id-3gpp\" EQUAL (token / quoted-string)\n * dsl-location           = \"dsl-location\" EQUAL (token / quoted-string)\n * ci-3gpp2               = \"ci-3gpp2\" EQUAL (token / quoted-string)\n * extension-access-info  = gen-value\n * gen-value              = token / host / quoted-string\n * </pre>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic interface PAccessNetworkInfoHeader extends Parameters, Header\n{\n\n    public final static String NAME = \"P-Access-Network-Info\";\n\n    // access type\n    public static final String IEEE_802_11 = \"IEEE-802.11\";\n    public static final String IEEE_802_11A = \"IEEE-802.11a\";\n    public static final String IEEE_802_11B = \"IEEE-802.11b\";\n    public static final String IEEE_802_11G = \"IEEE-802.11g\";\n    public static final String GGGPP_GERAN = \"3GPP-GERAN\";\n    public static final String GGGPP_UTRAN_FDD = \"3GPP-UTRAN-FDD\";\n    public static final String GGGPP_UTRAN_TDD = \"3GPP-UTRAN-TDD\";\n    public static final String GGGPP_CDMA2000 = \"3GPP-CDMA2000\";\n    public static final String ADSL = \"ADSL\";\n    public static final String ADSL2 = \"ADSL2\";\n    public static final String ADSL2p = \"ADSL2+\";\n    public static final String RADSL = \"RADSL\";\n    public static final String SDSL = \"SDSL\";\n    public static final String HDSL = \"HDSL\";\n    public static final String HDSL2 = \"HDSL2\";\n    public static final String GSHDSL = \"G.SHDSL\";\n    public static final String VDSL = \"VDSL\";\n    public static final String IDSL = \"IDSL\";\n    public static final String GGGPP2_1X = \"3GPP2-1X\";\n    public static final String GGGPP2_1XHRPD = \"3GPP2-1XHRPD\";\n\n\n\n    public void setAccessType(String accessTypeVal) throws ParseException;\n    public String getAccessType();\n\n\n    public void setCGI3GPP(String cgi) throws ParseException;\n    public String getCGI3GPP();\n\n\n    public void setUtranCellID3GPP(String utranCellID) throws ParseException;\n    public String getUtranCellID3GPP();\n\n\n    public void setDSLLocation(String dslLocation) throws ParseException;\n    public String getDSLLocation();\n\n\n    public void setCI3GPP2(String ci2Gpp2) throws ParseException;\n    public String getCI3GPP2();\n\n\n    public void setExtensionAccessInfo(Object extendAccessInfo) throws ParseException;\n    public Object getExtensionAccessInfo();\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssertedIdentity.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.AddressParametersHeader;\nimport gov2.nist.javax2.sip.header.ims.PAssertedIdentityHeader;\n\n\n/**\n * P-Asserted-Identity SIP Private Header.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic class PAssertedIdentity\n    extends AddressParametersHeader\n    implements PAssertedIdentityHeader, SIPHeaderNamesIms, ExtensionHeader {\n\n\n\n    /**\n     * constructor\n     * @param address address to set\n     */\n    public PAssertedIdentity(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * default constructor\n     */\n    public PAssertedIdentity()\n    {\n        super(NAME);\n    }\n\n    /** Encode into canonical form.\n     *@return String containing the canonicaly encoded header.\n     */\n    public String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n\n\n        if (!parameters.isEmpty())\n            retval.append(COMMA + this.parameters.encode());\n        return retval.toString();\n    }\n\n\n    public Object clone() {\n        PAssertedIdentity retval = (PAssertedIdentity) super.clone();\n        return retval;\n    }\n\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssertedIdentityHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO- EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\n\n/*\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n/**\n * P-Asserted-Identity header\n * Private Header: RFC 3455.\n * Contains a URI (commonly a SIP URI) and an optional display-name\n * enable a network of trusted SIP servers to assert\n * the identity of authenticated users, and the application of existing\n * privacy mechanisms to the identity problem.\n * The use of this extension is only applicable inside an administrative\n * domain with previously agreed-upon policies for generation,\n * transport and usage of such information.\n *\n *\n */\n\n\n\npublic interface PAssertedIdentityHeader extends HeaderAddress, Header {\n\n    /**\n     * Name of AssertIdentityHeader\n     */\n    public final static String NAME = \"P-Asserted-Identity\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssertedIdentityList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT   *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\n\n\n/**\n * List of P-Asserted-Identity headers\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n/*\n * PAssertedID = \"P-Asserted-Identity\" HCOLON PAssertedID-value\n *               *(COMMA PAssertedID-value)\n * PAssertedID-value = name-addr / addr-spec\n */\n\n\npublic class PAssertedIdentityList extends SIPHeaderList<PAssertedIdentity> {\n\n    private static final long serialVersionUID = -6465152445570308974L;\n\n\n    /**\n     * constructor.\n     */\n    public PAssertedIdentityList()\n    {\n        super(PAssertedIdentity.class, PAssertedIdentityHeader.NAME);\n    }\n\n\n    public Object clone() {\n        PAssertedIdentityList retval = new PAssertedIdentityList();\n        return retval.clonehlist(this.hlist);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssertedService.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\nimport javax2.sip.header.ExtensionHeader;\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n */\npublic class PAssertedService extends SIPHeader implements PAssertedServiceHeader, SIPHeaderNamesIms, ExtensionHeader{\n\n    private String subServiceIds;\n    private String subAppIds;\n\n    protected PAssertedService(String name) {\n        super(NAME);\n    }\n\n    public PAssertedService()\n    {\n        super(P_ASSERTED_SERVICE);\n    }\n\n    @Override\n    protected String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n\n         retval.append(ParameterNamesIms.SERVICE_ID);\n\n            if(this.subServiceIds!=null)\n            {\n                retval.append(ParameterNamesIms.SERVICE_ID_LABEL).append(\".\");\n\n            retval.append(this.getSubserviceIdentifiers());\n            }\n\n            else if(this.subAppIds!=null)\n            {\n                retval.append(ParameterNamesIms.APPLICATION_ID_LABEL).append(\".\");\n                retval.append(this.getApplicationIdentifiers());\n            }\n\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n    public String getApplicationIdentifiers() {\n        if(this.subAppIds.charAt(0)=='.')\n        {\n            return this.subAppIds.substring(1);\n        }\n        return this.subAppIds;\n    }\n\n    public String getSubserviceIdentifiers() {\n        if(this.subServiceIds.charAt(0)=='.')\n        {\n            return this.subServiceIds.substring(1);\n        }\n        return this.subServiceIds;\n    }\n    public void setApplicationIdentifiers(String appids) {\n        this.subAppIds = appids;\n\n    }\n\n    public void setSubserviceIdentifiers(String subservices) {\n        this.subServiceIds = subservices;\n\n    }\n\n    public boolean equals(Object other)\n    {\n        return (other instanceof PAssertedServiceHeader) && super.equals(other);\n\n    }\n\n\n    public Object clone() {\n        PAssertedService retval = (PAssertedService) super.clone();\n        return retval;\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssertedServiceHeader.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport javax2.sip.header.Header;\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * The ABNF for this header is all follows:\n *\n *  PAssertedService = \"P-Asserted-Service\"\n *                       HCOLON PAssertedService-value\n *\n *  PAssertedService-value = Service-ID *(COMMA Service-ID)\n *\n *  where,\n *\n *     Service-ID      = \"urn:urn-7:\" urn-service-id\n *     urn-service-id  = top-level *(\".\" sub-service-id)\n *     top-level       = let-dig [ *26let-dig ]\n *     sub-service-id  = let-dig [ *let-dig ]\n *     let-dig         = ALPHA / DIGIT / \"-\"\n *\n * Egs: P-Asserted-Service: urn:urn-7:3gpp-service.exampletelephony.version1\n *      P-Asserted-Service: urn:urn-7:3gpp-application.exampletelephony.version1\n *\n */\npublic interface PAssertedServiceHeader extends Header{\n\n    public static final String NAME = \"P-Asserted-Service\";\n\n    public void setSubserviceIdentifiers(String subservices);\n\n    public String getSubserviceIdentifiers();\n\n    public void setApplicationIdentifiers(String appids);\n\n    public String getApplicationIdentifiers();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssociatedURI.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) *\n ****************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.address.URI;\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.address.GenericURI;\nimport gov2.nist.javax2.sip.header.ims.PAssociatedURIHeader;\n\n\n/**\n * <p>P-Associated-URI SIP Private Header. </p>\n * <p>An associated URI is a URI that the service provider\n * has allocated to a user for his own usage (address-of-record). </p>\n *\n * <p>sintax (RFC 3455): </p>\n * <pre>\n * P-Associated-URI  = \"P-Associated-URI\" HCOLON\n *                    (p-aso-uri-spec) *(COMMA p-aso-uri-spec)\n * p-aso-uri-spec    = name-addr *(SEMI ai-param)\n * ai-param          = generic-param\n * name-addr         =   [display-name] angle-addr\n * angle-addr        =   [CFWS] \"<\" addr-spec \">\" [CFWS] / obs-angle-addr\n * </pre>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class PAssociatedURI\n    extends gov2.nist.javax2.sip.header.AddressParametersHeader\n    implements PAssociatedURIHeader, SIPHeaderNamesIms, ExtensionHeader\n{\n    // TODO: Need a unique UID\n\n\n    /**\n     * Default Constructor\n     */\n    public PAssociatedURI()\n    {\n        super(PAssociatedURIHeader.NAME);\n    }\n\n    /**\n     * Constructor\n     * @param address to be set in the header\n     */\n    public PAssociatedURI(AddressImpl address)\n    {\n        super(PAssociatedURIHeader.NAME);\n        this.address = address;\n    }\n\n    /**\n     * Constructor\n     * @param associatedURI - GenericURI to be set in the address of this header\n     */\n    public PAssociatedURI(GenericURI associatedURI)\n    {\n        super(PAssociatedURIHeader.NAME);\n        this.address = new AddressImpl();\n        this.address.setURI(associatedURI);\n    }\n\n\n\n\n    /**\n     * Encode into canonical form.\n     * @return String containing the canonicaly encoded header.\n     */\n    public String encodeBody()\n    {\n        StringBuffer retval = new StringBuffer();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n\n\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n        return retval.toString();\n    }\n\n\n    /**\n     * <p>Set the URI on this address</p>\n     * @param associatedURI - GenericURI to be set in the address of this header\n     * @throws NullPointerException when supplied URI is null\n     */\n    public void setAssociatedURI(URI associatedURI) throws NullPointerException\n    {\n        if (associatedURI == null)\n            throw new NullPointerException(\"null URI\");\n\n        this.address.setURI(associatedURI);\n    }\n\n    /**\n     * <p>Get the address's URI</p>\n     * @return URI set in the address of this header\n     */\n    public URI getAssociatedURI() {\n        return this.address.getURI();\n    }\n\n\n    public Object clone() {\n        PAssociatedURI retval = (PAssociatedURI) super.clone();\n        if (this.address != null)\n            retval.address = (AddressImpl) this.address.clone();\n        return retval;\n    }\n\n\n    public void setValue(String value) throws ParseException{\n        // not implemented\n        throw new ParseException(value,0);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssociatedURIHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) *\n ****************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.address.URI;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\n\n\n/**\n * <p>P-Associated-URI SIP Private Header. </p>\n * <p>An associated URI is a URI that the service provider\n * has allocated to a user for his own usage (address-of-record). </p>\n *\n * <p>sintax (RFC 3455): </p>\n * <pre>\n * P-Associated-URI  = \"P-Associated-URI\" HCOLON\n *                    (p-aso-uri-spec) *(COMMA p-aso-uri-spec)\n * p-aso-uri-spec    = name-addr *(SEMI ai-param)\n * ai-param          = generic-param\n * name-addr         =   [display-name] angle-addr\n * angle-addr        =   [CFWS] \"<\" addr-spec \">\" [CFWS] / obs-angle-addr\n * </pre>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n/*\n\n */\n\n\npublic interface PAssociatedURIHeader\n    extends HeaderAddress, Parameters, Header\n{\n\n    /**\n     * Name of PAssociatedURIHeader\n     */\n    public final static String NAME = \"P-Associated-URI\";\n\n\n    /**\n     * <p>Set the URI on this address</p>\n     * @param associatedURI - GenericURI to be set in the address of this header\n     * @throws NullPointerException when supplied URI is null\n     */\n    public void setAssociatedURI(URI associatedURI) throws NullPointerException;\n\n    /**\n     * <p>Get the address's URI</p>\n     * @return URI set in the address of this header\n     */\n    public URI getAssociatedURI();\n\n    //public void setAssociatedURI(AddressImpl associatedURI);\n    //public AddressImpl getAssociatedURI();\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PAssociatedURIList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT   *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\n\n\n/**\n * List of P-Associated-URI headers\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n/*\n * P-Associated-URI  =  \"P-Associated-URI\" \":\" # ( \"<\" URI \">\" *( \";\" generic-param ))\n */\n\n\npublic class PAssociatedURIList extends SIPHeaderList<PAssociatedURI> {\n\n\n    private static final long serialVersionUID = 4454306052557362851L;\n\n\n    /**\n     * constructor.\n     */\n    public PAssociatedURIList()\n    {\n        super(PAssociatedURI.class, PAssociatedURI.NAME);\n    }\n\n\n    public Object clone() {\n        PAssociatedURIList retval = new PAssociatedURIList();\n        return retval.clonehlist(this.hlist);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PCalledPartyID.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.ims.PCalledPartyIDHeader;\n\n/**\n * P-Called-Party-ID SIP Private Header.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic class PCalledPartyID\n    extends gov2.nist.javax2.sip.header.AddressParametersHeader\n    implements PCalledPartyIDHeader, SIPHeaderNamesIms , ExtensionHeader{\n\n    /**\n     * constructor\n     * @param address address to set\n     */\n    public PCalledPartyID(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * default constructor\n     */\n    public PCalledPartyID() {\n        super(CALLED_PARTY_ID);\n\n    }\n\n    /** Encode into canonical form.\n     *@return String containing the canonicaly encoded header.\n     */\n    public String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        // not implemented.\n        throw new ParseException(value,0);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PCalledPartyIDHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\n\n/**\n * P-Called-Party-ID header - Private Header: RFC 3455.\n * <p>A proxy server inserts a P-Called-Party-ID header, typically in an INVITE request,\n * en-route to its destination. The header is populated with the Request-URI received\n * by the proxy in the request. </p>\n * <p>Both the business SIP URI and the personal SIP URI are registered in the SIP registrar,\n * so both URIs can receive invitations to new sessions. When the user receives an invitation\n * to join a session, he/she should be aware of which of the several registered SIP URIs this\n * session was sent to. </p>\n *\n * <pre>\n * P-Called-Party-ID    = \"P-Called-Party-ID\" HCOLON\n *                        called-pty-id-spec\n * called-pty-id-spec   = name-addr *(SEMI cpid-param)\n * cpid-param           = generic-param\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n *\n */\n\n\npublic interface PCalledPartyIDHeader extends HeaderAddress, Parameters, Header {\n\n    /**\n     * Name of CalledPartyIDHeader\n     */\n    public final static String NAME = \"P-Called-Party-ID\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PChargingFunctionAddresses.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.ListIterator;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.javax2.sip.header.ims.PChargingFunctionAddressesHeader;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\n\n\n/**\n * <p>P-Charging-Function-Addresses SIP Private Header. </p>\n *\n * <p>Sintax (RFC 3455):</p>\n * <pre>\n * P-Charging-Addr        = \"P-Charging-Function-Addresses\" HCOLON\n *                           charge-addr-params\n *                           *(SEMI charge-addr-params)\n * charge-addr-params     = ccf / ecf / generic-param\n * ccf                    = \"ccf\" EQUAL gen-value\n * ecf                    = \"ecf\" EQUAL gen-value\n * gen-value              = token / host / quoted-string\n * </pre>\n *\n * <p>example:</p>\n *  <p>P-Charging-Function-Addresses: ccf=192.1.1.1; ccf=192.1.1.2;\n *  ecf=192.1.1.3; ecf=192.1.1.4</p>\n *\n * <p>TODO: add PARSER support for IPv6 address.\n * eg: P-Charging-Function-Addresses: ccf=[5555.b99.c88.d77.e66]; ecf=[5555.6aa.7bb.8cc.9dd] </p>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\npublic class PChargingFunctionAddresses\n    extends gov2.nist.javax2.sip.header.ParametersHeader\n    implements PChargingFunctionAddressesHeader, SIPHeaderNamesIms , ExtensionHeader{\n\n\n    // TODO: serialVersionUID\n\n    /**\n     * Defaul Constructor\n     */\n    public PChargingFunctionAddresses() {\n\n        super(P_CHARGING_FUNCTION_ADDRESSES);\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.header.ParametersHeader#encodeBody()\n     */\n    protected String encodeBody() {\n\n        StringBuffer encoding = new StringBuffer();\n\n        // issued by Miguel Freitas\n        if (!duplicates.isEmpty())\n        {\n            encoding.append(duplicates.encode());\n        }\n\n        return encoding.toString();\n\n    }\n\n    /**\n     * <p>Set the Charging Collection Function (CCF) Address</p>\n     *\n     * @param ccfAddress - the address to set in the CCF parameter\n     * @throws ParseException\n     */\n    public void setChargingCollectionFunctionAddress(String ccfAddress) throws ParseException {\n\n        if (ccfAddress == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"P-Charging-Function-Addresses, setChargingCollectionFunctionAddress(), the ccfAddress parameter is null.\");\n\n       // setParameter(ParameterNamesIms.CCF, ccfAddress);\n        setMultiParameter(ParameterNamesIms.CCF, ccfAddress);\n\n    }\n\n    /**\n     * <p>Add another Charging Collection Function (CCF) Address to this header</p>\n     *\n     * @param ccfAddress - the address to set in the CCF parameter\n     * @throws ParseException\n     */\n    public void addChargingCollectionFunctionAddress(String ccfAddress) throws ParseException {\n\n        if (ccfAddress == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"P-Charging-Function-Addresses, setChargingCollectionFunctionAddress(), the ccfAddress parameter is null.\");\n\n        this.parameters.set(ParameterNamesIms.CCF, ccfAddress);\n\n    }\n\n    /**\n     * <p>Remove a Charging Collection Function (CCF) Address set in this header</p>\n     *\n     * @param ccfAddress - the address in the CCF parameter to remove\n     * @throws ParseException if the address was not removed\n     */\n    public void removeChargingCollectionFunctionAddress(String ccfAddress) throws ParseException {\n\n        if (ccfAddress == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"P-Charging-Function-Addresses, setChargingCollectionFunctionAddress(), the ccfAddress parameter is null.\");\n\n        if(!this.delete(ccfAddress, ParameterNamesIms.CCF)) {\n\n            throw new ParseException(\"CCF Address Not Removed\",0);\n\n        }\n\n    }\n\n    /**\n     * <p>Get all the Charging Collection Function (CCF) Addresses set in this header</p>\n     *\n     * @return ListIterator that constains all CCF addresses of this header\n     */\n    public ListIterator getChargingCollectionFunctionAddresses() {\n\n        Iterator li = this.parameters.iterator();\n        LinkedList ccfLIST = new LinkedList();\n        NameValue nv;\n        while (li.hasNext()) {\n            nv = (NameValue) li.next();\n            if (nv.getName().equalsIgnoreCase(ParameterNamesIms.CCF)) {\n\n                NameValue ccfNV = new NameValue();\n\n                ccfNV.setName(nv.getName());\n                ccfNV.setValueAsObject(nv.getValueAsObject());\n\n                ccfLIST.add(ccfNV);\n\n            }\n        }\n\n        return ccfLIST.listIterator();\n    }\n\n    /**\n     * <p>Set the Event Charging Function (ECF) Address</p>\n     *\n     * @param ecfAddress - the address to set in the ECF parameter\n     * @throws ParseException\n     */\n    public void setEventChargingFunctionAddress(String ecfAddress) throws ParseException {\n\n        if (ecfAddress == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"P-Charging-Function-Addresses, setEventChargingFunctionAddress(), the ecfAddress parameter is null.\");\n\n        setMultiParameter(ParameterNamesIms.ECF, ecfAddress);\n       // setParameter(ParameterNamesIms.ECF, ecfAddress);\n\n    }\n\n    /**\n     * <p>Add another Event Charging Function (ECF) Address to this header</p>\n     *\n     * @param ecfAddress - the address to set in the ECF parameter\n     * @throws ParseException\n     */\n    public void addEventChargingFunctionAddress(String ecfAddress) throws ParseException {\n\n        if (ecfAddress == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"P-Charging-Function-Addresses, setEventChargingFunctionAddress(), the ecfAddress parameter is null.\");\n\n        this.parameters.set(ParameterNamesIms.ECF, ecfAddress);\n\n    }\n\n    /**\n     * <p>Remove a Event Charging Function (ECF) Address set in this header</p>\n     *\n     * @param ecfAddress - the address in the ECF parameter to remove\n     * @throws ParseException if the address was not removed\n     */\n    public void removeEventChargingFunctionAddress(String ecfAddress) throws ParseException {\n\n        if (ecfAddress == null)\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \"P-Charging-Function-Addresses, setEventChargingFunctionAddress(), the ecfAddress parameter is null.\");\n\n        if(!this.delete(ecfAddress, ParameterNamesIms.ECF)) {\n\n            throw new java.text.ParseException(\"ECF Address Not Removed\",0);\n\n        }\n\n    }\n\n    /**\n     * <p>Get all the Event Charging Function (ECF) Addresses set in this header</p>\n     *\n     * @return ListIterator that constains all CCF addresses of this header\n     */\n    public ListIterator<NameValue> getEventChargingFunctionAddresses() {\n\n    \tLinkedList<NameValue> listw = new LinkedList<NameValue>();\n   \n        Iterator li = this.parameters.iterator();\n        ListIterator<NameValue> ecfLIST = listw.listIterator();\n        NameValue nv;\n        boolean removed = false;\n        while (li.hasNext()) {\n            nv = (NameValue) li.next();\n            if (nv.getName().equalsIgnoreCase(ParameterNamesIms.ECF)) {\n\n                NameValue ecfNV = new NameValue();\n\n                ecfNV.setName(nv.getName());\n                ecfNV.setValueAsObject(nv.getValueAsObject());\n\n                ecfLIST.add(ecfNV);\n\n            }\n        }\n\n        return ecfLIST;\n    }\n\n    /**\n     * <p>Remove parameter </p>\n     *\n     * @param value - of the parameter\n     * @param name - of the parameter\n     * @return true if parameter was removed, and false if not\n     */\n    public boolean delete(String value, String name) {\n        Iterator li = this.parameters.iterator();\n        NameValue nv;\n        boolean removed = false;\n        while (li.hasNext()) {\n            nv = (NameValue) li.next();\n            if (((String) nv.getValueAsObject()).equalsIgnoreCase(value) && nv.getName().equalsIgnoreCase(name)) {\n                li.remove();\n                removed = true;\n            }\n        }\n\n        return removed;\n\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException ( value,0);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PChargingFunctionAddressesHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.core.NameValue;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.ListIterator;\n\n\n/**\n * P-Charging-Function-Addresses header -\n * Private Header: RFC 3455.\n *\n * There is a need to inform each SIP proxy involved in a transaction about the common\n * charging functional entities to receive the generated charging records or charging events.\n * <ul>\n * <li>\n *   - CCF is used for off-line charging (e.g., for postpaid account charging).\n * <li>\n *   - ECF is used for on-line charging (e.g., for pre-paid account charging).\n * </ul>\n * Only one instance of the header MUST be present in a particular request or response.\n *\n * <pre>\n * P-Charging-Addr = \"P-Charging-Function-Addresses\" HCOLON\n *          charge-addr-params\n *          *(SEMI charge-addr-params)\n * charge-addr-params   = ccf / ecf / generic-param\n * ccf              = \"ccf\" EQUAL gen-value\n * ecf              = \"ecf\" EQUAL gen-value\n *\n * gen-value    = token / host / quoted-string\n *\n * host             =  hostname / IPv4address / IPv6reference\n * hostname         =  *( domainlabel \".\" ) toplabel [ \".\" ]\n * domainlabel      =  alphanum / alphanum *( alphanum / \"-\" ) alphanum\n * toplabel         =  ALPHA / ALPHA *( alphanum / \"-\" ) alphanum\n *\n *\n * example:\n *  P-Charging-Function-Addresses: ccf=192.1.1.1; ccf=192.1.1.2;\n *  ecf=192.1.1.3; ecf=192.1.1.4\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n\npublic interface PChargingFunctionAddressesHeader extends Parameters, Header {\n\n    /**\n     * Name of PChargingFunctionAddressesHeader\n     */\n    public final static String NAME = \"P-Charging-Function-Addresses\";\n\n\n    /**\n     * <p>Set the Charging Collection Function (CCF) Address</p>\n     * @param ccfAddress - the address to set in the CCF parameter\n     * @throws ParseException\n     */\n    public void setChargingCollectionFunctionAddress(String ccfAddress) throws ParseException;\n\n    /**\n     * <p>Add another Charging Collection Function (CCF) Address to this header</p>\n     * @param ccfAddress - the address to set in the CCF parameter\n     * @throws ParseException\n     */\n    public void addChargingCollectionFunctionAddress(String ccfAddress) throws ParseException;\n\n    /**\n     * <p>Remove a Charging Collection Function (CCF) Address set in this header</p>\n     * @param ccfAddress - the address in the CCF parameter to remove\n     * @throws ParseException if the address was not removed\n     */\n    public void removeChargingCollectionFunctionAddress(String ccfAddress) throws ParseException;\n\n    /**\n     * <p>Get all the Charging Collection Function (CCF) Addresses set in this header</p>\n     * @return ListIterator that constains all CCF addresses of this header\n     */\n    public ListIterator getChargingCollectionFunctionAddresses();\n\n    /**\n     * <p>Set the Event Charging Function (ECF) Address</p>\n     * @param ecfAddress - the address to set in the ECF parameter\n     * @throws ParseException\n     */\n    public void setEventChargingFunctionAddress(String ecfAddress)throws ParseException;\n\n    /**\n     * <p>Add another Event Charging Function (ECF) Address to this header</p>\n     * @param ecfAddress - the address to set in the ECF parameter\n     * @throws ParseException\n     */\n    public void addEventChargingFunctionAddress(String ecfAddress) throws ParseException;\n\n    /**\n     * <p>Remove a Event Charging Function (ECF) Address set in this header</p>\n     * @param ecfAddress - the address in the ECF parameter to remove\n     * @throws ParseException if the address was not removed\n     */\n    public void removeEventChargingFunctionAddress(String ecfAddress) throws ParseException;\n\n    /**\n     * <p>Get all the Event Charging Function (ECF) Addresses set in this header</p>\n     * @return ListIterator that constains all CCF addresses of this header\n     */\n    public ListIterator getEventChargingFunctionAddresses();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PChargingVector.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.header.ims.PChargingVectorHeader;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\n\n/**\n * P-Charging-Vector header SIP Private Header: RFC 3455.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\npublic class PChargingVector extends gov2.nist.javax2.sip.header.ParametersHeader\n        implements PChargingVectorHeader, SIPHeaderNamesIms, ExtensionHeader {\n\n    /**\n     * Default Constructor\n     */\n    public PChargingVector() {\n\n        super(P_CHARGING_VECTOR);\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see gov2.nist.javax2.sip.header.ParametersHeader#encodeBody()\n     */\n    protected String encodeBody() {\n\n        StringBuffer encoding = new StringBuffer();\n        /*\n         * no need to check for the presence of icid-value. According to the\n         * spec above this is a mandatory field. if it does not exist, then we\n         * should throw an exception\n         *\n         * JvB 26/5: fix for issue #159, check for quotes around icid value\n         */\n        gov2.nist.core.NameValue nv = getNameValue( ParameterNamesIms.ICID_VALUE );\n        nv.encode( encoding );\n\n        //the remaining parameters are optional.\n        // check for their presence, then add the parameter if it exists.\n        if (parameters.containsKey(ParameterNamesIms.ICID_GENERATED_AT))\n            encoding.append(SEMICOLON).append(\n                    ParameterNamesIms.ICID_GENERATED_AT).append(EQUALS).append(\n                    getICIDGeneratedAt());\n\n        if (parameters.containsKey(ParameterNamesIms.TERM_IOI))\n\n            encoding.append(SEMICOLON).append(ParameterNamesIms.TERM_IOI)\n                    .append(EQUALS).append(getTerminatingIOI());\n\n        if (parameters.containsKey(ParameterNamesIms.ORIG_IOI))\n\n            encoding.append(SEMICOLON).append(ParameterNamesIms.ORIG_IOI)\n                    .append(EQUALS).append(getOriginatingIOI());\n\n        return encoding.toString();\n    }\n\n    /**\n     * <p>\n     * Get the icid-value parameter value\n     * </p>\n     *\n     * @return the value of the icid-value parameter\n     */\n    public String getICID() {\n\n        return getParameter(ParameterNamesIms.ICID_VALUE);\n    }\n\n    /**\n     * <p>\n     * Set the icid-value parameter\n     * </p>\n     *\n     * @param icid -\n     *            value to set in the icid-value parameter\n     * @throws ParseException\n     */\n    public void setICID(String icid) throws ParseException {\n\n        if (icid == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Charging-Vector, setICID(), the icid parameter is null.\");\n\n        setParameter(ParameterNamesIms.ICID_VALUE, icid);\n\n    }\n\n    /**\n     * <p>\n     * Get the icid-generated-at parameter value\n     * </p>\n     *\n     * @return the icid-generated-at parameter value\n     */\n    public String getICIDGeneratedAt() {\n\n        return getParameter(ParameterNamesIms.ICID_GENERATED_AT);\n\n    }\n\n    /**\n     * <p>\n     * Set the icid-generated-at parameter\n     * </p>\n     *\n     * @param host -\n     *            value to set in the icid-generated-at parameter\n     * @throws ParseException\n     */\n    public void setICIDGeneratedAt(String host) throws ParseException {\n\n        if (host == null)\n            throw new NullPointerException(\n                    \"JAIN-SIP Exception, \"\n                            + \"P-Charging-Vector, setICIDGeneratedAt(), the host parameter is null.\");\n\n        setParameter(ParameterNamesIms.ICID_GENERATED_AT, host);\n\n    }\n\n    /**\n     * <p>\n     * Get the orig-ioi parameter value\n     * </p>\n     *\n     * @return the orig-ioi parameter value\n     */\n    public String getOriginatingIOI() {\n\n        return getParameter(ParameterNamesIms.ORIG_IOI);\n    }\n\n    /**\n     * <p>\n     * Set the orig-ioi parameter\n     * </p>\n     *\n     * @param origIOI -\n     *            value to set in the orig-ioi parameter. If value is null or\n     *            empty, the parameter is removed\n     * @throws ParseException\n     */\n    public void setOriginatingIOI(String origIOI) throws ParseException {\n\n        if (origIOI == null || origIOI.length() == 0) {\n            removeParameter(ParameterNamesIms.ORIG_IOI);\n        } else\n            setParameter(ParameterNamesIms.ORIG_IOI, origIOI);\n\n    }\n\n    /**\n     * <p>\n     * Get the term-ioi parameter value\n     * </p>\n     *\n     * @return the term-ioi parameter value\n     */\n    public String getTerminatingIOI() {\n\n        return getParameter(ParameterNamesIms.TERM_IOI);\n    }\n\n    /**\n     * <p>\n     * Set the term-ioi parameter\n     * </p>\n     *\n     * @param termIOI -\n     *            value to set in the term-ioi parameter. If value is null or\n     *            empty, the parameter is removed\n     * @throws ParseException\n     */\n    public void setTerminatingIOI(String termIOI) throws ParseException {\n\n        if (termIOI == null || termIOI.length() == 0) {\n            removeParameter(ParameterNamesIms.TERM_IOI);\n        } else\n            setParameter(ParameterNamesIms.TERM_IOI, termIOI);\n\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value, 0);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PChargingVectorHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n\n\n\n/**\n * <p>P-Charging-Vector header SIP Private Header. </p>\n *\n *  <p> Sintax (RFC 3455): </p>\n * <pre>\n * P-Charging-Vector   = \"P-Charging-Vector\" HCOLON icid-value (SEMI charge-params)\n * charge-params        = icid-gen-addr / orig-ioi / term-ioi / generic-param\n * icid-value           = \"icid-value\" EQUAL gen-value\n * icid-gen-addr        = \"icid-generated-at\" EQUAL host\n * orig-ioi             = \"orig-ioi\" EQUAL gen-value\n * term-ioi             = \"term-ioi\" EQUAL gen-value\n * </pre>\n *\n * <p>Sintax from RFC3261: </p>\n * <pre>\n * generic-param       = token [ EQUAL gen-value ]\n * gen-value           = token / host / quoted-string\n * host                = hostname / IPv4address / Ipv6reference\n * </pre>\n *\n *\n * <p> syntax as in 3GPP TS 24.229-720 (2005-12) :\n *\n *    The access-network-charging-info parameter is an instance of generic-param\n *    from the current charge-params: </p>\n *\n * <pre>\n * access-network-charging-info   = (gprs-charging-info / i-wlan-charging-info / xdsl-charging-info / generic-param)\n * gprs-charging-info          = ggsn SEMI auth-token [SEMI pdp-info-hierarchy] *(SEMI extension-param)\n * ggsn                        = \"ggsn\" EQUAL gen-value\n * pdp-info-hierarchy          = \"pdp-info\" EQUAL LDQUOT pdp-info *(COMMA pdp-info) RDQUOT\n * pdp-info                    = pdp-item SEMI pdp-sig SEMI gcid [SEMI flow-id]\n * pdp-item                    = \"pdp-item\" EQUAL DIGIT\n * pdp-sig                     = \"pdp-sig\" EQUAL (\"yes\" / \"no\")\n * gcid                        = \"gcid\" EQUAL 1*HEXDIG\n * auth-token                  = \"auth-token\" EQUAL 1*HEXDIG\n * flow-id                     = \"flow-id\" EQUAL \"(\" \"{\" 1*DIGIT COMMA 1*DIGIT \"}\" *(COMMA \"{\" 1*DIGIT COMMA 1*DIGIT\"}\")\")\"\n * extension-param             = token [EQUAL token]\n * i-wlan-charging-info        = \"pdg\"\n * xdsl-charging-info          = bras SEMI auth-token [SEMI xDSL-bearer-info] *(SEMI extension-param)\n * bras                        = \"bras\" EQUAL gen-value\n * xDSL-bearer-info            = \"dsl-bearer-info\" EQUAL LDQUOT dsl-bearer-info *(COMMA dsl-bearer-info) RDQUOT\n * dsl-bearer-info             = dsl-bearer-item SEMI dsl-bearer-sig SEMI dslcid [SEMI flow-id]\n * dsl-bearer-item             = \"dsl-bearer-item\" EQUAL DIGIT\n * dsl-bearer-sig              = \"dsl-bearer-sig\"\n * </pre>\n *\n *\n * <p>example:\n * P-Charging-Vector: icid-value=1234bc9876e; icid-generated-at=192.0.6.8; orig-ioi=home1.net </p>\n *\n *\n * <p>TODO: gen-value can be token / host / quoted-string</p>\n * <p>TODO: add suport for the new header extensions access-network-charging-info</p>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\n\n\npublic interface PChargingVectorHeader extends Header, Parameters {\n\n    /**\n     * Name of PChargingVectorHeader\n     */\n    public final static String NAME = \"P-Charging-Vector\";\n\n\n    /**\n     * @return -- icid value.\n     */\n    public String getICID();\n\n\n    /**\n     * @param icid\n     * @throws ParseException\n     */\n    public void setICID(String icid) throws ParseException;\n\n    /**\n     * @return -- the ICID generatedAt field.\n     */\n    public String getICIDGeneratedAt();\n\n\n    /**\n     * @param host -- set the icid host value.\n     *\n     * @throws ParseException -- if bad host value.\n     */\n    public void setICIDGeneratedAt(String host) throws ParseException;\n\n\n    /**\n     *\n     * @return the originating IOI\n     */\n    public String getOriginatingIOI();\n\n\n    /**\n     * @param origIOI\n     * @throws ParseException\n     *\n     */\n    public void setOriginatingIOI(String origIOI) throws ParseException;\n\n\n    /**\n     * @return -- the terminating IOI field\n     */\n    public String getTerminatingIOI();\n\n\n    /**\n     * @param termIOI -- the terminating IOI field to set.\n     * @throws ParseException\n     */\n    public void setTerminatingIOI(String termIOI) throws ParseException;\n\n\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PMediaAuthorization.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\n\n/**\n * P-Media-Authorization SIP Private Header - RFC 3313.\n *\n * <p>Sintax:</p>\n * <pre>\n * P-Media-Authorization   = \"P-Media-Authorization\" HCOLON\n *                            P-Media-Authorization-Token\n *                            *(COMMA P-Media-Authorization-Token)\n * P-Media-Authorization-Token = 1*HEXDIG\n * </pre>\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic class PMediaAuthorization\n    extends SIPHeader\n    implements PMediaAuthorizationHeader, SIPHeaderNamesIms, ExtensionHeader\n{\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -6463630258703731133L;\n\n\n    /**\n     *  P-Media-Authorization Token\n     */\n    private String token;\n\n\n    /**\n     * Constructor\n     */\n    public PMediaAuthorization()\n    {\n        super(P_MEDIA_AUTHORIZATION);\n    }\n\n\n    /**\n     * Get the media authorization token.\n     *\n     * @return token\n     */\n    public String getToken()\n    {\n        return token;\n    }\n\n\n    /**\n     * Set the media authorization token.\n     *\n     * @param token - media authorization token to set\n     * @throws InvalidArgumentException - if token is null or empty\n     */\n    public void setMediaAuthorizationToken(String token) throws InvalidArgumentException\n    {\n        if (token == null || token.length() == 0)\n            throw new InvalidArgumentException(\" the Media-Authorization-Token parameter is null or empty\");\n\n        this.token = token;\n    }\n\n    /**\n     * Encode header\n     * @return the header content\n     */\n    protected String encodeBody()\n    {\n        return token;\n    }\n\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException (value,0);\n\n    }\n\n\n    public boolean equals(Object other)\n    {\n        if (other instanceof PMediaAuthorizationHeader)\n        {\n            final PMediaAuthorizationHeader o = (PMediaAuthorizationHeader) other;\n            return this.getToken().equals(o.getToken());\n        }\n        return false;\n\n    }\n\n\n    public Object clone() {\n        PMediaAuthorization retval = (PMediaAuthorization) super.clone();\n        if (this.token != null)\n            retval.token = this.token;\n        return retval;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PMediaAuthorizationHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.Header;\n\n\n/**\n * The P-Media-Authorization SIP Private Header - RFC 3313.\n *\n * <p>Sintax:</p>\n * <pre>\n * P-Media-Authorization   = \"P-Media-Authorization\" HCOLON\n *                            P-Media-Authorization-Token\n *                            *(COMMA P-Media-Authorization-Token)\n * P-Media-Authorization-Token = 1*HEXDIG\n * </pre>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic interface PMediaAuthorizationHeader extends Header\n{\n\n    /**\n     * Name of PMediaAuthorizationHeader\n     */\n    public final static String NAME = \"P-Media-Authorization\";\n\n    /**\n     * Set the media authorization token.\n     * @param token - media authorization token to set\n     * @throws InvalidArgumentException - if token is null or empty\n     */\n    public void setMediaAuthorizationToken(String token) throws InvalidArgumentException;\n\n    /**\n     * Get the media authorization token.\n     * @return token\n     */\n    public String getToken();\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PMediaAuthorizationList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\n\n/**\n * List of P-Media-Authorization headers.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic class PMediaAuthorizationList extends SIPHeaderList<PMediaAuthorization> {\n    private static final long serialVersionUID = -8226328073989632317L;\n\n\n    public PMediaAuthorizationList()\n    {\n        super(PMediaAuthorization.class, PMediaAuthorizationHeader.NAME);\n    }\n\n\n    public Object clone() {\n        PMediaAuthorizationList retval = new PMediaAuthorizationList();\n        return retval.clonehlist(this.hlist);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PPreferredIdentity.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.AddressParametersHeader;\n\n\n\n\n/**\n * P-Preferred-Identity SIP Private Header - RFC 3325.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n\npublic class PPreferredIdentity\n    extends AddressParametersHeader\n    implements PPreferredIdentityHeader, SIPHeaderNamesIms , ExtensionHeader {\n\n    /**\n     * constructor\n     * @param address address to set\n     */\n    public PPreferredIdentity(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * default constructor\n     */\n    public PPreferredIdentity() {\n        super(P_PREFERRED_IDENTITY);\n    }\n\n    /** Encode into canonical form.\n     * @return String containing the canonicaly encoded header.\n     */\n    public String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n\n\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException (value,0);\n\n    }\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PPreferredIdentityHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\n\n/**\n * P-Preferred-Identity header -\n * SIP Private Header: RFC 3325\n *\n * <ul>\n * <li>\n * . is used from a user agent to a trusted proxy to carry the identity the\n * user sending the SIP message wishes to be used for the P-Asserted-Header\n * field value that the trusted element will insert.\n * <li>\n * . If there are two values, one value MUST be a sip or sips URI and the other\n * MUST be a tel URI.\n * </ul>\n *\n * <p>Sintax: </p>\n * <pre>\n * PPreferredID = \"P-Preferred-Identity\" HCOLON PPreferredID-value\n *                 *(COMMA PPreferredID-value)\n * PPreferredID-value = name-addr / addr-spec\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\npublic interface PPreferredIdentityHeader extends HeaderAddress, Header {\n\n     /**\n     * Name of PreferredIdentityHeader\n     */\n    public final static String NAME = \"P-Preferred-Identity\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PPreferredService.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\n/**\n *\n * @author aayush.bhatnagar\n *\n */\npublic class PPreferredService extends SIPHeader implements PPreferredServiceHeader, SIPHeaderNamesIms, ExtensionHeader{\n\n    private String subServiceIds;\n    private String subAppIds;\n\n    protected PPreferredService(String name) {\n        super(NAME);\n    }\n\n    public PPreferredService()\n    {\n        super(P_PREFERRED_SERVICE);\n    }\n\n    @Override\n    protected String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n\n         retval.append(ParameterNamesIms.SERVICE_ID);\n\n            if(this.subServiceIds!=null)\n            {\n                retval.append(ParameterNamesIms.SERVICE_ID_LABEL).append(\".\");\n\n            retval.append(this.getSubserviceIdentifiers());\n\n            }\n\n            else if(this.subAppIds!=null)\n            {\n                retval.append(ParameterNamesIms.APPLICATION_ID_LABEL).append(\".\");\n                retval.append(this.getApplicationIdentifiers());\n            }\n\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n    public String getApplicationIdentifiers() {\n        if(this.subAppIds.charAt(0)=='.')\n        {\n            return this.subAppIds.substring(1);\n        }\n        return this.subAppIds;\n    }\n\n    public String getSubserviceIdentifiers() {\n        if(this.subServiceIds.charAt(0)=='.')\n        {\n            return this.subServiceIds.substring(1);\n        }\n        return this.subServiceIds;\n    }\n\n    public void setApplicationIdentifiers(String appids) {\n        this.subAppIds = appids;\n\n    }\n\n    public void setSubserviceIdentifiers(String subservices) {\n        this.subServiceIds = \".\".concat(subservices);\n\n    }\n\n    public boolean equals(Object other)\n    {\n        return (other instanceof PPreferredServiceHeader) && super.equals(other);\n\n    }\n\n\n    public Object clone() {\n        PPreferredService retval = (PPreferredService) super.clone();\n        return retval;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PPreferredServiceHeader.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport javax2.sip.header.Header;\n\n/**\n *\n * @author aayush.bhatnagar\n *\n * The ABNF for this header is all follows:\n *\n *  PPreferredService = \"P-Preferred-Service\"\n *                       HCOLON PPreferredService-value\n *\n *  PPreferredService-value = Service-ID *(COMMA Service-ID)\n *\n *  where,\n *\n *     Service-ID      = \"urn:urn-7:\" urn-service-id\n *     urn-service-id  = top-level *(\".\" sub-service-id)\n *     top-level       = let-dig [ *26let-dig ]\n *     sub-service-id  = let-dig [ *let-dig ]\n *     let-dig         = ALPHA / DIGIT / \"-\"\n *\n * Egs: P-Preferred-Service: urn:urn-7:3gpp-service.exampletelephony.version1\n *      P-Preferred-Service: urn:urn-7:3gpp-application.exampletelephony.version1\n *\n */\npublic interface PPreferredServiceHeader extends Header{\n\n    public static final String NAME = \"P-Preferred-Service\";\n\n    public void setSubserviceIdentifiers(String subservices);\n\n    public String getSubserviceIdentifiers();\n\n    public void setApplicationIdentifiers(String appids);\n\n    public String getApplicationIdentifiers();\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PProfileKey.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.AddressParametersHeader;\n\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n */\npublic class PProfileKey extends AddressParametersHeader implements PProfileKeyHeader, SIPHeaderNamesIms , ExtensionHeader {\n\n    public PProfileKey( ) {\n        super(P_PROFILE_KEY);\n\n    }\n\n    public PProfileKey(AddressImpl address)\n    {\n        super(NAME);\n        this.address = address;\n    }\n\n    @Override\n    protected String encodeBody() {\n\n        StringBuffer retval = new StringBuffer();\n\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n    public boolean equals(Object other)\n    {\n        return (other instanceof PProfileKey) && super.equals(other);\n\n    }\n\n\n    public Object clone() {\n        PProfileKey retval = (PProfileKey) super.clone();\n        return retval;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PProfileKeyHeader.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * The ABNF syntax of this header is as follows:\n * P-Profile-Key            = \"P-Profile-Key\" HCOLON {name-addr / addr-spec}\n *                          *{ SEMI generic-param }\n *\n * Eg: P-Profile-Key: <sip:chatroom-!.*!@example.com>\n *\n */\npublic interface PProfileKeyHeader extends HeaderAddress, Header{\n\n    public final static String NAME = \"P-Profile-Key\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PServedUser.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.AddressParametersHeader;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * This is the class used for encoding of the P-Served-User header\n *\n *\n */\npublic class PServedUser extends AddressParametersHeader implements PServedUserHeader, SIPHeaderNamesIms, ExtensionHeader{\n\n\n    public PServedUser(AddressImpl address)\n    {\n        super(P_SERVED_USER);\n        this.address = address;\n    }\n\n    public PServedUser()\n    {\n        super(NAME);\n    }\n\n    public String getRegistrationState() {\n\n        return getParameter(ParameterNamesIms.REGISTRATION_STATE);\n    }\n\n    public String getSessionCase() {\n\n        return getParameter(ParameterNamesIms.SESSION_CASE);\n    }\n\n    public void setRegistrationState(String registrationState) {\n\n        if((registrationState!=null))\n        {\n            if(registrationState.equals(\"reg\")||registrationState.equals(\"unreg\"))\n            {\n                try {\n                    setParameter(ParameterNamesIms.REGISTRATION_STATE, registrationState);\n                } catch (ParseException e) {\n                    e.printStackTrace();\n                }\n\n            }\n              else\n              {\n                  try {\n                      throw new InvalidArgumentException(\"Value can be either reg or unreg\");\n                  } catch (InvalidArgumentException e) {\n                         e.printStackTrace();\n                    }\n              }\n\n        }\n        else\n        {\n            throw new NullPointerException(\"regstate Parameter value is null\");\n        }\n\n    }\n\n    public void setSessionCase(String sessionCase) {\n\n        if((sessionCase!=null))\n        {\n            if((sessionCase.equals(\"orig\"))||(sessionCase.equals(\"term\")))\n            {\n                try {\n                    setParameter(ParameterNamesIms.SESSION_CASE, sessionCase);\n                } catch (ParseException e) {\n                    e.printStackTrace();\n                }\n            }\n              else\n              {\n                  try {\n                    throw new InvalidArgumentException(\"Value can be either orig or term\");\n                } catch (InvalidArgumentException e) {\n                    e.printStackTrace();\n                }\n\n              }\n        }\n        else\n        {\n            throw new NullPointerException(\"sess-case Parameter value is null\");\n        }\n\n    }\n\n    @Override\n    protected String encodeBody() {\n\n        StringBuffer retval = new StringBuffer();\n\n        retval.append(address.encode());\n\n        if(parameters.containsKey(ParameterNamesIms.REGISTRATION_STATE))\n            retval.append(SEMICOLON).append(ParameterNamesIms.REGISTRATION_STATE).append(EQUALS)\n            .append(this.getRegistrationState());\n\n        if(parameters.containsKey(ParameterNamesIms.SESSION_CASE))\n            retval.append(SEMICOLON).append(ParameterNamesIms.SESSION_CASE).append(EQUALS)\n            .append(this.getSessionCase());\n\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n    public boolean equals(Object other)\n    {\n         if(other instanceof PServedUser)\n         {\n            final PServedUserHeader psu = (PServedUserHeader)other;\n            return this.getAddress().equals(((PServedUser) other).getAddress());\n         }\n        return false;\n    }\n\n\n    public Object clone() {\n        PServedUser retval = (PServedUser) super.clone();\n        return retval;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PServedUserHeader.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * The ABNF of the P-Served-User Header is as follows:\n *\n * P-Served-User              = \"P-Served-User\" HCOLON PServedUser-value\n *                              *(SEMI served-user-param)\n * served-user-param          = sessioncase-param\n *                              / registration-state-param\n *                              / generic-param\n * PServedUser-value          = name-addr / addr-spec\n * sessioncase-param          = \"sescase\" EQUAL \"orig\" / \"term\"\n * registration-state-param   = \"regstate\" EQUAL \"unreg\" / \"reg\"\n *\n * Eg: P-Served-User: <sip:aayush@rancore.com>; sescase=orig; regstate=reg\n *\n *\n */\npublic interface PServedUserHeader {\n\n    public static final String NAME = \"P-Served-User\";\n\n    public void setSessionCase(String sessionCase);\n\n    public String getSessionCase();\n\n    public void setRegistrationState(String registrationState);\n\n    public String getRegistrationState();\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PUserDatabase.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n */\npublic class PUserDatabase extends gov2.nist.javax2.sip.header.ParametersHeader  implements PUserDatabaseHeader,SIPHeaderNamesIms, ExtensionHeader{\n\n    private String databaseName;\n\n    /**\n     *\n     * @param databaseName\n     */\n    public PUserDatabase(String databaseName)\n    {\n        super(NAME);\n        this.databaseName = databaseName;\n    }\n\n    /**\n     * Default constructor.\n     */\n    public PUserDatabase() {\n        super(P_USER_DATABASE);\n    }\n\n    public String getDatabaseName() {\n\n        return this.databaseName;\n    }\n\n\n    public void setDatabaseName(String databaseName) {\n        if((databaseName==null)||(databaseName.equals(\" \")))\n            throw new NullPointerException(\"Database name is null\");\n        else\n            if(!databaseName.contains(\"aaa://\"))\n        this.databaseName = new StringBuffer().append(\"aaa://\").append(databaseName).toString();\n            else\n                this.databaseName = databaseName;\n\n    }\n\n    protected String encodeBody() {\n\n        StringBuffer retval = new StringBuffer();\n        retval.append(\"<\");\n        if(getDatabaseName()!=null)\n        retval.append(getDatabaseName());\n\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n        retval.append(\">\");\n\n        return retval.toString();\n    }\n\n    public boolean equals(Object other)\n    {\n        return (other instanceof PUserDatabaseHeader) && super.equals(other);\n\n    }\n\n\n    public Object clone() {\n        PUserDatabase retval = (PUserDatabase) super.clone();\n        return retval;\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PUserDatabaseHeader.java",
    "content": "package gov2.nist.javax2.sip.header.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * This is the interface that exposes the behavior\n * of the P-User-Database header. We only have one\n * major value for this header, as per RFC 4457.\n * This value is the Database name. The DB here refers\n * to the IMS HSS. The DB name is encoded as a URI, delimited\n * by the < and > signs. There may be generic parameters for\n * this header encoded as URI parameters. They also lie between\n * the < and > delimiters. However, this URI is neither a SIP URI\n * nor a TEL URI. It is a DIAMETER AAA URI.The value of this AAA URI\n * is consumed by the S-CSCF. The S-CSCF can cache the value of the\n * HSS received in this header,thus optimizing the IMS registration\n * process.\n *\n */\npublic interface PUserDatabaseHeader extends Parameters,Header\n{\n    public final static String NAME = \"P-User-Database\";\n\n    public String getDatabaseName();\n\n    public void setDatabaseName(String name);\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PVisitedNetworkID.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Parameters;\n\nimport gov2.nist.core.Token;\n\n/**\n * P-Visited-Network-ID SIP Private Header: RFC 3455.\n *\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n\npublic class PVisitedNetworkID\n    extends gov2.nist.javax2.sip.header.ParametersHeader\n    implements PVisitedNetworkIDHeader, SIPHeaderNamesIms, ExtensionHeader {\n\n    /**\n     * visited Network ID\n     */\n    private String networkID;\n\n    // issued by Miguel Freitas\n    private boolean isQuoted;\n\n\n    public PVisitedNetworkID() {\n\n        super(P_VISITED_NETWORK_ID);\n\n    }\n\n    public PVisitedNetworkID(String networkID) {\n\n        super(P_VISITED_NETWORK_ID);\n        setVisitedNetworkID(networkID);\n\n    }\n\n    public PVisitedNetworkID(Token tok) {\n\n        super(P_VISITED_NETWORK_ID);\n        setVisitedNetworkID(tok.getTokenValue());\n\n    }\n\n    protected String encodeBody() {\n\n        StringBuffer retval = new StringBuffer();\n\n        if (getVisitedNetworkID() != null)\n        {\n            // issued by Miguel Freitas\n            if (isQuoted)\n                retval.append(DOUBLE_QUOTE + getVisitedNetworkID() + DOUBLE_QUOTE);\n            else\n                retval.append(getVisitedNetworkID());\n        }\n\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n\n        return retval.toString();\n\n    }\n\n    /**\n     * Set the visited network ID as a string. The value will be quoted in the header.\n     * @param networkID - string value\n     */\n    public void setVisitedNetworkID(String networkID) {\n        if (networkID == null)\n            throw new NullPointerException(\" the networkID parameter is null\");\n\n        this.networkID = networkID;\n\n        // issued by Miguel Freitas\n        this.isQuoted = true;\n    }\n\n    /**\n     * Set the visited network ID as a token\n     * @param networkID - token value\n     */\n    public void setVisitedNetworkID(Token networkID) {\n        if (networkID == null)\n            throw new NullPointerException(\" the networkID parameter is null\");\n\n        this.networkID = networkID.getTokenValue();\n\n        // issued by Miguel Freitas\n        this.isQuoted = false;\n    }\n\n    /**\n     * Get the visited network ID value of this header\n     */\n    public String getVisitedNetworkID() {\n        return networkID;\n    }\n\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException (value,0);\n\n    }\n\n\n    public boolean equals(Object other)\n    {\n        if (other instanceof PVisitedNetworkIDHeader)\n        {\n            PVisitedNetworkIDHeader o = (PVisitedNetworkIDHeader) other;\n            return (this.getVisitedNetworkID().equals( o.getVisitedNetworkID() )\n                && this.equalParameters( (Parameters) o ));\n        }\n        return false;\n    }\n\n\n    public Object clone() {\n        PVisitedNetworkID retval = (PVisitedNetworkID) super.clone();\n        if (this.networkID != null)\n            retval.networkID = this.networkID;\n        retval.isQuoted = this.isQuoted;\n        return retval;\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PVisitedNetworkIDHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.core.Token;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n\n\n/**\n * P-Visited-Network-ID SIP Private Header: RFC 3455.\n *\n * <ul>\n * <li>\n * . One of the conditions for a home network to accept the registration of a UA roaming to a\n * particular visited network, is the existence of a roaming agreement between the home and\n * the visited network. There is a need to indicate to the home network which one is the visited\n * network that is providing services to the roaming UA.\n * <li>\n * . user agents always register to the home network. The REGISTER request is proxied by\n * one or more proxies located in the visited network towards the home network\n * <li>\n * . the visited network includes an identification that is known at the home network\n * <li>\n * . This identification should be globally unique, and takes the form of a quoted text string or a token\n * <li>\n * . In case a REGISTER or other request is traversing different administrative domains\n * (e.g., different visited networks), a SIP proxy MAY insert a NEW P-Visited-Network-ID header\n * if the request does not contain a P-Visited-Network-ID header with the same network\n * identifier as its own network identifier\n * </ul>\n *\n * <p>Sintax: </p>\n *\n * <pre>\n * P-Visited-Network-ID = \"P-Visited-Network-ID\" HCOLON\n *                         vnetwork-spec\n *                         *(COMMA vnetwork-spec)\n * vnetwork-spec        = (token / quoted-string)\n *                         *(SEMI vnetwork-param)\n * vnetwork-param       = generic-param\n *\n *\n * eg: P-Visited-Network-ID: other.net, \"Visited network number 1\"\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n\n\npublic interface PVisitedNetworkIDHeader extends Parameters, Header {\n\n    /**\n     * Name of VisitedNetworkIDHeader\n     */\n    public final static String NAME = \"P-Visited-Network-ID\";\n\n\n    /**\n     * Set the visited network ID as a string. The value will be quoted in the header.\n     * @param networkID - string value\n     */\n    public void setVisitedNetworkID(String networkID);\n\n    /**\n     * Set the visited network ID as a token\n     * @param networkID - token value\n     */\n    public void setVisitedNetworkID(Token networkID);\n\n    /**\n     * Get the visited network ID value of this header\n     */\n    public String getVisitedNetworkID();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PVisitedNetworkIDList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\nimport gov2.nist.javax2.sip.header.ims.PVisitedNetworkIDHeader;\n\n/**\n * List of P-Visited-Network-ID headers.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic class PVisitedNetworkIDList extends SIPHeaderList<PVisitedNetworkID> {\n\n    private static final long serialVersionUID = -4346667490341752478L;\n\n    /** Default constructor\n     */\n    public PVisitedNetworkIDList() {\n        super(PVisitedNetworkID.class, PVisitedNetworkIDHeader.NAME);\n    }\n\n    public Object clone() {\n        PVisitedNetworkIDList retval = new PVisitedNetworkIDList();\n        return retval.clonehlist(this.hlist);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/ParameterNamesIms.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVAO - EST DEPARTMENT *\n *******************************************/\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.javax2.sip.address.ParameterNames;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\npublic interface ParameterNamesIms extends ParameterNames {\n\n    public static final String IK = \"ik\";\n    public static final String CK = \"ck\";\n    public static final String INTEGRITY_PROTECTED = \"integrity-protected\";\n    public static final String CCF = \"ccf\";\n    public static final String ECF = \"ecf\";\n    public static final String ICID_VALUE = \"icid-value\";\n    public static final String ICID_GENERATED_AT = \"icid-generated-at\";\n    public static final String ORIG_IOI = \"orig-ioi\";\n    public static final String TERM_IOI = \"term-ioi\";\n\n    // issued by Miguel Freitas //\n    // P-Access-Network-ID\n    public static final String CGI_3GPP = \"cgi-3gpp\";\n    public static final String UTRAN_CELL_ID_3GPP = \"utran-cell-id-3gpp\";\n    public static final String DSL_LOCATION = \"dsl-location\";\n    public static final String CI_3GPP2 = \"ci-3gpp2\";\n    // P-Charging-Vector\n    public static final String GGSN = \"ggsn\";\n    public static final String PDP_INFO = \"pdp-info\";\n    public static final String PDP_ITEM = \"pdp-item\";\n    public static final String PDP_SIG = \"pdp-sig\";\n    public static final String GCID = \"gcid\";\n    public static final String AUTH_TOKEN = \"auth-token\";\n    public static final String FLOW_ID = \"flow-id\";\n    public static final String PDG = \"pdg\";\n    public static final String BRAS = \"bras\";\n    public static final String DSL_BEARER_INFO = \"dsl-bearer-info\";\n    public static final String DSL_BEARER_ITEM = \"dsl-bearer-item\";\n    public static final String DSL_BEARER_SIG = \"dsl-bearer-sig\";\n\n    // sec-agree (Security-Server, Security-Client, Security-Verify)\n    public static final String ALG    = \"alg\";\n    public static final String EALG   = \"ealg\";\n    public static final String Q      = \"q\";\n    public static final String PROT   = \"prot\";\n    public static final String MOD    = \"mod\";\n    public static final String SPI_C  = \"spi-c\";\n    public static final String SPI_S  = \"spi-s\";\n    public static final String PORT_C = \"port-c\";\n    public static final String PORT_S = \"port-s\";\n    public static final String D_VER  = \"d-ver\";\n    // end //\n\n    //added by aayush.bhatnagar(Ref: RFC 5502)\n    public static final String SESSION_CASE = \"sescase\";\n    public static final String REGISTRATION_STATE = \"regstate\";\n\n    //added by aayush.bhatnagar(Ref: draft-drage-sipping-service-identification-03)\n    public static final String SERVICE_ID = \"urn:urn-7:\";\n    public static final String SERVICE_ID_LABEL = \"3gpp-service\";\n    public static final String APPLICATION_ID_LABEL = \"3gpp-application\";\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/Path.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.ims.PathHeader;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic class Path\n    extends gov2.nist.javax2.sip.header.AddressParametersHeader\n    implements PathHeader, SIPHeaderNamesIms , ExtensionHeader{\n\n    /**\n     * constructor\n     * @param address address to set\n     */\n    public Path(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * default constructor\n     */\n    public Path()\n    {\n        // issued by Miguel Freitas\n        super(NAME);\n\n    }\n\n    /** Encode into canonical form.\n     *@return String containing the canonicaly encoded header.\n     */\n    public String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PathHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\n/*\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n/**\n * PATH header SIP param: RFC 3327.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n *\n */\n\n\n\npublic interface PathHeader extends HeaderAddress, Parameters, Header {\n\n    /**\n     * Name of PathHeader\n     */\n    public final static String NAME = \"Path\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PathList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVAO - EST DEPARTMENT *\n *******************************************/\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic class PathList extends SIPHeaderList<Path> {\n\n    /** Default constructor\n     */\n    public PathList() {\n        super(Path.class, PathHeader.NAME);\n    }\n\n\n    public Object clone() {\n        PathList retval = new PathList();\n        return retval.clonehlist(this.hlist);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/Privacy.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\n\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\nimport javax2.sip.header.Parameters;\n\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\n/**\n * Privacy SIP header - RFC 3323.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class Privacy\n    extends SIPHeader\n    implements PrivacyHeader, SIPHeaderNamesIms, ExtensionHeader\n{\n\n    /**\n     * Privacy type\n     */\n    private String privacy;\n\n\n    /**\n     * Default constructor.\n     */\n    public Privacy() {\n        super(PRIVACY);\n    }\n\n    /**\n     * Constructor given a privacy type\n     *@param privacy\n     */\n    public Privacy(String privacy)\n    {\n        this();\n        this.privacy = privacy;\n\n    }\n\n\n    /**\n     * Encode into a canonical string.\n     * @return String.\n     */\n    public String encodeBody()\n    {\n        return this.privacy;\n    }\n\n\n\n    /**\n     * Get privacy type\n     * @return privacy type\n     */\n    public String getPrivacy()\n    {\n        return privacy;\n    }\n\n\n\n    /**\n     * set the privacy type.\n     * @param  privacy -- privacy type to set.\n     */\n\n    public void setPrivacy(String privacy) throws ParseException\n    {\n\n        if (privacy == null || privacy == \"\")\n            throw new NullPointerException(\n                \"JAIN-SIP Exception, \"\n                    + \" Privacy, setPrivacy(), privacy value is null or empty\");\n        this.privacy = privacy;\n\n    }\n\n    /**\n     * Suppress direct setting of values.\n     *\n     */\n    public void setValue(String value) throws ParseException {\n        throw new ParseException(value,0);\n\n    }\n\n\n    public boolean equals(Object other)\n    {\n        if (other instanceof PrivacyHeader)\n        {\n            PrivacyHeader o = (PrivacyHeader) other;\n            return (this.getPrivacy().equals( o.getPrivacy() ));\n        }\n        return false;\n\n    }\n\n\n    public Object clone() {\n        Privacy retval = (Privacy) super.clone();\n        if (this.privacy != null)\n            retval.privacy = this.privacy;\n        return retval;\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PrivacyHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n/**\n * Privacy Header RFC 3323.\n *\n * <p>Sintax: </p>\n *<pre>\n * Privacy-hdr  = \"Privacy\" HCOLON priv-value *(\";\" priv-value)\n * priv-value   = \"header\" / \"session\" / \"user\" /\n *                \"id\" / \"none\" / \"critical\" / token\n * example:\n *           Privacy: id\n * </pre>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic interface PrivacyHeader extends Header\n{\n\n    /**\n     * Name of PrivacyHeader\n     */\n    public final static String NAME = \"Privacy\";\n\n\n    /**\n     * Set Privacy header value\n     * @param  privacy -- privacy type to set.\n     */\n    public void setPrivacy(String privacy) throws ParseException;\n\n    /**\n     * Get Privacy header value\n     * @return privacy token name\n     */\n    public String getPrivacy();\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/PrivacyList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal)   *\n *****************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\n\n\n/**\n * List of Privacy headers.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class PrivacyList extends SIPHeaderList<Privacy> {\n\n    private static final long serialVersionUID = 1798720509806307461L;\n\n\n    /**\n     * Default constructor\n     */\n    public PrivacyList() {\n        super(Privacy.class, PrivacyHeader.NAME);\n    }\n\n\n    public Object clone() {\n        PrivacyList retval = new PrivacyList();\n        return retval.clonehlist(this.hlist);\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SIPHeaderNamesIms.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic interface SIPHeaderNamesIms\n    extends gov2.nist.javax2.sip.header.SIPHeaderNames {\n\n    public static final String PATH = PathHeader.NAME;\n    public static final String SERVICE_ROUTE = ServiceRouteHeader.NAME;\n    public static final String P_ASSERTED_IDENTITY = PAssertedIdentityHeader.NAME;\n    public static final String P_PREFERRED_IDENTITY = PPreferredIdentityHeader.NAME;\n    public static final String CALLED_PARTY_ID = PCalledPartyIDHeader.NAME;\n    public static final String P_VISITED_NETWORK_ID = PVisitedNetworkIDHeader.NAME;\n    public static final String P_CHARGING_FUNCTION_ADDRESSES = PChargingFunctionAddressesHeader.NAME;\n    public static final String P_CHARGING_VECTOR = PChargingVectorHeader.NAME;\n\n\n    // issued by Miguel Freitas\n    public static final String PRIVACY = PrivacyHeader.NAME;\n    public static final String P_ASSOCIATED_URI = PAssociatedURIHeader.NAME;\n    public static final String P_MEDIA_AUTHORIZATION = PMediaAuthorizationHeader.NAME;\n    public static final String P_ACCESS_NETWORK_INFO = PAccessNetworkInfoHeader.NAME;\n    public static final String SECURITY_SERVER = SecurityServerHeader.NAME;\n    public static final String SECURITY_CLIENT = SecurityClientHeader.NAME;\n    public static final String SECURITY_VERIFY = SecurityVerifyHeader.NAME;\n\n    //added by aayush\n    public static final String P_USER_DATABASE = PUserDatabaseHeader.NAME;\n    //added by aayush\n    public static final String P_PROFILE_KEY = PProfileKeyHeader.NAME;\n    //added by aayush\n    public static final String P_SERVED_USER = PServedUserHeader.NAME;\n    //added by aayush\n    public static final String P_PREFERRED_SERVICE = PPreferredServiceHeader.NAME;\n    //added by aayush\n    public static final String P_ASSERTED_SERVICE = PAssertedServiceHeader.NAME;\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityAgree.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.Parameters;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.Separators;\nimport gov2.nist.javax2.sip.header.ParametersHeader;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\n\n\n/**\n * \"Security Mechanism Agreemet for SIP Sessions\"\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p>Headers: Security-Server + Security-Client + Security-Verify</p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic abstract class SecurityAgree\n    extends ParametersHeader\n{\n    //TODO serialVersionUID\n    //private static final long serialVersionUID = -6671234553927258745L;\n\n    //public static final String EALG = ParameterNamesIms.EALG;\n    // ...\n\n    /**\n     * Security Mechanism value\n     */\n    private String secMechanism;\n\n\n    /**\n     * Constructor\n     * @param name - name of the Security Agree header to create\n     */\n    public SecurityAgree(String name)\n    {\n        super(name);\n        parameters.setSeparator(Separators.SEMICOLON);\n    }\n\n    /**\n     * Default constructor\n     */\n    public SecurityAgree()\n    {\n        super();\n        parameters.setSeparator(Separators.SEMICOLON);\n    }\n\n\n    public void setParameter(String name, String value) throws ParseException\n    {\n        if (value == null)\n            throw new NullPointerException(\"null value\");\n\n        NameValue nv = super.parameters.getNameValue(name.toLowerCase());\n        if (nv == null)\n        {\n            nv = new NameValue(name, value);\n\n            // quoted values\n            if (name.equalsIgnoreCase(ParameterNamesIms.D_VER))\n            {\n                nv.setQuotedValue();\n\n                if (value.startsWith(Separators.DOUBLE_QUOTE))\n                    throw new ParseException(value\n                            + \" : Unexpected DOUBLE_QUOTE\", 0);\n            }\n\n            super.setParameter(nv);\n        }\n        else\n        {\n            nv.setValueAsObject(value);\n        }\n\n    }\n\n    public String encodeBody()\n    {\n        return this.secMechanism + SEMICOLON + SP + parameters.encode();\n    }\n\n\n\n    /**\n     * Set security mechanism.\n     * <p>eg: Security-Client: ipsec-3gpp</p>\n     * @param secMech - security mechanism name\n     */\n    public void setSecurityMechanism(String secMech) throws ParseException {\n        if (secMech == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityAgree, setSecurityMechanism(), the sec-mechanism parameter is null\");\n        this.secMechanism = secMech;\n    }\n\n    /**\n     * Set Encryption Algorithm (ealg parameter)\n     * @param ealg - encryption algorithm value\n     * @throws ParseException\n     */\n    public void setEncryptionAlgorithm(String ealg) throws ParseException {\n        if (ealg == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setEncryptionAlgorithm(), the encryption-algorithm parameter is null\");\n\n        setParameter(ParameterNamesIms.EALG, ealg);\n    }\n\n    /**\n     * Set Algorithm (alg parameter)\n     * @param alg - algorithm value\n     * @throws ParseException\n     */\n    public void setAlgorithm(String alg) throws ParseException {\n        if (alg == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setAlgorithm(), the algorithm parameter is null\");\n        setParameter(ParameterNamesIms.ALG, alg);\n    }\n\n    /**\n     * Set Protocol (prot paramater)\n     * @param prot - protocol value\n     * @throws ParseException\n     */\n    public void setProtocol(String prot) throws ParseException {\n        if (prot == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setProtocol(), the protocol parameter is null\");\n        setParameter(ParameterNamesIms.PROT, prot);\n    }\n\n    /**\n     * Set Mode (mod parameter)\n     * @param mod - mode value\n     * @throws ParseException\n     */\n    public void setMode(String mod) throws ParseException {\n        if (mod == null)\n            throw new NullPointerException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setMode(), the mode parameter is null\");\n        setParameter(ParameterNamesIms.MOD, mod);\n    }\n\n    /**\n     * Set Client SPI (spi-c parameter)\n     * @param spic - spi-c value\n     * @throws InvalidArgumentException\n     */\n    public void setSPIClient(int spic) throws InvalidArgumentException {\n        if (spic < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setSPIClient(), the spi-c parameter is <0\");\n        setParameter(ParameterNamesIms.SPI_C, spic);\n    }\n\n    /**\n     * Set Server SPI (spi-s parameter)\n     * @param spis - spi-s value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setSPIServer(int spis) throws InvalidArgumentException {\n        if (spis < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setSPIServer(), the spi-s parameter is <0\");\n        setParameter(ParameterNamesIms.SPI_S, spis);\n    }\n\n    /**\n     * Set Client Port (port-c parameter)\n     * @param portC - port-c value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setPortClient(int portC) throws InvalidArgumentException {\n        if (portC < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setPortClient(), the port-c parameter is <0\");\n        setParameter(ParameterNamesIms.PORT_C, portC);\n    }\n\n    /**\n     * Set Server Port (port-s parameter)\n     * @param portS - port-s value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setPortServer(int portS) throws InvalidArgumentException {\n        if (portS < 0)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setPortServer(), the port-s parameter is <0\");\n        setParameter(ParameterNamesIms.PORT_S, portS);\n    }\n\n    /**\n     * <p>Set Preference.\n     * The \"q\" parameter indicates a relative preference for the particular mechanism.\n     * The higher the value the more preferred the mechanism is.\n     * Range from 0.001 to 0.999.</p>\n     * @param q - q parameter value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setPreference(float q) throws InvalidArgumentException {\n        if (q < 0.0f)\n            throw new InvalidArgumentException(\n                \"JAIN-SIP \"\n                    + \"Exception, SecurityClient, setPreference(), the preference (q) parameter is <0\");\n        setParameter(ParameterNamesIms.Q, q);\n    }\n\n\n\n    // get param\n\n    /**\n     * Get Security Mechanism\n     * @return security mechanims value\n     */\n    public String getSecurityMechanism() {\n        return this.secMechanism;\n    }\n    /**\n     * Get Encryption Algorithm\n     * @return ealg parameter value\n     */\n    public String getEncryptionAlgorithm() {\n        return getParameter(ParameterNamesIms.EALG);\n    }\n\n    /**\n     * Get Algorithm\n     * @return alg parameter value\n     */\n    public String getAlgorithm() {\n        return getParameter(ParameterNamesIms.ALG);\n    }\n\n    /**\n     * Get Protocol\n     * @return prot parameter value\n     */\n    public String getProtocol() {\n        return getParameter(ParameterNamesIms.PROT);\n    }\n\n    /**\n     * Get Mode\n     * @return mod parameter value\n     */\n    public String getMode() {\n        return getParameter(ParameterNamesIms.MOD);\n\n    }\n    /**\n     * Get Client SPI\n     * @return spi-c parameter value\n     */\n    public int getSPIClient() {\n        return (Integer.parseInt(getParameter(ParameterNamesIms.SPI_C)));\n    }\n\n    /**\n     * Get Server SPI\n     * @return spi-s parameter value\n     */\n    public int getSPIServer() {\n        return (Integer.parseInt(getParameter(ParameterNamesIms.SPI_S)));\n    }\n\n    /**\n     * Get Client Port\n     * @return port-c parameter value\n     */\n    public int getPortClient() {\n        return (Integer.parseInt(getParameter(ParameterNamesIms.PORT_C)));\n    }\n\n    /**\n     * Get Server Port\n     * @return port-s parameter value\n     */\n    public int getPortServer() {\n        return (Integer.parseInt(getParameter(ParameterNamesIms.PORT_S)));\n    }\n\n    /**\n     * Get Preference\n     * @return q parameter value\n     */\n    public float getPreference() {\n        return (Float.parseFloat(getParameter(ParameterNamesIms.Q)));\n    }\n\n\n    public boolean equals(Object other)\n    {\n\n        if(other instanceof SecurityAgreeHeader)\n        {\n            SecurityAgreeHeader o = (SecurityAgreeHeader) other;\n            return (this.getSecurityMechanism().equals( o.getSecurityMechanism() )\n                && this.equalParameters( (Parameters) o ));\n        }\n        return false;\n\n    }\n\n\n    public Object clone() {\n        SecurityAgree retval = (SecurityAgree) super.clone();\n        if (this.secMechanism != null)\n            retval.secMechanism = this.secMechanism;\n        return retval;\n    }\n\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityAgreeHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n\n/**\n * \"Security Mechanism Agreemet for SIP Sessions\"\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p>Headers: Security-Server + Security-Client + Security-Verify</p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic interface SecurityAgreeHeader extends Parameters, Header\n{\n\n    /**\n     * Set security mechanism.\n     * <p>eg: Security-Client: ipsec-3gpp</p>\n     * @param secMech - security mechanism name\n     */\n    public void setSecurityMechanism(String secMech) throws ParseException;\n\n    /**\n     * Set Encryption Algorithm (ealg parameter)\n     * @param ealg - encryption algorithm value\n     * @throws ParseException\n     */\n    public void setEncryptionAlgorithm(String ealg) throws ParseException;\n\n    /**\n     * Set Algorithm (alg parameter)\n     * @param alg - algorithm value\n     * @throws ParseException\n     */\n    public void setAlgorithm(String alg) throws ParseException;\n\n    /**\n     * Set Protocol (prot paramater)\n     * @param prot - protocol value\n     * @throws ParseException\n     */\n    public void setProtocol(String prot) throws ParseException;\n\n    /**\n     * Set Mode (mod parameter)\n     * @param mod - mode value\n     * @throws ParseException\n     */\n    public void setMode(String mod) throws ParseException;\n\n    /**\n     * Set Client SPI (spi-c parameter)\n     * @param spic - spi-c value\n     * @throws InvalidArgumentException\n     */\n    public void setSPIClient(int spic) throws InvalidArgumentException;\n\n    /**\n     * Set Server SPI (spi-s parameter)\n     * @param spis - spi-s value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setSPIServer(int spis) throws InvalidArgumentException;\n\n    /**\n     * Set Client Port (port-c parameter)\n     * @param portC - port-c value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setPortClient(int portC) throws InvalidArgumentException;\n\n\n    /**\n     * Set Server Port (port-s parameter)\n     * @param portS - port-s value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setPortServer(int portS) throws InvalidArgumentException;\n\n    /**\n     * Set Preference\n     * @param q - q parameter value\n     * @throws InvalidArgumentException - when value is not valid\n     */\n    public void setPreference(float q) throws InvalidArgumentException;\n\n\n\n    /**\n     * Get Security Mechanism\n     * @return security mechanims value\n     */\n    public String getSecurityMechanism();\n\n    /**\n     * Get Encryption Algorithm\n     * @return ealg parameter value\n     */\n    public String getEncryptionAlgorithm();\n\n    /**\n     * Get Algorithm\n     * @return alg parameter value\n     */\n    public String getAlgorithm();\n\n    /**\n     * Get Protocol\n     * @return prot parameter value\n     */\n    public String getProtocol();\n\n    /**\n     * Get Mode\n     * @return mod parameter value\n     */\n    public String getMode();\n\n    /**\n     * Get Client SPI\n     * @return spi-c parameter value\n     */\n    public int getSPIClient();\n\n    /**\n     * Get Server SPI\n     * @return spi-s parameter value\n     */\n    public int getSPIServer();\n\n    /**\n     * Get Client Port\n     * @return port-c parameter value\n     */\n    public int getPortClient();\n\n    /**\n     * Get Server Port\n     * @return port-s parameter value\n     */\n    public int getPortServer();\n\n    /**\n     * Get Preference\n     * @return q parameter value\n     */\n    public float getPreference();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityClient.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.ExtensionHeader;\n\n\n/**\n * Security-Client header\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class SecurityClient\n    extends SecurityAgree\n    implements SecurityClientHeader, ExtensionHeader\n{\n\n    // TODO serialVersionUID\n\n    public SecurityClient()\n    {\n        super(SecurityClientHeader.NAME);\n\n    }\n\n\n    public void setValue(String value) throws ParseException\n    {\n        throw new ParseException(value,0);\n    }\n\n}\n\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityClientHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\n/**\n * Security-Client header\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic interface SecurityClientHeader extends SecurityServerHeader\n{\n    /**\n     * Name of SecurityClientHeader\n     */\n    public final static String NAME = \"Security-Client\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityClientList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\nimport gov2.nist.javax2.sip.header.ims.SecurityClient;\n\n\n/**\n * List of Security-Client headers.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class SecurityClientList extends SIPHeaderList<SecurityClient>\n{\n\n\n    private static final long serialVersionUID = 3094231003329176217L;\n\n\n    public SecurityClientList()\n    {\n        super(SecurityClient.class, SecurityClientHeader.NAME);\n    }\n\n\n    public Object clone() {\n        SecurityClientList retval = new SecurityClientList();\n        return retval.clonehlist(this.hlist);\n    }\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityServer.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\n\n/**\n * Security-Server header\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class SecurityServer\n    extends SecurityAgree\n    implements SecurityServerHeader, ExtensionHeader\n{\n\n    // TODO serialVersionUID\n\n    public SecurityServer()\n    {\n        super(SecurityServerHeader.NAME);\n\n    }\n\n\n    public void setValue(String value) throws ParseException\n    {\n        throw new ParseException(value,0);\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityServerHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.Parameters;\n\n\n/**\n * Security-Server header\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic interface SecurityServerHeader extends SecurityAgreeHeader\n{\n    /**\n     * Name of SecurityServerHeader\n     */\n    public final static String NAME = \"Security-Server\";\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityServerList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\nimport gov2.nist.javax2.sip.header.ims.SecurityServer;\n\n\n/**\n * List of Security-Server headers.\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class SecurityServerList extends SIPHeaderList<SecurityServer>\n{\n\n\n    private static final long serialVersionUID = -1392066520803180238L;\n\n    public SecurityServerList()\n    {\n        super(SecurityServer.class, SecurityServerHeader.NAME);\n    }\n\n    public Object clone() {\n        SecurityServerList retval = new SecurityServerList();\n        return retval.clonehlist(this.hlist);\n    }\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityVerify.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\n\n/**\n * Security-Verify header\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class SecurityVerify\n    extends SecurityAgree\n    implements SecurityVerifyHeader, ExtensionHeader\n{\n\n    // TODO serialVersionUID\n\n    public SecurityVerify()\n    {\n        super(SecurityVerifyHeader.NAME);\n\n    }\n\n\n    public void setValue(String value) throws ParseException\n    {\n        throw new ParseException(value,0);\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityVerifyHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement.\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n/**\n * Security-Verify header\n *  - sec-agree: RFC 3329 + 3GPP TS33.203 (Annex H).\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\n\npublic interface SecurityVerifyHeader extends SecurityAgreeHeader\n{\n    /**\n     * Name of SecurityVerifyHeader\n     */\n    public final static String NAME = \"Security-Verify\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/SecurityVerifyList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government,\n* and others.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.header.ims;\n\n\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\nimport gov2.nist.javax2.sip.header.ims.SecurityVerify;\n\n\n/**\n * List of Security-Verify headers.\n *\n * <p></p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\n\npublic class SecurityVerifyList extends SIPHeaderList<SecurityVerify>\n{\n\n\n    private static final long serialVersionUID = 563201040577795125L;\n\n    public SecurityVerifyList()\n    {\n        super(SecurityVerify.class, SecurityVerifyHeader.NAME);\n    }\n\n    public Object clone() {\n        SecurityVerifyList retval = new SecurityVerifyList();\n        return retval.clonehlist(this.hlist);\n    }\n\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/ServiceRoute.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ExtensionHeader;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\n\n\n\n/**\n * SERVICE-ROUTE header SIP param: RFC 3608.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\n\npublic class ServiceRoute\n    extends gov2.nist.javax2.sip.header.AddressParametersHeader\n    implements ServiceRouteHeader, SIPHeaderNamesIms, ExtensionHeader {\n\n    /**\n     * constructor\n     * @param address address to set\n     */\n    public ServiceRoute(AddressImpl address) {\n        super(NAME);\n        this.address = address;\n    }\n\n    /**\n     * default constructor\n     */\n    public ServiceRoute() {\n        super(SERVICE_ROUTE);\n    }\n\n    /** Encode into canonical form.\n     *@return String containing the canonicaly encoded header.\n     */\n    public String encodeBody() {\n        StringBuffer retval = new StringBuffer();\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(LESS_THAN);\n        }\n        retval.append(address.encode());\n        if (address.getAddressType() == AddressImpl.ADDRESS_SPEC) {\n            retval.append(GREATER_THAN);\n        }\n\n        if (!parameters.isEmpty())\n            retval.append(SEMICOLON + this.parameters.encode());\n        return retval.toString();\n    }\n\n    public void setValue(String value) throws ParseException {\n        throw new ParseException (value,0);\n\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/ServiceRouteHeader.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\npackage gov2.nist.javax2.sip.header.ims;\n\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderAddress;\nimport javax2.sip.header.Parameters;\n\n\n/**\n * SERVICE-ROUTE header SIP param: RFC 3608.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\npublic interface ServiceRouteHeader extends HeaderAddress, Parameters, Header {\n\n    /**\n     * Name of ServiceRouteHeader\n     */\n    public final static String NAME = \"Service-Route\";\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/ServiceRouteList.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVAO - EST DEPARTMENT *\n *******************************************/\npackage gov2.nist.javax2.sip.header.ims;\n\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\npublic class ServiceRouteList extends SIPHeaderList<ServiceRoute> {\n\n\n    private static final long serialVersionUID = -4264811439080938519L;\n\n    /** Default constructor\n     */\n    public ServiceRouteList() {\n        super(ServiceRoute.class, ServiceRouteHeader.NAME);\n    }\n\n    public Object clone() {\n        ServiceRouteList retval = new ServiceRouteList();\n        return retval.clonehlist(this.hlist);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/header/ims/WWWAuthenticateHeaderIms.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.header.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.WWWAuthenticateHeader;\n\n\n\n/**\n * Extension to WWW-authenticate header (3GPP TS 24229-5d0).\n *\n * <p>Defines a new authentication parameter (auth-param) for the WWW-Authenticate header\n * used in a 401 (Unauthorized) response to the REGISTER request.\n * For more information, see RFC 2617 [21] subclause 3.2.1.</p>\n *\n * <pre>\n *  auth-param = 1#( integrity-key / cipher-key )\n *  integrity-key = \"ik\" EQUAL ik-value\n *  cipher-key = \"ck\" EQUAL ck-value\n *  ik-value = LDQUOT *(HEXDIG) RDQUOT\n *  ck-value = LDQUOT *(HEXDIG) RDQUOT\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS - Nú 10045401\n */\n\n\npublic interface WWWAuthenticateHeaderIms extends WWWAuthenticateHeader\n{\n    // issued by Miguel Freitas\n    public static final String IK = ParameterNamesIms.IK;\n    public static final String CK = ParameterNamesIms.CK;\n\n\n    public void setIK(String ik) throws ParseException;\n\n    public String getIK();\n\n    public void setCK(String ck) throws ParseException;\n\n    public String getCK();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/Content.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentTypeHeader;\n\npublic interface Content {\n\n    public abstract void setContent(Object content);\n    \n    public abstract Object getContent();\n \n    public abstract ContentTypeHeader getContentTypeHeader();\n    \n    public abstract ContentDispositionHeader getContentDispositionHeader();\n\n    /**\n     * The default packing method. This packs the content to be appended to the\n     * sip message.\n     * \n     */\n    public abstract String toString();\n\n \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/ContentImpl.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentTypeHeader;\n\npublic class ContentImpl implements Content {\n   \n   \n    /*\n     * The content type header for this chunk of content.\n     */\n   \n    private Object content;\n\n    private String boundary;\n    \n    private ContentTypeHeader contentTypeHeader;\n    \n    private ContentDispositionHeader contentDispositionHeader;\n\n    \n\n    public ContentImpl( String content, String boundary ) {\n        this.content = content;\n    \n        this.boundary = boundary;\n    }\n\n    \n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.message.ContentExt#setContent(java.lang.String)\n     */\n    public void setContent(Object content) {\n        this.content = content;\n    }\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.message.ContentExt#getContentTypeHeader()\n     */\n    public ContentTypeHeader getContentTypeHeader() {\n        return contentTypeHeader;\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.message.Content#getContent()\n     */\n    public Object getContent() {\n        return this.content;\n    }\n    \n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.message.ContentExt#toString()\n     */\n    public String toString() {\n        // This is not part of a multipart message.\n        if (boundary == null) {\n            return content.toString();\n        } else {\n           if ( this.contentDispositionHeader != null ) {\n            return \"--\" + boundary + \"\\r\\n\" + getContentTypeHeader() + \n                    this.getContentDispositionHeader().toString() + \"\\r\\n\"\n                    + content.toString();\n           } else {\n               return \"--\" + boundary + \"\\r\\n\" + getContentTypeHeader() + \"\\r\\n\" +  content.toString();\n           }\n        }\n    }\n\n\n\n    /**\n     * @param contentDispositionHeader the contentDispositionHeader to set\n     */\n    public void setContentDispositionHeader(ContentDispositionHeader contentDispositionHeader) {\n        this.contentDispositionHeader = contentDispositionHeader;\n    }\n\n\n\n    /**\n     * @return the contentDispositionHeader\n     */\n    public ContentDispositionHeader getContentDispositionHeader() {\n        return contentDispositionHeader;\n    }\n\n\n\n    /**\n     * @param contentTypeHeader the contentTypeHeader to set\n     */\n    public void setContentTypeHeader(ContentTypeHeader contentTypeHeader) {\n        this.contentTypeHeader = contentTypeHeader;\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/HeaderIterator.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.message;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.util.ListIterator;\nimport java.util.NoSuchElementException;\n\n/**\n * Iterator over lists of headers. Allows for uniform removal handling for singleton headers.\n * @author M. Ranganathan\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:53 $\n * @since 1.1\n */\npublic class HeaderIterator implements ListIterator {\n    private boolean toRemove;\n    private int index;\n    private SIPMessage sipMessage;\n    private SIPHeader sipHeader;\n\n    protected HeaderIterator(SIPMessage sipMessage, SIPHeader sipHeader) {\n        this.sipMessage = sipMessage;\n        this.sipHeader = sipHeader;\n    }\n\n    public Object next() throws NoSuchElementException {\n        if (sipHeader == null || index == 1)\n            throw new NoSuchElementException();\n        toRemove = true;\n        index = 1;\n        return (Object) sipHeader;\n    }\n\n    public Object previous() throws NoSuchElementException {\n        if (sipHeader == null || index == 0)\n            throw new NoSuchElementException();\n        toRemove = true;\n        index = 0;\n        return (Object) sipHeader;\n    }\n\n    public int nextIndex() {\n        return 1;\n    }\n\n    public int previousIndex() {\n        return index == 0 ? -1 : 0;\n    }\n\n    public void set(Object header) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void add(Object header) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void remove() throws IllegalStateException {\n        if (this.sipHeader == null)\n            throw new IllegalStateException();\n        if (toRemove) {\n            this.sipHeader = null;\n            this.sipMessage.removeHeader(sipHeader.getName());\n        } else {\n            throw new IllegalStateException();\n        }\n    }\n\n    public boolean hasNext() {\n        return index == 0;\n    }\n\n    public boolean hasPrevious() {\n        return index == 1;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/ListMap.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.header.ims.*;\n\nimport java.util.Hashtable;\n\n/**\n * A map of which of the standard headers may appear as a list\n *\n * @version 1.2 $Revision: 1.14 $ $Date: 2009/07/17 18:57:53 $\n * @since 1.1\n */\nclass ListMap {\n    // A table that indicates whether a header has a list representation or\n    // not (to catch adding of the non-list form when a list exists.)\n    // Entries in this table allow you to look up the list form of a header\n    // (provided it has a list form). Note that under JAVA-5 we have\n    // typed collections which would render such a list obsolete. However,\n    // we are not using java 5.\n    private static Hashtable<Class<?>,Class<?>> headerListTable;\n\n    private static boolean initialized;\n    static {\n        initializeListMap();\n    }\n\n    static private void initializeListMap() {\n        /*\n         * Build a table mapping between objects that have a list form and the\n         * class of such objects.\n         */\n        headerListTable = new Hashtable<Class<?>, Class<?>>();\n        headerListTable.put(ExtensionHeaderImpl.class, ExtensionHeaderList.class);\n\n        headerListTable.put(Contact.class, ContactList.class);\n\n        headerListTable.put(ContentEncoding.class, ContentEncodingList.class);\n\n        headerListTable.put(Via.class, ViaList.class);\n\n        headerListTable.put(WWWAuthenticate.class, WWWAuthenticateList.class);\n\n        headerListTable.put(Accept.class, AcceptList.class);\n\n        headerListTable.put(AcceptEncoding.class, AcceptEncodingList.class);\n\n        headerListTable.put(AcceptLanguage.class, AcceptLanguageList.class);\n\n        headerListTable.put(ProxyRequire.class, ProxyRequireList.class);\n\n        headerListTable.put(Route.class, RouteList.class);\n\n        headerListTable.put(Require.class, RequireList.class);\n\n        headerListTable.put(Warning.class, WarningList.class);\n\n        headerListTable.put(Unsupported.class, UnsupportedList.class);\n\n        headerListTable.put(AlertInfo.class, AlertInfoList.class);\n\n        headerListTable.put(CallInfo.class, CallInfoList.class);\n\n        headerListTable.put(ProxyAuthenticate.class,ProxyAuthenticateList.class);\n\n        headerListTable.put(ProxyAuthorization.class, ProxyAuthorizationList.class);\n\n        headerListTable.put(Authorization.class, AuthorizationList.class);\n\n        headerListTable.put(Allow.class, AllowList.class);\n\n        headerListTable.put(RecordRoute.class, RecordRouteList.class);\n\n        headerListTable.put(ContentLanguage.class, ContentLanguageList.class);\n\n        headerListTable.put(ErrorInfo.class, ErrorInfoList.class);\n\n        headerListTable.put(Supported.class, SupportedList.class);\n\n        headerListTable.put(InReplyTo.class,InReplyToList.class);\n\n        // IMS headers.\n\n        headerListTable.put(PAssociatedURI.class, PAssociatedURIList.class);\n\n        headerListTable.put(PMediaAuthorization.class, PMediaAuthorizationList.class);\n\n        headerListTable.put(Path.class, PathList.class);\n\n        headerListTable.put(Privacy.class,PrivacyList.class);\n\n        headerListTable.put(ServiceRoute.class, ServiceRouteList.class);\n\n        headerListTable.put(PVisitedNetworkID.class, PVisitedNetworkIDList.class);\n\n        headerListTable.put(SecurityClient.class, SecurityClientList.class);\n\n        headerListTable.put(SecurityServer.class, SecurityServerList.class);\n\n        headerListTable.put(SecurityVerify.class, SecurityVerifyList.class);\n\n        headerListTable.put(PAssertedIdentity.class, PAssertedIdentityList.class);\n\n        initialized = true;\n\n    }\n\n    /**\n     * return true if this has an associated list object.\n     */\n    static protected boolean hasList(SIPHeader sipHeader) {\n        if (sipHeader instanceof SIPHeaderList)\n            return false;\n        else {\n            Class<?> headerClass = sipHeader.getClass();\n            return headerListTable.get(headerClass) != null;\n        }\n    }\n\n    /**\n     * Return true if this has an associated list object.\n     */\n    static protected boolean hasList(Class<?> sipHdrClass) {\n        if (!initialized)\n            initializeListMap();\n        return headerListTable.get(sipHdrClass) != null;\n    }\n\n    /**\n     * Get the associated list class.\n     */\n    static protected Class<?> getListClass(Class<?> sipHdrClass) {\n        if (!initialized)\n            initializeListMap();\n        return (Class<?>) headerListTable.get(sipHdrClass);\n    }\n\n    /**\n     * Return a list object for this header if it has an associated list object.\n     */\n    @SuppressWarnings(\"unchecked\")\n    static protected SIPHeaderList<SIPHeader> getList(SIPHeader sipHeader) {\n        if (!initialized)\n            initializeListMap();\n        try {\n            Class<?> headerClass = sipHeader.getClass();\n            Class<?> listClass =  headerListTable.get(headerClass);\n            SIPHeaderList<SIPHeader> shl = (SIPHeaderList<SIPHeader>) listClass.newInstance();\n            shl.setHeaderName(sipHeader.getName());\n            return shl;\n        } catch (InstantiationException ex) {\n            ex.printStackTrace();\n        } catch (IllegalAccessException ex) {\n            ex.printStackTrace();\n        }\n        return null;\n    }\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/MessageExt.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContentLengthHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.ToHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.message.Message;\n\n/**\n *\n * @author jean.deruelle@gmail.com\n *\n */\npublic interface MessageExt extends Message {\n\n     /**\n     * This method allows applications to associate application context with\n     * the message. This specification does not define the format of this\n     * data, this the responsibility of the application and is dependent\n     * on the application.\n     * this application data is un-interpreted by the stack.\n     * Beware : when you clone a message, the deepcopy does not apply to the application data\n     * (instead, we would just make a copy of the pointer).\n     *\n     * @param applicationData - un-interpreted application data.\n     * @since v2.0\n     *\n     */\n\n    public void setApplicationData (Object applicationData);\n\n\n    /**\n     * Returns the application data associated with the transaction.This\n     * specification does not define the format of this application specific\n     * data. This is the responsibility of the application.\n     *\n     * @return application data associated with the message by the application.\n     * @since v2.0\n     *\n     */\n    public Object getApplicationData();\n    \n    /**\n     * Get the multipart mime content from a message. Builds a wrapper around the\n     * content and breaks it into multiple sections. Returns these sections as\n     * a multipart mime content list. If the content type is not multipart mime\n     * then the list will have a single element in it. \n     * \n     * @since v2.0\n     * @param Message message\n     * @throws ParseException if the content type is multipart mime but the content\n     *  is not properly encoded.\n     *  \n     */\n    public MultipartMimeContent getMultipartMimeContent() throws ParseException;\n    \n    /**\n     * Get the topmost Via header.\n     * \n     * @since v2.0\n     */\n    public ViaHeader getTopmostViaHeader();\n    \n    /**\n     * Get the From header or null if none present.\n     * \n     * @since v2.0\n     */\n    public FromHeader getFromHeader();\n    \n    /**\n     * Get the To header or null if none present.\n     * \n     * @since v2.0\n     */\n    public ToHeader getToHeader();\n    \n    \n    /**\n     * Get the callId header or null if none present.\n     * \n     * @since v2.0\n     */\n    public CallIdHeader getCallIdHeader();\n    \n    /**\n     * Get the CSeq header or null if none present.\n     * \n     * @since v2.0\n     */\n    public  CSeqHeader getCSeqHeader();\n    \n    /**\n     * Get the content type header or null if none present.\n     * \n     * @since v2.0\n     */\n    public ContentTypeHeader getContentTypeHeader();\n    \n    /**\n     * Get the content length header or null if none present.\n     * \n     * @since v2.0\n     */\n    public ContentLengthHeader getContentLengthHeader();\n    \n    /**\n     * Get the first line of the request or response.\n     * \n     * @since v2.0\n     */\n    public String getFirstLine();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/MessageFactoryExt.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.ServerHeader;\nimport javax2.sip.header.UserAgentHeader;\nimport javax2.sip.message.MessageFactory;\n\n/**\n * Intefaces that will be supported by the next release of JAIN-SIP.\n *\n * @author mranga\n *\n */\npublic interface MessageFactoryExt extends MessageFactory {\n    /**\n     * Set the common UserAgent header for all Requests created from this message factory.\n     * This header is applied to all Messages created from this Factory object except those\n     * that take String for an argument and create Message from the given String.\n     *\n     * @param userAgent -- the user agent header to set.\n     *\n     */\n\n    public void setDefaultUserAgentHeader(UserAgentHeader userAgent);\n\n\n    /**\n     * Set the common Server header for all Responses created from this message factory.\n     * This header is applied to all Messages created from this Factory object except those\n     * that take String for an argument and create Message from the given String.\n     *\n     * @param userAgent -- the user agent header to set.\n     * \n     * @since 2.0\n     *\n     */\n\n    public void setDefaultServerHeader(ServerHeader userAgent);\n\n    /**\n     * Set default charset used for encoding String content. Note that this\n     * will be applied to all content that is encoded. The default is UTF-8.\n     * \n     * @since 2.0\n     *\n     * @param charset -- charset to set.\n     * @throws NullPointerException if null arg\n     * @throws IllegalArgumentException if Charset is not a known charset.\n     *\n     */\n    public  void setDefaultContentEncodingCharset(String charset)\n            throws NullPointerException,IllegalArgumentException ;\n    \n    /**\n     * Create a MultipartMime attachment from a list of content type, subtype and content.\n     * \n     * @since 2.0\n     * \n     * @throws NullPointerException, IllegalArgumentException\n     */\n    public MultipartMimeContent createMultipartMimeContent(ContentTypeHeader multipartMimeContentTypeHeader,\n            String[] contentType, \n            String[] contentSubtype, \n            String[] contentBody);\n    \n    \n    \n    \n    \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/MessageFactoryImpl.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\nimport java.text.ParseException;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport javax2.sip.address.*;\nimport javax2.sip.header.*;\nimport javax2.sip.message.*;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.parser.*;\n\n/**\n * Message Factory implementation\n *\n * @version 1.2 $Revision: 1.23 $ $Date: 2009/09/08 01:58:40 $\n * @since 1.1\n *\n * @author M. Ranganathan <br/>\n * @author Olivier Deruelle <br/>\n *\n */\n@SuppressWarnings(\"unchecked\")\npublic class MessageFactoryImpl implements MessageFactory, MessageFactoryExt {\n\n    private boolean testing = false;\n    \n    private boolean strict  = true;\n\n    private static String defaultContentEncodingCharset = \"UTF-8\";\n\n\n    /*\n     * The UserAgent header to include for all requests created from this message factory.\n     */\n    private static UserAgentHeader userAgent;\n\n    /*\n     * The Server header to include\n     */\n    private static ServerHeader server;\n    \n    \n    public void setStrict(boolean strict) {\n        this.strict = strict;\n    }\n\n\n\n    /**\n     * This is for testing -- allows you to generate invalid requests\n     */\n    public void setTest(boolean flag) {\n        this.testing = flag;\n    }\n\n    /**\n     * Creates a new instance of MessageFactoryImpl\n     */\n    public MessageFactoryImpl() {\n    }\n\n    /**\n     * Creates a new Request message of type specified by the method paramater,\n     * containing the URI of the Request, the mandatory headers of the message\n     * with a body in the form of a Java object and the body content type.\n     *\n     * @param requestURI -\n     *            the new URI object of the requestURI value of this Message.\n     * @param method -\n     *            the new string of the method value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @param content -\n     *            the new Object of the body content value of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the method or the body.\n     */\n    public Request createRequest(javax2.sip.address.URI requestURI,\n            String method, CallIdHeader callId, CSeqHeader cSeq,\n            FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            Object content) throws ParseException {\n        if (requestURI == null || method == null || callId == null\n                || cSeq == null || from == null || to == null || via == null\n                || maxForwards == null || content == null\n                || contentType == null)\n            throw new NullPointerException(\"Null parameters\");\n\n        SIPRequest sipRequest = new SIPRequest();\n        sipRequest.setRequestURI(requestURI);\n        sipRequest.setMethod(method);\n        sipRequest.setCallId(callId);\n        sipRequest.setCSeq(cSeq);\n        sipRequest.setFrom(from);\n        sipRequest.setTo(to);\n        sipRequest.setVia(via);\n        sipRequest.setMaxForwards(maxForwards);\n        sipRequest.setContent(content, contentType);\n        if ( userAgent != null ) {\n            sipRequest.setHeader(userAgent);\n        }\n\n        return sipRequest;\n    }\n\n    /**\n     * Creates a new Request message of type specified by the method paramater,\n     * containing the URI of the Request, the mandatory headers of the message\n     * with a body in the form of a byte array and body content type.\n     *\n     * @param requestURI -\n     *            the new URI object of the requestURI value of this Message.\n     * @param method -\n     *            the new string of the method value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @param content -\n     *            the new byte array of the body content value of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the method or the body.\n     */\n    public Request createRequest(URI requestURI, String method,\n            CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to,\n            List via, MaxForwardsHeader maxForwards, byte[] content,\n            ContentTypeHeader contentType) throws ParseException {\n        if (requestURI == null || method == null || callId == null\n                || cSeq == null || from == null || to == null || via == null\n                || maxForwards == null || content == null\n                || contentType == null)\n            throw new ParseException(\n                    \"JAIN-SIP Exception, some parameters are missing\"\n                            + \", unable to create the request\", 0);\n\n        SIPRequest sipRequest = new SIPRequest();\n        sipRequest.setRequestURI(requestURI);\n        sipRequest.setMethod(method);\n        sipRequest.setCallId(callId);\n        sipRequest.setCSeq(cSeq);\n        sipRequest.setFrom(from);\n        sipRequest.setTo(to);\n        sipRequest.setVia(via);\n        sipRequest.setMaxForwards(maxForwards);\n        sipRequest.setHeader((ContentType) contentType);\n        sipRequest.setMessageContent(content);\n        if ( userAgent != null ) {\n            sipRequest.setHeader(userAgent);\n        }\n        return sipRequest;\n    }\n\n    /**\n     * Creates a new Request message of type specified by the method paramater,\n     * containing the URI of the Request, the mandatory headers of the message.\n     * This new Request does not contain a body.\n     *\n     * @param requestURI -\n     *            the new URI object of the requestURI value of this Message.\n     * @param method -\n     *            the new string of the method value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the method.\n     */\n    public Request createRequest(URI requestURI, String method,\n            CallIdHeader callId, CSeqHeader cSeq, FromHeader from, ToHeader to,\n            List via, MaxForwardsHeader maxForwards) throws ParseException {\n        if (requestURI == null || method == null || callId == null\n                || cSeq == null || from == null || to == null || via == null\n                || maxForwards == null)\n            throw new ParseException(\n                    \"JAIN-SIP Exception, some parameters are missing\"\n                            + \", unable to create the request\", 0);\n\n        SIPRequest sipRequest = new SIPRequest();\n        sipRequest.setRequestURI(requestURI);\n        sipRequest.setMethod(method);\n        sipRequest.setCallId(callId);\n        sipRequest.setCSeq(cSeq);\n        sipRequest.setFrom(from);\n        sipRequest.setTo(to);\n        sipRequest.setVia(via);\n        sipRequest.setMaxForwards(maxForwards);\n        if (userAgent != null) {\n            sipRequest.setHeader(userAgent);\n        }\n\n        return sipRequest;\n    }\n\n    // Standard Response Creation methods\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, containing the mandatory headers of the message with a body in\n     * the form of a Java object and the body content type.\n     *\n     * @param statusCode -\n     *            the new integer of the statusCode value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @param content -\n     *            the new Object of the body content value of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode or the body.\n     */\n    public Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, Object content,\n            ContentTypeHeader contentType) throws ParseException {\n        if (callId == null || cSeq == null || from == null || to == null\n                || via == null || maxForwards == null || content == null\n                || contentType == null)\n            throw new NullPointerException(\" unable to create the response\");\n\n        SIPResponse sipResponse = new SIPResponse();\n        StatusLine statusLine = new StatusLine();\n        statusLine.setStatusCode(statusCode);\n        String reasonPhrase = SIPResponse.getReasonPhrase(statusCode);\n        //if (reasonPhrase == null)\n        //  throw new ParseException(statusCode + \" Unkown  \", 0);\n        statusLine.setReasonPhrase(reasonPhrase);\n        sipResponse.setStatusLine(statusLine);\n        sipResponse.setCallId(callId);\n        sipResponse.setCSeq(cSeq);\n        sipResponse.setFrom(from);\n        sipResponse.setTo(to);\n        sipResponse.setVia(via);\n        sipResponse.setMaxForwards(maxForwards);\n        sipResponse.setContent(content, contentType);\n        if (userAgent != null) {\n            sipResponse.setHeader(userAgent);\n        }\n        return sipResponse;\n    }\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, containing the mandatory headers of the message with a body in\n     * the form of a byte array and the body content type.\n     *\n     * @param statusCode -\n     *            the new integer of the statusCode value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @param content -\n     *            the new byte array of the body content value of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode or the body.\n     */\n    public Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, byte[] content,\n            ContentTypeHeader contentType) throws ParseException {\n        if (callId == null || cSeq == null || from == null || to == null\n                || via == null || maxForwards == null || content == null\n                || contentType == null)\n            throw new NullPointerException(\"Null params \");\n\n        SIPResponse sipResponse = new SIPResponse();\n        sipResponse.setStatusCode(statusCode);\n        sipResponse.setCallId(callId);\n        sipResponse.setCSeq(cSeq);\n        sipResponse.setFrom(from);\n        sipResponse.setTo(to);\n        sipResponse.setVia(via);\n        sipResponse.setMaxForwards(maxForwards);\n        sipResponse.setHeader((ContentType) contentType);\n        sipResponse.setMessageContent(content);\n        if (userAgent != null) {\n            sipResponse.setHeader(userAgent);\n        }\n        return sipResponse;\n    }\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, containing the mandatory headers of the message. This new\n     * Response does not contain a body.\n     *\n     * @param statusCode -\n     *            the new integer of the statusCode value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode.\n     */\n    public Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards) throws ParseException {\n        if (callId == null || cSeq == null || from == null || to == null\n                || via == null || maxForwards == null)\n            throw new ParseException(\n                    \"JAIN-SIP Exception, some parameters are missing\"\n                            + \", unable to create the response\", 0);\n\n        SIPResponse sipResponse = new SIPResponse();\n        sipResponse.setStatusCode(statusCode);\n        sipResponse.setCallId(callId);\n        sipResponse.setCSeq(cSeq);\n        sipResponse.setFrom(from);\n        sipResponse.setTo(to);\n        sipResponse.setVia(via);\n        sipResponse.setMaxForwards(maxForwards);\n        if (userAgent != null) {\n            sipResponse.setHeader(userAgent);\n        }\n        return sipResponse;\n    }\n\n    // Response Creation methods based on a Request\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, based on a specific Request with a new body in the form of a\n     * Java object and the body content type.\n     *\n     * @param statusCode -\n     *            the new integer of the statusCode value of this Message.\n     * @param request -\n     *            the received Reqest object upon which to base the Response.\n     * @param content -\n     *            the new Object of the body content value of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode or the body.\n     */\n    public Response createResponse(int statusCode, Request request,\n            ContentTypeHeader contentType, Object content)\n            throws ParseException {\n        if (request == null || content == null || contentType == null)\n            throw new NullPointerException(\"null parameters\");\n\n        SIPRequest sipRequest = (SIPRequest) request;\n        SIPResponse sipResponse = sipRequest.createResponse(statusCode);\n        sipResponse.setContent(content, contentType);\n        if (server != null) {\n            sipResponse.setHeader(server);\n        }\n        return sipResponse;\n    }\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, based on a specific Request with a new body in the form of a\n     * byte array and the body content type.\n     *\n     * @param statusCode -\n     *            the new integer of the statusCode value of this Message.\n     * @param request -\n     *            the received Reqest object upon which to base the Response.\n     * @param content -\n     *            the new byte array of the body content value of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode or the body.\n     */\n    public Response createResponse(int statusCode, Request request,\n            ContentTypeHeader contentType, byte[] content)\n            throws ParseException {\n        if (request == null || content == null || contentType == null)\n            throw new NullPointerException(\"null Parameters\");\n\n        SIPRequest sipRequest = (SIPRequest) request;\n        SIPResponse sipResponse = sipRequest.createResponse(statusCode);\n        sipResponse.setHeader((ContentType) contentType);\n        sipResponse.setMessageContent(content);\n        if (server != null) {\n            sipResponse.setHeader(server);\n        }\n        return sipResponse;\n    }\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, based on a specific Request message. This new Response does\n     * not contain a body.\n     *\n     * @param statusCode -\n     *            the new integer of the statusCode value of this Message.\n     * @param request -\n     *            the received Reqest object upon which to base the Response.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode.\n     */\n    public Response createResponse(int statusCode, Request request)\n            throws ParseException {\n        if (request == null)\n            throw new NullPointerException(\"null parameters\");\n\n        // if (LogWriter.needsLogging)\n        // LogWriter.logMessage(\"createResponse \" + request);\n\n        SIPRequest sipRequest = (SIPRequest) request;\n        SIPResponse sipResponse = sipRequest.createResponse(statusCode);\n        // Remove the content from the message (Bug report from\n        // Antonis Karydas.\n        sipResponse.removeContent();\n        sipResponse.removeHeader(ContentTypeHeader.NAME);\n        if (server != null) {\n            sipResponse.setHeader(server);\n        }\n        return sipResponse;\n    }\n\n    /**\n     * Creates a new Request message of type specified by the method paramater,\n     * containing the URI of the Request, the mandatory headers of the message\n     * with a body in the form of a byte array and body content type.\n     *\n     * @param requestURI -\n     *            the new URI object of the requestURI value of this Message.\n     * @param method -\n     *            the new string of the method value of this Message.\n     * @param callId -\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq -\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from -\n     *            the new FromHeader object of the from value of this Message.\n     * @param to -\n     *            the new ToHeader object of the to value of this Message.\n     * @param via -\n     *            the new List object of the ViaHeaders of this Message.\n     * @param contentType -\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @param content -\n     *            the new byte array of the body content value of this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the method or the body.\n     */\n    public Request createRequest(javax2.sip.address.URI requestURI,\n            String method, CallIdHeader callId, CSeqHeader cSeq,\n            FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            byte[] content) throws ParseException {\n        if (requestURI == null || method == null || callId == null\n                || cSeq == null || from == null || to == null || via == null\n                || maxForwards == null || content == null\n                || contentType == null)\n            throw new NullPointerException(\"missing parameters\");\n\n        SIPRequest sipRequest = new SIPRequest();\n        sipRequest.setRequestURI(requestURI);\n        sipRequest.setMethod(method);\n        sipRequest.setCallId(callId);\n        sipRequest.setCSeq(cSeq);\n        sipRequest.setFrom(from);\n        sipRequest.setTo(to);\n        sipRequest.setVia(via);\n        sipRequest.setMaxForwards(maxForwards);\n        sipRequest.setContent(content, contentType);\n        if (userAgent != null) {\n            sipRequest.setHeader(userAgent);\n        }\n        return sipRequest;\n    }\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, containing the mandatory headers of the message with a body in\n     * the form of a Java object and the body content type.\n     *\n     * @param statusCode\n     *            the new integer of the statusCode value of this Message.\n     * @param callId\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from\n     *            the new FromHeader object of the from value of this Message.\n     * @param to\n     *            the new ToHeader object of the to value of this Message.\n     * @param via\n     *            the new List object of the ViaHeaders of this Message.\n     * @param contentType\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @param content\n     *            the new Object of the body content value of this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode or the body.\n     */\n    public Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            Object content) throws ParseException {\n        if (callId == null || cSeq == null || from == null || to == null\n                || via == null || maxForwards == null || content == null\n                || contentType == null)\n            throw new NullPointerException(\"missing parameters\");\n        SIPResponse sipResponse = new SIPResponse();\n        StatusLine statusLine = new StatusLine();\n        statusLine.setStatusCode(statusCode);\n        String reason = SIPResponse.getReasonPhrase(statusCode);\n        if (reason == null)\n            throw new ParseException(statusCode + \" Unknown\", 0);\n        statusLine.setReasonPhrase(reason);\n        sipResponse.setStatusLine(statusLine);\n        sipResponse.setCallId(callId);\n        sipResponse.setCSeq(cSeq);\n        sipResponse.setFrom(from);\n        sipResponse.setTo(to);\n        sipResponse.setVia(via);\n        sipResponse.setContent(content, contentType);\n        if ( userAgent != null) {\n            sipResponse.setHeader(userAgent);\n        }\n        return sipResponse;\n\n    }\n\n    /**\n     * Creates a new Response message of type specified by the statusCode\n     * paramater, containing the mandatory headers of the message with a body in\n     * the form of a byte array and the body content type.\n     *\n     * @param statusCode\n     *            the new integer of the statusCode value of this Message.\n     * @param callId\n     *            the new CallIdHeader object of the callId value of this\n     *            Message.\n     * @param cSeq\n     *            the new CSeqHeader object of the cSeq value of this Message.\n     * @param from\n     *            the new FromHeader object of the from value of this Message.\n     * @param to\n     *            the new ToHeader object of the to value of this Message.\n     * @param via\n     *            the new List object of the ViaHeaders of this Message.\n     * @param contentType\n     *            the new ContentTypeHeader object of the content type value of\n     *            this Message.\n     * @param content\n     *            the new byte array of the body content value of this Message.\n     * @throws ParseException\n     *             which signals that an error has been reached unexpectedly\n     *             while parsing the statusCode or the body.\n     */\n    public Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            byte[] content) throws ParseException {\n        if (callId == null || cSeq == null || from == null || to == null\n                || via == null || maxForwards == null || content == null\n                || contentType == null)\n            throw new NullPointerException(\"missing parameters\");\n        SIPResponse sipResponse = new SIPResponse();\n        StatusLine statusLine = new StatusLine();\n        statusLine.setStatusCode(statusCode);\n        String reason = SIPResponse.getReasonPhrase(statusCode);\n        if (reason == null)\n            throw new ParseException(statusCode + \" : Unknown\", 0);\n        statusLine.setReasonPhrase(reason);\n        sipResponse.setStatusLine(statusLine);\n        sipResponse.setCallId(callId);\n        sipResponse.setCSeq(cSeq);\n        sipResponse.setFrom(from);\n        sipResponse.setTo(to);\n        sipResponse.setVia(via);\n        sipResponse.setContent(content, contentType);\n        if ( userAgent != null) {\n            sipResponse.setHeader(userAgent);\n        }\n        return sipResponse;\n    }\n\n    /**\n     * Create a request from a string. Conveniance method for UACs that want to\n     * create an outgoing request from a string. Only the headers of the request\n     * should be included in the String that is supplied to this method.\n     *\n     * @param requestString --\n     *            string from which to create the message null string returns an\n     *            empty message.\n     */\n    public javax2.sip.message.Request createRequest(String requestString)\n            throws java.text.ParseException {\n        if (requestString == null || requestString.equals(\"\")) {\n            SIPRequest retval = new SIPRequest();\n            retval.setNullRequest();\n            return retval;\n        }\n\n        StringMsgParser smp = new StringMsgParser();\n        smp.setStrict(this.strict);\n\n        /*\n         * This allows you to catch parse exceptions and create invalid messages\n         * if you want.\n         */\n        ParseExceptionListener parseExceptionListener = new ParseExceptionListener() {\n\n            public void handleException(ParseException ex,\n                    SIPMessage sipMessage, Class headerClass,\n                    String headerText, String messageText)\n                    throws ParseException {\n                // Rethrow the error for the essential headers. Otherwise bad\n                // headers are simply\n                // recorded in the message.\n                if (testing) {\n                    if (headerClass == From.class || headerClass == To.class\n                            || headerClass == CallID.class\n                            || headerClass == MaxForwards.class\n                            || headerClass == Via.class\n                            || headerClass == RequestLine.class\n                            || headerClass == StatusLine.class\n                            || headerClass == CSeq.class)\n                        throw ex;\n\n                    sipMessage.addUnparsed(headerText);\n                }\n\n            }\n\n        };\n\n        if (this.testing)\n            smp.setParseExceptionListener(parseExceptionListener);\n\n        SIPMessage sipMessage = smp.parseSIPMessage(requestString);\n\n        if (!(sipMessage instanceof SIPRequest))\n            throw new ParseException(requestString, 0);\n\n        return (SIPRequest) sipMessage;\n    }\n\n    /**\n     * Create a response from a string\n     *\n     * @param responseString --\n     *            string from which to create the message null string returns an\n     *            empty message.\n     *\n     */\n    public Response createResponse(String responseString)\n            throws java.text.ParseException {\n        if (responseString == null)\n            return new SIPResponse();\n\n        StringMsgParser smp = new StringMsgParser();\n\n        SIPMessage sipMessage = smp.parseSIPMessage(responseString);\n\n        if (!(sipMessage instanceof SIPResponse))\n            throw new ParseException(responseString, 0);\n\n        return (SIPResponse) sipMessage;\n    }\n\n    /**\n     * Set the common UserAgent header for all requests created from this message factory.\n     * This header is applied to all Messages created from this Factory object except those\n     * that take String for an argument and create Message from the given String.\n     *\n     * @param userAgent -- the user agent header to set.\n     *\n     * @since 2.0\n     */\n\n    public void setDefaultUserAgentHeader(UserAgentHeader userAgent) {\n        MessageFactoryImpl.userAgent = userAgent;\n    }\n\n    /**\n     * Set the common Server header for all responses created from this message factory.\n     * This header is applied to all Messages created from this Factory object except those\n     * that take String for an argument and create Message from the given String.\n     *\n     * @param userAgent -- the user agent header to set.\n     *\n     * @since 2.0\n     */\n\n    public void setDefaultServerHeader(ServerHeader server) {\n        MessageFactoryImpl.server = server;\n    }\n    /**\n     * Get the default common UserAgentHeader.\n     *\n     * @return the user agent header.\n     *\n     * @since 2.0\n     */\n    public static UserAgentHeader getDefaultUserAgentHeader() {\n        return userAgent;\n    }\n\n\n    /**\n     * Get the default common server header.\n     *\n     * @return the server header.\n     */\n    public static ServerHeader getDefaultServerHeader() {\n        return server;\n    }\n\n\n    /**\n     * Set default charset used for encoding String content.\n     * @param charset\n     */\n    public  void setDefaultContentEncodingCharset(String charset) throws NullPointerException,\n    IllegalArgumentException {\n        if (charset == null ) throw new NullPointerException (\"Null argument!\");\n        MessageFactoryImpl.defaultContentEncodingCharset = charset;\n\n    }\n\n    public static String getDefaultContentEncodingCharset() {\n        return MessageFactoryImpl.defaultContentEncodingCharset;\n    }\n\n    \n    public MultipartMimeContent createMultipartMimeContent(ContentTypeHeader multipartMimeCth,\n            String[] contentType,\n            String[] contentSubtype, \n            String[] contentBody) {\n        String boundary = multipartMimeCth.getParameter(\"boundary\");\n        MultipartMimeContentImpl retval = new MultipartMimeContentImpl(multipartMimeCth);\n        for (int i = 0 ;  i < contentType.length; i++ ) {\n            ContentTypeHeader cth = new ContentType(contentType[i],contentSubtype[i]);\n            ContentImpl contentImpl  = new ContentImpl(contentBody[i],boundary);\n            contentImpl.setContentTypeHeader(cth);\n            retval.add(contentImpl);\n        }\n        return retval;\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/MessageObject.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)        *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\nimport gov2.nist.core.*;\n\nimport java.lang.reflect.*;\n\n/**\n * This is the root object from which all other objects in this package\n * are derived. This class is never directly instantiated (and hence it\n * is abstract).\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:54 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic abstract class MessageObject extends GenericObject {\n    public abstract String encode();\n\n    public void dbgPrint() {\n        super.dbgPrint();\n    }\n\n    /**\n     * An introspection based string formatting method. We need this because\n     * in this package (although it is an exact duplicate of the one in\n     * the superclass) because it needs to access the protected members\n     * of the other objects in this class.\n     */\n    public String debugDump() {\n        stringRepresentation = \"\";\n        Class<?> myclass = getClass();\n        sprint(myclass.getName());\n        sprint(\"{\");\n        Field[] fields = myclass.getDeclaredFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field f = fields[i];\n            // Only print protected and public members.\n            int modifier = f.getModifiers();\n            if (modifier == Modifier.PRIVATE)\n                continue;\n            Class<?> fieldType = f.getType();\n            String fieldName = f.getName();\n            if (fieldName.compareTo(\"stringRepresentation\") == 0) {\n                // avoid nasty recursions...\n                continue;\n            }\n            if (fieldName.compareTo(\"indentation\") == 0) {\n                // formatting stuff - not relevant here.\n                continue;\n            }\n            sprint(fieldName + \":\");\n            try {\n                // Primitive fields are printed with type: value\n                if (fieldType.isPrimitive()) {\n                    String fname = fieldType.toString();\n                    sprint(fname + \":\");\n                    if (fname.compareTo(\"int\") == 0) {\n                        int intfield = f.getInt(this);\n                        sprint(intfield);\n                    } else if (fname.compareTo(\"short\") == 0) {\n                        short shortField = f.getShort(this);\n                        sprint(shortField);\n                    } else if (fname.compareTo(\"char\") == 0) {\n                        char charField = f.getChar(this);\n                        sprint(charField);\n                    } else if (fname.compareTo(\"long\") == 0) {\n                        long longField = f.getLong(this);\n                        sprint(longField);\n                    } else if (fname.compareTo(\"boolean\") == 0) {\n                        boolean booleanField = f.getBoolean(this);\n                        sprint(booleanField);\n                    } else if (fname.compareTo(\"double\") == 0) {\n                        double doubleField = f.getDouble(this);\n                        sprint(doubleField);\n                    } else if (fname.compareTo(\"float\") == 0) {\n                        float floatField = f.getFloat(this);\n                        sprint(floatField);\n                    }\n                } else if (\n                    GenericObject.class.isAssignableFrom(\n                        fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObject) f.get(this)).debugDump(\n                                this.indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else if (GenericObjectList.class.isAssignableFrom(\n                        fieldType)) {\n                    if (f.get(this) != null) {\n                        sprint(\n                            ((GenericObjectList) f.get(this)).debugDump(\n                                indentation + 1));\n                    } else {\n                        sprint(\"<null>\");\n                    }\n\n                } else {\n                    // Dont do recursion on things that are not\n                    // of our header type...\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).getClass().getName() + \":\");\n                    } else {\n                        sprint(fieldType.getName() + \":\");\n                    }\n\n                    sprint(\"{\");\n                    if (f.get(this) != null) {\n                        sprint(f.get(this).toString());\n                    } else {\n                        sprint(\"<null>\");\n                    }\n                    sprint(\"}\");\n                }\n            } catch (IllegalAccessException ex1) {\n                continue; // we are accessing a private field...\n            }\n        }\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n\n    protected MessageObject() {\n        super();\n    }\n\n    /**\n     * Formatter with a given starting indentation (for nested structs).\n     */\n    public String dbgPrint(int indent) {\n        int save = indentation;\n        indentation = indent;\n        String retval = this.toString();\n        indentation = save;\n        return retval;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/MultipartMimeContent.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport java.util.Iterator;\nimport java.util.List;\n\nimport javax2.sip.header.ContentTypeHeader;\n\npublic interface MultipartMimeContent {\n\n    public abstract boolean add(Content content);\n\n    /**\n     * Return the Content type header to assign to the outgoing sip meassage.\n     * \n     * @return\n     */\n    public abstract ContentTypeHeader getContentTypeHeader();\n\n    public abstract String toString();\n\n    /**\n     * Set the content by its type.\n     * \n     * @param content\n     */\n    public abstract void addContent( Content content);\n    \n    /**\n     * Retrieve the list of Content that is part of this MultitypeMime content.\n     * \n     * @return - the content iterator. Returns an empty iterator if no content list present.\n     */\n    public Iterator<Content> getContents();\n    \n    /**\n     * Get the number of Content parts.\n     * \n     * @return - the content parts.\n     */\n    public int getContentCount();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/MultipartMimeContentImpl.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport gov2.nist.javax2.sip.header.HeaderFactoryExt;\nimport gov2.nist.javax2.sip.header.HeaderFactoryImpl;\nimport gov2.nist.javax2.sip.parser.StringMsgParser;\n\nimport java.text.ParseException;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.HeaderFactory;\nimport javax2.sip.message.Message;\n\n\n\n/**\n * Content list for multipart mime content type.\n * \n * @author M. Ranganathan\n * \n */\npublic class MultipartMimeContentImpl implements MultipartMimeContent {\n    private List<Content> contentList = new LinkedList<Content>();\n\n    private ContentTypeHeader multipartMimeContentTypeHeader;\n\n    private String boundary;\n\n    public static String BOUNDARY = \"boundary\";\n\n    /**\n     * Creates a default content list.\n     */\n    public MultipartMimeContentImpl(ContentTypeHeader contentTypeHeader) {\n        this.multipartMimeContentTypeHeader = contentTypeHeader;\n        this.boundary = contentTypeHeader.getParameter(BOUNDARY);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.message.MultipartMimeContentExt#add(gov2.nist.javax2.sip.message.Content)\n     */\n    public boolean add(Content content) {\n        return contentList.add((ContentImpl) content);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.message.MultipartMimeContentExt#getContentTypeHeader()\n     */\n    public ContentTypeHeader getContentTypeHeader() {\n        return multipartMimeContentTypeHeader;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.message.MultipartMimeContentExt#toString()\n     */\n    @Override\n    public String toString() {\n        StringBuffer stringBuffer = new StringBuffer();\n\n        for (Content content : this.contentList) {\n            stringBuffer.append(content.toString());\n        }\n        return stringBuffer.toString();\n\n    }\n\n    /**\n     * unpack a multipart mime packet and return a list of content packets.\n     * \n     * @return -- an iterator of Content blocks.\n     * \n     */\n    public void createContentList(String body) throws ParseException {\n        try {\n            HeaderFactoryExt headerFactory = new HeaderFactoryImpl();\n            String delimiter = this.getContentTypeHeader().getParameter(BOUNDARY);\n\n            if (delimiter == null) {\n                this.contentList = new LinkedList<Content>();\n                ContentImpl content = new ContentImpl(body, delimiter);\n                content.setContentTypeHeader(this.getContentTypeHeader());\n                this.contentList.add(content);\n                return;\n            }\n\n            String[] fragments = body.split(\"--\" + delimiter + \"\\r\\n\");\n\n\n            for (String nextPart : fragments) {\n                // NOTE - we are not hanlding line folding for the sip header here.\n\n                if (nextPart == null) {\n                    return;\n                }\n                StringBuffer strbuf = new StringBuffer(nextPart);\n                while (strbuf.length() > 0\n                        && (strbuf.charAt(0) == '\\r' || strbuf.charAt(0) == '\\n'))\n                    strbuf.deleteCharAt(0);\n\n                if (strbuf.length() == 0)\n                    continue;\n                nextPart = strbuf.toString();\n                int position = nextPart.indexOf(\"\\r\\n\\r\\n\");\n                int off = 4;\n                if (position == -1) {\n                    position = nextPart.indexOf(\"\\n\");\n                    off = 2;\n                }\n                if (position == -1)\n                    throw new ParseException(\"no content type header found in \" + nextPart, 0);\n                String rest = nextPart.substring(position + off);\n\n                if (rest == null)\n                    throw new ParseException(\"No content [\" + nextPart + \"]\", 0);\n                // logger.debug(\"rest = [[\" + rest + \"]]\");\n                String headers = nextPart.substring(0, position);\n                ContentImpl content = new ContentImpl(rest, boundary);\n\n                String[] headerArray = headers.split(\"\\r\\n\");\n                for (String hdr : headerArray) {\n                    Header header = headerFactory.createHeader(hdr);\n                    if (header instanceof ContentTypeHeader) {\n                        content.setContentTypeHeader((ContentTypeHeader) header);\n                    } else if (header instanceof ContentDispositionHeader) {\n                        content.setContentDispositionHeader((ContentDispositionHeader) header);\n                    } else {\n                        throw new ParseException(\"Unexpected header type \" + header.getName(), 0);\n                    }\n                    contentList.add(content);\n                }\n\n            }\n        } catch (StringIndexOutOfBoundsException ex) {\n            throw new ParseException(\"Invalid Multipart mime format\", 0);\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.message.MultipartMimeContentExt#getContentByType(java.lang.String,\n     *      java.lang.String)\n     */\n    public Content getContentByType(String contentType, String contentSubtype) {\n        Content retval = null;\n        if (contentList == null)\n            return null;\n        for (Content content : contentList) {\n            if (content.getContentTypeHeader().getContentType().equalsIgnoreCase(contentType)\n                    && content.getContentTypeHeader().getContentSubType().equalsIgnoreCase(\n                            contentSubtype)) {\n                retval = content;\n                break;\n            }\n\n        }\n        return retval;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.message.MultipartMimeContentExt#setContent(java.lang.String,\n     *      java.lang.String, gov2.nist.javax2.sip.message.Content)\n     */\n    public void addContent(Content content) {\n        this.add(content);\n    }\n\n    public Iterator<Content> getContents() {\n        return this.contentList.iterator();\n    }\n\n    \n    public int getContentCount() {\n        return this.contentList.size();\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/RequestExt.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport javax2.sip.message.Request;\n\n/**\n * Extensions for the JAIN-SIP Request interface.\n */\npublic interface RequestExt extends Request, MessageExt {\n\t\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/ResponseExt.java",
    "content": "package gov2.nist.javax2.sip.message;\n\nimport javax2.sip.message.Response;\n\n/**\n *Extension for the jain-sip Response interface. This is a convenience \n *interface (placeholder).\n */\npublic interface ResponseExt extends Response, MessageExt {\n\t\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/SIPDuplicateHeaderException.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Duplicate header exception:  thrown when there is more\n * than one header of a type where there should only be one.\n * The exception handler may choose to :\n * 1. discard the duplicate  by returning null\n * 2. keep the duplicate by just returning it.\n * 3. Discard the entire message by throwing an exception.\n * @version 1.2 $Revision: 1.6 $ $Date: 2009/07/17 18:57:54 $\n * @since 1.1\n * @author M. Ranganathan\n */\npublic class SIPDuplicateHeaderException extends ParseException {\n\n    private static final long serialVersionUID = 8241107266407879291L;\n    protected SIPHeader sipHeader;\n    protected SIPMessage sipMessage;\n    public SIPDuplicateHeaderException(String msg) {\n        super(msg, 0);\n    }\n    public SIPMessage getSIPMessage() {\n        return sipMessage;\n    }\n\n    public SIPHeader getSIPHeader() {\n        return sipHeader;\n    }\n\n    public void setSIPHeader(SIPHeader sipHeader) {\n        this.sipHeader = sipHeader;\n    }\n\n    public void setSIPMessage(SIPMessage sipMessage) {\n        this.sipMessage = sipMessage;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/SIPMessage.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)        *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.Utils;\nimport gov2.nist.javax2.sip.header.AlertInfo;\nimport gov2.nist.javax2.sip.header.Authorization;\nimport gov2.nist.javax2.sip.header.CSeq;\nimport gov2.nist.javax2.sip.header.CallID;\nimport gov2.nist.javax2.sip.header.Contact;\nimport gov2.nist.javax2.sip.header.ContactList;\nimport gov2.nist.javax2.sip.header.ContentLength;\nimport gov2.nist.javax2.sip.header.ContentType;\nimport gov2.nist.javax2.sip.header.ErrorInfo;\nimport gov2.nist.javax2.sip.header.ErrorInfoList;\nimport gov2.nist.javax2.sip.header.From;\nimport gov2.nist.javax2.sip.header.InReplyTo;\nimport gov2.nist.javax2.sip.header.MaxForwards;\nimport gov2.nist.javax2.sip.header.Priority;\nimport gov2.nist.javax2.sip.header.ProxyAuthenticate;\nimport gov2.nist.javax2.sip.header.ProxyAuthorization;\nimport gov2.nist.javax2.sip.header.ProxyRequire;\nimport gov2.nist.javax2.sip.header.ProxyRequireList;\nimport gov2.nist.javax2.sip.header.RSeq;\nimport gov2.nist.javax2.sip.header.RecordRouteList;\nimport gov2.nist.javax2.sip.header.RetryAfter;\nimport gov2.nist.javax2.sip.header.Route;\nimport gov2.nist.javax2.sip.header.RouteList;\nimport gov2.nist.javax2.sip.header.SIPETag;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\nimport gov2.nist.javax2.sip.header.SIPHeaderNamesCache;\nimport gov2.nist.javax2.sip.header.SIPIfMatch;\nimport gov2.nist.javax2.sip.header.Server;\nimport gov2.nist.javax2.sip.header.Subject;\nimport gov2.nist.javax2.sip.header.To;\nimport gov2.nist.javax2.sip.header.Unsupported;\nimport gov2.nist.javax2.sip.header.UserAgent;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.header.WWWAuthenticate;\nimport gov2.nist.javax2.sip.header.Warning;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.ParserFactory;\nimport gov2.nist.javax2.sip.parser.PipelinedMsgParser;\nimport gov2.nist.javax2.sip.parser.StringMsgParser;\n\nimport java.io.UnsupportedEncodingException;\nimport java.lang.reflect.Field;\nimport java.text.ParseException;\nimport java.util.Collection;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.SipException;\nimport javax2.sip.header.AuthorizationHeader;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentEncodingHeader;\nimport javax2.sip.header.ContentLanguageHeader;\nimport javax2.sip.header.ContentLengthHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.Header;\nimport javax2.sip.header.MaxForwardsHeader;\nimport javax2.sip.header.RecordRouteHeader;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.ToHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.message.Request;\n\n/*\n * Acknowledgements: Yanick Belanger sent in a patch for the right content length when the content\n * is a String. Bill Mccormick from Nortel Networks sent in a bug fix for setContent.\n * \n */\n/**\n * This is the main SIP Message structure.\n * \n * @see StringMsgParser\n * @see PipelinedMsgParser\n * \n * @version 1.2 $Revision: 1.53 $ $Date: 2009/12/16 14:58:40 $\n * @since 1.1\n * \n * @author M. Ranganathan <br/>\n * \n * \n */\npublic abstract class SIPMessage extends MessageObject implements javax2.sip.message.Message,\n        MessageExt {\n\n\t// JvB: use static here?\n    private String contentEncodingCharset = MessageFactoryImpl.getDefaultContentEncodingCharset();\n    \n    /*\n     * True if this is a null request.\n     */\n    protected boolean nullRequest;\n    \n    /**\n     * unparsed headers\n     */\n    protected LinkedList<String> unrecognizedHeaders;\n\n    /**\n     * List of parsed headers (in the order they were added)\n     */\n    protected ConcurrentLinkedQueue<SIPHeader> headers;\n\n    /**\n     * Direct accessors for frequently accessed headers\n     */\n    protected From fromHeader;\n\n    protected To toHeader;\n\n    protected CSeq cSeqHeader;\n\n    protected CallID callIdHeader;\n\n    protected ContentLength contentLengthHeader;\n\n    protected MaxForwards maxForwardsHeader;\n\n    // Cumulative size of all the headers.\n    protected int size;\n\n    // Payload\n    private String messageContent;\n\n    private byte[] messageContentBytes;\n\n    private Object messageContentObject;\n\n    // Table of headers indexed by name.\n    private Hashtable<String, SIPHeader> nameTable;\n\n    /**\n     * The application data pointer. This is un-interpreted by the stack. This is provided as a\n     * convenient way of keeping book-keeping data for applications.\n     */\n    protected Object applicationData;\n\n    /**\n     * Return true if the header belongs only in a Request.\n     * \n     * @param sipHeader is the header to test.\n     */\n    public static boolean isRequestHeader(SIPHeader sipHeader) {\n        return sipHeader instanceof AlertInfo || sipHeader instanceof InReplyTo\n                || sipHeader instanceof Authorization || sipHeader instanceof MaxForwards\n                || sipHeader instanceof UserAgent || sipHeader instanceof Priority\n                || sipHeader instanceof ProxyAuthorization || sipHeader instanceof ProxyRequire\n                || sipHeader instanceof ProxyRequireList || sipHeader instanceof Route\n                || sipHeader instanceof RouteList || sipHeader instanceof Subject\n                || sipHeader instanceof SIPIfMatch;\n    }\n\n    /**\n     * Return true if the header belongs only in a response.\n     * \n     * @param sipHeader is the header to test.\n     */\n    public static boolean isResponseHeader(SIPHeader sipHeader) {\n        return sipHeader instanceof ErrorInfo || sipHeader instanceof ProxyAuthenticate\n                || sipHeader instanceof Server || sipHeader instanceof Unsupported\n                || sipHeader instanceof RetryAfter || sipHeader instanceof Warning\n                || sipHeader instanceof WWWAuthenticate || sipHeader instanceof SIPETag\n                || sipHeader instanceof RSeq;\n\n    }\n\n    /**\n     * Get the headers as a linked list of encoded Strings\n     * \n     * @return a linked list with each element of the list containing a string encoded header in\n     *         canonical form.\n     */\n    public LinkedList<String> getMessageAsEncodedStrings() {\n        LinkedList<String> retval = new LinkedList<String>();\n        Iterator<SIPHeader> li = headers.iterator();\n        while (li.hasNext()) {\n            SIPHeader sipHeader = (SIPHeader) li.next();\n            if (sipHeader instanceof SIPHeaderList) {\n                SIPHeaderList< ? > shl = (SIPHeaderList< ? >) sipHeader;\n                retval.addAll(shl.getHeadersAsEncodedStrings());\n            } else {\n                retval.add(sipHeader.encode());\n            }\n        }\n\n        return retval;\n    }\n\n    /**\n     * Encode only the message and exclude the contents (for debugging);\n     * \n     * @return a string with all the headers encoded.\n     */\n    protected String encodeSIPHeaders() {\n        StringBuffer encoding = new StringBuffer();\n        Iterator<SIPHeader> it = this.headers.iterator();\n\n        while (it.hasNext()) {\n            SIPHeader siphdr = (SIPHeader) it.next();\n            if (!(siphdr instanceof ContentLength))\n                siphdr.encode(encoding);\n        }\n\n        return contentLengthHeader.encode(encoding).append(NEWLINE).toString();\n    }\n\n    /**\n     * Encode all the headers except the contents. For debug logging.\n     */\n    public abstract String encodeMessage();\n\n    /**\n     * Get A dialog identifier constructed from this messsage. This is an id that can be used to\n     * identify dialogs.\n     * \n     * @param isServerTransaction is a flag that indicates whether this is a server transaction.\n     */\n    public abstract String getDialogId(boolean isServerTransaction);\n\n    /**\n     * Template match for SIP messages. The matchObj is a SIPMessage template to match against.\n     * This method allows you to do pattern matching with incoming SIP messages. Null matches wild\n     * card.\n     * \n     * @param other is the match template to match against.\n     * @return true if a match occured and false otherwise.\n     */\n    public boolean match(Object other) {\n        if (other == null)\n            return true;\n        if (!other.getClass().equals(this.getClass()))\n            return false;\n        SIPMessage matchObj = (SIPMessage) other;\n        Iterator<SIPHeader> li = matchObj.getHeaders();\n        while (li.hasNext()) {\n            SIPHeader hisHeaders = (SIPHeader) li.next();\n            List<SIPHeader> myHeaders = this.getHeaderList(hisHeaders.getHeaderName());\n\n            // Could not find a header to match his header.\n            if (myHeaders == null || myHeaders.size() == 0)\n                return false;\n\n            if (hisHeaders instanceof SIPHeaderList) {\n                ListIterator< ? > outerIterator = ((SIPHeaderList< ? >) hisHeaders)\n                        .listIterator();\n                while (outerIterator.hasNext()) {\n                    SIPHeader hisHeader = (SIPHeader) outerIterator.next();\n                    if (hisHeader instanceof ContentLength)\n                        continue;\n                    ListIterator< ? > innerIterator = myHeaders.listIterator();\n                    boolean found = false;\n                    while (innerIterator.hasNext()) {\n                        SIPHeader myHeader = (SIPHeader) innerIterator.next();\n                        if (myHeader.match(hisHeader)) {\n                            found = true;\n                            break;\n                        }\n                    }\n                    if (!found)\n                        return false;\n                }\n            } else {\n                SIPHeader hisHeader = hisHeaders;\n                ListIterator<SIPHeader> innerIterator = myHeaders.listIterator();\n                boolean found = false;\n                while (innerIterator.hasNext()) {\n                    SIPHeader myHeader = (SIPHeader) innerIterator.next();\n                    if (myHeader.match(hisHeader)) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found)\n                    return false;\n            }\n        }\n        return true;\n\n    }\n\n    /**\n     * Merge a request with a template\n     * \n     * @param template -- template to merge with.\n     * \n     */\n    public void merge(Object template) {\n        if (!template.getClass().equals(this.getClass()))\n            throw new IllegalArgumentException(\"Bad class \" + template.getClass());\n        SIPMessage templateMessage = (SIPMessage) template;\n        Object[] templateHeaders = templateMessage.headers.toArray();\n        for (int i = 0; i < templateHeaders.length; i++) {\n            SIPHeader hdr = (SIPHeader) templateHeaders[i];\n            String hdrName = hdr.getHeaderName();\n            List<SIPHeader> myHdrs = this.getHeaderList(hdrName);\n            if (myHdrs == null) {\n                this.attachHeader(hdr);\n            } else {\n                ListIterator<SIPHeader> it = myHdrs.listIterator();\n                while (it.hasNext()) {\n                    SIPHeader sipHdr = (SIPHeader) it.next();\n                    sipHdr.merge(hdr);\n                }\n            }\n        }\n\n    }\n\n    /**\n     * Encode this message as a string. This is more efficient when the payload is a string\n     * (rather than a binary array of bytes). If the payload cannot be encoded as a UTF-8 string\n     * then it is simply ignored (will not appear in the encoded message).\n     * \n     * @return The Canonical String representation of the message (including the canonical string\n     *         representation of the SDP payload if it exists).\n     */\n    public String encode() {\n        StringBuffer encoding = new StringBuffer();\n        Iterator<SIPHeader> it = this.headers.iterator();\n\n        while (it.hasNext()) {\n            SIPHeader siphdr = (SIPHeader) it.next();\n            if (!(siphdr instanceof ContentLength))\n                encoding.append(siphdr.encode());\n        }\n        // Append the unrecognized headers. Headers that are not\n        // recognized are passed through unchanged.\n        for (String unrecognized : this.unrecognizedHeaders) {\n            encoding.append(unrecognized).append(NEWLINE);\n        }\n\n        encoding.append(contentLengthHeader.encode()).append(NEWLINE);\n\n        if (this.messageContentObject != null) {\n            String mbody = this.getContent().toString();\n\n            encoding.append(mbody);\n        } else if (this.messageContent != null || this.messageContentBytes != null) {\n\n            String content = null;\n            try {\n                if (messageContent != null)\n                    content = messageContent;\n                else {\n                \t// JvB: Check for 'charset' parameter which overrides the default UTF-8\n                    content = new String(messageContentBytes, getCharset() );\n                }\n            } catch (UnsupportedEncodingException ex) {\n            \tInternalErrorHandler.handleException(ex);\n            }\n\n            encoding.append(content);\n        }\n        return encoding.toString();\n    }\n\n    /**\n     * Encode the message as a byte array. Use this when the message payload is a binary byte\n     * array.\n     * \n     * @return The Canonical byte array representation of the message (including the canonical\n     *         byte array representation of the SDP payload if it exists all in one contiguous\n     *         byte array).\n     */\n    public byte[] encodeAsBytes(String transport) {\n        if (this instanceof SIPRequest && ((SIPRequest) this).isNullRequest()) {\n            return \"\\r\\n\\r\\n\".getBytes();\n        }\n        // JvB: added to fix case where application provides the wrong transport\n        // in the topmost Via header\n        ViaHeader topVia = (ViaHeader) this.getHeader(ViaHeader.NAME);\n        try {\n            topVia.setTransport(transport);\n        } catch (ParseException e) {\n            InternalErrorHandler.handleException(e);\n        }\n\n        StringBuffer encoding = new StringBuffer();\n        synchronized (this.headers) {\n            Iterator<SIPHeader> it = this.headers.iterator();\n\n            while (it.hasNext()) {\n                SIPHeader siphdr = (SIPHeader) it.next();\n                if (!(siphdr instanceof ContentLength))\n                    siphdr.encode(encoding);\n\n            }\n        }\n        contentLengthHeader.encode(encoding);\n        encoding.append(NEWLINE);\n\n        byte[] retval = null;\n        byte[] content = this.getRawContent();\n        if (content != null) {\n            // Append the content\n\n            byte[] msgarray = null;\n            try {\n                msgarray = encoding.toString().getBytes( getCharset() );\n            } catch (UnsupportedEncodingException ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n\n            retval = new byte[msgarray.length + content.length];\n            System.arraycopy(msgarray, 0, retval, 0, msgarray.length);\n            System.arraycopy(content, 0, retval, msgarray.length, content.length);\n        } else {\n            // Message content does not exist.\n\n            try {\n                retval = encoding.toString().getBytes( getCharset() );\n            } catch (UnsupportedEncodingException ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n        }\n        return retval;\n    }\n\n    /**\n     * clone this message (create a new deep physical copy). All headers in the message are\n     * cloned. You can modify the cloned copy without affecting the original. The content is\n     * handled as follows: If the content is a String, or a byte array, a new copy of the content\n     * is allocated and copied over. If the content is an Object that supports the clone method,\n     * then the clone method is invoked and the cloned content is the new content. Otherwise, the\n     * content of the new message is set equal to the old one.\n     * \n     * @return A cloned copy of this object.\n     */\n    public Object clone() {\n        SIPMessage retval = (SIPMessage) super.clone();\n        retval.nameTable = new Hashtable<String, SIPHeader>();\n        retval.fromHeader = null;\n        retval.toHeader = null;\n        retval.cSeqHeader = null;\n        retval.callIdHeader = null;\n        retval.contentLengthHeader = null;\n        retval.maxForwardsHeader = null;\n        if (this.headers != null) {\n            retval.headers = new ConcurrentLinkedQueue<SIPHeader>();\n            for (Iterator<SIPHeader> iter = headers.iterator(); iter.hasNext();) {\n                SIPHeader hdr = (SIPHeader) iter.next();\n                retval.attachHeader((SIPHeader) hdr.clone());\n            }\n\n        }\n        if (this.messageContentBytes != null)\n            retval.messageContentBytes = (byte[]) this.messageContentBytes.clone();\n        if (this.messageContentObject != null)\n            retval.messageContentObject = makeClone(messageContentObject);\n        retval.unrecognizedHeaders = this.unrecognizedHeaders;\n        return retval;\n    }\n\n    /**\n     * Get the string representation of this header (for pretty printing the generated structure).\n     * \n     * @return Formatted string representation of the object. Note that this is NOT the same as\n     *         encode(). This is used mainly for debugging purposes.\n     */\n    public String debugDump() {\n        stringRepresentation = \"\";\n        sprint(\"SIPMessage:\");\n        sprint(\"{\");\n        try {\n\n            Field[] fields = this.getClass().getDeclaredFields();\n            for (int i = 0; i < fields.length; i++) {\n                Field f = fields[i];\n                Class< ? > fieldType = f.getType();\n                String fieldName = f.getName();\n                if (f.get(this) != null && SIPHeader.class.isAssignableFrom(fieldType)\n                        && fieldName.compareTo(\"headers\") != 0) {\n                    sprint(fieldName + \"=\");\n                    sprint(((SIPHeader) f.get(this)).debugDump());\n                }\n            }\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n\n        sprint(\"List of headers : \");\n        sprint(headers.toString());\n        sprint(\"messageContent = \");\n        sprint(\"{\");\n        sprint(messageContent);\n        sprint(\"}\");\n        if (this.getContent() != null) {\n            sprint(this.getContent().toString());\n        }\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n    /**\n     * Constructor: Initializes lists and list headers. All the headers for which there can be\n     * multiple occurances in a message are derived from the SIPHeaderListClass. All singleton\n     * headers are derived from SIPHeader class.\n     */\n    public SIPMessage() {\n        this.unrecognizedHeaders = new LinkedList<String>();\n        this.headers = new ConcurrentLinkedQueue<SIPHeader>();\n        nameTable = new Hashtable<String, SIPHeader>();\n        try {\n            this.attachHeader(new ContentLength(0), false);\n        } catch (Exception ex) {\n        }\n    }\n\n    /**\n     * Attach a header and die if you get a duplicate header exception.\n     * \n     * @param h SIPHeader to attach.\n     */\n    private void attachHeader(SIPHeader h) {\n        if (h == null)\n            throw new IllegalArgumentException(\"null header!\");\n        try {\n            if (h instanceof SIPHeaderList) {\n                SIPHeaderList< ? > hl = (SIPHeaderList< ? >) h;\n                if (hl.isEmpty()) {\n                    return;\n                }\n            }\n            attachHeader(h, false, false);\n        } catch (SIPDuplicateHeaderException ex) {\n            // InternalErrorHandler.handleException(ex);\n        }\n    }\n\n    /**\n     * Attach a header (replacing the original header).\n     * \n     * @param sipHeader SIPHeader that replaces a header of the same type.\n     */\n    public void setHeader(Header sipHeader) {\n        SIPHeader header = (SIPHeader) sipHeader;\n        if (header == null)\n            throw new IllegalArgumentException(\"null header!\");\n        try {\n            if (header instanceof SIPHeaderList) {\n                SIPHeaderList< ? > hl = (SIPHeaderList< ? >) header;\n                // Ignore empty lists.\n                if (hl.isEmpty())\n                    return;\n            }\n            this.removeHeader(header.getHeaderName());\n            attachHeader(header, true, false);\n        } catch (SIPDuplicateHeaderException ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n    }\n\n    /**\n     * Set a header from a linked list of headers.\n     * \n     * @param headers -- a list of headers to set.\n     */\n    public void setHeaders(java.util.List<SIPHeader> headers) {\n        ListIterator<SIPHeader> listIterator = headers.listIterator();\n        while (listIterator.hasNext()) {\n            SIPHeader sipHeader = (SIPHeader) listIterator.next();\n            try {\n                this.attachHeader(sipHeader, false);\n            } catch (SIPDuplicateHeaderException ex) {\n            }\n        }\n    }\n\n    /**\n     * Attach a header to the end of the existing headers in this SIPMessage structure. This is\n     * equivalent to the attachHeader(SIPHeader,replaceflag,false); which is the normal way in\n     * which headers are attached. This was added in support of JAIN-SIP.\n     * \n     * @param h header to attach.\n     * @param replaceflag if true then replace a header if it exists.\n     * @throws SIPDuplicateHeaderException If replaceFlag is false and only a singleton header is\n     *         allowed (fpr example CSeq).\n     */\n    public void attachHeader(SIPHeader h, boolean replaceflag) throws SIPDuplicateHeaderException {\n        this.attachHeader(h, replaceflag, false);\n    }\n\n    /**\n     * Attach the header to the SIP Message structure at a specified position in its list of\n     * headers.\n     * \n     * @param header Header to attach.\n     * @param replaceFlag If true then replace the existing header.\n     * @param top Location in the header list to insert the header.\n     * @exception SIPDuplicateHeaderException if the header is of a type that cannot tolerate\n     *            duplicates and one of this type already exists (e.g. CSeq header).\n     * @throws IndexOutOfBoundsException If the index specified is greater than the number of\n     *         headers that are in this message.\n     */\n\n    public void attachHeader(SIPHeader header, boolean replaceFlag, boolean top)\n            throws SIPDuplicateHeaderException {\n        if (header == null) {\n            throw new NullPointerException(\"null header\");\n        }\n\n        SIPHeader h;\n\n        if (ListMap.hasList(header) && !SIPHeaderList.class.isAssignableFrom(header.getClass())) {\n            SIPHeaderList<SIPHeader> hdrList = ListMap.getList(header);\n            hdrList.add(header);\n            h = hdrList;\n        } else {\n            h = header;\n        }\n\n        String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(h.getName());\n        if (replaceFlag) {\n            nameTable.remove(headerNameLowerCase);\n        } else if (nameTable.containsKey(headerNameLowerCase) && !(h instanceof SIPHeaderList)) {\n            if (h instanceof ContentLength) {\n                try {\n                    ContentLength cl = (ContentLength) h;\n                    contentLengthHeader.setContentLength(cl.getContentLength());\n                } catch (InvalidArgumentException e) {\n                }\n            }\n            // Just ignore duplicate header.\n            return;\n        }\n\n        SIPHeader originalHeader = (SIPHeader) getHeader(header.getName());\n\n        // Delete the original header from our list structure.\n        if (originalHeader != null) {\n            Iterator<SIPHeader> li = headers.iterator();\n            while (li.hasNext()) {\n                SIPHeader next = (SIPHeader) li.next();\n                if (next.equals(originalHeader)) {\n                    li.remove();\n                }\n            }\n        }\n\n        if (!nameTable.containsKey(headerNameLowerCase)) {\n            nameTable.put(headerNameLowerCase, h);\n            headers.add(h);\n        } else {\n            if (h instanceof SIPHeaderList) {\n                SIPHeaderList< ? > hdrlist = (SIPHeaderList< ? >) nameTable\n                        .get(headerNameLowerCase);\n                if (hdrlist != null)\n                    hdrlist.concatenate((SIPHeaderList) h, top);\n                else\n                    nameTable.put(headerNameLowerCase, h);\n            } else {\n                nameTable.put(headerNameLowerCase, h);\n            }\n        }\n\n        // Direct accessor fields for frequently accessed headers.\n        if (h instanceof From) {\n            this.fromHeader = (From) h;\n        } else if (h instanceof ContentLength) {\n            this.contentLengthHeader = (ContentLength) h;\n        } else if (h instanceof To) {\n            this.toHeader = (To) h;\n        } else if (h instanceof CSeq) {\n            this.cSeqHeader = (CSeq) h;\n        } else if (h instanceof CallID) {\n            this.callIdHeader = (CallID) h;\n        } else if (h instanceof MaxForwards) {\n            this.maxForwardsHeader = (MaxForwards) h;\n        }\n\n    }\n\n    /**\n     * Remove a header given its name. If multiple headers of a given name are present then the\n     * top flag determines which end to remove headers from.\n     * \n     * @param headerName is the name of the header to remove.\n     * @param top -- flag that indicates which end of header list to process.\n     */\n    public void removeHeader(String headerName, boolean top) {\n\n        String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(headerName);\n        SIPHeader toRemove = (SIPHeader) nameTable.get(headerNameLowerCase);\n        // nothing to do then we are done.\n        if (toRemove == null)\n            return;\n        if (toRemove instanceof SIPHeaderList) {\n            SIPHeaderList< ? > hdrList = (SIPHeaderList< ? >) toRemove;\n            if (top)\n                hdrList.removeFirst();\n            else\n                hdrList.removeLast();\n            // Clean up empty list\n            if (hdrList.isEmpty()) {\n                Iterator<SIPHeader> li = this.headers.iterator();\n                while (li.hasNext()) {\n                    SIPHeader sipHeader = (SIPHeader) li.next();\n                    if (sipHeader.getName().equalsIgnoreCase(headerNameLowerCase))\n                        li.remove();\n                }\n\n                // JvB: also remove it from the nameTable! Else NPE in\n                // DefaultRouter\n                nameTable.remove(headerNameLowerCase);\n            }\n        } else {\n            this.nameTable.remove(headerNameLowerCase);\n            if (toRemove instanceof From) {\n                this.fromHeader = null;\n            } else if (toRemove instanceof To) {\n                this.toHeader = null;\n            } else if (toRemove instanceof CSeq) {\n                this.cSeqHeader = null;\n            } else if (toRemove instanceof CallID) {\n                this.callIdHeader = null;\n            } else if (toRemove instanceof MaxForwards) {\n                this.maxForwardsHeader = null;\n            } else if (toRemove instanceof ContentLength) {\n                this.contentLengthHeader = null;\n            }\n            Iterator<SIPHeader> li = this.headers.iterator();\n            while (li.hasNext()) {\n                SIPHeader sipHeader = (SIPHeader) li.next();\n                if (sipHeader.getName().equalsIgnoreCase(headerName))\n                    li.remove();\n            }\n        }\n\n    }\n\n    /**\n     * Remove all headers given its name.\n     * \n     * @param headerName is the name of the header to remove.\n     */\n    public void removeHeader(String headerName) {\n\n        if (headerName == null)\n            throw new NullPointerException(\"null arg\");\n        String headerNameLowerCase = SIPHeaderNamesCache.toLowerCase(headerName);\n        SIPHeader removed = (SIPHeader) nameTable.remove(headerNameLowerCase);\n        // nothing to do then we are done.\n        if (removed == null)\n            return;\n\n        // Remove the fast accessor fields.\n        if (removed instanceof From) {\n            this.fromHeader = null;\n        } else if (removed instanceof To) {\n            this.toHeader = null;\n        } else if (removed instanceof CSeq) {\n            this.cSeqHeader = null;\n        } else if (removed instanceof CallID) {\n            this.callIdHeader = null;\n        } else if (removed instanceof MaxForwards) {\n            this.maxForwardsHeader = null;\n        } else if (removed instanceof ContentLength) {\n            this.contentLengthHeader = null;\n        }\n\n        Iterator<SIPHeader> li = this.headers.iterator();\n        while (li.hasNext()) {\n            SIPHeader sipHeader = (SIPHeader) li.next();\n            if (sipHeader.getName().equalsIgnoreCase(headerNameLowerCase))\n                li.remove();\n\n        }\n    }\n\n    /**\n     * Generate (compute) a transaction ID for this SIP message.\n     * \n     * @return A string containing the concatenation of various portions of the From,To,Via and\n     *         RequestURI portions of this message as specified in RFC 2543: All responses to a\n     *         request contain the same values in the Call-ID, CSeq, To, and From fields (with the\n     *         possible addition of a tag in the To field (section 10.43)). This allows responses\n     *         to be matched with requests. Incorporates a bug fix for a bug sent in by Gordon\n     *         Ledgard of IPera for generating transactionIDs when no port is present in the via\n     *         header. Incorporates a bug fix for a bug report sent in by Chris Mills of Nortel\n     *         Networks (converts to lower case when returning the transaction identifier).\n     * \n     * @return a string that can be used as a transaction identifier for this message. This can be\n     *         used for matching responses and requests (i.e. an outgoing request and its matching\n     *         response have the same computed transaction identifier).\n     */\n    public String getTransactionId() {\n        Via topVia = null;\n        if (!this.getViaHeaders().isEmpty()) {\n            topVia = (Via) this.getViaHeaders().getFirst();\n        }\n        // Have specified a branch Identifier so we can use it to identify\n        // the transaction. BranchId is not case sensitive.\n        // Branch Id prefix is not case sensitive.\n        if (topVia != null\n                && topVia.getBranch() != null\n                && topVia.getBranch().toUpperCase().startsWith(\n                        SIPConstants.BRANCH_MAGIC_COOKIE_UPPER_CASE)) {\n            // Bis 09 compatible branch assignment algorithm.\n            // implies that the branch id can be used as a transaction\n            // identifier.\n            if (this.getCSeq().getMethod().equals(Request.CANCEL))\n                return (topVia.getBranch() + \":\" + this.getCSeq().getMethod()).toLowerCase();\n            else\n                return topVia.getBranch().toLowerCase();\n        } else {\n            // Old style client so construct the transaction identifier\n            // from various fields of the request.\n            StringBuffer retval = new StringBuffer();\n            From from = (From) this.getFrom();\n            To to = (To) this.getTo();\n            // String hpFrom = from.getUserAtHostPort();\n            // retval.append(hpFrom).append(\":\");\n            if (from.hasTag())\n                retval.append(from.getTag()).append(\"-\");\n            // String hpTo = to.getUserAtHostPort();\n            // retval.append(hpTo).append(\":\");\n            String cid = this.callIdHeader.getCallId();\n            retval.append(cid).append(\"-\");\n            retval.append(this.cSeqHeader.getSequenceNumber()).append(\"-\").append(\n                    this.cSeqHeader.getMethod());\n            if (topVia != null) {\n                retval.append(\"-\").append(topVia.getSentBy().encode());\n                if (!topVia.getSentBy().hasPort()) {\n                    retval.append(\"-\").append(5060);\n                }\n            }\n            if (this.getCSeq().getMethod().equals(Request.CANCEL)) {\n                retval.append(Request.CANCEL);\n            }\n            return retval.toString().toLowerCase().replace(\":\", \"-\").replace(\"@\", \"-\")\n                    + Utils.getSignature();\n        }\n    }\n\n    /**\n     * Override the hashcode method ( see issue # 55 ) Note that if you try to use this method\n     * before you assemble a valid request, you will get a constant ( -1 ). Beware of placing any\n     * half formed requests in a table.\n     */\n    public int hashCode() {\n        if (this.callIdHeader == null)\n            throw new RuntimeException(\n                    \"Invalid message! Cannot compute hashcode! call-id header is missing !\");\n        else\n            return this.callIdHeader.getCallId().hashCode();\n    }\n\n    /**\n     * Return true if this message has a body.\n     */\n    public boolean hasContent() {\n        return messageContent != null || messageContentBytes != null;\n    }\n\n    /**\n     * Return an iterator for the list of headers in this message.\n     * \n     * @return an Iterator for the headers of this message.\n     */\n    public Iterator<SIPHeader> getHeaders() {\n        return headers.iterator();\n    }\n\n    /**\n     * Get the first header of the given name.\n     * \n     * @return header -- the first header of the given name.\n     */\n    public Header getHeader(String headerName) {\n        return getHeaderLowerCase(SIPHeaderNamesCache.toLowerCase(headerName));\n    }\n\n    private Header getHeaderLowerCase(String lowerCaseHeaderName) {\n        if (lowerCaseHeaderName == null)\n            throw new NullPointerException(\"bad name\");\n        SIPHeader sipHeader = (SIPHeader) nameTable.get(lowerCaseHeaderName);\n        if (sipHeader instanceof SIPHeaderList)\n            return (Header) ((SIPHeaderList) sipHeader).getFirst();\n        else\n            return (Header) sipHeader;\n    }\n\n    /**\n     * Get the contentType header (null if one does not exist).\n     * \n     * @return contentType header\n     */\n    \n    public ContentType getContentTypeHeader() {\n        return (ContentType) getHeaderLowerCase(CONTENT_TYPE_LOWERCASE);\n    }\n    \n    private static final String CONTENT_TYPE_LOWERCASE = SIPHeaderNamesCache\n    .toLowerCase(ContentTypeHeader.NAME);\n\n    \n    /**\n     * Get the contentLength header.\n     */\n    public ContentLengthHeader getContentLengthHeader() {\n        return this.getContentLength();\n    }\n\n  \n    /**\n     * Get the from header.\n     * \n     * @return -- the from header.\n     */\n    public FromHeader getFrom() {\n        return (FromHeader) fromHeader;\n    }\n\n    /**\n     * Get the ErrorInfo list of headers (null if one does not exist).\n     * \n     * @return List containing ErrorInfo headers.\n     */\n    public ErrorInfoList getErrorInfoHeaders() {\n        return (ErrorInfoList) getSIPHeaderListLowerCase(ERROR_LOWERCASE);\n    }\n\n    private static final String ERROR_LOWERCASE = SIPHeaderNamesCache.toLowerCase(ErrorInfo.NAME);\n\n    /**\n     * Get the Contact list of headers (null if one does not exist).\n     * \n     * @return List containing Contact headers.\n     */\n    public ContactList getContactHeaders() {\n        return (ContactList) this.getSIPHeaderListLowerCase(CONTACT_LOWERCASE);\n    }\n\n    private static final String CONTACT_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(ContactHeader.NAME);\n\n    /**\n     * Get the contact header ( the first contact header) which is all we need for the most part.\n     * \n     */\n    public Contact getContactHeader() {\n        ContactList clist = this.getContactHeaders();\n        if (clist != null) {\n            return (Contact) clist.getFirst();\n\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Get the Via list of headers (null if one does not exist).\n     * \n     * @return List containing Via headers.\n     */\n    public ViaList getViaHeaders() {\n        return (ViaList) getSIPHeaderListLowerCase(VIA_LOWERCASE);\n    }\n\n    private static final String VIA_LOWERCASE = SIPHeaderNamesCache.toLowerCase(ViaHeader.NAME);\n\n    /**\n     * Set A list of via headers.\n     * \n     * @param viaList a list of via headers to add.\n     */\n    public void setVia(java.util.List viaList) {\n        ViaList vList = new ViaList();\n        ListIterator it = viaList.listIterator();\n        while (it.hasNext()) {\n            Via via = (Via) it.next();\n            vList.add(via);\n        }\n        this.setHeader(vList);\n    }\n\n    /**\n     * Set the header given a list of headers.\n     * \n     * @param sipHeaderList a headerList to set\n     */\n\n    public void setHeader(SIPHeaderList<Via> sipHeaderList) {\n        this.setHeader((Header) sipHeaderList);\n    }\n\n    /**\n     * Get the topmost via header.\n     * \n     * @return the top most via header if one exists or null if none exists.\n     */\n    public Via getTopmostVia() {\n        if (this.getViaHeaders() == null)\n            return null;\n        else\n            return (Via) (getViaHeaders().getFirst());\n    }\n\n    /**\n     * Get the CSeq list of header (null if one does not exist).\n     * \n     * @return CSeq header\n     */\n    public CSeqHeader getCSeq() {\n        return (CSeqHeader) cSeqHeader;\n    }\n\n    /**\n     * Get the Authorization header (null if one does not exist).\n     * \n     * @return Authorization header.\n     */\n    public Authorization getAuthorization() {\n        return (Authorization) getHeaderLowerCase(AUTHORIZATION_LOWERCASE);\n    }\n\n    private static final String AUTHORIZATION_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(AuthorizationHeader.NAME);\n\n    /**\n     * Get the MaxForwards header (null if one does not exist).\n     * \n     * @return Max-Forwards header\n     */\n\n    public MaxForwardsHeader getMaxForwards() {\n        return maxForwardsHeader;\n    }\n\n    /**\n     * Set the max forwards header.\n     * \n     * @param maxForwards is the MaxForwardsHeader to set.\n     */\n    public void setMaxForwards(MaxForwardsHeader maxForwards) {\n        this.setHeader(maxForwards);\n    }\n\n    /**\n     * Get the Route List of headers (null if one does not exist).\n     * \n     * @return List containing Route headers\n     */\n    public RouteList getRouteHeaders() {\n        return (RouteList) getSIPHeaderListLowerCase(ROUTE_LOWERCASE);\n    }\n\n    private static final String ROUTE_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(RouteHeader.NAME);\n\n    /**\n     * Get the CallID header (null if one does not exist)\n     * \n     * @return Call-ID header .\n     */\n    public CallIdHeader getCallId() {\n        return callIdHeader;\n    }\n\n    /**\n     * Set the call id header.\n     * \n     * @param callId call idHeader (what else could it be?)\n     */\n    public void setCallId(CallIdHeader callId) {\n        this.setHeader(callId);\n    }\n\n    /**\n     * Get the CallID header (null if one does not exist)\n     * \n     * @param callId -- the call identifier to be assigned to the call id header\n     */\n    public void setCallId(String callId) throws java.text.ParseException {\n        if (callIdHeader == null) {\n            this.setHeader(new CallID());\n        }\n        callIdHeader.setCallId(callId);\n    }\n\n    /**\n     * Get the RecordRoute header list (null if one does not exist).\n     * \n     * @return Record-Route header\n     */\n    public RecordRouteList getRecordRouteHeaders() {\n        return (RecordRouteList) this.getSIPHeaderListLowerCase(RECORDROUTE_LOWERCASE);\n    }\n\n    private static final String RECORDROUTE_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(RecordRouteHeader.NAME);\n\n    /**\n     * Get the To header (null if one does not exist).\n     * \n     * @return To header\n     */\n    public ToHeader getTo() {\n        return (ToHeader) toHeader;\n    }\n\n    public void setTo(ToHeader to) {\n        this.setHeader(to);\n    }\n\n    public void setFrom(FromHeader from) {\n        this.setHeader(from);\n\n    }\n\n    /**\n     * Get the ContentLength header (null if one does not exist).\n     * \n     * @return content-length header.\n     */\n    public ContentLengthHeader getContentLength() {\n        return this.contentLengthHeader;\n    }\n\n    /**\n     * Get the message body as a string. If the message contains a content type header with a\n     * specified charset, and if the payload has been read as a byte array, then it is returned\n     * encoded into this charset.\n     * \n     * @return Message body (as a string)\n     * @throws UnsupportedEncodingException if the platform does not support the charset specified\n     *         in the content type header.\n     * \n     */\n    public String getMessageContent() throws UnsupportedEncodingException {\n        if (this.messageContent == null && this.messageContentBytes == null)\n            return null;\n        else if (this.messageContent == null) {\n            this.messageContent = new String(messageContentBytes, getCharset() );\n        }\n        return this.messageContent;\n    }\n\n    /**\n     * Get the message content as an array of bytes. If the payload has been read as a String then\n     * it is decoded using the charset specified in the content type header if it exists.\n     * Otherwise, it is encoded using the default encoding which is UTF-8.\n     * \n     * @return an array of bytes that is the message payload.\n     */\n    public byte[] getRawContent() {\n        try {\n            if ( this.messageContentBytes != null ) {\n                // return messageContentBytes;\n            } else if (this.messageContentObject != null) {\n                String messageContent = this.messageContentObject.toString();\n                this.messageContentBytes = messageContent.getBytes( getCharset() );\n            } else if (this.messageContent != null) {\n            \tthis.messageContentBytes = messageContent.getBytes( getCharset() );                \n            }\n            return this.messageContentBytes;\n        } catch (UnsupportedEncodingException ex) {\n            InternalErrorHandler.handleException(ex);\n            return null;\n        }\n    }\n\n    /**\n     * Set the message content given type and subtype.\n     * \n     * @param type is the message type (eg. application)\n     * @param subType is the message sybtype (eg. sdp)\n     * @param messageContent is the messge content as a string.\n     */\n    public void setMessageContent(String type, String subType, String messageContent) {\n        if (messageContent == null)\n            throw new IllegalArgumentException(\"messgeContent is null\");\n        ContentType ct = new ContentType(type, subType);\n        this.setHeader(ct);\n        this.messageContent = messageContent;\n        this.messageContentBytes = null;\n        this.messageContentObject = null;\n        // Could be double byte so we need to compute length\n        // after converting to byte[]\n        computeContentLength(messageContent);\n    }\n\n    /**\n     * Set the message content after converting the given object to a String.\n     * \n     * @param content -- content to set.\n     * @param contentTypeHeader -- content type header corresponding to content.\n     */\n    public void setContent(Object content, ContentTypeHeader contentTypeHeader)\n            throws ParseException {\n        if (content == null)\n            throw new NullPointerException(\"null content\");\n        this.setHeader(contentTypeHeader);\n\n        this.messageContent = null;\n        this.messageContentBytes = null;\n        this.messageContentObject = null;\n\n        if (content instanceof String) {\n            this.messageContent = (String) content;\n        } else if (content instanceof byte[]) {\n            this.messageContentBytes = (byte[]) content;\n        } else\n            this.messageContentObject = content;\n\n        computeContentLength(content);\n    }\n\n    /**\n     * Get the content (body) of the message.\n     * \n     * @return the content of the sip message.\n     */\n    public Object getContent() {\n        if (this.messageContentObject != null)\n            return messageContentObject;\n        else if (this.messageContent != null)\n            return this.messageContent;\n        else if (this.messageContentBytes != null)\n            return this.messageContentBytes;\n        else\n            return null;\n    }\n\n    /**\n     * Set the message content for a given type and subtype.\n     * \n     * @param type is the messge type.\n     * @param subType is the message subType.\n     * @param messageContent is the message content as a byte array.\n     */\n    public void setMessageContent(String type, String subType, byte[] messageContent) {\n        ContentType ct = new ContentType(type, subType);\n        this.setHeader(ct);\n        this.setMessageContent(messageContent);\n\n        computeContentLength(messageContent);\n    }\n\n    /**\n     * Set the message content for this message.\n     * \n     * @param content Message body as a string.\n     */\n    public void setMessageContent(String content, boolean strict, boolean computeContentLength, int givenLength)\n            throws ParseException {\n        // Note that that this could be a double byte character\n        // set - bug report by Masafumi Watanabe\n        computeContentLength(content);\n        if ((!computeContentLength)) {\n            if ( (!strict && this.contentLengthHeader.getContentLength() != givenLength) \n                    || this.contentLengthHeader.getContentLength() < givenLength) {\n                throw new ParseException(\"Invalid content length \"\n                        + this.contentLengthHeader.getContentLength() + \" / \" + givenLength, 0);\n            }\n        }\n\n        messageContent = content;\n        messageContentBytes = null;\n        messageContentObject = null;\n    }\n\n    /**\n     * Set the message content as an array of bytes.\n     * \n     * @param content is the content of the message as an array of bytes.\n     */\n    public void setMessageContent(byte[] content) {\n        computeContentLength(content);\n\n        messageContentBytes = content;\n        messageContent = null;\n        messageContentObject = null;\n    }\n\n    /**\n     * Method to set the content - called by the parser\n     * \n     * @param content\n     * @throws ParseException\n     */\n    public void setMessageContent(byte[] content, boolean computeContentLength, int givenLength)\n            throws ParseException {\n        computeContentLength(content);\n        if ((!computeContentLength) && this.contentLengthHeader.getContentLength() < givenLength) {\n            // System.out.println(\"!!!!!!!!!!! MISMATCH !!!!!!!!!!!\");\n            throw new ParseException(\"Invalid content length \"\n                    + this.contentLengthHeader.getContentLength() + \" / \" + givenLength, 0);\n        }\n        messageContentBytes = content;\n        messageContent = null;\n        messageContentObject = null;\n    }\n\n    /**\n     * Compute and set the Content-length header based on the given content object.\n     * \n     * @param content is the content, as String, array of bytes, or other object.\n     */\n    private void computeContentLength(Object content) {\n        int length = 0;\n        if (content != null) {\n            if (content instanceof String) {\n                try {\n                    length = ((String) content).getBytes( getCharset() ).length;\n                } catch (UnsupportedEncodingException ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n            } else if (content instanceof byte[]) {\n                length = ((byte[]) content).length;\n            } else {\n                length = content.toString().length();\n            }\n        }\n\n        try {\n            contentLengthHeader.setContentLength(length);\n        } catch (InvalidArgumentException e) {\n            // Cannot happen.\n        }\n    }\n\n    /**\n     * Remove the message content if it exists.\n     */\n    public void removeContent() {\n        messageContent = null;\n        messageContentBytes = null;\n        messageContentObject = null;\n        try {\n            this.contentLengthHeader.setContentLength(0);\n        } catch (InvalidArgumentException ex) {\n        }\n    }\n\n    /**\n     * Get a SIP header or Header list given its name.\n     * \n     * @param headerName is the name of the header to get.\n     * @return a header or header list that contians the retrieved header.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public ListIterator<SIPHeader> getHeaders(String headerName) {\n        if (headerName == null)\n            throw new NullPointerException(\"null headerName\");\n        SIPHeader sipHeader = (SIPHeader) nameTable.get(SIPHeaderNamesCache\n                .toLowerCase(headerName));\n        // empty iterator\n        if (sipHeader == null)\n            return new LinkedList<SIPHeader>().listIterator();\n        if (sipHeader instanceof SIPHeaderList) {\n            return ((SIPHeaderList<SIPHeader>) sipHeader).listIterator();\n        } else {\n            return new HeaderIterator(this, sipHeader);\n        }\n    }\n\n    /**\n     * Get a header of the given name as a string. This concatenates the headers of a given type\n     * as a comma separted list. This is useful for formatting and printing headers.\n     * \n     * @param name\n     * @return the header as a formatted string\n     */\n    public String getHeaderAsFormattedString(String name) {\n        String lowerCaseName = name.toLowerCase();\n        if (this.nameTable.containsKey(lowerCaseName)) {\n            return this.nameTable.get(lowerCaseName).toString();\n        } else {\n            return this.getHeader(name).toString();\n        }\n    }\n\n    private SIPHeader getSIPHeaderListLowerCase(String lowerCaseHeaderName) {\n        return nameTable.get(lowerCaseHeaderName);\n    }\n\n    /**\n     * Get a list of headers of the given name ( or null if no such header exists ).\n     * \n     * @param headerName -- a header name from which to retrieve the list.\n     * @return -- a list of headers with that name.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private List<SIPHeader> getHeaderList(String headerName) {\n        SIPHeader sipHeader = (SIPHeader) nameTable.get(SIPHeaderNamesCache\n                .toLowerCase(headerName));\n        if (sipHeader == null)\n            return null;\n        else if (sipHeader instanceof SIPHeaderList)\n            return (List<SIPHeader>) (((SIPHeaderList< ? >) sipHeader).getHeaderList());\n        else {\n            LinkedList<SIPHeader> ll = new LinkedList<SIPHeader>();\n            ll.add(sipHeader);\n            return ll;\n        }\n    }\n\n    /**\n     * Return true if the SIPMessage has a header of the given name.\n     * \n     * @param headerName is the header name for which we are testing.\n     * @return true if the header is present in the message\n     */\n    public boolean hasHeader(String headerName) {\n        return nameTable.containsKey(SIPHeaderNamesCache.toLowerCase(headerName));\n    }\n\n    /**\n     * Return true if the message has a From header tag.\n     * \n     * @return true if the message has a from header and that header has a tag.\n     */\n    public boolean hasFromTag() {\n        return fromHeader != null && fromHeader.getTag() != null;\n    }\n\n    /**\n     * Return true if the message has a To header tag.\n     * \n     * @return true if the message has a to header and that header has a tag.\n     */\n    public boolean hasToTag() {\n        return toHeader != null && toHeader.getTag() != null;\n    }\n\n    /**\n     * Return the from tag.\n     * \n     * @return the tag from the from header.\n     * \n     */\n    public String getFromTag() {\n        return fromHeader == null ? null : fromHeader.getTag();\n    }\n\n    /**\n     * Set the From Tag.\n     * \n     * @param tag -- tag to set in the from header.\n     */\n    public void setFromTag(String tag) {\n        try {\n            fromHeader.setTag(tag);\n        } catch (ParseException e) {\n        }\n    }\n\n    /**\n     * Set the to tag.\n     * \n     * @param tag -- tag to set.\n     */\n    public void setToTag(String tag) {\n        try {\n            toHeader.setTag(tag);\n        } catch (ParseException e) {\n        }\n    }\n\n    /**\n     * Return the to tag.\n     */\n    public String getToTag() {\n        return toHeader == null ? null : toHeader.getTag();\n    }\n\n    /**\n     * Return the encoded first line.\n     */\n    public abstract String getFirstLine();\n\n    /**\n     * Add a SIP header.\n     * \n     * @param sipHeader -- sip header to add.\n     */\n    public void addHeader(Header sipHeader) {\n        // Content length is never stored. Just computed.\n        SIPHeader sh = (SIPHeader) sipHeader;\n        try {\n            if ((sipHeader instanceof ViaHeader) || (sipHeader instanceof RecordRouteHeader)) {\n                attachHeader(sh, false, true);\n            } else {\n                attachHeader(sh, false, false);\n            }\n        } catch (SIPDuplicateHeaderException ex) {\n            try {\n                if (sipHeader instanceof ContentLength) {\n                    ContentLength cl = (ContentLength) sipHeader;\n                    contentLengthHeader.setContentLength(cl.getContentLength());\n                }\n            } catch (InvalidArgumentException e) {\n            }\n        }\n    }\n\n    /**\n     * Add a header to the unparsed list of headers.\n     * \n     * @param unparsed -- unparsed header to add to the list.\n     */\n    public void addUnparsed(String unparsed) {\n        this.unrecognizedHeaders.add(unparsed);\n    }\n\n    /**\n     * Add a SIP header.\n     * \n     * @param sipHeader -- string version of SIP header to add.\n     */\n\n    public void addHeader(String sipHeader) {\n        String hdrString = sipHeader.trim() + \"\\n\";\n        try {\n            HeaderParser parser = ParserFactory.createParser(sipHeader);\n            SIPHeader sh = parser.parse();\n            this.attachHeader(sh, false);\n        } catch (ParseException ex) {\n            this.unrecognizedHeaders.add(hdrString);\n        }\n    }\n\n    /**\n     * Get a list containing the unrecognized headers.\n     * \n     * @return a linked list containing unrecongnized headers.\n     */\n    public ListIterator<String> getUnrecognizedHeaders() {\n        return this.unrecognizedHeaders.listIterator();\n    }\n\n    /**\n     * Get the header names.\n     * \n     * @return a list iterator to a list of header names. These are ordered in the same order as\n     *         are present in the message.\n     */\n    public ListIterator<String> getHeaderNames() {\n        Iterator<SIPHeader> li = this.headers.iterator();\n        LinkedList<String> retval = new LinkedList<String>();\n        while (li.hasNext()) {\n            SIPHeader sipHeader = (SIPHeader) li.next();\n            String name = sipHeader.getName();\n            retval.add(name);\n        }\n        return retval.listIterator();\n    }\n\n    /**\n     * Compare for equality.\n     * \n     * @param other -- the other object to compare with.\n     */\n    public boolean equals(Object other) {\n        if (!other.getClass().equals(this.getClass())) {\n            return false;\n        }\n        SIPMessage otherMessage = (SIPMessage) other;\n        Collection<SIPHeader> values = this.nameTable.values();\n        Iterator<SIPHeader> it = values.iterator();\n        if (nameTable.size() != otherMessage.nameTable.size()) {\n            return false;\n        }\n\n        while (it.hasNext()) {\n            SIPHeader mine = (SIPHeader) it.next();\n            SIPHeader his = (SIPHeader) (otherMessage.nameTable.get(SIPHeaderNamesCache\n                    .toLowerCase(mine.getName())));\n            if (his == null) {\n                return false;\n            } else if (!his.equals(mine)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * get content disposition header or null if no such header exists.\n     * \n     * @return the contentDisposition header\n     */\n    public javax2.sip.header.ContentDispositionHeader getContentDisposition() {\n        return (ContentDispositionHeader) getHeaderLowerCase(CONTENT_DISPOSITION_LOWERCASE);\n    }\n\n    private static final String CONTENT_DISPOSITION_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(ContentDispositionHeader.NAME);\n\n    /**\n     * get the content encoding header.\n     * \n     * @return the contentEncoding header.\n     */\n    public javax2.sip.header.ContentEncodingHeader getContentEncoding() {\n        return (ContentEncodingHeader) getHeaderLowerCase(CONTENT_ENCODING_LOWERCASE);\n    }\n\n    private static final String CONTENT_ENCODING_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(ContentEncodingHeader.NAME);\n\n    /**\n     * Get the contentLanguage header.\n     * \n     * @return the content language header.\n     */\n    public javax2.sip.header.ContentLanguageHeader getContentLanguage() {\n        return (ContentLanguageHeader) getHeaderLowerCase(CONTENT_LANGUAGE_LOWERCASE);\n    }\n\n    private static final String CONTENT_LANGUAGE_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(ContentLanguageHeader.NAME);\n\n    /**\n     * Get the exipres header.\n     * \n     * @return the expires header or null if one does not exist.\n     */\n    public javax2.sip.header.ExpiresHeader getExpires() {\n        return (ExpiresHeader) getHeaderLowerCase(EXPIRES_LOWERCASE);\n    }\n\n    private static final String EXPIRES_LOWERCASE = SIPHeaderNamesCache\n            .toLowerCase(ExpiresHeader.NAME);\n\n    /**\n     * Set the expiresHeader\n     * \n     * @param expiresHeader -- the expires header to set.\n     */\n\n    public void setExpires(ExpiresHeader expiresHeader) {\n        this.setHeader(expiresHeader);\n    }\n\n    /**\n     * Set the content disposition header.\n     * \n     * @param contentDispositionHeader -- content disposition header.\n     */\n\n    public void setContentDisposition(ContentDispositionHeader contentDispositionHeader) {\n        this.setHeader(contentDispositionHeader);\n\n    }\n\n    public void setContentEncoding(ContentEncodingHeader contentEncodingHeader) {\n        this.setHeader(contentEncodingHeader);\n\n    }\n\n    public void setContentLanguage(ContentLanguageHeader contentLanguageHeader) {\n        this.setHeader(contentLanguageHeader);\n    }\n\n    /**\n     * Set the content length header.\n     * \n     * @param contentLength -- content length header.\n     */\n    public void setContentLength(ContentLengthHeader contentLength) {\n        try {\n            this.contentLengthHeader.setContentLength(contentLength.getContentLength());\n        } catch (InvalidArgumentException ex) {\n        }\n\n    }\n\n    /**\n     * Set the size of all the headers. This is for book keeping. Called by the parser.\n     * \n     * @param size -- size of the headers.\n     */\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n    public int getSize() {\n        return this.size;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.message.Message#addLast(javax2.sip.header.Header)\n     */\n    public void addLast(Header header) throws SipException, NullPointerException {\n        if (header == null)\n            throw new NullPointerException(\"null arg!\");\n\n        try {\n            this.attachHeader((SIPHeader) header, false, false);\n        } catch (SIPDuplicateHeaderException ex) {\n            throw new SipException(\"Cannot add header - header already exists\");\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.message.Message#addFirst(javax2.sip.header.Header)\n     */\n    public void addFirst(Header header) throws SipException, NullPointerException {\n\n        if (header == null)\n            throw new NullPointerException(\"null arg!\");\n\n        try {\n            this.attachHeader((SIPHeader) header, false, true);\n        } catch (SIPDuplicateHeaderException ex) {\n            throw new SipException(\"Cannot add header - header already exists\");\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.message.Message#removeFirst(java.lang.String)\n     */\n    public void removeFirst(String headerName) throws NullPointerException {\n        if (headerName == null)\n            throw new NullPointerException(\"Null argument Provided!\");\n        this.removeHeader(headerName, true);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.message.Message#removeLast(java.lang.String)\n     */\n    public void removeLast(String headerName) {\n        if (headerName == null)\n            throw new NullPointerException(\"Null argument Provided!\");\n        this.removeHeader(headerName, false);\n\n    }\n\n    /**\n     * Set the CSeq header.\n     * \n     * @param cseqHeader -- CSeq Header.\n     */\n\n    public void setCSeq(CSeqHeader cseqHeader) {\n        this.setHeader(cseqHeader);\n    }\n\n    /**\n     * Set the application data pointer. This method is not used the stack. It is provided as a\n     * convenient way of storing book-keeping data for applications. Note that null clears the\n     * application data pointer (releases it).\n     * \n     * @param applicationData -- application data pointer to set. null clears the application data\n     *        pointer.\n     */\n    public void setApplicationData(Object applicationData) {\n        this.applicationData = applicationData;\n    }\n\n    /**\n     * Get the application data associated with this message.\n     * \n     * @return stored application data.\n     */\n    public Object getApplicationData() {\n        return this.applicationData;\n    }\n\n    /**\n     * Get the multipart MIME content\n     * \n     */\n    public MultipartMimeContent getMultipartMimeContent() throws ParseException {\n        if (this.contentLengthHeader.getContentLength() == 0) {\n            return null;\n        }\n        MultipartMimeContentImpl retval = new MultipartMimeContentImpl(this\n                .getContentTypeHeader());\n        byte[] rawContent = getRawContent();\n\t\ttry {\n\t\t\tString body = new String( rawContent, getCharset() );\n\t        retval.createContentList(body);\n\t        return retval;\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tInternalErrorHandler.handleException(e);\n\t\t\treturn null;\n\t\t}\n    }\n    \n    public CallIdHeader getCallIdHeader() {\n        return this.callIdHeader;\n    }\n\n   \n    public FromHeader getFromHeader() {\n        return this.fromHeader;\n    }\n\n   \n    public ToHeader getToHeader() {\n        return this.toHeader;\n    }\n\n  \n    public ViaHeader getTopmostViaHeader() {\n        return this.getTopmostVia();\n    }\n    \n    public CSeqHeader getCSeqHeader() {\n        return this.cSeqHeader;\n    }\n \n    /**\n     * Returns the charset to use for encoding/decoding the body of this message\n     */\n    protected final String getCharset() {\n    \tContentType ct = getContentTypeHeader();\n    \tif (ct!=null) {\n    \t\tString c = ct.getCharset();\n    \t\treturn c!=null ? c : contentEncodingCharset;\n    \t} else return contentEncodingCharset;\n    }\n    \n    /**\n     * Return true if this is a null request (i.e. does not have a request line ).\n     * \n     * @return true if null request.\n     */\n    public boolean isNullRequest() {\n        return  this.nullRequest;\n    }\n    \n    /**\n     * Set a flag to indiate this is a special message ( encoded with CRLFCRLF ).\n     * \n     */\n    public void setNullRequest() {\n        this.nullRequest = true;\n    }\n    \n    \n    public abstract void setSIPVersion(String sipVersion) throws ParseException;\n\n    public abstract String getSIPVersion();\n\n    public abstract String toString();\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/SIPRequest.java",
    "content": "/*\n * Conditions Of Use \n * \n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n * \n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *  \n * .\n * \n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\n\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.LinkedList;\nimport java.util.Set;\nimport java.io.UnsupportedEncodingException;\nimport java.util.Iterator;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\nimport javax2.sip.address.URI;\nimport javax2.sip.header.*;\nimport javax2.sip.message.*;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.stack.SIPTransactionStack;\n\n/*\n * Acknowledgements: Mark Bednarek made a few fixes to this code. Jeff Keyser added two methods\n * that create responses and generate cancel requests from incoming orignial requests without the\n * additional overhead of encoding and decoding messages. Bruno Konik noticed an extraneous\n * newline added to the end of the buffer when encoding it. Incorporates a bug report from Andreas\n * Bystrom. Szabo Barna noticed a contact in a cancel request - this is a pointless header for\n * cancel. Antonis Kyardis contributed bug fixes. Jeroen van Bemmel noted that method names are\n * case sensitive, should use equals() in getting CannonicalName\n * \n */\n\n/**\n * The SIP Request structure.\n * \n * @version 1.2 $Revision: 1.52 $ $Date: 2009/12/16 14:58:40 $\n * @since 1.1\n * \n * @author M. Ranganathan <br/>\n * \n * \n * \n */\n\npublic final class SIPRequest extends SIPMessage implements javax2.sip.message.Request, RequestExt {\n\n    private static final long serialVersionUID = 3360720013577322927L;\n\n    private static final String DEFAULT_USER = \"ip\";\n\n    private static final String DEFAULT_TRANSPORT = \"udp\";\n\n    private transient Object transactionPointer;\n\n    private RequestLine requestLine;\n\n    private transient Object messageChannel;\n    \n    \n\n    private transient Object inviteTransaction; // The original invite request for a\n    // given cancel request\n\n    /**\n     * Set of target refresh methods, currently: INVITE, UPDATE, SUBSCRIBE, NOTIFY, REFER\n     * \n     * A target refresh request and its response MUST have a Contact\n     */\n    private static final Set<String> targetRefreshMethods = new HashSet<String>();\n\n    /*\n     * A table that maps a name string to its cannonical constant. This is used to speed up\n     * parsing of messages .equals reduces to == if we use the constant value.\n     */\n    private static final Hashtable<String, String> nameTable = new Hashtable<String, String>();\n\n    private static void putName(String name) {\n        nameTable.put(name, name);\n    }\n\n    static {\n        targetRefreshMethods.add(Request.INVITE);\n        targetRefreshMethods.add(Request.UPDATE);\n        targetRefreshMethods.add(Request.SUBSCRIBE);\n        targetRefreshMethods.add(Request.NOTIFY);\n        targetRefreshMethods.add(Request.REFER);\n\n        putName(Request.INVITE);\n        putName(Request.BYE);\n        putName(Request.CANCEL);\n        putName(Request.ACK);\n        putName(Request.PRACK);\n        putName(Request.INFO);\n        putName(Request.MESSAGE);\n        putName(Request.NOTIFY);\n        putName(Request.OPTIONS);\n        putName(Request.PRACK);\n        putName(Request.PUBLISH);\n        putName(Request.REFER);\n        putName(Request.REGISTER);\n        putName(Request.SUBSCRIBE);\n        putName(Request.UPDATE);\n\n    }\n\n    /**\n     * @return true iff the method is a target refresh\n     */\n    public static boolean isTargetRefresh(String ucaseMethod) {\n        return targetRefreshMethods.contains(ucaseMethod);\n    }\n\n    /**\n     * @return true iff the method is a dialog creating method\n     */\n    public static boolean isDialogCreating(String ucaseMethod) {\n        return SIPTransactionStack.isDialogCreated(ucaseMethod);\n    }\n    \n    /**\n     * Set to standard constants to speed up processing. this makes equals comparisons run much\n     * faster in the stack because then it is just identity comparision. Character by char\n     * comparison is not required. The method returns the String CONSTANT corresponding to the\n     * String name.\n     * \n     */\n    public static String getCannonicalName(String method) {\n\n        if (nameTable.containsKey(method))\n            return (String) nameTable.get(method);\n        else\n            return method;\n    }\n\n    /**\n     * Get the Request Line of the SIPRequest.\n     * \n     * @return the request line of the SIP Request.\n     */\n\n    public RequestLine getRequestLine() {\n        return requestLine;\n    }\n\n    /**\n     * Set the request line of the SIP Request.\n     * \n     * @param requestLine is the request line to set in the SIP Request.\n     */\n\n    public void setRequestLine(RequestLine requestLine) {\n        this.requestLine = requestLine;\n    }\n\n    /**\n     * Constructor.\n     */\n    public SIPRequest() {\n        super();\n    }\n\n    /**\n     * Convert to a formatted string for pretty printing. Note that the encode method converts\n     * this into a sip message that is suitable for transmission. Note hack here if you want to\n     * convert the nice curly brackets into some grotesque XML tag.\n     * \n     * @return a string which can be used to examine the message contents.\n     * \n     */\n    public String debugDump() {\n        String superstring = super.debugDump();\n        stringRepresentation = \"\";\n        sprint(SIPRequest.class.getName());\n        sprint(\"{\");\n        if (requestLine != null)\n            sprint(requestLine.debugDump());\n        sprint(superstring);\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n    /**\n     * Check header for constraints. (1) Invite options and bye requests can only have SIP URIs in\n     * the contact headers. (2) Request must have cseq, to and from and via headers. (3) Method in\n     * request URI must match that in CSEQ.\n     */\n    public void checkHeaders() throws ParseException {\n        String prefix = \"Missing a required header : \";\n\n        /* Check for required headers */\n\n        if (getCSeq() == null) {\n            throw new ParseException(prefix + CSeqHeader.NAME, 0);\n        }\n        if (getTo() == null) {\n            throw new ParseException(prefix + ToHeader.NAME, 0);\n        }\n\n        if (this.callIdHeader == null || this.callIdHeader.getCallId() == null\n                || callIdHeader.getCallId().equals(\"\")) {\n            throw new ParseException(prefix + CallIdHeader.NAME, 0);\n        }\n        if (getFrom() == null) {\n            throw new ParseException(prefix + FromHeader.NAME, 0);\n        }\n        if (getViaHeaders() == null) {\n            throw new ParseException(prefix + ViaHeader.NAME, 0);\n        }\n        if (getMaxForwards() == null) {\n            throw new ParseException(prefix + MaxForwardsHeader.NAME, 0);\n        }\n\n        if (getTopmostVia() == null)\n            throw new ParseException(\"No via header in request! \", 0);\n\n        if (getMethod().equals(Request.NOTIFY)) {\n            if (getHeader(SubscriptionStateHeader.NAME) == null)\n                throw new ParseException(prefix + SubscriptionStateHeader.NAME, 0);\n\n            if (getHeader(EventHeader.NAME) == null)\n                throw new ParseException(prefix + EventHeader.NAME, 0);\n\n        } else if (getMethod().equals(Request.PUBLISH)) {\n            /*\n             * For determining the type of the published event state, the EPA MUST include a\n             * single Event header field in PUBLISH requests. The value of this header field\n             * indicates the event package for which this request is publishing event state.\n             */\n            if (getHeader(EventHeader.NAME) == null)\n                throw new ParseException(prefix + EventHeader.NAME, 0);\n        }\n\n        /*\n         * RFC 3261 8.1.1.8 The Contact header field MUST be present and contain exactly one SIP\n         * or SIPS URI in any request that can result in the establishment of a dialog. For the\n         * methods defined in this specification, that includes only the INVITE request. For these\n         * requests, the scope of the Contact is global. That is, the Contact header field value\n         * contains the URI at which the UA would like to receive requests, and this URI MUST be\n         * valid even if used in subsequent requests outside of any dialogs.\n         * \n         * If the Request-URI or top Route header field value contains a SIPS URI, the Contact\n         * header field MUST contain a SIPS URI as well.\n         */\n        if (requestLine.getMethod().equals(Request.INVITE)\n                || requestLine.getMethod().equals(Request.SUBSCRIBE)\n                || requestLine.getMethod().equals(Request.REFER)) {\n            if (this.getContactHeader() == null) {\n                // Make sure this is not a target refresh. If this is a target\n                // refresh its ok not to have a contact header. Otherwise\n                // contact header is mandatory.\n                if (this.getToTag() == null)\n                    throw new ParseException(prefix + ContactHeader.NAME, 0);\n            }\n\n            if (requestLine.getUri() instanceof SipUri) {\n                String scheme = ((SipUri) requestLine.getUri()).getScheme();\n                if (\"sips\".equalsIgnoreCase(scheme)) {\n                    SipUri sipUri = (SipUri) this.getContactHeader().getAddress().getURI();\n                    if (!sipUri.getScheme().equals(\"sips\")) {\n                        throw new ParseException(\"Scheme for contact should be sips:\" + sipUri, 0);\n                    }\n                }\n            }\n        }\n\n        /*\n         * Contact header is mandatory for a SIP INVITE request.\n         */\n        if (this.getContactHeader() == null\n                && (this.getMethod().equals(Request.INVITE)\n                        || this.getMethod().equals(Request.REFER) || this.getMethod().equals(\n                        Request.SUBSCRIBE))) {\n            throw new ParseException(\"Contact Header is Mandatory for a SIP INVITE\", 0);\n        }\n\n        if (requestLine != null && requestLine.getMethod() != null\n                && getCSeq().getMethod() != null\n                && requestLine.getMethod().compareTo(getCSeq().getMethod()) != 0) {\n            throw new ParseException(\"CSEQ method mismatch with  Request-Line \", 0);\n\n        }\n\n    }\n\n    /**\n     * Set the default values in the request URI if necessary.\n     */\n    protected void setDefaults() {\n        // The request line may be unparseable (set to null by the\n        // exception handler.\n        if (requestLine == null)\n            return;\n        String method = requestLine.getMethod();\n        // The requestLine may be malformed!\n        if (method == null)\n            return;\n        GenericURI u = requestLine.getUri();\n        if (u == null)\n            return;\n        if (method.compareTo(Request.REGISTER) == 0 || method.compareTo(Request.INVITE) == 0) {\n            if (u instanceof SipUri) {\n                SipUri sipUri = (SipUri) u;\n                sipUri.setUserParam(DEFAULT_USER);\n                try {\n                    sipUri.setTransportParam(DEFAULT_TRANSPORT);\n                } catch (ParseException ex) {\n                }\n            }\n        }\n    }\n\n    /**\n     * Patch up the request line as necessary.\n     */\n    protected void setRequestLineDefaults() {\n        String method = requestLine.getMethod();\n        if (method == null) {\n            CSeq cseq = (CSeq) this.getCSeq();\n            if (cseq != null) {\n                method = getCannonicalName(cseq.getMethod());\n                requestLine.setMethod(method);\n            }\n        }\n    }\n\n    /**\n     * A conveniance function to access the Request URI.\n     * \n     * @return the requestURI if it exists.\n     */\n    public javax2.sip.address.URI getRequestURI() {\n        if (this.requestLine == null)\n            return null;\n        else\n            return (javax2.sip.address.URI) this.requestLine.getUri();\n    }\n\n    /**\n     * Sets the RequestURI of Request. The Request-URI is a SIP or SIPS URI or a general URI. It\n     * indicates the user or service to which this request is being addressed. SIP elements MAY\n     * support Request-URIs with schemes other than \"sip\" and \"sips\", for example the \"tel\" URI\n     * scheme. SIP elements MAY translate non-SIP URIs using any mechanism at their disposal,\n     * resulting in SIP URI, SIPS URI, or some other scheme.\n     * \n     * @param uri the new Request URI of this request message\n     */\n    public void setRequestURI(URI uri) {\n        if ( uri == null ) {\n            throw new NullPointerException(\"Null request URI\");\n        }\n        if (this.requestLine == null) {\n            this.requestLine = new RequestLine();\n        }\n        this.requestLine.setUri((GenericURI) uri);\n        this.nullRequest = false;\n    }\n\n    /**\n     * Set the method.\n     * \n     * @param method is the method to set.\n     * @throws IllegalArgumentException if the method is null\n     */\n    public void setMethod(String method) {\n        if (method == null)\n            throw new IllegalArgumentException(\"null method\");\n        if (this.requestLine == null) {\n            this.requestLine = new RequestLine();\n        }\n\n        // Set to standard constants to speed up processing.\n        // this makes equals compares run much faster in the\n        // stack because then it is just identity comparision\n\n        String meth = getCannonicalName(method);\n        this.requestLine.setMethod(meth);\n\n        if (this.cSeqHeader != null) {\n            try {\n                this.cSeqHeader.setMethod(meth);\n            } catch (ParseException e) {\n            }\n        }\n    }\n\n    /**\n     * Get the method from the request line.\n     * \n     * @return the method from the request line if the method exits and null if the request line\n     *         or the method does not exist.\n     */\n    public String getMethod() {\n        if (requestLine == null)\n            return null;\n        else\n            return requestLine.getMethod();\n    }\n\n    /**\n     * Encode the SIP Request as a string.\n     * \n     * @return an encoded String containing the encoded SIP Message.\n     */\n\n    public String encode() {\n        String retval;\n        if (requestLine != null) {\n            this.setRequestLineDefaults();\n            retval = requestLine.encode() + super.encode();\n        } else if (this.isNullRequest()) {\n            retval = \"\\r\\n\\r\\n\";\n        } else {       \n            retval = super.encode();\n        }\n        return retval;\n    }\n\n    /**\n     * Encode only the headers and not the content.\n     */\n    public String encodeMessage() {\n        String retval;\n        if (requestLine != null) {\n            this.setRequestLineDefaults();\n            retval = requestLine.encode() + super.encodeSIPHeaders();\n        } else if (this.isNullRequest()) {\n            retval = \"\\r\\n\\r\\n\";\n        } else\n            retval = super.encodeSIPHeaders();\n        return retval;\n\n    }\n\n    /**\n     * ALias for encode above.\n     */\n    public String toString() {\n        return this.encode();\n    }\n\n    /**\n     * Make a clone (deep copy) of this object. You can use this if you want to modify a request\n     * while preserving the original\n     * \n     * @return a deep copy of this object.\n     */\n\n    public Object clone() {\n        SIPRequest retval = (SIPRequest) super.clone();\n        // Do not copy over the tx pointer -- this is only for internal\n        // tracking.\n        retval.transactionPointer = null;\n        if (this.requestLine != null)\n            retval.requestLine = (RequestLine) this.requestLine.clone();\n\n        return retval;\n    }\n\n    /**\n     * Compare for equality.\n     * \n     * @param other object to compare ourselves with.\n     */\n    public boolean equals(Object other) {\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        SIPRequest that = (SIPRequest) other;\n\n        return requestLine.equals(that.requestLine) && super.equals(other);\n    }\n\n    /**\n     * Get the message as a linked list of strings. Use this if you want to iterate through the\n     * message.\n     * \n     * @return a linked list containing the request line and headers encoded as strings.\n     */\n    public LinkedList getMessageAsEncodedStrings() {\n        LinkedList retval = super.getMessageAsEncodedStrings();\n        if (requestLine != null) {\n            this.setRequestLineDefaults();\n            retval.addFirst(requestLine.encode());\n        }\n        return retval;\n\n    }\n\n    /**\n     * Match with a template. You can use this if you want to match incoming messages with a\n     * pattern and do something when you find a match. This is useful for building filters/pattern\n     * matching responders etc.\n     * \n     * @param matchObj object to match ourselves with (null matches wildcard)\n     * \n     */\n    public boolean match(Object matchObj) {\n        if (matchObj == null)\n            return true;\n        else if (!matchObj.getClass().equals(this.getClass()))\n            return false;\n        else if (matchObj == this)\n            return true;\n        SIPRequest that = (SIPRequest) matchObj;\n        RequestLine rline = that.requestLine;\n        if (this.requestLine == null && rline != null)\n            return false;\n        else if (this.requestLine == rline)\n            return super.match(matchObj);\n        return requestLine.match(that.requestLine) && super.match(matchObj);\n\n    }\n\n    /**\n     * Get a dialog identifier. Generates a string that can be used as a dialog identifier.\n     * \n     * @param isServer is set to true if this is the UAS and set to false if this is the UAC\n     */\n    public String getDialogId(boolean isServer) {\n        CallID cid = (CallID) this.getCallId();\n        StringBuffer retval = new StringBuffer(cid.getCallId());\n        From from = (From) this.getFrom();\n        To to = (To) this.getTo();\n        if (!isServer) {\n            // retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n            // retval.append(COLON).append(to.getUserAtHostPort());\n            if (to.getTag() != null) {\n                retval.append(COLON);\n                retval.append(to.getTag());\n            }\n        } else {\n            // retval.append(COLON).append(to.getUserAtHostPort());\n            if (to.getTag() != null) {\n                retval.append(COLON);\n                retval.append(to.getTag());\n            }\n            // retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n        }\n        return retval.toString().toLowerCase();\n\n    }\n\n    /**\n     * Get a dialog id given the remote tag.\n     */\n    public String getDialogId(boolean isServer, String toTag) {\n        From from = (From) this.getFrom();\n        CallID cid = (CallID) this.getCallId();\n        StringBuffer retval = new StringBuffer(cid.getCallId());\n        if (!isServer) {\n            // retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n            // retval.append(COLON).append(to.getUserAtHostPort());\n            if (toTag != null) {\n                retval.append(COLON);\n                retval.append(toTag);\n            }\n        } else {\n            // retval.append(COLON).append(to.getUserAtHostPort());\n            if (toTag != null) {\n                retval.append(COLON);\n                retval.append(toTag);\n            }\n            // retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n        }\n        return retval.toString().toLowerCase();\n    }\n\n    /**\n     * Encode this into a byte array. This is used when the body has been set as a binary array\n     * and you want to encode the body as a byte array for transmission.\n     * \n     * @return a byte array containing the SIPRequest encoded as a byte array.\n     */\n\n    public byte[] encodeAsBytes(String transport) {\n        if (this.isNullRequest()) {\n            // Encoding a null message for keepalive.\n            return \"\\r\\n\\r\\n\".getBytes();\n        } else if ( this.requestLine == null ) {\n            return new byte[0];\n        }\n\n        byte[] rlbytes = null;\n        if (requestLine != null) {\n            try {\n                rlbytes = requestLine.encode().getBytes(\"UTF-8\");\n            } catch (UnsupportedEncodingException ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n        }\n        byte[] superbytes = super.encodeAsBytes(transport);\n        byte[] retval = new byte[rlbytes.length + superbytes.length];\n        System.arraycopy(rlbytes, 0, retval, 0, rlbytes.length);\n        System.arraycopy(superbytes, 0, retval, rlbytes.length, superbytes.length);\n        return retval;\n    }\n\n    /**\n     * Creates a default SIPResponse message for this request. Note You must add the necessary\n     * tags to outgoing responses if need be. For efficiency, this method does not clone the\n     * incoming request. If you want to modify the outgoing response, be sure to clone the\n     * incoming request as the headers are shared and any modification to the headers of the\n     * outgoing response will result in a modification of the incoming request. Tag fields are\n     * just copied from the incoming request. Contact headers are removed from the incoming\n     * request. Added by Jeff Keyser.\n     * \n     * @param statusCode Status code for the response. Reason phrase is generated.\n     * \n     * @return A SIPResponse with the status and reason supplied, and a copy of all the original\n     *         headers from this request.\n     */\n\n    public SIPResponse createResponse(int statusCode) {\n\n        String reasonPhrase = SIPResponse.getReasonPhrase(statusCode);\n        return this.createResponse(statusCode, reasonPhrase);\n\n    }\n\n    /**\n     * Creates a default SIPResponse message for this request. Note You must add the necessary\n     * tags to outgoing responses if need be. For efficiency, this method does not clone the\n     * incoming request. If you want to modify the outgoing response, be sure to clone the\n     * incoming request as the headers are shared and any modification to the headers of the\n     * outgoing response will result in a modification of the incoming request. Tag fields are\n     * just copied from the incoming request. Contact headers are removed from the incoming\n     * request. Added by Jeff Keyser. Route headers are not added to the response.\n     * \n     * @param statusCode Status code for the response.\n     * @param reasonPhrase Reason phrase for this response.\n     * \n     * @return A SIPResponse with the status and reason supplied, and a copy of all the original\n     *         headers from this request except the ones that are not supposed to be part of the\n     *         response .\n     */\n\n    public SIPResponse createResponse(int statusCode, String reasonPhrase) {\n        SIPResponse newResponse;\n        Iterator headerIterator;\n        SIPHeader nextHeader;\n\n        newResponse = new SIPResponse();\n        try {\n            newResponse.setStatusCode(statusCode);\n        } catch (ParseException ex) {\n            throw new IllegalArgumentException(\"Bad code \" + statusCode);\n        }\n        if (reasonPhrase != null)\n            newResponse.setReasonPhrase(reasonPhrase);\n        else\n            newResponse.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode));\n        headerIterator = getHeaders();\n        while (headerIterator.hasNext()) {\n            nextHeader = (SIPHeader) headerIterator.next();\n            if (nextHeader instanceof From\n                    || nextHeader instanceof To\n                    || nextHeader instanceof ViaList\n                    || nextHeader instanceof CallID\n                    || (nextHeader instanceof RecordRouteList && mustCopyRR(statusCode))\n                    || nextHeader instanceof CSeq\n                    // We just copy TimeStamp for all headers (not just 100).\n                    || nextHeader instanceof TimeStamp) {\n\n                try {\n\n                    newResponse.attachHeader((SIPHeader) nextHeader.clone(), false);\n                } catch (SIPDuplicateHeaderException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        if (MessageFactoryImpl.getDefaultServerHeader() != null) {\n            newResponse.setHeader(MessageFactoryImpl.getDefaultServerHeader());\n\n        }\n        if (newResponse.getStatusCode() == 100) {\n            // Trying is never supposed to have the tag parameter set.\n            newResponse.getTo().removeParameter(\"tag\");\n\n        }\n        ServerHeader server = MessageFactoryImpl.getDefaultServerHeader();\n        if (server != null) {\n            newResponse.setHeader(server);\n        }\n        return newResponse;\n    }\n\n    // Helper method for createResponse, to avoid copying Record-Route unless needed\n    private final boolean mustCopyRR( int code ) {\n    \t// Only for 1xx-2xx, not for 100 or errors\n    \tif ( code>100 && code<300 ) {\n    \t\treturn isDialogCreating( this.getMethod() ) && getToTag() == null;\n    \t} else return false;\n    }\n    \n    /**\n     * Creates a default SIPResquest message that would cancel this request. Note that tag\n     * assignment and removal of is left to the caller (we use whatever tags are present in the\n     * original request).\n     * \n     * @return A CANCEL SIPRequest constructed according to RFC3261 section 9.1\n     * \n     * @throws SipException\n     * @throws ParseException\n     */\n    public SIPRequest createCancelRequest() throws SipException {\n\n        // see RFC3261 9.1\n\n        // A CANCEL request SHOULD NOT be sent to cancel a request other than\n        // INVITE\n\n        if (!this.getMethod().equals(Request.INVITE))\n            throw new SipException(\"Attempt to create CANCEL for \" + this.getMethod());\n\n        /*\n         * The following procedures are used to construct a CANCEL request. The Request-URI,\n         * Call-ID, To, the numeric part of CSeq, and From header fields in the CANCEL request\n         * MUST be identical to those in the request being cancelled, including tags. A CANCEL\n         * constructed by a client MUST have only a single Via header field value matching the top\n         * Via value in the request being cancelled. Using the same values for these header fields\n         * allows the CANCEL to be matched with the request it cancels (Section 9.2 indicates how\n         * such matching occurs). However, the method part of the CSeq header field MUST have a\n         * value of CANCEL. This allows it to be identified and processed as a transaction in its\n         * own right (See Section 17).\n         */\n        SIPRequest cancel = new SIPRequest();\n        cancel.setRequestLine((RequestLine) this.requestLine.clone());\n        cancel.setMethod(Request.CANCEL);\n        cancel.setHeader((Header) this.callIdHeader.clone());\n        cancel.setHeader((Header) this.toHeader.clone());\n        cancel.setHeader((Header) cSeqHeader.clone());\n        try {\n            cancel.getCSeq().setMethod(Request.CANCEL);\n        } catch (ParseException e) {\n            e.printStackTrace(); // should not happen\n        }\n        cancel.setHeader((Header) this.fromHeader.clone());\n\n        cancel.addFirst((Header) this.getTopmostVia().clone());\n        cancel.setHeader((Header) this.maxForwardsHeader.clone());\n\n        /*\n         * If the request being cancelled contains a Route header field, the CANCEL request MUST\n         * include that Route header field's values.\n         */\n        if (this.getRouteHeaders() != null) {\n            cancel.setHeader((SIPHeaderList< ? >) this.getRouteHeaders().clone());\n        }\n        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {\n            cancel.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n\n        }\n        return cancel;\n    }\n\n    /**\n     * Creates a default ACK SIPRequest message for this original request. Note that the\n     * defaultACK SIPRequest does not include the content of the original SIPRequest. If\n     * responseToHeader is null then the toHeader of this request is used to construct the ACK.\n     * Note that tag fields are just copied from the original SIP Request. Added by Jeff Keyser.\n     * \n     * @param responseToHeader To header to use for this request.\n     * \n     * @return A SIPRequest with an ACK method.\n     */\n    public SIPRequest createAckRequest(To responseToHeader) {\n        SIPRequest newRequest;\n        Iterator headerIterator;\n        SIPHeader nextHeader;\n\n        newRequest = new SIPRequest();\n        newRequest.setRequestLine((RequestLine) this.requestLine.clone());\n        newRequest.setMethod(Request.ACK);\n        headerIterator = getHeaders();\n        while (headerIterator.hasNext()) {\n            nextHeader = (SIPHeader) headerIterator.next();\n            if (nextHeader instanceof RouteList) {\n                // Ack and cancel do not get ROUTE headers.\n                // Route header for ACK is assigned by the\n                // Dialog if necessary.\n                continue;\n            } else if (nextHeader instanceof ProxyAuthorization) {\n                // Remove proxy auth header.\n                // Assigned by the Dialog if necessary.\n                continue;\n            } else if (nextHeader instanceof ContentLength) {\n                // Adding content is responsibility of user.\n                nextHeader = (SIPHeader) nextHeader.clone();\n                try {\n                    ((ContentLength) nextHeader).setContentLength(0);\n                } catch (InvalidArgumentException e) {\n                }\n            } else if (nextHeader instanceof ContentType) {\n                // Content type header is removed since\n                // content length is 0.\n                continue;\n            } else if (nextHeader instanceof CSeq) {\n                // The CSeq header field in the\n                // ACK MUST contain the same value for the\n                // sequence number as was present in the\n                // original request, but the method parameter\n                // MUST be equal to \"ACK\".\n                CSeq cseq = (CSeq) nextHeader.clone();\n                try {\n                    cseq.setMethod(Request.ACK);\n                } catch (ParseException e) {\n                }\n                nextHeader = cseq;\n            } else if (nextHeader instanceof To) {\n                if (responseToHeader != null) {\n                    nextHeader = responseToHeader;\n                } else {\n                    nextHeader = (SIPHeader) nextHeader.clone();\n                }\n            } else if (nextHeader instanceof ContactList || nextHeader instanceof Expires) {\n                // CONTACT header does not apply for ACK requests.\n                continue;\n            } else if (nextHeader instanceof ViaList) {\n                // Bug reported by Gianluca Martinello\n                // The ACK MUST contain a single Via header field,\n                // and this MUST be equal to the top Via header\n                // field of the original\n                // request.\n\n                nextHeader = (SIPHeader) ((ViaList) nextHeader).getFirst().clone();\n            } else {\n                nextHeader = (SIPHeader) nextHeader.clone();\n            }\n\n            try {\n                newRequest.attachHeader(nextHeader, false);\n            } catch (SIPDuplicateHeaderException e) {\n                e.printStackTrace();\n            }\n        }\n        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {\n            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n\n        }\n        return newRequest;\n    }\n\n    /**\n     * Creates an ACK for non-2xx responses according to RFC3261 17.1.1.3\n     * \n     * @return A SIPRequest with an ACK method.\n     * @throws SipException\n     * @throws NullPointerException\n     * @throws ParseException\n     * \n     * @author jvb\n     */\n    public final SIPRequest createErrorAck(To responseToHeader) throws SipException,\n            ParseException {\n\n        /*\n         * The ACK request constructed by the client transaction MUST contain values for the\n         * Call-ID, From, and Request-URI that are equal to the values of those header fields in\n         * the request passed to the transport by the client transaction (call this the \"original\n         * request\"). The To header field in the ACK MUST equal the To header field in the\n         * response being acknowledged, and therefore will usually differ from the To header field\n         * in the original request by the addition of the tag parameter. The ACK MUST contain a\n         * single Via header field, and this MUST be equal to the top Via header field of the\n         * original request. The CSeq header field in the ACK MUST contain the same value for the\n         * sequence number as was present in the original request, but the method parameter MUST\n         * be equal to \"ACK\".\n         */\n        SIPRequest newRequest = new SIPRequest();\n        newRequest.setRequestLine((RequestLine) this.requestLine.clone());\n        newRequest.setMethod(Request.ACK);\n        newRequest.setHeader((Header) this.callIdHeader.clone());\n        newRequest.setHeader((Header) this.maxForwardsHeader.clone()); // ISSUE\n        // 130\n        // fix\n        newRequest.setHeader((Header) this.fromHeader.clone());\n        newRequest.setHeader((Header) responseToHeader.clone());\n        newRequest.addFirst((Header) this.getTopmostVia().clone());\n        newRequest.setHeader((Header) cSeqHeader.clone());\n        newRequest.getCSeq().setMethod(Request.ACK);\n\n        /*\n         * If the INVITE request whose response is being acknowledged had Route header fields,\n         * those header fields MUST appear in the ACK. This is to ensure that the ACK can be\n         * routed properly through any downstream stateless proxies.\n         */\n        if (this.getRouteHeaders() != null) {\n            newRequest.setHeader((SIPHeaderList) this.getRouteHeaders().clone());\n        }\n        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {\n            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n\n        }\n        return newRequest;\n    }\n\n    /**\n     * Create a new default SIPRequest from the original request. Warning: the newly created\n     * SIPRequest, shares the headers of this request but we generate any new headers that we need\n     * to modify so the original request is umodified. However, if you modify the shared headers\n     * after this request is created, then the newly created request will also be modified. If you\n     * want to modify the original request without affecting the returned Request make sure you\n     * clone it before calling this method.\n     * \n     * Only required headers are copied.\n     * <ul>\n     * <li> Contact headers are not included in the newly created request. Setting the appropriate\n     * sequence number is the responsibility of the caller. </li>\n     * <li> RouteList is not copied for ACK and CANCEL </li>\n     * <li> Note that we DO NOT copy the body of the argument into the returned header. We do not\n     * copy the content type header from the original request either. These have to be added\n     * seperately and the content length has to be correctly set if necessary the content length\n     * is set to 0 in the returned header. </li>\n     * <li>Contact List is not copied from the original request.</li>\n     * <li>RecordRoute List is not included from original request. </li>\n     * <li>Via header is not included from the original request. </li>\n     * </ul>\n     * \n     * @param requestLine is the new request line.\n     * \n     * @param switchHeaders is a boolean flag that causes to and from headers to switch (set this\n     *        to true if you are the server of the transaction and are generating a BYE request).\n     *        If the headers are switched, we generate new From and To headers otherwise we just\n     *        use the incoming headers.\n     * \n     * @return a new Default SIP Request which has the requestLine specified.\n     * \n     */\n    public SIPRequest createSIPRequest(RequestLine requestLine, boolean switchHeaders) {\n        SIPRequest newRequest = new SIPRequest();\n        newRequest.requestLine = requestLine;\n        Iterator<SIPHeader> headerIterator = this.getHeaders();\n        while (headerIterator.hasNext()) {\n            SIPHeader nextHeader = (SIPHeader) headerIterator.next();\n            // For BYE and cancel set the CSeq header to the\n            // appropriate method.\n            if (nextHeader instanceof CSeq) {\n                CSeq newCseq = (CSeq) nextHeader.clone();\n                nextHeader = newCseq;\n                try {\n                    newCseq.setMethod(requestLine.getMethod());\n                } catch (ParseException e) {\n                }\n            } else if (nextHeader instanceof ViaList) {\n                Via via = (Via) (((ViaList) nextHeader).getFirst().clone());\n                via.removeParameter(\"branch\");\n                nextHeader = via;\n                // Cancel and ACK preserve the branch ID.\n            } else if (nextHeader instanceof To) {\n                To to = (To) nextHeader;\n                if (switchHeaders) {\n                    nextHeader = new From(to);\n                    ((From) nextHeader).removeTag();\n                } else {\n                    nextHeader = (SIPHeader) to.clone();\n                    ((To) nextHeader).removeTag();\n                }\n            } else if (nextHeader instanceof From) {\n                From from = (From) nextHeader;\n                if (switchHeaders) {\n                    nextHeader = new To(from);\n                    ((To) nextHeader).removeTag();\n                } else {\n                    nextHeader = (SIPHeader) from.clone();\n                    ((From) nextHeader).removeTag();\n                }\n            } else if (nextHeader instanceof ContentLength) {\n                ContentLength cl = (ContentLength) nextHeader.clone();\n                try {\n                    cl.setContentLength(0);\n                } catch (InvalidArgumentException e) {\n                }\n                nextHeader = cl;\n            } else if (!(nextHeader instanceof CallID) && !(nextHeader instanceof MaxForwards)) {\n                // Route is kept by dialog.\n                // RR is added by the caller.\n                // Contact is added by the Caller\n                // Any extension headers must be added\n                // by the caller.\n                continue;\n            }\n            try {\n                newRequest.attachHeader(nextHeader, false);\n            } catch (SIPDuplicateHeaderException e) {\n                e.printStackTrace();\n            }\n        }\n        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {\n            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n\n        }\n        return newRequest;\n\n    }\n\n    /**\n     * Create a BYE request from this request.\n     * \n     * @param switchHeaders is a boolean flag that causes from and isServerTransaction to headers\n     *        to be swapped. Set this to true if you are the server of the dialog and are\n     *        generating a BYE request for the dialog.\n     * @return a new default BYE request.\n     */\n    public SIPRequest createBYERequest(boolean switchHeaders) {\n        RequestLine requestLine = (RequestLine) this.requestLine.clone();\n        requestLine.setMethod(\"BYE\");\n        return this.createSIPRequest(requestLine, switchHeaders);\n    }\n\n    /**\n     * Create an ACK request from this request. This is suitable for generating an ACK for an\n     * INVITE client transaction.\n     * \n     * @return an ACK request that is generated from this request.\n     */\n    public SIPRequest createACKRequest() {\n        RequestLine requestLine = (RequestLine) this.requestLine.clone();\n        requestLine.setMethod(Request.ACK);\n        return this.createSIPRequest(requestLine, false);\n    }\n\n    /**\n     * Get the host from the topmost via header.\n     * \n     * @return the string representation of the host from the topmost via header.\n     */\n    public String getViaHost() {\n        Via via = (Via) this.getViaHeaders().getFirst();\n        return via.getHost();\n\n    }\n\n    /**\n     * Get the port from the topmost via header.\n     * \n     * @return the port from the topmost via header (5060 if there is no port indicated).\n     */\n    public int getViaPort() {\n        Via via = (Via) this.getViaHeaders().getFirst();\n        if (via.hasPort())\n            return via.getPort();\n        else\n            return 5060;\n    }\n\n    /**\n     * Get the first line encoded.\n     * \n     * @return a string containing the encoded request line.\n     */\n    public String getFirstLine() {\n        if (requestLine == null)\n            return null;\n        else\n            return this.requestLine.encode();\n    }\n\n    /**\n     * Set the sip version.\n     * \n     * @param sipVersion the sip version to set.\n     */\n    public void setSIPVersion(String sipVersion) throws ParseException {\n        if (sipVersion == null || !sipVersion.equalsIgnoreCase(\"SIP/2.0\"))\n            throw new ParseException(\"sipVersion\", 0);\n        this.requestLine.setSipVersion(sipVersion);\n    }\n\n    /**\n     * Get the SIP version.\n     * \n     * @return the SIP version from the request line.\n     */\n    public String getSIPVersion() {\n        return this.requestLine.getSipVersion();\n    }\n\n    /**\n     * Book keeping method to return the current tx for the request if one exists.\n     * \n     * @return the assigned tx.\n     */\n    public Object getTransaction() {\n        // Return an opaque pointer to the transaction object.\n        // This is for consistency checking and quick lookup.\n        return this.transactionPointer;\n    }\n\n    /**\n     * Book keeping field to set the current tx for the request.\n     * \n     * @param transaction\n     */\n    public void setTransaction(Object transaction) {\n        this.transactionPointer = transaction;\n    }\n\n    /**\n     * Book keeping method to get the messasge channel for the request.\n     * \n     * @return the message channel for the request.\n     */\n\n    public Object getMessageChannel() {\n        // return opaque ptr to the message chanel on\n        // which the message was recieved. For consistency\n        // checking and lookup.\n        return this.messageChannel;\n    }\n\n    /**\n     * Set the message channel for the request ( bookkeeping field ).\n     * \n     * @param messageChannel\n     */\n\n    public void setMessageChannel(Object messageChannel) {\n        this.messageChannel = messageChannel;\n    }\n\n    /**\n     * Generates an Id for checking potentially merged requests.\n     * \n     * @return String to check for merged requests\n     */\n    public String getMergeId() {\n        /*\n         * generate an identifier from the From tag, Call-ID, and CSeq\n         */\n        String fromTag = this.getFromTag();\n        String cseq = this.cSeqHeader.toString();\n        String callId = this.callIdHeader.getCallId();\n        /* NOTE : The RFC does NOT specify you need to include a Request URI \n         * This is added here for the case of Back to Back User Agents.\n         */\n        String requestUri = this.getRequestURI().toString();\n\n        if (fromTag != null) {\n            return new StringBuffer().append(requestUri).append(\":\").append(fromTag).append(\":\").append(cseq).append(\":\")\n                    .append(callId).toString();\n        } else\n            return null;\n\n    }\n\n    /**\n     * @param inviteTransaction the inviteTransaction to set\n     */\n    public void setInviteTransaction(Object inviteTransaction) {\n        this.inviteTransaction = inviteTransaction;\n    }\n\n    /**\n     * @return the inviteTransaction\n     */\n    public Object getInviteTransaction() {\n        return inviteTransaction;\n    }\n\n   \n   \n    \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/message/SIPResponse.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.message;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.Utils;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.header.CSeq;\nimport gov2.nist.javax2.sip.header.CallID;\nimport gov2.nist.javax2.sip.header.ContactList;\nimport gov2.nist.javax2.sip.header.ContentLength;\nimport gov2.nist.javax2.sip.header.ContentType;\nimport gov2.nist.javax2.sip.header.From;\nimport gov2.nist.javax2.sip.header.MaxForwards;\nimport gov2.nist.javax2.sip.header.ReasonList;\nimport gov2.nist.javax2.sip.header.RecordRouteList;\nimport gov2.nist.javax2.sip.header.RequireList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.StatusLine;\nimport gov2.nist.javax2.sip.header.To;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.header.extensions.SessionExpires;\n\nimport java.io.UnsupportedEncodingException;\nimport java.text.ParseException;\nimport java.util.Iterator;\nimport java.util.LinkedList;\n\nimport javax2.sip.header.ReasonHeader;\nimport javax2.sip.header.ServerHeader;\nimport javax2.sip.message.Request;\n\n\n/**\n * SIP Response structure.\n *\n * @version 1.2 $Revision: 1.29 $ $Date: 2009/10/25 03:07:52 $\n * @since 1.1\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic final class SIPResponse\n    extends SIPMessage\n    implements javax2.sip.message.Response, ResponseExt {\n    protected StatusLine statusLine;\n\n    public static String getReasonPhrase(int rc) {\n        String retval = null;\n        switch (rc) {\n\n            case TRYING :\n                retval = \"Trying\";\n                break;\n\n            case RINGING :\n                retval = \"Ringing\";\n                break;\n\n            case CALL_IS_BEING_FORWARDED :\n                retval = \"Call is being forwarded\";\n                break;\n\n            case QUEUED :\n                retval = \"Queued\";\n                break;\n\n            case SESSION_PROGRESS :\n                retval = \"Session progress\";\n                break;\n\n            case OK :\n                retval = \"OK\";\n                break;\n\n            case ACCEPTED :\n                retval = \"Accepted\";\n                break;\n\n            case MULTIPLE_CHOICES :\n                retval = \"Multiple choices\";\n                break;\n\n            case MOVED_PERMANENTLY :\n                retval = \"Moved permanently\";\n                break;\n\n            case MOVED_TEMPORARILY :\n                retval = \"Moved Temporarily\";\n                break;\n\n            case USE_PROXY :\n                retval = \"Use proxy\";\n                break;\n\n            case ALTERNATIVE_SERVICE :\n                retval = \"Alternative service\";\n                break;\n\n            case BAD_REQUEST :\n                retval = \"Bad request\";\n                break;\n\n            case UNAUTHORIZED :\n                retval = \"Unauthorized\";\n                break;\n\n            case PAYMENT_REQUIRED :\n                retval = \"Payment required\";\n                break;\n\n            case FORBIDDEN :\n                retval = \"Forbidden\";\n                break;\n\n            case NOT_FOUND :\n                retval = \"Not found\";\n                break;\n\n            case METHOD_NOT_ALLOWED :\n                retval = \"Method not allowed\";\n                break;\n\n            case NOT_ACCEPTABLE :\n                retval = \"Not acceptable\";\n                break;\n\n            case PROXY_AUTHENTICATION_REQUIRED :\n                retval = \"Proxy Authentication required\";\n                break;\n\n            case REQUEST_TIMEOUT :\n                retval = \"Request timeout\";\n                break;\n\n            case GONE :\n                retval = \"Gone\";\n                break;\n\n            case TEMPORARILY_UNAVAILABLE :\n                retval = \"Temporarily Unavailable\";\n                break;\n\n            case REQUEST_ENTITY_TOO_LARGE :\n                retval = \"Request entity too large\";\n                break;\n\n            case REQUEST_URI_TOO_LONG :\n                retval = \"Request-URI too large\";\n                break;\n\n            case UNSUPPORTED_MEDIA_TYPE :\n                retval = \"Unsupported media type\";\n                break;\n\n            case UNSUPPORTED_URI_SCHEME :\n                retval = \"Unsupported URI Scheme\";\n                break;\n\n            case BAD_EXTENSION :\n                retval = \"Bad extension\";\n                break;\n\n            case EXTENSION_REQUIRED :\n                retval = \"Etension Required\";\n                break;\n\n            case INTERVAL_TOO_BRIEF :\n                retval = \"Interval too brief\";\n                break;\n\n            case CALL_OR_TRANSACTION_DOES_NOT_EXIST :\n                retval = \"Call leg/Transaction does not exist\";\n                break;\n\n            case LOOP_DETECTED :\n                retval = \"Loop detected\";\n                break;\n\n            case TOO_MANY_HOPS :\n                retval = \"Too many hops\";\n                break;\n\n            case ADDRESS_INCOMPLETE :\n                retval = \"Address incomplete\";\n                break;\n\n            case AMBIGUOUS :\n                retval = \"Ambiguous\";\n                break;\n\n            case BUSY_HERE :\n                retval = \"Busy here\";\n                break;\n\n            case REQUEST_TERMINATED :\n                retval = \"Request Terminated\";\n                break;\n\n            //Issue 168, Typo fix reported by fre on the retval\n            case NOT_ACCEPTABLE_HERE :\n                retval = \"Not Acceptable here\";\n                break;\n\n            case BAD_EVENT :\n                retval = \"Bad Event\";\n                break;\n\n            case REQUEST_PENDING :\n                retval = \"Request Pending\";\n                break;\n\n            case SERVER_INTERNAL_ERROR :\n                retval = \"Server Internal Error\";\n                break;\n\n            case UNDECIPHERABLE :\n                retval = \"Undecipherable\";\n                break;\n\n            case NOT_IMPLEMENTED :\n                retval = \"Not implemented\";\n                break;\n\n            case BAD_GATEWAY :\n                retval = \"Bad gateway\";\n                break;\n\n            case SERVICE_UNAVAILABLE :\n                retval = \"Service unavailable\";\n                break;\n\n            case SERVER_TIMEOUT :\n                retval = \"Gateway timeout\";\n                break;\n\n            case VERSION_NOT_SUPPORTED :\n                retval = \"SIP version not supported\";\n                break;\n\n            case MESSAGE_TOO_LARGE :\n                retval = \"Message Too Large\";\n                break;\n\n            case BUSY_EVERYWHERE :\n                retval = \"Busy everywhere\";\n                break;\n\n            case DECLINE :\n                retval = \"Decline\";\n                break;\n\n            case DOES_NOT_EXIST_ANYWHERE :\n                retval = \"Does not exist anywhere\";\n                break;\n\n            case SESSION_NOT_ACCEPTABLE :\n                retval = \"Session Not acceptable\";\n                break;\n\n            case CONDITIONAL_REQUEST_FAILED:\n                retval = \"Conditional request failed\";\n                break;\n\n            default :\n                retval = \"Unknown Status\";\n\n        }\n        return retval;\n\n    }\n\n    /** set the status code.\n     *@param statusCode is the status code to set.\n     *@throws IlegalArgumentException if invalid status code.\n     */\n    public void setStatusCode(int statusCode) throws ParseException {\n\n      // RFC3261 defines statuscode as 3DIGIT, 606 is the highest officially\n      // defined code but extensions may add others (in theory up to 999,\n      // but in practice up to 699 since the 6xx range is defined as 'final error')\n        if (statusCode < 100 || statusCode > 699)\n            throw new ParseException(\"bad status code\", 0);\n        if (this.statusLine == null)\n            this.statusLine = new StatusLine();\n        this.statusLine.setStatusCode(statusCode);\n    }\n\n    /**\n     * Get the status line of the response.\n     *@return StatusLine\n     */\n    public StatusLine getStatusLine() {\n        return statusLine;\n    }\n\n    /** Get the staus code (conveniance function).\n     *@return the status code of the status line.\n     */\n    public int getStatusCode() {\n        return statusLine.getStatusCode();\n    }\n\n    /** Set the reason phrase.\n     *@param reasonPhrase the reason phrase.\n     *@throws IllegalArgumentException if null string\n     */\n    public void setReasonPhrase(String reasonPhrase) {\n        if (reasonPhrase == null)\n            throw new IllegalArgumentException(\"Bad reason phrase\");\n        if (this.statusLine == null)\n            this.statusLine = new StatusLine();\n        this.statusLine.setReasonPhrase(reasonPhrase);\n    }\n\n    /** Get the reason phrase.\n     *@return the reason phrase.\n     */\n    public String getReasonPhrase() {\n        if (statusLine == null || statusLine.getReasonPhrase() == null)\n            return \"\";\n        else\n            return statusLine.getReasonPhrase();\n    }\n\n    /** Return true if the response is a final response.\n     *@param rc is the return code.\n     *@return true if the parameter is between the range 200 and 700.\n     */\n    public static boolean isFinalResponse(int rc) {\n        return rc >= 200 && rc < 700;\n    }\n\n    /** Is this a final response?\n     *@return true if this is a final response.\n     */\n    public boolean isFinalResponse() {\n        return isFinalResponse(statusLine.getStatusCode());\n    }\n\n    /**\n     * Set the status line field.\n     *@param sl Status line to set.\n     */\n    public void setStatusLine(StatusLine sl) {\n        statusLine = sl;\n    }\n\n    /** Constructor.\n     */\n    public SIPResponse() {\n        super();\n    }\n    /**\n     * Print formatting function.\n     *Indent and parenthesize for pretty printing.\n     * Note -- use the encode method for formatting the message.\n     * Hack here to XMLize.\n     *\n     *@return a string for pretty printing.\n     */\n    public String debugDump() {\n        String superstring = super.debugDump();\n        stringRepresentation = \"\";\n        sprint(SIPResponse.class.getCanonicalName());\n        sprint(\"{\");\n        if (statusLine != null) {\n            sprint(statusLine.debugDump());\n        }\n        sprint(superstring);\n        sprint(\"}\");\n        return stringRepresentation;\n    }\n\n    /**\n     * Check the response structure. Must have from, to CSEQ and VIA\n     * headers.\n     */\n    public void checkHeaders() throws ParseException {\n        if (getCSeq() == null) {\n            throw new ParseException(CSeq.NAME+ \" Is missing \", 0);\n        }\n        if (getTo() == null) {\n            throw new ParseException(To.NAME+ \" Is missing \", 0);\n        }\n        if (getFrom() == null) {\n            throw new ParseException(From.NAME+ \" Is missing \", 0);\n        }\n        if (getViaHeaders() == null) {\n            throw new ParseException(Via.NAME+ \" Is missing \", 0);\n        }\n        if (getCallId() == null) {\n            throw new ParseException(CallID.NAME + \" Is missing \", 0);\n        }\n\n\n        if (getStatusCode() > 699) {\n            throw new ParseException(\"Unknown error code!\" + getStatusCode(), 0);\n        }\n\n    }\n\n    /**\n     *  Encode the SIP Request as a string.\n     *@return The string encoded canonical form of the message.\n     */\n\n    public String encode() {\n        String retval;\n        if (statusLine != null)\n            retval = statusLine.encode() + super.encode();\n        else\n            retval = super.encode();\n        return retval ;\n    }\n\n    /** Encode the message except for the body.\n    *\n    *@return The string except for the body.\n    */\n\n    public String encodeMessage() {\n        String retval;\n        if (statusLine != null)\n            retval = statusLine.encode() + super.encodeSIPHeaders();\n        else\n            retval = super.encodeSIPHeaders();\n        return retval ;\n    }\n\n\n\n    /** Get this message as a list of encoded strings.\n     *@return LinkedList containing encoded strings for each header in\n     *   the message.\n     */\n\n    public LinkedList getMessageAsEncodedStrings() {\n        LinkedList retval = super.getMessageAsEncodedStrings();\n\n        if (statusLine != null)\n            retval.addFirst(statusLine.encode());\n        return retval;\n\n    }\n\n    /**\n     * Make a clone (deep copy) of this object.\n     *@return a deep copy of this object.\n     */\n\n    public Object clone() {\n        SIPResponse retval = (SIPResponse) super.clone();\n        if (this.statusLine != null)\n            retval.statusLine = (StatusLine) this.statusLine.clone();\n        return retval;\n    }\n\n\n    /**\n     * Compare for equality.\n     *@param other other object to compare with.\n     */\n    public boolean equals(Object other) {\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        SIPResponse that = (SIPResponse) other;\n        return statusLine.equals(that.statusLine) && super.equals(other);\n    }\n\n    /**\n     * Match with a template.\n     *@param matchObj template object to match ourselves with (null\n     * in any position in the template object matches wildcard)\n     */\n    public boolean match(Object matchObj) {\n        if (matchObj == null)\n            return true;\n        else if (!matchObj.getClass().equals(this.getClass())) {\n            return false;\n        } else if (matchObj == this)\n            return true;\n        SIPResponse that = (SIPResponse) matchObj;\n\n        StatusLine rline = that.statusLine;\n        if (this.statusLine == null && rline != null)\n            return false;\n        else if (this.statusLine == rline)\n            return super.match(matchObj);\n        else {\n\n            return statusLine.match(that.statusLine) && super.match(matchObj);\n        }\n\n    }\n\n    /** Encode this into a byte array.\n     * This is used when the body has been set as a binary array\n     * and you want to encode the body as a byte array for transmission.\n     *\n     *@return a byte array containing the SIPRequest encoded as a byte\n     *  array.\n     */\n\n    public byte[] encodeAsBytes( String transport ) {\n        byte[] slbytes = null;\n        if (statusLine != null) {\n            try {\n                slbytes = statusLine.encode().getBytes(\"UTF-8\");\n            } catch (UnsupportedEncodingException ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n        }\n        byte[] superbytes = super.encodeAsBytes( transport );\n        byte[] retval = new byte[slbytes.length + superbytes.length];\n        System.arraycopy(slbytes, 0, retval, 0, slbytes.length);\n        System.arraycopy(superbytes, 0, retval, slbytes.length,\n                superbytes.length);\n        return retval;\n    }\n\n\n\n    /** Get a dialog identifier.\n     * Generates a string that can be used as a dialog identifier.\n     *\n     * @param isServer is set to true if this is the UAS\n     * and set to false if this is the UAC\n     */\n    public String getDialogId(boolean isServer) {\n        CallID cid = (CallID) this.getCallId();\n        From from = (From) this.getFrom();\n        To to = (To) this.getTo();\n        StringBuffer retval = new StringBuffer(cid.getCallId());\n        if (!isServer) {\n            //retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n            //retval.append(COLON).append(to.getUserAtHostPort());\n            if (to.getTag() != null) {\n                retval.append(COLON);\n                retval.append(to.getTag());\n            }\n        } else {\n            //retval.append(COLON).append(to.getUserAtHostPort());\n            if (to.getTag() != null) {\n                retval.append(COLON);\n                retval.append(to.getTag());\n            }\n            //retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n        }\n        return retval.toString().toLowerCase();\n    }\n\n    public String getDialogId(boolean isServer, String toTag) {\n        CallID cid = (CallID) this.getCallId();\n        From from = (From) this.getFrom();\n        StringBuffer retval = new StringBuffer(cid.getCallId());\n        if (!isServer) {\n            //retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n            //retval.append(COLON).append(to.getUserAtHostPort());\n            if (toTag != null) {\n                retval.append(COLON);\n                retval.append(toTag);\n            }\n        } else {\n            //retval.append(COLON).append(to.getUserAtHostPort());\n            if (toTag != null) {\n                retval.append(COLON);\n                retval.append(toTag);\n            }\n            //retval.append(COLON).append(from.getUserAtHostPort());\n            if (from.getTag() != null) {\n                retval.append(COLON);\n                retval.append(from.getTag());\n            }\n        }\n        return retval.toString().toLowerCase();\n    }\n\n    /**\n     * Sets the Via branch for CANCEL or ACK requests\n     *\n     * @param via\n     * @param method\n     * @throws ParseException\n     */\n    private final void setBranch( Via via, String method ) {\n        String branch;\n        if (method.equals( Request.ACK ) ) {\n            if (statusLine.getStatusCode() >= 300 ) {\n                branch = getTopmostVia().getBranch();   // non-2xx ACK uses same branch\n            } else {\n                branch = Utils.getInstance().generateBranchId();    // 2xx ACK gets new branch\n            }\n        } else if (method.equals( Request.CANCEL )) {\n            branch = getTopmostVia().getBranch();   // CANCEL uses same branch\n        } else return;\n\n        try {\n            via.setBranch( branch );\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    /**\n     * Get the encoded first line.\n     *\n     *@return the status line encoded.\n     *\n     */\n    public String getFirstLine() {\n        if (this.statusLine == null)\n            return null;\n        else\n            return this.statusLine.encode();\n    }\n\n    public void setSIPVersion(String sipVersion) {\n        this.statusLine.setSipVersion(sipVersion);\n    }\n\n    public String getSIPVersion() {\n        return this.statusLine.getSipVersion();\n    }\n\n    public String toString() {\n        if (statusLine == null) return  \"\";\n        else return statusLine.encode() + super.encode();\n    }\n\n    /**\n     * Generate a request from a response.\n     *\n     * @param requestURI -- the request URI to assign to the request.\n     * @param via -- the Via header to assign to the request\n     * @param cseq -- the CSeq header to assign to the request\n     * @param from -- the From header to assign to the request\n     * @param to -- the To header to assign to the request\n     * @return -- the newly generated sip request.\n     */\n    public SIPRequest createRequest(SipUri requestURI, Via via, CSeq cseq, From from, To to) {\n        SIPRequest newRequest = new SIPRequest();\n        String method = cseq.getMethod();\n\n        newRequest.setMethod(method);\n        newRequest.setRequestURI(requestURI);\n        this.setBranch( via, method );\n        newRequest.setHeader(via);\n        newRequest.setHeader(cseq);\n        // aligned with NIST version 1.2\n        newRequest.setHeader(from);\n        newRequest.setHeader(to);\n        newRequest.setHeader(getCallId());\n\n        try {\n          // JvB: all requests need a Max-Forwards\n          newRequest.attachHeader( new MaxForwards(70), false);\n        } catch (Exception d) {\n\n        }\n\n        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {\n            newRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n        }\n        return newRequest;\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AcceptEncodingParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Accept-Encoding SIP (HTTP) Header parser.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:56 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n *\n * <pre>\n *\n *   The Accept-Encoding request-header field is similar to Accept, but\n *   restricts the content-codings (section 3.5) that are acceptable in\n *   the response.\n *\n *\n *       Accept-Encoding  = \"Accept-Encoding\" \":\"\n *                      ( encoding *( \",\" encoding) )\n *       encoding         = ( codings *[ \";\" \"q\" \"=\" qvalue ] )\n *       codings          = ( content-coding | \"*\" )\n *\n *   Examples of its use are:\n *\n *       Accept-Encoding: compress, gzip\n *       Accept-Encoding:\n *       Accept-Encoding: *\n *       Accept-Encoding: compress;q=0.5, gzip;q=1.0\n *       Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0\n * </pre>\n *\n */\npublic class AcceptEncodingParser extends HeaderParser {\n\n    /**\n     * Constructor\n     * @param acceptEncoding message to parse\n     */\n    public AcceptEncodingParser(String acceptEncoding) {\n        super(acceptEncoding);\n    }\n\n    /**\n     * Constructor\n     * @param lexer Lexer to set\n     */\n    protected AcceptEncodingParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (AcceptEncoding object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        AcceptEncodingList acceptEncodingList = new AcceptEncodingList();\n        if (debug)\n            dbg_enter(\"AcceptEncodingParser.parse\");\n\n        try {\n            headerName(TokenTypes.ACCEPT_ENCODING);\n            // empty body is fine for this header.\n            if (lexer.lookAhead(0) == '\\n') {\n                AcceptEncoding acceptEncoding = new AcceptEncoding();\n                acceptEncodingList.add(acceptEncoding);\n            } else {\n                while (lexer.lookAhead(0) != '\\n') {\n                    AcceptEncoding acceptEncoding = new AcceptEncoding();\n                    if (lexer.lookAhead(0) != ';') {\n                        // Content-Coding:\n                        lexer.match(TokenTypes.ID);\n                        Token value = lexer.getNextToken();\n                        acceptEncoding.setEncoding(value.getTokenValue());\n                    }\n\n                    while (lexer.lookAhead(0) == ';') {\n                        this.lexer.match(';');\n                        this.lexer.SPorHT();\n                        this.lexer.match('q');\n                        this.lexer.SPorHT();\n                        this.lexer.match('=');\n                        this.lexer.SPorHT();\n                        lexer.match(TokenTypes.ID);\n                        Token value = lexer.getNextToken();\n                        try {\n                            float qv = Float.parseFloat(value.getTokenValue());\n                            acceptEncoding.setQValue(qv);\n                        } catch (NumberFormatException ex) {\n                            throw createParseException(ex.getMessage());\n                        } catch (InvalidArgumentException ex) {\n                            throw createParseException(ex.getMessage());\n                        }\n                        this.lexer.SPorHT();\n                    }\n\n                    acceptEncodingList.add(acceptEncoding);\n                    if (lexer.lookAhead(0) == ',') {\n                        this.lexer.match(',');\n                        this.lexer.SPorHT();\n                    }\n\n                }\n            }\n            return acceptEncodingList;\n        } finally {\n            if (debug)\n                dbg_leave(\"AcceptEncodingParser.parse\");\n        }\n    }\n}\n/*\n * $Log: AcceptEncodingParser.java,v $\n * Revision 1.7  2009/07/17 18:57:56  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:03  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AcceptLanguageParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*\n * AcceptLanguageParser.java\n *\n * Created on June 10, 2002, 3:31 PM\n */\n\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport javax2.sip.*;\n\nimport java.text.ParseException;\n\n\n/**\n * Parser for Accept Language Headers.\n *\n * Accept Language body.\n * <pre>\n *\n * Accept-Language = \"Accept-Language\" \":\"\n *                         1#( language-range [ \";\" \"q\" \"=\" qvalue ] )\n *       language-range  = ( ( 1*8ALPHA *( \"-\" 1*8ALPHA ) ) | \"*\" )\n *\n * HTTP RFC 2616 Section 14.4\n * </pre>\n *\n *  Accept-Language: da, en-gb;q=0.8, en;q=0.7\n *\n * @see AcceptLanguageList\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:56 $\n *\n * @author Olivier Deruelle\n *\n */\npublic class AcceptLanguageParser extends HeaderParser {\n\n    /**\n     * Constructor\n     * @param acceptLanguage AcceptLanguage message to parse\n     */\n    public AcceptLanguageParser(String acceptLanguage) {\n        super(acceptLanguage);\n    }\n\n    /**\n     * Constructor\n     * @param lexer Lexer to set\n     */\n    protected AcceptLanguageParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (AcceptLanguage object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        AcceptLanguageList acceptLanguageList = new AcceptLanguageList();\n        if (debug)\n            dbg_enter(\"AcceptLanguageParser.parse\");\n\n        try {\n            headerName(TokenTypes.ACCEPT_LANGUAGE);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                AcceptLanguage acceptLanguage = new AcceptLanguage();\n                acceptLanguage.setHeaderName(SIPHeaderNames.ACCEPT_LANGUAGE);\n                if (lexer.lookAhead(0) != ';') {\n                    // Content-Coding:\n                    lexer.match(TokenTypes.ID);\n                    Token value = lexer.getNextToken();\n                    acceptLanguage.setLanguageRange(value.getTokenValue());\n                }\n\n                while (lexer.lookAhead(0) == ';') {\n                    this.lexer.match(';');\n                    this.lexer.SPorHT();\n                    this.lexer.match('q');\n                    this.lexer.SPorHT();\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    Token value = lexer.getNextToken();\n                    try {\n                        float fl = Float.parseFloat(value.getTokenValue());\n                        acceptLanguage.setQValue(fl);\n                    } catch (NumberFormatException ex) {\n                        throw createParseException(ex.getMessage());\n                    } catch (InvalidArgumentException ex) {\n                        throw createParseException(ex.getMessage());\n                    }\n                    this.lexer.SPorHT();\n                }\n\n                acceptLanguageList.add(acceptLanguage);\n                if (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else\n                    this.lexer.SPorHT();\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"AcceptLanguageParser.parse\");\n        }\n\n        return acceptLanguageList;\n    }\n}\n/*\n * $Log: AcceptLanguageParser.java,v $\n * Revision 1.8  2009/07/17 18:57:56  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:11  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AcceptParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Accept header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:57:56 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class AcceptParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of Accept Parser\n     * @param accept  the header to parse\n     */\n    public AcceptParser(String accept) {\n        super(accept);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected AcceptParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the Accept  String header\n     * @return SIPHeader (AcceptList  object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"AcceptParser.parse\");\n        AcceptList list = new AcceptList();\n\n        try {\n            headerName(TokenTypes.ACCEPT);\n\n            Accept accept = new Accept();\n            accept.setHeaderName(SIPHeaderNames.ACCEPT);\n\n            this.lexer.SPorHT();\n            this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n            accept.setContentType(token.getTokenValue());\n            this.lexer.match('/');\n            this.lexer.match(TokenTypes.ID);\n            token = lexer.getNextToken();\n            accept.setContentSubType(token.getTokenValue());\n            this.lexer.SPorHT();\n\n            super.parse(accept);\n            list.add(accept);\n\n            while (lexer.lookAhead(0) == ',') {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n\n                accept = new Accept();\n\n                this.lexer.match(TokenTypes.ID);\n                token = lexer.getNextToken();\n                accept.setContentType(token.getTokenValue());\n                this.lexer.match('/');\n                this.lexer.match(TokenTypes.ID);\n                token = lexer.getNextToken();\n                accept.setContentSubType(token.getTokenValue());\n                this.lexer.SPorHT();\n                super.parse(accept);\n                list.add(accept);\n\n            }\n            return list;\n        } finally {\n            if (debug)\n                dbg_leave(\"AcceptParser.parse\");\n        }\n    }\n}\n/*\n * $Log: AcceptParser.java,v $\n * Revision 1.7  2009/07/17 18:57:56  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:16  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AddressParametersParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Address parameters parser.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/10/22 10:25:57 $\n * @author M. Ranganathan\n * @since 1.1\n *\n */\npublic class AddressParametersParser extends ParametersParser {\n\n    protected AddressParametersParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    protected AddressParametersParser(String buffer) {\n        super(buffer);\n    }\n\n    protected void parse(AddressParametersHeader addressParametersHeader)\n        throws ParseException {\n        dbg_enter(\"AddressParametersParser.parse\");\n        try {\n            AddressParser addressParser = new AddressParser(this.getLexer());\n            AddressImpl addr = addressParser.address(false);\n            addressParametersHeader.setAddress(addr);\n            lexer.SPorHT();\n            char la = this.lexer.lookAhead(0);\n            if ( this.lexer.hasMoreChars() &&\n                 la != '\\0' &&\n                 la != '\\n' &&\n                 this.lexer.startsId()) {\n\n                 super.parseNameValueList(addressParametersHeader);\n\n\n            }  else super.parse(addressParametersHeader);\n\n        } catch (ParseException ex) {\n            throw ex;\n        } finally {\n            dbg_leave(\"AddressParametersParser.parse\");\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AddressParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.address.*;\n\nimport java.text.ParseException;\n\n/** Parser for addresses.\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/10/22 10:26:27 $\n * @author M. Ranganathan\n *\n *\n */\npublic class AddressParser extends Parser {\n\n    public AddressParser(Lexer lexer) {\n        this.lexer = lexer;\n        this.lexer.selectLexer(\"charLexer\");\n    }\n\n    public AddressParser(String address) {\n        this.lexer = new Lexer(\"charLexer\", address);\n    }\n\n    protected AddressImpl nameAddr() throws ParseException {\n        if (debug)\n            dbg_enter(\"nameAddr\");\n        try {\n            if (this.lexer.lookAhead(0) == '<') {\n                this.lexer.consume(1);\n                this.lexer.selectLexer(\"sip_urlLexer\");\n                this.lexer.SPorHT();\n                URLParser uriParser = new URLParser((Lexer) lexer);\n                GenericURI uri = uriParser.uriReference( true );\n                AddressImpl retval = new AddressImpl();\n                retval.setAddressType(AddressImpl.NAME_ADDR);\n                retval.setURI(uri);\n                this.lexer.SPorHT();\n                this.lexer.match('>');\n                return retval;\n            } else {\n                AddressImpl addr = new AddressImpl();\n                addr.setAddressType(AddressImpl.NAME_ADDR);\n                String name = null;\n                if (this.lexer.lookAhead(0) == '\\\"') {\n                    name = this.lexer.quotedString();\n                    this.lexer.SPorHT();\n                } else\n                    name = this.lexer.getNextToken('<');\n                addr.setDisplayName(name.trim());\n                this.lexer.match('<');\n                this.lexer.SPorHT();\n                URLParser uriParser = new URLParser((Lexer) lexer);\n                GenericURI uri = uriParser.uriReference( true );\n                AddressImpl retval = new AddressImpl();\n                addr.setAddressType(AddressImpl.NAME_ADDR);\n                addr.setURI(uri);\n                this.lexer.SPorHT();\n                this.lexer.match('>');\n                return addr;\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"nameAddr\");\n        }\n    }\n\n    public AddressImpl address( boolean inclParams ) throws ParseException {\n        if (debug)\n            dbg_enter(\"address\");\n        AddressImpl retval = null;\n        try {\n            int k = 0;\n            while (lexer.hasMoreChars()) {\n                char la = lexer.lookAhead(k);\n                if (la == '<'\n                    || la == '\\\"'\n                    || la == ':'\n                    || la == '/')\n                    break;\n                else if (la == '\\0')\n                    throw createParseException(\"unexpected EOL\");\n                else\n                    k++;\n            }\n            char la = lexer.lookAhead(k);\n            if (la == '<' || la == '\\\"') {\n                retval = nameAddr();\n            } else if (la == ':' || la == '/') {\n                retval = new AddressImpl();\n                URLParser uriParser = new URLParser((Lexer) lexer);\n                GenericURI uri = uriParser.uriReference( inclParams );\n                retval.setAddressType(AddressImpl.ADDRESS_SPEC);\n                retval.setURI(uri);\n            } else {\n                throw createParseException(\"Bad address spec\");\n            }\n            return retval;\n        } finally {\n            if (debug)\n                dbg_leave(\"address\");\n        }\n\n    }\n\n    /*\n\n    */\n}\n/*\n * $Log: AddressParser.java,v $\n * Revision 1.11  2009/10/22 10:26:27  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.10  2009/07/17 18:57:57  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.9  2007/02/12 15:19:26  belangery\n * Changed the encode() and encodeBody() methods of SIP headers and basic classes to make them use the same StringBuffer instance during the encoding phase.\n *\n * Revision 1.8  2007/02/06 16:40:02  belangery\n * Introduced simple code optimizations.\n *\n * Revision 1.7  2006/07/13 09:01:57  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2006/03/08 23:32:54  mranga\n * *** empty log message ***\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AlertInfoParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.address.GenericURI;\nimport gov2.nist.javax2.sip.header.AlertInfo;\nimport gov2.nist.javax2.sip.header.AlertInfoList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.SIPHeaderNames;\n\nimport java.text.ParseException;\n\n/**\n * Parser for AlertInfo header.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/07 23:35:49 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n */\npublic class AlertInfoParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of AlertInfo Parser\n     * @param alertInfo  the header to parse\n     */\n    public AlertInfoParser(String alertInfo) {\n        super(alertInfo);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected AlertInfoParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the AlertInfo  String header\n     * @return SIPHeader (AlertInfoList  object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"AlertInfoParser.parse\");\n        AlertInfoList list = new AlertInfoList();\n\n        try {\n            headerName(TokenTypes.ALERT_INFO);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                AlertInfo alertInfo = new AlertInfo();\n                alertInfo.setHeaderName(SIPHeaderNames.ALERT_INFO);\n                URLParser urlParser;\n                GenericURI uri;\n\n                do {\n\t                this.lexer.SPorHT();\n\t                if (this.lexer.lookAhead(0) == '<') {\n\t                    this.lexer.match('<');\n\t                    urlParser = new URLParser((Lexer) this.lexer);\n\t                    uri = urlParser.uriReference( true );\n\t                    alertInfo.setAlertInfo(uri);\n\t                    this.lexer.match('>');\n\t                } else {\n\t                \t/* This is non standard for Polycom support. \n\t                \t * I know it is bad grammar but please do not remove. mranga \n\t                \t */\n\t                \tString alertInfoStr = this.lexer.byteStringNoSemicolon();\n\t                \talertInfo.setAlertInfo(alertInfoStr);\n\t                }\n\t                \t\n\t                this.lexer.SPorHT();\n\t\n\t                super.parse(alertInfo);\n\t                list.add(alertInfo);\n\t                \n\t                if ( lexer.lookAhead(0) == ',' ) {\n\t                \tthis.lexer.match(',');\n\t                } else break;\n                } while (true);\n            }\n            return list;\n        } finally {\n            if (debug)\n                dbg_leave(\"AlertInfoParser.parse\");\n        }\n    }\n}\n/*\n * $Log: AlertInfoParser.java,v $\n * Revision 1.10  2009/11/07 23:35:49  mranga\n * Fix Alert-Info ( loosen up parsing). Define AUTOMATIC_DIALOG_ERROR_HANDLING flag.\n *\n * Revision 1.9  2009/10/22 10:27:36  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.8  2009/07/17 18:57:57  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2007/10/18 17:48:09  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mardy\n * Reviewed by:   mranga\n * Alert info patch to accept non standard alert info headers.\n *\n * Revision 1.6  2006/07/13 09:02:19  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AllowEventsParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for AllowEvents header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:57 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n *\n */\npublic class AllowEventsParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of AllowEventsParser\n     * @param allowEvents the header to parse\n     */\n    public AllowEventsParser(String allowEvents) {\n        super(allowEvents);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected AllowEventsParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the AllowEvents String header\n     * @return SIPHeader (AllowEventsList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"AllowEventsParser.parse\");\n        AllowEventsList list = new AllowEventsList();\n\n        try {\n            headerName(TokenTypes.ALLOW_EVENTS);\n\n            AllowEvents allowEvents = new AllowEvents();\n            allowEvents.setHeaderName(SIPHeaderNames.ALLOW_EVENTS);\n\n            this.lexer.SPorHT();\n            this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n            allowEvents.setEventType(token.getTokenValue());\n\n            list.add(allowEvents);\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) == ',') {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n\n                allowEvents = new AllowEvents();\n                this.lexer.match(TokenTypes.ID);\n                token = lexer.getNextToken();\n                allowEvents.setEventType(token.getTokenValue());\n\n                list.add(allowEvents);\n                this.lexer.SPorHT();\n            }\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return list;\n        } finally {\n            if (debug)\n                dbg_leave(\"AllowEventsParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: AllowEventsParser.java,v $\n * Revision 1.8  2009/07/17 18:57:57  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:01  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AllowParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Allow header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:57 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n */\npublic class AllowParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of AllowParser\n     * @param allow the header to parse\n     */\n    public AllowParser(String allow) {\n        super(allow);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected AllowParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the Allow String header\n     * @return SIPHeader (AllowList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"AllowParser.parse\");\n        AllowList list = new AllowList();\n\n        try {\n            headerName(TokenTypes.ALLOW);\n\n            Allow allow = new Allow();\n            allow.setHeaderName(SIPHeaderNames.ALLOW);\n\n            this.lexer.SPorHT();\n            this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n            allow.setMethod(token.getTokenValue());\n\n            list.add(allow);\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) == ',') {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n\n                allow = new Allow();\n                this.lexer.match(TokenTypes.ID);\n                token = lexer.getNextToken();\n                allow.setMethod(token.getTokenValue());\n\n                list.add(allow);\n                this.lexer.SPorHT();\n            }\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return list;\n        } finally {\n            if (debug)\n                dbg_leave(\"AllowParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: AllowParser.java,v $\n * Revision 1.8  2009/07/17 18:57:57  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:01:58  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AuthenticationInfoParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Authentication-Info header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:57 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n */\npublic class AuthenticationInfoParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of AuthenticationInfoParser\n     * @param authenticationInfo the header to parse\n     */\n    public AuthenticationInfoParser(String authenticationInfo) {\n        super(authenticationInfo);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected AuthenticationInfoParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the AuthenticationInfo String header\n     * @return SIPHeader (AuthenticationInfoList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"AuthenticationInfoParser.parse\");\n\n        try {\n            headerName(TokenTypes.AUTHENTICATION_INFO);\n\n            AuthenticationInfo authenticationInfo = new AuthenticationInfo();\n            authenticationInfo.setHeaderName(\n                SIPHeaderNames.AUTHENTICATION_INFO);\n\n            this.lexer.SPorHT();\n\n            NameValue nv = super.nameValue();\n            authenticationInfo.setParameter(nv);\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) == ',') {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n\n                nv = super.nameValue();\n                authenticationInfo.setParameter(nv);\n                this.lexer.SPorHT();\n            }\n            this.lexer.SPorHT();\n            //this.lexer.match('\\n');\n\n            return authenticationInfo;\n        } finally {\n            if (debug)\n                dbg_leave(\"AuthenticationInfoParser.parse\");\n        }\n    }\n\n    /*\n\n    **/\n}\n/*\n * $Log: AuthenticationInfoParser.java,v $\n * Revision 1.9  2009/07/17 18:57:57  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.8  2006/07/13 09:02:06  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.6  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.5  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/AuthorizationParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for authorization headers.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:57 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n *\n */\npublic class AuthorizationParser extends ChallengeParser {\n\n    /**\n     * Constructor\n     * @param authorization Authorization message to parse\n     */\n    public AuthorizationParser(String authorization) {\n        super(authorization);\n    }\n\n    /**\n     * Cosntructor\n     * @param lexer Lexer to set\n     */\n    protected AuthorizationParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (Authorization object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.AUTHORIZATION);\n            Authorization auth = new Authorization();\n            super.parse(auth);\n            return auth;\n        } finally {\n            dbg_leave(\"parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: AuthorizationParser.java,v $\n * Revision 1.8  2009/07/17 18:57:57  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:22  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/CSeqParser.java",
    "content": "/*\n* Conditions Of Use \n* \n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n* \n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n* \n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*  \n* .\n* \n*/\npackage gov2.nist.javax2.sip.parser;\n\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.message.SIPRequest;\n\n/**\n * Parser for CSeq headers.\n * \n * @version 1.2 $Revision: 1.10 $ $Date: 2006/08/15 21:44:50 $\n * \n * @author M. Ranganathan \n * @author Olivier Deruelle \n * \n */\npublic class CSeqParser extends HeaderParser {\n\n    public CSeqParser(String cseq) {\n        super(cseq);\n    }\n\n    protected CSeqParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n        try {\n            CSeq c = new CSeq();\n\n            this.lexer.match(TokenTypes.CSEQ);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n            String number = this.lexer.number();\n            c.setSeqNumber(Long.parseLong(number));\n            this.lexer.SPorHT();\n            String m = SIPRequest.getCannonicalName( method() );\n            \n            \n            \n            c.setMethod(m);\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n            return c;\n        } catch (NumberFormatException ex) {\n            Debug.printStackTrace(ex);\n            throw createParseException(\"Number format exception\");\n        } catch (InvalidArgumentException ex) {\n            Debug.printStackTrace(ex);\n            throw createParseException(ex.getMessage());\n        }\n    }\n\n    /**\n     *  \n     */\n}\n/*\n * $Log: CSeqParser.java,v $\n * Revision 1.10  2006/08/15 21:44:50  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Incorporating the latest API changes from Phelim\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.9  2006/07/13 09:02:17  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.5  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.4  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.3  2006/05/22 08:16:15  mranga\n * Added tests for retransmissionAlert flag\n * Added tests for transaction terminated event\n *\n * Revision 1.2  2006/04/17 17:45:01  jeroen\n * - Using SIPRequest method to canonicalize request name (current code was omitting some)\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.7  2005/04/27 14:12:04  mranga\n * Submitted by:  Mario Mantak\n * Reviewed by:   mranga\n *\n * Added a missing \"short form\" for event header.\n *\n * Revision 1.6  2005/04/21 00:01:59  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:  mranga\n *\n * Adjust remote sequence number when sending out a 491\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n * Revision 1.5 2004/07/28 14:13:54 mranga Submitted\n * by: mranga\n * \n * Move out the test code to a separate test/unit class. Fixed some encode\n * methods.\n * \n * Revision 1.4 2004/01/22 13:26:31 sverker Issue number: Obtained from:\n * Submitted by: sverker Reviewed by: mranga\n * \n * Major reformat of code to conform with style guide. Resolved compiler and\n * javadoc warnings. Added CVS tags.\n * \n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number: CVS: If this change addresses one or more issues, CVS:\n * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change\n * has been taken from another system, CVS: then name the system in this line,\n * otherwise delete it. CVS: Submitted by: CVS: If this code has been\n * contributed to the project by someone else; i.e., CVS: they sent us a patch\n * or a set of diffs, then include their name/email CVS: address here. If this\n * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing\n * pre-commit code reviews and someone else has CVS: reviewed your changes,\n * include their name(s) here. CVS: If you have not had it reviewed then delete\n * this line.\n *  \n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/CallIDParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.*;\n\n/** Parser for CALL ID header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $\n *\n * @author M. Ranganathan\n * @author  Olivier Deruelle\n *\n */\npublic class CallIDParser extends HeaderParser {\n\n    /**\n     * Creates new CallIDParser\n     * @param callID message to parse\n     */\n    public CallIDParser(String callID) {\n        super(callID);\n    }\n\n    /**\n     * Constructor\n     * @param lexer Lexer to set\n     */\n    protected CallIDParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (CallID object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            this.lexer.match(TokenTypes.CALL_ID);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n\n            CallID callID = new CallID();\n\n            this.lexer.SPorHT();\n            String rest = lexer.getRest();\n            callID.setCallId(rest.trim());\n            return callID;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n    /*\n\n\n        }\n    */\n}\n/*\n * $Log: CallIDParser.java,v $\n * Revision 1.8  2009/07/17 18:57:58  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:17  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/CallInfoParser.java",
    "content": "/*\n* Conditions Of Use \n* \n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n* \n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n* \n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*  \n* .\n* \n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for CallInfo header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/10/22 10:27:36 $\n *\n * @author Olivier Deruelle  \n * @author M. Ranganathan  \n * \n */\npublic class CallInfoParser  extends ParametersParser{\n    \n    /**\n     * Creates a new instance of CallInfoParser\n     * @param callInfo the header to parse \n     */\n    public CallInfoParser(String callInfo) {\n        super(callInfo);\n    }\n    \n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected  CallInfoParser(Lexer lexer) {\n        super(lexer);\n    }\n    \n    /**\n     * parse the CallInfo String header\n     * @return SIPHeader (CallInfoList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        \n        if (debug) dbg_enter(\"CallInfoParser.parse\");\n        CallInfoList list=new CallInfoList();\n        \n        try {\n            headerName(TokenTypes.CALL_INFO);\n            \n            while (lexer.lookAhead(0) != '\\n') {\n                CallInfo callInfo= new CallInfo();\n                callInfo.setHeaderName(SIPHeaderNames.CALL_INFO);\n                \n                this.lexer.SPorHT();\n                this.lexer.match('<');\n                URLParser urlParser=new URLParser((Lexer)this.lexer);\n                GenericURI uri=urlParser.uriReference(true); \n                callInfo.setInfo(uri);\n                this.lexer.match('>');\n                this.lexer.SPorHT();\n                \n                super.parse(callInfo);\n                list.add(callInfo);\n                \n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                    \n                    callInfo= new CallInfo();\n                    \n                    this.lexer.SPorHT();\n                    this.lexer.match('<');\n                    urlParser=new URLParser((Lexer)this.lexer);\n                    uri=urlParser.uriReference(true);\n                    callInfo.setInfo(uri);\n                    this.lexer.match('>');\n                    this.lexer.SPorHT();\n                    \n                    super.parse(callInfo);\n                    list.add(callInfo);\n                }\n            }\n            \n            return list;\n        }\n        finally {\n            if (debug) dbg_leave(\"CallInfoParser.parse\");\n        }\n    }\n    \n    \n}\n/*\n * $Log: CallInfoParser.java,v $\n * Revision 1.8  2009/10/22 10:27:36  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.7  2006/07/13 09:02:15  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:54  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ChallengeParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for the challenge portion of the authentication header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $\n * @since 1.1\n *\n * @author Olivier Deruelle    <br/>\n *\n *\n */\n\npublic abstract class ChallengeParser extends HeaderParser {\n\n    /**\n     * Constructor\n     * @param String challenge  message to parse to set\n     */\n    protected ChallengeParser(String challenge) {\n        super(challenge);\n    }\n\n    /**\n     * Constructor\n     * @param String challenge  message to parse to set\n     */\n    protected ChallengeParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * Get the parameter of the challenge string\n     * @return NameValue containing the parameter\n     */\n    protected void parseParameter(AuthenticationHeader header)\n        throws ParseException {\n\n        if (debug)\n            dbg_enter(\"parseParameter\");\n        try {\n            NameValue nv = this.nameValue('=');\n            header.setParameter(nv);\n        } finally {\n            if (debug)\n                dbg_leave(\"parseParameter\");\n        }\n\n    }\n\n    /**\n     * parser the String message.\n     * @param header - header structure to fill in.\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public void parse(AuthenticationHeader header) throws ParseException {\n\n        // the Scheme:\n        this.lexer.SPorHT();\n        lexer.match(TokenTypes.ID);\n        Token type = lexer.getNextToken();\n        this.lexer.SPorHT();\n        header.setScheme(type.getTokenValue());\n\n        // The parameters:\n        try {\n            while (lexer.lookAhead(0) != '\\n') {\n                this.parseParameter(header);\n                this.lexer.SPorHT();\n                char la = lexer.lookAhead(0);\n                if (la == '\\n' || la == '\\0')\n                    break;\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n            }\n        } catch (ParseException ex) {\n            throw ex;\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ContactParser.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n *\n */\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.header.Contact;\nimport gov2.nist.javax2.sip.header.ContactList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\nimport javax2.sip.address.URI;\n\nimport java.text.ParseException;\nimport java.util.HashSet;\nimport java.util.Iterator;\n\n/**\n * A parser for The SIP contact header.\n *\n * @version 1.2 $Revision: 1.13 $ $Date: 2009/10/22 10:27:37 $\n * @since 1.1\n */\npublic class ContactParser extends AddressParametersParser {\n\n    public ContactParser(String contact) {\n        super(contact);\n    }\n\n    protected ContactParser(Lexer lexer) {\n        super(lexer);\n        this.lexer = lexer;\n    }\n\n    public SIPHeader parse() throws ParseException {\n        // past the header name and the colon.\n        headerName(TokenTypes.CONTACT);\n        ContactList retval = new ContactList();\n        while (true) {\n            Contact contact = new Contact();\n            if (lexer.lookAhead(0) == '*') {\n                final char next = lexer.lookAhead(1);\n                if (next == ' ' || next == '\\t' || next == '\\r' || next == '\\n') {\n                    this.lexer.match('*');\n                    contact.setWildCardFlag(true);\n                } else {\n                    super.parse(contact);\n                }\n            } else {\n                super.parse(contact);\n            }\n            retval.add(contact);\n            this.lexer.SPorHT();\n            char la = lexer.lookAhead(0);\n            if (la == ',') {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n            } else if (la == '\\n' || la == '\\0')\n                break;\n            else\n                throw createParseException(\"unexpected char\");\n        }\n        return retval;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ContentDispositionParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ContentLanguage header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ContentDispositionParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of ContentDispositionParser\n     * @param contentDisposition the header to parse\n     */\n    public ContentDispositionParser(String contentDisposition) {\n        super(contentDisposition);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ContentDispositionParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the ContentDispositionHeader String header\n     * @return SIPHeader (ContentDispositionList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"ContentDispositionParser.parse\");\n\n        try {\n            headerName(TokenTypes.CONTENT_DISPOSITION);\n\n            ContentDisposition cd = new ContentDisposition();\n            cd.setHeaderName(SIPHeaderNames.CONTENT_DISPOSITION);\n\n            this.lexer.SPorHT();\n            this.lexer.match(TokenTypes.ID);\n\n            Token token = lexer.getNextToken();\n            cd.setDispositionType(token.getTokenValue());\n            this.lexer.SPorHT();\n            super.parse(cd);\n\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return cd;\n        } catch (ParseException ex) {\n            throw createParseException(ex.getMessage());\n        } finally {\n            if (debug)\n                dbg_leave(\"ContentDispositionParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: ContentDispositionParser.java,v $\n * Revision 1.8  2009/07/17 18:57:58  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:15  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:55  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ContentEncodingParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ContentLanguage header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * @version 1.0\n */\npublic class ContentEncodingParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of ContentEncodingParser\n     * @param contentEncoding the header to parse\n     */\n    public ContentEncodingParser(String contentEncoding) {\n        super(contentEncoding);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ContentEncodingParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the ContentEncodingHeader String header\n     * @return SIPHeader (ContentEncodingList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"ContentEncodingParser.parse\");\n        ContentEncodingList list = new ContentEncodingList();\n\n        try {\n            headerName(TokenTypes.CONTENT_ENCODING);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                ContentEncoding cl = new ContentEncoding();\n                cl.setHeaderName(SIPHeaderNames.CONTENT_ENCODING);\n\n                this.lexer.SPorHT();\n                this.lexer.match(TokenTypes.ID);\n\n                Token token = lexer.getNextToken();\n                cl.setEncoding(token.getTokenValue());\n\n                this.lexer.SPorHT();\n                list.add(cl);\n\n                while (lexer.lookAhead(0) == ',') {\n                    cl = new ContentEncoding();\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                    this.lexer.match(TokenTypes.ID);\n                    this.lexer.SPorHT();\n                    token = lexer.getNextToken();\n                    cl.setEncoding(token.getTokenValue());\n                    this.lexer.SPorHT();\n                    list.add(cl);\n                }\n            }\n\n            return list;\n        } catch (ParseException ex) {\n            throw createParseException(ex.getMessage());\n        } finally {\n            if (debug)\n                dbg_leave(\"ContentEncodingParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: ContentEncodingParser.java,v $\n * Revision 1.8  2009/07/17 18:57:58  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:01:56  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:55  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ContentLanguageParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ContentLanguage header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ContentLanguageParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of ContentLanguageParser\n     * @param contentLanguage the header to parse\n     */\n    public ContentLanguageParser(String contentLanguage) {\n        super(contentLanguage);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ContentLanguageParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the ContentLanguageHeader String header\n     * @return SIPHeader (ContentLanguageList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"ContentLanguageParser.parse\");\n        ContentLanguageList list = new ContentLanguageList();\n\n        try {\n            headerName(TokenTypes.CONTENT_LANGUAGE);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                this.lexer.SPorHT();\n                this.lexer.match(TokenTypes.ID);\n\n                Token token = lexer.getNextToken();\n                ContentLanguage cl = new ContentLanguage( token.getTokenValue() );\n                this.lexer.SPorHT();\n                list.add(cl);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                    this.lexer.match(TokenTypes.ID);\n                    this.lexer.SPorHT();\n                    token = lexer.getNextToken();\n                    cl = new ContentLanguage( token.getTokenValue() );\n                    this.lexer.SPorHT();\n                    list.add(cl);\n                }\n            }\n\n            return list;\n        } catch (ParseException ex) {\n            throw createParseException(ex.getMessage());\n        } finally {\n            if (debug)\n                dbg_leave(\"ContentLanguageParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: ContentLanguageParser.java,v $\n * Revision 1.8  2009/07/17 18:57:58  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:24  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2005/10/16 15:47:41  jeroen\n * fixed language sub tag handling\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:55  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ContentLengthParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport javax2.sip.*;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Content-Length Header.\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:58 $\n *\n * @author Olivier Deruelle  <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ContentLengthParser extends HeaderParser {\n\n    public ContentLengthParser(String contentLength) {\n        super(contentLength);\n    }\n\n    protected ContentLengthParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"ContentLengthParser.enter\");\n        try {\n            ContentLength contentLength = new ContentLength();\n            headerName(TokenTypes.CONTENT_LENGTH);\n            String number = this.lexer.number();\n            contentLength.setContentLength(Integer.parseInt(number));\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n            return contentLength;\n        } catch (InvalidArgumentException ex) {\n            throw createParseException(ex.getMessage());\n        } catch (NumberFormatException ex) {\n            throw createParseException(ex.getMessage());\n        } finally {\n            if (debug)\n                dbg_leave(\"ContentLengthParser.leave\");\n        }\n    }\n\n\n}\n/*\n * $Log: ContentLengthParser.java,v $\n * Revision 1.8  2009/07/17 18:57:58  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:14  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/07/28 14:13:55  mranga\n * Submitted by:  mranga\n *\n * Move out the test code to a separate test/unit class.\n * Fixed some encode methods.\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ContentTypeParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*\n * ContentTypeParser.java\n *\n * Created on February 26, 2002, 2:42 PM\n */\n\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for content type header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:57:59 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ContentTypeParser extends ParametersParser {\n\n    public ContentTypeParser(String contentType) {\n        super(contentType);\n    }\n\n    protected ContentTypeParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n\n        ContentType contentType = new ContentType();\n        if (debug)\n            dbg_enter(\"ContentTypeParser.parse\");\n\n        try {\n            this.headerName(TokenTypes.CONTENT_TYPE);\n\n            // The type:\n            lexer.match(TokenTypes.ID);\n            Token type = lexer.getNextToken();\n            this.lexer.SPorHT();\n            contentType.setContentType(type.getTokenValue());\n\n            // The sub-type:\n            lexer.match('/');\n            lexer.match(TokenTypes.ID);\n            Token subType = lexer.getNextToken();\n            this.lexer.SPorHT();\n            contentType.setContentSubType(subType.getTokenValue());\n            super.parse(contentType);\n            this.lexer.match('\\n');\n        } finally {\n            if (debug)\n                dbg_leave(\"ContentTypeParser.parse\");\n        }\n        return contentType;\n\n    }\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/DateParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.util.*;\nimport java.text.ParseException;\n\n/**\n * Parser for SIP Date field. Converts from SIP Date to the\n * internal storage (Calendar)\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:57:59 $\n */\npublic class DateParser extends HeaderParser {\n\n    /**\n     * Constructor\n     * @param date message to parse to set\n     */\n    public DateParser(String date) {\n        super(date);\n    }\n\n    protected DateParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * Parse method.\n     * @throws ParseException\n     * @return  the parsed Date header/\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"DateParser.parse\");\n        try {\n            headerName(TokenTypes.DATE);\n            wkday();\n            lexer.match(',');\n            lexer.match(' ');\n            Calendar cal = date();\n            lexer.match(' ');\n            time(cal);\n            lexer.match(' ');\n            String tzone = this.lexer.ttoken().toLowerCase();\n            if (!\"gmt\".equals(tzone))\n                throw createParseException(\"Bad Time Zone \" + tzone);\n            this.lexer.match('\\n');\n            SIPDateHeader retval = new SIPDateHeader();\n            retval.setDate(cal);\n            return retval;\n        } finally {\n            if (debug)\n                dbg_leave(\"DateParser.parse\");\n\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ErrorInfoParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ErrorInfo header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/10/22 10:27:37 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ErrorInfoParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of ErrorInfoParser\n     * @param errorInfo the header to parse\n     */\n    public ErrorInfoParser(String errorInfo) {\n        super(errorInfo);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ErrorInfoParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the ErrorInfo String header\n     * @return SIPHeader (ErrorInfoList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"ErrorInfoParser.parse\");\n        ErrorInfoList list = new ErrorInfoList();\n\n        try {\n            headerName(TokenTypes.ERROR_INFO);\n\n            while (lexer.lookAhead(0) != '\\n') {\n            \tdo {\n\t                ErrorInfo errorInfo = new ErrorInfo();\n\t                errorInfo.setHeaderName(SIPHeaderNames.ERROR_INFO);\n\t\n\t                this.lexer.SPorHT();\n\t                this.lexer.match('<');\n\t                URLParser urlParser = new URLParser((Lexer) this.lexer);\n\t                GenericURI uri = urlParser.uriReference( true );\n\t                errorInfo.setErrorInfo(uri);\n\t                this.lexer.match('>');\n\t                this.lexer.SPorHT();\n\t\n\t                super.parse(errorInfo);\n\t                list.add(errorInfo);\n\t                \n\t                if ( lexer.lookAhead(0) == ',' ) {\n\t                \tthis.lexer.match(',');\n\t                } else break;\n            \t} while (true);\n            }\n\n            return list;\n        } finally {\n            if (debug)\n                dbg_leave(\"ErrorInfoParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: ErrorInfoParser.java,v $\n * Revision 1.9  2009/10/22 10:27:37  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.8  2009/07/17 18:57:59  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:17  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/08/10 21:35:43  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/EventParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Event header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:57:59 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class EventParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of EventParser\n     * @param event the header to parse\n     */\n    public EventParser(String event) {\n        super(event);\n    }\n\n    /**\n     * Cosntructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected EventParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (Event object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"EventParser.parse\");\n\n        try {\n            headerName(TokenTypes.EVENT);\n            this.lexer.SPorHT();\n\n            Event event = new Event();\n            this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n            String value = token.getTokenValue();\n\n            event.setEventType(value);\n            super.parse(event);\n\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return event;\n\n        } catch (ParseException ex) {\n            throw createParseException(ex.getMessage());\n        } finally {\n            if (debug)\n                dbg_leave(\"EventParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: EventParser.java,v $\n * Revision 1.8  2009/07/17 18:57:59  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:14  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/08/10 21:35:43  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ExpiresParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for SIP Expires Parser. Converts from SIP Date to the\n * internal storage (Calendar).\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:00 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ExpiresParser extends HeaderParser {\n\n    /**\n     * protected constructor.\n     * @param text is the text of the header to parse\n     */\n    public ExpiresParser(String text) {\n        super(text);\n    }\n\n    /**\n     * constructor.\n     * @param lexer is the lexer passed in from the enclosing parser.\n     */\n    protected ExpiresParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * Parse the header.\n     */\n    public SIPHeader parse() throws ParseException {\n        Expires expires = new Expires();\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            lexer.match(TokenTypes.EXPIRES);\n            lexer.SPorHT();\n            lexer.match(':');\n            lexer.SPorHT();\n            String nextId = lexer.getNextId();\n            lexer.match('\\n');\n            try {\n                int delta = Integer.parseInt(nextId);\n                expires.setExpires(delta);\n                return expires;\n            } catch (NumberFormatException ex) {\n                throw createParseException(\"bad integer format\");\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n\n    }\n\n\n\n}\n/*\n * $Log: ExpiresParser.java,v $\n * Revision 1.8  2009/07/17 18:58:00  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:12  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/08/10 21:35:44  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/FromParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.javax2.sip.header.From;\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\nimport java.text.ParseException;\n\n/** From header parser.\n *\n * @version 1.2 $Revision: 1.12 $ $Date: 2009/10/22 10:27:37 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class FromParser extends AddressParametersParser {\n\n    public FromParser(String from) {\n        super(from);\n    }\n\n    protected FromParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n\n        From from = new From();\n\n        this.lexer.match(TokenTypes.FROM);\n        this.lexer.SPorHT();\n        this.lexer.match(':');\n        this.lexer.SPorHT();\n        super.parse(from);\n        this.lexer.match('\\n');\n        return from;\n    }\n\n\n}\n/*\n * $Log: FromParser.java,v $\n * Revision 1.12  2009/10/22 10:27:37  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.11  2009/07/17 18:58:00  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.10  2007/10/23 17:34:55  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n *\n * Refactored header collections.\n *\n * Revision 1.9  2006/07/13 09:02:16  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.7  2004/08/10 21:35:44  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.6  2004/04/22 22:51:17  mranga\n * Submitted by:  Thomas Froment\n * Reviewed by:   mranga\n *\n * Fixed corner cases.\n *\n * Revision 1.5  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/HeaderParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.util.*;\nimport java.text.ParseException;\n\n/**\n * Generic header parser class. The parsers for various headers extend this\n * class. To create a parser for a new header, extend this class and change\n * the createParser class.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:00 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class HeaderParser extends Parser {\n\n    /**\n     * Parse the weekday field\n     * @return an integer with the calendar content for wkday.\n     */\n    protected int wkday() throws ParseException {\n        dbg_enter(\"wkday\");\n        try {\n            String tok = lexer.ttoken();\n            String id = tok.toLowerCase();\n\n            if (TokenNames.MON.equalsIgnoreCase(id))\n                return Calendar.MONDAY;\n            else if (TokenNames.TUE.equalsIgnoreCase(id))\n                return Calendar.TUESDAY;\n            else if (TokenNames.WED.equalsIgnoreCase(id))\n                return Calendar.WEDNESDAY;\n            else if (TokenNames.THU.equalsIgnoreCase(id))\n                return Calendar.THURSDAY;\n            else if (TokenNames.FRI.equalsIgnoreCase(id))\n                return Calendar.FRIDAY;\n            else if (TokenNames.SAT.equalsIgnoreCase(id))\n                return Calendar.SATURDAY;\n            else if (TokenNames.SUN.equalsIgnoreCase(id))\n                return Calendar.SUNDAY;\n            else\n                throw createParseException(\"bad wkday\");\n        } finally {\n            dbg_leave(\"wkday\");\n        }\n\n    }\n\n    /**\n     * parse and return a date field.\n     * @return a date structure with the parsed value.\n     */\n    protected Calendar date() throws ParseException {\n        try {\n            Calendar retval = Calendar.getInstance(TimeZone.getTimeZone(\"GMT\"));\n            String s1 = lexer.number();\n            int day = Integer.parseInt(s1);\n            if (day <= 0 || day > 31)\n                throw createParseException(\"Bad day \");\n            retval.set(Calendar.DAY_OF_MONTH, day);\n            lexer.match(' ');\n            String month = lexer.ttoken().toLowerCase();\n            if (month.equals(\"jan\")) {\n                retval.set(Calendar.MONTH, Calendar.JANUARY);\n            } else if (month.equals(\"feb\")) {\n                retval.set(Calendar.MONTH, Calendar.FEBRUARY);\n            } else if (month.equals(\"mar\")) {\n                retval.set(Calendar.MONTH, Calendar.MARCH);\n            } else if (month.equals(\"apr\")) {\n                retval.set(Calendar.MONTH, Calendar.APRIL);\n            } else if (month.equals(\"may\")) {\n                retval.set(Calendar.MONTH, Calendar.MAY);\n            } else if (month.equals(\"jun\")) {\n                retval.set(Calendar.MONTH, Calendar.JUNE);\n            } else if (month.equals(\"jul\")) {\n                retval.set(Calendar.MONTH, Calendar.JULY);\n            } else if (month.equals(\"aug\")) {\n                retval.set(Calendar.MONTH, Calendar.AUGUST);\n            } else if (month.equals(\"sep\")) {\n                retval.set(Calendar.MONTH, Calendar.SEPTEMBER);\n            } else if (month.equals(\"oct\")) {\n                retval.set(Calendar.MONTH, Calendar.OCTOBER);\n            } else if (month.equals(\"nov\")) {\n                retval.set(Calendar.MONTH, Calendar.NOVEMBER);\n            } else if (month.equals(\"dec\")) {\n                retval.set(Calendar.MONTH, Calendar.DECEMBER);\n            }\n            lexer.match(' ');\n            String s2 = lexer.number();\n            int yr = Integer.parseInt(s2);\n            retval.set(Calendar.YEAR, yr);\n            return retval;\n\n        } catch (Exception ex) {\n            throw createParseException(\"bad date field\");\n        }\n\n    }\n\n    /**\n     * Set the time field. This has the format hour:minute:second\n     */\n    protected void time(Calendar calendar) throws ParseException {\n        try {\n            String s = lexer.number();\n            int hour = Integer.parseInt(s);\n            calendar.set(Calendar.HOUR_OF_DAY, hour);\n            lexer.match(':');\n            s = lexer.number();\n            int min = Integer.parseInt(s);\n            calendar.set(Calendar.MINUTE, min);\n            lexer.match(':');\n            s = lexer.number();\n            int sec = Integer.parseInt(s);\n            calendar.set(Calendar.SECOND, sec);\n        } catch (Exception ex) {\n            throw createParseException(\"error processing time \");\n\n        }\n\n    }\n\n    /**\n     * Creates new HeaderParser\n     * @param String to parse.\n     */\n    protected HeaderParser(String header) {\n        this.lexer = new Lexer(\"command_keywordLexer\", header);\n    }\n\n    protected HeaderParser(Lexer lexer) {\n        this.lexer = lexer;\n        this.lexer.selectLexer(\"command_keywordLexer\");\n    }\n\n    /**\n     * Parse the SIP header from the buffer and return a parsed\n     * structure.\n     * @throws ParseException if there was an error parsing.\n     */\n    public SIPHeader parse() throws ParseException {\n        String name = lexer.getNextToken(':');\n        lexer.consume(1);\n        String body = lexer.getLine().trim();\n        // we dont set any fields because the header is\n        // ok\n        ExtensionHeaderImpl retval = new ExtensionHeaderImpl(name);\n        retval.setValue(body);\n        return retval;\n\n    }\n\n    /**\n     * Parse the header name until the colon  and chew WS after that.\n     */\n    protected void headerName(int tok) throws ParseException {\n        this.lexer.match(tok);\n        this.lexer.SPorHT();\n        this.lexer.match(':');\n        this.lexer.SPorHT();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/InReplyToParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for InReplyTo header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:00 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class InReplyToParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of InReplyToParser\n     * @param inReplyTo the header to parse\n     */\n    public InReplyToParser(String inReplyTo) {\n        super(inReplyTo);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected InReplyToParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (InReplyToList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"InReplyToParser.parse\");\n        InReplyToList list = new InReplyToList();\n\n        try {\n            headerName(TokenTypes.IN_REPLY_TO);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                InReplyTo inReplyTo = new InReplyTo();\n                inReplyTo.setHeaderName(SIPHeaderNames.IN_REPLY_TO);\n\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                if (lexer.lookAhead(0) == '@') {\n                    this.lexer.match('@');\n                    this.lexer.match(TokenTypes.ID);\n                    Token secToken = lexer.getNextToken();\n                    inReplyTo.setCallId(\n                        token.getTokenValue() + \"@\" + secToken.getTokenValue());\n                } else {\n                    inReplyTo.setCallId(token.getTokenValue());\n                }\n\n                this.lexer.SPorHT();\n\n                list.add(inReplyTo);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n\n                    inReplyTo = new InReplyTo();\n\n                    this.lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    if (lexer.lookAhead(0) == '@') {\n                        this.lexer.match('@');\n                        this.lexer.match(TokenTypes.ID);\n                        Token secToken = lexer.getNextToken();\n                        inReplyTo.setCallId(\n                            token.getTokenValue()\n                                + \"@\"\n                                + secToken.getTokenValue());\n                    } else {\n                        inReplyTo.setCallId(token.getTokenValue());\n                    }\n\n                    list.add(inReplyTo);\n                }\n            }\n\n            return list;\n        } finally {\n            if (debug)\n                dbg_leave(\"InReplyToParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: InReplyToParser.java,v $\n * Revision 1.8  2009/07/17 18:58:00  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:18  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/08/10 21:35:44  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/Lexer.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip.parser;\n\n\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.header.ims.*;\n\nimport javax2.sip.header.*;\n\nimport java.util.Hashtable;\n\n/**\n * Lexer class for the parser.\n *\n * @version 1.2\n *\n * @author M. Ranganathan <br/>\n *\n *\n */\npublic class Lexer extends LexerCore {\n    /**\n     * get the header name of the line\n     *\n     * @return the header name (stuff before the :) bug fix submitted by\n     *         zvali@dev.java.net\n     */\n    public static String getHeaderName(String line) {\n        if (line == null)\n            return null;\n        String headerName = null;\n        try {\n            int begin = line.indexOf(\":\");\n            headerName = null;\n            if (begin >= 1)\n                headerName = line.substring(0, begin).trim();\n        } catch (IndexOutOfBoundsException e) {\n            return null;\n        }\n        return headerName;\n    }\n\n    public Lexer(String lexerName, String buffer) {\n        super(lexerName, buffer);\n        this.selectLexer(lexerName);\n    }\n\n    /**\n     * get the header value of the line\n     *\n     * @return String\n     */\n    public static String getHeaderValue(String line) {\n        if (line == null)\n            return null;\n        String headerValue = null;\n        try {\n            int begin = line.indexOf(\":\");\n            headerValue = line.substring(begin + 1);\n        } catch (IndexOutOfBoundsException e) {\n            return null;\n        }\n        return headerValue;\n    }\n\n    public void selectLexer(String lexerName) {\n        synchronized (lexerTables) {\n            // Synchronization Bug fix by Robert Rosen.\n            currentLexer = (Hashtable) lexerTables.get(lexerName);\n            this.currentLexerName = lexerName;\n            if (currentLexer == null) {\n                addLexer(lexerName);\n                if (lexerName.equals(\"method_keywordLexer\")) {\n                    addKeyword(TokenNames.REGISTER, TokenTypes.REGISTER);\n                    addKeyword(TokenNames.ACK, TokenTypes.ACK);\n                    addKeyword(TokenNames.OPTIONS, TokenTypes.OPTIONS);\n                    addKeyword(TokenNames.BYE, TokenTypes.BYE);\n                    addKeyword(TokenNames.INVITE, TokenTypes.INVITE);\n                    addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP);\n                    addKeyword(TokenNames.SIPS.toUpperCase(), TokenTypes.SIPS);\n                    addKeyword(TokenNames.SUBSCRIBE, TokenTypes.SUBSCRIBE);\n                    addKeyword(TokenNames.NOTIFY, TokenTypes.NOTIFY);\n                    addKeyword(TokenNames.MESSAGE, TokenTypes.MESSAGE);\n\n                    // JvB: added to support RFC3903\n                    addKeyword(TokenNames.PUBLISH, TokenTypes.PUBLISH);\n\n                } else if (lexerName.equals(\"command_keywordLexer\")) {\n                    addKeyword(ErrorInfoHeader.NAME.toUpperCase(),\n                            TokenTypes.ERROR_INFO);\n                    addKeyword(AllowEventsHeader.NAME.toUpperCase(),\n                            TokenTypes.ALLOW_EVENTS);\n                    addKeyword(AuthenticationInfoHeader.NAME.toUpperCase(),\n                            TokenTypes.AUTHENTICATION_INFO);\n                    addKeyword(EventHeader.NAME.toUpperCase(), TokenTypes.EVENT);\n                    addKeyword(MinExpiresHeader.NAME.toUpperCase(),\n                            TokenTypes.MIN_EXPIRES);\n                    addKeyword(RSeqHeader.NAME.toUpperCase(), TokenTypes.RSEQ);\n                    addKeyword(RAckHeader.NAME.toUpperCase(), TokenTypes.RACK);\n                    addKeyword(ReasonHeader.NAME.toUpperCase(),\n                            TokenTypes.REASON);\n                    addKeyword(ReplyToHeader.NAME.toUpperCase(),\n                            TokenTypes.REPLY_TO);\n                    addKeyword(SubscriptionStateHeader.NAME.toUpperCase(),\n                            TokenTypes.SUBSCRIPTION_STATE);\n                    addKeyword(TimeStampHeader.NAME.toUpperCase(),\n                            TokenTypes.TIMESTAMP);\n                    addKeyword(InReplyToHeader.NAME.toUpperCase(),\n                            TokenTypes.IN_REPLY_TO);\n                    addKeyword(MimeVersionHeader.NAME.toUpperCase(),\n                            TokenTypes.MIME_VERSION);\n                    addKeyword(AlertInfoHeader.NAME.toUpperCase(),\n                            TokenTypes.ALERT_INFO);\n                    addKeyword(FromHeader.NAME.toUpperCase(), TokenTypes.FROM);\n                    addKeyword(ToHeader.NAME.toUpperCase(), TokenTypes.TO);\n                    addKeyword(ReferToHeader.NAME.toUpperCase(),\n                            TokenTypes.REFER_TO);\n                    addKeyword(ViaHeader.NAME.toUpperCase(), TokenTypes.VIA);\n                    addKeyword(UserAgentHeader.NAME.toUpperCase(),\n                            TokenTypes.USER_AGENT);\n                    addKeyword(ServerHeader.NAME.toUpperCase(),\n                            TokenTypes.SERVER);\n                    addKeyword(AcceptEncodingHeader.NAME.toUpperCase(),\n                            TokenTypes.ACCEPT_ENCODING);\n                    addKeyword(AcceptHeader.NAME.toUpperCase(),\n                            TokenTypes.ACCEPT);\n                    addKeyword(AllowHeader.NAME.toUpperCase(), TokenTypes.ALLOW);\n                    addKeyword(RouteHeader.NAME.toUpperCase(), TokenTypes.ROUTE);\n                    addKeyword(AuthorizationHeader.NAME.toUpperCase(),\n                            TokenTypes.AUTHORIZATION);\n                    addKeyword(ProxyAuthorizationHeader.NAME.toUpperCase(),\n                            TokenTypes.PROXY_AUTHORIZATION);\n                    addKeyword(RetryAfterHeader.NAME.toUpperCase(),\n                            TokenTypes.RETRY_AFTER);\n                    addKeyword(ProxyRequireHeader.NAME.toUpperCase(),\n                            TokenTypes.PROXY_REQUIRE);\n                    addKeyword(ContentLanguageHeader.NAME.toUpperCase(),\n                            TokenTypes.CONTENT_LANGUAGE);\n                    addKeyword(UnsupportedHeader.NAME.toUpperCase(),\n                            TokenTypes.UNSUPPORTED);\n                    addKeyword(SupportedHeader.NAME.toUpperCase(),\n                            TokenTypes.SUPPORTED);\n                    addKeyword(WarningHeader.NAME.toUpperCase(),\n                            TokenTypes.WARNING);\n                    addKeyword(MaxForwardsHeader.NAME.toUpperCase(),\n                            TokenTypes.MAX_FORWARDS);\n                    addKeyword(DateHeader.NAME.toUpperCase(), TokenTypes.DATE);\n                    addKeyword(PriorityHeader.NAME.toUpperCase(),\n                            TokenTypes.PRIORITY);\n                    addKeyword(ProxyAuthenticateHeader.NAME.toUpperCase(),\n                            TokenTypes.PROXY_AUTHENTICATE);\n                    addKeyword(ContentEncodingHeader.NAME.toUpperCase(),\n                            TokenTypes.CONTENT_ENCODING);\n                    addKeyword(ContentLengthHeader.NAME.toUpperCase(),\n                            TokenTypes.CONTENT_LENGTH);\n                    addKeyword(SubjectHeader.NAME.toUpperCase(),\n                            TokenTypes.SUBJECT);\n                    addKeyword(ContentTypeHeader.NAME.toUpperCase(),\n                            TokenTypes.CONTENT_TYPE);\n                    addKeyword(ContactHeader.NAME.toUpperCase(),\n                            TokenTypes.CONTACT);\n                    addKeyword(CallIdHeader.NAME.toUpperCase(),\n                            TokenTypes.CALL_ID);\n                    addKeyword(RequireHeader.NAME.toUpperCase(),\n                            TokenTypes.REQUIRE);\n                    addKeyword(ExpiresHeader.NAME.toUpperCase(),\n                            TokenTypes.EXPIRES);\n                    addKeyword(RecordRouteHeader.NAME.toUpperCase(),\n                            TokenTypes.RECORD_ROUTE);\n                    addKeyword(OrganizationHeader.NAME.toUpperCase(),\n                            TokenTypes.ORGANIZATION);\n                    addKeyword(CSeqHeader.NAME.toUpperCase(), TokenTypes.CSEQ);\n                    addKeyword(AcceptLanguageHeader.NAME.toUpperCase(),\n                            TokenTypes.ACCEPT_LANGUAGE);\n                    addKeyword(WWWAuthenticateHeader.NAME.toUpperCase(),\n                            TokenTypes.WWW_AUTHENTICATE);\n                    addKeyword(CallInfoHeader.NAME.toUpperCase(),\n                            TokenTypes.CALL_INFO);\n                    addKeyword(ContentDispositionHeader.NAME.toUpperCase(),\n                            TokenTypes.CONTENT_DISPOSITION);\n                    // And now the dreaded short forms....\n                    addKeyword(TokenNames.K.toUpperCase(), TokenTypes.SUPPORTED);\n                    addKeyword(TokenNames.C.toUpperCase(),\n                            TokenTypes.CONTENT_TYPE);\n                    addKeyword(TokenNames.E.toUpperCase(),\n                            TokenTypes.CONTENT_ENCODING);\n                    addKeyword(TokenNames.F.toUpperCase(), TokenTypes.FROM);\n                    addKeyword(TokenNames.I.toUpperCase(), TokenTypes.CALL_ID);\n                    addKeyword(TokenNames.M.toUpperCase(), TokenTypes.CONTACT);\n                    addKeyword(TokenNames.L.toUpperCase(),\n                            TokenTypes.CONTENT_LENGTH);\n                    addKeyword(TokenNames.S.toUpperCase(), TokenTypes.SUBJECT);\n                    addKeyword(TokenNames.T.toUpperCase(), TokenTypes.TO);\n                    addKeyword(TokenNames.U.toUpperCase(),\n                            TokenTypes.ALLOW_EVENTS); // JvB: added\n                    addKeyword(TokenNames.V.toUpperCase(), TokenTypes.VIA);\n                    addKeyword(TokenNames.R.toUpperCase(), TokenTypes.REFER_TO);\n                    addKeyword(TokenNames.O.toUpperCase(), TokenTypes.EVENT); // Bug fix by Mario Mantak\n                    addKeyword(TokenNames.X.toUpperCase(), TokenTypes.SESSIONEXPIRES_TO); // Bug fix by Jozef Saniga\n                    \n                    // JvB: added to support RFC3903\n                    addKeyword(SIPETagHeader.NAME.toUpperCase(),\n                            TokenTypes.SIP_ETAG);\n                    addKeyword(SIPIfMatchHeader.NAME.toUpperCase(),\n                            TokenTypes.SIP_IF_MATCH);\n\n                    // pmusgrave: Add RFC4028 and ReferredBy\n                    addKeyword(SessionExpiresHeader.NAME.toUpperCase(),\n                            TokenTypes.SESSIONEXPIRES_TO);\n                    addKeyword(MinSEHeader.NAME.toUpperCase(),\n                            TokenTypes.MINSE_TO);\n                    addKeyword(ReferredByHeader.NAME.toUpperCase(), TokenTypes.REFERREDBY_TO);\n                    addKeyword(TokenNames.B.toUpperCase(), TokenTypes.REFERREDBY_TO); // Bug fix OrangeLabs, AUFFRET Jean-Marc\n\n\n                    // pmusgrave RFC3891\n                    addKeyword(ReplacesHeader.NAME.toUpperCase(),\n                            TokenTypes.REPLACES_TO);\n                    //jean deruelle RFC3911\n                    addKeyword(JoinHeader.NAME.toUpperCase(),\n                            TokenTypes.JOIN_TO);\n\n                    // IMS Headers\n                    addKeyword(PathHeader.NAME.toUpperCase(), TokenTypes.PATH);\n                    addKeyword(ServiceRouteHeader.NAME.toUpperCase(),\n                            TokenTypes.SERVICE_ROUTE);\n                    addKeyword(PAssertedIdentityHeader.NAME.toUpperCase(),\n                            TokenTypes.P_ASSERTED_IDENTITY);\n                    addKeyword(PPreferredIdentityHeader.NAME.toUpperCase(),\n                            TokenTypes.P_PREFERRED_IDENTITY);\n                    addKeyword(PrivacyHeader.NAME.toUpperCase(),\n                            TokenTypes.PRIVACY);\n\n                    // issued by Miguel Freitas\n                    addKeyword(PCalledPartyIDHeader.NAME.toUpperCase(),\n                            TokenTypes.P_CALLED_PARTY_ID);\n                    addKeyword(PAssociatedURIHeader.NAME.toUpperCase(),\n                            TokenTypes.P_ASSOCIATED_URI);\n                    addKeyword(PVisitedNetworkIDHeader.NAME.toUpperCase(),\n                            TokenTypes.P_VISITED_NETWORK_ID);\n                    addKeyword(PChargingFunctionAddressesHeader.NAME\n                            .toUpperCase(),\n                            TokenTypes.P_CHARGING_FUNCTION_ADDRESSES);\n                    addKeyword(PChargingVectorHeader.NAME.toUpperCase(),\n                            TokenTypes.P_VECTOR_CHARGING);\n                    addKeyword(PAccessNetworkInfoHeader.NAME.toUpperCase(),\n                            TokenTypes.P_ACCESS_NETWORK_INFO);\n                    addKeyword(PMediaAuthorizationHeader.NAME.toUpperCase(),\n                            TokenTypes.P_MEDIA_AUTHORIZATION);\n\n                    addKeyword(SecurityServerHeader.NAME.toUpperCase(),\n                            TokenTypes.SECURITY_SERVER);\n                    addKeyword(SecurityVerifyHeader.NAME.toUpperCase(),\n                            TokenTypes.SECURITY_VERIFY);\n                    addKeyword(SecurityClientHeader.NAME.toUpperCase(),\n                            TokenTypes.SECURITY_CLIENT);\n\n                    // added by aayush@rancore\n                    addKeyword(PUserDatabaseHeader.NAME.toUpperCase(),\n                            TokenTypes.P_USER_DATABASE);\n\n                    // added by aayush@rancore\n                    addKeyword(PProfileKeyHeader.NAME.toUpperCase(),\n                            TokenTypes.P_PROFILE_KEY);\n\n                    // added by aayush@rancore\n                    addKeyword(PServedUserHeader.NAME.toUpperCase(),\n                            TokenTypes.P_SERVED_USER);\n\n                    // added by aayush@rancore\n                    addKeyword(PPreferredServiceHeader.NAME.toUpperCase(),\n                            TokenTypes.P_PREFERRED_SERVICE);\n\n                    // added by aayush@rancore\n                    addKeyword(PAssertedServiceHeader.NAME.toUpperCase(),\n                            TokenTypes.P_ASSERTED_SERVICE);\n                    \n                    // added References header\n                    addKeyword(ReferencesHeader.NAME.toUpperCase(),TokenTypes.REFERENCES);\n\n                    // end //\n\n\n                } else if (lexerName.equals(\"status_lineLexer\")) {\n                    addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP);\n                } else if (lexerName.equals(\"request_lineLexer\")) {\n                    addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP);\n                } else if (lexerName.equals(\"sip_urlLexer\")) {\n                    addKeyword(TokenNames.TEL.toUpperCase(), TokenTypes.TEL);\n                    addKeyword(TokenNames.SIP.toUpperCase(), TokenTypes.SIP);\n                    addKeyword(TokenNames.SIPS.toUpperCase(), TokenTypes.SIPS);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/MaxForwardsParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport javax2.sip.*;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Max Forwards Header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:00 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class MaxForwardsParser extends HeaderParser {\n\n    public MaxForwardsParser(String contentLength) {\n        super(contentLength);\n    }\n\n    protected MaxForwardsParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"MaxForwardsParser.enter\");\n        try {\n            MaxForwards contentLength = new MaxForwards();\n            headerName(TokenTypes.MAX_FORWARDS);\n            String number = this.lexer.number();\n            contentLength.setMaxForwards(Integer.parseInt(number));\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n            return contentLength;\n        } catch (InvalidArgumentException ex) {\n            throw createParseException(ex.getMessage());\n        } catch (NumberFormatException ex) {\n            throw createParseException(ex.getMessage());\n        } finally {\n            if (debug)\n                dbg_leave(\"MaxForwardsParser.leave\");\n        }\n    }\n\n\n}\n/*\n * $Log: MaxForwardsParser.java,v $\n * Revision 1.7  2009/07/17 18:58:00  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:05  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/08/10 21:35:44  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.3  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/MimeVersionParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for MimeVersion header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:01 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n*/\npublic class MimeVersionParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of MimeVersionParser\n     * @param mimeVersion the header to parse\n     */\n    public MimeVersionParser(String mimeVersion) {\n        super(mimeVersion);\n    }\n\n    /**\n     * Cosntructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected MimeVersionParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (MimeVersion object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"MimeVersionParser.parse\");\n        MimeVersion mimeVersion = new MimeVersion();\n        try {\n            headerName(TokenTypes.MIME_VERSION);\n\n            mimeVersion.setHeaderName(SIPHeaderNames.MIME_VERSION);\n\n            try {\n                String majorVersion = this.lexer.number();\n                mimeVersion.setMajorVersion(Integer.parseInt(majorVersion));\n                this.lexer.match('.');\n                String minorVersion = this.lexer.number();\n                mimeVersion.setMinorVersion(Integer.parseInt(minorVersion));\n\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n            this.lexer.SPorHT();\n\n            this.lexer.match('\\n');\n\n            return mimeVersion;\n        } finally {\n            if (debug)\n                dbg_leave(\"MimeVersionParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: MimeVersionParser.java,v $\n * Revision 1.8  2009/07/17 18:58:01  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:16  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/08/10 21:35:44  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/MinExpiresParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for MinExpires header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:01 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * @version 1.0\n */\npublic class MinExpiresParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of MinExpiresParser\n     * @param minExpires the header to parse\n     */\n    public MinExpiresParser(String minExpires) {\n        super(minExpires);\n    }\n\n    /**\n     * Cosntructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected MinExpiresParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (MinExpiresParser)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"MinExpiresParser.parse\");\n        MinExpires minExpires = new MinExpires();\n        try {\n            headerName(TokenTypes.MIN_EXPIRES);\n\n            minExpires.setHeaderName(SIPHeaderNames.MIN_EXPIRES);\n\n            String number = this.lexer.number();\n            try {\n                minExpires.setExpires(Integer.parseInt(number));\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            } catch (NumberFormatException ex) {\n                throw createParseException(ex.getMessage());\n            }\n            this.lexer.SPorHT();\n\n            this.lexer.match('\\n');\n\n            return minExpires;\n        } finally {\n            if (debug)\n                dbg_leave(\"MinExpiresParser.parse\");\n        }\n    }\n\n\n}\n/*\n * $Log: MinExpiresParser.java,v $\n * Revision 1.8  2009/07/17 18:58:01  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:03  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/08/10 21:35:44  mranga\n * Reviewed by:   mranga\n * move test cases out to another package\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/OrganizationParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/** Parser for Organization header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:01 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class OrganizationParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of OrganizationParser\n     * @param organization the header to parse\n     */\n    public OrganizationParser(String organization) {\n        super(organization);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected OrganizationParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String header\n     * @return SIPHeader (Organization object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"OrganizationParser.parse\");\n        Organization organization = new Organization();\n        try {\n            headerName(TokenTypes.ORGANIZATION);\n\n            organization.setHeaderName(SIPHeaderNames.ORGANIZATION);\n\n            this.lexer.SPorHT();\n            String value = this.lexer.getRest();\n\n            organization.setOrganization(value.trim());\n\n            return organization;\n        } finally {\n            if (debug)\n                dbg_leave(\"OrganizationParser.parse\");\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ParametersParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/** parameters parser header.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:58:01 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic abstract class ParametersParser extends HeaderParser {\n\n    protected ParametersParser(Lexer lexer) {\n        super((Lexer) lexer);\n    }\n\n    protected ParametersParser(String buffer) {\n        super(buffer);\n    }\n\n    protected void parse(ParametersHeader parametersHeader)\n        throws ParseException {\n        this.lexer.SPorHT();\n        while (lexer.lookAhead(0) == ';') {\n            this.lexer.consume(1);\n            // eat white space\n            this.lexer.SPorHT();\n            NameValue nv = nameValue();\n            parametersHeader.setParameter(nv);\n            // eat white space\n            this.lexer.SPorHT();\n        }\n    }\n\n\n\n    protected void parseNameValueList(ParametersHeader parametersHeader)\n        throws ParseException{\n        parametersHeader.removeParameters();\n        while (true) {\n                this.lexer.SPorHT();\n            NameValue nv = nameValue();\n            parametersHeader.setParameter(nv.getName(), (String) nv.getValueAsObject());\n            // eat white space\n            this.lexer.SPorHT();\n            if (lexer.lookAhead(0) != ';')  break;\n            else lexer.consume(1);\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ParseExceptionListener.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.javax2.sip.message.*;\n\nimport java.text.ParseException;\n\n/**\n * A listener interface that enables customization of parse error handling.\n * An class that implements this interface is registered with the\n * parser and is called back from the parser handle parse errors.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:01 $\n */\npublic interface ParseExceptionListener {\n    /**\n     * This gets called from the parser when a parse error is generated.\n     * The handler is supposed to introspect on the error class and\n     * header name to handle the error appropriately. The error can\n     * be handled by :\n     *<ul>\n     * <li>1. Re-throwing an exception and aborting the parse.\n     * <li>2. Ignoring the header (attach the unparseable header to\n     * the SIPMessage being parsed).\n     * <li>3. Re-Parsing the bad header and adding it to the sipMessage\n     * </ul>\n     *\n     * @param  ex - parse exception being processed.\n     * @param  sipMessage -- sip message being processed.\n     * @param headerText --  header/RL/SL text being parsed.\n     * @param messageText -- message where this header was detected.\n     */\n    public void handleException(\n        ParseException ex,\n        SIPMessage sipMessage,\n        Class headerClass,\n        String headerText,\n        String messageText)\n        throws ParseException;\n}\n/*\n * $Log: ParseExceptionListener.java,v $\n * Revision 1.7  2009/07/17 18:58:01  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:01:55  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/Parser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.core.Debug;\nimport gov2.nist.core.LexerCore;\nimport gov2.nist.core.ParserCore;\nimport gov2.nist.core.Token;\n\nimport java.text.ParseException;\n\n/**\n * Base parser class.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/17 18:58:01 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic abstract class Parser extends ParserCore implements TokenTypes {\n\n    protected ParseException createParseException(String exceptionString) {\n        return new ParseException(\n            lexer.getBuffer() + \":\" + exceptionString,\n            lexer.getPtr());\n    }\n\n    protected Lexer getLexer() {\n        return (Lexer) this.lexer;\n    }\n\n    protected String sipVersion() throws ParseException {\n        if (debug)\n            dbg_enter(\"sipVersion\");\n        try {\n            Token tok = lexer.match(SIP);\n            if (!tok.getTokenValue().equalsIgnoreCase(\"SIP\"))\n                createParseException(\"Expecting SIP\");\n            lexer.match('/');\n            tok = lexer.match(ID);\n            if (!tok.getTokenValue().equals(\"2.0\"))\n                createParseException(\"Expecting SIP/2.0\");\n\n            return \"SIP/2.0\";\n        } finally {\n            if (debug)\n                dbg_leave(\"sipVersion\");\n        }\n    }\n\n    /**\n     * parses a method. Consumes if a valid method has been found.\n     */\n    protected String method() throws ParseException {\n        try {\n            if (debug)\n                dbg_enter(\"method\");\n            Token[] tokens = this.lexer.peekNextToken(1);\n            Token token = (Token) tokens[0];\n            if (token.getTokenType() == INVITE\n                || token.getTokenType() == ACK\n                || token.getTokenType() == OPTIONS\n                || token.getTokenType() == BYE\n                || token.getTokenType() == REGISTER\n                || token.getTokenType() == CANCEL\n                || token.getTokenType() == SUBSCRIBE\n                || token.getTokenType() == NOTIFY\n                || token.getTokenType() == PUBLISH\n                || token.getTokenType() == MESSAGE\n                || token.getTokenType() == ID) {\n                lexer.consume();\n                return token.getTokenValue();\n            } else {\n                throw createParseException(\"Invalid Method\");\n            }\n        } finally {\n            if (Debug.debug)\n                dbg_leave(\"method\");\n        }\n    }\n\n    /**\n     * Verifies that a given string matches the 'token' production in RFC3261\n     *\n     * @param token\n     * @throws ParseException - if there are invalid characters\n     *\n     * @author JvB\n     */\n    public static final void checkToken( String token ) throws ParseException {\n\n        if (token == null || token.length()==0 ) {\n            throw new ParseException(\"null or empty token\", -1 );\n        } else {\n            // JvB: check that it is a valid token\n            for ( int i=0; i<token.length(); ++i ) {\n                if ( !LexerCore.isTokenChar( token.charAt(i) )) {\n                    throw new ParseException( \"Invalid character(s) in string (not allowed in 'token')\", i );\n                }\n            }\n        }\n    }\n}\n/*\n * $Log: Parser.java,v $\n * Revision 1.10  2009/07/17 18:58:01  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.9  2008/01/18 11:19:24  jbemmel\n * added a method to check strings for valid token characters\n *\n * Revision 1.8  2007/02/23 14:56:05  belangery\n * Added performance improvement around header name lowercase conversion.\n *\n * Revision 1.7  2006/09/27 15:02:43  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:\n * Reviewed by:   mranga\n * rfc 2543 transaction matching. fix for MESSAGE request type parsing.\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.6  2006/07/13 09:02:18  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.5  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.4  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.3  2005/11/21 23:24:49  jeroen\n * \"SIP\" is case insensitive\n *\n * Revision 1.2  2005/10/27 20:49:00  jeroen\n * added support for RFC3903 PUBLISH\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.3  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ParserFactory.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport java.util.Hashtable;\nimport java.lang.reflect.*;\n\nimport javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.SIPHeaderNamesCache;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.header.ims.*;\nimport gov2.nist.javax2.sip.parser.extensions.*;\nimport gov2.nist.javax2.sip.parser.ims.*;\n\n/**\n * A factory class that does a name lookup on a registered parser and\n * returns a header parser for the given name.\n *\n * @version 1.2 $Revision: 1.17 $ $Date: 2010/01/12 00:05:25 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ParserFactory {\n\n    private static Hashtable<String,Class<? extends HeaderParser>> parserTable;\n    private static Class[] constructorArgs;\n    private static Hashtable parserConstructorCache;\n\n    static {\n        parserTable = new Hashtable<String,Class<? extends HeaderParser>>();\n        parserConstructorCache = new Hashtable();\n        constructorArgs = new Class[1];\n        constructorArgs[0] = String.class;\n        parserTable.put(ReplyToHeader.NAME.toLowerCase(), ReplyToParser.class);\n\n        parserTable.put(\n            InReplyToHeader.NAME.toLowerCase(),\n            InReplyToParser.class);\n\n        parserTable.put(\n            AcceptEncodingHeader.NAME.toLowerCase(),\n            AcceptEncodingParser.class);\n\n        parserTable.put(\n            AcceptLanguageHeader.NAME.toLowerCase(),\n            AcceptLanguageParser.class);\n\n        parserTable.put(\"t\", ToParser.class);\n        parserTable.put(ToHeader.NAME.toLowerCase(), ToParser.class);\n\n        parserTable.put(FromHeader.NAME.toLowerCase(), FromParser.class);\n        parserTable.put(\"f\", FromParser.class);\n\n        parserTable.put(CSeqHeader.NAME.toLowerCase(), CSeqParser.class);\n\n        parserTable.put(ViaHeader.NAME.toLowerCase(), ViaParser.class);\n        parserTable.put(\"v\", ViaParser.class);\n\n        parserTable.put(ContactHeader.NAME.toLowerCase(), ContactParser.class);\n        parserTable.put(\"m\", ContactParser.class);\n\n        parserTable.put(\n            ContentTypeHeader.NAME.toLowerCase(),\n            ContentTypeParser.class);\n        parserTable.put(\"c\", ContentTypeParser.class);\n\n        parserTable.put(\n            ContentLengthHeader.NAME.toLowerCase(),\n            ContentLengthParser.class);\n        parserTable.put(\"l\", ContentLengthParser.class);\n\n        parserTable.put(\n            AuthorizationHeader.NAME.toLowerCase(),\n            AuthorizationParser.class);\n\n        parserTable.put(\n            WWWAuthenticateHeader.NAME.toLowerCase(),\n            WWWAuthenticateParser.class);\n\n        parserTable.put(CallIdHeader.NAME.toLowerCase(), CallIDParser.class);\n        parserTable.put(\"i\", CallIDParser.class);\n\n        parserTable.put(RouteHeader.NAME.toLowerCase(), RouteParser.class);\n\n        parserTable.put(\n            RecordRouteHeader.NAME.toLowerCase(),\n            RecordRouteParser.class);\n\n        parserTable.put(DateHeader.NAME.toLowerCase(), DateParser.class);\n\n        parserTable.put(\n            ProxyAuthorizationHeader.NAME.toLowerCase(),\n            ProxyAuthorizationParser.class);\n\n        parserTable.put(\n            ProxyAuthenticateHeader.NAME.toLowerCase(),\n            ProxyAuthenticateParser.class);\n\n        parserTable.put(\n            RetryAfterHeader.NAME.toLowerCase(),\n            RetryAfterParser.class);\n\n        parserTable.put(RequireHeader.NAME.toLowerCase(), RequireParser.class);\n\n        parserTable.put(\n            ProxyRequireHeader.NAME.toLowerCase(),\n            ProxyRequireParser.class);\n\n        parserTable.put(\n            TimeStampHeader.NAME.toLowerCase(),\n            TimeStampParser.class);\n\n        parserTable.put(\n            UnsupportedHeader.NAME.toLowerCase(),\n            UnsupportedParser.class);\n\n        parserTable.put(\n            UserAgentHeader.NAME.toLowerCase(),\n            UserAgentParser.class);\n\n        parserTable.put(\n            SupportedHeader.NAME.toLowerCase(),\n            SupportedParser.class);\n        // bug fix by Steve Crosley\n        parserTable.put(\"k\", SupportedParser.class);\n\n        parserTable.put(ServerHeader.NAME.toLowerCase(), ServerParser.class);\n\n        parserTable.put(SubjectHeader.NAME.toLowerCase(), SubjectParser.class);\n        parserTable.put( \"s\", SubjectParser.class); // JvB: added\n\n        parserTable.put(\n            SubscriptionStateHeader.NAME.toLowerCase(),\n            SubscriptionStateParser.class);\n\n        parserTable.put(\n            MaxForwardsHeader.NAME.toLowerCase(),\n            MaxForwardsParser.class);\n\n        parserTable.put(\n            MimeVersionHeader.NAME.toLowerCase(),\n            MimeVersionParser.class);\n\n        parserTable.put(\n            MinExpiresHeader.NAME.toLowerCase(),\n            MinExpiresParser.class);\n\n        parserTable.put(\n            OrganizationHeader.NAME.toLowerCase(),\n            OrganizationParser.class);\n\n        parserTable.put(\n            PriorityHeader.NAME.toLowerCase(),\n            PriorityParser.class);\n\n        parserTable.put(RAckHeader.NAME.toLowerCase(), RAckParser.class);\n\n        parserTable.put(RSeqHeader.NAME.toLowerCase(), RSeqParser.class);\n\n        parserTable.put(ReasonHeader.NAME.toLowerCase(), ReasonParser.class);\n\n        parserTable.put(WarningHeader.NAME.toLowerCase(), WarningParser.class);\n\n        parserTable.put(ExpiresHeader.NAME.toLowerCase(), ExpiresParser.class);\n\n        parserTable.put(EventHeader.NAME.toLowerCase(), EventParser.class);\n        parserTable.put(\"o\", EventParser.class);\n\n        parserTable.put(\n            ErrorInfoHeader.NAME.toLowerCase(),\n            ErrorInfoParser.class);\n\n        parserTable.put(\n            ContentLanguageHeader.NAME.toLowerCase(),\n            ContentLanguageParser.class);\n\n        parserTable.put(\n            ContentEncodingHeader.NAME.toLowerCase(),\n            ContentEncodingParser.class);\n        parserTable.put(\"e\", ContentEncodingParser.class);\n\n        parserTable.put(\n            ContentDispositionHeader.NAME.toLowerCase(),\n            ContentDispositionParser.class);\n\n        parserTable.put(\n            CallInfoHeader.NAME.toLowerCase(),\n            CallInfoParser.class);\n\n        parserTable.put(\n            AuthenticationInfoHeader.NAME.toLowerCase(),\n            AuthenticationInfoParser.class);\n\n        parserTable.put(AllowHeader.NAME.toLowerCase(), AllowParser.class);\n\n        parserTable.put(\n            AllowEventsHeader.NAME.toLowerCase(),\n            AllowEventsParser.class);\n        parserTable.put(\"u\", AllowEventsParser.class);\n\n        parserTable.put(\n            AlertInfoHeader.NAME.toLowerCase(),\n            AlertInfoParser.class);\n\n        parserTable.put(AcceptHeader.NAME.toLowerCase(), AcceptParser.class);\n\n        parserTable.put(ReferToHeader.NAME.toLowerCase(), ReferToParser.class);\n        // Was missing (bug noticed by Steve Crossley)\n        parserTable.put(\"r\", ReferToParser.class);\n\n        // JvB: added to support RFC3903 PUBLISH\n        parserTable.put(SIPETagHeader.NAME.toLowerCase(), SIPETagParser.class);\n        parserTable.put(SIPIfMatchHeader.NAME.toLowerCase(), SIPIfMatchParser.class);\n\n        //IMS headers\n        parserTable.put(PAccessNetworkInfoHeader.NAME.toLowerCase(), PAccessNetworkInfoParser.class);\n        parserTable.put(PAssertedIdentityHeader.NAME.toLowerCase(), PAssertedIdentityParser.class);\n        parserTable.put(PPreferredIdentityHeader.NAME.toLowerCase(), PPreferredIdentityParser.class);\n        parserTable.put(PChargingVectorHeader.NAME.toLowerCase(), PChargingVectorParser.class);\n        parserTable.put(PChargingFunctionAddressesHeader.NAME.toLowerCase(), PChargingFunctionAddressesParser.class);\n        parserTable.put(PMediaAuthorizationHeader.NAME.toLowerCase(), PMediaAuthorizationParser.class);\n        parserTable.put(PathHeader.NAME.toLowerCase(), PathParser.class);\n        parserTable.put(PrivacyHeader.NAME.toLowerCase(), PrivacyParser.class);\n        parserTable.put(ServiceRouteHeader.NAME.toLowerCase(), ServiceRouteParser.class);\n        parserTable.put(PVisitedNetworkIDHeader.NAME.toLowerCase(), PVisitedNetworkIDParser.class);\n\n        parserTable.put(PAssociatedURIHeader.NAME.toLowerCase(), PAssociatedURIParser.class);\n        parserTable.put(PCalledPartyIDHeader.NAME.toLowerCase(), PCalledPartyIDParser.class);\n\n        parserTable.put(SecurityServerHeader.NAME.toLowerCase(), SecurityServerParser.class);\n        parserTable.put(SecurityClientHeader.NAME.toLowerCase(), SecurityClientParser.class);\n        parserTable.put(SecurityVerifyHeader.NAME.toLowerCase(), SecurityVerifyParser.class);\n\n\n        // Per RFC 3892 (pmusgrave)\n        parserTable.put(ReferredBy.NAME.toLowerCase(), ReferredByParser.class);\n        parserTable.put(\"b\", ReferredByParser.class); // Bug fix OrangeLabs, AUFFRET Jean-Marc\n\n        // Per RFC4028 Session Timers (pmusgrave)\n        parserTable.put(SessionExpires.NAME.toLowerCase(), SessionExpiresParser.class);\n        parserTable.put(\"x\", SessionExpiresParser.class);\n        parserTable.put(MinSE.NAME.toLowerCase(), MinSEParser.class);\n        // (RFC4028 does not give a short form header for MinSE)\n\n        // Per RFC3891 (pmusgrave)\n        parserTable.put(Replaces.NAME.toLowerCase(), ReplacesParser.class);\n\n        // Per RFC3911 (jean deruelle)\n        parserTable.put(Join.NAME.toLowerCase(), JoinParser.class);\n        \n        //http://tools.ietf.org/html/draft-worley-references-05\n        parserTable.put(References.NAME.toLowerCase(), ReferencesParser.class);\n    }\n\n    /**\n     * create a parser for a header. This is the parser factory.\n     */\n    public static HeaderParser createParser(String line)\n        throws ParseException {\n        String headerName = Lexer.getHeaderName(line);\n        String headerValue = Lexer.getHeaderValue(line);\n        if (headerName == null || headerValue == null)\n            throw new ParseException(\"The header name or value is null\", 0);\n\n        Class parserClass = (Class) parserTable.get(SIPHeaderNamesCache.toLowerCase(headerName));\n        if (parserClass != null) {\n            try {\n                Constructor cons = (Constructor) parserConstructorCache.get(parserClass);\n                if (cons == null) {\n                    cons = parserClass.getConstructor(constructorArgs);\n                    parserConstructorCache.put(parserClass, cons);\n                }\n                Object[] args = new Object[1];\n                args[0] = line;\n                HeaderParser retval = (HeaderParser) cons.newInstance(args);\n                return retval;\n\n            } catch (Exception ex) {\n                InternalErrorHandler.handleException(ex);\n                return null; // to placate the compiler.\n            }\n\n        } else {\n            // Just generate a generic SIPHeader. We define\n            // parsers only for the above.\n            return new HeaderParser(line);\n        }\n    }\n}\n/*\n * $Log: ParserFactory.java,v $\n * Revision 1.17  2010/01/12 00:05:25  mranga\n * Add support for References header draft-worley-references-05\n *\n * Revision 1.16  2009/07/17 18:58:01  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.15  2009/01/22 19:33:48  deruelle_jean\n * Add support for JOIN (RFC 3911)\n * Issue number:  186\n * Obtained from:\n * Submitted by:  Jean Deruelle\n * Reviewed by:   Ranga, The high priest and grand poobah of Jain-SIP\n *\n * Revision 1.14  2007/03/07 14:29:46  belangery\n * Yet another bunch of improvements in the parsing code.\n *\n * Revision 1.13  2007/02/23 14:56:06  belangery\n * Added performance improvement around header name lowercase conversion.\n *\n * Revision 1.12  2007/01/08 19:24:21  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  Miguel Freitas\n * Reviewed by:   mranga\n *\n * Miguel -- please implement a deep clone method for the IMS headers.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.11  2006/10/12 11:57:54  pmusgrave\n * Issue number:  79, 80\n * Submitted by:  pmusgrave@newheights.com\n * Reviewed by:   mranga\n *\n * Revision 1.10  2006/09/29 19:40:50  jbemmel\n * fixed missing IMS header parsing plumbing\n *\n * Revision 1.9  2006/09/11 18:41:32  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:\n * Tighter integration of IMS headers.\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.8  2006/08/15 21:44:50  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Incorporating the latest API changes from Phelim\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.7  2006/07/13 09:02:06  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.5  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.4  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.3  2005/10/27 20:49:00  jeroen\n * added support for RFC3903 PUBLISH\n *\n * Revision 1.2  2005/10/14 19:59:00  jeroen\n * bugfix: missing parser for shortform of Subject (s)\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2005/04/04 09:29:03  dmuresan\n * Replaced new String().getClass() with String.class.\n *\n * Revision 1.3  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/Pipeline.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.stack.SIPStackTimerTask;\n\nimport java.io.*;\nimport java.util.*;\n\n/**\n * Input class for the pipelined parser. Buffer all bytes read from the socket\n * and make them available to the message parser.\n *\n * @author M. Ranganathan (Contains a bug fix contributed by Rob Daugherty (\n *         Lucent Technologies) )\n *\n */\n\npublic class Pipeline extends InputStream {\n    private LinkedList buffList;\n\n    private Buffer currentBuffer;\n\n    private boolean isClosed;\n\n    private Timer timer;\n\n    private InputStream pipe;\n\n    private int readTimeout;\n\n    private TimerTask myTimerTask;\n\n    class MyTimer extends SIPStackTimerTask {\n        Pipeline pipeline;\n\n        private boolean isCancelled;\n\n        protected MyTimer(Pipeline pipeline) {\n            this.pipeline = pipeline;\n        }\n\n        protected void runTask() {\n            if (this.isCancelled)\n                return;\n\n            try {\n                pipeline.close();\n            } catch (IOException ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n        }\n\n        public boolean cancel() {\n            boolean retval = super.cancel();\n            this.isCancelled = true;\n            return retval;\n        }\n\n    }\n\n    class Buffer {\n        byte[] bytes;\n\n        int length;\n\n        int ptr;\n\n        public Buffer(byte[] bytes, int length) {\n            ptr = 0;\n            this.length = length;\n            this.bytes = bytes;\n        }\n\n        public int getNextByte() {\n            int retval = bytes[ptr++] & 0xFF;\n            return retval;\n        }\n\n    }\n\n    public void startTimer() {\n        if (this.readTimeout == -1)\n            return;\n        // TODO make this a tunable number. For now 4 seconds\n        // between reads seems reasonable upper limit.\n        this.myTimerTask = new MyTimer(this);\n        this.timer.schedule(this.myTimerTask, this.readTimeout);\n    }\n\n    public void stopTimer() {\n        if (this.readTimeout == -1)\n            return;\n        if (this.myTimerTask != null)\n            this.myTimerTask.cancel();\n    }\n\n    public Pipeline(InputStream pipe, int readTimeout, Timer timer) {\n        // pipe is the Socket stream\n        // this is recorded here to implement a timeout.\n        this.timer = timer;\n        this.pipe = pipe;\n        buffList = new LinkedList();\n        this.readTimeout = readTimeout;\n    }\n\n    public void write(byte[] bytes, int start, int length) throws IOException {\n        if (this.isClosed)\n            throw new IOException(\"Closed!!\");\n        Buffer buff = new Buffer(bytes, length);\n        buff.ptr = start;\n        synchronized (this.buffList) {\n            buffList.add(buff);\n            buffList.notifyAll();\n        }\n    }\n\n    public void write(byte[] bytes) throws IOException {\n        if (this.isClosed)\n            throw new IOException(\"Closed!!\");\n        Buffer buff = new Buffer(bytes, bytes.length);\n        synchronized (this.buffList) {\n            buffList.add(buff);\n            buffList.notifyAll();\n        }\n    }\n\n    public void close() throws IOException {\n        this.isClosed = true;\n        synchronized (this.buffList) {\n            this.buffList.notifyAll();\n        }\n\n        // JvB: added\n        this.pipe.close();\n    }\n\n    public int read() throws IOException {\n        // if (this.isClosed) return -1;\n        synchronized (this.buffList) {\n            if (currentBuffer != null\n                    && currentBuffer.ptr < currentBuffer.length) {\n                int retval = currentBuffer.getNextByte();\n                if (currentBuffer.ptr == currentBuffer.length)\n                    this.currentBuffer = null;\n                return retval;\n            }\n            // Bug fix contributed by Rob Daugherty.\n            if (this.isClosed && this.buffList.isEmpty())\n                return -1;\n            try {\n                // wait till something is posted.\n                while (this.buffList.isEmpty()) {\n                    this.buffList.wait();\n                    if (this.isClosed)\n                        return -1;\n                }\n                currentBuffer = (Buffer) this.buffList.removeFirst();\n                int retval = currentBuffer.getNextByte();\n                if (currentBuffer.ptr == currentBuffer.length)\n                    this.currentBuffer = null;\n                return retval;\n            } catch (InterruptedException ex) {\n                throw new IOException(ex.getMessage());\n            } catch (NoSuchElementException ex) {\n                ex.printStackTrace();\n                throw new IOException(ex.getMessage());\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/PipelinedMsgParser.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)       *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.parser;\n\n/*\n *\n * Lamine Brahimi and Yann Duponchel (IBM Zurich) noticed that the parser was\n * blocking so I threw out some cool pipelining which ran fast but only worked\n * when the phase of the moon matched its mood. Now things are serialized and\n * life goes slower but more reliably.\n *\n */\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.message.*;\n\nimport java.text.ParseException;\nimport java.io.*;\n\n/**\n * This implements a pipelined message parser suitable for use with a stream -\n * oriented input such as TCP. The client uses this class by instatiating with\n * an input stream from which input is read and fed to a message parser. It\n * keeps reading from the input stream and process messages in a never ending\n * interpreter loop. The message listener interface gets called for processing\n * messages or for processing errors. The payload specified by the\n * content-length header is read directly from the input stream. This can be\n * accessed from the SIPMessage using the getContent and getContentBytes methods\n * provided by the SIPMessage class.\n *\n * @version 1.2 $Revision: 1.23 $ $Date: 2009/08/16 17:28:28 $\n *\n * @author M. Ranganathan\n *\n * @see SIPMessageListener\n */\npublic final class PipelinedMsgParser implements Runnable {\n\n\n\n    /**\n     * The message listener that is registered with this parser. (The message\n     * listener has methods that can process correct and erroneous messages.)\n     */\n    protected SIPMessageListener sipMessageListener;\n    private Thread mythread; // Preprocessor thread\n    //private byte[] messageBody;\n    //private boolean errorFlag;\n    private Pipeline rawInputStream;\n    private int maxMessageSize;\n    private int sizeCounter;\n    //private int messageSize;\n\n    /**\n     * default constructor.\n     */\n    protected PipelinedMsgParser() {\n        super();\n\n    }\n\n    private static int uid = 0;\n\n    private static synchronized int getNewUid() {\n        return uid++;\n    }\n\n    /**\n     * Constructor when we are given a message listener and an input stream\n     * (could be a TCP connection or a file)\n     *\n     * @param sipMessageListener\n     *            Message listener which has methods that get called back from\n     *            the parser when a parse is complete\n     * @param in\n     *            Input stream from which to read the input.\n     * @param debug\n     *            Enable/disable tracing or lexical analyser switch.\n     */\n    public PipelinedMsgParser(SIPMessageListener sipMessageListener,\n            Pipeline in, boolean debug, int maxMessageSize) {\n        this();\n        this.sipMessageListener = sipMessageListener;\n        rawInputStream = in;\n        this.maxMessageSize = maxMessageSize;\n        mythread = new Thread(this);\n        mythread.setName(\"PipelineThread-\" + getNewUid());\n\n    }\n\n    /**\n     * This is the constructor for the pipelined parser.\n     *\n     * @param mhandler\n     *            a SIPMessageListener implementation that provides the message\n     *            handlers to handle correctly and incorrectly parsed messages.\n     * @param in\n     *            An input stream to read messages from.\n     */\n\n    public PipelinedMsgParser(SIPMessageListener mhandler, Pipeline in,\n            int maxMsgSize) {\n        this(mhandler, in, false, maxMsgSize);\n    }\n\n    /**\n     * This is the constructor for the pipelined parser.\n     *\n     * @param in -\n     *            An input stream to read messages from.\n     */\n\n    public PipelinedMsgParser(Pipeline in) {\n        this(null, in, false, 0);\n    }\n\n    /**\n     * Start reading and processing input.\n     */\n    public void processInput() {\n        mythread.start();\n    }\n\n    /**\n     * Create a new pipelined parser from an existing one.\n     *\n     * @return A new pipelined parser that reads from the same input stream.\n     */\n    protected Object clone() {\n        PipelinedMsgParser p = new PipelinedMsgParser();\n\n        p.rawInputStream = this.rawInputStream;\n        p.sipMessageListener = this.sipMessageListener;\n        Thread mythread = new Thread(p);\n        mythread.setName(\"PipelineThread\");\n        return p;\n    }\n\n    /**\n     * Add a class that implements a SIPMessageListener interface whose methods\n     * get called * on successful parse and error conditons.\n     *\n     * @param mlistener\n     *            a SIPMessageListener implementation that can react to correct\n     *            and incorrect pars.\n     */\n\n    public void setMessageListener(SIPMessageListener mlistener) {\n        sipMessageListener = mlistener;\n    }\n\n    /**\n     * read a line of input (I cannot use buffered reader because we may need to\n     * switch encodings mid-stream!\n     */\n    private String readLine(InputStream inputStream) throws IOException {\n        StringBuffer retval = new StringBuffer(\"\");\n        while (true) {\n            char ch;\n            int i = inputStream.read();\n            if (i == -1) {\n                throw new IOException(\"End of stream\");\n            } else\n                ch = (char) i;\n            // reduce the available read size by 1 (\"size\" of a char).\n            if (this.maxMessageSize > 0) {\n                this.sizeCounter--;\n                if (this.sizeCounter <= 0)\n                    throw new IOException(\"Max size exceeded!\");\n            }\n            if (ch != '\\r')\n                retval.append(ch);\n            if (ch == '\\n') {\n                break;\n            }\n        }\n        return retval.toString();\n    }\n\n    /**\n     * This is input reading thread for the pipelined parser. You feed it input\n     * through the input stream (see the constructor) and it calls back an event\n     * listener interface for message processing or error. It cleans up the\n     * input - dealing with things like line continuation\n     */\n    public void run() {\n\n        Pipeline inputStream = this.rawInputStream;\n        // inputStream = new MyFilterInputStream(this.rawInputStream);\n        // I cannot use buffered reader here because we may need to switch\n        // encodings to read the message body.\n        try {\n            while (true) {\n                this.sizeCounter = this.maxMessageSize;\n                // this.messageSize = 0;\n                StringBuffer inputBuffer = new StringBuffer();\n\n                if (Debug.parserDebug)\n                    Debug.println(\"Starting parse!\");\n\n                String line1;\n                String line2 = null;\n\n                while (true) {\n                    try {\n                        line1 = readLine(inputStream);\n                        // ignore blank lines.\n                        if (line1.equals(\"\\n\")) {\n                            if (Debug.parserDebug) {\n                                Debug.println(\"Discarding blank line. \");\n                            }\n                            continue;\n                        } else\n                            break;\n                    } catch (IOException ex) {\n                        Debug.printStackTrace(ex);\n                        this.rawInputStream.stopTimer();\n                        return;\n\n                    }\n                }\n\n                inputBuffer.append(line1);\n                // Guard against bad guys.\n                this.rawInputStream.startTimer();\n\n                Debug.println(\"Reading Input Stream\");\n                while (true) {\n                    try {\n                        line2 = readLine(inputStream);\n                        inputBuffer.append(line2);\n                        if (line2.trim().equals(\"\"))\n                            break;\n                    } catch (IOException ex) {\n                        this.rawInputStream.stopTimer();\n                        Debug.printStackTrace(ex);\n                        return;\n\n                    }\n                }\n\n                // Stop the timer that will kill the read.\n                this.rawInputStream.stopTimer();\n                inputBuffer.append(line2);\n                StringMsgParser smp = new StringMsgParser(sipMessageListener);\n                smp.readBody = false;\n                SIPMessage sipMessage = null;\n\n                try {\n                    if (Debug.debug) {\n                        Debug.println(\"About to parse : \" + inputBuffer.toString());\n                    }\n                    sipMessage = smp.parseSIPMessage(inputBuffer.toString());\n                    if (sipMessage == null) {\n                        this.rawInputStream.stopTimer();\n                        continue;\n                    }\n                } catch (ParseException ex) {\n                    // Just ignore the parse exception.\n                    Debug.logError(\"Detected a parse error\", ex);\n                    continue;\n                }\n\n                if (Debug.debug) {\n                    Debug.println(\"Completed parsing message\");\n                }\n                ContentLength cl = (ContentLength) sipMessage\n                        .getContentLength();\n                int contentLength = 0;\n                if (cl != null) {\n                    contentLength = cl.getContentLength();\n                } else {\n                    contentLength = 0;\n                }\n\n                if (Debug.debug) {\n                    Debug.println(\"contentLength \" + contentLength);\n                }\n\n                if (contentLength == 0) {\n                    sipMessage.removeContent();\n                } else if (maxMessageSize == 0\n                        || contentLength < this.sizeCounter) {\n                    byte[] message_body = new byte[contentLength];\n                    int nread = 0;\n                    while (nread < contentLength) {\n                        // Start my starvation timer.\n                        // This ensures that the other end\n                        // writes at least some data in\n                        // or we will close the pipe from\n                        // him. This prevents DOS attack\n                        // that takes up all our connections.\n                        this.rawInputStream.startTimer();\n                        try {\n\n                            int readlength = inputStream.read(message_body,\n                                    nread, contentLength - nread);\n                            if (readlength > 0) {\n                                nread += readlength;\n                            } else {\n                                break;\n                            }\n                        } catch (IOException ex) {\n                            Debug.logError(\"Exception Reading Content\",ex);\n                            break;\n                        } finally {\n                            // Stop my starvation timer.\n                            this.rawInputStream.stopTimer();\n                        }\n                    }\n                    sipMessage.setMessageContent(message_body);\n                }\n                // Content length too large - process the message and\n                // return error from there.\n                if (sipMessageListener != null) {\n                    try {\n                        sipMessageListener.processMessage(sipMessage);\n                    } catch (Exception ex) {\n                        // fatal error in processing - close the\n                        // connection.\n                        break;\n                    }\n                }\n            }\n        } finally {\n            try {\n                inputStream.close();\n            } catch (IOException e) {\n                InternalErrorHandler.handleException(e);\n            }\n        }\n    }\n\n    public void close() {\n        try {\n            this.rawInputStream.close();\n        } catch (IOException ex) {\n            // Ignore.\n        }\n    }\n}\n/*\n * $Log: PipelinedMsgParser.java,v $\n * Revision 1.23  2009/08/16 17:28:28  mranga\n * Issue number:  208\n * Obtained from:\n * Submitted by:\n * Reviewed by:\n *\n * Add authentication mechanism that uses H(username:domain:password)\n *\n * Revision 1.22  2009/07/17 18:58:02  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.21  2008/05/24 04:10:01  mranga\n *\n * Issue number:   158\n * Obtained from:\n * Submitted by:\n * Reviewed by:   mranga\n *\n * Deliver tx timeout for Canceled INVITE. Fix pipeline thread exit.\n *\n * Revision 1.20  2008/05/22 19:38:07  jbemmel\n * Fix for issue 149: the logic wasn't always closing the internal socket pipe,\n * causing the pipe reader thread to block indefinitely\n *\n * Repeatedly starting/stopping the stack then gives hanging threads\n * Revision 1.19 2007/01/28 13:06:21 mranga\n * Issue number: 99 Obtained from: Submitted by: Reviewed by: mranga\n *\n * Fixed PRACK handling null pointer exception (for proxy case) and cleanup of\n * unused variables.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number: CVS: If this change addresses one or more issues, CVS:\n * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change\n * has been taken from another system, CVS: then name the system in this line,\n * otherwise delete it. CVS: Submitted by: CVS: If this code has been\n * contributed to the project by someone else; i.e., CVS: they sent us a patch\n * or a set of diffs, then include their name/email CVS: address here. If this\n * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing\n * pre-commit code reviews and someone else has CVS: reviewed your changes,\n * include their name(s) here. CVS: If you have not had it reviewed then delete\n * this line.\n *\n * Revision 1.18 2006/07/13 09:02:10 mranga Issue number: Obtained from:\n * Submitted by: jeroen van bemmel Reviewed by: mranga Moved some changes from\n * jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number: CVS: If this change addresses one or more issues, CVS:\n * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change\n * has been taken from another system, CVS: then name the system in this line,\n * otherwise delete it. CVS: Submitted by: CVS: If this code has been\n * contributed to the project by someone else; i.e., CVS: they sent us a patch\n * or a set of diffs, then include their name/email CVS: address here. If this\n * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing\n * pre-commit code reviews and someone else has CVS: reviewed your changes,\n * include their name(s) here. CVS: If you have not had it reviewed then delete\n * this line.\n *\n * Revision 1.4 2006/06/19 06:47:27 mranga javadoc fixups\n *\n * Revision 1.3 2006/06/17 10:18:14 mranga Added some synchronization to the\n * sequence number checking. Small javadoc fixups\n *\n * Revision 1.2 2006/06/16 15:26:28 mranga Added NIST disclaimer to all public\n * domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1 2005/10/04 17:12:35 mranga\n *\n * Import\n *\n *\n * Revision 1.16 2004/11/30 23:28:14 mranga Issue number: 44 Submitted by: Rob\n * Daugherty Reviewed by: M. Ranganathan\n *\n * TCP Pipelining truncates content when other end of pipe is closed.\n *\n * Revision 1.15 2004/05/30 18:55:56 mranga Reviewed by: mranga Move to timers\n * and eliminate the Transaction scanner Thread to improve scalability and\n * reduce cpu usage.\n *\n * Revision 1.14 2004/05/16 14:13:22 mranga Reviewed by: mranga Fixed the\n * use-count issue reported by Peter Parnes. Added property to prevent against\n * content-length dos attacks.\n *\n * Revision 1.13 2004/03/19 04:22:22 mranga Reviewed by: mranga Added IO Pacing\n * for long writes - split write into chunks and flush after each chunk to avoid\n * socket back pressure.\n *\n * Revision 1.12 2004/03/18 22:01:19 mranga Reviewed by: mranga Get rid of the\n * PipedInputStream from pipelined parser to avoid a copy.\n *\n * Revision 1.11 2004/03/07 22:25:23 mranga Reviewed by: mranga Added a new\n * configuration parameter that instructs the stack to drop a server connection\n * after server transaction termination set\n * gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS=false for this Default behavior\n * is true.\n *\n * Revision 1.10 2004/02/29 15:32:58 mranga Reviewed by: mranga bug fixes on\n * limiting the max message size.\n *\n * Revision 1.9 2004/02/29 00:46:34 mranga Reviewed by: mranga Added new\n * configuration property to limit max message size for TCP transport. The\n * property is gov2.nist.javax2.sip.MAX_MESSAGE_SIZE\n *\n * Revision 1.8 2004/02/25 21:43:03 mranga Reviewed by: mranga Added a couple of\n * todo's and removed some debug printlns that could slow code down by a bit.\n *\n * Revision 1.7 2004/02/25 20:52:46 mranga Reviewed by: mranga Fix TCP transport\n * so messages in excess of 8192 bytes are accepted.\n *\n * Revision 1.6 2004/01/22 18:39:41 mranga Reviewed by: M. Ranganathan Moved the\n * ifdef SIMULATION and associated tags to the first column so Prep preprocessor\n * can deal with them.\n *\n * Revision 1.5 2004/01/22 14:23:45 mranga Reviewed by: mranga Fixed some minor\n * formatting issues.\n *\n * Revision 1.4 2004/01/22 13:26:31 sverker Issue number: Obtained from:\n * Submitted by: sverker Reviewed by: mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and\n * javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number: CVS: If this change addresses one or more issues, CVS:\n * then enter the issue number(s) here. CVS: Obtained from: CVS: If this change\n * has been taken from another system, CVS: then name the system in this line,\n * otherwise delete it. CVS: Submitted by: CVS: If this code has been\n * contributed to the project by someone else; i.e., CVS: they sent us a patch\n * or a set of diffs, then include their name/email CVS: address here. If this\n * is your work then delete this line. CVS: Reviewed by: CVS: If we are doing\n * pre-commit code reviews and someone else has CVS: reviewed your changes,\n * include their name(s) here. CVS: If you have not had it reviewed then delete\n * this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/PriorityParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Priority header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:02 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * @version 1.0\n */\npublic class PriorityParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of PriorityParser\n     * @param priority the header to parse\n     */\n    public PriorityParser(String priority) {\n        super(priority);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected PriorityParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String header\n     * @return SIPHeader (Priority object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"PriorityParser.parse\");\n        Priority priority = new Priority();\n        try {\n            headerName(TokenTypes.PRIORITY);\n\n            priority.setHeaderName(SIPHeaderNames.PRIORITY);\n\n            this.lexer.SPorHT();\n            /*this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n\n            priority.setPriority(token.getTokenValue());\n            */\n            // This is in violation of the RFC but\n            // let us be generous in what we accept.\n            priority.setPriority(this.lexer.ttokenSafe());\n\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return priority;\n        } finally {\n            if (debug)\n                dbg_leave(\"PriorityParser.parse\");\n        }\n    }\n\n\n    public static void main(String args[]) throws ParseException {\n    String p[] = {\n            \"Priority: 8;a\\n\"\n            };\n\n    for (int i = 0; i < p.length; i++ ) {\n        PriorityParser parser =\n          new PriorityParser(p[i]);\n        Priority prio= (Priority) parser.parse();\n        System.out.println(\"encoded = \" + prio.encode());\n    }\n    }\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ProxyAuthenticateParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ProxyAuthenticate headers.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:02 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ProxyAuthenticateParser extends ChallengeParser {\n\n    /**\n     * Constructor\n     * @param proxyAuthenticate message to parse\n     */\n    public ProxyAuthenticateParser(String proxyAuthenticate) {\n        super(proxyAuthenticate);\n    }\n\n    /**\n     * Cosntructor\n     * @param Lexer lexer to set\n     */\n    protected ProxyAuthenticateParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (ProxyAuthenticate object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        headerName(TokenTypes.PROXY_AUTHENTICATE);\n        ProxyAuthenticate proxyAuthenticate = new ProxyAuthenticate();\n        super.parse(proxyAuthenticate);\n        return proxyAuthenticate;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n    String paAuth[] = {\n    \"Proxy-Authenticate: Digest realm=\\\"MCI WorldCom SIP\\\",\"+\n    \"domain=\\\"sip:ss2.wcom.com\\\", nonce=\\\"ea9c8e88df84f1cec4341ae6cbe5a359\\\",\"+\n    \"opaque=\\\"\\\", stale=FALSE, algorithm=MD5\\n\",\n\n    \"Proxy-Authenticate: Digest realm=\\\"MCI WorldCom SIP\\\",\"+\n    \"qop=\\\"auth\\\" , nonce-value=\\\"oli\\\"\\n\"\n            };\n\n    for (int i = 0; i < paAuth.length; i++ ) {\n        ProxyAuthenticateParser pap =\n          new ProxyAuthenticateParser(paAuth[i]);\n        ProxyAuthenticate pa= (ProxyAuthenticate) pap.parse();\n        System.out.println(\"encoded = \" + pa.encode());\n    }\n\n    }\n     */\n}\n/*\n * $Log: ProxyAuthenticateParser.java,v $\n * Revision 1.7  2009/07/17 18:58:02  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:17  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ProxyAuthorizationParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ProxyAuthorization headers.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:02 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class ProxyAuthorizationParser extends ChallengeParser {\n\n    /**\n     * Constructor\n     * @param proxyAuthorization --  header to parse\n     */\n    public ProxyAuthorizationParser(String proxyAuthorization) {\n        super(proxyAuthorization);\n    }\n\n    /**\n     * Cosntructor\n     * @param Lexer lexer to set\n     */\n    protected ProxyAuthorizationParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (ProxyAuthenticate object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        headerName(TokenTypes.PROXY_AUTHORIZATION);\n        ProxyAuthorization proxyAuth = new ProxyAuthorization();\n        super.parse(proxyAuth);\n        return proxyAuth;\n    }\n\n/**\n\n    public static void main(String args[]) throws ParseException {\n    String paAuth[] = {\n    \"Proxy-Authorization: Digest realm=\\\"MCI WorldCom SIP\\\",\"+\n    \"domain=\\\"sip:ss2.wcom.com\\\",nonce=\\\"ea9c8e88df84f1cec4341ae6cbe5a359\\\",\"+\n    \"opaque=\\\"\\\",stale=FALSE,algorithm=MD5\\n\",\n\n    \"Proxy-Authorization: Digest realm=\\\"MCI WorldCom SIP\\\",\"+\n    \"qop=\\\"auth\\\" , nonce-value=\\\"oli\\\"\\n\"\n            };\n\n    for (int i = 0; i < paAuth.length; i++ ) {\n        ProxyAuthorizationParser pap =\n          new ProxyAuthorizationParser(paAuth[i]);\n        ProxyAuthorization pa= (ProxyAuthorization) pap.parse();\n        String encoded =   pa.encode();\n        System.out.println (\"original = \\n\" + paAuth[i]);\n        System.out.println(\"encoded = \\n\" + encoded);\n        pap = new ProxyAuthorizationParser(encoded.trim() + \"\\n\");\n        pap.parse();\n    }\n\n    }\n**/\n\n}\n/*\n * $Log: ProxyAuthorizationParser.java,v $\n * Revision 1.7  2009/07/17 18:58:02  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:18  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2005/02/24 16:13:11  mranga\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Just some additional testing on the parser.\n *\n * Revision 1.3  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ProxyRequireParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for ProxyRequire header.\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:02 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ProxyRequireParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of ProxyRequireParser\n     * @param require the header to parse\n     */\n    public ProxyRequireParser(String require) {\n        super(require);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ProxyRequireParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (ProxyRequireList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        ProxyRequireList list = new ProxyRequireList();\n        if (debug)\n            dbg_enter(\"ProxyRequireParser.parse\");\n\n        try {\n            headerName(TokenTypes.PROXY_REQUIRE);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                ProxyRequire r = new ProxyRequire();\n                r.setHeaderName(SIPHeaderNames.PROXY_REQUIRE);\n\n                // Parsing the option tag\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                r.setOptionTag(token.getTokenValue());\n                this.lexer.SPorHT();\n\n                list.add(r);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n\n                    r = new ProxyRequire();\n\n                    // Parsing the option tag\n                    this.lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    r.setOptionTag(token.getTokenValue());\n                    this.lexer.SPorHT();\n\n                    list.add(r);\n                }\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"ProxyRequireParser.parse\");\n        }\n\n        return list;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n        String r[] = {\n            \"Proxy-Require: foo \\n\",\n            \"Proxy-Require: foo1, foo2 , 389\\n\"\n        };\n\n        for (int i = 0; i < r.length; i++ ) {\n            ProxyRequireParser parser =\n            new ProxyRequireParser(r[i]);\n            ProxyRequireList rl= (ProxyRequireList) parser.parse();\n            System.out.println(\"encoded = \" + rl.encode());\n        }\n    }\n     */\n}\n/*\n * $Log: ProxyRequireParser.java,v $\n * Revision 1.7  2009/07/17 18:58:02  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:15  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RAckParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for RAck header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:02 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * @version 1.0\n */\npublic class RAckParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of RAckParser\n     * @param rack the header to parse\n     */\n    public RAckParser(String rack) {\n        super(rack);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected RAckParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (RAck object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"RAckParser.parse\");\n        RAck rack = new RAck();\n        try {\n            headerName(TokenTypes.RACK);\n\n            rack.setHeaderName(SIPHeaderNames.RACK);\n\n            try {\n                String number = this.lexer.number();\n                rack.setRSequenceNumber(Long.parseLong(number));\n                this.lexer.SPorHT();\n                number = this.lexer.number();\n                rack.setCSequenceNumber(Long.parseLong(number));\n                this.lexer.SPorHT();\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                rack.setMethod(token.getTokenValue());\n\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return rack;\n        } finally {\n            if (debug)\n                dbg_leave(\"RAckParser.parse\");\n        }\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n    String r[] = {\n            \"RAck: 776656 1 INVITE\\n\"\n            };\n\n    for (int i = 0; i < r.length; i++ ) {\n        RAckParser parser =\n          new RAckParser(r[i]);\n        RAck ra= (RAck) parser.parse();\n        System.out.println(\"encoded = \" + ra.encode());\n    }\n    }\n     */\n}\n/*\n * $Log: RAckParser.java,v $\n * Revision 1.8  2009/07/17 18:58:02  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/08/15 21:44:50  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Incorporating the latest API changes from Phelim\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.6  2006/07/13 09:02:24  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2006/05/24 06:21:43  mranga\n * change to use the long setter\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RSeqParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for RSeq header.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:03 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class RSeqParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of RSeqParser\n     * @param rseq the header to parse\n     */\n    public RSeqParser(String rseq) {\n        super(rseq);\n    }\n\n    /**\n     * Constructor\n     * param lexer the lexer to use to parse the header\n     */\n    protected RSeqParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader ( RSeq object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"RSeqParser.parse\");\n        RSeq rseq = new RSeq();\n        try {\n            headerName(TokenTypes.RSEQ);\n\n            rseq.setHeaderName(SIPHeaderNames.RSEQ);\n\n            String number = this.lexer.number();\n            try {\n                rseq.setSeqNumber(Long.parseLong(number));\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n            this.lexer.SPorHT();\n\n            this.lexer.match('\\n');\n\n            return rseq;\n        } finally {\n            if (debug)\n                dbg_leave(\"RSeqParser.parse\");\n        }\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n    String r[] = {\n            \"RSeq: 988789 \\n\"\n            };\n\n    for (int i = 0; i < r.length; i++ ) {\n        RSeqParser parser =\n          new RSeqParser(r[i]);\n        RSeq rs= (RSeq) parser.parse();\n        System.out.println(\"encoded = \" + rs.encode());\n    }\n    }\n     */\n\n}\n/*\n * $Log: RSeqParser.java,v $\n * Revision 1.8  2009/07/17 18:58:03  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/08/15 21:44:49  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Incorporating the latest API changes from Phelim\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.6  2006/07/13 09:01:53  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2006/05/24 06:21:43  mranga\n * change to use the long setter\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ReasonParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Reason header.\n *\n * @version 1.2\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ReasonParser extends ParametersParser {\n\n    /**\n     * Creates a new instance of ReasonParser\n     * @param reason the header to parse\n     */\n    public ReasonParser(String reason) {\n        super(reason);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ReasonParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (ReasonParserList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        ReasonList reasonList = new ReasonList();\n        if (debug)\n            dbg_enter(\"ReasonParser.parse\");\n\n        try {\n            headerName(TokenTypes.REASON);\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) != '\\n') {\n                Reason reason = new Reason();\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                String value = token.getTokenValue();\n\n                reason.setProtocol(value);\n                super.parse(reason);\n                reasonList.add(reason);\n                if (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else\n                    this.lexer.SPorHT();\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"ReasonParser.parse\");\n        }\n\n        return reasonList;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n        String r[] = {\n            \"Reason: SIP ;cause=200 ;text=\\\"Call completed elsewhere\\\"\\n\",\n            \"Reason: Q.850 ;cause=16 ;text=\\\"Terminated\\\"\\n\",\n            \"Reason: SIP ;cause=600 ;text=\\\"Busy Everywhere\\\"\\n\",\n            \"Reason: SIP ;cause=580 ;text=\\\"Precondition Failure\\\",\"+\n            \"SIP ;cause=530 ;text=\\\"Pre Failure\\\"\\n\",\n            \"Reason: SIP \\n\"\n        };\n\n        for (int i = 0; i < r.length; i++ ) {\n            ReasonParser parser =\n            new ReasonParser(r[i]);\n            ReasonList rl= (ReasonList) parser.parse();\n            System.out.println(\"encoded = \" + rl.encode());\n        }\n    }\n     */\n}\n/*\n * $Log: ReasonParser.java,v $\n * Revision 1.8  2009/07/17 18:58:03  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2008/11/19 10:10:50  jbemmel\n * Don't catch ParseException but throw it\n *\n * Revision 1.6  2006/07/13 09:02:12  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RecordRouteParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.RecordRoute;\nimport gov2.nist.javax2.sip.header.RecordRouteList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\n\nimport java.text.ParseException;\n\n/**\n * Parser for a list of route headers.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:03 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n */\npublic class RecordRouteParser extends AddressParametersParser {\n\n    /**\n     * Constructor\n     * @param recordRoute message to parse to set\n     */\n    public RecordRouteParser(String recordRoute) {\n        super(recordRoute);\n    }\n\n    protected RecordRouteParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message and generate the RecordRoute List Object\n     * @return SIPHeader the RecordRoute List object\n     * @throws ParseException if errors occur during the parsing\n     */\n    public SIPHeader parse() throws ParseException {\n        RecordRouteList recordRouteList = new RecordRouteList();\n\n        if (debug)\n            dbg_enter(\"RecordRouteParser.parse\");\n\n        try {\n            this.lexer.match(TokenTypes.RECORD_ROUTE);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n            while (true) {\n                RecordRoute recordRoute = new RecordRoute();\n                super.parse(recordRoute);\n                recordRouteList.add(recordRoute);\n                this.lexer.SPorHT();\n                char la = lexer.lookAhead(0);\n                if (la == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else if (la == '\\n')\n                    break;\n                else\n                    throw createParseException(\"unexpected char\");\n            }\n            return recordRouteList;\n        } finally {\n            if (debug)\n                dbg_leave(\"RecordRouteParser.parse\");\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ReferToParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * To Header parser.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:03 $\n *\n * @author Olivier Deruelle   <br/>\n *\n *\n *\n */\npublic class ReferToParser extends AddressParametersParser {\n\n    /**\n     * Creates new ToParser\n     * @param referTo String to set\n     */\n    public ReferToParser(String referTo) {\n        super(referTo);\n    }\n\n    protected ReferToParser(Lexer lexer) {\n        super(lexer);\n    }\n    public SIPHeader parse() throws ParseException {\n\n        headerName(TokenTypes.REFER_TO);\n        ReferTo referTo = new ReferTo();\n        super.parse(referTo);\n        this.lexer.match('\\n');\n        return referTo;\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String to[] =\n            {   \"Refer-To: <sip:dave@denver.example.org?\" +\n                    \"Replaces=12345%40192.168.118.3%3Bto-tag%3D12345%3Bfrom-tag%3D5FFE-3994>\\n\",\n                \"Refer-To: <sip:+1-650-555-2222@ss1.wcom.com;user=phone>;tag=5617\\n\",\n                \"Refer-To: T. A. Watson <sip:watson@bell-telephone.com>\\n\",\n                \"Refer-To: LittleGuy <sip:UserB@there.com>\\n\",\n                \"Refer-To: sip:mranga@120.6.55.9\\n\",\n                \"Refer-To: sip:mranga@129.6.55.9 ; tag=696928473514.129.6.55.9\\n\" };\n\n        for (int i = 0; i < to.length; i++) {\n            ReferToParser tp = new ReferToParser(to[i]);\n            ReferTo t = (ReferTo) tp.parse();\n            System.out.println(\"encoded = \" + t.encode());\n\n        }\n    }\n}\n/*\n * $Log: ReferToParser.java,v $\n * Revision 1.8  2009/07/17 18:58:03  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:21  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2005/03/29 03:50:01  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n *\n * Remove transaction for early bye.\n * Reviewed by:\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2005/03/27 14:00:14  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n *\n * Added example\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ReplyToParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * Parser for a list of RelpyTo headers.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:03 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n */\npublic class ReplyToParser extends AddressParametersParser {\n\n    /**\n     * Creates a new instance of ReplyToParser\n     * @param replyTo the header to parse\n     */\n    public ReplyToParser(String replyTo) {\n        super(replyTo);\n    }\n\n    /**\n     * Cosntructor\n     * param lexer the lexer to use to parse the header\n     */\n    protected ReplyToParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message and generate the ReplyTo List Object\n     * @return SIPHeader the ReplyTo List object\n     * @throws SIPParseException if errors occur during the parsing\n     */\n    public SIPHeader parse() throws ParseException {\n        ReplyTo replyTo = new ReplyTo();\n        if (debug)\n            dbg_enter(\"ReplyTo.parse\");\n\n        try {\n            headerName(TokenTypes.REPLY_TO);\n\n            replyTo.setHeaderName(SIPHeaderNames.REPLY_TO);\n\n            super.parse(replyTo);\n\n            return replyTo;\n        } finally {\n            if (debug)\n                dbg_leave(\"ReplyTo.parse\");\n        }\n\n    }\n\n    /**\n        public static void main(String args[]) throws ParseException {\n            String r[] = {\n                \"Reply-To: Bob <sip:bob@biloxi.com>\\n\"\n            };\n\n            for (int i = 0; i < r.length; i++ ) {\n                ReplyToParser rt =\n                new ReplyToParser(r[i]);\n                ReplyTo re = (ReplyTo) rt.parse();\n                System.out.println(\"encoded = \" +re.encode());\n            }\n\n        }\n    */\n}\n/*\n * $Log: ReplyToParser.java,v $\n * Revision 1.7  2009/07/17 18:58:03  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:16  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RequestLineParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * Parser for the SIP request line.\n *\n * @version 1.2\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class RequestLineParser extends Parser {\n    public RequestLineParser(String requestLine) {\n        this.lexer = new Lexer(\"method_keywordLexer\", requestLine);\n    }\n    public RequestLineParser(Lexer lexer) {\n        this.lexer = lexer;\n        this.lexer.selectLexer(\"method_keywordLexer\");\n    }\n\n    public RequestLine parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            RequestLine retval = new RequestLine();\n            String m = method();\n            lexer.SPorHT();\n            retval.setMethod(m);\n            this.lexer.selectLexer(\"sip_urlLexer\");\n            URLParser urlParser = new URLParser(this.getLexer());\n            GenericURI url = urlParser.uriReference(true);\n            lexer.SPorHT();\n            retval.setUri(url);\n            this.lexer.selectLexer(\"request_lineLexer\");\n            String v = sipVersion();\n            retval.setSipVersion(v);\n            lexer.SPorHT();\n            lexer.match('\\n');\n            return retval;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n            public static void main(String args[]) throws ParseException {\n            String requestLines[] = {\n                \"REGISTER sip:192.168.0.68 SIP/2.0\\n\",\n                \"REGISTER sip:company.com SIP/2.0\\n\",\n                \"INVITE sip:3660@166.35.231.140 SIP/2.0\\n\",\n                \"INVITE sip:user@company.com SIP/2.0\\n\",\n                \"REGISTER sip:[2001::1]:5060;transport=tcp SIP/2.0\\n\", // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n                \"REGISTER sip:[2002:800:700:600:30:4:6:1]:5060;transport=udp SIP/2.0\\n\", // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n                \"REGISTER sip:[3ffe:800:700::30:4:6:1]:5060;transport=tls SIP/2.0\\n\", // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n                \"REGISTER sip:[2001:720:1710:0:201:29ff:fe21:f403]:5060;transport=udp SIP/2.0\\n\",\n                \"OPTIONS sip:135.180.130.133 SIP/2.0\\n\" };\n            for (int i = 0; i < requestLines.length; i++ ) {\n                RequestLineParser rlp =\n                  new RequestLineParser(requestLines[i]);\n                RequestLine rl = rlp.parse();\n                System.out.println(\"encoded = \" + rl.encode());\n            }\n\n        }\n\n}\n/*\n * $Log: RequestLineParser.java,v $\n * Revision 1.11  2009/10/22 10:27:38  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.10  2009/09/15 02:55:27  mranga\n * Issue number:  222\n * Add HeaderFactoryExt.createStatusLine(String) and HeaderFactoryExt.createRequestLine(String)\n * Allows users to easily parse SipFrag bodies (for example NOTIFY bodies\n * during call transfer).\n *\n * Revision 1.9  2009/07/17 18:58:03  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.8  2006/07/13 09:02:14  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:35  mranga\n *\n * Import\n *\n *\n * Revision 1.6  2004/10/28 19:02:50  mranga\n * Submitted by:  Daniel Martinez\n * Reviewed by:   M. Ranganathan\n *\n * Added changes for TLS support contributed by Daniel Martinez\n *\n * Revision 1.5  2004/06/27 00:41:51  mranga\n * Submitted by:  Thomas Froment and Pierre De Rop\n * Reviewed by:   mranga\n * Performance improvements\n * (auxiliary data structure for fast lookup of transactions).\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RequireParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Require header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:04 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * @version 1.0\n */\npublic class RequireParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of RequireParser\n     * @param require the header to parse\n     */\n    public RequireParser(String require) {\n        super(require);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected RequireParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (RequireList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        RequireList requireList = new RequireList();\n        if (debug)\n            dbg_enter(\"RequireParser.parse\");\n\n        try {\n            headerName(TokenTypes.REQUIRE);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                Require r = new Require();\n                r.setHeaderName(SIPHeaderNames.REQUIRE);\n\n                // Parsing the option tag\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                r.setOptionTag(token.getTokenValue());\n                this.lexer.SPorHT();\n\n                requireList.add(r);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n\n                    r = new Require();\n\n                    // Parsing the option tag\n                    this.lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    r.setOptionTag(token.getTokenValue());\n                    this.lexer.SPorHT();\n\n                    requireList.add(r);\n                }\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"RequireParser.parse\");\n        }\n\n        return requireList;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n        String r[] = {\n            \"Require: 100rel \\n\",\n            \"Require: 100rel, 200ok , 389\\n\"\n        };\n\n        for (int i = 0; i < r.length; i++ ) {\n            RequireParser parser =\n            new RequireParser(r[i]);\n            RequireList rl= (RequireList) parser.parse();\n            System.out.println(\"encoded = \" + rl.encode());\n        }\n    }\n     */\n\n}\n/*\n * $Log: RequireParser.java,v $\n * Revision 1.7  2009/07/17 18:58:04  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:18  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:31  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RetryAfterParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for RetryAfter header.\n *\n * @version 1.2\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/11/04 17:23:00 $\n */\npublic class RetryAfterParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of RetryAfterParser\n     * @param retryAfter the header to parse\n     */\n    public RetryAfterParser(String retryAfter) {\n        super(retryAfter);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected RetryAfterParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (RetryAfter object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"RetryAfterParser.parse\");\n\n        RetryAfter retryAfter = new RetryAfter();\n        try {\n            headerName(TokenTypes.RETRY_AFTER);\n\n            // mandatory delatseconds:\n            String value = lexer.number();\n            try {\n                int ds = Integer.parseInt(value);\n                retryAfter.setRetryAfter(ds);\n            } catch (NumberFormatException ex) {\n                throw createParseException(ex.getMessage());\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n\n            this.lexer.SPorHT();\n            if (lexer.lookAhead(0) == '(') {\n                String comment = this.lexer.comment();\n                retryAfter.setComment(comment);\n            }\n            this.lexer.SPorHT();\n\n            while (lexer.lookAhead(0) == ';') {\n                this.lexer.match(';');\n                this.lexer.SPorHT();\n                lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                value = token.getTokenValue();\n                if (value.equalsIgnoreCase(\"duration\")) {\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    value = lexer.number();\n                    try {\n                        int duration = Integer.parseInt(value);\n                        retryAfter.setDuration(duration);\n                    } catch (NumberFormatException ex) {\n                        throw createParseException(ex.getMessage());\n                    } catch (InvalidArgumentException ex) {\n                        throw createParseException(ex.getMessage());\n                    }\n                } else {\n                    this.lexer.SPorHT();\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    Token secondToken = lexer.getNextToken();\n                    String secondValue = secondToken.getTokenValue();\n                    retryAfter.setParameter(value, secondValue);\n                }\n                this.lexer.SPorHT();\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"RetryAfterParser.parse\");\n        }\n\n        return retryAfter;\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/RouteParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * Parser for a list of route headers.\n *\n * @version 1.2\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *@version 1.0\n */\npublic class RouteParser extends AddressParametersParser {\n\n    /**\n     * Constructor\n     * @param route message to parse to set\n     */\n    public RouteParser(String route) {\n        super(route);\n    }\n\n    protected RouteParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /** parse the String message and generate the Route List Object\n     * @return SIPHeader the Route List object\n     * @throws SIPParseException if errors occur during the parsing\n     */\n    public SIPHeader parse() throws ParseException {\n        RouteList routeList = new RouteList();\n        if (debug)\n            dbg_enter(\"parse\");\n\n        try {\n            this.lexer.match(TokenTypes.ROUTE);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n            while (true) {\n                Route route = new Route();\n                super.parse(route);\n                routeList.add(route);\n                this.lexer.SPorHT();\n                char la = lexer.lookAhead(0);\n                if (la == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else if (la == '\\n')\n                    break;\n                else\n                    throw createParseException(\"unexpected char\");\n            }\n            return routeList;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n\n    }\n\n    /**\n            public static void main(String args[]) throws ParseException {\n        String rou[] = {\n         \"Route: <sip:alice@atlanta.com>\\n\",\n         \"Route: sip:bob@biloxi.com \\n\",\n         \"Route: sip:alice@atlanta.com, sip:bob@biloxi.com, sip:carol@chicago.com\\n\"\n             };\n\n            for (int i = 0; i < rou.length; i++ ) {\n                RouteParser rp =\n                  new RouteParser(rou[i]);\n                RouteList routeList = (RouteList) rp.parse();\n                System.out.println(\"encoded = \" +routeList.encode());\n            }\n\n        }\n\n    */\n}\n/*\n * $Log: RouteParser.java,v $\n * Revision 1.8  2009/07/17 18:58:04  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2007/02/06 16:40:03  belangery\n * Introduced simple code optimizations.\n *\n * Revision 1.6  2006/07/13 09:02:07  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/SIPETagParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for SIP-ETag header.\n *\n *\n * @author Jeroen van Bemmel <br/>\n *\n *\n *\n * @version 1.2\n * @since 1.2\n */\npublic class SIPETagParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of PriorityParser\n     * @param etag the header to parse\n     */\n    public SIPETagParser(String etag) {\n        super(etag);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected SIPETagParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String header\n     * @return SIPHeader (Priority object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"SIPEtag.parse\");\n\n        SIPETag sipEtag = new SIPETag();\n        try {\n            headerName(TokenTypes.SIP_ETAG);\n\n            this.lexer.SPorHT();\n            this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n\n            sipEtag.setETag(token.getTokenValue());\n\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return sipEtag;\n        } finally {\n            if (debug)\n                dbg_leave(\"SIPEtag.parse\");\n        }\n    }\n}\n/*\n * $Log: SIPETagParser.java,v $\n * Revision 1.3  2009/07/17 18:58:04  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.2  2006/07/13 09:01:58  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1  2005/10/27 20:49:00  jeroen\n * added support for RFC3903 PUBLISH\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/SIPIfMatchParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for SIP-If-Match header.\n *\n *\n * @author Jeroen van Bemmel <br/>\n *\n *\n * @version 1.2 $Revision: 1.3 $ $Date: 2009/07/17 18:58:04 $\n *\n * @since 1.2\n */\npublic class SIPIfMatchParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of PriorityParser\n     * @param etag the header to parse\n     */\n    public SIPIfMatchParser(String etag) {\n        super(etag);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected SIPIfMatchParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String header\n     * @return SIPHeader (Priority object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"SIPIfMatch.parse\");\n\n        SIPIfMatch sipIfMatch = new SIPIfMatch();\n        try {\n            headerName(TokenTypes.SIP_IF_MATCH);\n\n            this.lexer.SPorHT();\n            this.lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n\n            sipIfMatch.setETag(token.getTokenValue());\n\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return sipIfMatch;\n        } finally {\n            if (debug)\n                dbg_leave(\"SIPIfMatch.parse\");\n        }\n    }\n}\n/*\n * $Log: SIPIfMatchParser.java,v $\n * Revision 1.3  2009/07/17 18:58:04  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.2  2006/07/13 09:02:08  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1  2005/10/27 20:49:00  jeroen\n * added support for RFC3903 PUBLISH\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/SIPMessageListener.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD)         *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.javax2.sip.message.*;\n\n/**\n * Interface  that provides methods for processing good\n * and bad messages for the PipelinedMessageParser.\n *\n * @version 1.2 $Revision: 1.8 $ $Date: 2009/07/17 18:58:04 $\n * @see PipelinedMsgParser\n */\npublic interface SIPMessageListener extends ParseExceptionListener {\n    /**\n     * This is called from the parser on successful message processing.\n     * @see ParseExceptionListener for the method that gets called\n     * on parse exception.\n     * @param msg  SIP Message structure that is generated by the parser.\n     */\n    public void processMessage(SIPMessage msg) throws Exception;\n}\n/*\n * $Log: SIPMessageListener.java,v $\n * Revision 1.8  2009/07/17 18:58:04  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/07/13 09:02:17  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2004/02/29 00:46:34  mranga\n * Reviewed by:   mranga\n * Added new configuration property to limit max message size for TCP transport.\n * The property is gov2.nist.javax2.sip.MAX_MESSAGE_SIZE\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ServerParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Server header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:05 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class ServerParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of ServerParser\n     * @param server the header to parse\n     */\n    public ServerParser(String server) {\n        super(server);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ServerParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String server\n     * @return SIPHeader (Server object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"ServerParser.parse\");\n        Server server = new Server();\n        try {\n            headerName(TokenTypes.SERVER);\n            if (this.lexer.lookAhead(0) == '\\n')\n                throw createParseException(\"empty header\");\n\n            //  mandatory token: product[/product-version] | (comment)\n            while (this.lexer.lookAhead(0) != '\\n'\n                && this.lexer.lookAhead(0) != '\\0') {\n                if (this.lexer.lookAhead(0) == '(') {\n                    String comment = this.lexer.comment();\n                    server.addProductToken('(' + comment + ')');\n                } else {\n                    String tok;\n                    int marker = 0;\n                    try {\n                        marker = this.lexer.markInputPosition();\n                        tok = this.lexer.getString('/');\n\n                        if (tok.charAt(tok.length() - 1) == '\\n')\n                            tok = tok.trim();\n                        server.addProductToken(tok);\n                    } catch (ParseException ex) {\n                        this.lexer.rewindInputPosition(marker);\n                        tok = this.lexer.getRest().trim();\n                        server.addProductToken(tok);\n                        break;\n                    }\n                }\n            }\n\n        } finally {\n            if (debug)\n                dbg_leave(\"ServerParser.parse\");\n        }\n\n        return server;\n    }\n\n/*\n    public static void main(String args[]) throws ParseException {\n    String server[] = {\n            \"Server: Softphone/Beta1.5 \\n\",\n            \"Server: HomeServer v2\\n\",\n            \"Server: Nist/Beta1 (beta version) \\n\",\n            \"Server: Nist proxy (beta version)\\n\",\n            \"Server: Nist1.0/Beta2 UbiServer/vers.1.0 (new stuff) (Cool) \\n\",\n        \"Server: Sip EXpress router (0.8.11 (sparc64/solaris))\\n\"\n            };\n\n    for (int i = 0; i < server.length; i++ ) {\n        ServerParser parser =\n          new ServerParser(server[i]);\n        Server s= (Server) parser.parse();\n        System.out.println(\"encoded = \" + s.encode());\n    }\n\n    }\n*/\n\n}\n/*\n * $Log: ServerParser.java,v $\n * Revision 1.9  2009/07/17 18:58:05  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.8  2006/07/13 09:02:16  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/17 10:18:14  mranga\n * Added some synchronization to the sequence number checking.\n * Small javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.6  2004/01/30 17:10:47  mranga\n * Reviewed by:   mranga\n * Server and user agent parser leave an extra Linefeed at the end of token.\n *\n * Revision 1.5  2004/01/27 13:52:11  mranga\n * Reviewed by:   mranga\n * Fixed server/user-agent parser.\n * suppress sending ack to TU when retransFilter is enabled and ack is retransmitted.\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/StatusLineParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for the SIP status line.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:05 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic class StatusLineParser extends Parser {\n    public StatusLineParser(String statusLine) {\n        this.lexer = new Lexer(\"status_lineLexer\", statusLine);\n    }\n\n    public StatusLineParser(Lexer lexer) {\n        this.lexer = lexer;\n        this.lexer.selectLexer(\"status_lineLexer\");\n    }\n\n    protected int statusCode() throws ParseException {\n        String scode = this.lexer.number();\n        if (debug)\n            dbg_enter(\"statusCode\");\n        try {\n            int retval = Integer.parseInt(scode);\n            return retval;\n        } catch (NumberFormatException ex) {\n            throw new ParseException(\n                lexer.getBuffer() + \":\" + ex.getMessage(),\n                lexer.getPtr());\n        } finally {\n            if (debug)\n                dbg_leave(\"statusCode\");\n        }\n\n    }\n\n    protected String reasonPhrase() throws ParseException {\n        return this.lexer.getRest().trim();\n    }\n\n    public StatusLine parse() throws ParseException {\n        try {\n            if (debug)\n                dbg_enter(\"parse\");\n            StatusLine retval = new StatusLine();\n            String version = this.sipVersion();\n            retval.setSipVersion(version);\n            lexer.SPorHT();\n            int scode = statusCode();\n            retval.setStatusCode(scode);\n            lexer.SPorHT();\n            String rp = reasonPhrase();\n            retval.setReasonPhrase(rp);\n            lexer.SPorHT();\n            return retval;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n    /**\n        public static void main(String[] args)  throws ParseException {\n            String[] statusLines = {\n             \"SIP/2.0 200 OK\\n\",\n             \"BOO 200 OK\\n\",\n             \"SIP/2.0 500 OK bad things happened \\n\"\n            };\n            for (int i = 0 ; i < statusLines.length; i++) {\n               try {\n               StatusLineParser slp = new StatusLineParser(statusLines[i]);\n               StatusLine sl = slp.parse();\n               System.out.println(\"encoded = \" + sl.encode());\n               } catch (ParseException ex) {\n                System.out.println(\"error message \" + ex.getMessage());\n               }\n            }\n        }\n    */\n}\n/*\n * $Log: StatusLineParser.java,v $\n * Revision 1.7  2009/07/17 18:58:05  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:20  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/StringMsgParser.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD)        *\n ******************************************************************************/\n\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.Host;\nimport gov2.nist.core.HostNameParser;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.address.GenericURI;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.address.TelephoneNumber;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.io.UnsupportedEncodingException;\nimport java.text.ParseException;\n/*\n * Acknowledgement: 1/12/2007: Yanick Belanger rewrote the parsing loops to make them\n * simpler and quicker.\n */\n\n/**\n * Parse SIP message and parts of SIP messages such as URI's etc from memory and\n * return a structure. Intended use: UDP message processing. This class is used\n * when you have an entire SIP message or SIPHeader or SIP URL in memory and you\n * want to generate a parsed structure from it. For SIP messages, the payload\n * can be binary or String. If you have a binary payload, use\n * parseSIPMessage(byte[]) else use parseSIPMessage(String) The payload is\n * accessible from the parsed message using the getContent and getContentBytes\n * methods provided by the SIPMessage class. If SDP parsing is enabled using the\n * parseContent method, then the SDP body is also parsed and can be accessed\n * from the message using the getSDPAnnounce method. Currently only eager\n * parsing of the message is supported (i.e. the entire message is parsed in one\n * feld swoop).\n *\n *\n * @version 1.2 $Revision: 1.26 $ $Date: 2009/10/22 10:27:38 $\n *\n * @author M. Ranganathan <br/>\n *\n  *\n */\npublic class StringMsgParser {\n\n    protected boolean readBody;\n    private ParseExceptionListener parseExceptionListener;\n    private String rawStringMessage;\n    private boolean strict;\n\n    private static boolean computeContentLengthFromMessage = false;\n\n    /**\n     * @since v0.9\n     */\n    public StringMsgParser() {\n        super();\n        readBody = true;\n    }\n\n    /**\n     * Constructor (given a parse exception handler).\n     *\n     * @since 1.0\n     * @param exhandler\n     *            is the parse exception listener for the message parser.\n     */\n    public StringMsgParser(ParseExceptionListener exhandler) {\n        this();\n        parseExceptionListener = exhandler;\n    }\n\n    /**\n     * Add a handler for header parsing errors.\n     *\n     * @param pexhandler\n     *            is a class that implements the ParseExceptionListener\n     *            interface.\n     */\n    public void setParseExceptionListener(ParseExceptionListener pexhandler) {\n        parseExceptionListener = pexhandler;\n    }\n\n    /**\n     * Parse a buffer containing a single SIP Message where the body is an array\n     * of un-interpreted bytes. This is intended for parsing the message from a\n     * memory buffer when the buffer. Incorporates a bug fix for a bug that was\n     * noted by Will Sullin of Callcast\n     *\n     * @param msgBuffer\n     *            a byte buffer containing the messages to be parsed. This can\n     *            consist of multiple SIP Messages concatenated together.\n     * @return a SIPMessage[] structure (request or response) containing the\n     *         parsed SIP message.\n     * @exception ParseException\n     *                is thrown when an illegal message has been encountered\n     *                (and the rest of the buffer is discarded).\n     * @see ParseExceptionListener\n     */\n    public SIPMessage parseSIPMessage(byte[] msgBuffer) throws ParseException {\n        if (msgBuffer == null || msgBuffer.length == 0)\n            return null;\n\n        int i = 0;\n\n        // Squeeze out any leading control character.\n        try {\n            while (msgBuffer[i] < 0x20)\n                i++;\n        }\n        catch (ArrayIndexOutOfBoundsException e) {\n            // Array contains only control char, return null.\n            return null;\n        }\n\n        // Iterate thru the request/status line and headers.\n        String currentLine = null;\n        String currentHeader = null;\n        boolean isFirstLine = true;\n        SIPMessage message = null;\n        do\n        {\n            int lineStart = i;\n\n            // Find the length of the line.\n            try {\n                while (msgBuffer[i] != '\\r' && msgBuffer[i] != '\\n')\n                    i++;\n            }\n            catch (ArrayIndexOutOfBoundsException e) {\n                // End of the message.\n                break;\n            }\n            int lineLength = i - lineStart;\n\n            // Make it a String.\n            try {\n                currentLine = new String(msgBuffer, lineStart, lineLength, \"UTF-8\");\n            } catch (UnsupportedEncodingException e) {\n                throw new ParseException(\"Bad message encoding!\", 0);\n            }\n\n            currentLine = trimEndOfLine(currentLine);\n\n            if (currentLine.length() == 0) {\n                // Last header line, process the previous buffered header.\n                if (currentHeader != null && message != null) {\n                     processHeader(currentHeader, message);\n                 }\n\n            }\n            else {\n                if (isFirstLine) {\n                    message = processFirstLine(currentLine);\n                } else {\n                    char firstChar = currentLine.charAt(0);\n                    if (firstChar == '\\t' || firstChar == ' ') {\n                        if (currentHeader == null)\n                            throw new ParseException(\"Bad header continuation.\", 0);\n\n                        // This is a continuation, append it to the previous line.\n                        currentHeader += currentLine.substring(1);\n                    }\n                    else {\n                        if (currentHeader != null && message != null) {\n                             processHeader(currentHeader, message);\n                         }\n                        currentHeader = currentLine;\n                    }\n                }\n            }\n\n            if (msgBuffer[i] == '\\r' && msgBuffer.length > i+1 && msgBuffer[i+1] == '\\n')\n                i++;\n\n            i++;\n\n            isFirstLine = false;\n        } while (currentLine.length() > 0); // End do - while\n\n        if (message == null) throw new ParseException(\"Bad message\", 0);\n        message.setSize(i);\n\n        if (readBody && message.getContentLength() != null &&\n                message.getContentLength().getContentLength() != 0) {\n\n            int bodyLength = msgBuffer.length - i;\n\n            byte[] body = new byte[bodyLength];\n            System.arraycopy(msgBuffer, i, body, 0, bodyLength);\n            message.setMessageContent(body,computeContentLengthFromMessage ,message.getContentLength().getContentLength() );\n        }\n\n        return message;\n    }\n\n    /**\n     * Parse a buffer containing one or more SIP Messages and return an array of\n     * SIPMessage parsed structures.\n     *\n     * @param msgString\n     *            a String containing the messages to be parsed. This can\n     *            consist of multiple SIP Messages concatenated together.\n     * @return a SIPMessage structure (request or response) containing the\n     *         parsed SIP message.\n     * @exception ParseException\n     *                is thrown when an illegal message has been encountered\n     *                (and the rest of the buffer is discarded).\n     * @see ParseExceptionListener\n     */\n    public SIPMessage parseSIPMessage(String msgString) throws ParseException {\n        if (msgString == null || msgString.length() == 0)\n            return null;\n\n        rawStringMessage = msgString;\n\n        int i = 0;\n\n        // Squeeze out any leading control character.\n        try {\n            while (msgString.charAt(i) < 0x20)\n                i++;\n        }\n        catch (ArrayIndexOutOfBoundsException e) {\n            // Array contains only control char, return null.\n            return null;\n        } catch (StringIndexOutOfBoundsException ex) {\n            return null;\n        }\n\n        // Iterate thru the request/status line and headers.\n        String currentLine = null;\n        String currentHeader = null;\n        boolean isFirstLine = true;\n        SIPMessage message = null;\n        do\n        {\n            int lineStart = i;\n\n            // Find the length of the line.\n            try {\n                char c = msgString.charAt(i);\n                while (c != '\\r' && c != '\\n')\n                    c = msgString.charAt(++i);\n            }\n            catch (ArrayIndexOutOfBoundsException e) {\n                // End of the message.\n                break;\n            } catch ( StringIndexOutOfBoundsException ex) {\n                break;\n            }\n\n            // Make it a String.\n            currentLine = msgString.substring(lineStart, i);\n            currentLine = trimEndOfLine(currentLine);\n\n            if (currentLine.length() == 0) {\n                // Last header line, process the previous buffered header.\n                if (currentHeader != null) {\n                    processHeader(currentHeader, message);\n                }\n            }\n            else {\n                if (isFirstLine) {\n                    message = processFirstLine(currentLine);\n                } else {\n                    char firstChar = currentLine.charAt(0);\n                    if (firstChar == '\\t' || firstChar == ' ') {\n                        if (currentHeader == null)\n                            throw new ParseException(\"Bad header continuation.\", 0);\n\n                        // This is a continuation, append it to the previous line.\n                        currentHeader += currentLine.substring(1);\n                    }\n                    else {\n                        if (currentHeader != null) {\n                            processHeader(currentHeader, message);\n                        }\n                        currentHeader = currentLine;\n                    }\n                }\n            }\n\n            if (msgString.charAt(i) == '\\r' && msgString.length() > i+1 && msgString.charAt(i+1) == '\\n')\n                i++;\n\n            i++;\n\n            isFirstLine = false;\n        }\n        while (currentLine.length() > 0);\n\n        message.setSize(i);\n\n        // Check for content legth header\n        if (readBody && message.getContentLength() != null ) {\n            if ( message.getContentLength().getContentLength() != 0) {\n                String body = msgString.substring(i);\n                message.setMessageContent(body,this.strict,computeContentLengthFromMessage,message.getContentLength().getContentLength());\n             } else if (!computeContentLengthFromMessage && message.getContentLength().getContentLength() == 0 && !msgString.endsWith(\"\\r\\n\\r\\n\") ){\n                 if ( strict ) {\n                     throw new ParseException(\"Extraneous characters at the end of the message \",i);\n                 }\n             } \n\n        }\n\n        return message;\n    }\n\n    private String trimEndOfLine(String line) {\n        if (line == null)\n            return line;\n\n        int i = line.length() - 1;\n        while (i >= 0 && line.charAt(i) <= 0x20)\n            i--;\n\n        if (i == line.length() - 1)\n            return line;\n\n        if (i == -1)\n            return \"\";\n\n        return line.substring(0, i+1);\n    }\n\n    private SIPMessage processFirstLine(String firstLine) throws ParseException {\n        SIPMessage message;\n        if (!firstLine.startsWith(SIPConstants.SIP_VERSION_STRING)) {\n            message = new SIPRequest();\n            try {\n                RequestLine requestLine = new RequestLineParser(firstLine + \"\\n\")\n                        .parse();\n                ((SIPRequest) message).setRequestLine(requestLine);\n            } catch (ParseException ex) {\n                if (this.parseExceptionListener != null)\n                    this.parseExceptionListener.handleException(ex, message,\n                            RequestLine.class, firstLine, rawStringMessage);\n                else\n                    throw ex;\n\n            }\n        } else {\n            message = new SIPResponse();\n            try {\n                StatusLine sl = new StatusLineParser(firstLine + \"\\n\").parse();\n                ((SIPResponse) message).setStatusLine(sl);\n            } catch (ParseException ex) {\n                if (this.parseExceptionListener != null) {\n                    this.parseExceptionListener.handleException(ex, message,\n                            StatusLine.class, firstLine, rawStringMessage);\n                } else\n                    throw ex;\n\n            }\n        }\n        return message;\n    }\n\n    private void processHeader(String header, SIPMessage message) throws ParseException {\n        if (header == null || header.length() == 0)\n            return;\n\n        HeaderParser headerParser = null;\n        try {\n            headerParser = ParserFactory.createParser(header + \"\\n\");\n        } catch (ParseException ex) {\n            this.parseExceptionListener.handleException(ex, message, null,\n                    header, rawStringMessage);\n            return;\n        }\n\n        try {\n            SIPHeader sipHeader = headerParser.parse();\n            message.attachHeader(sipHeader, false);\n        } catch (ParseException ex) {\n            if (this.parseExceptionListener != null) {\n                String headerName = Lexer.getHeaderName(header);\n                Class headerClass = NameMap.getClassFromName(headerName);\n                if (headerClass == null) {\n                    headerClass = ExtensionHeaderImpl.class;\n\n                }\n                this.parseExceptionListener.handleException(ex, message,\n                        headerClass, header, rawStringMessage);\n\n            }\n        }\n    }\n\n    /**\n     * Parse an address (nameaddr or address spec) and return and address\n     * structure.\n     *\n     * @param address\n     *            is a String containing the address to be parsed.\n     * @return a parsed address structure.\n     * @since v1.0\n     * @exception ParseException\n     *                when the address is badly formatted.\n     */\n    public AddressImpl parseAddress(String address) throws ParseException {\n        AddressParser addressParser = new AddressParser(address);\n        return addressParser.address(true);\n    }\n\n    /**\n     * Parse a host:port and return a parsed structure.\n     *\n     * @param hostport\n     *            is a String containing the host:port to be parsed\n     * @return a parsed address structure.\n     * @since v1.0\n     * @exception throws\n     *                a ParseException when the address is badly formatted.\n     *\n    public HostPort parseHostPort(String hostport) throws ParseException {\n        Lexer lexer = new Lexer(\"charLexer\", hostport);\n        return new HostNameParser(lexer).hostPort();\n\n    }\n    */\n\n    /**\n     * Parse a host name and return a parsed structure.\n     *\n     * @param host\n     *            is a String containing the host name to be parsed\n     * @return a parsed address structure.\n     * @since v1.0\n     * @exception ParseException\n     *                a ParseException when the hostname is badly formatted.\n     */\n    public Host parseHost(String host) throws ParseException {\n        Lexer lexer = new Lexer(\"charLexer\", host);\n        return new HostNameParser(lexer).host();\n\n    }\n\n    /**\n     * Parse a telephone number return a parsed structure.\n     *\n     * @param telephone_number\n     *            is a String containing the telephone # to be parsed\n     * @return a parsed address structure.\n     * @since v1.0\n     * @exception ParseException\n     *                a ParseException when the address is badly formatted.\n     */\n    public TelephoneNumber parseTelephoneNumber(String telephone_number)\n            throws ParseException {\n        // Bug fix contributed by Will Scullin\n        return new URLParser(telephone_number).parseTelephoneNumber(true);\n\n    }\n\n    /**\n     * Parse a SIP url from a string and return a URI structure for it.\n     *\n     * @param url\n     *            a String containing the URI structure to be parsed.\n     * @return A parsed URI structure\n     * @exception ParseException\n     *                if there was an error parsing the message.\n     */\n\n    public SipUri parseSIPUrl(String url) throws ParseException {\n        try {\n            return new URLParser(url).sipURL(true);\n        } catch (ClassCastException ex) {\n            throw new ParseException(url + \" Not a SIP URL \", 0);\n        }\n    }\n\n    /**\n     * Parse a uri from a string and return a URI structure for it.\n     *\n     * @param url\n     *            a String containing the URI structure to be parsed.\n     * @return A parsed URI structure\n     * @exception ParseException\n     *                if there was an error parsing the message.\n     */\n\n    public GenericURI parseUrl(String url) throws ParseException {\n        return new URLParser(url).parse();\n    }\n\n    /**\n     * Parse an individual SIP message header from a string.\n     *\n     * @param header\n     *            String containing the SIP header.\n     * @return a SIPHeader structure.\n     * @exception ParseException\n     *                if there was an error parsing the message.\n     */\n    public SIPHeader parseSIPHeader(String header) throws ParseException {\n        int start = 0;\n        int end = header.length() - 1;\n        try {\n            // Squeeze out any leading control character.\n            while (header.charAt(start) <= 0x20)\n                start++;\n\n            // Squeeze out any trailing control character.\n            while (header.charAt(end) <= 0x20)\n                end--;\n        }\n        catch (ArrayIndexOutOfBoundsException e) {\n            // Array contains only control char.\n            throw new ParseException(\"Empty header.\", 0);\n        }\n\n        StringBuffer buffer = new StringBuffer(end + 1);\n        int i = start;\n        int lineStart = start;\n        boolean endOfLine = false;\n        while (i <= end) {\n            char c = header.charAt(i);\n            if (c == '\\r' || c == '\\n') {\n                if (!endOfLine) {\n                    buffer.append(header.substring(lineStart, i));\n                    endOfLine = true;\n                }\n            }\n            else {\n                if (endOfLine) {\n                    endOfLine = false;\n                    if (c == ' ' || c == '\\t') {\n                        buffer.append(' ');\n                        lineStart = i + 1;\n                    }\n                    else {\n                        lineStart = i;\n                    }\n                }\n            }\n\n            i++;\n        }\n        buffer.append(header.substring(lineStart, i));\n        buffer.append('\\n');\n\n        HeaderParser hp = ParserFactory.createParser(buffer.toString());\n        if (hp == null)\n            throw new ParseException(\"could not create parser\", 0);\n        return hp.parse();\n    }\n\n    /**\n     * Parse the SIP Request Line\n     *\n     * @param requestLine\n     *            a String containing the request line to be parsed.\n     * @return a RequestLine structure that has the parsed RequestLine\n     * @exception ParseException\n     *                if there was an error parsing the requestLine.\n     */\n\n    public RequestLine parseSIPRequestLine(String requestLine)\n            throws ParseException {\n        requestLine += \"\\n\";\n        return new RequestLineParser(requestLine).parse();\n    }\n\n    /**\n     * Parse the SIP Response message status line\n     *\n     * @param statusLine\n     *            a String containing the Status line to be parsed.\n     * @return StatusLine class corresponding to message\n     * @exception ParseException\n     *                if there was an error parsing\n     * @see StatusLine\n     */\n\n    public StatusLine parseSIPStatusLine(String statusLine)\n            throws ParseException {\n        statusLine += \"\\n\";\n        return new StatusLineParser(statusLine).parse();\n    }\n\n    public static void setComputeContentLengthFromMessage(\n            boolean computeContentLengthFromMessage) {\n        StringMsgParser.computeContentLengthFromMessage = computeContentLengthFromMessage;\n    }\n\n\n\n    /**\n     * Test code.\n     */\n    public static void main(String[] args) throws ParseException {\n        String messages[] = {\n                \"SIP/2.0 200 OK\\r\\n\"\n                        + \"To: \\\"The Little Blister\\\" <sip:LittleGuy@there.com>;tag=469bc066\\r\\n\"\n                        + \"From: \\\"The Master Blaster\\\" <sip:BigGuy@here.com>;tag=11\\r\\n\"\n                        + \"Via: SIP/2.0/UDP 139.10.134.246:5060;branch=z9hG4bK8b0a86f6_1030c7d18e0_17;received=139.10.134.246\\r\\n\"\n                        + \"Call-ID: 1030c7d18ae_a97b0b_b@8b0a86f6\\r\\n\"\n                        + \"CSeq: 1 SUBSCRIBE\\r\\n\"\n                        + \"Contact: <sip:172.16.11.162:5070>\\r\\n\"\n                        + \"Content-Length: 0\\r\\n\\r\\n\",\n\n                \"SIP/2.0 180 Ringing\\r\\n\"\n                        + \"Via: SIP/2.0/UDP 172.18.1.29:5060;branch=z9hG4bK43fc10fb4446d55fc5c8f969607991f4\\r\\n\"\n                        + \"To: \\\"0440\\\" <sip:0440@212.209.220.131>;tag=2600\\r\\n\"\n                        + \"From: \\\"Andreas\\\" <sip:andreas@e-horizon.se>;tag=8524\\r\\n\"\n                        + \"Call-ID: f51a1851c5f570606140f14c8eb64fd3@172.18.1.29\\r\\n\"\n                        + \"CSeq: 1 INVITE\\r\\n\" + \"Max-Forwards: 70\\r\\n\"\n                        + \"Record-Route: <sip:212.209.220.131:5060>\\r\\n\"\n                        + \"Content-Length: 0\\r\\n\\r\\n\",\n                \"REGISTER sip:nist.gov SIP/2.0\\r\\n\"\n                        + \"Via: SIP/2.0/UDP 129.6.55.182:14826\\r\\n\"\n                        + \"Max-Forwards: 70\\r\\n\"\n                        + \"From: <sip:mranga@nist.gov>;tag=6fcd5c7ace8b4a45acf0f0cd539b168b;epid=0d4c418ddf\\r\\n\"\n                        + \"To: <sip:mranga@nist.gov>\\r\\n\"\n                        + \"Call-ID: c5679907eb954a8da9f9dceb282d7230@129.6.55.182\\r\\n\"\n                        + \"CSeq: 1 REGISTER\\r\\n\"\n                        + \"Contact: <sip:129.6.55.182:14826>;methods=\\\"INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER\\\"\\r\\n\"\n                        + \"User-Agent: RTC/(Microsoft RTC)\\r\\n\"\n                        + \"Event:  registration\\r\\n\"\n                        + \"Allow-Events: presence\\r\\n\"\n                        + \"Content-Length: 0\\r\\n\\r\\n\"\n                        + \"INVITE sip:littleguy@there.com:5060 SIP/2.0\\r\\n\"\n                        + \"Via: SIP/2.0/UDP 65.243.118.100:5050\\r\\n\"\n                        + \"From: M. Ranganathan  <sip:M.Ranganathan@sipbakeoff.com>;tag=1234\\r\\n\"\n                        + \"To: \\\"littleguy@there.com\\\" <sip:littleguy@there.com:5060> \\r\\n\"\n                        + \"Call-ID: Q2AboBsaGn9!?x6@sipbakeoff.com \\r\\n\"\n                        + \"CSeq: 1 INVITE \\r\\n\"\n                        + \"Content-Length: 247\\r\\n\\r\\n\"\n                        + \"v=0\\r\\n\"\n                        + \"o=4855 13760799956958020 13760799956958020 IN IP4  129.6.55.78\\r\\n\"\n                        + \"s=mysession session\\r\\n\" + \"p=+46 8 52018010\\r\\n\"\n                        + \"c=IN IP4  129.6.55.78\\r\\n\" + \"t=0 0\\r\\n\"\n                        + \"m=audio 6022 RTP/AVP 0 4 18\\r\\n\"\n                        + \"a=rtpmap:0 PCMU/8000\\r\\n\"\n                        + \"a=rtpmap:4 G723/8000\\r\\n\"\n                        + \"a=rtpmap:18 G729A/8000\\r\\n\" + \"a=ptime:20\\r\\n\" };\n\n        class ParserThread implements Runnable {\n            String[] messages;\n\n            public ParserThread(String[] messagesToParse) {\n                this.messages = messagesToParse;\n            }\n\n            public void run() {\n                for (int i = 0; i < messages.length; i++) {\n                    StringMsgParser smp = new StringMsgParser();\n                    try {\n                        SIPMessage sipMessage = smp\n                                .parseSIPMessage(messages[i]);\n                        System.out.println(\" i = \" + i + \" branchId = \"\n                                + sipMessage.getTopmostVia().getBranch());\n                        // System.out.println(\"encoded \" +\n                        // sipMessage.toString());\n                    } catch (ParseException ex) {\n\n                    }\n\n                    // System.out.println(\"dialog id = \" +\n                    // sipMessage.getDialogId(false));\n                }\n            }\n        }\n\n        for (int i = 0; i < 20; i++) {\n            new Thread(new ParserThread(messages)).start();\n        }\n\n    }\n\n    public void setStrict(boolean strict) {\n       this.strict = strict;\n        \n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/SubjectParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Subject  header.\n *\n * @version 1.2\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class SubjectParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of SubjectParser\n     * @param subject the header to parse\n     */\n    public SubjectParser(String subject) {\n        super(subject);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected SubjectParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (Subject object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        Subject subject = new Subject();\n        if (debug)\n            dbg_enter(\"SubjectParser.parse\");\n\n        try {\n            headerName(TokenTypes.SUBJECT);\n\n            this.lexer.SPorHT();\n\n            String s = this.lexer.getRest();\n            subject.setSubject(s.trim());\n\n        } finally {\n            if (debug)\n                dbg_leave(\"SubjectParser.parse\");\n        }\n\n        return subject;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n    String subject[] = {\n            \"Subject: Where is the Moscone?\\n\",\n            \"Subject: Need more boxes\\n\"\n            };\n\n    for (int i = 0; i < subject.length; i++ ) {\n        SubjectParser parser =\n          new SubjectParser(subject[i]);\n        Subject s= (Subject) parser.parse();\n        System.out.println(\"encoded = \" +s.encode());\n    }\n\n    }\n     */\n}\n/*\n * $Log: SubjectParser.java,v $\n * Revision 1.7  2009/07/17 18:58:05  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:17  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/SubscriptionStateParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for SubscriptionState header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:05 $\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n */\npublic class SubscriptionStateParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of SubscriptionStateParser\n     * @param subscriptionState the header to parse\n     */\n    public SubscriptionStateParser(String subscriptionState) {\n        super(subscriptionState);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected SubscriptionStateParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (SubscriptionState  object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"SubscriptionStateParser.parse\");\n\n        SubscriptionState subscriptionState = new SubscriptionState();\n        try {\n            headerName(TokenTypes.SUBSCRIPTION_STATE);\n\n            subscriptionState.setHeaderName(SIPHeaderNames.SUBSCRIPTION_STATE);\n\n            // State:\n            lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n            subscriptionState.setState(token.getTokenValue());\n\n            while (lexer.lookAhead(0) == ';') {\n                this.lexer.match(';');\n                this.lexer.SPorHT();\n                lexer.match(TokenTypes.ID);\n                token = lexer.getNextToken();\n                String value = token.getTokenValue();\n                if (value.equalsIgnoreCase(\"reason\")) {\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    value = token.getTokenValue();\n                    subscriptionState.setReasonCode(value);\n                } else if (value.equalsIgnoreCase(\"expires\")) {\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    value = token.getTokenValue();\n                    try {\n                        int expires = Integer.parseInt(value);\n                        subscriptionState.setExpires(expires);\n                    } catch (NumberFormatException ex) {\n                        throw createParseException(ex.getMessage());\n                    } catch (InvalidArgumentException ex) {\n                        throw createParseException(ex.getMessage());\n                    }\n                } else if (value.equalsIgnoreCase(\"retry-after\")) {\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    value = token.getTokenValue();\n                    try {\n                        int retryAfter = Integer.parseInt(value);\n                        subscriptionState.setRetryAfter(retryAfter);\n                    } catch (NumberFormatException ex) {\n                        throw createParseException(ex.getMessage());\n                    } catch (InvalidArgumentException ex) {\n                        throw createParseException(ex.getMessage());\n                    }\n                } else {\n                    this.lexer.match('=');\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    Token secondToken = lexer.getNextToken();\n                    String secondValue = secondToken.getTokenValue();\n                    subscriptionState.setParameter(value, secondValue);\n                }\n                this.lexer.SPorHT();\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"SubscriptionStateParser.parse\");\n        }\n\n        return subscriptionState;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n        String subscriptionState[] = {\n            \"Subscription-State: active \\n\",\n            \"Subscription-State: terminated;reason=rejected \\n\",\n            \"Subscription-State: pending;reason=probation;expires=36\\n\",\n            \"Subscription-State: pending;retry-after=10;expires=36\\n\",\n            \"Subscription-State: pending;generic=void\\n\"\n        };\n\n        for (int i = 0; i < subscriptionState.length; i++ ) {\n            SubscriptionStateParser parser =\n            new SubscriptionStateParser(subscriptionState[i]);\n            SubscriptionState ss= (SubscriptionState) parser.parse();\n            System.out.println(\"encoded = \" + ss.encode());\n        }\n    }\n     */\n}\n/*\n * $Log: SubscriptionStateParser.java,v $\n * Revision 1.7  2009/07/17 18:58:05  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:25  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/SupportedParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Supported header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:06 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n *\n * @version 1.0\n */\npublic class SupportedParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of SupportedParser\n     * @param supported the header to parse\n     */\n    public SupportedParser(String supported) {\n        super(supported);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected SupportedParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (Supported object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        SupportedList supportedList = new SupportedList();\n        if (debug)\n            dbg_enter(\"SupportedParser.parse\");\n\n        try {\n            headerName(TokenTypes.SUPPORTED);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                this.lexer.SPorHT();\n                Supported supported = new Supported();\n                supported.setHeaderName(SIPHeaderNames.SUPPORTED);\n\n                // Parsing the option tag\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                supported.setOptionTag(token.getTokenValue());\n                this.lexer.SPorHT();\n\n                supportedList.add(supported);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n\n                    supported = new Supported();\n\n                    // Parsing the option tag\n                    this.lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    supported.setOptionTag(token.getTokenValue());\n                    this.lexer.SPorHT();\n\n                    supportedList.add(supported);\n                }\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"SupportedParser.parse\");\n        }\n\n        return supportedList;\n    }\n\n    /** Test program\n    public static void main(String args[]) throws ParseException {\n        String supported[] = {\n            \"Supported: 100rel \\n\",\n            \"Supported: foo1, foo2 ,foo3 , foo4 \\n\"\n        };\n\n        for (int i = 0; i < supported.length; i++ ) {\n            SupportedParser parser =\n            new SupportedParser(supported[i]);\n            SupportedList s= (SupportedList) parser.parse();\n            System.out.println(\"encoded = \" + s.encode());\n        }\n\n    }\n     */\n}\n/*\n * $Log: SupportedParser.java,v $\n * Revision 1.7  2009/07/17 18:58:06  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:02  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/TimeStampParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for TimeStamp header.\n *\n * @version 1.2 $Revision: 1.9 $ $Date: 2009/10/18 13:46:39 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class TimeStampParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of TimeStampParser\n     * @param timeStamp the header to parse\n     */\n    public TimeStampParser(String timeStamp) {\n        super(timeStamp);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected TimeStampParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (TimeStamp object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"TimeStampParser.parse\");\n        TimeStamp timeStamp = new TimeStamp();\n        try {\n            headerName(TokenTypes.TIMESTAMP);\n\n            timeStamp.setHeaderName(SIPHeaderNames.TIMESTAMP);\n\n            this.lexer.SPorHT();\n            String firstNumber = this.lexer.number();\n\n            try {\n\n                if (lexer.lookAhead(0) == '.') {\n                    this.lexer.match('.');\n                    String secondNumber = this.lexer.number();\n\n                    String s = firstNumber + \".\" + secondNumber;\n                    float ts = Float.parseFloat(s);\n                    timeStamp.setTimeStamp(ts);\n                } else {\n                    long ts = Long.parseLong(firstNumber);\n                    timeStamp.setTime(ts);\n                }\n\n\n            } catch (NumberFormatException ex) {\n                throw createParseException(ex.getMessage());\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n\n            this.lexer.SPorHT();\n            if (lexer.lookAhead(0) != '\\n') {\n                firstNumber = this.lexer.number();\n\n                try {\n\n                    if (lexer.lookAhead(0) == '.') {\n                        this.lexer.match('.');\n                        String secondNumber = this.lexer.number();\n\n                        String s = firstNumber + \".\" + secondNumber;\n                        float ts = Float.parseFloat(s);\n                        timeStamp.setDelay(ts);\n                    } else {\n                        int ts = Integer.parseInt(firstNumber);\n                        timeStamp.setDelay(ts);\n                    }\n\n\n                } catch (NumberFormatException ex) {\n                    throw createParseException(ex.getMessage());\n                } catch (InvalidArgumentException ex) {\n                    throw createParseException(ex.getMessage());\n                }\n            }\n\n        } finally {\n            if (debug)\n                dbg_leave(\"TimeStampParser.parse\");\n        }\n\n        return timeStamp;\n    }\n\n\n\n\n}\n/*\n * $Log: TimeStampParser.java,v $\n * Revision 1.9  2009/10/18 13:46:39  deruelle_jean\n * FindBugs Fixes (Category Performance Warnings)\n *\n * Issue number:\n * Obtained from:\n * Submitted by: Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.8  2009/07/17 18:58:06  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.7  2006/08/15 21:44:50  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n * Incorporating the latest API changes from Phelim\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.6  2006/07/13 09:02:14  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.5  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.4  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.3  2006/05/25 23:46:23  mranga\n * Added @author NIST to all API files. Moved a package around in the tck directory.\n *\n * Ranga.\n *\n * Revision 1.2  2006/05/18 10:08:43  mranga\n * Fixes null pointer in comparison when host is not specified. Add methods to allow longs and ints as args in TimeStamp Header.\n *\n * Ranga.\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ToParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport java.text.ParseException;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * To Header parser.\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/10/22 10:27:38 $\n *\n * @author Olivier Deruelle   <br/>\n *\n *\n */\npublic class ToParser extends AddressParametersParser {\n\n    /**\n     * Creates new ToParser\n     * @param to String to set\n     */\n    public ToParser(String to) {\n        super(to);\n    }\n\n    protected ToParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n\n        headerName(TokenTypes.TO);\n        To to = new To();\n        super.parse(to);\n        this.lexer.match('\\n');        \n        return to;\n    }\n\n    /**\n\n        public static void main(String args[]) throws ParseException {\n            String to[] = {\n               \"To: <sip:+1-650-555-2222@ss1.wcom.com;user=phone>;tag=5617\\n\",\n               \"To: T. A. Watson <sip:watson@bell-telephone.com;param=something>\\n\",\n               \"To: LittleGuy <sip:UserB@there.com;tag=foo>;tag=bar\\n\",\n               \"To: sip:mranga@120.6.55.9\\n\",\n               \"To: sip:mranga@129.6.55.9;tag=696928473514.129.6.55.9\\n\",\n               \"To: sip:mranga@129.6.55.9; tag=696928473514.129.6.55.9\\n\",\n               \"To: sip:mranga@129.6.55.9 ;tag=696928473514.129.6.55.9\\n\",\n               \"To: sip:mranga@129.6.55.9 ; tag=696928473514.129.6.55.9\\n\"\n            };\n\n            for (int i = 0; i < to.length; i++ ) {\n            System.out.println(\"toParse = \" + to[i]);\n                ToParser tp =\n                new ToParser(to[i]);\n                To t = (To) tp.parse();\n                System.out.println(\"encoded = \" + t.encode());\n            }\n\n        }\n    **/\n}\n/*\n * $Log: ToParser.java,v $\n * Revision 1.11  2009/10/22 10:27:38  jbemmel\n * Fix for issue #230, restructured the code such that parsing for any address appearing without '<' '>'\n * stops at ';', then parameters are assigned to the header as expected\n *\n * Revision 1.10  2009/07/17 18:58:06  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.9  2007/10/23 17:34:55  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:   mranga\n *\n * Refactored header collections.\n *\n * Revision 1.8  2006/07/13 09:02:00  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.6  2004/04/22 22:51:18  mranga\n * Submitted by:  Thomas Froment\n * Reviewed by:   mranga\n *\n * Fixed corner cases.\n *\n * Revision 1.5  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/TokenNames.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport javax2.sip.message.Request;\n\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * A grab bag of SIP Token names.\n *\n * @version 1.2 $Revision: 1.10 $ $Date: 2009/07/27 20:35:02 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic interface TokenNames\n    extends\n        gov2.nist.javax2.sip.header.ParameterNames,\n        gov2.nist.javax2.sip.address.ParameterNames {\n    // And now dreaded short forms....\n    public static final String INVITE = Request.INVITE;\n    public static final String ACK = Request.ACK;\n    public static final String BYE = Request.BYE;\n    public static final String SUBSCRIBE = Request.SUBSCRIBE;\n    public static final String NOTIFY = Request.NOTIFY;\n    public static final String OPTIONS = Request.OPTIONS;\n    public static final String REGISTER = Request.REGISTER;\n    public static final String MESSAGE = Request.MESSAGE;\n    public static final String PUBLISH = Request.PUBLISH;\n\n    public static final String SIP = GenericURI.SIP;\n    public static final String SIPS = GenericURI.SIPS;\n    public static final String TEL = GenericURI.TEL;\n    public static final String GMT = SIPDate.GMT;\n    public static final String MON = SIPDate.MON;\n    public static final String TUE = SIPDate.TUE;\n    public static final String WED = SIPDate.WED;\n    public static final String THU = SIPDate.THU;\n    public static final String FRI = SIPDate.FRI;\n    public static final String SAT = SIPDate.SAT;\n    public static final String SUN = SIPDate.SUN;\n    public static final String JAN = SIPDate.JAN;\n    public static final String FEB = SIPDate.FEB;\n    public static final String MAR = SIPDate.MAR;\n    public static final String APR = SIPDate.APR;\n    public static final String MAY = SIPDate.MAY;\n    public static final String JUN = SIPDate.JUN;\n    public static final String JUL = SIPDate.JUL;\n    public static final String AUG = SIPDate.AUG;\n    public static final String SEP = SIPDate.SEP;\n    public static final String OCT = SIPDate.OCT;\n    public static final String NOV = SIPDate.NOV;\n    public static final String DEC = SIPDate.DEC;\n    public static final String K = \"K\";\n    public static final String C = \"C\";\n    public static final String E = \"E\";\n    public static final String F = \"F\";\n    public static final String I = \"I\";\n    public static final String M = \"M\";\n    public static final String L = \"L\";\n    public static final String S = \"S\";\n    public static final String T = \"T\";\n    public static final String U = \"U\";// JvB: added\n    public static final String V = \"V\";\n    public static final String R = \"R\";\n    public static final String O = \"O\";\n    public static final String X = \"X\"; //Jozef Saniga added\n    public static final String B = \"B\"; // Bug fix OrangeLabs, AUFFRET Jean-Marc\n}\n/*\n * $Log: TokenNames.java,v $\n * Revision 1.10  2009/07/27 20:35:02  deruelle_jean\n * Fix for the compact form of SessionExpires Header from RFC 4028\n *\n * Issue number:\n * Obtained from: Jozef Saniga\n * Submitted by:  Jean Deruelle\n * Reviewed by:\n *\n * Revision 1.9  2009/07/17 18:58:06  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.8  2006/07/13 09:02:13  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.5  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.4  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.3  2005/10/27 20:49:00  jeroen\n * added support for RFC3903 PUBLISH\n *\n * Revision 1.2  2005/10/08 23:13:56  jeroen\n * added short form for Allow-Events\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.5  2005/04/27 14:12:05  mranga\n * Submitted by:  Mario Mantak\n * Reviewed by:   mranga\n *\n * Added a missing \"short form\" for event header.\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/TokenTypes.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\n\n/**\n * @version 1.2 $Revision: 1.13 $ $Date: 2010/01/12 00:05:25 $\n */\npublic interface TokenTypes {\n\n    public static final int START = LexerCore.START;\n    // Everything under this is reserved\n    public static final int END = LexerCore.END;\n    // End markder.\n\n    public static final int SIP = START + 3;\n    public static final int REGISTER = START + 4;\n    public static final int INVITE = START + 5;\n    public static final int ACK = START + 6;\n    public static final int BYE = START + 7;\n    public static final int OPTIONS = START + 8;\n    public static final int CANCEL = START + 9;\n    public static final int ERROR_INFO = START + 10;\n    public static final int IN_REPLY_TO = START + 11;\n    public static final int MIME_VERSION = START + 12;\n    public static final int ALERT_INFO = START + 13;\n    public static final int FROM = START + 14;\n    public static final int TO = START + 15;\n    public static final int VIA = START + 16;\n    public static final int USER_AGENT = START + 17;\n    public static final int SERVER = START + 18;\n    public static final int ACCEPT_ENCODING = START + 19;\n    public static final int ACCEPT = START + 20;\n    public static final int ALLOW = START + 21;\n    public static final int ROUTE = START + 22;\n    public static final int AUTHORIZATION = START + 23;\n    public static final int PROXY_AUTHORIZATION = START + 24;\n    public static final int RETRY_AFTER = START + 25;\n    public static final int PROXY_REQUIRE = START + 26;\n    public static final int CONTENT_LANGUAGE = START + 27;\n    public static final int UNSUPPORTED = START + 28;\n    public static final int SUPPORTED = START + 20;\n    public static final int WARNING = START + 30;\n    public static final int MAX_FORWARDS = START + 31;\n    public static final int DATE = START + 32;\n    public static final int PRIORITY = START + 33;\n    public static final int PROXY_AUTHENTICATE = START + 34;\n    public static final int CONTENT_ENCODING = START + 35;\n    public static final int CONTENT_LENGTH = START + 36;\n    public static final int SUBJECT = START + 37;\n    public static final int CONTENT_TYPE = START + 38;\n    public static final int CONTACT = START + 39;\n    public static final int CALL_ID = START + 40;\n    public static final int REQUIRE = START + 41;\n    public static final int EXPIRES = START + 42;\n    public static final int ENCRYPTION = START + 43;\n    public static final int RECORD_ROUTE = START + 44;\n    public static final int ORGANIZATION = START + 45;\n    public static final int CSEQ = START + 46;\n    public static final int ACCEPT_LANGUAGE = START + 47;\n    public static final int WWW_AUTHENTICATE = START + 48;\n    public static final int RESPONSE_KEY = START + 49;\n    public static final int HIDE = START + 50;\n    public static final int CALL_INFO = START + 51;\n    public static final int CONTENT_DISPOSITION = START + 52;\n    public static final int SUBSCRIBE = START + 53;\n    public static final int NOTIFY = START + 54;\n    public static final int TIMESTAMP = START + 55;\n    public static final int SUBSCRIPTION_STATE = START + 56;\n    public static final int TEL = START + 57;\n    public static final int REPLY_TO = START + 58;\n    public static final int REASON = START + 59;\n    public static final int RSEQ = START + 60;\n    public static final int RACK = START + 61;\n    public static final int MIN_EXPIRES = START + 62;\n    public static final int EVENT = START + 63;\n    public static final int AUTHENTICATION_INFO = START + 64;\n    public static final int ALLOW_EVENTS = START + 65;\n    public static final int REFER_TO = START + 66;\n\n    // JvB: added to support RFC3903\n    public static final int PUBLISH = START + 67;\n    public static final int SIP_ETAG = START + 68;\n    public static final int SIP_IF_MATCH = START + 69;\n\n\n\n\n    public static final int MESSAGE = START + 70;\n\n    // IMS Headers\n    public static final int PATH = START + 71;\n    public static final int SERVICE_ROUTE = START + 72;\n    public static final int P_ASSERTED_IDENTITY = START + 73;\n    public static final int P_PREFERRED_IDENTITY = START + 74;\n    public static final int P_VISITED_NETWORK_ID = START + 75;\n    public static final int P_CHARGING_FUNCTION_ADDRESSES = START + 76;\n    public static final int P_VECTOR_CHARGING = START + 77;\n\n\n\n    // issued by Miguel Freitas - IMS headers\n    public static final int PRIVACY = START + 78;\n    public static final int P_ACCESS_NETWORK_INFO = START + 79;\n    public static final int P_CALLED_PARTY_ID = START + 80;\n    public static final int P_ASSOCIATED_URI = START + 81;\n    public static final int P_MEDIA_AUTHORIZATION = START + 82;\n    public static final int P_MEDIA_AUTHORIZATION_TOKEN = START + 83;\n\n\n    // pmusgrave - additions\n    public static final int REFERREDBY_TO = START + 84;\n\n    // pmusgrave RFC4028\n    public static final int SESSIONEXPIRES_TO = START + 85;\n    public static final int MINSE_TO = START + 86;\n\n    // pmusgrave RFC3891\n    public static final int REPLACES_TO = START + 87;\n\n    // pmusgrave sips bug fix\n    public static final int SIPS = START + 88;\n\n\n    // issued by Miguel Freitas - SIP Security Agreement (RFC3329)\n    public static final int SECURITY_SERVER = START + 89;\n    public static final int SECURITY_CLIENT = START + 90;\n    public static final int SECURITY_VERIFY = START + 91;\n\n    // jean deruelle RFC3911\n    public static final int JOIN_TO = START + 92;\n\n    // aayush.bhatnagar: RFC 4457 support.\n    public static final int P_USER_DATABASE = START + 93;\n    //aayush.bhatnagar: RFC 5002 support.\n    public static final int P_PROFILE_KEY = START + 94;\n    //aayush.bhatnagar: RFC 5502 support.\n    public static final int P_SERVED_USER = START + 95;\n    //aayush.bhatnaagr: P-Preferred-Service Header:\n    public static final int P_PREFERRED_SERVICE = START + 96;\n    //aayush.bhatnagar: P-Asserted-Service Header:\n    public static final int P_ASSERTED_SERVICE = START + 97;\n    //mranga - References header\n    public static final int REFERENCES = START + 98;\n\n    public static final int ALPHA = LexerCore.ALPHA;\n    public static final int DIGIT = LexerCore.DIGIT;\n    public static final int ID = LexerCore.ID;\n    public static final int WHITESPACE = LexerCore.WHITESPACE;\n    public static final int BACKSLASH = LexerCore.BACKSLASH;\n    public static final int QUOTE = LexerCore.QUOTE;\n    public static final int AT = LexerCore.AT;\n    public static final int SP = LexerCore.SP;\n    public static final int HT = LexerCore.HT;\n    public static final int COLON = LexerCore.COLON;\n    public static final int STAR = LexerCore.STAR;\n    public static final int DOLLAR = LexerCore.DOLLAR;\n    public static final int PLUS = LexerCore.PLUS;\n    public static final int POUND = LexerCore.POUND;\n    public static final int MINUS = LexerCore.MINUS;\n    public static final int DOUBLEQUOTE = LexerCore.DOUBLEQUOTE;\n    public static final int TILDE = LexerCore.TILDE;\n    public static final int BACK_QUOTE = LexerCore.BACK_QUOTE;\n    public static final int NULL = LexerCore.NULL;\n    public static final int EQUALS = (int) '=';\n    public static final int SEMICOLON = (int) ';';\n    public static final int SLASH = (int) '/';\n    public static final int L_SQUARE_BRACKET = (int) '[';\n    public static final int R_SQUARE_BRACKET = (int) ']';\n    public static final int R_CURLY = (int) '}';\n    public static final int L_CURLY = (int) '{';\n    public static final int HAT = (int) '^';\n    public static final int BAR = (int) '|';\n    public static final int DOT = (int) '.';\n    public static final int EXCLAMATION = (int) '!';\n    public static final int LPAREN = (int) '(';\n    public static final int RPAREN = (int) ')';\n    public static final int GREATER_THAN = (int) '>';\n    public static final int LESS_THAN = (int) '<';\n    public static final int PERCENT = (int) '%';\n    public static final int QUESTION = (int) '?';\n    public static final int AND = (int) '&';\n    public static final int UNDERSCORE = (int) '_';\n\n}\n/*\n * $Log: TokenTypes.java,v $\n * Revision 1.13  2010/01/12 00:05:25  mranga\n * Add support for References header draft-worley-references-05\n *\n * Revision 1.12  2009/07/17 18:58:06  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.11  2009/05/10 00:29:53  mranga\n *\n * Submitted by:  Aayush Bhatnagar\n * Reviewed by:\n * IMS headers and parsers.\n *\n * Revision 1.10  2009/01/22 19:33:47  deruelle_jean\n * Add support for JOIN (RFC 3911)\n * Issue number:  186\n * Obtained from:\n * Submitted by:  Jean Deruelle\n * Reviewed by:   Ranga, The high priest and grand poobah of Jain-SIP\n *\n * Revision 1.9  2007/01/08 19:24:22  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  Miguel Freitas\n * Reviewed by:   mranga\n *\n * Miguel -- please implement a deep clone method for the IMS headers.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.8  2006/10/12 11:57:54  pmusgrave\n * Issue number:  79, 80\n * Submitted by:  pmusgrave@newheights.com\n * Reviewed by:   mranga\n *\n * Revision 1.7  2006/09/11 18:41:32  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  mranga\n * Reviewed by:\n * Tighter integration of IMS headers.\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.6  2006/07/13 09:01:55  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.4  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.3  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.2  2005/10/27 20:49:00  jeroen\n * added support for RFC3903 PUBLISH\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/URLParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport gov2.nist.core.HostNameParser;\nimport gov2.nist.core.HostPort;\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.address.GenericURI;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.address.TelURLImpl;\nimport gov2.nist.javax2.sip.address.TelephoneNumber;\n\nimport java.text.ParseException;\n\n/**\n * Parser For SIP and Tel URLs. Other kinds of URL's are handled by the\n * J2SE 1.4 URL class.\n * @version 1.2 $Revision: 1.27 $ $Date: 2009/10/22 10:27:39 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class URLParser extends Parser {\n\n    public URLParser(String url) {\n        this.lexer = new Lexer(\"sip_urlLexer\", url);\n    }\n\n    // public tag added - issued by Miguel Freitas\n    public URLParser(Lexer lexer) {\n        this.lexer = lexer;\n        this.lexer.selectLexer(\"sip_urlLexer\");\n    }\n    protected static boolean isMark(char next) {\n        switch (next) {\n            case '-':\n            case '_':\n            case '.':\n            case '!':\n            case '~':\n            case '*':\n            case '\\'':\n            case '(':\n            case ')':\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    protected static boolean isUnreserved(char next) {\n        return Lexer.isAlphaDigit(next) || isMark(next);\n    }\n\n    protected static boolean isReservedNoSlash(char next) {\n        switch (next) {\n            case ';':\n            case '?':\n            case ':':\n            case '@':\n            case '&':\n            case '+':\n            case '$':\n            case ',':\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    // Missing '=' bug in character set - discovered by interop testing\n    // at SIPIT 13 by Bob Johnson and Scott Holben.\n    // change . to ; by Bruno Konik\n    protected static boolean isUserUnreserved(char la) {\n        switch (la) {\n            case '&':\n            case '?':\n            case '+':\n            case '$':\n            case '#':\n            case '/':\n            case ',':\n            case ';':\n            case '=':\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    protected String unreserved() throws ParseException {\n        char next = lexer.lookAhead(0);\n        if (isUnreserved(next)) {\n            lexer.consume(1);\n            return String.valueOf(next);\n        } else\n            throw createParseException(\"unreserved\");\n\n    }\n\n    /** Name or value of a parameter.\n     */\n    protected String paramNameOrValue() throws ParseException {\n        int startIdx = lexer.getPtr();\n        while (lexer.hasMoreChars()) {\n            char next = lexer.lookAhead(0);\n            boolean isValidChar = false;\n            switch (next) {\n                case '[':\n                case ']':// JvB: fixed this one\n                case '/':\n                case ':':\n                case '&':\n                case '+':\n                case '$':\n                    isValidChar = true;\n            }\n            if (isValidChar || isUnreserved(next)) {\n                lexer.consume(1);\n            } else if (isEscaped()) {\n                lexer.consume(3);\n            } else\n                break;\n        }\n        return lexer.getBuffer().substring(startIdx, lexer.getPtr());\n    }\n\n    private NameValue uriParam() throws ParseException {\n        if (debug)\n            dbg_enter(\"uriParam\");\n        try {\n            String pvalue = \"\";\n            String pname = paramNameOrValue();\n            char next = lexer.lookAhead(0);\n            boolean isFlagParam = true;\n            if (next == '=') {\n                lexer.consume(1);\n                pvalue = paramNameOrValue();\n                isFlagParam = false;\n            }\n            if (pname.length() == 0 &&\n                ( pvalue == null ||\n                pvalue.length() == 0))\n                return null;\n            else return new NameValue(pname, pvalue, isFlagParam);\n        } finally {\n            if (debug)\n                dbg_leave(\"uriParam\");\n        }\n    }\n\n    protected static boolean isReserved(char next) {\n        switch (next) {\n            case ';':\n            case '/':\n            case '?':\n            case ':':\n            case '=': // Bug fix by Bruno Konik\n            case '@':\n            case '&':\n            case '+':\n            case '$':\n            case ',':\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    protected String reserved() throws ParseException {\n        char next = lexer.lookAhead(0);\n        if (isReserved(next)) {\n            lexer.consume(1);\n            return new StringBuffer().append(next).toString();\n        } else\n            throw createParseException(\"reserved\");\n    }\n\n    protected boolean isEscaped() {\n        try {\n            return lexer.lookAhead(0) == '%' &&\n                Lexer.isHexDigit(lexer.lookAhead(1)) &&\n                Lexer.isHexDigit(lexer.lookAhead(2));\n        } catch (Exception ex) {\n            return false;\n        }\n    }\n\n    protected String escaped() throws ParseException {\n        if (debug)\n            dbg_enter(\"escaped\");\n        try {\n            StringBuffer retval = new StringBuffer();\n            char next = lexer.lookAhead(0);\n            char next1 = lexer.lookAhead(1);\n            char next2 = lexer.lookAhead(2);\n            if (next == '%'\n                && Lexer.isHexDigit(next1)\n                && Lexer.isHexDigit(next2)) {\n                lexer.consume(3);\n                retval.append(next);\n                retval.append(next1);\n                retval.append(next2);\n            } else\n                throw createParseException(\"escaped\");\n            return retval.toString();\n        } finally {\n            if (debug)\n                dbg_leave(\"escaped\");\n        }\n    }\n\n    protected String mark() throws ParseException {\n        if (debug)\n            dbg_enter(\"mark\");\n        try {\n            char next = lexer.lookAhead(0);\n            if (isMark(next)) {\n                lexer.consume(1);\n                return new String( new char[]{next} );\n            } else\n                throw createParseException(\"mark\");\n        } finally {\n            if (debug)\n                dbg_leave(\"mark\");\n        }\n    }\n\n    protected String uric() {\n        if (debug)\n            dbg_enter(\"uric\");\n        try {\n            try {\n                char la = lexer.lookAhead(0);\n                if (isUnreserved(la)) {\n                    lexer.consume(1);\n                    return Lexer.charAsString(la);\n                } else if (isReserved(la)) {\n                    lexer.consume(1);\n                    return Lexer.charAsString(la);\n                } else if (isEscaped()) {\n                    String retval = lexer.charAsString(3);\n                    lexer.consume(3);\n                    return retval;\n                } else\n                    return null;\n            } catch (Exception ex) {\n                return null;\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"uric\");\n        }\n\n    }\n\n    protected String uricNoSlash() {\n        if (debug)\n            dbg_enter(\"uricNoSlash\");\n        try {\n            try {\n                char la = lexer.lookAhead(0);\n                if (isEscaped()) {\n                    String retval = lexer.charAsString(3);\n                    lexer.consume(3);\n                    return retval;\n                } else if (isUnreserved(la)) {\n                    lexer.consume(1);\n                    return Lexer.charAsString(la);\n                } else if (isReservedNoSlash(la)) {\n                    lexer.consume(1);\n                    return Lexer.charAsString(la);\n                } else\n                    return null;\n            } catch (ParseException ex) {\n                return null;\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"uricNoSlash\");\n        }\n    }\n\n    protected String uricString() throws ParseException {\n        StringBuffer retval = new StringBuffer();\n        while (true) {\n            String next = uric();\n            if (next == null) {\n                char la = lexer.lookAhead(0);\n                // JvB: allow IPv6 addresses in generic URI strings\n                // e.g. http://[::1]\n                if ( la == '[' ) {\n                    HostNameParser hnp = new HostNameParser(this.getLexer());\n                    HostPort hp = hnp.hostPort( false );\n                    retval.append(hp.toString());\n                    continue;\n                }\n                break;\n            }\n            retval.append(next);\n        }\n        return retval.toString();\n    }\n\n    /**\n     * Parse and return a structure for a generic URL.\n     * Note that non SIP URLs are just stored as a string (not parsed).\n     * @return URI is a URL structure for a SIP url.\n     * @throws ParseException if there was a problem parsing.\n     */\n    public GenericURI uriReference( boolean inBrackets ) throws ParseException {\n        if (debug)\n            dbg_enter(\"uriReference\");\n        GenericURI retval = null;\n        Token[] tokens = lexer.peekNextToken(2);\n        Token t1 = (Token) tokens[0];\n        Token t2 = (Token) tokens[1];\n        try {\n\n            if (t1.getTokenType() == TokenTypes.SIP ||\n                    t1.getTokenType() == TokenTypes.SIPS) {\n                if (t2.getTokenType() == ':')\n                    retval = sipURL( inBrackets );\n                else\n                    throw createParseException(\"Expecting \\':\\'\");\n            } else if (t1.getTokenType() == TokenTypes.TEL) {\n                if (t2.getTokenType() == ':') {\n                    retval = telURL( inBrackets );\n                } else\n                    throw createParseException(\"Expecting \\':\\'\");\n            } else {\n                String urlString = uricString();\n                try {\n                    retval = new GenericURI(urlString);\n                } catch (ParseException ex) {\n                    throw createParseException(ex.getMessage());\n                }\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"uriReference\");\n        }\n        return retval;\n    }\n\n    /**\n     * Parser for the base phone number.\n     */\n    private String base_phone_number() throws ParseException {\n        StringBuffer s = new StringBuffer();\n\n        if (debug)\n            dbg_enter(\"base_phone_number\");\n        try {\n            int lc = 0;\n            while (lexer.hasMoreChars()) {\n                char w = lexer.lookAhead(0);\n                if (Lexer.isDigit(w)\n                    || w == '-'\n                    || w == '.'\n                    || w == '('\n                    || w == ')') {\n                    lexer.consume(1);\n                    s.append(w);\n                    lc++;\n                } else if (lc > 0)\n                    break;\n                else\n                    throw createParseException(\"unexpected \" + w);\n            }\n            return s.toString();\n        } finally {\n            if (debug)\n                dbg_leave(\"base_phone_number\");\n        }\n\n    }\n\n    /**\n     * Parser for the local phone #.\n     */\n    private String local_number() throws ParseException {\n        StringBuffer s = new StringBuffer();\n        if (debug)\n            dbg_enter(\"local_number\");\n        try {\n            int lc = 0;\n            while (lexer.hasMoreChars()) {\n                char la = lexer.lookAhead(0);\n                if (la == '*'\n                    || la == '#'\n                    || la == '-'\n                    || la == '.'\n                    || la == '('\n                    || la == ')'\n                        // JvB: allow 'A'..'F', should be uppercase\n                    || Lexer.isHexDigit(la)) {\n                    lexer.consume(1);\n                    s.append(la);\n                    lc++;\n                } else if (lc > 0)\n                    break;\n                else\n                    throw createParseException(\"unexepcted \" + la);\n            }\n            return s.toString();\n        } finally {\n            if (debug)\n                dbg_leave(\"local_number\");\n        }\n\n    }\n\n    /**\n     * Parser for telephone subscriber.\n     *\n     * @return the parsed telephone number.\n     */\n    public final TelephoneNumber parseTelephoneNumber( boolean inBrackets ) \n    \tthrows ParseException {\n        TelephoneNumber tn;\n\n        if (debug)\n            dbg_enter(\"telephone_subscriber\");\n        lexer.selectLexer(\"charLexer\");\n        try {\n            char c = lexer.lookAhead(0);\n            if (c == '+')\n                tn = global_phone_number( inBrackets );\n            else if (\n                Lexer.isHexDigit(c)// see RFC3966\n                    || c == '#'\n                    || c == '*'\n                    || c == '-'\n                    || c == '.'\n                    || c == '('\n                    || c == ')' ) {\n                tn = local_phone_number( inBrackets );\n            } else\n                throw createParseException(\"unexpected char \" + c);\n            return tn;\n        } finally {\n            if (debug)\n                dbg_leave(\"telephone_subscriber\");\n        }\n\n    }\n\n    private final TelephoneNumber global_phone_number( boolean inBrackets ) throws ParseException {\n        if (debug)\n            dbg_enter(\"global_phone_number\");\n        try {\n            TelephoneNumber tn = new TelephoneNumber();\n            tn.setGlobal(true);\n            NameValueList nv = null;\n            this.lexer.match(PLUS);\n            String b = base_phone_number();\n            tn.setPhoneNumber(b);\n            if (lexer.hasMoreChars()) {\n                char tok = lexer.lookAhead(0);\n                if (tok == ';' && inBrackets) {\n                    this.lexer.consume(1);\n                    nv = tel_parameters();\n                    tn.setParameters(nv);\n                }\n            }\n            return tn;\n        } finally {\n            if (debug)\n                dbg_leave(\"global_phone_number\");\n        }\n    }\n\n    private TelephoneNumber local_phone_number( boolean inBrackets ) throws ParseException {\n        if (debug)\n            dbg_enter(\"local_phone_number\");\n        TelephoneNumber tn = new TelephoneNumber();\n        tn.setGlobal(false);\n        NameValueList nv = null;\n        String b = null;\n        try {\n            b = local_number();\n            tn.setPhoneNumber(b);\n            if (lexer.hasMoreChars()) {\n                Token tok = this.lexer.peekNextToken();\n                switch (tok.getTokenType()) {\n                    case SEMICOLON:\n                        {\n                        \tif (inBrackets) {\n                        \t\tthis.lexer.consume(1);\n                        \t\tnv = tel_parameters();\n                        \t\ttn.setParameters(nv);\n                        \t}\n                            break;\n                        }\n                    default :\n                        {\n                            break;\n                        }\n                }\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"local_phone_number\");\n        }\n        return tn;\n    }\n\n    private NameValueList tel_parameters() throws ParseException {\n        NameValueList nvList = new NameValueList();\n\n        // JvB: Need to handle 'phone-context' specially\n        // 'isub' (or 'ext') MUST appear first, but we accept any order here\n        NameValue nv;\n        while ( true ) {\n            String pname = paramNameOrValue();\n\n            // Handle 'phone-context' specially, it may start with '+'\n            if ( pname.equalsIgnoreCase(\"phone-context\")) {\n                nv = phone_context();\n            } else {\n                if (lexer.lookAhead(0) == '=') {\n                    lexer.consume(1);\n                    String value = paramNameOrValue();\n                    nv = new NameValue( pname, value, false );\n                } else {\n                    nv = new NameValue( pname, \"\", true );// flag param\n                }\n            }\n            nvList.set( nv );\n\n            if ( lexer.lookAhead(0) == ';' ) {\n                lexer.consume(1);\n            } else {\n                return nvList;\n            }\n        }\n\n    }\n\n    /**\n     * Parses the 'phone-context' parameter in tel: URLs\n     * @throws ParseException\n     */\n    private NameValue phone_context() throws ParseException {\n        lexer.match('=');\n\n        char la = lexer.lookAhead(0);\n        Object value;\n        if (la=='+') {// global-number-digits\n            lexer.consume(1);// skip '+'\n            value = \"+\" + base_phone_number();\n        } else if ( Lexer.isAlphaDigit(la) ) {\n            Token t = lexer.match( Lexer.ID );// more broad than allowed\n            value = t.getTokenValue();\n        } else {\n            throw new ParseException( \"Invalid phone-context:\" + la , -1 );\n        }\n        return new NameValue( \"phone-context\", value, false );\n    }\n\n    /**\n     * Parse and return a structure for a Tel URL.\n     * @return a parsed tel url structure.\n     */\n    public TelURLImpl telURL( boolean inBrackets ) throws ParseException {\n        lexer.match(TokenTypes.TEL);\n        lexer.match(':');\n        TelephoneNumber tn = this.parseTelephoneNumber(inBrackets);\n        TelURLImpl telUrl = new TelURLImpl();\n        telUrl.setTelephoneNumber(tn);\n        return telUrl;\n\n    }\n\n    /**\n     * Parse and return a structure for a SIP URL.\n     * @return a URL structure for a SIP url.\n     * @throws ParseException if there was a problem parsing.\n     */\n    public SipUri sipURL( boolean inBrackets ) throws ParseException {\n        if (debug)\n            dbg_enter(\"sipURL\");\n        SipUri retval = new SipUri();\n        // pmusgrave - handle sips case\n        Token nextToken = lexer.peekNextToken();\n        int sipOrSips = TokenTypes.SIP;\n        String scheme = TokenNames.SIP;\n        if ( nextToken.getTokenType() == TokenTypes.SIPS)\n        {\n            sipOrSips = TokenTypes.SIPS;\n            scheme = TokenNames.SIPS;\n        }\n\n        try {\n            lexer.match(sipOrSips);\n            lexer.match(':');\n            retval.setScheme(scheme);\n            int startOfUser = lexer.markInputPosition();\n            String userOrHost = user();// Note: user may contain ';', host may not...\n            String passOrPort = null;\n\n            // name:password or host:port\n            if ( lexer.lookAhead() == ':' ) {\n                lexer.consume(1);\n                passOrPort = password();\n            }\n\n            // name@hostPort\n            if ( lexer.lookAhead() == '@' ) {\n                lexer.consume(1);\n                retval.setUser( userOrHost );\n                if (passOrPort!=null) retval.setUserPassword( passOrPort );\n            } else {\n                // then userOrHost was a host, backtrack just in case a ';' was eaten...\n                lexer.rewindInputPosition( startOfUser );\n            }\n\n            HostNameParser hnp = new HostNameParser(this.getLexer());\n            HostPort hp = hnp.hostPort( false );\n            retval.setHostPort(hp);\n\n            lexer.selectLexer(\"charLexer\");\n            while (lexer.hasMoreChars()) {\n            \t// If the URI is not enclosed in brackets, parameters belong to header\n                if (lexer.lookAhead(0) != ';' || !inBrackets)\n                    break;\n                lexer.consume(1);\n                NameValue parms = uriParam();\n                if (parms != null) retval.setUriParameter(parms);\n            }\n\n            if (lexer.hasMoreChars() && lexer.lookAhead(0) == '?') {\n                lexer.consume(1);\n                while (lexer.hasMoreChars()) {\n                    NameValue parms = qheader();\n                    retval.setQHeader(parms);\n                    if (lexer.hasMoreChars() && lexer.lookAhead(0) != '&')\n                        break;\n                    else\n                        lexer.consume(1);\n                }\n            }\n            return retval;\n        } finally {\n            if (debug)\n                dbg_leave(\"sipURL\");\n        }\n    }\n\n    public String peekScheme() throws ParseException {\n        Token[] tokens = lexer.peekNextToken(1);\n        if (tokens.length == 0)\n            return null;\n        String scheme = ((Token) tokens[0]).getTokenValue();\n        return scheme;\n    }\n\n    /**\n     * Get a name value for a given query header (ie one that comes\n     * after the ?).\n     */\n    protected NameValue qheader() throws ParseException {\n        String name = lexer.getNextToken('=');\n        lexer.consume(1);\n        String value = hvalue();\n        return new NameValue(name, value, false);\n\n    }\n\n    protected String hvalue() throws ParseException {\n        StringBuffer retval = new StringBuffer();\n        while (lexer.hasMoreChars()) {\n            char la = lexer.lookAhead(0);\n            // Look for a character that can terminate a URL.\n            boolean isValidChar = false;\n            switch (la) {\n                case '+':\n                case '?':\n                case ':':\n                case '[':\n                case ']':\n                case '/':\n                case '$':\n                case '_':\n                case '-':\n                case '\"':\n                case '!':\n                case '~':\n                case '*':\n                case '.':\n                case '(':\n                case ')':\n                    isValidChar = true;\n            }\n            if (isValidChar || Lexer.isAlphaDigit(la)) {\n                lexer.consume(1);\n                retval.append(la);\n            } else if (la == '%') {\n                retval.append(escaped());\n            } else\n                break;\n        }\n        return retval.toString();\n    }\n\n    /**\n     * Scan forward until you hit a terminating character for a URL.\n     * We do not handle non sip urls in this implementation.\n     * @return the string that takes us to the end of this URL (i.e. to\n     * the next delimiter).\n     */\n    protected String urlString() throws ParseException {\n        StringBuffer retval = new StringBuffer();\n        lexer.selectLexer(\"charLexer\");\n\n        while (lexer.hasMoreChars()) {\n            char la = lexer.lookAhead(0);\n            // Look for a character that can terminate a URL.\n            if (la == ' '\n                || la == '\\t'\n                || la == '\\n'\n                || la == '>'\n                || la == '<')\n                break;\n            lexer.consume(0);\n            retval.append(la);\n        }\n        return retval.toString();\n    }\n\n    protected String user() throws ParseException {\n        if (debug)\n            dbg_enter(\"user\");\n        try {\n            int startIdx = lexer.getPtr();\n            while (lexer.hasMoreChars()) {\n                char la = lexer.lookAhead(0);\n                if (isUnreserved(la) || isUserUnreserved(la)) {\n                    lexer.consume(1);\n                } else if (isEscaped()) {\n                    lexer.consume(3);\n                } else\n                    break;\n            }\n            return lexer.getBuffer().substring(startIdx, lexer.getPtr());\n        } finally {\n            if (debug)\n                dbg_leave(\"user\");\n        }\n\n    }\n\n    protected String password() throws ParseException {\n        int startIdx = lexer.getPtr();\n        while (true) {\n            char la = lexer.lookAhead(0);\n            boolean isValidChar = false;\n            switch (la) {\n                case '&':\n                case '=':\n                case '+':\n                case '$':\n                case ',':\n                    isValidChar = true;\n            }\n            if (isValidChar || isUnreserved(la)) {\n                lexer.consume(1);\n            } else if (isEscaped()) {\n                lexer.consume(3); // bug reported by\n                                // Jeff Haynie\n            } else\n                break;\n\n        }\n        return lexer.getBuffer().substring(startIdx, lexer.getPtr());\n    }\n\n    /**\n     * Default parse method. This method just calls uriReference.\n     */\n    public GenericURI parse() throws ParseException {\n        return uriReference( true );\n    }\n\n    // quick test routine for debugging type assignment\n    public static void main(String[] args) throws ParseException\n    {\n        // quick test for sips parsing\n        String[] test = { \"sip:alice@example.com\",\n                    \"sips:alice@examples.com\" ,\n                    \"sip:3Zqkv5dajqaaas0tCjCxT0xH2ZEuEMsFl0xoasip%3A%2B3519116786244%40siplab.domain.com@213.0.115.163:7070\"};\n\n        for ( int i = 0; i < test.length; i++)\n        {\n            URLParser p  = new URLParser(test[i]);\n\n                GenericURI uri = p.parse();\n                System.out.println(\"uri type returned \" + uri.getClass().getName());\n                System.out.println(test[i] + \" is SipUri? \" + uri.isSipURI()\n                        + \">\" + uri.encode());\n        }\n    }\n\n    /**\n\n    **/\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/UnsupportedParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for Unsupported header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:07 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class UnsupportedParser extends HeaderParser {\n\n    /**\n     * Creates a new instance of UnsupportedParser\n     * @param unsupported - Unsupported header to parse\n     */\n    public UnsupportedParser(String unsupported) {\n        super(unsupported);\n    }\n\n    /**\n     * Constructor\n     * @param lexer - the lexer to use to parse the header\n     */\n    protected UnsupportedParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (Unsupported object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        UnsupportedList unsupportedList = new UnsupportedList();\n        if (debug)\n            dbg_enter(\"UnsupportedParser.parse\");\n\n        try {\n            headerName(TokenTypes.UNSUPPORTED);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                this.lexer.SPorHT();\n                Unsupported unsupported = new Unsupported();\n                unsupported.setHeaderName(SIPHeaderNames.UNSUPPORTED);\n\n                // Parsing the option tag\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                unsupported.setOptionTag(token.getTokenValue());\n                this.lexer.SPorHT();\n\n                unsupportedList.add(unsupported);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n\n                    unsupported = new Unsupported();\n\n                    // Parsing the option tag\n                    this.lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    unsupported.setOptionTag(token.getTokenValue());\n                    this.lexer.SPorHT();\n\n                    unsupportedList.add(unsupported);\n                }\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"UnsupportedParser.parse\");\n        }\n\n        return unsupportedList;\n    }\n\n    /**\n    public static void main(String args[]) throws ParseException {\n    String unsupported[] = {\n            \"Unsupported: foo \\n\",\n            \"Unsupported: foo1, foo2 ,foo3 , foo4\\n\"\n            };\n\n    for (int i = 0; i < unsupported.length; i++ ) {\n        UnsupportedParser parser =\n          new UnsupportedParser(unsupported[i]);\n        UnsupportedList u= (UnsupportedList) parser.parse();\n        System.out.println(\"encoded = \" + u.encode());\n    }\n\n    }\n    */\n}\n/*\n * $Log: UnsupportedParser.java,v $\n * Revision 1.7  2009/07/17 18:58:07  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:01:54  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/UserAgentParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for UserAgent header.\n *\n * @version 1.2 $Revision: 1.15 $ $Date: 2009/07/17 18:58:07 $\n *\n * @author Olivier Deruelle  <br/>\n * @author M. Ranganathan  <br/>\n *\n *\n */\npublic class UserAgentParser extends HeaderParser {\n\n    /**\n     * Constructor\n     *\n     * @param userAgent -\n     *            UserAgent header to parse\n     */\n    public UserAgentParser(String userAgent) {\n        super(userAgent);\n    }\n\n    /**\n     * Constructor\n     *\n     * @param lexer -\n     *            the lexer to use.\n     */\n    protected UserAgentParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the message. Note that we have losened up on the parsing quite a bit because\n     * user agents tend to be very bad about specifying the user agent according to RFC.\n     *\n     * @return SIPHeader (UserAgent object)\n     * @throws SIPParseException\n     *             if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"UserAgentParser.parse\");\n        UserAgent userAgent = new UserAgent();\n        try {\n            headerName(TokenTypes.USER_AGENT);\n            if (this.lexer.lookAhead(0) == '\\n')\n                throw createParseException(\"empty header\");\n\n            /*\n             * BNF User-Agent = \"User-Agent\" HCOLON server-val *(LWS server-val)\n             * server-val = product / comment product = token [SLASH\n             * product-version] product-version = token\n             */\n            while (this.lexer.lookAhead(0) != '\\n'\n                    && this.lexer.lookAhead(0) != '\\0') {\n\n                if (this.lexer.lookAhead(0) == '(') {\n                    String comment = this.lexer.comment();\n                    userAgent.addProductToken('(' + comment + ')');\n                } else {\n                    // product = token [SLASHproduct-version]\n                    // product-version = token\n                    // The RFC Does NOT allow this space but we are generous in what we accept\n\n                    this.getLexer().SPorHT();\n\n\n                    String product = this.lexer.byteStringNoSlash();\n                    if ( product == null ) throw createParseException(\"Expected product string\");\n\n                    StringBuffer productSb = new StringBuffer(product);\n                    // do we possibily have the optional product-version?\n                    if (this.lexer.peekNextToken().getTokenType() == TokenTypes.SLASH) {\n                        // yes\n                        this.lexer.match(TokenTypes.SLASH);\n                        // product-version\n                        // The RFC Does NOT allow this space but we are generous in what we accept\n                        this.getLexer().SPorHT();\n\n                        String productVersion = this.lexer.byteStringNoSlash();\n\n                        if ( productVersion == null ) throw createParseException(\"Expected product version\");\n\n                        productSb.append(\"/\");\n\n                        productSb.append(productVersion);\n                    }\n\n                    userAgent.addProductToken(productSb.toString());\n                }\n                // LWS\n                this.lexer.SPorHT();\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"UserAgentParser.parse\");\n        }\n\n        return userAgent;\n    }\n\n\n      public static void main(String args[]) throws ParseException { String\n      userAgent[] = { \"User-Agent: Softphone/Beta1.5 \\n\", \"User-Agent:Nist/Beta1 (beta version) \\n\", \"User-Agent: Nist UA (beta version)\\n\",\n      \"User-Agent: Nist1.0/Beta2 Ubi/vers.1.0 (very cool) \\n\" ,\n      \"User-Agent: SJphone/1.60.299a/L (SJ Labs)\\n\",\n      \"User-Agent: sipXecs/3.5.11 sipXecs/sipxbridge (Linux)\\n\"};\n\n      for (int i = 0; i < userAgent.length; i++ ) { UserAgentParser parser =\n      new UserAgentParser(userAgent[i]); UserAgent ua= (UserAgent)\n      parser.parse(); System.out.println(\"encoded = \" + ua.encode()); }\n       }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ViaParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\n/**\n * Parser for via headers.\n *\n * @version 1.2 $Revision: 1.12 $ $Date: 2009/07/17 18:58:07 $\n * @since 1.1\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n */\npublic class ViaParser extends HeaderParser {\n\n    public ViaParser(String via) {\n        super(via);\n    }\n\n    public ViaParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * a parser for the essential part of the via header.\n     */\n    private void parseVia(Via v) throws ParseException {\n        // The protocol\n        lexer.match(TokenTypes.ID);\n        Token protocolName = lexer.getNextToken();\n\n        this.lexer.SPorHT();\n        // consume the \"/\"\n        lexer.match('/');\n        this.lexer.SPorHT();\n        lexer.match(TokenTypes.ID);\n        this.lexer.SPorHT();\n        Token protocolVersion = lexer.getNextToken();\n\n        this.lexer.SPorHT();\n\n        // We consume the \"/\"\n        lexer.match('/');\n        this.lexer.SPorHT();\n        lexer.match(TokenTypes.ID);\n        this.lexer.SPorHT();\n\n        Token transport = lexer.getNextToken();\n        this.lexer.SPorHT();\n\n        Protocol protocol = new Protocol();\n        protocol.setProtocolName(protocolName.getTokenValue());\n        protocol.setProtocolVersion(protocolVersion.getTokenValue());\n        protocol.setTransport(transport.getTokenValue());\n        v.setSentProtocol(protocol);\n\n        // sent-By\n        HostNameParser hnp = new HostNameParser(this.getLexer());\n        HostPort hostPort = hnp.hostPort( true );\n        v.setSentBy(hostPort);\n\n        // Ignore blanks\n        this.lexer.SPorHT();\n\n        // parameters\n        while (lexer.lookAhead(0) == ';') {\n            this.lexer.consume(1);\n            this.lexer.SPorHT();\n            NameValue nameValue = this.nameValue();\n            String name = nameValue.getName();\n            if (name.equals(Via.BRANCH)) {\n                String branchId = (String) nameValue.getValueAsObject();\n                if (branchId == null)\n                    throw new ParseException(\"null branch Id\", lexer.getPtr());\n\n            }\n            v.setParameter(nameValue);\n            this.lexer.SPorHT();\n        }\n\n        //\n        // JvB Note: RFC3261 does not allow a comment in Via headers anymore\n        //\n        if (lexer.lookAhead(0) == '(') {\n            this.lexer.selectLexer(\"charLexer\");\n            lexer.consume(1);\n            StringBuffer comment = new StringBuffer();\n            while (true) {\n                char ch = lexer.lookAhead(0);\n                if (ch == ')') {\n                    lexer.consume(1);\n                    break;\n                } else if (ch == '\\\\') {\n                    // Escaped character\n                    Token tok = lexer.getNextToken();\n                    comment.append(tok.getTokenValue());\n                    lexer.consume(1);\n                    tok = lexer.getNextToken();\n                    comment.append(tok.getTokenValue());\n                    lexer.consume(1);\n                } else if (ch == '\\n') {\n                    break;\n                } else {\n                    comment.append(ch);\n                    lexer.consume(1);\n                }\n            }\n            v.setComment(comment.toString());\n        }\n\n    }\n\n    /**\n     * Overrides the superclass nameValue parser because we have to tolerate\n     * IPV6 addresses in the received parameter.\n     */\n    protected NameValue nameValue() throws ParseException {\n        if (debug)\n            dbg_enter(\"nameValue\");\n        try {\n\n            lexer.match(LexerCore.ID);\n            Token name = lexer.getNextToken();\n            // eat white space.\n            lexer.SPorHT();\n            try {\n\n                boolean quoted = false;\n\n                char la = lexer.lookAhead(0);\n\n                if (la == '=') {\n                    lexer.consume(1);\n                    lexer.SPorHT();\n                    String str = null;\n                    if (name.getTokenValue().compareToIgnoreCase(Via.RECEIVED) == 0) {\n                        // Allow for IPV6 Addresses.\n                        // these could have : in them!\n                        str = lexer.byteStringNoSemicolon();\n                    } else {\n                        if (lexer.lookAhead(0) == '\\\"') {\n                            str = lexer.quotedString();\n                            quoted = true;\n                        } else {\n                            lexer.match(LexerCore.ID);\n                            Token value = lexer.getNextToken();\n                            str = value.getTokenValue();\n                        }\n                    }\n                    NameValue nv = new NameValue(name.getTokenValue()\n                            .toLowerCase(), str);\n                    if (quoted)\n                        nv.setQuotedValue();\n                    return nv;\n                } else {\n                    return new NameValue(name.getTokenValue().toLowerCase(),\n                            null);\n                }\n            } catch (ParseException ex) {\n                return new NameValue(name.getTokenValue(), null);\n            }\n\n        } finally {\n            if (debug)\n                dbg_leave(\"nameValue\");\n        }\n\n    }\n\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            ViaList viaList = new ViaList();\n            // The first via header.\n            this.lexer.match(TokenTypes.VIA);\n            this.lexer.SPorHT(); // ignore blanks\n            this.lexer.match(':'); // expect a colon.\n            this.lexer.SPorHT(); // ingore blanks.\n\n            while (true) {\n                Via v = new Via();\n                parseVia(v);\n                viaList.add(v);\n                this.lexer.SPorHT(); // eat whitespace.\n                if (this.lexer.lookAhead(0) == ',') {\n                    this.lexer.consume(1); // Consume the comma\n                    this.lexer.SPorHT(); // Ignore space after.\n                }\n                if (this.lexer.lookAhead(0) == '\\n')\n                    break;\n            }\n            this.lexer.match('\\n');\n            return viaList;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n\n    }\n\n    /**\n     *\n     * public static void main(String args[]) throws ParseException { String\n     * via[] = { \"Via: SIP/2.0/UDP 135.180.130.133;branch=-12345\\n\", \"Via:\n     * SIP/2.0/UDP 166.34.120.100;branch=0000045d-00000001\"+ \",SIP/2.0/UDP\n     * 166.35.224.216:5000\\n\", \"Via: SIP/2.0/UDP sip33.example.com,\"+ \"\n     * SIP/2.0/UDP sip32.example.com (oli),\"+ \"SIP/2.0/UDP sip31.example.com\\n\",\n     * \"Via: SIP/2.0/UDP host.example.com;received=::133;\"+ \"\n     * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\\n\", \"Via:\n     * SIP/2.0/UDP host.example.com;received=135.180.130.133;\"+ \"\n     * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\\n\", \"Via:\n     * SIP/2.0/UDP company.com:5604 ( Hello )\"+ \", SIP / 2.0 / UDP\n     * 135.180.130.133\\n\", \"Via: SIP/2.0/UDP\n     * 129.6.55.9:7060;received=stinkbug.antd.nist.gov\\n\",\n     *\n     * \"Via: SIP/2.0/UDP ss2.wcom.com:5060;branch=721e418c4.1\"+ \", SIP/2.0/UDP\n     * ss1.wcom.com:5060;branch=2d4790.1\"+ \" , SIP/2.0/UDP here.com:5060( Hello\n     * the big world) \\n\" ,\"Via: SIP/2.0/UDP\n     * ss1.wcom.com:5060;branch=2d4790.1\\n\", \"Via: SIP/2.0/UDP\n     * first.example.com:4000;ttl=16\"+ \";maddr=224.2.0.1 ;branch=a7c6a8dlze.1\n     * (Acme server)\\n\" };\n     *\n     * for (int i = 0; i < via.length; i++ ) { ViaParser vp = new\n     * ViaParser(via[i]); System.out.println(\"toParse = \" + via[i]); ViaList vl =\n     * (ViaList) vp.parse(); System.out.println(\"encoded = \" + vl.encode()); }\n     *  }\n     *\n     */\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/WWWAuthenticateParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\n\n/**\n * Parser for WWW authenitcate header.\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:07 $\n *\n * @author Olivier Deruelle   <br/>\n * @author M. Ranganathan   <br/>\n *\n *\n */\npublic class WWWAuthenticateParser extends ChallengeParser {\n\n    /**\n     * Constructor\n     * @param wwwAuthenticate -  message to parse\n     */\n    public WWWAuthenticateParser(String wwwAuthenticate) {\n        super(wwwAuthenticate);\n    }\n\n    /**\n     * Cosntructor\n     * @param  lexer - lexer to use.\n     */\n    protected WWWAuthenticateParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (WWWAuthenticate object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.WWW_AUTHENTICATE);\n            WWWAuthenticate wwwAuthenticate = new WWWAuthenticate();\n            super.parse(wwwAuthenticate);\n            return wwwAuthenticate;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n}\n/*\n * $Log: WWWAuthenticateParser.java,v $\n * Revision 1.7  2009/07/17 18:58:07  emcho\n * Converts indentation tabs to spaces so that we have a uniform indentation policy in the whole project.\n *\n * Revision 1.6  2006/07/13 09:02:15  mranga\n * Issue number:\n * Obtained from:\n * Submitted by:  jeroen van bemmel\n * Reviewed by:   mranga\n * Moved some changes from jain-sip-1.2 to java.net\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n * Revision 1.3  2006/06/19 06:47:27  mranga\n * javadoc fixups\n *\n * Revision 1.2  2006/06/16 15:26:28  mranga\n * Added NIST disclaimer to all public domain files. Clean up some javadoc. Fixed a leak\n *\n * Revision 1.1.1.1  2005/10/04 17:12:36  mranga\n *\n * Import\n *\n *\n * Revision 1.4  2004/01/22 13:26:32  sverker\n * Issue number:\n * Obtained from:\n * Submitted by:  sverker\n * Reviewed by:   mranga\n *\n * Major reformat of code to conform with style guide. Resolved compiler and javadoc warnings. Added CVS tags.\n *\n * CVS: ----------------------------------------------------------------------\n * CVS: Issue number:\n * CVS:   If this change addresses one or more issues,\n * CVS:   then enter the issue number(s) here.\n * CVS: Obtained from:\n * CVS:   If this change has been taken from another system,\n * CVS:   then name the system in this line, otherwise delete it.\n * CVS: Submitted by:\n * CVS:   If this code has been contributed to the project by someone else; i.e.,\n * CVS:   they sent us a patch or a set of diffs, then include their name/email\n * CVS:   address here. If this is your work then delete this line.\n * CVS: Reviewed by:\n * CVS:   If we are doing pre-commit code reviews and someone else has\n * CVS:   reviewed your changes, include their name(s) here.\n * CVS:   If you have not had it reviewed then delete this line.\n *\n */\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/WarningParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.parser;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for Warning header.\n *\n * @version 1.2\n *\n * @author Olivier Deruelle\n * @author M. Ranganathan\n *\n *\n *\n * @version 1.0\n */\npublic class WarningParser extends HeaderParser {\n\n    /**\n     * Constructor\n     *\n     * @param warning -\n     *            Warning header to parse\n     */\n    public WarningParser(String warning) {\n        super(warning);\n    }\n\n    /**\n     * Cosntructor\n     *\n     * @param lexer -\n     *            the lexer to use.\n     */\n    protected WarningParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     *\n     * @return SIPHeader (WarningList object)\n     * @throws SIPParseException\n     *             if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        WarningList warningList = new WarningList();\n        if (debug)\n            dbg_enter(\"WarningParser.parse\");\n\n        try {\n            headerName(TokenTypes.WARNING);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                Warning warning = new Warning();\n                warning.setHeaderName(SIPHeaderNames.WARNING);\n\n                // Parsing the 3digits code\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                try {\n                    int code = Integer.parseInt(token.getTokenValue());\n                    warning.setCode(code);\n                } catch (NumberFormatException ex) {\n                    throw createParseException(ex.getMessage());\n                } catch (InvalidArgumentException ex) {\n                    throw createParseException(ex.getMessage());\n                }\n                this.lexer.SPorHT();\n\n                // Parsing the agent\n                this.lexer.match(TokenTypes.ID);\n                token = lexer.getNextToken();\n                // Bug reported by zvali@dev.java.net\n                if (lexer.lookAhead(0) == ':') {\n                    this.lexer.match(':');\n                    this.lexer.match(TokenTypes.ID);\n                    Token token2 = lexer.getNextToken();\n                    warning.setAgent(token.getTokenValue() + \":\"\n                            + token2.getTokenValue());\n                } else {\n                    warning.setAgent(token.getTokenValue());\n                }\n\n                this.lexer.SPorHT();\n\n                // Parsing the text\n                String text = this.lexer.quotedString();\n                warning.setText(text);\n                this.lexer.SPorHT();\n\n                warningList.add(warning);\n\n                while (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n\n                    warning = new Warning();\n\n                    // Parsing the 3digits code\n                    this.lexer.match(TokenTypes.ID);\n                    Token tok = lexer.getNextToken();\n                    try {\n                        int code = Integer.parseInt(tok.getTokenValue());\n                        warning.setCode(code);\n                    } catch (NumberFormatException ex) {\n                        throw createParseException(ex.getMessage());\n                    } catch (InvalidArgumentException ex) {\n                        throw createParseException(ex.getMessage());\n                    }\n                    this.lexer.SPorHT();\n\n                    // Parsing the agent\n                    this.lexer.match(TokenTypes.ID);\n                    tok = lexer.getNextToken();\n\n                    // Bug reported by zvali@dev.java.net\n\n                    if (lexer.lookAhead(0) == ':') {\n                        this.lexer.match(':');\n                        this.lexer.match(TokenTypes.ID);\n                        Token token2 = lexer.getNextToken();\n                        warning.setAgent(tok.getTokenValue() + \":\"\n                                + token2.getTokenValue());\n                    } else {\n                        warning.setAgent(tok.getTokenValue());\n                    }\n\n                    this.lexer.SPorHT();\n\n                    // Parsing the text\n                    text = this.lexer.quotedString();\n                    warning.setText(text);\n                    this.lexer.SPorHT();\n\n                    warningList.add(warning);\n                }\n\n            }\n        } finally {\n            if (debug)\n                dbg_leave(\"WarningParser.parse\");\n        }\n\n        return warningList;\n    }\n\n    /**\n     * public static void main(String args[]) throws ParseException { String\n     * warning[] = { \"Warning: 307 isi.edu \\\"Session parameter 'foo' not\n     * understood\\\"\\n\", \"Warning: 301 isi.edu \\\"Incompatible network address\n     * type 'E.164'\\\"\\n\", \"Warning: 312 ii.edu \\\"Soda\\\", \"+ \" 351 i.edu \\\"I\n     * network address 'E.164'\\\" , 323 ii.edu \\\"Sodwea\\\"\\n\", \"Warning: 392\n     * 192.168.89.71:5060 \\\"Noisy feedback tells: pid=936\n     * req_src_ip=192.168.89.20 in_uri=sip:xxx@yyyy.org:5061\n     * out_uri=sip:xxx@yyyy.org:5061 via_cnt==1\\\"\\n\" };\n     *\n     * for (int i = 0; i < warning.length; i++ ) { WarningParser parser = new\n     * WarningParser(warning[i]); WarningList warningList= (WarningList)\n     * parser.parse(); System.out.println(\"encoded = \" + warningList.encode()); }\n     *  }\n     */\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/extensions/JoinParser.java",
    "content": "package gov2.nist.javax2.sip.parser.extensions;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.text.ParseException;\n\n// Parser for Join Header (RFC3911)\n// Extension by jean deruelle\n//\n// Join        = \"Join\" HCOLON callid *(SEMI join-param)\n// join-param  = to-tag / from-tag / generic-param\n// to-tag          = \"to-tag\" EQUAL token\n// from-tag        = \"from-tag\" EQUAL token\n//\n//\n\npublic class JoinParser extends ParametersParser {\n\n    /**\n     * Creates new CallIDParser\n     * @param callID message to parse\n     */\n    public JoinParser(String callID) {\n        super(callID);\n    }\n\n    /**\n     * Constructor\n     * @param lexer Lexer to set\n     */\n    protected JoinParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (CallID object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.JOIN_TO);\n\n            Join join = new Join();\n            this.lexer.SPorHT();\n            String callId = lexer.byteStringNoSemicolon();\n            this.lexer.SPorHT();\n            super.parse(join);\n            join.setCallId(callId);\n            return join;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String to[] =\n            {   \"Join: 12345th5z8z\\n\",\n                \"Join: 12345th5z8z;to-tag=tozght6-45;from-tag=fromzght789-337-2\\n\",\n            };\n\n        for (int i = 0; i < to.length; i++) {\n            JoinParser tp = new JoinParser(to[i]);\n            Join t = (Join) tp.parse();\n            System.out.println(\"Parsing => \" + to[i]);\n            System.out.print(\"encoded = \" + t.encode() + \"==> \");\n            System.out.println(\"callId \" + t.getCallId() + \" from-tag=\" + t.getFromTag()\n                    + \" to-tag=\" + t.getToTag()) ;\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/extensions/MinSEParser.java",
    "content": "package gov2.nist.javax2.sip.parser.extensions;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for SIP MinSE Parser.\n *\n *    Min-SE  =  \"Min-SE\" HCOLON delta-seconds *(SEMI generic-param)\n *\n * @author P. Musgrave <pmusgrave@newheights.com>\n *\n * <a href=\"{@docRoot}/uncopyright.html\">This code is in the public domain.</a>\n */\npublic class MinSEParser extends ParametersParser {\n\n    /**\n     * protected constructor.\n     * @param text is the text of the header to parse\n     */\n    public MinSEParser(String text) {\n        super(text);\n    }\n\n    /**\n     * constructor.\n     * @param lexer is the lexer passed in from the enclosing parser.\n     */\n    protected MinSEParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * Parse the header.\n     */\n    public SIPHeader parse() throws ParseException {\n        MinSE minse = new MinSE();\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.MINSE_TO);\n\n            String nextId = lexer.getNextId();\n            try {\n                int delta = Integer.parseInt(nextId);\n                minse.setExpires(delta);\n            } catch (NumberFormatException ex) {\n                throw createParseException(\"bad integer format\");\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n            this.lexer.SPorHT();\n            super.parse(minse);\n            return minse;\n\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String to[] =\n            {   \"Min-SE: 30\\n\",\n                \"Min-SE: 45;some-param=somevalue\\n\",\n            };\n\n        for (int i = 0; i < to.length; i++) {\n            MinSEParser tp = new MinSEParser(to[i]);\n            MinSE t = (MinSE) tp.parse();\n            System.out.println(\"encoded = \" + t.encode());\n            System.out.println(\"\\ntime=\" + t.getExpires() );\n            if ( t.getParameter(\"some-param\") != null)\n                System.out.println(\"some-param=\" + t.getParameter(\"some-param\") );\n\n        }\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/extensions/ReferencesParser.java",
    "content": "package gov2.nist.javax2.sip.parser.extensions;\n\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.Reason;\nimport gov2.nist.javax2.sip.header.ReasonList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.extensions.References;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\nimport java.text.ParseException;\n\npublic class ReferencesParser extends ParametersParser {\n    /**\n     * Creates a new instance of ReferencesParser\n     * @param references the header to parse\n     */\n    public ReferencesParser(String references) {\n        super(references);\n    }\n\n    /**\n     * Constructor\n     * @param lexer the lexer to use to parse the header\n     */\n    protected ReferencesParser(Lexer lexer) {\n        super(lexer);\n    }\n    \n    /**\n     * parse the String message\n     * @return SIPHeader (ReasonParserList object)\n     * @throws SIPParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n       \n        if (debug)\n            dbg_enter(\"ReasonParser.parse\");\n\n        try {\n            headerName(TokenTypes.REFERENCES);\n            References references= new References();\n            this.lexer.SPorHT();\n               \n            String callId = lexer.byteStringNoSemicolon();\n           \n            references.setCallId(callId);\n            super.parse(references);\n            return references;\n       } finally {\n            if (debug)\n                dbg_leave(\"ReferencesParser.parse\");\n        }\n\n      \n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/extensions/ReferredByParser.java",
    "content": "package gov2.nist.javax2.sip.parser.extensions;\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.parser.*;\n\n\n/**\n * ReferredBy Header parser.\n *\n * <a href=\"{@docRoot}/uncopyright.html\">This code is in the public domain.</a>\n *\n * Based on JAIN ReferToParser\n *\n */\npublic class ReferredByParser extends AddressParametersParser {\n\n    /**\n     * Creates new ToParser\n     * @param referBy String to set\n     */\n    public ReferredByParser(String referBy) {\n        super(referBy);\n    }\n\n    protected ReferredByParser(Lexer lexer) {\n        super(lexer);\n    }\n    public SIPHeader parse() throws ParseException {\n\n        headerName(TokenTypes.REFERREDBY_TO);\n        ReferredBy referBy = new ReferredBy();\n        super.parse(referBy);\n        this.lexer.match('\\n');\n        return referBy;\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String to[] =\n            {   \"Referred-By: <sip:dave@denver.example.org?\" +\n                    \"Replaces=12345%40192.168.118.3%3Bto-tag%3D12345%3Bfrom-tag%3D5FFE-3994>\\n\",\n                \"Referred-By: <sip:+1-650-555-2222@ss1.wcom.com;user=phone>;tag=5617\\n\",\n                \"Referred-By: T. A. Watson <sip:watson@bell-telephone.com>\\n\",\n                \"Referred-By: LittleGuy <sip:UserB@there.com>\\n\",\n                \"Referred-By: sip:mranga@120.6.55.9\\n\",\n                \"Referred-By: sip:mranga@129.6.55.9 ; tag=696928473514.129.6.55.9\\n\" };\n\n        for (int i = 0; i < to.length; i++) {\n            ReferredByParser tp = new ReferredByParser(to[i]);\n            ReferredBy t = (ReferredBy) tp.parse();\n            System.out.println(\"encoded = \" + t.encode());\n\n        }\n    }\n}\n/*\n * $Log:\n *\n */\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/extensions/ReplacesParser.java",
    "content": "package gov2.nist.javax2.sip.parser.extensions;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.text.ParseException;\n\n// Parser for Replaces Header (RFC3891)\n// Extension by pmusgrave\n//\n// Replaces        = \"Replaces\" HCOLON callid *(SEMI replaces-param)\n// replaces-param  = to-tag / from-tag / early-flag / generic-param\n// to-tag          = \"to-tag\" EQUAL token\n// from-tag        = \"from-tag\" EQUAL token\n// early-flag      = \"early-only\"\n//\n// TODO Should run a test case on early-only\n//\n\npublic class ReplacesParser extends ParametersParser {\n\n    /**\n     * Creates new CallIDParser\n     * @param callID message to parse\n     */\n    public ReplacesParser(String callID) {\n        super(callID);\n    }\n\n    /**\n     * Constructor\n     * @param lexer Lexer to set\n     */\n    protected ReplacesParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * parse the String message\n     * @return SIPHeader (CallID object)\n     * @throws ParseException if the message does not respect the spec.\n     */\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.REPLACES_TO);\n\n            Replaces replaces = new Replaces();\n            this.lexer.SPorHT();\n            String callId = lexer.byteStringNoSemicolon();\n            this.lexer.SPorHT();\n            super.parse(replaces);\n            replaces.setCallId(callId);\n            return replaces;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String to[] =\n            {   \"Replaces: 12345th5z8z\\n\",\n                \"Replaces: 12345th5z8z;to-tag=tozght6-45;from-tag=fromzght789-337-2\\n\",\n            };\n\n        for (int i = 0; i < to.length; i++) {\n            ReplacesParser tp = new ReplacesParser(to[i]);\n            Replaces t = (Replaces) tp.parse();\n            System.out.println(\"Parsing => \" + to[i]);\n            System.out.print(\"encoded = \" + t.encode() + \"==> \");\n            System.out.println(\"callId \" + t.getCallId() + \" from-tag=\" + t.getFromTag()\n                    + \" to-tag=\" + t.getToTag()) ;\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/extensions/SessionExpiresParser.java",
    "content": "package gov2.nist.javax2.sip.parser.extensions;\n\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.header.extensions.*;\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.text.ParseException;\n\nimport javax2.sip.*;\n\n/**\n * Parser for SIP Session Expires Header.\n *\n *\n */\npublic class SessionExpiresParser extends ParametersParser {\n\n    /**\n     * protected constructor.\n     * @param text is the text of the header to parse\n     */\n    public SessionExpiresParser(String text) {\n        super(text);\n    }\n\n    /**\n     * constructor.\n     * @param lexer is the lexer passed in from the enclosing parser.\n     */\n    protected SessionExpiresParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    /**\n     * Parse the header.\n     */\n    public SIPHeader parse() throws ParseException {\n        SessionExpires se = new SessionExpires();\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.SESSIONEXPIRES_TO);\n\n            String nextId = lexer.getNextId();\n\n            try {\n                int delta = Integer.parseInt(nextId);\n                se.setExpires(delta);\n            } catch (NumberFormatException ex) {\n                throw createParseException(\"bad integer format\");\n            } catch (InvalidArgumentException ex) {\n                throw createParseException(ex.getMessage());\n            }\n            // May have parameters...\n            this.lexer.SPorHT();\n            super.parse(se);\n            return se;\n\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n\n    }\n\n    public static void main(String args[]) throws ParseException {\n        String to[] =\n            {   \"Session-Expires: 30\\n\",\n                \"Session-Expires: 45;refresher=uac\\n\",\n            };\n\n        for (int i = 0; i < to.length; i++) {\n            SessionExpiresParser tp = new SessionExpiresParser(to[i]);\n            SessionExpires t = (SessionExpires) tp.parse();\n            System.out.println(\"encoded = \" + t.encode());\n            System.out.println(\"\\ntime=\" + t.getExpires() );\n            if ( t.getParameter(\"refresher\") != null)\n                System.out.println(\"refresher=\" + t.getParameter(\"refresher\") );\n\n        }\n    }\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/AddressHeaderParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.ims.AddressHeaderIms;\nimport gov2.nist.javax2.sip.parser.AddressParser;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\nabstract class AddressHeaderParser extends HeaderParser {\n\n\n    protected AddressHeaderParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    protected AddressHeaderParser(String buffer) {\n        super(buffer);\n    }\n\n    protected void parse(AddressHeaderIms addressHeader)\n        throws ParseException {\n        dbg_enter(\"AddressHeaderParser.parse\");\n        try {\n            AddressParser addressParser = new AddressParser(this.getLexer());\n            AddressImpl addr = addressParser.address(true);\n            addressHeader.setAddress(addr);\n\n\n        } catch (ParseException ex) {\n            throw ex;\n        } finally {\n            dbg_leave(\"AddressParametersParser.parse\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PAccessNetworkInfoParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PAccessNetworkInfo;\nimport gov2.nist.javax2.sip.header.ims.SIPHeaderNamesIms;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n\n/**\n * P-Access-Network-Info header parser.\n *\n * <p>RFC 3455 - Private Header (P-Header) Extensions to the Session Initiation\n *   Protocol (SIP) for the 3rd-Generation Partnership Project (3GPP) </p>\n *\n * <p>Sintax (RFC 3455):</p>\n * <pre>\n * P-Access-Network-Info  = \"P-Access-Network-Info\" HCOLON access-net-spec\n * access-net-spec        = access-type *(SEMI access-info)\n * access-type            = \"IEEE-802.11a\" / \"IEEE-802.11b\" /\n *                          \"3GPP-GERAN\" / \"3GPP-UTRAN-FDD\" /\n *                          \"3GPP-UTRAN-TDD\" / \"3GPP-CDMA2000\" / token\n * access-info            = cgi-3gpp / utran-cell-id-3gpp / extension-access-info\n * extension-access-info  = gen-value\n * cgi-3gpp               = \"cgi-3gpp\" EQUAL (token / quoted-string)\n * utran-cell-id-3gpp     = \"utran-cell-id-3gpp\" EQUAL (token / quoted-string)\n * </pre>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic class PAccessNetworkInfoParser\n    extends HeaderParser\n    implements TokenTypes\n{\n\n    public PAccessNetworkInfoParser(String accessNetwork) {\n\n        super(accessNetwork);\n\n    }\n\n\n    protected PAccessNetworkInfoParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n\n        if (debug)\n            dbg_enter(\"AccessNetworkInfoParser.parse\");\n        try {\n            headerName(TokenTypes.P_ACCESS_NETWORK_INFO);\n            PAccessNetworkInfo accessNetworkInfo = new PAccessNetworkInfo();\n            accessNetworkInfo.setHeaderName(SIPHeaderNamesIms.P_ACCESS_NETWORK_INFO);\n\n            this.lexer.SPorHT();\n            lexer.match(TokenTypes.ID);\n            Token token = lexer.getNextToken();\n            accessNetworkInfo.setAccessType(token.getTokenValue());\n\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) == ';') {\n                this.lexer.match(';');\n                this.lexer.SPorHT();\n\n                NameValue nv = super.nameValue('=');\n                accessNetworkInfo.setParameter(nv);\n                this.lexer.SPorHT();\n            }\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n\n            return accessNetworkInfo;\n        } finally {\n            if (debug)\n                dbg_leave(\"AccessNetworkInfoParser.parse\");\n        }\n\n    }\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PAssertedIdentityParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n\nimport java.text.ParseException;\n\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PAssertedIdentity;\nimport gov2.nist.javax2.sip.header.ims.PAssertedIdentityList;\nimport gov2.nist.javax2.sip.header.ims.SIPHeaderNamesIms;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\npublic class PAssertedIdentityParser\n    extends AddressParametersParser\n    implements TokenTypes{\n\n    /**\n     * Constructor\n     * @param assertedIdentity -  message to parse to set\n     */\n    public PAssertedIdentityParser(String assertedIdentity) {\n        super(assertedIdentity);\n\n    }\n\n    protected PAssertedIdentityParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"AssertedIdentityParser.parse\");\n\n        PAssertedIdentityList assertedIdList = new PAssertedIdentityList();\n\n        try {\n\n            headerName(TokenTypes.P_ASSERTED_IDENTITY);\n\n            PAssertedIdentity pai = new PAssertedIdentity();\n            pai.setHeaderName(SIPHeaderNamesIms.P_ASSERTED_IDENTITY);\n\n            super.parse(pai);\n            assertedIdList.add(pai);\n\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) == ',')\n            {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n\n                pai = new PAssertedIdentity();\n                super.parse(pai);\n                assertedIdList.add(pai);\n\n                this.lexer.SPorHT();\n            }\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return assertedIdList;\n\n        }\n\n        finally {\n            if (debug)\n                dbg_leave(\"AssertedIdentityParser.parse\");\n            }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PAssertedServiceParser.java",
    "content": "package gov2.nist.javax2.sip.parser.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PAssertedService;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * Parse this:\n * P-Asserted-Service: urn:urn-7:3gpp-service.exampletelephony.version1\n *\n */\npublic class PAssertedServiceParser extends HeaderParser implements TokenTypes{\n\n    protected PAssertedServiceParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public PAssertedServiceParser(String pas)\n    {\n        super(pas);\n    }\n\n    public SIPHeader parse() throws ParseException {\n        if(debug)\n            dbg_enter(\"PAssertedServiceParser.parse\");\n        try\n        {\n        this.lexer.match(TokenTypes.P_ASSERTED_SERVICE);\n        this.lexer.SPorHT();\n        this.lexer.match(':');\n        this.lexer.SPorHT();\n\n        PAssertedService pps = new PAssertedService();\n        String urn = this.lexer.getBuffer();\n        if(urn.contains(ParameterNamesIms.SERVICE_ID)){\n\n           if(urn.contains(ParameterNamesIms.SERVICE_ID_LABEL))\n                   {\n                    String serviceID = urn.split(ParameterNamesIms.SERVICE_ID_LABEL+\".\")[1];\n\n                     if(serviceID.trim().equals(\"\"))\n                        try {\n                            throw new InvalidArgumentException(\"URN should atleast have one sub-service\");\n                        } catch (InvalidArgumentException e) {\n\n                            e.printStackTrace();\n                        }\n                        else\n                    pps.setSubserviceIdentifiers(urn.split(ParameterNamesIms.SERVICE_ID_LABEL)[1]);\n                   }\n           else if(urn.contains(ParameterNamesIms.APPLICATION_ID_LABEL))\n              {\n               String appID = urn.split(ParameterNamesIms.APPLICATION_ID_LABEL+\".\")[1];\n               if(appID.trim().equals(\"\"))\n                    try {\n                        throw new InvalidArgumentException(\"URN should atleast have one sub-application\");\n                    } catch (InvalidArgumentException e) {\n                        e.printStackTrace();\n                    }\n                    else\n                  pps.setApplicationIdentifiers(urn.split(ParameterNamesIms.APPLICATION_ID_LABEL)[1]);\n              }\n           else\n           {\n               try {\n                throw new InvalidArgumentException(\"URN is not well formed\");\n\n            } catch (InvalidArgumentException e) {\n                e.printStackTrace();\n                    }\n                  }\n          }\n\n            super.parse();\n            return pps;\n        }\n        finally{\n            if(debug)\n                dbg_enter(\"PAssertedServiceParser.parse\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PAssociatedURIParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) *\n ****************************************************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport java.text.ParseException;\n\n\n\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.address.GenericURI;\nimport gov2.nist.javax2.sip.header.Allow;\nimport gov2.nist.javax2.sip.header.ErrorInfo;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.SIPHeaderNames;\nimport gov2.nist.javax2.sip.header.ims.PAssociatedURI;\nimport gov2.nist.javax2.sip.header.ims.PAssociatedURIList;\nimport gov2.nist.javax2.sip.header.ims.SIPHeaderNamesIms;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\nimport gov2.nist.javax2.sip.parser.URLParser;\n\n\n/**\n * P-Associated-URI header parser\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic class PAssociatedURIParser\n    extends AddressParametersParser\n{\n\n\n    /**\n     * Constructor\n     * @param associatedURI content to set\n     */\n    public PAssociatedURIParser(String associatedURI)\n    {\n        super(associatedURI);\n    }\n\n    protected PAssociatedURIParser(Lexer lexer)\n    {\n        super(lexer);\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n        if (debug)\n            dbg_enter(\"PAssociatedURIParser.parse\");\n\n        PAssociatedURIList associatedURIList = new PAssociatedURIList();\n\n        try {\n\n            headerName(TokenTypes.P_ASSOCIATED_URI);\n\n            PAssociatedURI associatedURI = new PAssociatedURI();\n            associatedURI.setHeaderName(SIPHeaderNamesIms.P_ASSOCIATED_URI);\n\n            super.parse(associatedURI);\n            associatedURIList.add(associatedURI);\n\n            this.lexer.SPorHT();\n            while (lexer.lookAhead(0) == ',')\n            {\n                this.lexer.match(',');\n                this.lexer.SPorHT();\n\n                associatedURI = new PAssociatedURI();\n                super.parse(associatedURI);\n                associatedURIList.add(associatedURI);\n\n                this.lexer.SPorHT();\n            }\n            this.lexer.SPorHT();\n            this.lexer.match('\\n');\n\n            return associatedURIList;\n\n\n\n\n        } finally {\n            if (debug)\n                dbg_leave(\"PAssociatedURIParser.parse\");\n        }\n\n    }\n\n\n\n\n\n    /** Test program\n    public static void main(String args[]) throws ParseException\n    {\n        String rou[] = {\n\n                \"P-Associated-URI: <sip:123qwe@ptinovacao.pt>\\n\",\n\n                    \"P-Associated-URI: <sip:testes1@ptinovacao.pt>,  \" +\n                                    \"<sip:testes2@ptinovacao.pt> \\n\"\n                    };\n\n        for (int i = 0; i < rou.length; i++ ) {\n            PAssociatedURIParser rp =\n              new PAssociatedURIParser(rou[i]);\n            PAssociatedURIList list = (PAssociatedURIList) rp.parse();\n            System.out.println(\"encoded = \" +list.encode());\n        }\n    }\n\n    */\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PCalledPartyIDParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/****************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University (Portugal) *\n ****************************************************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PCalledPartyID;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n * P-Called-Party-ID header parser\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic class PCalledPartyIDParser\n    extends AddressParametersParser\n{\n\n\n    /**\n     * Constructor\n     * @param calledPartyID content to set\n     */\n    public PCalledPartyIDParser(String calledPartyID)\n    {\n        super(calledPartyID);\n    }\n\n    protected PCalledPartyIDParser(Lexer lexer)\n    {\n        super(lexer);\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n\n        if (debug)\n            dbg_enter(\"PCalledPartyIDParser.parse\");\n\n        try {\n            this.lexer.match(TokenTypes.P_CALLED_PARTY_ID);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n\n            PCalledPartyID calledPartyID = new PCalledPartyID();\n            super.parse(calledPartyID);\n\n            return calledPartyID;\n\n        } finally {\n            if (debug)\n                dbg_leave(\"PCalledPartyIDParser.parse\");\n        }\n\n    }\n\n\n\n\n    /** Test program\n    public static void main(String args[]) throws ParseException\n    {\n        String rou[] = {\n                    \"P-Associated-URI: <sip:testes1@ptinovacao.pt>,  \" +\n                                    \"<sip:testes2@ptinovacao.pt> \\n\"\n                    };\n\n        for (int i = 0; i < rou.length; i++ ) {\n            RecordRouteParser rp =\n              new RecordRouteParser(rou[i]);\n            RecordRouteList recordRouteList = (RecordRouteList) rp.parse();\n            System.out.println(\"encoded = \" +recordRouteList.encode());\n        }\n    }\n    */\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PChargingFunctionAddressesParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PChargingFunctionAddresses;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\nimport java.text.ParseException;\n\n\n/**\n * P-Charging-Function-Addresses header parser.\n *\n * <p>Sintax (RFC 3455):</p>\n * <pre>\n * P-Charging-Addr    = \"P-Charging-Function-Addresses\" HCOLON\n *                      charge-addr-params\n *                      * (SEMI charge-addr-params)\n * charge-addr-params = ccf / ecf / generic-param\n * ccf                = \"ccf\" EQUAL gen-value\n * ecf                = \"ecf\" EQUAL gen-value\n * gen-value          = token / host / quoted-string\n * host               = hostname / IPv4address / IPv6reference\n * hostname           = *( domainlabel \".\" ) toplabel [ \".\" ]\n * domainlabel        = alphanum / alphanum *( alphanum / \"-\" ) alphanum\n * toplabel           = ALPHA / ALPHA *( alphanum / \"-\" ) alphanum\n * ipv6reference      = \"[\" IPv6address \"]\"\n *\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n * @author aayush.bhatnagar: proposed change to allow duplicate ecf and ccf header parameters.\n */\n\npublic class PChargingFunctionAddressesParser\n    extends ParametersParser\n    implements TokenTypes {\n\n\n    public PChargingFunctionAddressesParser(String charging) {\n\n        super(charging);\n\n\n    }\n\n\n    protected PChargingFunctionAddressesParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n\n\n    public SIPHeader parse() throws ParseException {\n\n\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.P_CHARGING_FUNCTION_ADDRESSES);\n            PChargingFunctionAddresses chargingFunctionAddresses = new PChargingFunctionAddresses();\n\n            try {\n                while (lexer.lookAhead(0) != '\\n') {\n\n                    this.parseParameter(chargingFunctionAddresses);\n                    this.lexer.SPorHT();\n                    char la = lexer.lookAhead(0);\n                    if (la == '\\n' || la == '\\0')\n                        break;\n\n                    this.lexer.match(';');\n                    this.lexer.SPorHT();\n                }\n            } catch (ParseException ex) {\n                throw ex;\n            }\n\n\n            super.parse(chargingFunctionAddresses);\n            return chargingFunctionAddresses;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n    protected void parseParameter(PChargingFunctionAddresses chargingFunctionAddresses) throws ParseException {\n\n        if (debug)\n            dbg_enter(\"parseParameter\");\n        try {\n\n            NameValue nv = this.nameValue('=');\n             \n            //chargingFunctionAddresses.setParameter(nv);\n            chargingFunctionAddresses.setMultiParameter(nv);\n\n        } finally {\n            if (debug)\n                dbg_leave(\"parseParameter\");\n        }\n\n\n\n    }\n\n\n\n\n\n\n    /** Test program */\n\n    public static void main(String args[]) throws ParseException {\n        String r[] = {\n                \"P-Charging-Function-Addresses: ccf=\\\"test str\\\"; ecf=token\\n\",\n                \"P-Charging-Function-Addresses: ccf=192.1.1.1; ccf=192.1.1.2; ecf=192.1.1.3; ecf=192.1.1.4\\n\",\n                \"P-Charging-Function-Addresses: ccf=[5555::b99:c88:d77:e66]; ccf=[5555::a55:b44:c33:d22]; \" +\n                     \"ecf=[5555::1ff:2ee:3dd:4cc]; ecf=[5555::6aa:7bb:8cc:9dd]\\n\"\n\n                };\n\n\n        for (int i = 0; i < r.length; i++ )\n        {\n\n            PChargingFunctionAddressesParser parser =\n              new PChargingFunctionAddressesParser(r[i]);\n\n            System.out.println(\"original = \" + r[i]);\n\n            PChargingFunctionAddresses chargAddr= (PChargingFunctionAddresses) parser.parse();\n            System.out.println(\"encoded = \" + chargAddr.encode());\n        }\n\n\n    }\n\n\n\n\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PChargingVectorParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PChargingVector;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\nimport java.text.ParseException;\n\n/**\n * P-Charging-Vector header parser.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\npublic class PChargingVectorParser\nextends ParametersParser implements TokenTypes {\n\n    public PChargingVectorParser(String chargingVector) {\n\n        super(chargingVector);\n\n    }\n\n    protected PChargingVectorParser(Lexer lexer) {\n\n        super(lexer);\n\n    }\n\n\n\n    public SIPHeader parse() throws ParseException {\n\n\n        if (debug)\n            dbg_enter(\"parse\");\n        try {\n            headerName(TokenTypes.P_VECTOR_CHARGING);\n            PChargingVector chargingVector = new PChargingVector();\n\n            try {\n                while (lexer.lookAhead(0) != '\\n') {\n                    this.parseParameter(chargingVector);\n                    this.lexer.SPorHT();\n                    char la = lexer.lookAhead(0);\n                    if (la == '\\n' || la == '\\0')\n                        break;\n                    this.lexer.match(';');\n                    this.lexer.SPorHT();\n                }\n\n            } catch (ParseException ex) {\n                throw ex;\n            }\n\n\n            super.parse(chargingVector);\n            if ( chargingVector.getParameter(ParameterNamesIms.ICID_VALUE) == null )\n                throw new ParseException(\"Missing a required Parameter : \" + ParameterNamesIms.ICID_VALUE, 0);\n            return chargingVector;\n        } finally {\n            if (debug)\n                dbg_leave(\"parse\");\n        }\n    }\n\n    protected void parseParameter(PChargingVector chargingVector) throws ParseException {\n\n        if (debug)\n            dbg_enter(\"parseParameter\");\n        try {\n            NameValue nv = this.nameValue('=');\n            chargingVector.setParameter(nv);\n        } finally {\n            if (debug)\n                dbg_leave(\"parseParameter\");\n        }\n\n\n\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PMediaAuthorizationParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PMediaAuthorization;\nimport gov2.nist.javax2.sip.header.ims.PMediaAuthorizationList;\nimport gov2.nist.javax2.sip.header.ims.SIPHeaderNamesIms;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n\n/**\n * P-Media-Authorization header parser.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\npublic class PMediaAuthorizationParser\n    extends HeaderParser\n    implements TokenTypes\n{\n\n    public PMediaAuthorizationParser(String mediaAuthorization)\n    {\n        super(mediaAuthorization);\n\n    }\n\n    public PMediaAuthorizationParser(Lexer lexer)\n    {\n        super(lexer);\n\n    }\n\n\n\n\n\n    public SIPHeader parse() throws ParseException\n    {\n        PMediaAuthorizationList mediaAuthorizationList = new PMediaAuthorizationList();\n\n        if (debug)\n            dbg_enter(\"MediaAuthorizationParser.parse\");\n\n\n        try\n        {\n            headerName(TokenTypes.P_MEDIA_AUTHORIZATION);\n\n            PMediaAuthorization mediaAuthorization = new PMediaAuthorization();\n            mediaAuthorization.setHeaderName(SIPHeaderNamesIms.P_MEDIA_AUTHORIZATION);\n\n            while (lexer.lookAhead(0) != '\\n')\n            {\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                try {\n                    mediaAuthorization.setMediaAuthorizationToken(token.getTokenValue());\n                } catch (InvalidArgumentException e) {\n                    throw createParseException(e.getMessage());\n                }\n                mediaAuthorizationList.add(mediaAuthorization);\n\n                this.lexer.SPorHT();\n                if (lexer.lookAhead(0) == ',')\n                {\n                    this.lexer.match(',');\n                    mediaAuthorization = new PMediaAuthorization();\n                }\n                this.lexer.SPorHT();\n            }\n\n            return mediaAuthorizationList;\n\n        }\n        finally\n        {\n            if (debug)\n                dbg_leave(\"MediaAuthorizationParser.parse\");\n        }\n\n    }\n\n\n\n\n    /*\n     * test\n     *\n    public static void main(String args[]) throws ParseException\n    {\n        String pHeader[] = {\n            \"P-Media-Authorization: 0123456789 \\n\",\n            \"P-Media-Authorization: 0123456789, ABCDEF\\n\"\n            };\n\n        for (int i = 0; i < pHeader.length; i++ )\n        {\n            PMediaAuthorizationParser mParser =\n                new PMediaAuthorizationParser(pHeader[i]);\n\n            PMediaAuthorizationList mList= (PMediaAuthorizationList) mParser.parse();\n            System.out.println(\"encoded = \" + mList.encode());\n        }\n    }\n     */\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PPreferredIdentityParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport java.text.ParseException;\n\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PPreferredIdentity;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n * P-Preferred-Identity header parser.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\npublic class PPreferredIdentityParser\n    //extends AddressHeaderParser\n    extends AddressParametersParser\n    implements TokenTypes {\n\n    public PPreferredIdentityParser(String preferredIdentity) {\n        super(preferredIdentity);\n\n    }\n\n\n    protected PPreferredIdentityParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"PreferredIdentityParser.parse\");\n\n        try {\n            this.lexer.match(TokenTypes.P_PREFERRED_IDENTITY);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n\n            PPreferredIdentity p = new PPreferredIdentity();\n            super.parse( p );\n            return p;\n        } finally {\n            if (debug)\n                dbg_leave(\"PreferredIdentityParser.parse\");\n            }\n\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PPreferredServiceParser.java",
    "content": "package gov2.nist.javax2.sip.parser.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PPreferredService;\nimport gov2.nist.javax2.sip.header.ims.ParameterNamesIms;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * Parse this:\n * P-Preferred-Service: urn:urn-7:3gpp-service.exampletelephony.version1\n *\n */\npublic class PPreferredServiceParser extends HeaderParser implements TokenTypes{\n\n    protected PPreferredServiceParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public PPreferredServiceParser(String pps)\n    {\n        super(pps);\n    }\n\n    /**\n     * \"The URN consists of a hierarchical service identifier or application\n     * identifier, with a sequence of labels separated by periods.The left-most label is\n     * the most significant one and is called 'top-level service\n     * identifier', while names to the right are called 'sub-services' or\n     * 'sub-applications'.\n     *\n     * For any given service identifier, labels can be removed right-to-left and\n     * the resulting URN is still valid, referring a more generic\n     * service, with the exception of the top-level service identifier\n     * and possibly the first sub-service or sub-application identifier.\n     *\n     *  Labels cannot be removed beyond a defined basic service, for\n     *  example, the label w.x may define a service, but the label w may\n     *  only define an assignment authority for assigning subsequent\n     *  values and not define a service in its own right.  In other words,\n     *  if a service identifier 'w.x.y.z' exists, the URNs 'w.x' and\n     *  'w.x.y' are also valid service identifiers, but w may not be a\n     *  valid service identifier if it merely defines who is responsible\"\n     *\n     * TODO: PLEASE VALIDATE MY UNDERSTANDING OF THE ABOVE TEXT :)\n     * @ranga: Please validate my understanding of the above text in the draft :)\n     *         This last para is a little ambiguous.I will only check that atleast\n     *         1 sub-service or 1 sub-application is present in the URN declaration.\n     *         If not, I throw an exception. I thought of not throwing an exception\n     *         and returning whatever was encoded..but the resultant encoding wont\n     *         make sense. It would be something like-->\n     *         urn:urn-7:3gpp-service OR urn:urn-7:3gpp-application alone with no sub-services\n     *         or sub-applications. This is bound to cause an error at the recepient later.\n     *\n     * Sub-service and Application identifiers are not maintained by IANA and\n     * are organization/application dependent (Section 8.2). So we cannot gurantee what lies\n     * beyond the first sub-service or sub-application identifier. It should be the responsibility\n     * of the application to make sense of the entire URN holistically. We can only check for the\n     * standardized part as per the ABNF.\n     */\n    public SIPHeader parse() throws ParseException {\n        if(debug)\n            dbg_enter(\"PPreferredServiceParser.parse\");\n        try\n        {\n\n        this.lexer.match(TokenTypes.P_PREFERRED_SERVICE);\n        this.lexer.SPorHT();\n        this.lexer.match(':');\n        this.lexer.SPorHT();\n\n        PPreferredService pps = new PPreferredService();\n        String urn = this.lexer.getBuffer();\n        if(urn.contains(ParameterNamesIms.SERVICE_ID)){\n\n           if(urn.contains(ParameterNamesIms.SERVICE_ID_LABEL))\n                   {\n                    String serviceID = urn.split(ParameterNamesIms.SERVICE_ID_LABEL+\".\")[1];\n\n                     if(serviceID.trim().equals(\"\"))\n                        try {\n                            throw new InvalidArgumentException(\"URN should atleast have one sub-service\");\n                        } catch (InvalidArgumentException e) {\n\n                            e.printStackTrace();\n                        }\n                        else\n                    pps.setSubserviceIdentifiers(serviceID);\n                   }\n           else if(urn.contains(ParameterNamesIms.APPLICATION_ID_LABEL))\n              {\n               String appID = urn.split(ParameterNamesIms.APPLICATION_ID_LABEL)[1];\n               if(appID.trim().equals(\"\"))\n                    try {\n                        throw new InvalidArgumentException(\"URN should atleast have one sub-application\");\n                    } catch (InvalidArgumentException e) {\n                        e.printStackTrace();\n                    }\n                    else\n                  pps.setApplicationIdentifiers(appID);\n              }\n           else\n           {\n               try {\n                throw new InvalidArgumentException(\"URN is not well formed\");\n\n            } catch (InvalidArgumentException e) {\n                e.printStackTrace();\n                    }\n                  }\n          }\n\n            super.parse();\n            return pps;\n        }\n        finally{\n            if(debug)\n                dbg_enter(\"PPreferredServiceParser.parse\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PProfileKeyParser.java",
    "content": "package gov2.nist.javax2.sip.parser.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PProfileKey;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n */\npublic class PProfileKeyParser extends AddressParametersParser implements TokenTypes{\n\n    protected PProfileKeyParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n    public PProfileKeyParser(String profilekey){\n        super(profilekey);\n    }\n\n    public SIPHeader parse() throws ParseException {\n        if (debug)\n            dbg_enter(\"PProfileKey.parse\");\n        try {\n\n            this.lexer.match(TokenTypes.P_PROFILE_KEY);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n\n            PProfileKey p = new PProfileKey();\n            super.parse(p);\n            return p;\n\n        } finally {\n            if (debug)\n                dbg_leave(\"PProfileKey.parse\");\n            }\n\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PServedUserParser.java",
    "content": "package gov2.nist.javax2.sip.parser.ims;\n\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.address.AddressFactoryImpl;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PServedUser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n *\n * @author aayush.bhatnagar\n *\n */\npublic class PServedUserParser extends ParametersParser implements TokenTypes{\n\n    protected PServedUserParser(Lexer lexer) {\n        super(lexer);\n    }\n\n    public PServedUserParser(String servedUser){\n        super(servedUser);\n    }\n\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"PServedUser.parse\");\n\n        try{\n\n            this.lexer.match(TokenTypes.P_SERVED_USER);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n            PServedUser servedUser = new PServedUser();\n            this.lexer.SPorHT();\n            String servedUsername = lexer.byteStringNoSemicolon();\n            servedUser.setAddress(new AddressFactoryImpl().createAddress(servedUsername));\n            super.parse(servedUser);\n\n            return servedUser;\n\n        }\n        finally {\n            if (debug)\n                dbg_leave(\"PServedUser.parse\");\n            }\n    }\n\n    }\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PUserDatabaseParser.java",
    "content": "package gov2.nist.javax2.sip.parser.ims;\n/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PUserDatabase;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n *\n * @author aayush.bhatnagar\n * Rancore Technologies Pvt Ltd, Mumbai India.\n *\n * This is the parser for the P-user-database header.\n * The syntax for the P-user-database header as per\n * RFC 4457 is given below:\n *\n * P-User-Database = \"P-User-Database\" HCOLON database\n *                    *( SEMI generic-param )\n * database        = LAQUOT DiameterURI RAQUOT\n *\n * Eg: P-User-Database: <aaa://host.example.com;transport=tcp>\n *\n */\npublic class PUserDatabaseParser extends ParametersParser implements TokenTypes{\n\n    /**\n     *\n     * @param databaseName\n     */\n    public PUserDatabaseParser(String databaseName)\n    {\n        super(databaseName);\n    }\n\n    /**\n     *\n     * @param lexer\n     */\n    public PUserDatabaseParser(Lexer lexer)\n    {\n        super(lexer);\n    }\n\n    public SIPHeader parse() throws ParseException {\n\n        if (debug)\n            dbg_enter(\"PUserDatabase.parse\");\n\n        try{\n            this.lexer.match(TokenTypes.P_USER_DATABASE);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n\n            PUserDatabase userDatabase = new PUserDatabase();\n            this.parseheader(userDatabase);\n\n             return userDatabase;\n        }\n        finally{\n            if(debug)\n            dbg_leave(\"PUserDatabase.parse\");\n        }\n    }\n\n    private void parseheader(PUserDatabase userDatabase) throws ParseException\n    {\n        StringBuffer dbname = new StringBuffer();\n        this.lexer.match(LESS_THAN);\n\n        while(this.lexer.hasMoreChars())\n        {\n            char next = this.lexer.getNextChar();\n          if (next!='>'&&next!='\\n')\n          {\n          dbname.append(next);\n          }\n\n         }\n        userDatabase.setDatabaseName(dbname.toString());\n          super.parse(userDatabase);\n\n}\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PVisitedNetworkIDParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.PVisitedNetworkID;\nimport gov2.nist.javax2.sip.header.ims.PVisitedNetworkIDList;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.ParametersParser;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\nimport java.text.ParseException;\n\n/**\n * P-Visited-Network-ID header parser.\n *\n * <pre>\n * P-Visited-Network-ID   = \"P-Visited-Network-ID\" HCOLON\n *                          vnetwork-spec\n *                          *(COMMA vnetwork-spec)\n * vnetwork-spec          = (token / quoted-string)\n *                          *(SEMI vnetwork-param)\n * vnetwork-param         = generic-param\n * </pre>\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\n/*\n\n */\n\npublic class PVisitedNetworkIDParser extends ParametersParser implements TokenTypes {\n\n    /**\n     * Constructor\n     */\n    public PVisitedNetworkIDParser(String networkID) {\n        super(networkID);\n\n    }\n\n    protected PVisitedNetworkIDParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n\n\n\n    public SIPHeader parse() throws ParseException {\n\n        PVisitedNetworkIDList visitedNetworkIDList = new PVisitedNetworkIDList();\n\n        if (debug)\n            dbg_enter(\"VisitedNetworkIDParser.parse\");\n\n        try {\n            this.lexer.match(TokenTypes.P_VISITED_NETWORK_ID);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n\n            while (true) {\n\n                PVisitedNetworkID visitedNetworkID = new PVisitedNetworkID();\n\n                if (this.lexer.lookAhead(0) == '\\\"')\n                    parseQuotedString(visitedNetworkID);\n                else\n                    parseToken(visitedNetworkID);\n\n                visitedNetworkIDList.add(visitedNetworkID);\n\n                this.lexer.SPorHT();\n                char la = lexer.lookAhead(0);\n                if (la == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else if (la == '\\n')\n                    break;\n                else\n                    throw createParseException(\"unexpected char = \" + la);\n            }\n            return visitedNetworkIDList;\n        } finally {\n            if (debug)\n                dbg_leave(\"VisitedNetworkIDParser.parse\");\n        }\n\n    }\n\n    protected void parseQuotedString(PVisitedNetworkID visitedNetworkID) throws ParseException {\n\n        if (debug)\n            dbg_enter(\"parseQuotedString\");\n\n        try {\n\n            StringBuffer retval = new StringBuffer();\n\n            if (this.lexer.lookAhead(0) != '\\\"')\n                throw createParseException(\"unexpected char\");\n            this.lexer.consume(1);\n\n            while (true) {\n                char next = this.lexer.getNextChar();\n                if (next == '\\\"') {\n                    // Got to the terminating quote.\n                    break;\n                } else if (next == '\\0') {\n                    throw new ParseException(\"unexpected EOL\", 1);\n                } else if (next == '\\\\') {\n                    retval.append(next);\n                    next = this.lexer.getNextChar();\n                    retval.append(next);\n                } else {\n                    retval.append(next);\n                }\n            }\n\n            visitedNetworkID.setVisitedNetworkID(retval.toString());\n            super.parse(visitedNetworkID);\n\n\n\n        }finally {\n            if (debug)\n                dbg_leave(\"parseQuotedString.parse\");\n        }\n\n    }\n\n    protected void parseToken(PVisitedNetworkID visitedNetworkID) throws ParseException\n    {\n        // issued by Miguel Freitas\n\n        lexer.match(TokenTypes.ID);\n        Token token = lexer.getNextToken();\n        //String value = token.getTokenValue();\n        visitedNetworkID.setVisitedNetworkID(token);\n        super.parse(visitedNetworkID);\n\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PathParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.Path;\nimport gov2.nist.javax2.sip.header.ims.PathList;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\nimport java.text.ParseException;\n\n/**\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\n\npublic class PathParser extends AddressParametersParser implements TokenTypes {\n\n    /**\n     * Constructor\n     */\n    public PathParser(String path) {\n        super(path);\n\n    }\n\n    protected PathParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n\n\n\n    /**\n     * parse the String message and generate the RecordRoute List Object\n     * @return SIPHeader the RecordRoute List object\n     * @throws ParseException if errors occur during the parsing\n     */\n\n    public SIPHeader parse() throws ParseException {\n\n        PathList pathList = new PathList();\n\n        if (debug)\n            dbg_enter(\"PathParser.parse\");\n\n        try {\n            this.lexer.match(TokenTypes.PATH);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n            while (true) {\n                Path path = new Path();\n                super.parse(path);\n                pathList.add(path);\n                this.lexer.SPorHT();\n                char la = lexer.lookAhead(0);\n                if (la == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else if (la == '\\n')\n                    break;\n                else\n                    throw createParseException(\"unexpected char\");\n            }\n            return pathList;\n        } finally {\n            if (debug)\n                dbg_leave(\"PathParser.parse\");\n        }\n\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/PrivacyParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n/**\n * Privacy header parser.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n/*\n * Privacy-hdr  =  \"Privacy\" HCOLON priv-value *(\";\" priv-value)\n * priv-value   =   \"header\" / \"session\" / \"user\" / \"none\" / \"critical\" / token\n */\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.Privacy;\nimport gov2.nist.javax2.sip.header.ims.PrivacyList;\nimport gov2.nist.javax2.sip.header.ims.SIPHeaderNamesIms;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n\n\npublic class PrivacyParser\n    extends HeaderParser\n    implements TokenTypes\n{\n\n\n    public PrivacyParser(String privacyType) {\n\n        super(privacyType);\n    }\n\n    protected PrivacyParser(Lexer lexer) {\n\n        super(lexer);\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n        if (debug)\n            dbg_enter(\"PrivacyParser.parse\");\n\n        PrivacyList privacyList = new PrivacyList();\n\n        try\n        {\n            this.headerName(TokenTypes.PRIVACY);\n\n            while (lexer.lookAhead(0) != '\\n') {\n                this.lexer.SPorHT();\n\n                Privacy privacy = new Privacy();\n                privacy.setHeaderName(SIPHeaderNamesIms.PRIVACY);\n\n                this.lexer.match(TokenTypes.ID);\n                Token token = lexer.getNextToken();\n                privacy.setPrivacy(token.getTokenValue());\n                this.lexer.SPorHT();\n                privacyList.add(privacy);\n\n                // Parsing others option-tags\n                while (lexer.lookAhead(0) == ';')\n                {\n                    this.lexer.match(';');\n                    this.lexer.SPorHT();\n                    privacy = new Privacy();\n                    this.lexer.match(TokenTypes.ID);\n                    token = lexer.getNextToken();\n                    privacy.setPrivacy(token.getTokenValue());\n                    this.lexer.SPorHT();\n\n                    privacyList.add(privacy);\n                }\n            }\n\n            return privacyList;\n\n        }\n        finally {\n            if (debug)\n                dbg_leave(\"PrivacyParser.parse\");\n        }\n\n    }\n\n\n    /** Test program */\n    public static void main(String args[]) throws ParseException\n    {\n        String rou[] = {\n\n                \"Privacy: none\\n\",\n                \"Privacy: none;id;user\\n\"\n            };\n\n        for (int i = 0; i < rou.length; i++ ) {\n            PrivacyParser rp =\n              new PrivacyParser(rou[i]);\n            PrivacyList list = (PrivacyList) rp.parse();\n            System.out.println(\"encoded = \" +list.encode());\n        }\n    }\n\n\n\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/SecurityAgreeParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n/**\n * Security Agreement for SIP.\n * <p>headers: Security-Client, Security-Server and Security-Verify</p>\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\nimport gov2.nist.core.NameValue;\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.SIPHeaderList;\nimport gov2.nist.javax2.sip.header.ims.*;\nimport gov2.nist.javax2.sip.parser.HeaderParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\nimport java.text.ParseException;\n\n\n\npublic class SecurityAgreeParser extends HeaderParser\n{\n\n    public SecurityAgreeParser(String security) {\n        super(security);\n    }\n\n\n    protected SecurityAgreeParser(Lexer lexer) {\n        super(lexer);\n    }\n\n\n    protected void parseParameter(SecurityAgree header)\n        throws ParseException\n    {\n        if (debug)\n            dbg_enter(\"parseParameter\");\n        try {\n            NameValue nv = this.nameValue('=');\n            header.setParameter(nv);\n        } finally {\n            if (debug)\n                dbg_leave(\"parseParameter\");\n        }\n    }\n\n\n    public SIPHeaderList parse(SecurityAgree header) throws ParseException\n    {\n\n        SIPHeaderList list;\n\n        if (header.getClass().isInstance(new SecurityClient())) {\n            list = new SecurityClientList();\n        } else if (header.getClass().isInstance(new SecurityServer())) {\n            list = new SecurityServerList();\n        } else if (header.getClass().isInstance(new SecurityVerify())) {\n            list = new SecurityVerifyList();\n        }\n        else\n            return null;\n\n\n        // the security-mechanism:\n        this.lexer.SPorHT();\n        lexer.match(TokenTypes.ID);\n        Token type = lexer.getNextToken();\n        header.setSecurityMechanism(type.getTokenValue());\n        this.lexer.SPorHT();\n\n        char la = lexer.lookAhead(0);\n        if (la == '\\n')\n        {\n            list.add(header);\n            return list;\n        }\n        else if (la == ';')\n            this.lexer.match(';');\n\n        this.lexer.SPorHT();\n\n        // The parameters:\n        try {\n            while (lexer.lookAhead(0) != '\\n') {\n\n                this.parseParameter(header);\n                this.lexer.SPorHT();\n                char laInLoop = lexer.lookAhead(0);\n                if (laInLoop == '\\n' || laInLoop == '\\0')\n                    break;\n                else if (laInLoop == ',')\n                {\n                    list.add(header);\n                    if (header.getClass().isInstance(new SecurityClient())) {\n                        header = new SecurityClient();\n                    } else if (header.getClass().isInstance(new SecurityServer())) {\n                        header = new SecurityServer();\n                    } else if (header.getClass().isInstance(new SecurityVerify())) {\n                        header = new SecurityVerify();\n                    }\n\n                    this.lexer.match(',');\n                    // the security-mechanism:\n                    this.lexer.SPorHT();\n                    lexer.match(TokenTypes.ID);\n                    type = lexer.getNextToken();\n                    header.setSecurityMechanism(type.getTokenValue());\n\n                }\n                this.lexer.SPorHT();\n\n                if (lexer.lookAhead(0) == ';')\n                    this.lexer.match(';');\n\n                this.lexer.SPorHT();\n\n            }\n            list.add(header);\n\n            return list;\n\n        } catch (ParseException ex) {\n            throw ex;\n        }\n\n\n    }\n\n\n\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/SecurityClientParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n/**\n * Security-Client header parser.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.core.Token;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.SecurityClient;\nimport gov2.nist.javax2.sip.header.ims.SecurityClientList;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n\npublic class SecurityClientParser extends SecurityAgreeParser\n{\n\n    public SecurityClientParser(String security)\n    {\n        super(security);\n    }\n\n    protected SecurityClientParser(Lexer lexer)\n    {\n        super(lexer);\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n        dbg_enter(\"SecuriryClient parse\");\n        try {\n\n            headerName(TokenTypes.SECURITY_CLIENT);\n            SecurityClient secClient = new SecurityClient();\n            SecurityClientList secClientList =\n                (SecurityClientList) super.parse(secClient);\n            return secClientList;\n\n\n        } finally {\n            dbg_leave(\"SecuriryClient parse\");\n        }\n    }\n\n\n\n\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/SecurityServerParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n/**\n * Security-Server header parser.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.SecurityServer;\nimport gov2.nist.javax2.sip.header.ims.SecurityServerList;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n\npublic class SecurityServerParser extends SecurityAgreeParser\n{\n\n    public SecurityServerParser(String security)\n    {\n        super(security);\n    }\n\n    protected SecurityServerParser(Lexer lexer)\n    {\n        super(lexer);\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n        dbg_enter(\"SecuriryServer parse\");\n        try {\n\n            headerName(TokenTypes.SECURITY_SERVER);\n            SecurityServer secServer = new SecurityServer();\n            SecurityServerList secServerList =\n                (SecurityServerList) super.parse(secServer);\n            return secServerList;\n\n        } finally {\n            dbg_leave(\"SecuriryServer parse\");\n        }\n    }\n\n\n\n    /** Test program\n\n    public static void main(String args[]) throws ParseException {\n        String r[] = {\n                \"Security-Server: ipsec-3gpp; ealg=aes-cbc; \" +\n                                \"alg=hmac-md5-96; port-c=5062; port-s=5063; \" +\n                                \"q=0.1\\n\"\n                };\n\n        String r2[] = {\n                \"Security-Server: ipsec-3gpp; ealg=aes-cbc; \" +\n                                \"alg=hmac-md5-96; port-c=5062; port-s=5063; \" +\n                                \"q=0.1, \" +\n                                \"digest; d-alg=md5; \" +\n                                \"d-qop=auth-int; d-ver=AEF1D222; \" +\n                                \"q=0.01\\n\"\n                };\n\n\n        for (int i = 0; i < r.length; i++ )\n        {\n\n            SecurityServerParser parser =\n              new SecurityServerParser(r[i]);\n\n            SecurityServer secServer= (SecurityServer) parser.parse();\n            System.out.println(\"encoded = \" + secServer.encode());\n        }\n\n\n        for (int i = 0; i < r2.length; i++ ) {\n            SecurityServerParser parser =\n              new SecurityServerParser(r2[i]);\n\n            java.util.ListIterator list;\n            SecurityServerList secList = (SecurityServerList) parser.parse();\n            System.out.println(\"encoded = \" + secList.encode());\n        }\n\n\n    }\n    */\n\n\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/SecurityVerifyParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n/**\n * Security-Verify header parser.\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.SecurityVerify;\nimport gov2.nist.javax2.sip.header.ims.SecurityVerifyList;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n\npublic class SecurityVerifyParser extends SecurityAgreeParser\n{\n\n    public SecurityVerifyParser(String security)\n    {\n        super(security);\n    }\n\n    protected SecurityVerifyParser(Lexer lexer)\n    {\n        super(lexer);\n    }\n\n\n    public SIPHeader parse() throws ParseException\n    {\n        dbg_enter(\"SecuriryVerify parse\");\n        try {\n\n            headerName(TokenTypes.SECURITY_VERIFY);\n            SecurityVerify secVerify = new SecurityVerify();\n            SecurityVerifyList secVerifyList =\n                (SecurityVerifyList) super.parse(secVerify);\n            return secVerifyList;\n\n        } finally {\n            dbg_leave(\"SecuriryVerify parse\");\n        }\n    }\n\n\n\n\n\n}\n\n\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/ServiceRouteParser.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************\n * PRODUCT OF PT INOVAO - EST DEPARTMENT *\n *******************************************/\n\npackage gov2.nist.javax2.sip.parser.ims;\n\nimport java.text.ParseException;\n\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.ims.ServiceRoute;\nimport gov2.nist.javax2.sip.header.ims.ServiceRouteList;\nimport gov2.nist.javax2.sip.parser.AddressParametersParser;\nimport gov2.nist.javax2.sip.parser.Lexer;\nimport gov2.nist.javax2.sip.parser.TokenTypes;\n\n/**\n * Service-Route header parser.\n *\n * @author ALEXANDRE MIGUEL SILVA SANTOS\n */\n\npublic class ServiceRouteParser extends AddressParametersParser {\n\n    /**\n     * Constructor\n     */\n    public ServiceRouteParser(String serviceRoute) {\n        super(serviceRoute);\n\n    }\n\n    protected ServiceRouteParser(Lexer lexer) {\n        super(lexer);\n\n    }\n\n\n\n\n    /**\n     * parse the String message and generate the RecordRoute List Object\n     * @return SIPHeader the RecordRoute List object\n     * @throws ParseException if errors occur during the parsing\n     */\n\n    public SIPHeader parse() throws ParseException {\n        ServiceRouteList serviceRouteList = new ServiceRouteList();\n\n        if (debug)\n            dbg_enter(\"ServiceRouteParser.parse\");\n\n        try {\n            this.lexer.match(TokenTypes.SERVICE_ROUTE);\n            this.lexer.SPorHT();\n            this.lexer.match(':');\n            this.lexer.SPorHT();\n            while (true) {\n                ServiceRoute serviceRoute = new ServiceRoute();\n                super.parse(serviceRoute);\n                serviceRouteList.add(serviceRoute);\n                this.lexer.SPorHT();\n                if (lexer.lookAhead(0) == ',') {\n                    this.lexer.match(',');\n                    this.lexer.SPorHT();\n                } else if (lexer.lookAhead(0) == '\\n')\n                    break;\n                else\n                    throw createParseException(\"unexpected char\");\n            }\n            return serviceRouteList;\n        } finally {\n            if (debug)\n                dbg_leave(\"ServiceRouteParser.parse\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/parser/ims/TokenNamesIms.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/************************************************************************************************\n * PRODUCT OF PT INOVACAO - EST DEPARTMENT and Telecommunications Institute (Aveiro, Portugal)  *\n ************************************************************************************************/\n\n\npackage gov2.nist.javax2.sip.parser.ims;\n\n/**\n *\n * @author Miguel Freitas (IT) PT-Inovacao\n */\n\n\npublic interface TokenNamesIms\n    extends gov2.nist.javax2.sip.parser.TokenNames\n{\n\n    public static final String IEEE_802_11A = \"IEEE-802.11a\";\n    public static final String IEEE_802_11B = \"IEEE-802.11b\";\n    public static final String GGGPP_GERAN = \"3GPP-GERAN\";\n    public static final String GGGPP_UTRAN_FDD = \"3GPP-UTRAN-FDD\";\n    public static final String GGGPP_UTRAN_TDD = \"3GPP-UTRAN-TDD\";\n    public static final String GGGPP_CDMA2000 = \"3GPP-CDMA2000\";\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/DefaultMessageLogFactory.java",
    "content": "package gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.javax2.sip.LogRecord;\nimport gov2.nist.javax2.sip.LogRecordFactory;\n\n/**\n * The Default Message log factory. This can be replaced as a stack\n * configuration parameter.\n *\n * @author M. Ranganathan\n *\n */\npublic class DefaultMessageLogFactory implements LogRecordFactory {\n\n    public LogRecord createLogRecord(String message, String source,\n            String destination, String timeStamp, boolean isSender,\n            String firstLine, String tid, String callId, long tsHeaderValue) {\n        return new MessageLog(message, source, destination, timeStamp,\n                isSender, firstLine, tid, callId, tsHeaderValue);\n    }\n\n    public LogRecord createLogRecord(String message, String source,\n            String destination, long timeStamp, boolean isSender,\n            String firstLine, String tid, String callId, long timestampVal) {\n        return new MessageLog(message, source, destination, timeStamp,\n                isSender, firstLine, tid, callId, timestampVal);\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/DefaultRouter.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.*;\nimport gov2.nist.core.net.AddressResolver;\nimport gov2.nist.javax2.sip.*;\nimport gov2.nist.javax2.sip.address.*;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.message.*;\n\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.ListIterator;\n\nimport javax2.sip.*;\nimport javax2.sip.address.*;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.ViaHeader;\nimport javax2.sip.message.*;\n\n/*\n * Bug reported by Will Scullin -- maddr was being ignored when routing\n * requests. Bug reported by Antonis Karydas - the RequestURI can be a non-sip\n * URI Jiang He - use address in route header. Significant changes to conform to\n * RFC 3261 made by Jeroen van Bemmel. Hagai Sela contributed a bug fix to the\n * strict route post processing code.\n *\n */\n\n/**\n * This is the default router. When the implementation wants to forward a\n * request and had run out of othe options, then it calls this method to figure\n * out where to send the request. The default router implements a simple\n * \"default routing algorithm\" which just forwards to the configured proxy\n * address.\n *\n * <p>\n * When <code>javax2.sip.USE_ROUTER_FOR_ALL_URIS</code> is set to\n * <code>false</code>, the next hop is determined according to the following\n * algorithm:\n * <ul>\n * <li> If the request contains one or more Route headers, use the URI of the\n * topmost Route header as next hop, possibly modifying the request in the\n * process if the topmost Route header contains no lr parameter(*)\n * <li> Else, if the property <code>javax2.sip.OUTBOUND_PROXY</code> is set,\n * use its value as the next hop\n * <li> Otherwise, use the request URI as next hop. If the request URI is not a\n * SIP URI, call {@link javax2.sip.address.Router#getNextHop(Request)} provided\n * by the application.\n * </ul>\n *\n * <p>\n * (*)Note that in case the topmost Route header contains no 'lr' parameter\n * (which means the next hop is a strict router), the implementation will\n * perform 'Route Information Postprocessing' as described in RFC3261 section\n * 16.6 step 6 (also known as \"Route header popping\"). That is, the following\n * modifications will be made to the request:\n * <ol>\n * <li>The implementation places the Request-URI into the Route header field as\n * the last value.\n * <li>The implementation then places the first Route header field value into\n * the Request-URI and removes that value from the Route header field.\n * </ol>\n * Subsequently, the request URI will be used as next hop target\n *\n *\n * @version 1.2 $Revision: 1.17 $ $Date: 2009/11/14 20:06:17 $\n *\n * @author M. Ranganathan <br/>\n *\n */\npublic class DefaultRouter implements Router {\n\n    private SipStackImpl sipStack;\n\n    private Hop defaultRoute;\n\n    private DefaultRouter() {\n\n    }\n\n    /**\n     * Constructor.\n     */\n    public DefaultRouter(SipStack sipStack, String defaultRoute) {\n        this.sipStack = (SipStackImpl) sipStack;\n        if (defaultRoute != null) {\n            try {\n                this.defaultRoute = (Hop) this.sipStack.getAddressResolver()\n                        .resolveAddress((Hop) (new HopImpl(defaultRoute)));\n            } catch (IllegalArgumentException ex) {\n                // The outbound proxy is optional. If specified it should be host:port/transport.\n                ((SIPTransactionStack) sipStack)\n                        .getStackLogger()\n                        .logError(\n                                \"Invalid default route specification - need host:port/transport\");\n                throw ex;\n            }\n        }\n    }\n\n    /**\n     * Return addresses for default proxy to forward the request to. The list is\n     * organized in the following priority. If the requestURI refers directly to\n     * a host, the host and port information are extracted from it and made the\n     * next hop on the list. If the default route has been specified, then it is\n     * used to construct the next element of the list. <code>\n     * RouteHeader firstRoute = (RouteHeader) req.getHeader( RouteHeader.NAME );\n     * if (firstRoute!=null) {\n     *   URI uri = firstRoute.getAddress().getURI();\n     *    if (uri.isSIPUri()) {\n     *       SipURI nextHop = (SipURI) uri;\n     *       if ( nextHop.hasLrParam() ) {\n     *           // OK, use it\n     *       } else {\n     *           nextHop = fixStrictRouting( req );        <--- Here, make the modifications as per RFC3261\n     *       }\n     *   } else {\n     *       // error: non-SIP URI not allowed in Route headers\n     *       throw new SipException( \"Request has Route header with non-SIP URI\" );\n     *   }\n     * } else if (outboundProxy!=null) {\n     *   // use outbound proxy for nextHop\n     * } else if ( req.getRequestURI().isSipURI() ) {\n     *   // use request URI for nextHop\n     * }\n     *\n     * </code>\n     *\n     * @param request\n     *            is the sip request to route.\n     *\n     */\n    public Hop getNextHop(Request request) throws SipException {\n\n        SIPRequest sipRequest = (SIPRequest) request;\n\n        RequestLine requestLine = sipRequest.getRequestLine();\n        if (requestLine == null) {\n            return defaultRoute;\n        }\n        javax2.sip.address.URI requestURI = requestLine.getUri();\n        if (requestURI == null)\n            throw new IllegalArgumentException(\"Bad message: Null requestURI\");\n\n        RouteList routes = sipRequest.getRouteHeaders();\n\n        /*\n         * In case the topmost Route header contains no 'lr' parameter (which\n         * means the next hop is a strict router), the implementation will\n         * perform 'Route Information Postprocessing' as described in RFC3261\n         * section 16.6 step 6 (also known as \"Route header popping\"). That is,\n         * the following modifications will be made to the request:\n         *\n         * The implementation places the Request-URI into the Route header field\n         * as the last value.\n         *\n         * The implementation then places the first Route header field value\n         * into the Request-URI and removes that value from the Route header\n         * field.\n         *\n         * Subsequently, the request URI will be used as next hop target\n         */\n\n        if (routes != null) {\n\n            // to send the request through a specified hop the application is\n            // supposed to prepend the appropriate Route header which.\n            Route route = (Route) routes.getFirst();\n            URI uri = route.getAddress().getURI();\n            if (uri.isSipURI()) {\n                SipURI sipUri = (SipURI) uri;\n                if (!sipUri.hasLrParam()) {\n\n                    fixStrictRouting(sipRequest);\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger()\n                                .logDebug(\"Route post processing fixed strict routing\");\n                }\n\n                Hop hop = createHop(sipUri,request);\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger()\n                            .logDebug(\"NextHop based on Route:\" + hop);\n                return hop;\n            } else {\n                throw new SipException(\"First Route not a SIP URI\");\n            }\n\n        } else if (requestURI.isSipURI()\n                && ((SipURI) requestURI).getMAddrParam() != null) {\n            Hop hop = createHop((SipURI) requestURI,request);\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger()\n                        .logDebug(\"Using request URI maddr to route the request = \"\n                                + hop.toString());\n\n            // JvB: don't remove it!\n            // ((SipURI) requestURI).removeParameter(\"maddr\");\n\n            return hop;\n\n        } else if (defaultRoute != null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger()\n                        .logDebug(\"Using outbound proxy to route the request = \"\n                                + defaultRoute.toString());\n            return defaultRoute;\n        } else if (requestURI.isSipURI()) {\n            Hop hop = createHop((SipURI) requestURI,request);\n            if (hop != null && sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Used request-URI for nextHop = \"\n                        + hop.toString());\n            else if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger()\n                        .logDebug(\"returning null hop -- loop detected\");\n            }\n            return hop;\n\n        } else {\n            // The internal router should never be consulted for non-sip URIs.\n            InternalErrorHandler.handleException(\"Unexpected non-sip URI\",\n                    this.sipStack.getStackLogger());\n            return null;\n        }\n\n    }\n\n    /**\n     * Performs strict router fix according to RFC3261 section 16.6 step 6\n     *\n     * pre: top route header in request has no 'lr' parameter in URI post:\n     * request-URI added as last route header, new req-URI = top-route-URI\n     */\n    public void fixStrictRouting(SIPRequest req) {\n\n        RouteList routes = req.getRouteHeaders();\n        Route first = (Route) routes.getFirst();\n        SipUri firstUri = (SipUri) first.getAddress().getURI();\n        routes.removeFirst();\n\n        // Add request-URI as last Route entry\n        AddressImpl addr = new AddressImpl();\n        addr.setAddess(req.getRequestURI()); // don't clone it\n        Route route = new Route(addr);\n\n        routes.add(route); // as last one\n        req.setRequestURI(firstUri);\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"post: fixStrictRouting\" + req);\n        }\n    }\n\n    /**\n     * Utility method to create a hop from a SIP URI\n     *\n     * @param sipUri\n     * @return\n     */\n\n\n    private final Hop createHop(SipURI sipUri, Request request) {\n        // always use TLS when secure\n        String transport = sipUri.isSecure() ? SIPConstants.TLS : sipUri\n                .getTransportParam();\n        if (transport == null) {\n            //@see issue 131\n            ViaHeader via = (ViaHeader) request.getHeader(ViaHeader.NAME);\n            transport = via.getTransport();\n        }\n\n        // sipUri.removeParameter(\"transport\");\n\n        int port;\n        if (sipUri.getPort() != -1) {\n            port = sipUri.getPort();\n        } else {\n            if (transport.equalsIgnoreCase(SIPConstants.TLS))\n                port = 5061;\n            else\n                port = 5060; // TCP or UDP\n        }\n        String host = sipUri.getMAddrParam() != null ? sipUri.getMAddrParam()\n                : sipUri.getHost();\n        AddressResolver addressResolver = this.sipStack.getAddressResolver();\n        return addressResolver\n                .resolveAddress(new HopImpl(host, port, transport));\n\n    }\n\n    /**\n     * Get the default hop.\n     *\n     * @return defaultRoute is the default route. public java.util.Iterator\n     *         getDefaultRoute(Request request) { return\n     *         this.getNextHops((SIPRequest)request); }\n     */\n\n    public javax2.sip.address.Hop getOutboundProxy() {\n        return this.defaultRoute;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.address.Router#getNextHop(javax2.sip.message.Request)\n     */\n    public ListIterator getNextHops(Request request) {\n        try {\n            LinkedList llist = new LinkedList();\n            llist.add(this.getNextHop(request));\n            return llist.listIterator();\n        } catch (SipException ex) {\n            return null;\n        }\n\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/HandshakeCompletedListenerImpl.java",
    "content": "/*\n * This software has been contributed by the author to the public domain.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip.stack;\n\nimport javax.net.ssl.HandshakeCompletedEvent;\nimport javax.net.ssl.HandshakeCompletedListener;\n\npublic class HandshakeCompletedListenerImpl implements HandshakeCompletedListener {\n\n    private HandshakeCompletedEvent handshakeCompletedEvent;\n    private TLSMessageChannel tlsMessageChannel;\n    \n    \n    public HandshakeCompletedListenerImpl(TLSMessageChannel tlsMessageChannel) {\n        this.tlsMessageChannel = tlsMessageChannel;\n        tlsMessageChannel.setHandshakeCompletedListener(this);\n    }\n\n    \n    public void handshakeCompleted(HandshakeCompletedEvent handshakeCompletedEvent) {\n       this.handshakeCompletedEvent = handshakeCompletedEvent;\n       /*\n       try {\n           Thread.sleep(10);\n       } catch (InterruptedException ex) {\n           \n       }*/\n    }\n\n    /**\n     * @return the handshakeCompletedEvent\n     */\n    public HandshakeCompletedEvent getHandshakeCompletedEvent() {\n        return handshakeCompletedEvent;\n    }\n    \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/HopImpl.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport java.io.Serializable;\nimport java.util.StringTokenizer;\n/*\n * IPv6 Support added by Emil Ivov (emil_ivov@yahoo.com)<br/>\n * Network Research Team (http://www-r2.u-strasbg.fr))<br/>\n * Louis Pasteur University - Strasbourg - France<br/>\n * Bug fix for correct handling of IPV6 Address added by\n * Daniel J. Martinez Manzano <dani@dif.um.es>\n */\n/**\n * Routing algorithms return a list of hops to which the request is\n * routed.\n *\n * @version 1.2 $Revision: 1.11 $ $Date: 2009/07/17 18:58:13 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n\n *\n */\npublic final class HopImpl extends Object implements javax2.sip.address.Hop, Serializable {\n    protected String host;\n    protected int port;\n    protected String transport;\n\n    protected boolean defaultRoute; // This is generated from the proxy addr\n    protected boolean uriRoute; // This is extracted from the requestURI.\n\n    /**\n     * Debugging println.\n     */\n    public String toString() {\n        return host + \":\" + port + \"/\" + transport;\n    }\n\n    /**\n     * Create new hop given host, port and transport.\n     * @param hostName hostname\n     * @param portNumber port\n     * @param trans transport\n     */\n    public HopImpl(String hostName, int portNumber, String trans) {\n        host = hostName;\n\n        // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n        // for correct management of IPv6 addresses.\n        if(host.indexOf(\":\") >= 0)\n            if(host.indexOf(\"[\") < 0)\n                host = \"[\" + host + \"]\";\n\n        port = portNumber;\n        transport = trans;\n    }\n\n\n    /**\n     * Creates new Hop\n     * @param hop is a hop string in the form of host:port/Transport\n     * @throws IllegalArgument exception if string is not properly formatted or null.\n     */\n    HopImpl(String hop) throws IllegalArgumentException {\n\n        if (hop == null)\n            throw new IllegalArgumentException(\"Null arg!\");\n\n        // System.out.println(\"hop = \" + hop);\n        int brack = hop.indexOf(']');\n        int colon = hop.indexOf(':',brack);\n        int slash = hop.indexOf('/',colon);\n\n        if (colon>0) {\n            this.host = hop.substring(0,colon);\n            String portstr;\n            if (slash>0) {\n                portstr = hop.substring(colon+1,slash);\n                this.transport = hop.substring(slash+1);\n            } else {\n                portstr = hop.substring(colon+1);\n                this.transport = \"UDP\";\n            }\n            try {\n                port = Integer.parseInt(portstr);\n            } catch (NumberFormatException ex) {\n                throw new IllegalArgumentException(\"Bad port spec\");\n            }\n        } else {\n            if (slash>0) {\n                this.host = hop.substring(0,slash);\n                this.transport = hop.substring(slash+1);\n                this.port = transport.equalsIgnoreCase(\"TLS\") ? 5061 : 5060;\n            } else {\n                this.host = hop;\n                this.transport = \"UDP\";\n                this.port = 5060;\n            }\n        }\n\n        // Validate it\n        if (host == null || host.length() == 0)\n            throw new IllegalArgumentException(\"no host!\");\n\n        // normalize\n        this.host = this.host.trim();\n        this.transport = this.transport.trim();\n\n        if ((brack>0) && host.charAt(0)!='[') {\n            throw new IllegalArgumentException(\"Bad IPv6 reference spec\");\n        }\n\n        if (transport.compareToIgnoreCase(\"UDP\") != 0\n            && transport.compareToIgnoreCase(\"TLS\") != 0\n            && transport.compareToIgnoreCase(\"TCP\") != 0) {\n            System.err.println(\"Bad transport string \" + transport);\n            throw new IllegalArgumentException(hop);\n        }\n    }\n\n    /**\n     * Retruns the host string.\n     * @return host String\n     */\n    public String getHost() {\n        return host;\n    }\n\n    /**\n     * Returns the port.\n     * @return port integer.\n     */\n    public int getPort() {\n        return port;\n    }\n\n    /** returns the transport string.\n     */\n    public String getTransport() {\n        return transport;\n    }\n\n\n\n    /** Return true if this is uriRoute\n     */\n    public boolean isURIRoute() {\n        return uriRoute;\n    }\n\n    /** Set the URIRoute flag.\n     */\n    public void setURIRouteFlag() {\n        uriRoute = true;\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/IOHandler.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 United States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.StackLogger;\nimport gov2.nist.javax2.sip.SipStackImpl;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.message.SIPMessage;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.util.Enumeration;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.net.ssl.HandshakeCompletedListener;\nimport javax.net.ssl.SSLSocket;\n\nimport android.text.TextUtils;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.address.Address;\nimport javax2.sip.header.ContactHeader;\n\n/*\n * TLS support Added by Daniel J.Martinez Manzano <dani@dif.um.es>\n * \n */\n\n/**\n * Low level Input output to a socket. Caches TCP connections and takes care of re-connecting to\n * the remote party if the other end drops the connection\n * \n * @version 1.2\n * \n * @author M. Ranganathan <br/>\n * \n * \n */\n\nclass IOHandler {\n\n    private Semaphore ioSemaphore = new Semaphore(1);\n\n    private SipStackImpl sipStack;\n\n    private static String TCP = \"tcp\";\n\n    // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n    private static String TLS = \"tls\";\n\n    // A cache of client sockets that can be re-used for\n    // sending tcp messages.\n    private ConcurrentHashMap<String, Socket> socketTable;\n\n    protected static String makeKey(InetAddress addr, int port) {\n        return addr.getHostAddress() + \":\" + port;\n\n    }\n\n    protected IOHandler(SIPTransactionStack sipStack) {\n        this.sipStack = (SipStackImpl) sipStack;\n        this.socketTable = new ConcurrentHashMap<String, Socket>();\n\n    }\n\n    protected void putSocket(String key, Socket sock) {\n        socketTable.put(key, sock);\n\n    }\n\n    protected Socket getSocket(String key) {\n        return (Socket) socketTable.get(key);\n    }\n\n    protected void removeSocket(String key) {\n        socketTable.remove(key);\n    }\n\n    /**\n     * A private function to write things out. This needs to be synchronized as writes can occur\n     * from multiple threads. We write in chunks to allow the other side to synchronize for large\n     * sized writes.\n     */\n    // Changed by Deutsche Telekom\n    // ***###*** DTAG, AS 2012-09-10; work around Android issue 34727 (large TCP packets from or to port 5060 not send)\n    private void writeChunks(OutputStream outputStream, byte[] bytes, int length, boolean smallChunks)\n            throws IOException {\n        // Chunk size is 16K - this hack is for large\n        // writes over slow connections.\n        synchronized (outputStream) {\n            // outputStream.write(bytes,0,length);\n            // Changed by Deutsche Telekom\n            // ***###*** DTAG, AS 2012-09-10; work around Android issue 34727 (large TCP packets from or to port 5060 not send)\n            int chunksize = 8 * 1024;\n            if (smallChunks) {\n                chunksize = 512;\n            }\n            for (int p = 0; p < length; p += chunksize) {\n                int chunk = p + chunksize < length ? chunksize : length - p;\n                outputStream.write(bytes, p, chunk);\n            }\n        }\n        outputStream.flush();\n    }\n\n    /**\n     * Creates and binds, if necessary, a socket connected to the specified destination address\n     * and port and then returns its local address.\n     * \n     * @param dst the destination address that the socket would need to connect to.\n     * @param dstPort the port number that the connection would be established with.\n     * @param localAddress the address that we would like to bind on (null for the \"any\" address).\n     * @param localPort the port that we'd like our socket to bind to (0 for a random port).\n     * \n     * @return the SocketAddress that this handler would use when connecting to the specified\n     *         destination address and port.\n     * \n     * @throws IOException\n     */\n    public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort,\n            InetAddress localAddress, int localPort) throws IOException {\n        String key = makeKey(dst, dstPort);\n\n        Socket clientSock = getSocket(key);\n\n        if (clientSock == null) {\n            clientSock = sipStack.getNetworkLayer().createSocket(dst, dstPort, localAddress,\n                    localPort);\n            putSocket(key, clientSock);\n        }\n\n        return clientSock.getLocalSocketAddress();\n\n    }\n\n    /**\n     * Send an array of bytes.\n     * \n     * @param senderAddress -- inet src address\n     * @param receiverAddress -- inet dst address\n     * @param contactPort -- port to connect to.\n     * @param transport -- tcp or udp.\n     * @param message -- sip message to send\n     * @param retry -- retry to connect if the other end closed connection\n     * @param messageChannel -- message channel\n     * @throws IOException -- if there is an IO exception sending message.\n     */\n\n    public Socket sendBytes(InetAddress senderAddress, InetAddress receiverAddress,\n            int contactPort, String transport, SIPMessage message, boolean retry,\n            MessageChannel messageChannel) throws IOException {\n        int retry_count = 0;\n        int max_retry = retry ? 2 : 1;\n        // Server uses TCP transport. TCP client sockets are cached\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"sendBytes \" + transport + \" inAddr \" + receiverAddress.getHostAddress()\n                            + \" port = \" + contactPort );\n        }\n        if (sipStack.isLoggingEnabled() && sipStack.isLogStackTraceOnMessageSend()) {\n            sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);\n        }\n        if (transport.compareToIgnoreCase(TCP) == 0) {\n            String key = makeKey(receiverAddress, contactPort);\n            // This should be in a synchronized block ( reported by\n            // Jayashenkhar ( lucent ).\n\n            try {\n                boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS); \n                if (!retval) {\n                    throw new IOException(\n                            \"Could not acquire IO Semaphore after 10 seconds -- giving up \");\n                }\n            } catch (InterruptedException ex) {\n                throw new IOException(\"exception in acquiring sem\");\n            }\n            Socket clientSock = getSocket(key);\n\n            try {\n\n                while (retry_count < max_retry) {\n                    if (clientSock == null) {\n                        if (sipStack.isLoggingEnabled()) {\n                            sipStack.getStackLogger().logDebug(\"inaddr = \" + receiverAddress);\n                            sipStack.getStackLogger().logDebug(\"port = \" + contactPort);\n                        }\n                        // note that the IP Address for stack may not be\n                        // assigned.\n                        // sender address is the address of the listening point.\n                        // in version 1.1 all listening points have the same IP\n                        // address (i.e. that of the stack). In version 1.2\n                        // the IP address is on a per listening point basis.\n                        clientSock = sipStack.getNetworkLayer().createSocket(receiverAddress,\n                                contactPort, senderAddress);\n                        OutputStream outputStream = clientSock.getOutputStream();\n                        // Changed by Deutsche Telekom\n                        // ***###*** DTAG, AS 2012-09-10; work around Android issue 34727 (large TCP packets from or to port 5060 not send)\n                        boolean doIssue34727workarround = false;\n                        if (clientSock.getLocalPort()==5060 || contactPort==5060)\n                            doIssue34727workarround = true;\n                        // Update Via header to reflect local port\n                        updateViaHeaderPort(clientSock.getLocalPort(), clientSock.getLocalAddress(),\n                            message);\n                        // Update Contact header to reflect local port\n                        updateContactHeaderPort(clientSock.getLocalPort(), message);\n                        // Encode the SIP message into byte array\n                        byte[] bytes = message.encodeAsBytes(transport);\n                        \n                        writeChunks(outputStream, bytes, bytes.length, doIssue34727workarround);\n                        putSocket(key, clientSock);\n                        break;\n                    } else {\n                        try {\n                            OutputStream outputStream = clientSock.getOutputStream();\n                            // Changed by Deutsche Telekom\n                            // ***###*** DTAG, AS 2012-09-10; work around Android issue 34727 (large TCP packets from or to port 5060 not send)\n                            boolean doIssue34727workarround = false;\n                            if (clientSock.getLocalPort()==5060 || contactPort==5060)\n                                doIssue34727workarround = true;\n                            // Update Via header to reflect local port\n                            updateViaHeaderPort(clientSock.getLocalPort(),\n                                clientSock.getLocalAddress(), message);\n                            // Update Contact header to reflect local port\n                            updateContactHeaderPort(clientSock.getLocalPort(), message);\n                            // Encode the SIP message into byte array\n                            byte[] bytes = message.encodeAsBytes(transport);\n                            \n                            writeChunks(outputStream, bytes, bytes.length, doIssue34727workarround);\n                            break;\n                        } catch (IOException ex) {\n                            if (sipStack.isLoggingEnabled())\n                                sipStack.getStackLogger().logDebug(\n                                        \"IOException occured retryCount \" + retry_count);\n                            // old connection is bad.\n                            // remove from our table.\n                            removeSocket(key);\n                            try {\n                                clientSock.close();\n                            } catch (Exception e) {\n                            }\n                            clientSock = null;\n                            retry_count++;\n                        }\n                    }\n                }\n            } finally {\n                ioSemaphore.release();\n            }\n\n            if (clientSock == null) {\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(this.socketTable.toString());\n                    sipStack.getStackLogger().logError(\n                            \"Could not connect to \" + receiverAddress + \":\" + contactPort);\n                }\n\n                throw new IOException(\"Could not connect to \" + receiverAddress + \":\"\n                        + contactPort);\n            } else\n                return clientSock;\n\n            // Added by Daniel J. Martinez Manzano <dani@dif.um.es>\n            // Copied and modified from the former section for TCP\n        } else if (transport.compareToIgnoreCase(TLS) == 0) {\n            String key = makeKey(receiverAddress, contactPort);\n            try {\n                boolean retval = this.ioSemaphore.tryAcquire(10000, TimeUnit.MILLISECONDS);\n                if (!retval)\n                    throw new IOException(\"Timeout acquiring IO SEM\");\n            } catch (InterruptedException ex) {\n                throw new IOException(\"exception in acquiring sem\");\n            }\n            Socket clientSock = getSocket(key);\n\n            try {\n                while (retry_count < max_retry) {\n                    if (clientSock == null) {\n                        if (sipStack.isLoggingEnabled()) {\n                            sipStack.getStackLogger().logDebug(\"inaddr = \" + receiverAddress);\n                            sipStack.getStackLogger().logDebug(\"port = \" + contactPort);\n                        }\n\n                        clientSock = sipStack.getNetworkLayer().createSSLSocket(receiverAddress,\n                                contactPort, senderAddress);\n                        SSLSocket sslsock = (SSLSocket) clientSock;\n                        HandshakeCompletedListener listner = new HandshakeCompletedListenerImpl(\n                                (TLSMessageChannel) messageChannel);\n                        ((TLSMessageChannel) messageChannel)\n                                .setHandshakeCompletedListener(listner);\n                        sslsock.addHandshakeCompletedListener(listner);\n                        sslsock.setEnabledProtocols(sipStack.getEnabledProtocols());\n                        sslsock.startHandshake();\n\n                        // Changed by Deutsche Telekom\n                        // ***###*** DTAG, AS 2012-09-10; work around Android issue 34727 (large TCP packets from or to port 5060 not send)\n                        boolean doIssue34727workarround = false;\n                        if (clientSock.getLocalPort()==5060 || contactPort==5060)\n                            doIssue34727workarround = true;\n                        OutputStream outputStream = clientSock.getOutputStream();\n                        // Update Via header to reflect local port\n                        updateViaHeaderPort(clientSock.getLocalPort(), clientSock.getLocalAddress(),\n                            message);\n                        // Update Contact header to reflect local port\n                        updateContactHeaderPort(clientSock.getLocalPort(), message);\n                        // Encode the SIP message into byte array\n                        byte[] bytes = message.encodeAsBytes(transport);\n                        \n                        writeChunks(outputStream, bytes, bytes.length, doIssue34727workarround);\n                        putSocket(key, clientSock);\n                        break;\n                    } else {\n                        try {\n                            // Changed by Deutsche Telekom\n                            // ***###*** DTAG, AS 2012-09-10; work around Android issue 34727 (large TCP packets from or to port 5060 not send)\n                            boolean doIssue34727workarround = false;\n                            if (clientSock.getLocalPort()==5060 || contactPort==5060)\n                                doIssue34727workarround = true;\n                            OutputStream outputStream = clientSock.getOutputStream();\n                            // Update Via header to reflect local port\n                            updateViaHeaderPort(clientSock.getLocalPort(),\n                                clientSock.getLocalAddress(), message);\n                            // Update Contact header to reflect local port\n                            updateContactHeaderPort(clientSock.getLocalPort(), message);\n                            // Encode the SIP message into byte array\n                            byte[] bytes = message.encodeAsBytes(transport);\n                            \n                            writeChunks(outputStream, bytes, bytes.length, doIssue34727workarround);\n                            break;\n                        } catch (IOException ex) {\n                            if (sipStack.isLoggingEnabled())\n                                sipStack.getStackLogger().logException(ex);\n                            // old connection is bad.\n                            // remove from our table.\n                            removeSocket(key);\n                            try {\n                                clientSock.close();\n                            } catch (Exception e) {\n                            }\n                            clientSock = null;\n                            retry_count++;\n                        }\n                    }\n                }\n            } finally {\n                ioSemaphore.release();\n            }\n            if (clientSock == null) {\n                throw new IOException(\"Could not connect to \" + receiverAddress + \":\"\n                        + contactPort);\n            } else\n                return clientSock;\n\n        } else {\n            // This is a UDP transport...\n            DatagramSocket datagramSock = sipStack.getNetworkLayer().createDatagramSocket();\n            datagramSock.connect(receiverAddress, contactPort);\n            \n            // Update Via header to reflect local port\n            updateViaHeaderPort(datagramSock.getLocalPort(), datagramSock.getLocalAddress(),\n                    message);\n            // Update Contact header to reflect local port\n            updateContactHeaderPort(datagramSock.getLocalPort(), message);\n            // Encode the SIP message into byte array\n            byte[] bytes = message.encodeAsBytes(transport);\n            \n            DatagramPacket dgPacket = new DatagramPacket(bytes, 0, bytes.length, receiverAddress,\n                    contactPort);\n            datagramSock.send(dgPacket);\n            datagramSock.close();\n            return null;\n        }\n\n    }\n    \n\t/**\n\t * Update port of Via header to reflect local port\n\t * \n\t * @param localPort the local port\n     * @param localAddress the local address\n     * @param message the SIP message to be updated\n     */\n    private void updateViaHeaderPort(int localPort, InetAddress localAddress, SIPMessage message) {\n\t\tif (localAddress == null) {\n\t\t\treturn;\n\t\t}\n\t\tif (message == null || message.getViaHeaders() == null) {\n\t\t\treturn;\n\t\t}\n\t\tViaList viaList = message.getViaHeaders();\n\t\tif (viaList == null || viaList.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tString localHostAddress = localAddress.getHostAddress();\n\t\t\tString viaHostAddress = viaList.get(0).getHost();\n\t\t\t// Only update port of via header if address of via header is set to the local host address\n\t\t\tif (!TextUtils.isEmpty(viaHostAddress) && viaHostAddress.equals(localHostAddress)) {\n\t\t\t\tviaList.get(0).setPort(localPort);\n\t\t\t}\n\t\t} catch (InvalidArgumentException e) {\n\t\t\tif (sipStack.isLoggingEnabled()) {\n\t\t\t\tsipStack.getStackLogger().logError(e.getMessage(), e);\n\t\t\t}\n\t\t}\n    }\n    \n    /**\n     * Update port of Contact header to reflect local port\n     *\n     * @param localPort the local port\n     * @param message the SIP message to be updated\n     */\n    private void updateContactHeaderPort(int localPort, SIPMessage message) {\n        if (message != null && message.getContactHeader() != null) {\n            ContactHeader contactHeader = message.getContactHeader();\n            Address contactAddress = contactHeader.getAddress();\n            contactAddress.setPort(localPort);\n        }\n    }\n\n    /**\n     * Close all the cached connections.\n     */\n    public void closeAll() {\n        for (Enumeration<Socket> values = socketTable.elements(); values.hasMoreElements();) {\n            Socket s = (Socket) values.nextElement();\n            try {\n                s.close();\n            } catch (IOException ex) {\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/MessageChannel.java",
    "content": "/*\n * Conditions Of Use \n * \n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n * \n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *  \n * .\n * \n */\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\n\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.Host;\nimport gov2.nist.core.HostPort;\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.core.ServerLogger;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.ContentLength;\nimport gov2.nist.javax2.sip.header.ContentType;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.message.MessageFactoryImpl;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\nimport gov2.nist.javax2.sip.parser.StringMsgParser;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.text.ParseException;\n\nimport javax2.sip.address.Hop;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ContentLengthHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.ServerHeader;\nimport javax2.sip.header.ToHeader;\nimport javax2.sip.header.ViaHeader;\n\n/**\n * Message channel abstraction for the SIP stack.\n * \n * @author M. Ranganathan <br/> Contains additions for support of symmetric NAT contributed by\n *         Hagai.\n * \n * @version 1.2 $Revision: 1.28 $ $Date: 2009/11/14 20:06:18 $\n * \n * \n */\npublic abstract class MessageChannel {\n\n    // Incremented whenever a transaction gets assigned\n    // to the message channel and decremented when\n    // a transaction gets freed from the message channel.\n\tprotected int useCount;\n\t\n\t/**\n\t * Hook method, overridden by subclasses\n\t */\n\tprotected void uncache() {}\n\t\n    /**\n     * Message processor to whom I belong (if set).\n     */\n    protected transient MessageProcessor messageProcessor;\n\n    /**\n     * Close the message channel.\n     */\n    public abstract void close();\n\n    /**\n     * Get the SIPStack object from this message channel.\n     * \n     * @return SIPStack object of this message channel\n     */\n    public abstract SIPTransactionStack getSIPStack();\n\n    /**\n     * Get transport string of this message channel.\n     * \n     * @return Transport string of this message channel.\n     */\n    public abstract String getTransport();\n\n    /**\n     * Get whether this channel is reliable or not.\n     * \n     * @return True if reliable, false if not.\n     */\n    public abstract boolean isReliable();\n\n    /**\n     * Return true if this is a secure channel.\n     */\n    public abstract boolean isSecure();\n\n    /**\n     * Send the message (after it has been formatted)\n     * \n     * @param sipMessage Message to send.\n     */\n    public abstract void sendMessage(SIPMessage sipMessage) throws IOException;\n\n    /**\n     * Get the peer address of the machine that sent us this message.\n     * \n     * @return a string contianing the ip address or host name of the sender of the message.\n     */\n    public abstract String getPeerAddress();\n\n    protected abstract InetAddress getPeerInetAddress();\n\n    protected abstract String getPeerProtocol();\n\n    /**\n     * Get the sender port ( the port of the other end that sent me the message).\n     */\n    public abstract int getPeerPort();\n\n    public abstract int getPeerPacketSourcePort();\n\n    public abstract InetAddress getPeerPacketSourceAddress();\n\n    /**\n     * Generate a key which identifies the message channel. This allows us to cache the message\n     * channel.\n     */\n    public abstract String getKey();\n\n    /**\n     * Get the host to assign for an outgoing Request via header.\n     */\n    public abstract String getViaHost();\n\n    /**\n     * Get the port to assign for the via header of an outgoing message.\n     */\n    public abstract int getViaPort();\n\n    /**\n     * Send the message (after it has been formatted), to a specified address and a specified port\n     * \n     * @param message Message to send.\n     * @param receiverAddress Address of the receiver.\n     * @param receiverPort Port of the receiver.\n     */\n    protected abstract void sendMessage(SIPMessage message, InetAddress receiverAddress,\n            int receiverPort, boolean reconnectFlag) throws IOException;\n\n    /**\n     * Get the host of this message channel.\n     * \n     * @return host of this messsage channel.\n     */\n    public String getHost() {\n        return this.getMessageProcessor().getIpAddress().getHostAddress();\n    }\n\n    /**\n     * Get port of this message channel.\n     * \n     * @return Port of this message channel.\n     */\n    public int getPort() {\n        if (this.messageProcessor != null)\n            return messageProcessor.getPort();\n        else\n            return -1;\n    }\n\n    /**\n     * Send a formatted message to the specified target.\n     * \n     * @param sipMessage Message to send.\n     * @param hop hop to send it to.\n     * @throws IOException If there is an error sending the message\n     */\n    public void sendMessage(SIPMessage sipMessage, Hop hop) throws IOException {\n        long time = System.currentTimeMillis();\n        InetAddress hopAddr = InetAddress.getByName(hop.getHost());\n\n        try {\n\n            for (MessageProcessor messageProcessor : getSIPStack().getMessageProcessors()) {\n                if (messageProcessor.getIpAddress().equals(hopAddr)\n                        && messageProcessor.getPort() == hop.getPort()\n                        && messageProcessor.getTransport().equals(hop.getTransport())) {\n                    MessageChannel messageChannel = messageProcessor.createMessageChannel(\n                            hopAddr, hop.getPort());\n                    if (messageChannel instanceof RawMessageChannel) {\n                        ((RawMessageChannel) messageChannel).processMessage(sipMessage);\n                        if (getSIPStack().isLoggingEnabled())\n                        \tgetSIPStack().getStackLogger().logDebug(\"Self routing message\");\n                        return;\n                    }\n\n                }\n            }\n\n            this.sendMessage(sipMessage, hopAddr, hop.getPort(), sipMessage instanceof SIPRequest);\n\n        } catch (IOException ioe) {\n            throw ioe;\n        } catch (Exception ex) {\n        \tif (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {\n        \t\tthis.getSIPStack().getStackLogger().logError(\"Error self routing message cause by: \", ex);\n        \t}\n        \t// TODO: When moving to Java 6, use the IOExcpetion(message, exception) constructor\n            throw new IOException(\"Error self routing message\");\n        } finally {\n\n            if (this.getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))\n                logMessage(sipMessage, hopAddr, hop.getPort(), time);\n        }\n    }\n\n    /**\n     * Send a message given SIP message.\n     * \n     * @param sipMessage is the messge to send.\n     * @param receiverAddress is the address to which we want to send\n     * @param receiverPort is the port to which we want to send\n     */\n    public void sendMessage(SIPMessage sipMessage, InetAddress receiverAddress, int receiverPort)\n            throws IOException {\n        long time = System.currentTimeMillis();\n        sendMessage(sipMessage, receiverAddress, receiverPort, sipMessage instanceof SIPRequest);\n        logMessage(sipMessage, receiverAddress, receiverPort, time);\n    }\n\n    /**\n     * Convenience function to get the raw IP source address of a SIP message as a String.\n     */\n    public String getRawIpSourceAddress() {\n        String sourceAddress = getPeerAddress();\n        String rawIpSourceAddress = null;\n        try {\n            InetAddress sourceInetAddress = InetAddress.getByName(sourceAddress);\n            rawIpSourceAddress = sourceInetAddress.getHostAddress();\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n        return rawIpSourceAddress;\n    }\n\n    /**\n     * generate a key given the inet address port and transport.\n     */\n    public static String getKey(InetAddress inetAddr, int port, String transport) {\n        return (transport + \":\" + inetAddr.getHostAddress() + \":\" + port).toLowerCase();\n    }\n\n    /**\n     * Generate a key given host and port.\n     */\n    public static String getKey(HostPort hostPort, String transport) {\n        return (transport + \":\" + hostPort.getHost().getHostname() + \":\" + hostPort.getPort())\n                .toLowerCase();\n    }\n\n    /**\n     * Get the hostport structure of this message channel.\n     */\n    public HostPort getHostPort() {\n        HostPort retval = new HostPort();\n        retval.setHost(new Host(this.getHost()));\n        retval.setPort(this.getPort());\n        return retval;\n    }\n\n    /**\n     * Get the peer host and port.\n     * \n     * @return a HostPort structure for the peer.\n     */\n    public HostPort getPeerHostPort() {\n        HostPort retval = new HostPort();\n        retval.setHost(new Host(this.getPeerAddress()));\n        retval.setPort(this.getPeerPort());\n        return retval;\n    }\n\n    /**\n     * Get the Via header for this transport. Note that this does not set a branch identifier.\n     * \n     * @return a via header for outgoing messages sent from this channel.\n     */\n    public Via getViaHeader() {\n        Via channelViaHeader;\n\n        channelViaHeader = new Via();\n        try {\n            channelViaHeader.setTransport(getTransport());\n        } catch (ParseException ex) {\n        }\n        channelViaHeader.setSentBy(getHostPort());\n        return channelViaHeader;\n    }\n\n    /**\n     * Get the via header host:port structure. This is extracted from the topmost via header of\n     * the request.\n     * \n     * @return a host:port structure\n     */\n    public HostPort getViaHostPort() {\n        HostPort retval = new HostPort();\n        retval.setHost(new Host(this.getViaHost()));\n        retval.setPort(this.getViaPort());\n        return retval;\n    }\n\n    /**\n     * Log a message sent to an address and port via the default interface.\n     * \n     * @param sipMessage is the message to log.\n     * @param address is the inet address to which the message is sent.\n     * @param port is the port to which the message is directed.\n     */\n    protected void logMessage(SIPMessage sipMessage, InetAddress address, int port, long time) {\n        if (!getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))\n            return;\n\n        // Default port.\n        if (port == -1)\n            port = 5060;\n        getSIPStack().serverLogger.logMessage(sipMessage, this.getHost() + \":\" + this.getPort(),\n                address.getHostAddress().toString() + \":\" + port, true, time);\n    }\n\n    /**\n     * Log a response received at this message channel. This is used for processing incoming\n     * responses to a client transaction.\n     * \n     * @param receptionTime is the time at which the response was received.\n     * @param status is the processing status of the message.\n     * \n     */\n    public void logResponse(SIPResponse sipResponse, long receptionTime, String status) {\n        int peerport = getPeerPort();\n        if (peerport == 0 && sipResponse.getContactHeaders() != null) {\n            ContactHeader contact = (ContactHeader) sipResponse.getContactHeaders().getFirst();\n            peerport = ((AddressImpl) contact.getAddress()).getPort();\n\n        }\n        String from = getPeerAddress().toString() + \":\" + peerport;\n        String to = this.getHost() + \":\" + getPort();\n        this.getSIPStack().serverLogger.logMessage(sipResponse, from, to, status, false,\n                receptionTime);\n    }\n\n    /**\n     * Creates a response to a bad request (ie one that causes a ParseException)\n     * \n     * @param badReq\n     * @return message bytes, null if unable to formulate response\n     */\n    protected final SIPMessage createBadReqRes(String badReq, ParseException pe) {\n\n        StringBuffer buf = new StringBuffer(512);\n        buf.append(\"SIP/2.0 400 Bad Request (\" + pe.getLocalizedMessage() + ')');\n\n        // We need the following headers: all Vias, CSeq, Call-ID, From, To\n        if (!copyViaHeaders(badReq, buf))\n            return null;\n        if (!copyHeader(CSeqHeader.NAME, badReq, buf))\n            return null;\n        if (!copyHeader(CallIdHeader.NAME, badReq, buf))\n            return null;\n        if (!copyHeader(FromHeader.NAME, badReq, buf))\n            return null;\n        if (!copyHeader(ToHeader.NAME, badReq, buf))\n            return null;\n\n        // Should add a to-tag if not already present...\n        int toStart = buf.indexOf(ToHeader.NAME);\n        if (toStart != -1 && buf.indexOf(\"tag\", toStart) == -1) {\n            buf.append(\";tag=badreq\");\n        }\n\n        // Let's add a Server header too..\n        ServerHeader s = MessageFactoryImpl.getDefaultServerHeader();\n        if ( s != null ) {\n            buf.append(\"\\r\\n\" + s.toString());\n        }\n        int clength = badReq.length();\n        if (! (this instanceof UDPMessageChannel) ||\n                clength + buf.length() + ContentTypeHeader.NAME.length()\n                + \": message/sipfrag\\r\\n\".length() +\n                ContentLengthHeader.NAME.length()  < 1300) { \n            \n            /*\n             * Check to see we are within one UDP packet.\n             */\n            ContentTypeHeader cth = new ContentType(\"message\", \"sipfrag\");\n            buf.append(\"\\r\\n\" + cth.toString());\n            ContentLength clengthHeader = new ContentLength(clength);\n            buf.append(\"\\r\\n\" + clengthHeader.toString());\n            buf.append(\"\\r\\n\\r\\n\" + badReq);\n        } else {\n            ContentLength clengthHeader = new ContentLength(0);\n            buf.append(\"\\r\\n\" + clengthHeader.toString());\n        }\n        \n\t\tStringMsgParser msgParser = new StringMsgParser();\n\t\ttry {\n\t\t\treturn msgParser.parseSIPMessage(buf.toString().getBytes());\n\t\t} catch (ParseException e) {\n\t\t\tInternalErrorHandler.handleException(e);\n\t\t}\n        \n        return null;\n    }\n\n    /**\n     * Copies a header from a request\n     * \n     * @param name\n     * @param fromReq\n     * @param buf\n     * @return\n     * \n     * Note: some limitations here: does not work for short forms of headers, or continuations;\n     * problems when header names appear in other parts of the request\n     */\n    private static final boolean copyHeader(String name, String fromReq, StringBuffer buf) {\n        int start = fromReq.indexOf(name);\n        if (start != -1) {\n            int end = fromReq.indexOf(\"\\r\\n\", start);\n            if (end != -1) {\n                // XX Assumes no continuation here...\n                buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF\n                // in front\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Copies all via headers from a request\n     * \n     * @param fromReq\n     * @param buf\n     * @return\n     * \n     * Note: some limitations here: does not work for short forms of headers, or continuations\n     */\n    private static final boolean copyViaHeaders(String fromReq, StringBuffer buf) {\n        int start = fromReq.indexOf(ViaHeader.NAME);\n        boolean found = false;\n        while (start != -1) {\n            int end = fromReq.indexOf(\"\\r\\n\", start);\n            if (end != -1) {\n                // XX Assumes no continuation here...\n                buf.append(fromReq.subSequence(start - 2, end)); // incl CRLF\n                // in front\n                found = true;\n                start = fromReq.indexOf(ViaHeader.NAME, end);\n            } else {\n                return false;\n            }\n        }\n        return found;\n    }\n\n    /**\n     * Get the message processor.\n     */\n    public MessageProcessor getMessageProcessor() {\n        return this.messageProcessor;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/MessageLog.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\n\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.javax2.sip.LogRecord;\n\n/**\n * This class stores a message along with some other informations\n * Used to log messages.\n *\n *@version 1.2 $Revision: 1.9 $ $Date: 2009/07/17 18:58:13 $\n *\n * @author M. Ranganathan   <br/>\n * @author Marc Bednarek  <br/>\n *\n *\n */\nclass MessageLog implements LogRecord {\n\n    private String message;\n\n    private String source;\n\n    private String destination;\n\n    private long timeStamp;\n\n    private boolean isSender;\n\n    private String firstLine;\n\n    private String tid;\n\n    private String callId;\n\n    private long timeStampHeaderValue;\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.stack.LogRecord#equals(java.lang.Object)\n     */\n    public boolean equals(Object other) {\n        if (!(other instanceof MessageLog)) {\n            return false;\n        } else {\n            MessageLog otherLog = (MessageLog) other;\n            return otherLog.message.equals(message)\n                && otherLog.timeStamp == timeStamp;\n        }\n    }\n\n    /**\n     * Constructor\n     */\n\n    public MessageLog(\n        String message,\n        String source,\n        String destination,\n        String timeStamp,\n        boolean isSender,\n        String firstLine,\n        String tid,\n        String callId,\n        long timeStampHeaderValue) {\n        if (message == null || message.equals(\"\"))\n            throw new IllegalArgumentException(\"null msg\");\n        this.message = message;\n        this.source = source;\n        this.destination = destination;\n        try {\n            long ts = Long.parseLong(timeStamp);\n            if (ts < 0)\n                throw new IllegalArgumentException(\"Bad time stamp \");\n            this.timeStamp = ts;\n        } catch (NumberFormatException ex) {\n            throw new IllegalArgumentException(\n                \"Bad number format \" + timeStamp);\n        }\n        this.isSender = isSender;\n        this.firstLine = firstLine;\n        this.tid = tid;\n        this.callId = callId;\n        this.timeStampHeaderValue = timeStampHeaderValue;\n    }\n\n\n\n    public MessageLog(\n        String message,\n        String source,\n        String destination,\n        long timeStamp,\n        boolean isSender,\n        String firstLine,\n        String tid,\n        String callId,\n        long timestampVal) {\n        if (message == null || message.equals(\"\"))\n            throw new IllegalArgumentException(\"null msg\");\n        this.message = message;\n        this.source = source;\n        this.destination = destination;\n        if (timeStamp < 0)\n            throw new IllegalArgumentException(\"negative ts\");\n        this.timeStamp = timeStamp;\n        this.isSender = isSender;\n        this.firstLine = firstLine;\n        this.tid = tid;\n        this.callId = callId;\n        this.timeStampHeaderValue = timestampVal;\n    }\n\n\n    /* (non-Javadoc)\n     * @see gov2.nist.javax2.sip.stack.LogRecord#toString()\n     */\n\n    public String toString() {\n        String log;\n\n\n            log =\n                \"<message\\nfrom=\\\"\"\n                    + source\n                    + \"\\\" \\nto=\\\"\"\n                    + destination\n                    + \"\\\" \\ntime=\\\"\"\n                    + timeStamp\n                    + \"\\\"\" +\n                    (this.timeStampHeaderValue != 0 ? \"\\ntimeStamp = \\\"\" + timeStampHeaderValue + \"\\\"\": \"\")\n                    +\"\\nisSender=\\\"\"\n                    + isSender\n                    + \"\\\" \\ntransactionId=\\\"\"\n                    + tid\n                    + \"\\\" \\ncallId=\\\"\"\n                    + callId\n                    + \"\\\" \\nfirstLine=\\\"\"\n                    + firstLine.trim() + \"\\\"\" +\n                    \" \\n>\\n\";\n            log += \"<![CDATA[\";\n            log += message;\n            log += \"]]>\\n\";\n            log += \"</message>\\n\";\n\n        return log;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/MessageProcessor.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.Host;\nimport gov2.nist.core.HostPort;\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.ListeningPointImpl;\nimport gov2.nist.javax2.sip.header.Via;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\n/**\n * This is the Stack abstraction for the active object that waits for messages\n * to appear on the wire and processes these messages by calling the\n * MessageFactory interface to create a ServerRequest or ServerResponse object.\n * The main job of the message processor is to instantiate message channels for\n * the given transport.\n *\n * @version 1.2 $Revision: 1.18 $ $Date: 2009/10/16 22:58:41 $\n *\n * @author M. Ranganathan <br/>\n *\n */\npublic abstract class MessageProcessor implements Runnable {\n    /**\n     * A string containing the 0.0.0.0 IPv4 ANY address.\n     */\n    protected static final String IN_ADDR_ANY = \"0.0.0.0\";\n\n    /**\n     * A string containing the ::0 IPv6 ANY address.\n     */\n    protected static final String IN6_ADDR_ANY = \"::0\";\n    /**\n     * My Sent by string ( which I use to set the outgoing via header)\n     */\n    private  String sentBy;\n\n    private HostPort sentByHostPort;\n\n    /*\n     * The IP Address that was originally assigned ( Can be ANY )\n     */\n\n    private String savedIpAddress;\n\n    /**\n     * The IP address where I am listening.\n     */\n    private InetAddress ipAddress;\n\n    /**\n     * The port where I am listening\n     */\n    private int port;\n\n    /**\n     * The transport where I am listening\n     */\n    protected String transport;\n\n    /**\n     * The Listening Point to which I am assigned.\n     */\n    private ListeningPointImpl listeningPoint;\n\n    private boolean sentBySet;\n\n    /**\n     * Our stack (that created us).\n     */\n    protected SIPTransactionStack sipStack;\n    \n    protected MessageProcessor( String transport ) {\n    \tthis.transport = transport;\n    }\n    \n    /**\n     * Constructor\n     *\n     * @param ipAddress -- ip address where I am listening for incoming requests.\n     * @param port -- port where i am listening for incoming requests.\n     * @param transport -- transport to use for the message processor (UDP/TCP/TLS).\n     */\n    protected MessageProcessor( InetAddress ipAddress, int port, String transport,\n    \t\t\t\t\t\t\tSIPTransactionStack transactionStack ) {\n    \tthis( transport );\n    \tthis.initialize(ipAddress, port, transactionStack);\n    }\n\n    /**\n     * Initializes this MessageProcessor. Needed for extensions\n     * that use classloading\n     * \n     * @param ipAddress2\n     * @param transactionStack\n     * @param port2\n     */\n\tpublic final void initialize( InetAddress ipAddress, int port,\n\t\t\tSIPTransactionStack transactionStack ) {\n\t\t\n\t\tthis.sipStack = transactionStack;\n        this.savedIpAddress = ipAddress.getHostAddress();\n        this.ipAddress = ipAddress;\n        this.port = port;\n        this.sentByHostPort = new HostPort();\n        this.sentByHostPort.setHost(new Host(ipAddress.getHostAddress()));\n        this.sentByHostPort.setPort(port);\t\t\n\t}\n    \n    /**\n     * Get the transport string.\n     *\n     * @return A string that indicates the transport. (i.e. \"tcp\" or \"udp\")\n     */\n    public String getTransport() {\n        return this.transport;\n    }\n\n    /**\n     * Get the port identifier.\n     *\n     * @return the port for this message processor. This is where you receive\n     *         messages.\n     */\n    public int getPort() {\n        return this.port;\n    }\n\n    /**\n     * Get the Via header to assign for this message processor. The topmost via\n     * header of the outoging messages use this.\n     *\n     * @return the ViaHeader to be used by the messages sent via this message processor.\n     */\n    public Via getViaHeader() {\n        try {\n            Via via = new Via();\n            if (this.sentByHostPort != null) {\n                via.setSentBy(sentByHostPort);\n                via.setTransport(this.getTransport());\n            } else {\n                Host host = new Host();\n                host.setHostname(this.getIpAddress().getHostAddress());\n                via.setHost(host);\n                via.setPort(this.getPort());\n                via.setTransport(this.getTransport());\n            }\n            return via;\n        } catch (ParseException ex) {\n            ex.printStackTrace();\n            return null;\n        } catch (InvalidArgumentException ex) {\n            ex.printStackTrace();\n            return null;\n        }\n    }\n    public ListeningPointImpl getListeningPoint() {\n        if ( listeningPoint == null )  {\n            if ( this.getSIPStack().isLoggingEnabled()) {\n                this.getSIPStack().getStackLogger().logError(\"getListeningPoint\" + this +\n                        \" returning null listeningpoint\");\n\n            }\n        }\n        return listeningPoint;\n    }\n\n    public void setListeningPoint(ListeningPointImpl lp) {\n        if ( this.getSIPStack().isLoggingEnabled()) {\n            this.getSIPStack().getStackLogger().logDebug(\"setListeningPoint\" + this +\n                    \" listeningPoint = \" + lp);\n\n        }\n        if ( lp.getPort() != this.getPort())\n            InternalErrorHandler.handleException\n            (\"lp mismatch with provider\",getSIPStack().getStackLogger());\n        this.listeningPoint = lp;\n\n    }\n\n    /**\n     * Get the saved IP Address.\n     */\n    public String getSavedIpAddress() {\n        return this.savedIpAddress;\n    }\n    /**\n     * @return the ip address for this message processor.\n     */\n    public InetAddress getIpAddress() {\n          return this.ipAddress;\n    }\n    /**\n     * @param ipAddress the ipAddress to set\n     */\n    protected void setIpAddress(InetAddress ipAddress) {\n        this.sentByHostPort.setHost( new Host(ipAddress.getHostAddress()));\n        this.ipAddress = ipAddress;\n    }\n\n    /**\n     * Set the sentby string. This is used for stamping outgoing messages sent\n     * from this listening point.\n     *\n     * @param sentBy\n     */\n    public void setSentBy(String sentBy) throws ParseException {\n\n        int ind = sentBy.indexOf(\":\");\n        if (ind == -1) {\n            this.sentByHostPort = new HostPort();\n            this.sentByHostPort.setHost(new Host(sentBy));\n        } else {\n            this.sentByHostPort = new HostPort();\n            this.sentByHostPort.setHost(new Host(sentBy.substring(0, ind)));\n            String portStr = sentBy.substring(ind + 1);\n            try {\n                int port = Integer.parseInt(portStr);\n                this.sentByHostPort.setPort(port);\n            } catch (NumberFormatException ex) {\n                throw new ParseException(\"Bad format encountered at \", ind);\n            }\n        }\n        this.sentBySet = true;\n        this.sentBy = sentBy;\n\n    }\n\n    /**\n     * Get the sentby string.\n     *\n     */\n    public String getSentBy() {\n        if ( this.sentBy == null && this.sentByHostPort != null) {\n            this.sentBy = this.sentByHostPort.toString();\n        }\n        return this.sentBy;\n    }\n\n    ////////////////////////////////////////////////////////////////////////////////////////\n    // Abstract methods\n    ///////////////////////////////////////////////////////////////////////////////////////\n    /**\n     * Get the SIP Stack.\n     *\n     * @return the sip stack.\n     */\n    public abstract SIPTransactionStack getSIPStack();\n\n    /**\n     * Create a message channel for the specified host/port.\n     *\n     * @return New MessageChannel for this processor.\n     */\n    public abstract MessageChannel createMessageChannel(HostPort targetHostPort)\n            throws IOException;\n\n    /**\n     * Create a message channel for the specified host/port.\n     *\n     * @return New MessageChannel for this processor.\n     */\n    public abstract MessageChannel createMessageChannel(InetAddress targetHost,\n            int port) throws IOException;\n\n\n    /**\n     * Start our thread.\n     */\n    public abstract void start() throws IOException;\n\n    /**\n     * Stop method.\n     */\n    public abstract void stop();\n\n    /**\n     * Default target port used by this processor. This is 5060 for TCP / UDP\n     */\n    public abstract int getDefaultTargetPort();\n\n    /**\n     * Flags whether this processor is secure or not.\n     */\n    public abstract boolean isSecure();\n\n    /**\n     * Maximum number of bytes that this processor can handle.\n     */\n    public abstract int getMaximumMessageSize();\n\n    /**\n     * Return true if there are pending messages to be processed (which prevents\n     * the message channel from being closed).\n     */\n    public abstract boolean inUse();\n\n\n\n    /**\n     * Run method.\n     */\n    public abstract void run();\n\n    /**\n     * @return Returns the sentBySet.\n     */\n    public boolean isSentBySet() {\n        return sentBySet;\n    }\n\n\n    /**\n     * Get the defalt port for the message processor.\n     *\n     * @param transport\n     * @return -- the default port for the message processor.\n     */\n\n    public static int getDefaultPort(String transport) {\n\n        return transport.equalsIgnoreCase(\"TLS\")?5061:5060;\n    }\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/RawMessageChannel.java",
    "content": "package gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.javax2.sip.message.SIPMessage;\n\npublic interface RawMessageChannel {\n\n    public abstract void processMessage(SIPMessage sipMessage) throws Exception ;\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPClientTransaction.java",
    "content": "/*\n * Conditions Of Use \n * \n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n * \n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *  \n * .\n * \n */\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.Utils;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.header.Contact;\nimport gov2.nist.javax2.sip.header.RecordRoute;\nimport gov2.nist.javax2.sip.header.RecordRouteList;\nimport gov2.nist.javax2.sip.header.Route;\nimport gov2.nist.javax2.sip.header.RouteList;\nimport gov2.nist.javax2.sip.header.TimeStamp;\nimport gov2.nist.javax2.sip.header.To;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.io.IOException;\nimport java.security.cert.X509Certificate;\nimport java.text.ParseException;\nimport java.util.ListIterator;\nimport java.util.TimerTask;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport javax.net.ssl.SSLPeerUnverifiedException;\nimport javax2.sip.Dialog;\nimport javax2.sip.DialogState;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.SipException;\nimport javax2.sip.Timeout;\nimport javax2.sip.TimeoutEvent;\nimport javax2.sip.TransactionState;\nimport javax2.sip.address.Hop;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.TimeStampHeader;\nimport javax2.sip.message.Request;\n\n/*\n * Jeff Keyser -- initial. Daniel J. Martinez Manzano --Added support for TLS message channel.\n * Emil Ivov -- bug fixes. Chris Beardshear -- bug fix. Andreas Bystrom -- bug fixes. Matt Keller\n * (Motorolla) -- bug fix.\n */\n\n/**\n * Represents a client transaction. Implements the following state machines. (From RFC 3261)\n * \n * <pre>\n *                   \n *                    \n *                     \n *                      \n *                      \n *                      \n *                                                     |INVITE from TU\n *                                   Timer A fires     |INVITE sent\n *                                   Reset A,          V                      Timer B fires\n *                                   INVITE sent +-----------+                or Transport Err.\n *                                     +---------|           |---------------+inform TU\n *                                     |         |  Calling  |               |\n *                                     +--------&gt;|           |--------------&gt;|\n *                                               +-----------+ 2xx           |\n *                                                  |  |       2xx to TU     |\n *                                                  |  |1xx                  |\n *                          300-699 +---------------+  |1xx to TU            |\n *                         ACK sent |                  |                     |\n *                      resp. to TU |  1xx             V                     |\n *                                  |  1xx to TU  -----------+               |\n *                                  |  +---------|           |               |\n *                                  |  |         |Proceeding |--------------&gt;|\n *                                  |  +--------&gt;|           | 2xx           |\n *                                  |            +-----------+ 2xx to TU     |\n *                                  |       300-699    |                     |\n *                                  |       ACK sent,  |                     |\n *                                  |       resp. to TU|                     |\n *                                  |                  |                     |      NOTE:\n *                                  |  300-699         V                     |\n *                                  |  ACK sent  +-----------+Transport Err. |  transitions\n *                                  |  +---------|           |Inform TU      |  labeled with\n *                                  |  |         | Completed |--------------&gt;|  the event\n *                                  |  +--------&gt;|           |               |  over the action\n *                                  |            +-----------+               |  to take\n *                                  |              &circ;   |                     |\n *                                  |              |   | Timer D fires       |\n *                                  +--------------+   | -                   |\n *                                                     |                     |\n *                                                     V                     |\n *                                               +-----------+               |\n *                                               |           |               |\n *                                               | Terminated|&lt;--------------+\n *                                               |           |\n *                                               +-----------+\n *                      \n *                                       Figure 5: INVITE client transaction\n *                      \n *                      \n *                                                         |Request from TU\n *                                                         |send request\n *                                     Timer E             V\n *                                     send request  +-----------+\n *                                         +---------|           |-------------------+\n *                                         |         |  Trying   |  Timer F          |\n *                                         +--------&gt;|           |  or Transport Err.|\n *                                                   +-----------+  inform TU        |\n *                                      200-699         |  |                         |\n *                                      resp. to TU     |  |1xx                      |\n *                                      +---------------+  |resp. to TU              |\n *                                      |                  |                         |\n *                                      |   Timer E        V       Timer F           |\n *                                      |   send req +-----------+ or Transport Err. |\n *                                      |  +---------|           | inform TU         |\n *                                      |  |         |Proceeding |------------------&gt;|\n *                                      |  +--------&gt;|           |-----+             |\n *                                      |            +-----------+     |1xx          |\n *                                      |              |      &circ;        |resp to TU   |\n *                                      | 200-699      |      +--------+             |\n *                                      | resp. to TU  |                             |\n *                                      |              |                             |\n *                                      |              V                             |\n *                                      |            +-----------+                   |\n *                                      |            |           |                   |\n *                                      |            | Completed |                   |\n *                                      |            |           |                   |\n *                                      |            +-----------+                   |\n *                                      |              &circ;   |                         |\n *                                      |              |   | Timer K                 |\n *                                      +--------------+   | -                       |\n *                                                         |                         |\n *                                                         V                         |\n *                                   NOTE:           +-----------+                   |\n *                                                   |           |                   |\n *                               transitions         | Terminated|&lt;------------------+\n *                               labeled with        |           |\n *                               the event           +-----------+\n *                               over the action\n *                               to take\n *                      \n *                                       Figure 6: non-INVITE client transaction\n *                      \n *                      \n *                      \n *                      \n *                     \n *                    \n * </pre>\n * \n * \n * @author M. Ranganathan\n * \n * @version 1.2 $Revision: 1.122 $ $Date: 2009/12/17 23:33:52 $\n */\npublic class SIPClientTransaction extends SIPTransaction implements ServerResponseInterface,\n        javax2.sip.ClientTransaction, gov2.nist.javax2.sip.ClientTransactionExt {\n\n    // a SIP Client transaction may belong simultaneously to multiple\n    // dialogs in the early state. These dialogs all have\n    // the same call ID and same From tag but different to tags.\n\n    private ConcurrentHashMap<String,SIPDialog> sipDialogs;\n\n    private SIPRequest lastRequest;\n\n    private int viaPort;\n\n    private String viaHost;\n\n    // Real ResponseInterface to pass messages to\n    private transient ServerResponseInterface respondTo;\n\n    private SIPDialog defaultDialog;\n\n    private Hop nextHop;\n\n    private boolean notifyOnRetransmit;\n\n    private boolean timeoutIfStillInCallingState;\n\n    private int callingStateTimeoutCount;\n\n    public class TransactionTimer extends SIPStackTimerTask {\n\n        public TransactionTimer() {\n\n        }\n\n        protected void runTask() {\n            SIPClientTransaction clientTransaction;\n            SIPTransactionStack sipStack;\n            clientTransaction = SIPClientTransaction.this;\n            sipStack = clientTransaction.sipStack;\n\n            // If the transaction has terminated,\n            if (clientTransaction.isTerminated()) {\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"removing  = \" + clientTransaction + \" isReliable \"\n                                    + clientTransaction.isReliable());\n                }\n\n                sipStack.removeTransaction(clientTransaction);\n\n                try {\n                    this.cancel();\n\n                } catch (IllegalStateException ex) {\n                    if (!sipStack.isAlive())\n                        return;\n                }\n\n                // Client transaction terminated. Kill connection if\n                // this is a TCP after the linger timer has expired.\n                // The linger timer is needed to allow any pending requests to\n                // return responses.\n                if ((!sipStack.cacheClientConnections) && clientTransaction.isReliable()) {\n\n                    int newUseCount = --clientTransaction.getMessageChannel().useCount;\n                    if (newUseCount <= 0) {\n                        // Let the connection linger for a while and then close\n                        // it.\n                        TimerTask myTimer = new LingerTimer();\n                        sipStack.getTimer().schedule(myTimer,\n                                SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);\n                    }\n\n                } else {\n                    // Cache the client connections so dont close the\n                    // connection. This keeps the connection open permanently\n                    // until the client disconnects.\n                    if (sipStack.isLoggingEnabled() && clientTransaction.isReliable()) {\n                       \tint useCount = clientTransaction.getMessageChannel().useCount;\n                       \tif (sipStack.isLoggingEnabled())\n                       \t\tsipStack.getStackLogger().logDebug(\"Client Use Count = \" + useCount);\n                    }\n                }\n\n            } else {\n                // If this transaction has not\n                // terminated,\n                // Fire the transaction timer.\n                clientTransaction.fireTimer();\n\n            }\n\n        }\n\n    }\n\n    /**\n     * Creates a new client transaction.\n     * \n     * @param newSIPStack Transaction stack this transaction belongs to.\n     * @param newChannelToUse Channel to encapsulate.\n     * @return the created client transaction.\n     */\n    protected SIPClientTransaction(SIPTransactionStack newSIPStack, MessageChannel newChannelToUse) {\n        super(newSIPStack, newChannelToUse);\n        // Create a random branch parameter for this transaction\n        // setBranch( SIPConstants.BRANCH_MAGIC_COOKIE +\n        // Integer.toHexString( hashCode( ) ) );\n        setBranch(Utils.getInstance().generateBranchId());\n        this.messageProcessor = newChannelToUse.messageProcessor;\n        this.setEncapsulatedChannel(newChannelToUse);\n        this.notifyOnRetransmit = false;\n        this.timeoutIfStillInCallingState = false;\n\n        // This semaphore guards the listener from being\n        // re-entered for this transaction. That is\n        // for a give tx, the listener is called at most\n        // once with an outstanding request.\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"Creating clientTransaction \" + this);\n            sipStack.getStackLogger().logStackTrace();\n        }\n        // this.startTransactionTimer();\n        this.sipDialogs = new ConcurrentHashMap();\n    }\n\n    /**\n     * Sets the real ResponseInterface this transaction encapsulates.\n     * \n     * @param newRespondTo ResponseInterface to send messages to.\n     */\n    public void setResponseInterface(ServerResponseInterface newRespondTo) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"Setting response interface for \" + this + \" to \" + newRespondTo);\n            if (newRespondTo == null) {\n                sipStack.getStackLogger().logStackTrace();\n                sipStack.getStackLogger().logDebug(\"WARNING -- setting to null!\");\n            }\n        }\n\n        respondTo = newRespondTo;\n\n    }\n\n    /**\n     * Returns this transaction.\n     */\n    public MessageChannel getRequestChannel() {\n\n        return this;\n\n    }\n\n    /**\n     * Deterines if the message is a part of this transaction.\n     * \n     * @param messageToTest Message to check if it is part of this transaction.\n     * \n     * @return true if the message is part of this transaction, false if not.\n     */\n    public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {\n\n        // List of Via headers in the message to test\n        ViaList viaHeaders = messageToTest.getViaHeaders();\n        // Flags whether the select message is part of this transaction\n        boolean transactionMatches;\n        String messageBranch = ((Via) viaHeaders.getFirst()).getBranch();\n        boolean rfc3261Compliant = getBranch() != null\n                && messageBranch != null\n                && getBranch().toLowerCase().startsWith(\n                        SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)\n                && messageBranch.toLowerCase().startsWith(\n                        SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE);\n\n        transactionMatches = false;\n        if (TransactionState.COMPLETED == this.getState()) {\n            if (rfc3261Compliant) {\n                transactionMatches = getBranch().equalsIgnoreCase(\n                        ((Via) viaHeaders.getFirst()).getBranch())\n                        && getMethod().equals(messageToTest.getCSeq().getMethod());\n            } else {\n                transactionMatches = getBranch().equals(messageToTest.getTransactionId());\n            }\n        } else if (!isTerminated()) {\n            if (rfc3261Compliant) {\n                if (viaHeaders != null) {\n                    // If the branch parameter is the\n                    // same as this transaction and the method is the same,\n                    if (getBranch().equalsIgnoreCase(((Via) viaHeaders.getFirst()).getBranch())) {\n                        transactionMatches = getOriginalRequest().getCSeq().getMethod().equals(\n                                messageToTest.getCSeq().getMethod());\n\n                    }\n                }\n            } else {\n                // not RFC 3261 compliant.\n                if (getBranch() != null) {\n                    transactionMatches = getBranch().equalsIgnoreCase(\n                            messageToTest.getTransactionId());\n                } else {\n                    transactionMatches = getOriginalRequest().getTransactionId()\n                            .equalsIgnoreCase(messageToTest.getTransactionId());\n                }\n\n            }\n\n        }\n        return transactionMatches;\n\n    }\n\n    /**\n     * Send a request message through this transaction and onto the client.\n     * \n     * @param messageToSend Request to process and send.\n     */\n    public void sendMessage(SIPMessage messageToSend) throws IOException {\n\n        try {\n            // Message typecast as a request\n            SIPRequest transactionRequest;\n\n            transactionRequest = (SIPRequest) messageToSend;\n\n            // Set the branch id for the top via header.\n            Via topVia = (Via) transactionRequest.getViaHeaders().getFirst();\n            // Tack on a branch identifier to match responses.\n            try {\n                topVia.setBranch(getBranch());\n            } catch (java.text.ParseException ex) {\n            }\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"Sending Message \" + messageToSend);\n                sipStack.getStackLogger().logDebug(\"TransactionState \" + this.getState());\n            }\n            // If this is the first request for this transaction,\n            if (TransactionState.PROCEEDING == getState()\n                    || TransactionState.CALLING == getState()) {\n\n                // If this is a TU-generated ACK request,\n                if (transactionRequest.getMethod().equals(Request.ACK)) {\n\n                    // Send directly to the underlying\n                    // transport and close this transaction\n                    if (isReliable()) {\n                        this.setState(TransactionState.TERMINATED);\n                    } else {\n                        this.setState(TransactionState.COMPLETED);\n                    }\n                    // BUGBUG -- This suppresses sending the ACK uncomment this\n                    // to\n                    // test 4xx retransmission\n                    // if (transactionRequest.getMethod() != Request.ACK)\n                    super.sendMessage(transactionRequest);\n                    return;\n\n                }\n\n            }\n            try {\n\n                // Send the message to the server\n                lastRequest = transactionRequest;\n                if (getState() == null) {\n                    // Save this request as the one this transaction\n                    // is handling\n                    setOriginalRequest(transactionRequest);\n                    // Change to trying/calling state\n                    // Set state first to avoid race condition..\n\n                    if (transactionRequest.getMethod().equals(Request.INVITE)) {\n                        this.setState(TransactionState.CALLING);\n                    } else if (transactionRequest.getMethod().equals(Request.ACK)) {\n                        // Acks are never retransmitted.\n                        this.setState(TransactionState.TERMINATED);\n                    } else {\n                        this.setState(TransactionState.TRYING);\n                    }\n                    if (!isReliable()) {\n                        enableRetransmissionTimer();\n                    }\n                    if (isInviteTransaction()) {\n                        enableTimeoutTimer(TIMER_B);\n                    } else {\n                        enableTimeoutTimer(TIMER_F);\n                    }\n                }\n                // BUGBUG This supresses sending ACKS -- uncomment to test\n                // 4xx retransmission.\n                // if (transactionRequest.getMethod() != Request.ACK)\n                super.sendMessage(transactionRequest);\n\n            } catch (IOException e) {\n\n                this.setState(TransactionState.TERMINATED);\n                throw e;\n\n            }\n        } finally {\n            this.isMapped = true;\n            this.startTransactionTimer();\n\n        }\n\n    }\n\n    /**\n     * Process a new response message through this transaction. If necessary, this message will\n     * also be passed onto the TU.\n     * \n     * @param transactionResponse Response to process.\n     * @param sourceChannel Channel that received this message.\n     */\n    public synchronized void processResponse(SIPResponse transactionResponse,\n            MessageChannel sourceChannel, SIPDialog dialog) {\n\n        // If the state has not yet been assigned then this is a\n        // spurious response.\n\n        if (getState() == null)\n            return;\n\n        // Ignore 1xx\n        if ((TransactionState.COMPLETED == this.getState() || TransactionState.TERMINATED == this\n                .getState())\n                && transactionResponse.getStatusCode() / 100 == 1) {\n            return;\n        }\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"processing \" + transactionResponse.getFirstLine() + \"current state = \"\n                            + getState());\n            sipStack.getStackLogger().logDebug(\"dialog = \" + dialog);\n        }\n\n        this.lastResponse = transactionResponse;\n\n        /*\n         * JvB: this is now duplicate with code in the other processResponse\n         * \n         * if (dialog != null && transactionResponse.getStatusCode() != 100 &&\n         * (transactionResponse.getTo().getTag() != null || sipStack .isRfc2543Supported())) { //\n         * add the route before you process the response. dialog.setLastResponse(this,\n         * transactionResponse); this.setDialog(dialog, transactionResponse.getDialogId(false)); }\n         */\n\n        try {\n            if (isInviteTransaction())\n                inviteClientTransaction(transactionResponse, sourceChannel, dialog);\n            else\n                nonInviteClientTransaction(transactionResponse, sourceChannel, dialog);\n        } catch (IOException ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(ex);\n            this.setState(TransactionState.TERMINATED);\n            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);\n        }\n    }\n\n    /**\n     * Implements the state machine for invite client transactions.\n     * \n     * <pre>\n     *                   \n     *                    \n     *                     \n     *                      \n     *                      \n     *                                                         |Request from TU\n     *                                                         |send request\n     *                                     Timer E             V\n     *                                     send request  +-----------+\n     *                                         +---------|           |-------------------+\n     *                                         |         |  Trying   |  Timer F          |\n     *                                         +--------&gt;|           |  or Transport Err.|\n     *                                                   +-----------+  inform TU        |\n     *                                      200-699         |  |                         |\n     *                                      resp. to TU     |  |1xx                      |\n     *                                      +---------------+  |resp. to TU              |\n     *                                      |                  |                         |\n     *                                      |   Timer E        V       Timer F           |\n     *                                      |   send req +-----------+ or Transport Err. |\n     *                                      |  +---------|           | inform TU         |\n     *                                      |  |         |Proceeding |------------------&gt;|\n     *                                      |  +--------&gt;|           |-----+             |\n     *                                      |            +-----------+     |1xx          |\n     *                                      |              |      &circ;        |resp to TU   |\n     *                                      | 200-699      |      +--------+             |\n     *                                      | resp. to TU  |                             |\n     *                                      |              |                             |\n     *                                      |              V                             |\n     *                                      |            +-----------+                   |\n     *                                      |            |           |                   |\n     *                                      |            | Completed |                   |\n     *                                      |            |           |                   |\n     *                                      |            +-----------+                   |\n     *                                      |              &circ;   |                         |\n     *                                      |              |   | Timer K                 |\n     *                                      +--------------+   | -                       |\n     *                                                         |                         |\n     *                                                         V                         |\n     *                                   NOTE:           +-----------+                   |\n     *                                                   |           |                   |\n     *                               transitions         | Terminated|&lt;------------------+\n     *                               labeled with        |           |\n     *                               the event           +-----------+\n     *                               over the action\n     *                               to take\n     *                      \n     *                                       Figure 6: non-INVITE client transaction\n     *                      \n     *                      \n     *                     \n     *                    \n     * </pre>\n     * \n     * @param transactionResponse -- transaction response received.\n     * @param sourceChannel - source channel on which the response was received.\n     */\n    private void nonInviteClientTransaction(SIPResponse transactionResponse,\n            MessageChannel sourceChannel, SIPDialog sipDialog) throws IOException {\n        int statusCode = transactionResponse.getStatusCode();\n        if (TransactionState.TRYING == this.getState()) {\n            if (statusCode / 100 == 1) {\n                this.setState(TransactionState.PROCEEDING);\n                enableRetransmissionTimer(MAXIMUM_RETRANSMISSION_TICK_COUNT);\n                enableTimeoutTimer(TIMER_F);\n                // According to RFC, the TU has to be informed on\n                // this transition.\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, sipDialog);\n                } else {\n                    this.semRelease();\n                }\n            } else if (200 <= statusCode && statusCode <= 699) {\n                // Send the response up to the TU.\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, sipDialog);\n                } else {\n                    this.semRelease();\n                }\n                if (!isReliable()) {\n                    this.setState(TransactionState.COMPLETED);\n                    enableTimeoutTimer(TIMER_K);\n                } else {\n                    this.setState(TransactionState.TERMINATED);\n                }\n            }\n        } else if (TransactionState.PROCEEDING == this.getState()) {\n            if (statusCode / 100 == 1) {\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, sipDialog);\n                } else {\n                    this.semRelease();\n                }\n            } else if (200 <= statusCode && statusCode <= 699) {\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, sipDialog);\n                } else {\n                    this.semRelease();\n                }\n                disableRetransmissionTimer();\n                disableTimeoutTimer();\n                if (!isReliable()) {\n                    this.setState(TransactionState.COMPLETED);\n                    enableTimeoutTimer(TIMER_K);\n                } else {\n                    this.setState(TransactionState.TERMINATED);\n                }\n            }\n        } else {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \" Not sending response to TU! \" + getState());\n            }\n            this.semRelease();\n        }\n    }\n\n    /**\n     * Implements the state machine for invite client transactions.\n     * \n     * <pre>\n     *                   \n     *                    \n     *                     \n     *                      \n     *                      \n     *                                                     |INVITE from TU\n     *                                   Timer A fires     |INVITE sent\n     *                                   Reset A,          V                      Timer B fires\n     *                                   INVITE sent +-----------+                or Transport Err.\n     *                                     +---------|           |---------------+inform TU\n     *                                     |         |  Calling  |               |\n     *                                     +--------&gt;|           |--------------&gt;|\n     *                                               +-----------+ 2xx           |\n     *                                                  |  |       2xx to TU     |\n     *                                                  |  |1xx                  |\n     *                          300-699 +---------------+  |1xx to TU            |\n     *                         ACK sent |                  |                     |\n     *                      resp. to TU |  1xx             V                     |\n     *                                  |  1xx to TU  -----------+               |\n     *                                  |  +---------|           |               |\n     *                                  |  |         |Proceeding |--------------&gt;|\n     *                                  |  +--------&gt;|           | 2xx           |\n     *                                  |            +-----------+ 2xx to TU     |\n     *                                  |       300-699    |                     |\n     *                                  |       ACK sent,  |                     |\n     *                                  |       resp. to TU|                     |\n     *                                  |                  |                     |      NOTE:\n     *                                  |  300-699         V                     |\n     *                                  |  ACK sent  +-----------+Transport Err. |  transitions\n     *                                  |  +---------|           |Inform TU      |  labeled with\n     *                                  |  |         | Completed |--------------&gt;|  the event\n     *                                  |  +--------&gt;|           |               |  over the action\n     *                                  |            +-----------+               |  to take\n     *                                  |              &circ;   |                     |\n     *                                  |              |   | Timer D fires       |\n     *                                  +--------------+   | -                   |\n     *                                                     |                     |\n     *                                                     V                     |\n     *                                               +-----------+               |\n     *                                               |           |               |\n     *                                               | Terminated|&lt;--------------+\n     *                                               |           |\n     *                                               +-----------+\n     *                      \n     *                      \n     *                     \n     *                    \n     * </pre>\n     * \n     * @param transactionResponse -- transaction response received.\n     * @param sourceChannel - source channel on which the response was received.\n     */\n\n    private void inviteClientTransaction(SIPResponse transactionResponse,\n            MessageChannel sourceChannel, SIPDialog dialog) throws IOException {\n        int statusCode = transactionResponse.getStatusCode();\n       \n        if (TransactionState.TERMINATED == this.getState()) {\n            boolean ackAlreadySent = false;\n            if (dialog != null && dialog.isAckSeen() && dialog.getLastAckSent() != null) {\n                if (dialog.getLastAckSent().getCSeq().getSeqNumber() == transactionResponse.getCSeq()\n                        .getSeqNumber()\n                        && transactionResponse.getFromTag().equals(\n                                dialog.getLastAckSent().getFromTag())) {\n                    // the last ack sent corresponded to this response\n                    ackAlreadySent = true;\n                }\n            }\n            // retransmit the ACK for this response.\n            if (dialog!= null && ackAlreadySent\n                    && transactionResponse.getCSeq().getMethod().equals(dialog.getMethod())) {\n                try {\n                    // Found the dialog - resend the ACK and\n                    // dont pass up the null transaction\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\"resending ACK\");\n\n                    dialog.resendAck();\n                } catch (SipException ex) {\n                    // What to do here ?? kill the dialog?\n                }\n            }\n\n            this.semRelease();\n            return;\n        } else if (TransactionState.CALLING == this.getState()) {\n            if (statusCode / 100 == 2) {\n\n                // JvB: do this ~before~ calling the application, to avoid\n                // retransmissions\n                // of the INVITE after app sends ACK\n                disableRetransmissionTimer();\n                disableTimeoutTimer();\n                this.setState(TransactionState.TERMINATED);\n\n                // 200 responses are always seen by TU.\n                if (respondTo != null)\n                    respondTo.processResponse(transactionResponse, this, dialog);\n                else {\n                    this.semRelease();\n                }\n\n            } else if (statusCode / 100 == 1) {\n                disableRetransmissionTimer();\n                disableTimeoutTimer();\n                this.setState(TransactionState.PROCEEDING);\n\n                if (respondTo != null)\n                    respondTo.processResponse(transactionResponse, this, dialog);\n                else {\n                    this.semRelease();\n                }\n\n            } else if (300 <= statusCode && statusCode <= 699) {\n                // Send back an ACK request\n\n                try {\n                    sendMessage((SIPRequest) createErrorAck());\n\n                } catch (Exception ex) {\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logError(\n                            \"Unexpected Exception sending ACK -- sending error AcK \", ex);\n\n                }\n\n                /*\n                 * When in either the \"Calling\" or \"Proceeding\" states, reception of response with\n                 * status code from 300-699 MUST cause the client transaction to transition to\n                 * \"Completed\". The client transaction MUST pass the received response up to the\n                 * TU, and the client transaction MUST generate an ACK request.\n                 */\n\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, dialog);\n                } else {\n                    this.semRelease();\n                }\n\n                if (this.getDialog() != null &&  ((SIPDialog)this.getDialog()).isBackToBackUserAgent()) {\n                    ((SIPDialog) this.getDialog()).releaseAckSem();\n                }\n\n                if (!isReliable()) {\n                    this.setState(TransactionState.COMPLETED);\n                    enableTimeoutTimer(TIMER_D);\n                } else {\n                    // Proceed immediately to the TERMINATED state.\n                    this.setState(TransactionState.TERMINATED);\n                }\n            }\n        } else if (TransactionState.PROCEEDING == this.getState()) {\n            if (statusCode / 100 == 1) {\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, dialog);\n                } else {\n                    this.semRelease();\n                }\n            } else if (statusCode / 100 == 2) {\n                this.setState(TransactionState.TERMINATED);\n                if (respondTo != null) {\n                    respondTo.processResponse(transactionResponse, this, dialog);\n                } else {\n                    this.semRelease();\n                }\n\n            } else if (300 <= statusCode && statusCode <= 699) {\n                // Send back an ACK request\n                try {\n                    sendMessage((SIPRequest) createErrorAck());\n                } catch (Exception ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n\n                if (this.getDialog() != null) {\n                    ((SIPDialog) this.getDialog()).releaseAckSem();\n                }\n                // JvB: update state before passing to app\n                if (!isReliable()) {\n                    this.setState(TransactionState.COMPLETED);\n                    this.enableTimeoutTimer(TIMER_D);\n                } else {\n                    this.setState(TransactionState.TERMINATED);\n                }\n\n                // Pass up to the TU for processing.\n                if (respondTo != null)\n                    respondTo.processResponse(transactionResponse, this, dialog);\n                else {\n                    this.semRelease();\n                }\n\n                // JvB: duplicate with line 874\n                // if (!isReliable()) {\n                // enableTimeoutTimer(TIMER_D);\n                // }\n            }\n        } else if (TransactionState.COMPLETED == this.getState()) {\n            if (300 <= statusCode && statusCode <= 699) {\n                // Send back an ACK request\n                try {\n                    sendMessage((SIPRequest) createErrorAck());\n                } catch (Exception ex) {\n                    InternalErrorHandler.handleException(ex);\n                } finally {\n                    this.semRelease();\n                }\n            }\n\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.ClientTransaction#sendRequest()\n     */\n    public void sendRequest() throws SipException {\n        SIPRequest sipRequest = this.getOriginalRequest();\n\n        if (this.getState() != null)\n            throw new SipException(\"Request already sent\");\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"sendRequest() \" + sipRequest);\n        }\n\n        try {\n            sipRequest.checkHeaders();\n        } catch (ParseException ex) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logError(\"missing required header\");\n            throw new SipException(ex.getMessage());\n        }\n\n        if (getMethod().equals(Request.SUBSCRIBE)\n                && sipRequest.getHeader(ExpiresHeader.NAME) == null) {\n            /*\n             * If no \"Expires\" header is present in a SUBSCRIBE request, the implied default is\n             * defined by the event package being used.\n             * \n             */\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logWarning(\n                    \"Expires header missing in outgoing subscribe --\"\n                            + \" Notifier will assume implied value on event package\");\n        }\n        try {\n            /*\n             * This check is removed because it causes problems for load balancers ( See issue\n             * 136) reported by Raghav Ramesh ( BT )\n             * \n             */\n            if (this.getOriginalRequest().getMethod().equals(Request.CANCEL)\n                    && sipStack.isCancelClientTransactionChecked()) {\n                SIPClientTransaction ct = (SIPClientTransaction) sipStack.findCancelTransaction(\n                        this.getOriginalRequest(), false);\n                if (ct == null) {\n                    /*\n                     * If the original request has generated a final response, the CANCEL SHOULD\n                     * NOT be sent, as it is an effective no-op, since CANCEL has no effect on\n                     * requests that have already generated a final response.\n                     */\n                    throw new SipException(\"Could not find original tx to cancel. RFC 3261 9.1\");\n                } else if (ct.getState() == null) {\n                    throw new SipException(\n                            \"State is null no provisional response yet -- cannot cancel RFC 3261 9.1\");\n                } else if (!ct.getMethod().equals(Request.INVITE)) {\n                    throw new SipException(\"Cannot cancel non-invite requests RFC 3261 9.1\");\n                }\n            } else\n\n            if (this.getOriginalRequest().getMethod().equals(Request.BYE)\n                    || this.getOriginalRequest().getMethod().equals(Request.NOTIFY)) {\n                SIPDialog dialog = sipStack.getDialog(this.getOriginalRequest()\n                        .getDialogId(false));\n                // I want to behave like a user agent so send the BYE using the\n                // Dialog\n                if (this.getSipProvider().isAutomaticDialogSupportEnabled() && dialog != null) {\n                    throw new SipException(\n                            \"Dialog is present and AutomaticDialogSupport is enabled for \"\n                                    + \" the provider -- Send the Request using the Dialog.sendRequest(transaction)\");\n                }\n            }\n            // Only map this after the fist request is sent out.\n            if (this.getMethod().equals(Request.INVITE)) {\n                SIPDialog dialog = this.getDefaultDialog();\n\n                if (dialog != null && dialog.isBackToBackUserAgent()) {\n                    // Block sending re-INVITE till we see the ACK.\n                    if ( ! dialog.takeAckSem() ) {\n                        throw new SipException (\"Failed to take ACK semaphore\");\n                    }\n\n                }\n            }\n            this.isMapped = true;\n            this.sendMessage(sipRequest);\n\n        } catch (IOException ex) {\n            this.setState(TransactionState.TERMINATED);\n            throw new SipException(\"IO Error sending request\", ex);\n\n        }\n\n    }\n\n    /**\n     * Called by the transaction stack when a retransmission timer fires.\n     */\n    protected void fireRetransmissionTimer() {\n\n        try {\n\n            // Resend the last request sent\n            if (this.getState() == null || !this.isMapped)\n                return;\n\n            boolean inv = isInviteTransaction();\n            TransactionState s = this.getState();\n\n            // JvB: INVITE CTs only retransmit in CALLING, non-INVITE in both TRYING and\n            // PROCEEDING\n            // Bug-fix for non-INVITE transactions not retransmitted when 1xx response received\n            if ((inv && TransactionState.CALLING == s)\n                    || (!inv && (TransactionState.TRYING == s || TransactionState.PROCEEDING == s))) {\n                // If the retransmission filter is disabled then\n                // retransmission of the INVITE is the application\n                // responsibility.\n\n                if (lastRequest != null) {\n                    if (sipStack.generateTimeStampHeader\n                            && lastRequest.getHeader(TimeStampHeader.NAME) != null) {\n                        long milisec = System.currentTimeMillis();\n                        TimeStamp timeStamp = new TimeStamp();\n                        try {\n                            timeStamp.setTimeStamp(milisec);\n                        } catch (InvalidArgumentException ex) {\n                            InternalErrorHandler.handleException(ex);\n                        }\n                        lastRequest.setHeader(timeStamp);\n                    }\n                    super.sendMessage(lastRequest);\n                    if (this.notifyOnRetransmit) {\n                        TimeoutEvent txTimeout = new TimeoutEvent(this.getSipProvider(), this,\n                                Timeout.RETRANSMIT);\n                        this.getSipProvider().handleEvent(txTimeout, this);\n                    }\n                    if (this.timeoutIfStillInCallingState\n                            && this.getState() == TransactionState.CALLING) {\n                        this.callingStateTimeoutCount--;\n                        if (callingStateTimeoutCount == 0) {\n                            TimeoutEvent timeoutEvent = new TimeoutEvent(this.getSipProvider(),\n                                    this, Timeout.RETRANSMIT);\n                            this.getSipProvider().handleEvent(timeoutEvent, this);\n                            this.timeoutIfStillInCallingState = false;\n                        }\n\n                    }\n                }\n\n            }\n        } catch (IOException e) {\n            this.raiseIOExceptionEvent();\n            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);\n        }\n\n    }\n\n    /**\n     * Called by the transaction stack when a timeout timer fires.\n     */\n    protected void fireTimeoutTimer() {\n\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"fireTimeoutTimer \" + this);\n\n        SIPDialog dialog = (SIPDialog) this.getDialog();\n        if (TransactionState.CALLING == this.getState()\n                || TransactionState.TRYING == this.getState()\n                || TransactionState.PROCEEDING == this.getState()) {\n            // Timeout occured. If this is asociated with a transaction\n            // creation then kill the dialog.\n            if (dialog != null\n                    && (dialog.getState() == null || dialog.getState() == DialogState.EARLY)) {\n                if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this\n                        .getOriginalRequest().getMethod())) {\n                    // If this is a re-invite we do not delete the dialog even\n                    // if the\n                    // reinvite times out. Else\n                    // terminate the enclosing dialog.\n                    dialog.delete();\n                }\n            } else if (dialog != null) {\n                // Guard against the case of BYE time out.\n\n                if (getOriginalRequest().getMethod().equalsIgnoreCase(Request.BYE)\n                        && dialog.isTerminatedOnBye()) {\n                    // Terminate the associated dialog on BYE Timeout.\n                    dialog.delete();\n                }\n            }\n        }\n        if (TransactionState.COMPLETED != this.getState()) {\n            raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);\n            // Got a timeout error on a cancel.\n            if (this.getOriginalRequest().getMethod().equalsIgnoreCase(Request.CANCEL)) {\n                SIPClientTransaction inviteTx = (SIPClientTransaction) this.getOriginalRequest()\n                        .getInviteTransaction();\n                if (inviteTx != null\n                        && ((inviteTx.getState() == TransactionState.CALLING || inviteTx\n                                .getState() == TransactionState.PROCEEDING))\n                        && inviteTx.getDialog() != null) {\n                    /*\n                     * A proxy server should have started TIMER C and take care of the Termination\n                     * using transaction.terminate() by itself (i.e. this is not the job of the\n                     * stack at this point but we do it to be nice.\n                     */\n                    inviteTx.setState(TransactionState.TERMINATED);\n\n                }\n            }\n\n        } else {\n            this.setState(TransactionState.TERMINATED);\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.ClientTransaction#createCancel()\n     */\n    public Request createCancel() throws SipException {\n        SIPRequest originalRequest = this.getOriginalRequest();\n        if (originalRequest == null)\n            throw new SipException(\"Bad state \" + getState());\n        if (!originalRequest.getMethod().equals(Request.INVITE))\n            throw new SipException(\"Only INIVTE may be cancelled\");\n\n        if (originalRequest.getMethod().equalsIgnoreCase(Request.ACK))\n            throw new SipException(\"Cannot Cancel ACK!\");\n        else {\n            SIPRequest cancelRequest = originalRequest.createCancelRequest();\n            cancelRequest.setInviteTransaction(this);\n            return cancelRequest;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.ClientTransaction#createAck()\n     */\n    public Request createAck() throws SipException {\n        SIPRequest originalRequest = this.getOriginalRequest();\n        if (originalRequest == null)\n            throw new SipException(\"bad state \" + getState());\n        if (getMethod().equalsIgnoreCase(Request.ACK)) {\n            throw new SipException(\"Cannot ACK an ACK!\");\n        } else if (lastResponse == null) {\n            throw new SipException(\"bad Transaction state\");\n        } else if (lastResponse.getStatusCode() < 200) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"lastResponse = \" + lastResponse);\n            }\n            throw new SipException(\"Cannot ACK a provisional response!\");\n        }\n        SIPRequest ackRequest = originalRequest.createAckRequest((To) lastResponse.getTo());\n        // Pull the record route headers from the last reesponse.\n        RecordRouteList recordRouteList = lastResponse.getRecordRouteHeaders();\n        if (recordRouteList == null) {\n            // If the record route list is null then we can\n            // construct the ACK from the specified contact header.\n            // Note the 3xx check here because 3xx is a redirect.\n            // The contact header for the 3xx is the redirected\n            // location so we cannot use that to construct the\n            // request URI.\n            if (lastResponse.getContactHeaders() != null\n                    && lastResponse.getStatusCode() / 100 != 3) {\n                Contact contact = (Contact) lastResponse.getContactHeaders().getFirst();\n                javax2.sip.address.URI uri = (javax2.sip.address.URI) contact.getAddress().getURI()\n                        .clone();\n                ackRequest.setRequestURI(uri);\n            }\n            return ackRequest;\n        }\n\n        ackRequest.removeHeader(RouteHeader.NAME);\n        RouteList routeList = new RouteList();\n        // start at the end of the list and walk backwards\n        ListIterator<RecordRoute> li = recordRouteList.listIterator(recordRouteList.size());\n        while (li.hasPrevious()) {\n            RecordRoute rr = (RecordRoute) li.previous();\n\n            Route route = new Route();\n            route.setAddress((AddressImpl) ((AddressImpl) rr.getAddress()).clone());\n            route.setParameters((NameValueList) rr.getParameters().clone());\n            routeList.add(route);\n        }\n\n        Contact contact = null;\n        if (lastResponse.getContactHeaders() != null) {\n            contact = (Contact) lastResponse.getContactHeaders().getFirst();\n        }\n\n        if (!((SipURI) ((Route) routeList.getFirst()).getAddress().getURI()).hasLrParam()) {\n\n            // Contact may not yet be there (bug reported by Andreas B).\n\n            Route route = null;\n            if (contact != null) {\n                route = new Route();\n                route.setAddress((AddressImpl) ((AddressImpl) (contact.getAddress())).clone());\n            }\n\n            Route firstRoute = (Route) routeList.getFirst();\n            routeList.removeFirst();\n            javax2.sip.address.URI uri = firstRoute.getAddress().getURI();\n            ackRequest.setRequestURI(uri);\n\n            if (route != null)\n                routeList.add(route);\n\n            ackRequest.addHeader(routeList);\n        } else {\n            if (contact != null) {\n                javax2.sip.address.URI uri = (javax2.sip.address.URI) contact.getAddress().getURI()\n                        .clone();\n                ackRequest.setRequestURI(uri);\n                ackRequest.addHeader(routeList);\n            }\n        }\n        return ackRequest;\n\n    }\n\n    /*\n     * Creates an ACK for an error response, according to RFC3261 section 17.1.1.3\n     * \n     * Note that this is different from an ACK for 2xx\n     */\n    private final Request createErrorAck() throws SipException, ParseException {\n        SIPRequest originalRequest = this.getOriginalRequest();\n        if (originalRequest == null)\n            throw new SipException(\"bad state \" + getState());\n        if (!getMethod().equals(Request.INVITE)) {\n            throw new SipException(\"Can only ACK an INVITE!\");\n        } else if (lastResponse == null) {\n            throw new SipException(\"bad Transaction state\");\n        } else if (lastResponse.getStatusCode() < 200) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"lastResponse = \" + lastResponse);\n            }\n            throw new SipException(\"Cannot ACK a provisional response!\");\n        }\n        return originalRequest.createErrorAck((To) lastResponse.getTo());\n    }\n\n    /**\n     * Set the port of the recipient.\n     */\n    protected void setViaPort(int port) {\n        this.viaPort = port;\n    }\n\n    /**\n     * Set the port of the recipient.\n     */\n    protected void setViaHost(String host) {\n        this.viaHost = host;\n    }\n\n    /**\n     * Get the port of the recipient.\n     */\n    public int getViaPort() {\n        return this.viaPort;\n    }\n\n    /**\n     * Get the host of the recipient.\n     */\n    public String getViaHost() {\n        return this.viaHost;\n    }\n\n    /**\n     * get the via header for an outgoing request.\n     */\n    public Via getOutgoingViaHeader() {\n        return this.getMessageProcessor().getViaHeader();\n    }\n\n    /**\n     * This is called by the stack after a non-invite client transaction goes to completed state.\n     */\n    public void clearState() {\n        // reduce the state to minimum\n        // This assumes that the application will not need\n        // to access the request once the transaction is\n        // completed.\n        // TODO -- revisit this - results in a null pointer\n        // occuring occasionally.\n        // this.lastRequest = null;\n        // this.originalRequest = null;\n        // this.lastResponse = null;\n    }\n\n    /**\n     * Sets a timeout after which the connection is closed (provided the server does not use the\n     * connection for outgoing requests in this time period) and calls the superclass to set\n     * state.\n     */\n    public void setState(TransactionState newState) {\n        // Set this timer for connection caching\n        // of incoming connections.\n        if (newState == TransactionState.TERMINATED && this.isReliable()\n                && (!getSIPStack().cacheClientConnections)) {\n            // Set a time after which the connection\n            // is closed.\n            this.collectionTime = TIMER_J;\n\n        }\n        if (super.getState() != TransactionState.COMPLETED\n                && (newState == TransactionState.COMPLETED || newState == TransactionState.TERMINATED)) {\n            sipStack.decrementActiveClientTransactionCount();\n        }\n        super.setState(newState);\n    }\n\n    /**\n     * Start the timer task.\n     */\n    protected  void startTransactionTimer() {\n        if (this.transactionTimerStarted.compareAndSet(false, true)) {\n\t        TimerTask myTimer = new TransactionTimer();\n\t        if ( sipStack.getTimer() != null ) {\n\t            sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);\n\t        }\n        }\n    }\n\n    /*\n     * Terminate a transaction. This marks the tx as terminated The tx scanner will run and remove\n     * the tx. (non-Javadoc)\n     * \n     * @see javax2.sip.Transaction#terminate()\n     */\n    public void terminate() throws ObjectInUseException {\n        this.setState(TransactionState.TERMINATED);\n\n    }\n\n    /**\n     * Check if the From tag of the response matches the from tag of the original message. A\n     * Response with a tag mismatch should be dropped if a Dialog has been created for the\n     * original request.\n     * \n     * @param sipResponse the response to check.\n     * @return true if the check passes.\n     */\n    public boolean checkFromTag(SIPResponse sipResponse) {\n        String originalFromTag = ((SIPRequest) this.getRequest()).getFromTag();\n        if (this.defaultDialog != null) {\n            if (originalFromTag == null ^ sipResponse.getFrom().getTag() == null) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logDebug(\"From tag mismatch -- dropping response\");\n                return false;\n            }\n            if (originalFromTag != null\n                    && !originalFromTag.equalsIgnoreCase(sipResponse.getFrom().getTag())) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logDebug(\"From tag mismatch -- dropping response\");\n                return false;\n            }\n        }\n        return true;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.stack.ServerResponseInterface#processResponse(gov2.nist.javax2.sip.message.SIPResponse,\n     *      gov2.nist.javax2.sip.stack.MessageChannel)\n     */\n    public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) {\n\n        // If a dialog has already been created for this response,\n        // pass it up.\n        SIPDialog dialog = null;\n        String method = sipResponse.getCSeq().getMethod();\n        String dialogId = sipResponse.getDialogId(false);\n        if (method.equals(Request.CANCEL) && lastRequest != null) {\n            // JvB for CANCEL: use invite CT in CANCEL request to get dialog\n            // (instead of stripping tag)\n            SIPClientTransaction ict = (SIPClientTransaction) lastRequest.getInviteTransaction();\n            if (ict != null) {\n                dialog = ict.defaultDialog;\n            }\n        } else {\n            dialog = this.getDialog(dialogId);\n        }\n\n        // JvB: Check all conditions required for creating a new Dialog\n        if (dialog == null) {\n            int code = sipResponse.getStatusCode();\n            if ((code > 100 && code < 300)\n            /* skip 100 (may have a to tag */\n            && (sipResponse.getToTag() != null || sipStack.isRfc2543Supported())\n                    && sipStack.isDialogCreated(method)) {\n\n                /*\n                 * Dialog cannot be found for the response. This must be a forked response. no\n                 * dialog assigned to this response but a default dialog has been assigned. Note\n                 * that if automatic dialog support is configured then a default dialog is always\n                 * created.\n                 */\n\n                synchronized (this) {\n                    /*\n                     * We need synchronization here because two responses may compete for the\n                     * default dialog simultaneously\n                     */\n                    if (defaultDialog != null) {\n                        if (sipResponse.getFromTag() != null) {\n                            SIPResponse dialogResponse = defaultDialog.getLastResponse();\n                            String defaultDialogId = defaultDialog.getDialogId();\n                            if (dialogResponse == null\n                                    || (method.equals(Request.SUBSCRIBE)\n                                            && dialogResponse.getCSeq().getMethod().equals(\n                                                    Request.NOTIFY) && defaultDialogId\n                                            .equals(dialogId))) {\n                                // The default dialog has not been claimed yet.\n                                defaultDialog.setLastResponse(this, sipResponse);\n                                dialog = defaultDialog;\n                            } else {\n                                /*\n                                 * check if we have created one previously (happens in the case of\n                                 * REINVITE processing. JvB: should not happen, this.defaultDialog\n                                 * should then get set in Dialog#sendRequest line 1662\n                                 */\n\n                                dialog = sipStack.getDialog(dialogId);\n                                if (dialog == null) {\n                                    if (defaultDialog.isAssigned()) {\n                                        /*\n                                         * Nop we dont have one. so go ahead and allocate a new\n                                         * one.\n                                         */\n                                        dialog = sipStack.createDialog(this, sipResponse);\n\n                                    }\n                                }\n\n                            }\n                            if ( dialog != null ) {\n                                this.setDialog(dialog, dialog.getDialogId());\n                            } else {\n                            \tif (sipStack.isLoggingEnabled())\n                            \t\tsipStack.getStackLogger().logError(\"dialog is unexpectedly null\",new NullPointerException());\n                            }\n                        } else {\n                            throw new RuntimeException(\"Response without from-tag\");\n                        }\n                    } else {\n                        // Need to create a new Dialog, this becomes default\n                        // JvB: not sure if this ever gets executed\n                        if (sipStack.isAutomaticDialogSupportEnabled) {\n                            dialog = sipStack.createDialog(this, sipResponse);\n                            this.setDialog(dialog, dialog.getDialogId());\n                        }\n                    }\n                } // synchronized\n            } else {\n                dialog = defaultDialog;\n            }\n        } else {\n            dialog.setLastResponse(this, sipResponse);\n        }\n        this.processResponse(sipResponse, incomingChannel, dialog);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.stack.SIPTransaction#getDialog()\n     */\n    public  Dialog getDialog() {\n        // This is for backwards compatibility.\n        Dialog retval = null;\n        if (this.lastResponse != null && this.lastResponse.getFromTag() != null\n                && this.lastResponse.getToTag() != null\n                && this.lastResponse.getStatusCode() != 100) {\n            String dialogId = this.lastResponse.getDialogId(false);\n            retval = (Dialog) getDialog(dialogId);\n        }\n\n        if (retval == null) {\n            retval = (Dialog) this.defaultDialog;\n\n        }\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \" sipDialogs =  \" + sipDialogs + \" default dialog \" + this.defaultDialog\n                            + \" retval \" + retval);\n        }\n        return retval;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.stack.SIPTransaction#setDialog(gov2.nist.javax2.sip.stack.SIPDialog,\n     *      gov2.nist.javax2.sip.message.SIPMessage)\n     */\n    public SIPDialog getDialog(String dialogId) {\n        SIPDialog retval = (SIPDialog) this.sipDialogs.get(dialogId);\n        return retval;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see gov2.nist.javax2.sip.stack.SIPTransaction#setDialog(gov2.nist.javax2.sip.stack.SIPDialog,\n     *      gov2.nist.javax2.sip.message.SIPMessage)\n     */\n    public void setDialog(SIPDialog sipDialog, String dialogId) {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"setDialog: \" + dialogId + \"sipDialog = \" + sipDialog);\n\n        if (sipDialog == null) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logError(\"NULL DIALOG!!\");\n            throw new NullPointerException(\"bad dialog null\");\n        }\n        if (this.defaultDialog == null) {\n            this.defaultDialog = sipDialog;\n            if ( this.getMethod().equals(Request.INVITE) && this.getSIPStack().maxForkTime != 0) {\n                this.getSIPStack().addForkedClientTransaction(this);\n            }\n        }\n        if (dialogId != null && sipDialog.getDialogId() != null) {\n            this.sipDialogs.put(dialogId, sipDialog);\n\n        }\n\n    }\n\n    public SIPDialog getDefaultDialog() {\n        return this.defaultDialog;\n    }\n\n    /**\n     * Set the next hop ( if it has already been computed).\n     * \n     * @param hop -- the hop that has been previously computed.\n     */\n    public void setNextHop(Hop hop) {\n        this.nextHop = hop;\n\n    }\n\n    /**\n     * Reeturn the previously computed next hop (avoid computing it twice).\n     * \n     * @return -- next hop previously computed.\n     */\n    public Hop getNextHop() {\n        return nextHop;\n    }\n\n    /**\n     * Set this flag if you want your Listener to get Timeout.RETRANSMIT notifications each time a\n     * retransmission occurs.\n     * \n     * @param notifyOnRetransmit the notifyOnRetransmit to set\n     */\n    public void setNotifyOnRetransmit(boolean notifyOnRetransmit) {\n        this.notifyOnRetransmit = notifyOnRetransmit;\n    }\n\n    /**\n     * @return the notifyOnRetransmit\n     */\n    public boolean isNotifyOnRetransmit() {\n        return notifyOnRetransmit;\n    }\n\n    public void alertIfStillInCallingStateBy(int count) {\n        this.timeoutIfStillInCallingState = true;\n        this.callingStateTimeoutCount = count;\n    }\n\n    \n   \n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPDialog.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/**************************************************************************/\n/* Product of NIST Advanced Networking Technologies Division      */\n/**************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.core.NameValueList;\nimport gov2.nist.javax2.sip.DialogExt;\nimport gov2.nist.javax2.sip.ListeningPointImpl;\nimport gov2.nist.javax2.sip.SipListenerExt;\nimport gov2.nist.javax2.sip.SipProviderImpl;\nimport gov2.nist.javax2.sip.Utils;\nimport gov2.nist.javax2.sip.address.AddressImpl;\nimport gov2.nist.javax2.sip.address.SipUri;\nimport gov2.nist.javax2.sip.header.Authorization;\nimport gov2.nist.javax2.sip.header.CSeq;\nimport gov2.nist.javax2.sip.header.Contact;\nimport gov2.nist.javax2.sip.header.ContactList;\nimport gov2.nist.javax2.sip.header.From;\nimport gov2.nist.javax2.sip.header.MaxForwards;\nimport gov2.nist.javax2.sip.header.RAck;\nimport gov2.nist.javax2.sip.header.RSeq;\nimport gov2.nist.javax2.sip.header.Reason;\nimport gov2.nist.javax2.sip.header.RecordRoute;\nimport gov2.nist.javax2.sip.header.RecordRouteList;\nimport gov2.nist.javax2.sip.header.Require;\nimport gov2.nist.javax2.sip.header.Route;\nimport gov2.nist.javax2.sip.header.RouteList;\nimport gov2.nist.javax2.sip.header.SIPHeader;\nimport gov2.nist.javax2.sip.header.TimeStamp;\nimport gov2.nist.javax2.sip.header.To;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.message.MessageFactoryImpl;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Serializable;\nimport java.io.StringWriter;\nimport java.net.InetAddress;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.DialogDoesNotExistException;\nimport javax2.sip.DialogState;\nimport javax2.sip.IOExceptionEvent;\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.ListeningPoint;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.SipException;\nimport javax2.sip.Transaction;\nimport javax2.sip.TransactionDoesNotExistException;\nimport javax2.sip.TransactionState;\nimport javax2.sip.address.Address;\nimport javax2.sip.address.Hop;\nimport javax2.sip.address.SipURI;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.header.OptionTag;\nimport javax2.sip.header.RAckHeader;\nimport javax2.sip.header.RSeqHeader;\nimport javax2.sip.header.ReasonHeader;\nimport javax2.sip.header.RequireHeader;\nimport javax2.sip.header.RouteHeader;\nimport javax2.sip.header.SupportedHeader;\nimport javax2.sip.header.TimeStampHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/*\n * Acknowledgements:\n * \n * Bugs in this class were reported by Antonis Karydas, Brad Templeton, Jeff Adams, Alex Rootham ,\n * Martin Le Clerk, Christophe Anzille, Andreas Bystrom, Lebing Xie, Jeroen van Bemmel. Hagai Sela\n * reported a bug in updating the route set (on RE-INVITE). Jens Tinfors submitted a bug fix and\n * the .equals method. Jan Schaumloeffel contributed a buf fix ( memory leak was happening when\n * 180 contained a To tag.\n * \n */\n\n/**\n * Tracks dialogs. A dialog is a peer to peer association of communicating SIP entities. For\n * INVITE transactions, a Dialog is created when a success message is received (i.e. a response\n * that has a To tag). The SIP Protocol stores enough state in the message structure to extract a\n * dialog identifier that can be used to retrieve this structure from the SipStack.\n * \n * @version 1.2 $Revision: 1.159 $ $Date: 2010/01/08 15:14:12 $\n * \n * @author M. Ranganathan\n * \n * \n */\n\npublic class SIPDialog implements javax2.sip.Dialog, DialogExt {\n\n    private static final long serialVersionUID = -1429794423085204069L;\n\n    private transient boolean dialogTerminatedEventDelivered; // prevent duplicate\n    \n    private transient String stackTrace; // for semaphore debugging.\n\n    private String method;\n\n    // delivery of the event\n    private transient boolean isAssigned;\n\n    private boolean reInviteFlag;\n\n    private transient Object applicationData; // Opaque pointer to application data.\n\n    private transient SIPRequest originalRequest;\n\n    // Last response (JvB: either sent or received).\n    private SIPResponse lastResponse;\n\n    // Should be transient, in case the dialog is serialized it will be null\n    // so when a subsequent request will be sent it will be set and a new message channel can be\n    // created\n    private transient SIPTransaction firstTransaction;\n\n    private transient SIPTransaction lastTransaction;\n\n    private String dialogId;\n\n    private transient String earlyDialogId;\n\n    private long localSequenceNumber;\n\n    private long remoteSequenceNumber;\n\n    protected String myTag;\n\n    protected String hisTag;\n\n    private RouteList routeList;\n\n    private transient SIPTransactionStack sipStack;\n\n    private int dialogState;\n\n    protected transient boolean ackSeen;\n    \n    private transient SIPRequest lastAckSent;\n\n    private SIPRequest lastAckReceived;\n\n    // could be set on recovery by examining the method looks like a duplicate of ackSeen\n    protected transient boolean ackProcessed;\n\n    protected transient DialogTimerTask timerTask;\n\n    protected transient Long nextSeqno;\n\n    private transient int retransmissionTicksLeft;\n\n    private transient int prevRetransmissionTicks;\n\n    private long originalLocalSequenceNumber;\n\n    // This is for debugging only.\n    private transient int ackLine;\n\n    // Audit tag used by the SIP Stack audit\n    public transient long auditTag = 0;\n\n    // The following fields are extracted from the request that created the\n    // Dialog.\n\n    protected javax2.sip.address.Address localParty;\n\n    protected javax2.sip.address.Address remoteParty;\n\n    protected CallIdHeader callIdHeader;\n\n    public final static int NULL_STATE = -1;\n\n    public final static int EARLY_STATE = DialogState._EARLY;\n\n    public final static int CONFIRMED_STATE = DialogState._CONFIRMED;\n\n    public final static int TERMINATED_STATE = DialogState._TERMINATED;\n\n    // the amount of time to keep this dialog around before the stack GC's it\n\n    private static final int DIALOG_LINGER_TIME = 8;\n\n    private boolean serverTransactionFlag;\n\n    private transient SipProviderImpl sipProvider;\n\n    private boolean terminateOnBye;\n\n    private transient boolean byeSent; // Flag set when BYE is sent, to disallow new\n\n    // requests\n\n    private Address remoteTarget;\n\n    private EventHeader eventHeader; // for Subscribe notify\n\n    // Stores the last OK for the INVITE\n    // Used in createAck.\n    private transient long lastInviteOkReceived;\n\n    private transient Semaphore ackSem = new Semaphore(1);\n\n    private transient int reInviteWaitTime = 100;\n\n    private transient DialogDeleteTask dialogDeleteTask;\n\n\tprivate transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask;\n    \n    private transient boolean isAcknowledged;\n    \n    private transient long highestSequenceNumberAcknowledged = -1;\n    \n    private boolean isBackToBackUserAgent;\n\n    private boolean sequenceNumberValidation = true;\n\n    // List of event listeners for this dialog\n\tprivate transient Set<SIPDialogEventListener> eventListeners;\n\t// added for Issue 248 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248\n\tprivate Semaphore timerTaskLock = new Semaphore(1);\n\t\n\t// We store here the useful data from the first transaction without having to\n\t// keep the whole transaction object for the duration of the dialog. It also\n\t// contains the non-transient information used in the replication of dialogs.\n\tprotected boolean firstTransactionSecure;\n\tprotected boolean firstTransactionSeen;\n    protected String firstTransactionMethod;\n    protected String firstTransactionId;\n    protected boolean firstTransactionIsServerTransaction;\n    protected int firstTransactionPort = 5060;   \n    protected Contact contactHeader;\n\n    // //////////////////////////////////////////////////////\n    // Inner classes\n    // //////////////////////////////////////////////////////\n\n    /**\n     * This task waits till a pending ACK has been recorded and then sends out a re-INVITE. This\n     * is to prevent interleaving INVITEs ( which will result in a 493 from the UA that receives\n     * the out of order INVITE). This is primarily for B2BUA support. A B2BUA may send a delayed\n     * ACK while it does mid call codec renegotiation. In the meanwhile, it cannot send an intervening\n     * re-INVITE otherwise the othr end will respond with a REQUEST_PENDING. We want to avoid this\n     * condition. Hence we wait till the ACK for the previous re-INVITE has been sent before \n     * sending the next re-INVITE. \n     */\n    public class ReInviteSender implements Runnable, Serializable {\n        private static final long serialVersionUID = 1019346148741070635L;\n        ClientTransaction ctx;\n\n        public void terminate() {\n            try {\n                ctx.terminate();\n                Thread.currentThread().interrupt();\n            } catch (ObjectInUseException e) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logError(\"unexpected error\", e);\n            }\n        }\n\n        public ReInviteSender(ClientTransaction ctx) {\n            this.ctx = ctx;\n        }\n\n        public void run() {\n            try {\n                long timeToWait = 0;\n                long startTime = System.currentTimeMillis();\n\n                if (!SIPDialog.this.takeAckSem()) {\n                    /*\n                     * Could not send re-INVITE fire a timeout on the INVITE.\n                     */\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logError(\n                            \"Could not send re-INVITE time out ClientTransaction\");\n                    ((SIPClientTransaction) ctx).fireTimeoutTimer();\n                    /*\n                     * Send BYE to the Dialog. \n                     */\n                    if ( sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) {\n                        raiseErrorEvent(SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT);\n                    } else {\n                        Request byeRequest = SIPDialog.this.createRequest(Request.BYE);\n                        if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {\n                            byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n                        }\n                        ReasonHeader reasonHeader = new Reason();\n                        reasonHeader.setCause(1024);\n                        reasonHeader.setText(\"Timed out waiting to re-INVITE\");\n                        byeRequest.addHeader(reasonHeader);\n                        ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest);\n                        SIPDialog.this.sendRequest(byeCtx);\n                        return;\n                    }\n                }\n                if (getState() != DialogState.TERMINATED) {\n\n                    timeToWait = System.currentTimeMillis() - startTime;\n                }\n\n                /*\n                 * If we had to wait for ACK then wait for the ACK to actually get to the other\n                 * side. Wait for any ACK retransmissions to finish. Then send out the request.\n                 * This is a hack in support of some UA that want re-INVITEs to be spaced out in\n                 * time ( else they return a 400 error code ).\n                 */\n                try {\n                    if (timeToWait != 0) {\n                        Thread.sleep(SIPDialog.this.reInviteWaitTime);\n                    }\n                } catch (InterruptedException ex) {\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logDebug(\"Interrupted sleep\");\n                    return;\n                }\n                if (SIPDialog.this.getState() != DialogState.TERMINATED) {\n                    SIPDialog.this.sendRequest(ctx, true);\n                }\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logDebug(\"re-INVITE successfully sent\");\n            } catch (Exception ex) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logError(\"Error sending re-INVITE\", ex);\n            } finally {\n                this.ctx = null;\n            }\n        }\n    }\n\n\tclass LingerTimer extends SIPStackTimerTask implements Serializable {\n\n        public LingerTimer() {\n\n        }\n\n        protected void runTask() {\n            SIPDialog dialog = SIPDialog.this;\n            if(eventListeners != null) {\n            \teventListeners.clear();\n            }\n            timerTaskLock = null;\n            sipStack.removeDialog(dialog);\n        }\n\n    }\n\n    class DialogTimerTask extends SIPStackTimerTask implements Serializable {\n        int nRetransmissions;\n\n        SIPServerTransaction transaction;\n\n        int ticks;\n\n        public DialogTimerTask(SIPServerTransaction transaction) {\n            this.transaction = transaction;\n            this.nRetransmissions = 0;\n\n            this.ticks = 64 * SIPTransaction.T1;\n            setTaskOutdatedTime(ticks);\n        }\n\n        protected void runTask() {\n            // If I ACK has not been seen on Dialog,\n            // resend last response.\n            SIPDialog dialog = SIPDialog.this;\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Running dialog timer\");\n            nRetransmissions++;\n            SIPServerTransaction transaction = this.transaction;\n            /*\n             * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed to the transport\n             * with an interval that starts at T1 seconds and doubles for each retransmission\n             * until it reaches T2 seconds If the server retransmits the 2xx response for 64*T1\n             * seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD\n             * be terminated.\n             */\n\n            if (nRetransmissions > ticks || isTaskOutdated()) {\n                if (sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) {\n                    raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT);\n                } else  {\n                    dialog.delete();\n                }\n                if (transaction != null\n                        && transaction.getState() != javax2.sip.TransactionState.TERMINATED) {\n                    transaction.raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);  \n                }\n            } else if ((!dialog.ackSeen) && (transaction != null)) {\n                // Retransmit to 200 until ack receivedialog.\n                SIPResponse response = transaction.getLastResponse();\n                if (response.getStatusCode() == 200) {\n                    try {\n\n                        // resend the last response.\n                        if (dialog.toRetransmitFinalResponse(transaction.T2))\n                            transaction.sendMessage(response);\n\n                    } catch (IOException ex) {\n\n                        raiseIOException(transaction.getPeerAddress(), transaction.getPeerPort(),\n                                transaction.getPeerProtocol());\n\n                    } finally {\n                        // Need to fire the timer so\n                        // transaction will eventually\n                        // time out whether or not\n                        // the IOException occurs\n                        // Note that this firing also\n                        // drives Listener timeout.\n                        SIPTransactionStack stack = dialog.sipStack;\n                        if (stack.isLoggingEnabled()) {\n                            stack.getStackLogger().logDebug(\"resend 200 response from \" + dialog);\n                        }\n                        transaction.fireTimer();\n                    }\n                }\n            }\n\n            // Stop running this timer if the dialog is in the\n            // confirmed state or ack seen if retransmit filter on.\n            if (dialog.isAckSeen() || dialog.dialogState == TERMINATED_STATE) {\n                this.transaction = null;\n                this.cancel();\n\n            }\n\n        }\n\n    }\n\n    /**\n     * This timer task is used to garbage collect the dialog after some time.\n     * \n     */\n\n    class DialogDeleteTask extends SIPStackTimerTask implements Serializable {\n\n        protected void runTask() {\n            delete();\n        }\n\n    }\n    \n    /**\n     * This timer task is used to garbage collect the dialog after some time.\n     * \n     */\n\n    class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements Serializable {\n        private long seqno;\n   \n        public DialogDeleteIfNoAckSentTask(long seqno) {\n            this.seqno = seqno;\n        }\n\n        protected void runTask() {\n            if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) {  \n                /*\n                 * Did not send ACK so we need to delete the dialog.\n                 * B2BUA NOTE: we may want to send BYE to the Dialog at this \n                 * point. Do we want to make this behavior tailorable?\n                 */\n            \tdialogDeleteIfNoAckSentTask = null;\n                if ( !SIPDialog.this.isBackToBackUserAgent) {\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logError(\"ACK Was not sent. killing dialog\");\n                \tif ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){\n                \t    raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);\n                \t} else {\n                \t    delete();\n                \t}\n                } else {\n                \tif (sipStack.isLoggingEnabled()) \n                \t\tsipStack.getStackLogger().logError(\"ACK Was not sent. Sending BYE\");\n                \t   if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){    \n                \t       raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);\n                \t   } else {\n\n                        /*\n                         * Send BYE to the Dialog. \n                         * This will be removed for the next spec revision.\n                         */\n                        try {\n                            Request byeRequest = SIPDialog.this.createRequest(Request.BYE);\n                            if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {\n                                byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n                            }\n                            ReasonHeader reasonHeader = new Reason();\n                            reasonHeader.setProtocol(\"SIP\");\n                            reasonHeader.setCause(1025);\n                            reasonHeader.setText(\"Timed out waiting to send ACK\");\n                            byeRequest.addHeader(reasonHeader);\n                            ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest);\n                            SIPDialog.this.sendRequest(byeCtx);\n                            return;\n                        } catch (Exception ex) {\n                            SIPDialog.this.delete();\n                        }\n                    }\n                }\n            }\n        }\n\n    }\n\n    // ///////////////////////////////////////////////////////////\n    // Constructors.\n    // ///////////////////////////////////////////////////////////\n    /**\n     * Protected Dialog constructor.\n     */\n    private SIPDialog(SipProviderImpl provider) {\n        this.terminateOnBye = true;\n        this.routeList = new RouteList();\n        this.dialogState = NULL_STATE; // not yet initialized.\n        localSequenceNumber = 0;\n        remoteSequenceNumber = -1;\n        this.sipProvider = provider;\n        eventListeners = new CopyOnWriteArraySet<SIPDialogEventListener>();\n    }\n    \n    private void recordStackTrace() {\n      StringWriter stringWriter = new StringWriter();\n      PrintWriter writer = new PrintWriter(stringWriter);\n      new Exception().printStackTrace(writer);\n       this.stackTrace = stringWriter.getBuffer().toString();\n    }\n\n    /**\n     * Constructor given the first transaction.\n     * \n     * @param transaction is the first transaction.\n     */\n    public SIPDialog(SIPTransaction transaction) {\n        this(transaction.getSipProvider());\n       \n        SIPRequest sipRequest = (SIPRequest) transaction.getRequest();\n        this.callIdHeader = sipRequest.getCallId();\n        this.earlyDialogId = sipRequest.getDialogId(false);\n        if (transaction == null)\n            throw new NullPointerException(\"Null tx\");\n        this.sipStack = transaction.sipStack;\n\n        // this.defaultRouter = new DefaultRouter((SipStack) sipStack,\n        // sipStack.outboundProxy);\n\n        this.sipProvider = (SipProviderImpl) transaction.getSipProvider();\n        if (sipProvider == null)\n            throw new NullPointerException(\"Null Provider!\");\n        this.addTransaction(transaction);\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"Creating a dialog : \" + this);\n            sipStack.getStackLogger().logDebug(\n                    \"provider port = \" + this.sipProvider.getListeningPoint().getPort());\n            sipStack.getStackLogger().logStackTrace();\n        }\n        this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;\n        addEventListener(sipStack);\n    }\n\n    /**\n     * Constructor given a transaction and a response.\n     * \n     * @param transaction -- the transaction ( client/server)\n     * @param sipResponse -- response with the appropriate tags.\n     */\n    public SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {\n        this(transaction);\n        if (sipResponse == null)\n            throw new NullPointerException(\"Null SipResponse\");\n        this.setLastResponse(transaction, sipResponse);\n        this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;\n    }\n\n    /**\n     * create a sip dialog with a response ( no tx)\n     */\n    public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) {\n        this(sipProvider);\n        this.sipStack = (SIPTransactionStack) sipProvider.getSipStack();\n        this.setLastResponse(null, sipResponse);\n        this.localSequenceNumber = sipResponse.getCSeq().getSeqNumber();\n        this.originalLocalSequenceNumber = localSequenceNumber;\n        this.myTag = sipResponse.getFrom().getTag();\n        this.hisTag = sipResponse.getTo().getTag();\n        this.localParty = sipResponse.getFrom().getAddress();\n        this.remoteParty = sipResponse.getTo().getAddress();\n        this.method = sipResponse.getCSeq().getMethod();\n        this.callIdHeader = sipResponse.getCallId();\n        this.serverTransactionFlag = false;\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"Creating a dialog : \" + this);\n            sipStack.getStackLogger().logStackTrace();\n        }\n        this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;\n        addEventListener(sipStack);\n    }\n\n    // ///////////////////////////////////////////////////////////\n    // Private methods\n    // ///////////////////////////////////////////////////////////\n    /**\n     * A debugging print routine.\n     */\n    private void printRouteList() {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"this : \" + this);\n            sipStack.getStackLogger().logDebug(\"printRouteList : \" + this.routeList.encode());\n        }\n    }\n\n    /**\n     * Return true if this is a client dialog.\n     * \n     * @return true if the transaction that created this dialog is a client transaction and false\n     *         otherwise.\n     */\n    private boolean isClientDialog() {\n        SIPTransaction transaction = (SIPTransaction) this.getFirstTransaction();\n        return transaction instanceof SIPClientTransaction;\n    }\n\n    /**\n     * Raise an io exception for asyncrhonous retransmission of responses\n     * \n     * @param host -- host to where the io was headed\n     * @param port -- remote port\n     * @param protocol -- protocol (udp/tcp/tls)\n     */\n    private void raiseIOException(String host, int port, String protocol) {\n        // Error occured in retransmitting response.\n        // Deliver the error event to the listener\n        // Kill the dialog.\n\n        IOExceptionEvent ioError = new IOExceptionEvent(this, host, port, protocol);\n        sipProvider.handleEvent(ioError, null);\n\n        setState(SIPDialog.TERMINATED_STATE);\n    }\n    \n    /**\n     * Raise a dialog timeout if an ACK has not been sent or received\n     * \n     * @param dialogTimeoutError \n     */\n    private void raiseErrorEvent(int dialogTimeoutError) {\n\t\t// Error event to send to all listeners\n\t\tSIPDialogErrorEvent newErrorEvent;\n\t\t// Iterator through the list of listeners\n\t\tIterator<SIPDialogEventListener> listenerIterator;\n\t\t// Next listener in the list\n\t\tSIPDialogEventListener nextListener;\n\n\t\t// Create the error event\n\t\tnewErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError);\n\n\t\t// Loop through all listeners of this transaction\n\t\tsynchronized (eventListeners) {\n\t\t\tlistenerIterator = eventListeners.iterator();\n\t\t\twhile (listenerIterator.hasNext()) {\n\t\t\t\t// Send the event to the next listener\n\t\t\t\tnextListener = (SIPDialogEventListener) listenerIterator.next();\n\t\t\t\tnextListener.dialogErrorEvent(newErrorEvent);\n\t\t\t}\n\t\t}\n\t\t// Clear the event listeners after propagating the error.\n\t\teventListeners.clear();\n\t\t// Errors always terminate a dialog except if a timeout has occured because an ACK was not sent or received, then it is the responsibility of the app to terminate\n\t\t// the dialog, either by sending a BYE or by calling delete() on the dialog\t\t\n\t\tif(dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT &&\n\t\t        dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT &&\n\t\t        dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT ) {\n\t\t\tdelete();\n\t\t}\n\t\t// we stop the timer in any case\n\t\tstopTimer();\n\t}\n\n    /**\n     * Set the remote party for this Dialog.\n     * \n     * @param sipMessage -- SIP Message to extract the relevant information from.\n     */\n    private void setRemoteParty(SIPMessage sipMessage) {\n\n        if (!isServer()) {\n\n            this.remoteParty = sipMessage.getTo().getAddress();\n        } else {\n            this.remoteParty = sipMessage.getFrom().getAddress();\n\n        }\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"settingRemoteParty \" + this.remoteParty);\n        }\n    }\n\n    /**\n     * Add a route list extracted from a record route list. If this is a server dialog then we\n     * assume that the record are added to the route list IN order. If this is a client dialog\n     * then we assume that the record route headers give us the route list to add in reverse\n     * order.\n     * \n     * @param recordRouteList -- the record route list from the incoming message.\n     */\n\n    private void addRoute(RecordRouteList recordRouteList) {\n        try {\n            if (this.isClientDialog()) {\n                // This is a client dialog so we extract the record\n                // route from the response and reverse its order to\n                // careate a route list.\n                this.routeList = new RouteList();\n                // start at the end of the list and walk backwards\n\n                ListIterator li = recordRouteList.listIterator(recordRouteList.size());\n                boolean addRoute = true;\n                while (li.hasPrevious()) {\n                    RecordRoute rr = (RecordRoute) li.previous();\n\n                    if (addRoute) {\n                        Route route = new Route();\n                        AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress())\n                                .clone());\n\n                        route.setAddress(address);\n                        route.setParameters((NameValueList) rr.getParameters().clone());\n\n                        this.routeList.add(route);\n                    }\n                }\n            } else {\n                // This is a server dialog. The top most record route\n                // header is the one that is closest to us. We extract the\n                // route list in the same order as the addresses in the\n                // incoming request.\n                this.routeList = new RouteList();\n                ListIterator li = recordRouteList.listIterator();\n                boolean addRoute = true;\n                while (li.hasNext()) {\n                    RecordRoute rr = (RecordRoute) li.next();\n\n                    if (addRoute) {\n                        Route route = new Route();\n                        AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress())\n                                .clone());\n                        route.setAddress(address);\n                        route.setParameters((NameValueList) rr.getParameters().clone());\n                        routeList.add(route);\n                    }\n                }\n            }\n        } finally {\n            if (sipStack.getStackLogger().isLoggingEnabled()) {\n                Iterator it = routeList.iterator();\n\n                while (it.hasNext()) {\n                    SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI());\n                    if (!sipUri.hasLrParam()) {                     \n                    \tif (sipStack.isLoggingEnabled()) {\n                    \t\tsipStack.getStackLogger().logWarning(\n                                \"NON LR route in Route set detected for dialog : \" + this);\n                        \tsipStack.getStackLogger().logStackTrace();\n                    \t}\t\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Add a route list extacted from the contact list of the incoming message.\n     * \n     * @param contact -- contact list extracted from the incoming message.\n     * \n     */\n\n    void setRemoteTarget(ContactHeader contact) {\n        this.remoteTarget = contact.getAddress();\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"Dialog.setRemoteTarget: \" + this.remoteTarget);\n            sipStack.getStackLogger().logStackTrace();\n        }\n\n    }\n\n    /**\n     * Extract the route information from this SIP Message and add the relevant information to the\n     * route set.\n     * \n     * @param sipResponse is the SIP message for which we want to add the route.\n     */\n    private synchronized void addRoute(SIPResponse sipResponse) {\n\n        try {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"setContact: dialogState: \" + this + \"state = \" + this.getState());\n            }\n            if (sipResponse.getStatusCode() == 100) {\n                // Do nothing for trying messages.\n                return;\n            } else if (this.dialogState == TERMINATED_STATE) {\n                // Do nothing if the dialog state is terminated.\n                return;\n            } else if (this.dialogState == CONFIRMED_STATE) {\n                // cannot add route list after the dialog is initialized.\n                // Remote target is updated on RE-INVITE but not\n                // the route list.\n                if (sipResponse.getStatusCode() / 100 == 2 && !this.isServer()) {\n                    ContactList contactList = sipResponse.getContactHeaders();\n                    if (contactList != null\n                            && SIPRequest.isTargetRefresh(sipResponse.getCSeq().getMethod())) {\n                        this.setRemoteTarget((ContactHeader) contactList.getFirst());\n                    }\n                }\n                return;\n            }\n\n            // Update route list on response if I am a client dialog.\n            if (!isServer()) {\n\n                // only update the route set if the dialog is not in the confirmed state.\n                if (this.getState() != DialogState.CONFIRMED\n                        && this.getState() != DialogState.TERMINATED) {\n                    RecordRouteList rrlist = sipResponse.getRecordRouteHeaders();\n                    // Add the route set from the incoming response in reverse\n                    // order for record route headers.\n                    if (rrlist != null) {\n                        this.addRoute(rrlist);\n                    } else {\n                        // Set the rotue list to the last seen route list.\n                        this.routeList = new RouteList();\n                    }\n                }\n\n                ContactList contactList = sipResponse.getContactHeaders();\n                if (contactList != null) {\n                    this.setRemoteTarget((ContactHeader) contactList.getFirst());\n                }\n            }\n\n        } finally {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logStackTrace();\n            }\n        }\n    }\n\n    /**\n     * Get a cloned copy of route list for the Dialog.\n     * \n     * @return -- a cloned copy of the dialog route list.\n     */\n    private synchronized RouteList getRouteList() {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"getRouteList \" + this);\n        // Find the top via in the route list.\n        ListIterator li;\n        RouteList retval = new RouteList();\n\n        retval = new RouteList();\n        if (this.routeList != null) {\n            li = routeList.listIterator();\n            while (li.hasNext()) {\n                Route route = (Route) li.next();\n                retval.add((Route) route.clone());\n            }\n        }\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"----- \");\n            sipStack.getStackLogger().logDebug(\"getRouteList for \" + this);\n            if (retval != null)\n                sipStack.getStackLogger().logDebug(\"RouteList = \" + retval.encode());\n            if (routeList != null)\n                sipStack.getStackLogger().logDebug(\"myRouteList = \" + routeList.encode());\n            sipStack.getStackLogger().logDebug(\"----- \");\n        }\n        return retval;\n    }\n    \n    void setRouteList(RouteList routeList) {\n    \tthis.routeList = routeList;\n    }\n\n    /**\n     * Sends ACK Request to the remote party of this Dialogue.\n     * \n     * \n     * @param request the new ACK Request message to send.\n     * @param throwIOExceptionAsSipException - throws SipException if IOEx encountered. Otherwise,\n     *        no exception is propagated.\n     * @throws SipException if implementation cannot send the ACK Request for any other reason\n     * \n     */\n    private void sendAck(Request request, boolean throwIOExceptionAsSipException)\n            throws SipException {\n        SIPRequest ackRequest = (SIPRequest) request;\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"sendAck\" + this);\n\n        if (!ackRequest.getMethod().equals(Request.ACK))\n            throw new SipException(\"Bad request method -- should be ACK\");\n        if (this.getState() == null || this.getState().getValue() == EARLY_STATE) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logError(\n                        \"Bad Dialog State for \" + this + \" dialogID = \" + this.getDialogId());\n            }\n            throw new SipException(\"Bad dialog state \" + this.getState());\n        }\n\n        if (!this.getCallId().getCallId().equals(((SIPRequest) request).getCallId().getCallId())) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logError(\"CallID \" + this.getCallId());\n                sipStack.getStackLogger().logError(\n                        \"RequestCallID = \" + ackRequest.getCallId().getCallId());\n                sipStack.getStackLogger().logError(\"dialog =  \" + this);\n            }\n            throw new SipException(\"Bad call ID in request\");\n        }\n        try {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"setting from tag For outgoing ACK= \" + this.getLocalTag());\n                sipStack.getStackLogger().logDebug(\n                        \"setting To tag for outgoing ACK = \" + this.getRemoteTag());\n                sipStack.getStackLogger().logDebug(\"ack = \" + ackRequest);\n            }\n            if (this.getLocalTag() != null)\n                ackRequest.getFrom().setTag(this.getLocalTag());\n            if (this.getRemoteTag() != null)\n                ackRequest.getTo().setTag(this.getRemoteTag());\n        } catch (ParseException ex) {\n            throw new SipException(ex.getMessage());\n        }\n\n        Hop hop = sipStack.getNextHop(ackRequest);\n        // Hop hop = defaultRouter.getNextHop(ackRequest);\n        if (hop == null)\n            throw new SipException(\"No route!\");\n        try {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"hop = \" + hop);\n            ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider.getListeningPoint(hop\n                    .getTransport());\n            if (lp == null)\n                throw new SipException(\"No listening point for this provider registered at \"\n                        + hop);\n            InetAddress inetAddress = InetAddress.getByName(hop.getHost());\n            MessageChannel messageChannel = lp.getMessageProcessor().createMessageChannel(\n                    inetAddress, hop.getPort());\n            boolean releaseAckSem = false;\n            long cseqNo = ((SIPRequest)request).getCSeq().getSeqNumber();\n            if (!this.isAckSent(cseqNo)) {\n                releaseAckSem = true;\n            }\n\n            this.setLastAckSent(ackRequest);\n            messageChannel.sendMessage(ackRequest);\n            // Sent atleast one ACK.\n            this.isAcknowledged = true;\n            this.highestSequenceNumberAcknowledged = Math.max(this.highestSequenceNumberAcknowledged,\n                    ((SIPRequest)ackRequest).getCSeq().getSeqNumber());\n            if (releaseAckSem && this.isBackToBackUserAgent) {\n                this.releaseAckSem();\n            } else {\n                if ( sipStack.isLoggingEnabled() ) {\n                    sipStack.getStackLogger().logDebug(\"Not releasing ack sem for \" + this + \" isAckSent \" + releaseAckSem );\n                }\n            }\n        } catch (IOException ex) {\n            if (throwIOExceptionAsSipException)\n                throw new SipException(\"Could not send ack\", ex);\n            this.raiseIOException(hop.getHost(), hop.getPort(), hop.getTransport());\n        } catch (SipException ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(ex);\n            throw ex;\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(ex);\n            throw new SipException(\"Could not create message channel\", ex);\n        }\n        if (this.dialogDeleteTask != null) {\n            this.dialogDeleteTask.cancel();\n            this.dialogDeleteTask = null;\n        }\n        this.ackSeen = true;\n\n    }\n\n    // /////////////////////////////////////////////////////////////\n    // Package local methods\n    // /////////////////////////////////////////////////////////////\n\n    /**\n     * Set the stack address. Prevent us from routing messages to ourselves.\n     * \n     * @param sipStack the address of the SIP stack.\n     * \n     */\n    void setStack(SIPTransactionStack sipStack) {\n        this.sipStack = sipStack;\n\n    }\n\n    /**\n     * Get the stack .\n     * \n     * @return sipStack the SIP stack of the dialog.\n     * \n     */\n    SIPTransactionStack getStack() {\n        return sipStack;\n    }\n\n    /**\n     * Return True if this dialog is terminated on BYE.\n     * \n     */\n    boolean isTerminatedOnBye() {\n\n        return this.terminateOnBye;\n    }\n\n    /**\n     * Mark that the dialog has seen an ACK.\n     */\n    void ackReceived(SIPRequest sipRequest) {\n\n        // Suppress retransmission of the final response\n        if (this.ackSeen)\n            return;\n        SIPServerTransaction tr = this.getInviteTransaction();\n        if (tr != null) {\n            if (tr.getCSeq() == sipRequest.getCSeq().getSeqNumber()) {\n            \tacquireTimerTaskSem();\n            \ttry {\n\t                if (this.timerTask != null) {                \t                \t\n\t                \tthis.timerTask.cancel();\n\t\t                this.timerTask = null;                \t\n\t                }\n            \t} finally {\n            \t\treleaseTimerTaskSem();\n            \t}\n                this.ackSeen = true;\n                if (this.dialogDeleteTask != null) {\n                    this.dialogDeleteTask.cancel();\n                    this.dialogDeleteTask = null;\n                }\n                this.setLastAckReceived(sipRequest);\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"ackReceived for \" + ((SIPTransaction) tr).getMethod());\n                    this.ackLine = sipStack.getStackLogger().getLineCount();\n                    this.printDebugInfo();\n                }\n                if (this.isBackToBackUserAgent) {\n                    this.releaseAckSem();\n                }\n                this.setState(CONFIRMED_STATE);\n            }\n        }\n    }\n\n    /**\n     * Return true if a terminated event was delivered to the application as a result of the\n     * dialog termination.\n     * \n     */\n    synchronized boolean testAndSetIsDialogTerminatedEventDelivered() {\n        boolean retval = this.dialogTerminatedEventDelivered;\n        this.dialogTerminatedEventDelivered = true;\n        return retval;\n    }\n\n    // /////////////////////////////////////////////////////////\n    // Public methods\n    // /////////////////////////////////////////////////////////\n\n    /**\n\t * Adds a new event listener to this dialog.\n\t * \n\t * @param newListener\n\t *            Listener to add.\n\t */\n\tpublic void addEventListener(SIPDialogEventListener newListener) {\n\t\teventListeners.add(newListener);\n\t}\n\n\t/**\n\t * Removed an event listener from this dialog.\n\t * \n\t * @param oldListener\n\t *            Listener to remove.\n\t */\n\tpublic void removeEventListener(SIPDialogEventListener oldListener) {\n\t\teventListeners.remove(oldListener);\n\t}\n    \n    /*\n     * @see javax2.sip.Dialog#setApplicationData()\n     */\n    public void setApplicationData(Object applicationData) {\n        this.applicationData = applicationData;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getApplicationData()\n     */\n    public Object getApplicationData() {\n        return this.applicationData;\n    }\n\n    /**\n     * Updates the next consumable seqno.\n     * \n     */\n    public synchronized void requestConsumed() {\n        this.nextSeqno = Long.valueOf(this.getRemoteSeqNumber() + 1);\n\n        if (sipStack.isLoggingEnabled()) {\n            this.sipStack.getStackLogger().logDebug(\n                    \"Request Consumed -- next consumable Request Seqno = \" + this.nextSeqno);\n        }\n\n    }\n\n    /**\n     * Return true if this request can be consumed by the dialog.\n     * \n     * @param dialogRequest is the request to check with the dialog.\n     * @return true if the dialogRequest sequence number matches the next consumable seqno.\n     */\n    public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) {\n        // have not yet set remote seqno - this is a fresh\n        if (dialogRequest.getMethod().equals(Request.ACK))\n            throw new RuntimeException(\"Illegal method\");\n\n        // For loose validation this function is delegated to the application\n        if (!this.isSequnceNumberValidation()) {\n            return true;\n        }\n\n        // JvB: Acceptable iff remoteCSeq < cseq. remoteCSeq==-1\n        // when not defined yet, so that works too\n        return remoteSequenceNumber < dialogRequest.getCSeq().getSeqNumber();\n    }\n\n    /**\n     * This method is called when a forked dialog is created from the client side. It starts a\n     * timer task. If the timer task expires before an ACK is sent then the dialog is cancelled\n     * (i.e. garbage collected ).\n     * \n     */\n    public void doDeferredDelete() {\n        if (sipStack.getTimer() == null)\n            this.setState(TERMINATED_STATE);\n        else {\n            this.dialogDeleteTask = new DialogDeleteTask();\n            // Delete the transaction after the max ack timeout.\n            sipStack.getTimer().schedule(this.dialogDeleteTask,\n                    SIPTransaction.TIMER_H * SIPTransactionStack.BASE_TIMER_INTERVAL);\n        }\n\n    }\n\n    /**\n     * Set the state for this dialog.\n     * \n     * @param state is the state to set for the dialog.\n     */\n\n    public void setState(int state) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"Setting dialog state for \" + this + \"newState = \" + state);\n            sipStack.getStackLogger().logStackTrace();\n            if (state != NULL_STATE && state != this.dialogState)\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            this + \"  old dialog state is \" + this.getState());\n                    sipStack.getStackLogger().logDebug(\n                            this + \"  New dialog state is \" + DialogState.getObject(state));\n                }\n\n        }\n        this.dialogState = state;\n        // Dialog is in terminated state set it up for GC.\n        if (state == TERMINATED_STATE) {\n            if (sipStack.getTimer() != null) { // may be null after shutdown\n                sipStack.getTimer().schedule(new LingerTimer(), DIALOG_LINGER_TIME * 1000);\n            }\n            this.stopTimer();\n\n        }\n    }\n\n    /**\n     * Debugging print for the dialog.\n     */\n    public void printDebugInfo() {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"isServer = \" + isServer());\n            sipStack.getStackLogger().logDebug(\"localTag = \" + getLocalTag());\n            sipStack.getStackLogger().logDebug(\"remoteTag = \" + getRemoteTag());\n            sipStack.getStackLogger().logDebug(\"localSequenceNumer = \" + getLocalSeqNumber());\n            sipStack.getStackLogger().logDebug(\"remoteSequenceNumer = \" + getRemoteSeqNumber());\n            sipStack.getStackLogger().logDebug(\"ackLine:\" + this.getRemoteTag() + \" \" + ackLine);\n        }\n    }\n\n    /**\n     * Return true if the dialog has already seen the ack.\n     * \n     * @return flag that records if the ack has been seen.\n     */\n    public boolean isAckSeen() {\n        return this.ackSeen;\n    }\n\n    /**\n     * Get the last ACK for this transaction.\n     */\n    public SIPRequest getLastAckSent() {\n        return this.lastAckSent;\n    }\n\n    /**\n     * Return true if ACK was sent ( for client tx ). For server tx, this is a NO-OP ( we dont\n     * send ACK).\n     */\n    public boolean isAckSent(long cseqNo) {\n        if (this.getLastTransaction() == null)\n            return true;\n        if (this.getLastTransaction() instanceof ClientTransaction) {\n            if (this.getLastAckSent() == null) {\n                return false;\n            } else {\n                return cseqNo <=((SIPRequest) this.getLastAckSent()).getCSeq().getSeqNumber();\n            }\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * Get the transaction that created this dialog.\n     */\n    public Transaction getFirstTransaction() {\n        return this.firstTransaction;\n    }\n\n\n    /**\n     * Gets the route set for the dialog. When acting as an User Agent Server the route set MUST\n     * be set to the list of URIs in the Record-Route header field from the request, taken in\n     * order and preserving all URI parameters. When acting as an User Agent Client the route set\n     * MUST be set to the list of URIs in the Record-Route header field from the response, taken\n     * in reverse order and preserving all URI parameters. If no Record-Route header field is\n     * present in the request or response, the route set MUST be set to the empty set. This route\n     * set, even if empty, overrides any pre-existing route set for future requests in this\n     * dialog.\n     * <p>\n     * Requests within a dialog MAY contain Record-Route and Contact header fields. However, these\n     * requests do not cause the dialog's route set to be modified.\n     * <p>\n     * The User Agent Client uses the remote target and route set to build the Request-URI and\n     * Route header field of the request.\n     * \n     * @return an Iterator containing a list of route headers to be used for forwarding. Empty\n     *         iterator is returned if route has not been established.\n     */\n    public Iterator getRouteSet() {\n        if (this.routeList == null) {\n            return new LinkedList().listIterator();\n        } else {\n            return this.getRouteList().listIterator();\n        }\n    }\n\n    /**\n     * Add a Route list extracted from a SIPRequest to this Dialog.\n     * \n     * @param sipRequest\n     */\n    public synchronized void addRoute(SIPRequest sipRequest) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"setContact: dialogState: \" + this + \"state = \" + this.getState());\n        }\n\n        if (this.dialogState == CONFIRMED_STATE\n                && SIPRequest.isTargetRefresh(sipRequest.getMethod())) {\n            this.doTargetRefresh(sipRequest);\n        }\n        if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) {\n            return;\n        }\n        \n        // Fix for issue #225: mustn't learn Route set from mid-dialog requests\n        if ( sipRequest.getToTag()!=null ) return;\n        \n        // Incoming Request has the route list\n        RecordRouteList rrlist = sipRequest.getRecordRouteHeaders();\n        // Add the route set from the incoming response in reverse\n        // order\n        if (rrlist != null) {\n            this.addRoute(rrlist);\n        } else {\n            // Set the rotue list to the last seen route list.\n            this.routeList = new RouteList();\n        }\n\n        // put the contact header from the incoming request into\n        // the route set. JvB: some duplication here, ref. doTargetRefresh\n        ContactList contactList = sipRequest.getContactHeaders();\n        if (contactList != null) {\n            this.setRemoteTarget((ContactHeader) contactList.getFirst());\n        }\n    }\n\n    /**\n     * Set the dialog identifier.\n     */\n    public void setDialogId(String dialogId) {\n        this.dialogId = dialogId;\n    }\n\n    /**\n     * Creates a new dialog based on a received NOTIFY. The dialog state is initialized\n     * appropriately. The NOTIFY differs in the From tag\n     * \n     * Made this a separate method to clearly distinguish what's happening here - this is a\n     * non-trivial case\n     * \n     * @param subscribeTx - the transaction started with the SUBSCRIBE that we sent\n     * @param notifyST - the ServerTransaction created for an incoming NOTIFY\n     * @return -- a new dialog created from the subscribe original SUBSCRIBE transaction.\n     * \n     * \n     */\n    public static SIPDialog createFromNOTIFY(SIPClientTransaction subscribeTx,\n            SIPTransaction notifyST) {\n        SIPDialog d = new SIPDialog(notifyST);\n        //\n        // The above sets d.firstTransaction to NOTIFY (ST), correct that\n        //\n        d.serverTransactionFlag = false;\n        // they share this one\n        d.lastTransaction = subscribeTx;\n        storeFirstTransactionInfo(d, subscribeTx);\n        d.terminateOnBye = false;\n        d.localSequenceNumber = subscribeTx.getCSeq();\n        SIPRequest not = (SIPRequest) notifyST.getRequest();\n        d.remoteSequenceNumber = not.getCSeq().getSeqNumber();\n        d.setDialogId(not.getDialogId(true));\n        d.setLocalTag(not.getToTag());\n        d.setRemoteTag(not.getFromTag());\n        // to properly create the Dialog object.\n        // If not the stack will throw an exception when creating the response.\n        d.setLastResponse(subscribeTx, subscribeTx.getLastResponse());\n\n        // Dont use setLocal / setRemote here, they make other assumptions\n        d.localParty = not.getTo().getAddress();\n        d.remoteParty = not.getFrom().getAddress();\n\n        // initialize d's route set based on the NOTIFY. Any proxies must have\n        // Record-Routed\n        d.addRoute(not);\n        d.setState(CONFIRMED_STATE); // set state, *after* setting route set!\n        return d;\n    }\n\n    /**\n     * Return true if is server.\n     * \n     * @return true if is server transaction created this dialog.\n     */\n    public boolean isServer() {\n        if (this.firstTransactionSeen == false)\n            return this.serverTransactionFlag;\n        else\n            return this.firstTransactionIsServerTransaction;\n\n    }\n\n    /**\n     * Return true if this is a re-establishment of the dialog.\n     * \n     * @return true if the reInvite flag is set.\n     */\n    protected boolean isReInvite() {\n        return this.reInviteFlag;\n    }\n\n    /**\n     * Get the id for this dialog.\n     * \n     * @return the string identifier for this dialog.\n     * \n     */\n    public String getDialogId() {\n\n        if (this.dialogId == null && this.lastResponse != null)\n            this.dialogId = this.lastResponse.getDialogId(isServer());\n\n        return this.dialogId;\n    }\n\n    private static void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) {\n    \tdialog.firstTransaction = transaction;\n    \tdialog.firstTransactionSeen = true;\n    \tdialog.firstTransactionIsServerTransaction = transaction.isServerTransaction(); \n    \tdialog.firstTransactionSecure = transaction.getRequest().getRequestURI().getScheme()\n        \t.equalsIgnoreCase(\"sips\");\n    \tdialog.firstTransactionPort = transaction.getPort();\n    \tdialog.firstTransactionId = transaction.getBranchId();\n    \tdialog.firstTransactionMethod = transaction.getMethod();\n    \t\n        if (dialog.isServer()) {\n            SIPServerTransaction st = (SIPServerTransaction) transaction;\n            SIPResponse response = st.getLastResponse();\n            dialog.contactHeader = response != null ? response.getContactHeader() : null;\n        } else {\n            SIPClientTransaction ct = (SIPClientTransaction) transaction;\n            if (ct != null){\n            \tSIPRequest sipRequest = ct.getOriginalRequest();\n            \tdialog.contactHeader = sipRequest.getContactHeader();\n            }\n        }\n    }\n    /**\n     * Add a transaction record to the dialog.\n     * \n     * @param transaction is the transaction to add to the dialog.\n     */\n    public void addTransaction(SIPTransaction transaction) {\n\n        SIPRequest sipRequest = (SIPRequest) transaction.getOriginalRequest();\n\n        // Proessing a re-invite.\n        if (firstTransactionSeen && !firstTransactionId.equals(transaction.getBranchId()) \n                && transaction.getMethod().equals(firstTransactionMethod)) {\n            this.reInviteFlag = true;\n        }\n\n        if (firstTransactionSeen == false) {\n            // Record the local and remote sequenc\n            // numbers and the from and to tags for future\n            // use on this dialog.\n        \tstoreFirstTransactionInfo(this, transaction);\n            if (sipRequest.getMethod().equals(Request.SUBSCRIBE))\n                this.eventHeader = (EventHeader) sipRequest.getHeader(EventHeader.NAME);\n\n            this.setLocalParty(sipRequest);\n            this.setRemoteParty(sipRequest);\n            this.setCallId(sipRequest);\n            if (this.originalRequest == null) {\n                this.originalRequest = sipRequest;\n            }\n            if (this.method == null) {\n                this.method = sipRequest.getMethod();\n            }\n\n            if (transaction instanceof SIPServerTransaction) {\n                this.hisTag = sipRequest.getFrom().getTag();\n                // My tag is assigned when sending response\n            } else {\n                setLocalSequenceNumber(sipRequest.getCSeq().getSeqNumber());\n                this.originalLocalSequenceNumber = localSequenceNumber;\n                this.myTag = sipRequest.getFrom().getTag();\n                if (myTag == null)\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logError(\n                            \"The request's From header is missing the required Tag parameter.\");\n            }\n        } else if (transaction.getMethod().equals(firstTransactionMethod)\n                && firstTransactionIsServerTransaction != transaction.isServerTransaction()) {\n            // This case occurs when you are processing a re-invite.\n            // Switch from client side to server side for re-invite\n            // (put the other side on hold).\n        \t\n\t\t\tstoreFirstTransactionInfo(this, transaction);\n\t\t\t\n            this.setLocalParty(sipRequest);\n            this.setRemoteParty(sipRequest);\n            this.setCallId(sipRequest);\n            this.originalRequest = sipRequest;\n            this.method = sipRequest.getMethod();\n\n        }\n        if (transaction instanceof SIPServerTransaction)\n            setRemoteSequenceNumber(sipRequest.getCSeq().getSeqNumber());\n\n        // If this is a server transaction record the remote\n        // sequence number to avoid re-processing of requests\n        // with the same sequence number directed towards this\n        // dialog.\n\n        this.lastTransaction = transaction;\n        // set a back ptr in the incoming dialog.\n        // CHECKME -- why is this here?\n        // transaction.setDialog(this,sipRequest);\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger()\n                    .logDebug(\"Transaction Added \" + this + myTag + \"/\" + hisTag);\n            sipStack.getStackLogger().logDebug(\n                    \"TID = \" + transaction.getTransactionId() + \"/\"\n                            + transaction.isServerTransaction());\n            sipStack.getStackLogger().logStackTrace();\n        }\n    }\n\n    /**\n     * Set the remote tag.\n     * \n     * @param hisTag is the remote tag to set.\n     */\n    private void setRemoteTag(String hisTag) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"setRemoteTag(): \" + this + \" remoteTag = \" + this.hisTag + \" new tag = \"\n                            + hisTag);\n        }\n        if (this.hisTag != null && hisTag != null && !hisTag.equals(this.hisTag)) {\n            if (this.getState() != DialogState.EARLY) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logDebug(\n                        \"Dialog is already established -- ignoring remote tag re-assignment\");\n                return;\n            } else if (sipStack.isRemoteTagReassignmentAllowed()) {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logDebug(\n                        \"UNSAFE OPERATION !  tag re-assignment \" + this.hisTag\n                                + \" trying to set to \" + hisTag\n                                + \" can cause unexpected effects \");\n                boolean removed = false;\n                if (this.sipStack.getDialog(dialogId) == this) {\n                    this.sipStack.removeDialog(dialogId);\n                    removed = true;\n\n                }\n                // Force recomputation of Dialog ID;\n                this.dialogId = null;\n                this.hisTag = hisTag;\n                if (removed) {\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logDebug(\"ReInserting Dialog\");\n                    this.sipStack.putDialog(this);\n                }\n            }\n        } else {\n            if (hisTag != null) {\n                this.hisTag = hisTag;\n            } else {\n            \tif (sipStack.isLoggingEnabled())\n            \t\tsipStack.getStackLogger().logWarning(\"setRemoteTag : called with null argument \");\n            }\n        }\n    }\n\n    /**\n     * Get the last transaction from the dialog.\n     */\n    public SIPTransaction getLastTransaction() {\n        return this.lastTransaction;\n    }\n\n    /**\n     * Get the INVITE transaction (null if no invite transaction).\n     */\n    public SIPServerTransaction getInviteTransaction() {\n        DialogTimerTask t = this.timerTask;\n        if (t != null)\n            return t.transaction;\n        else\n            return null;\n    }\n\n    /**\n     * Set the local sequece number for the dialog (defaults to 1 when the dialog is created).\n     * \n     * @param lCseq is the local cseq number.\n     * \n     */\n    private void setLocalSequenceNumber(long lCseq) {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"setLocalSequenceNumber: original  \" + this.localSequenceNumber + \" new  = \"\n                            + lCseq);\n        if (lCseq <= this.localSequenceNumber)\n            throw new RuntimeException(\"Sequence number should not decrease !\");\n        this.localSequenceNumber = lCseq;\n    }\n\n    /**\n     * Set the remote sequence number for the dialog.\n     * \n     * @param rCseq is the remote cseq number.\n     * \n     */\n    public void setRemoteSequenceNumber(long rCseq) {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"setRemoteSeqno \" + this + \"/\" + rCseq);\n        this.remoteSequenceNumber = rCseq;\n    }\n\n    /**\n     * Increment the local CSeq # for the dialog. This is useful for if you want to create a hole\n     * in the sequence number i.e. route a request outside the dialog and then resume within the\n     * dialog.\n     */\n    public void incrementLocalSequenceNumber() {\n        ++this.localSequenceNumber;\n    }\n\n    /**\n     * Get the remote sequence number (for cseq assignment of outgoing requests within this\n     * dialog).\n     * \n     * @deprecated\n     * @return local sequence number.\n     */\n\n    public int getRemoteSequenceNumber() {\n        return (int) this.remoteSequenceNumber;\n    }\n\n    /**\n     * Get the local sequence number (for cseq assignment of outgoing requests within this\n     * dialog).\n     * \n     * @deprecated\n     * @return local sequence number.\n     */\n\n    public int getLocalSequenceNumber() {\n        return (int) this.localSequenceNumber;\n    }\n\n    /**\n     * Get the sequence number for the request that origianlly created the Dialog.\n     * \n     * @return -- the original starting sequence number for this dialog.\n     */\n    public long getOriginalLocalSequenceNumber() {\n        return this.originalLocalSequenceNumber;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getLocalSequenceNumberLong()\n     */\n    public long getLocalSeqNumber() {\n        return this.localSequenceNumber;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getRemoteSequenceNumberLong()\n     */\n    public long getRemoteSeqNumber() {\n        return this.remoteSequenceNumber;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getLocalTag()\n     */\n    public String getLocalTag() {\n        return this.myTag;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getRemoteTag()\n     */\n    public String getRemoteTag() {\n\n        return hisTag;\n    }\n\n    /**\n     * Set local tag for the transaction.\n     * \n     * @param mytag is the tag to use in From headers client transactions that belong to this\n     *        dialog and for generating To tags for Server transaction requests that belong to\n     *        this dialog.\n     */\n    private void setLocalTag(String mytag) {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"set Local tag \" + mytag + \" \" + this.dialogId);\n            sipStack.getStackLogger().logStackTrace();\n        }\n\n        this.myTag = mytag;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#delete()\n     */\n\n    public void delete() {\n        // the reaper will get him later.\n        this.setState(TERMINATED_STATE);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getCallId()\n     */\n    public CallIdHeader getCallId() {\n        return this.callIdHeader;\n    }\n\n    /**\n     * set the call id header for this dialog.\n     */\n    private void setCallId(SIPRequest sipRequest) {\n        this.callIdHeader = sipRequest.getCallId();\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getLocalParty()\n     */\n\n    public javax2.sip.address.Address getLocalParty() {\n        return this.localParty;\n    }\n\n    private void setLocalParty(SIPMessage sipMessage) {\n        if (!isServer()) {\n            this.localParty = sipMessage.getFrom().getAddress();\n        } else {\n            this.localParty = sipMessage.getTo().getAddress();\n        }\n    }\n\n    /**\n     * Returns the Address identifying the remote party. This is the value of the To header of\n     * locally initiated requests in this dialogue when acting as an User Agent Client.\n     * <p>\n     * This is the value of the From header of recieved responses in this dialogue when acting as\n     * an User Agent Server.\n     * \n     * @return the address object of the remote party.\n     */\n    public javax2.sip.address.Address getRemoteParty() {\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"gettingRemoteParty \" + this.remoteParty);\n        }\n        return this.remoteParty;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getRemoteTarget()\n     */\n    public javax2.sip.address.Address getRemoteTarget() {\n\n        return this.remoteTarget;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#getState()\n     */\n    public DialogState getState() {\n        if (this.dialogState == NULL_STATE)\n            return null; // not yet initialized\n        return DialogState.getObject(this.dialogState);\n    }\n\n    /**\n     * Returns true if this Dialog is secure i.e. if the request arrived over TLS, and the\n     * Request-URI contained a SIPS URI, the \"secure\" flag is set to TRUE.\n     * \n     * @return <code>true</code> if this dialogue was established using a sips URI over TLS, and\n     *         <code>false</code> otherwise.\n     */\n    public boolean isSecure() {\n        return this.firstTransactionSecure;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#sendAck(javax2.sip.message.Request)\n     */\n    public void sendAck(Request request) throws SipException {\n        this.sendAck(request, true);\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#createRequest(java.lang.String)\n     */\n    public Request createRequest(String method) throws SipException {\n\n        if (method.equals(Request.ACK) || method.equals(Request.PRACK)) {\n            throw new SipException(\"Invalid method specified for createRequest:\" + method);\n        }\n        if (lastResponse != null)\n            return this.createRequest(method, this.lastResponse);\n        else\n            throw new SipException(\"Dialog not yet established -- no response!\");\n    }\n\n    /**\n     * The method that actually does the work of creating a request.\n     * \n     * @param method\n     * @param sipResponse\n     * @return\n     * @throws SipException\n     */\n    private Request createRequest(String method, SIPResponse sipResponse) throws SipException {\n        /*\n         * Check if the dialog is in the right state (RFC 3261 section 15). The caller's UA MAY\n         * send a BYE for either CONFIRMED or EARLY dialogs, and the callee's UA MAY send a BYE on\n         * CONFIRMED dialogs, but MUST NOT send a BYE on EARLY dialogs.\n         * \n         * Throw out cancel request.\n         */\n\n        if (method == null || sipResponse == null)\n            throw new NullPointerException(\"null argument\");\n\n        if (method.equals(Request.CANCEL))\n            throw new SipException(\"Dialog.createRequest(): Invalid request\");\n\n        if (this.getState() == null\n                || (this.getState().getValue() == TERMINATED_STATE && !method\n                        .equalsIgnoreCase(Request.BYE))\n                || (this.isServer() && this.getState().getValue() == EARLY_STATE && method\n                        .equalsIgnoreCase(Request.BYE)))\n            throw new SipException(\"Dialog  \" + getDialogId()\n                    + \" not yet established or terminated \" + this.getState());\n\n        SipUri sipUri = null;\n        if (this.getRemoteTarget() != null)\n            sipUri = (SipUri) this.getRemoteTarget().getURI().clone();\n        else {\n            sipUri = (SipUri) this.getRemoteParty().getURI().clone();\n            sipUri.clearUriParms();\n        }\n\n        CSeq cseq = new CSeq();\n        try {\n            cseq.setMethod(method);\n            cseq.setSeqNumber(this.getLocalSeqNumber());\n        } catch (Exception ex) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logError(\"Unexpected error\");\n            InternalErrorHandler.handleException(ex);\n        }\n        /*\n         * Add a via header for the outbound request based on the transport of the message\n         * processor.\n         */\n\n        ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider\n                .getListeningPoint(sipResponse.getTopmostVia().getTransport());\n        if (lp == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logError(\n                        \"Cannot find listening point for transport \"\n                                + sipResponse.getTopmostVia().getTransport());\n            throw new SipException(\"Cannot find listening point for transport \"\n                    + sipResponse.getTopmostVia().getTransport());\n        }\n        Via via = lp.getViaHeader();\n\n        From from = new From();\n        from.setAddress(this.localParty);\n        To to = new To();\n        to.setAddress(this.remoteParty);\n        SIPRequest sipRequest = sipResponse.createRequest(sipUri, via, cseq, from, to);\n\n        /*\n         * The default contact header is obtained from the provider. The application can override\n         * this.\n         * \n         * JvB: Should only do this for target refresh requests, ie not for BYE, PRACK, etc\n         */\n\n        if (SIPRequest.isTargetRefresh(method)) {\n            ContactHeader contactHeader = ((ListeningPointImpl) this.sipProvider\n                    .getListeningPoint(lp.getTransport())).createContactHeader();\n\n            ((SipURI) contactHeader.getAddress().getURI()).setSecure(this.isSecure());\n            sipRequest.setHeader(contactHeader);\n        }\n\n        try {\n            /*\n             * Guess of local sequence number - this is being re-set when the request is actually\n             * dispatched\n             */\n            cseq = (CSeq) sipRequest.getCSeq();\n            cseq.setSeqNumber(this.localSequenceNumber + 1);\n\n        } catch (InvalidArgumentException ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n\n        if (method.equals(Request.SUBSCRIBE)) {\n\n            if (eventHeader != null)\n                sipRequest.addHeader(eventHeader);\n\n        }\n\n        /*\n         * RFC3261, section 12.2.1.1:\n         * \n         * The URI in the To field of the request MUST be set to the remote URI from the dialog\n         * state. The tag in the To header field of the request MUST be set to the remote tag of\n         * the dialog ID. The From URI of the request MUST be set to the local URI from the dialog\n         * state. The tag in the From header field of the request MUST be set to the local tag of\n         * the dialog ID. If the value of the remote or local tags is null, the tag parameter MUST\n         * be omitted from the To or From header fields, respectively.\n         */\n\n        try {\n            if (this.getLocalTag() != null) {\n                from.setTag(this.getLocalTag());\n            } else {\n                from.removeTag();\n            }\n            if (this.getRemoteTag() != null) {\n                to.setTag(this.getRemoteTag());\n            } else {\n                to.removeTag();\n            }\n        } catch (ParseException ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n\n        // get the route list from the dialog.\n        this.updateRequest(sipRequest);\n\n        return sipRequest;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#sendRequest(javax2.sip.ClientTransaction)\n     */\n\n    public void sendRequest(ClientTransaction clientTransactionId)\n            throws TransactionDoesNotExistException, SipException {\n        this.sendRequest(clientTransactionId, !this.isBackToBackUserAgent);\n    }\n\n    public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving)\n            throws TransactionDoesNotExistException, SipException {\n\n        if ( (!allowInterleaving)\n                && clientTransactionId.getRequest().getMethod().equals(Request.INVITE)) {\n            new Thread((new ReInviteSender(clientTransactionId))).start();\n            return;\n        }\n\n        SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId)\n                .getOriginalRequest();\n\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\n                    \"dialog.sendRequest \" + \" dialog = \" + this + \"\\ndialogRequest = \\n\"\n                            + dialogRequest);\n\n        if (clientTransactionId == null)\n            throw new NullPointerException(\"null parameter\");\n\n        if (dialogRequest.getMethod().equals(Request.ACK)\n                || dialogRequest.getMethod().equals(Request.CANCEL))\n            throw new SipException(\"Bad Request Method. \" + dialogRequest.getMethod());\n\n        // JvB: added, allow re-sending of BYE after challenge\n        if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logError(\"BYE already sent for \" + this);\n            throw new SipException(\"Cannot send request; BYE already sent\");\n        }\n\n        if (dialogRequest.getTopmostVia() == null) {\n            Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader();\n            dialogRequest.addHeader(via);\n        }\n        if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) {\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logError(\"CallID \" + this.getCallId());\n                sipStack.getStackLogger().logError(\n                        \"RequestCallID = \" + dialogRequest.getCallId().getCallId());\n                sipStack.getStackLogger().logError(\"dialog =  \" + this);\n            }\n            throw new SipException(\"Bad call ID in request\");\n        }\n\n        // Set the dialog back pointer.\n        ((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId);\n\n        this.addTransaction((SIPTransaction) clientTransactionId);\n        // Enable the retransmission filter for the transaction\n\n        ((SIPClientTransaction) clientTransactionId).isMapped = true;\n\n        From from = (From) dialogRequest.getFrom();\n        To to = (To) dialogRequest.getTo();\n\n        // Caller already did the tag assignment -- check to see if the\n        // tag assignment is OK.\n        if (this.getLocalTag() != null && from.getTag() != null\n                && !from.getTag().equals(this.getLocalTag()))\n            throw new SipException(\"From tag mismatch expecting  \" + this.getLocalTag());\n\n        if (this.getRemoteTag() != null && to.getTag() != null\n                && !to.getTag().equals(this.getRemoteTag())) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tthis.sipStack.getStackLogger().logWarning(\n                    \"To header tag mismatch expecting \" + this.getRemoteTag());\n        }\n        /*\n         * The application is sending a NOTIFY before sending the response of the dialog.\n         */\n        if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) {\n            if (!this.getMethod().equals(Request.SUBSCRIBE))\n                throw new SipException(\"Trying to send NOTIFY without SUBSCRIBE Dialog!\");\n            this.setLocalTag(from.getTag());\n\n        }\n\n        try {\n            if (this.getLocalTag() != null)\n                from.setTag(this.getLocalTag());\n            if (this.getRemoteTag() != null)\n                to.setTag(this.getRemoteTag());\n\n        } catch (ParseException ex) {\n\n            InternalErrorHandler.handleException(ex);\n\n        }\n\n        Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop();\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"Using hop = \" + hop.getHost() + \" : \" + hop.getPort());\n        }\n\n        try {\n            MessageChannel messageChannel = sipStack.createRawMessageChannel(this\n                    .getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(),\n                    this.firstTransactionPort, hop);\n            \n            MessageChannel oldChannel = ((SIPClientTransaction) \n            \t\tclientTransactionId).getMessageChannel();\n\n            // Remove this from the connection cache if it is in the\n            // connection\n            // cache and is not yet active.\n            oldChannel.uncache();\n\n            // Not configured to cache client connections.\n            if (!sipStack.cacheClientConnections) {\n                oldChannel.useCount--;\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"oldChannel: useCount \" + oldChannel.useCount);\n\n            }\n\n            if (messageChannel == null) {\n                /*\n                 * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried\n                 * but the resulting next hop cannot be resolved (recall that the exception thrown\n                 * is caught and ignored in SIPStack.createMessageChannel() so we end up here with\n                 * a null messageChannel instead of the exception handler below). All else\n                 * failing, try the outbound proxy in accordance with 8.1.2, in particular: This\n                 * ensures that outbound proxies that do not add Record-Route header field values\n                 * will drop out of the path of subsequent requests. It allows endpoints that\n                 * cannot resolve the first Route URI to delegate that task to an outbound proxy.\n                 * \n                 * if one considers the 'first Route URI' of a request constructed according to\n                 * 12.2.1.1 to be the request URI when the route set is empty.\n                 */\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \"Null message channel using outbound proxy !\");\n                Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy();\n                if (outboundProxy == null)\n                    throw new SipException(\"No route found! hop=\" + hop);\n                messageChannel = sipStack.createRawMessageChannel(this.getSipProvider()\n                        .getListeningPoint(outboundProxy.getTransport()).getIPAddress(),\n                        this.firstTransactionPort, outboundProxy);\n                if (messageChannel != null)\n                    ((SIPClientTransaction) clientTransactionId)\n                            .setEncapsulatedChannel(messageChannel);\n            } else {\n                ((SIPClientTransaction) clientTransactionId)\n                        .setEncapsulatedChannel(messageChannel);\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\"using message channel \" + messageChannel);\n\n                }\n\n            }\n\n            if (messageChannel != null) messageChannel.useCount++;\n            \n            // See if we need to release the previously mapped channel.\n            if ((!sipStack.cacheClientConnections) && oldChannel != null\n                    && oldChannel.useCount <= 0)\n                oldChannel.close();            \n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(ex);\n            throw new SipException(\"Could not create message channel\", ex);\n        }\n\n        try {\n            // Increment before setting!!\n            localSequenceNumber++;\n            dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber());\n        } catch (InvalidArgumentException ex) {\n            sipStack.getStackLogger().logFatalError(ex.getMessage());\n        }\n\n        try {\n            ((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest);\n            /*\n             * Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED\n             * state so we only set state after successful send.\n             */\n            if (dialogRequest.getMethod().equals(Request.BYE)) {\n                this.byeSent = true;\n                /*\n                 * Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182.\n                 */\n                if (isTerminatedOnBye()) {\n                    this.setState(DialogState._TERMINATED);\n                }\n            }\n        } catch (IOException ex) {\n            throw new SipException(\"error sending message\", ex);\n        }\n\n    }\n\n    /**\n     * Return yes if the last response is to be retransmitted.\n     */\n    private boolean toRetransmitFinalResponse(int T2) {\n        if (--retransmissionTicksLeft == 0) {\n            if (2 * prevRetransmissionTicks <= T2)\n                this.retransmissionTicksLeft = 2 * prevRetransmissionTicks;\n            else\n                this.retransmissionTicksLeft = prevRetransmissionTicks;\n            this.prevRetransmissionTicks = retransmissionTicksLeft;\n            return true;\n        } else\n            return false;\n\n    }\n\n    protected void setRetransmissionTicks() {\n        this.retransmissionTicksLeft = 1;\n        this.prevRetransmissionTicks = 1;\n    }\n\n    /**\n     * Resend the last ack.\n     */\n    public void resendAck() throws SipException {\n        // Check for null.\n\n        if (this.getLastAckSent() != null) {\n            if (getLastAckSent().getHeader(TimeStampHeader.NAME) != null\n                    && sipStack.generateTimeStampHeader) {\n                TimeStamp ts = new TimeStamp();\n                try {\n                    ts.setTimeStamp(System.currentTimeMillis());\n                    getLastAckSent().setHeader(ts);\n                } catch (InvalidArgumentException e) {\n\n                }\n            }\n            this.sendAck(getLastAckSent(), false);\n        }\n\n    }\n\n    /**\n     * Get the method of the request/response that resulted in the creation of the Dialog.\n     * \n     * @return -- the method of the dialog.\n     */\n    public String getMethod() {\n        // Method of the request or response used to create this dialog\n        return this.method;\n    }\n\n    /**\n     * Start the dialog timer.\n     * \n     * @param transaction\n     */\n\n    protected void startTimer(SIPServerTransaction transaction) {\n        if (this.timerTask != null && timerTask.transaction == transaction) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logDebug(\"Timer already running for \" + getDialogId());\n            return;\n        }\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"Starting dialog timer for \" + getDialogId());\n        this.ackSeen = false;\n        \n\t\tacquireTimerTaskSem();\n\t\ttry {\n\t        if (this.timerTask != null) {\n\t            this.timerTask.transaction = transaction;\n\t        } else {\n\t            this.timerTask = new DialogTimerTask(transaction);\n\t            sipStack.getTimer().schedule(timerTask, SIPTransactionStack.BASE_TIMER_INTERVAL,\n\t                    SIPTransactionStack.BASE_TIMER_INTERVAL);\n\t        }\n\t\t} finally {\n\t\t\treleaseTimerTaskSem();\n\t\t}\n        \n        this.setRetransmissionTicks();\n    }\n\n    /**\n     * Stop the dialog timer. This is called when the dialog is terminated.\n     * \n     */\n    protected void stopTimer() {\n        try {\n        \tacquireTimerTaskSem();\n        \ttry {\n\t            if (this.timerTask != null) {            \t\n\t            \tthis.timerTask.cancel();\n\t\t            this.timerTask = null;\n\t            }   \n        \t} finally {\n        \t\treleaseTimerTaskSem();\n        \t}\n        } catch (Exception ex) {\n        }\n    }\n\n    /*\n     * (non-Javadoc) Retransmissions of the reliable provisional response cease when a matching\n     * PRACK is received by the UA core. PRACK is like any other request within a dialog, and the\n     * UAS core processes it according to the procedures of Sections 8.2 and 12.2.2 of RFC 3261. A\n     * matching PRACK is defined as one within the same dialog as the response, and whose method,\n     * CSeq-num, and response-num in the RAck header field match, respectively, the method from\n     * the CSeq, the sequence number from the CSeq, and the sequence number from the RSeq of the\n     * reliable provisional response.\n     * \n     * @see javax2.sip.Dialog#createPrack(javax2.sip.message.Response)\n     */\n    public Request createPrack(Response relResponse) throws DialogDoesNotExistException,\n            SipException {\n\n        if (this.getState() == null || this.getState().equals(DialogState.TERMINATED))\n            throw new DialogDoesNotExistException(\"Dialog not initialized or terminated\");\n\n        if ((RSeq) relResponse.getHeader(RSeqHeader.NAME) == null) {\n            throw new SipException(\"Missing RSeq Header\");\n        }\n\n        try {\n            SIPResponse sipResponse = (SIPResponse) relResponse;\n            SIPRequest sipRequest = (SIPRequest) this.createRequest(Request.PRACK,\n                    (SIPResponse) relResponse);\n            String toHeaderTag = sipResponse.getTo().getTag();\n            sipRequest.setToTag(toHeaderTag);\n            RAck rack = new RAck();\n            RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME);\n            rack.setMethod(sipResponse.getCSeq().getMethod());\n            rack.setCSequenceNumber((int) sipResponse.getCSeq().getSeqNumber());\n            rack.setRSequenceNumber(rseq.getSeqNumber());\n            sipRequest.setHeader(rack);\n            return (Request) sipRequest;\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n            return null;\n        }\n\n    }\n\n    private void updateRequest(SIPRequest sipRequest) {\n\n        RouteList rl = this.getRouteList();\n        if (rl.size() > 0) {\n            sipRequest.setHeader(rl);\n        } else {\n            sipRequest.removeHeader(RouteHeader.NAME);\n        }\n        if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {\n            sipRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());\n        }\n\n    }\n\n    /*\n     * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx received from the\n     * transaction layer. The header fields of the ACK are constructed in the same way as for any\n     * request sent within a dialog (see Section 12) with the exception of the CSeq and the header\n     * fields related to authentication. The sequence number of the CSeq header field MUST be the\n     * same as the INVITE being acknowledged, but the CSeq method MUST be ACK. The ACK MUST\n     * contain the same credentials as the INVITE. If the 2xx contains an offer (based on the\n     * rules above), the ACK MUST carry an answer in its body. If the offer in the 2xx response is\n     * not acceptable, the UAC core MUST generate a valid answer in the ACK and then send a BYE\n     * immediately.\n     * \n     * Note that for the case of forked requests, you can create multiple outgoing invites each\n     * with a different cseq and hence you need to supply the invite.\n     * \n     * @see javax2.sip.Dialog#createAck(long)\n     */\n    public Request createAck(long cseqno) throws InvalidArgumentException, SipException {\n\n        // JvB: strictly speaking it is allowed to start a dialog with\n        // SUBSCRIBE,\n        // then send INVITE+ACK later on\n        if (!method.equals(Request.INVITE))\n            throw new SipException(\"Dialog was not created with an INVITE\" + method);\n\n        if (cseqno <= 0)\n            throw new InvalidArgumentException(\"bad cseq <= 0 \");\n        else if (cseqno > ((((long) 1) << 32) - 1))\n            throw new InvalidArgumentException(\"bad cseq > \" + ((((long) 1) << 32) - 1));\n\n        if (this.remoteTarget == null) {\n            throw new SipException(\"Cannot create ACK - no remote Target!\");\n        }\n\n        if (this.sipStack.isLoggingEnabled()) {\n            this.sipStack.getStackLogger().logDebug(\"createAck \" + this + \" cseqno \" + cseqno);\n        }\n\n        // MUST ack in the same order that the OKs were received. This traps\n        // out of order ACK sending. Old ACKs seqno's can always be ACKed.\n        if (lastInviteOkReceived < cseqno) {\n        \tif (sipStack.isLoggingEnabled()) {\n        \t\tthis.sipStack.getStackLogger().logDebug(\n                    \"WARNING : Attempt to crete ACK without OK \" + this);\n            \tthis.sipStack.getStackLogger().logDebug(\"LAST RESPONSE = \" + this.lastResponse);\n        \t}\n            throw new SipException(\"Dialog not yet established -- no OK response!\");\n        }\n\n        try {\n\n            // JvB: Transport from first entry in route set, or remote Contact\n            // if none\n            // Only used to find correct LP & create correct Via\n            SipURI uri4transport = null;\n\n            if (this.routeList != null && !this.routeList.isEmpty()) {\n                Route r = (Route) this.routeList.getFirst();\n                uri4transport = ((SipURI) r.getAddress().getURI());\n            } else { // should be !=null, checked above\n                uri4transport = ((SipURI) this.remoteTarget.getURI());\n            }\n\n            String transport = uri4transport.getTransportParam();\n            if (transport == null) {\n                // JvB fix: also support TLS\n                transport = uri4transport.isSecure() ? ListeningPoint.TLS : ListeningPoint.UDP;\n            }\n            ListeningPointImpl lp = (ListeningPointImpl) sipProvider.getListeningPoint(transport);\n            if (lp == null) {\n            \tif (sipStack.isLoggingEnabled()) {\n            \t\tsipStack.getStackLogger().logError(\n                        \"remoteTargetURI \" + this.remoteTarget.getURI());\n                \tsipStack.getStackLogger().logError(\"uri4transport = \" + uri4transport);\n                \tsipStack.getStackLogger().logError(\"No LP found for transport=\" + transport);\n            \t}\n                throw new SipException(\n                        \"Cannot create ACK - no ListeningPoint for transport towards next hop found:\"\n                                + transport);\n            }\n            SIPRequest sipRequest = new SIPRequest();\n            sipRequest.setMethod(Request.ACK);\n            sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI().clone());\n            sipRequest.setCallId(this.callIdHeader);\n            sipRequest.setCSeq(new CSeq(cseqno, Request.ACK));\n            List<Via> vias = new ArrayList<Via>();\n            // Via via = lp.getViaHeader();\n            // The user may have touched the sentby for the response.\n            // so use the via header extracted from the response for the ACK =>\n            // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=205\n            // strip the params from the via of the response and use the params from the\n            // original request\n            Via via = this.lastResponse.getTopmostVia();\n            via.removeParameters();\n            if (originalRequest != null && originalRequest.getTopmostVia() != null) {\n                NameValueList originalRequestParameters = originalRequest.getTopmostVia()\n                        .getParameters();\n                if (originalRequestParameters != null && originalRequestParameters.size() > 0) {\n                    via.setParameters((NameValueList) originalRequestParameters.clone());\n                }\n            }\n            via.setBranch(Utils.getInstance().generateBranchId()); // new branch\n            vias.add(via);\n            sipRequest.setVia(vias);\n            From from = new From();\n            from.setAddress(this.localParty);\n            from.setTag(this.myTag);\n            sipRequest.setFrom(from);\n            To to = new To();\n            to.setAddress(this.remoteParty);\n            if (hisTag != null)\n                to.setTag(this.hisTag);\n            sipRequest.setTo(to);\n            sipRequest.setMaxForwards(new MaxForwards(70));\n\n            if (this.originalRequest != null) {\n                Authorization authorization = this.originalRequest.getAuthorization();\n                if (authorization != null)\n                    sipRequest.setHeader(authorization);\n            }\n\n            // ACKs for 2xx responses\n            // use the Route values learned from the Record-Route of the 2xx\n            // responses.\n            this.updateRequest(sipRequest);\n\n            return sipRequest;\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n            throw new SipException(\"unexpected exception \", ex);\n        }\n\n    }\n\n    /**\n     * Get the provider for this Dialog.\n     * \n     * SPEC_REVISION\n     * \n     * @return -- the SIP Provider associated with this transaction.\n     */\n    public SipProviderImpl getSipProvider() {\n        return this.sipProvider;\n    }\n\n    /**\n     * @param sipProvider the sipProvider to set\n     */\n    public void setSipProvider(SipProviderImpl sipProvider) {\n        this.sipProvider = sipProvider;\n    }\n\n    /**\n     * Check the tags of the response against the tags of the Dialog. Return true if the respnse\n     * matches the tags of the dialog. We do this check wehn sending out a response.\n     * \n     * @param sipResponse -- the response to check.\n     * \n     */\n    public void setResponseTags(SIPResponse sipResponse) {\n        if (this.getLocalTag() != null || this.getRemoteTag() != null) {\n            return;\n        }\n        String responseFromTag = sipResponse.getFromTag();\n        if ( responseFromTag != null ) {\n            if (responseFromTag.equals(this.getLocalTag())) {\n                sipResponse.setToTag(this.getRemoteTag());\n            } else if (responseFromTag.equals(this.getRemoteTag())) {\n                sipResponse.setToTag(this.getLocalTag());\n            }\n        } else {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logWarning(\"No from tag in response! Not RFC 3261 compatible.\");\n        }\n\n    }\n\n    /**\n     * Set the last response for this dialog. This method is called for updating the dialog state\n     * when a response is either sent or received from within a Dialog.\n     * \n     * @param transaction -- the transaction associated with the response\n     * @param sipResponse -- the last response to set.\n     */\n    public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) {\n        this.callIdHeader = sipResponse.getCallId();     \n        int statusCode = sipResponse.getStatusCode();\n        if (statusCode == 100) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logWarning(\n                    \"Invalid status code - 100 in setLastResponse - ignoring\");\n            return;\n        }\n\n        this.lastResponse = sipResponse;\n        this.setAssigned();\n        // Adjust state of the Dialog state machine.\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\n                    \"sipDialog: setLastResponse:\" + this + \" lastResponse = \"\n                            + this.lastResponse.getFirstLine());\n        }\n        if (this.getState() == DialogState.TERMINATED) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"sipDialog: setLastResponse -- dialog is terminated - ignoring \");\n            }\n            // Capture the OK response for later use in createAck\n            // This is handy for late arriving OK's that we want to ACK.\n            if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) {\n               \n                this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(),\n                        this.lastInviteOkReceived);\n            }\n            return;\n        }\n        String cseqMethod = sipResponse.getCSeq().getMethod();\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logStackTrace();\n            sipStack.getStackLogger().logDebug(\"cseqMethod = \" + cseqMethod);\n            sipStack.getStackLogger().logDebug(\"dialogState = \" + this.getState());\n            sipStack.getStackLogger().logDebug(\"method = \" + this.getMethod());\n            sipStack.getStackLogger().logDebug(\"statusCode = \" + statusCode);\n            sipStack.getStackLogger().logDebug(\"transaction = \" + transaction);\n        }\n\n        // JvB: don't use \"!this.isServer\" here\n        // note that the transaction can be null for forked\n        // responses.\n        if (transaction == null || transaction instanceof ClientTransaction) {\n            if (sipStack.isDialogCreated(cseqMethod)) {\n                // Make a final tag assignment.\n                if (getState() == null && (statusCode / 100 == 1)) {\n                    /*\n                     * Guard aginst slipping back into early state from confirmed state.\n                     */\n                    // Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported)\n                    setState(SIPDialog.EARLY_STATE);\n                    if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported)\n                            && this.getRemoteTag() == null) {\n                        setRemoteTag(sipResponse.getToTag());\n                        this.setDialogId(sipResponse.getDialogId(false));\n                        sipStack.putDialog(this);\n                        this.addRoute(sipResponse);\n                    }\n                } else if (getState() != null && getState().equals(DialogState.EARLY)\n                        && statusCode / 100 == 1) {\n                    /*\n                     * This case occurs for forked dialog responses. The To tag can change as a\n                     * result of the forking. The remote target can also change as a result of the\n                     * forking.\n                     */\n                    if (cseqMethod.equals(getMethod()) && transaction != null\n                            && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) {\n                        setRemoteTag(sipResponse.getToTag());\n                        this.setDialogId(sipResponse.getDialogId(false));\n                        sipStack.putDialog(this);\n                        this.addRoute(sipResponse);\n                    }\n                } else if (statusCode / 100 == 2) {\n                    // This is a dialog creating method (such as INVITE).\n                    // 2xx response -- set the state to the confirmed\n                    // state. To tag is MANDATORY for the response.\n\n                    // Only do this if method equals initial request!\n\n                    if (cseqMethod.equals(getMethod())\n                            && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)\n                            && this.getState() != DialogState.CONFIRMED) {\n                        setRemoteTag(sipResponse.getToTag());\n                        this.setDialogId(sipResponse.getDialogId(false));\n                        sipStack.putDialog(this);\n                        this.addRoute(sipResponse);\n\n                        setState(SIPDialog.CONFIRMED_STATE);\n                    }\n\n                    // Capture the OK response for later use in createAck\n                    if (cseqMethod.equals(Request.INVITE)) {\n                        this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(),\n                                this.lastInviteOkReceived);\n                    }\n\n                } else if (statusCode >= 300\n                        && statusCode <= 699\n                        && (getState() == null || (cseqMethod.equals(getMethod()) && getState()\n                                .getValue() == SIPDialog.EARLY_STATE))) {\n                    /*\n                     * This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 -\n                     * dialog termination. Independent of the method, if a request outside of a\n                     * dialog generates a non-2xx final response, any early dialogs created\n                     * through provisional responses to that request are terminated.\n                     */\n                    setState(SIPDialog.TERMINATED_STATE);\n                }\n\n                /*\n                 * This code is in support of \"proxy\" servers that are constructed as back to back\n                 * user agents. This could be a dialog in the middle of the call setup path\n                 * somewhere. Hence the incoming invite has record route headers in it. The\n                 * response will have additional record route headers. However, for this dialog\n                 * only the downstream record route headers matter. Ideally proxy servers should\n                 * not be constructed as Back to Back User Agents. Remove all the record routes\n                 * that are present in the incoming INVITE so you only have the downstream Route\n                 * headers present in the dialog. Note that for an endpoint - you will have no\n                 * record route headers present in the original request so the loop will not\n                 * execute.\n                 */\n                if ( this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED ) {\n                    if (originalRequest != null) {\n                        RecordRouteList rrList = originalRequest.getRecordRouteHeaders();\n                        if (rrList != null) {\n                            ListIterator<RecordRoute> it = rrList.listIterator(rrList.size());\n                            while (it.hasPrevious()) {\n                                RecordRoute rr = (RecordRoute) it.previous();\n                                Route route = (Route) routeList.getFirst();\n                                if (route != null && rr.getAddress().equals(route.getAddress())) {\n                                    routeList.removeFirst();\n                                } else\n                                    break;\n                            }\n                        }\n                    }\n                }\n\n            } else if (cseqMethod.equals(Request.NOTIFY)\n                    && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals(\n                            Request.REFER)) && sipResponse.getStatusCode() / 100 == 2\n                    && this.getState() == null) {\n                // This is a notify response.\n                this.setDialogId(sipResponse.getDialogId(true));\n                sipStack.putDialog(this);\n                this.setState(SIPDialog.CONFIRMED_STATE);\n\n            } else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2\n                    && isTerminatedOnBye()) {\n                // Dialog will be terminated when the transction is terminated.\n                setState(SIPDialog.TERMINATED_STATE);\n            }\n        } else {\n            // Processing Server Dialog.\n\n            if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2\n                    && this.isTerminatedOnBye()) {\n                /*\n                 * Only transition to terminated state when 200 OK is returned for the BYE. Other\n                 * status codes just result in leaving the state in COMPLETED state.\n                 */\n                this.setState(SIPDialog.TERMINATED_STATE);\n            } else {\n                boolean doPutDialog = false;\n\n                if (getLocalTag() == null && sipResponse.getTo().getTag() != null\n                        && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) {\n                    setLocalTag(sipResponse.getTo().getTag());\n\n                    doPutDialog = true;\n                }\n\n                if (statusCode / 100 != 2) {\n                    if (statusCode / 100 == 1) {\n                        if (doPutDialog) {\n\n                            setState(SIPDialog.EARLY_STATE);\n                            this.setDialogId(sipResponse.getDialogId(true));\n                            sipStack.putDialog(this);\n                        }\n                    } else {\n                        /*\n                         * RFC 3265 chapter 3.1.4.1 \"Non-200 class final responses indicate that\n                         * no subscription or dialog has been created, and no subsequent NOTIFY\n                         * message will be sent. All non-200 class\" + responses (with the\n                         * exception of \"489\", described herein) have the same meanings and\n                         * handling as described in SIP\"\n                         */\n                        // Bug Fix by Jens tinfors\n                        // see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797\n                        if (statusCode == 489\n                                && (cseqMethod.equals(Request.NOTIFY) || cseqMethod\n                                        .equals(Request.SUBSCRIBE))) {\n                        \tif (sipStack.isLoggingEnabled())\n                        \t\tsipStack.getStackLogger().logDebug(\n                                    \"RFC 3265 : Not setting dialog to TERMINATED for 489\");\n                        } else {\n                            // baranowb: simplest fix to\n                            // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175\n                            // application is responsible for terminating in this case\n                            // see rfc 5057 for better explanation\n                            if (!this.isReInvite() && getState() != DialogState.CONFIRMED) {\n                                this.setState(SIPDialog.TERMINATED_STATE);\n                            }\n                        }\n                    }\n\n                } else {\n\n                    /*\n                     * JvB: RFC4235 says that when sending 2xx on UAS side, state should move to\n                     * CONFIRMED\n                     */\n                    if (this.dialogState <= SIPDialog.EARLY_STATE\n                            && (cseqMethod.equals(Request.INVITE)\n                                    || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod\n                                    .equals(Request.REFER))) {\n                        this.setState(SIPDialog.CONFIRMED_STATE);\n                    }\n\n                    if (doPutDialog) {\n                        this.setDialogId(sipResponse.getDialogId(true));\n                        sipStack.putDialog(this);\n                    }\n                    /*\n                     * We put the dialog into the table. We must wait for ACK before re-INVITE is\n                     * sent\n                     */\n                    if (transaction.getState() != TransactionState.TERMINATED\n                            && sipResponse.getStatusCode() == Response.OK\n                            && cseqMethod.equals(Request.INVITE)\n                            && this.isBackToBackUserAgent) {\n                            /*\n                             * Acquire the flag for re-INVITE so that we cannot re-INVITE before\n                             * ACK is received.\n                             */\n                            if (!this.takeAckSem()) {\n                                if (sipStack.isLoggingEnabled()) {\n                                    sipStack.getStackLogger().logDebug(\n                                            \"Delete dialog -- cannot acquire ackSem\");\n                                }\n                                this.delete();\n                                return;\n                            }\n                        \n                    }\n                }\n            }\n\n        }\n\n    }\n\n    /**\n     * Start the retransmit timer.\n     * \n     * @param sipServerTx -- server transaction on which the response was sent\n     * @param response - response that was sent.\n     */\n    public void startRetransmitTimer(SIPServerTransaction sipServerTx, Response response) {\n        if (sipServerTx.getRequest().getMethod().equals(Request.INVITE)\n                && response.getStatusCode() / 100 == 2) {\n            this.startTimer(sipServerTx);\n        }\n    }\n\n    /**\n     * @return -- the last response associated with the dialog.\n     */\n    public SIPResponse getLastResponse() {\n\n        return lastResponse;\n    }\n\n    /**\n     * Do taget refresh dialog state updates.\n     * \n     * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact header fields.\n     * However, these requests do not cause the dialog's route set to be modified, although they\n     * may modify the remote target URI. Specifically, requests that are not target refresh\n     * requests do not modify the dialog's remote target URI, and requests that are target refresh\n     * requests do. For dialogs that have been established with an\n     * \n     * INVITE, the only target refresh request defined is re-INVITE (see Section 14). Other\n     * extensions may define different target refresh requests for dialogs established in other\n     * ways.\n     */\n    private void doTargetRefresh(SIPMessage sipMessage) {\n\n        ContactList contactList = sipMessage.getContactHeaders();\n\n        /*\n         * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the target refresh for\n         * subscribe dialogs from the client side. This modifies the remote target URI potentially\n         */\n        if (contactList != null) {\n\n            Contact contact = (Contact) contactList.getFirst();\n            this.setRemoteTarget(contact);\n\n        }\n\n    }\n\n    private static final boolean optionPresent(ListIterator l, String option) {\n        while (l.hasNext()) {\n            OptionTag opt = (OptionTag) l.next();\n            if (opt != null && option.equalsIgnoreCase(opt.getOptionTag()))\n                return true;\n        }\n        return false;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#createReliableProvisionalResponse(int)\n     */\n    public Response createReliableProvisionalResponse(int statusCode)\n            throws InvalidArgumentException, SipException {\n\n        if (!(firstTransactionIsServerTransaction)) {\n            throw new SipException(\"Not a Server Dialog!\");\n\n        }\n        /*\n         * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional\n         * responses numbered 101 to 199 may be sent reliably. If the request did not include\n         * either a Supported or Require header field indicating this feature, the UAS MUST NOT\n         * send the provisional response reliably.\n         */\n        if (statusCode <= 100 || statusCode > 199)\n            throw new InvalidArgumentException(\"Bad status code \");\n        SIPRequest request = this.originalRequest;\n        if (!request.getMethod().equals(Request.INVITE))\n            throw new SipException(\"Bad method\");\n\n        ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME);\n        if (list == null || !optionPresent(list, \"100rel\")) {\n            list = request.getHeaders(RequireHeader.NAME);\n            if (list == null || !optionPresent(list, \"100rel\")) {\n                throw new SipException(\"No Supported/Require 100rel header in the request\");\n            }\n        }\n\n        SIPResponse response = request.createResponse(statusCode);\n        /*\n         * The provisional response to be sent reliably is constructed by the UAS core according\n         * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require\n         * header field containing the option tag 100rel, and MUST include an RSeq header field.\n         * The value of the header field for the first reliable provisional response in a\n         * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen\n         * uniformly in this range. The RSeq numbering space is within a single transaction. This\n         * means that provisional responses for different requests MAY use the same values for the\n         * RSeq number.\n         */\n        Require require = new Require();\n        try {\n            require.setOptionTag(\"100rel\");\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n        response.addHeader(require);\n        RSeq rseq = new RSeq();\n        /*\n         * set an arbitrary sequence number. This is actually set when the response is sent out\n         */\n        rseq.setSeqNumber(1L);\n        /*\n         * Copy the record route headers from the request to the response ( Issue 160 ). Note that\n         * other 1xx headers do not get their Record Route headers copied over but reliable\n         * provisional responses do. See RFC 3262 Table 2.\n         */\n        RecordRouteList rrl = request.getRecordRouteHeaders();\n        if (rrl != null) {\n            RecordRouteList rrlclone = (RecordRouteList) rrl.clone();\n            response.setHeader(rrlclone);\n        }\n\n        return response;\n    }\n\n    /**\n     * Do the processing necessary for the PRACK\n     * \n     * @param prackRequest\n     * @return true if this is the first time the tx has seen the prack ( and hence needs to be\n     *         passed up to the TU)\n     */\n    public boolean handlePrack(SIPRequest prackRequest) {\n        /*\n         * The RAck header is sent in a PRACK request to support reliability of provisional\n         * responses. It contains two numbers and a method tag. The first number is the value from\n         * the RSeq header in the provisional response that is being acknowledged. The next\n         * number, and the method, are copied from the CSeq in the response that is being\n         * acknowledged. The method name in the RAck header is case sensitive.\n         */\n        if (!this.isServer()) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Dropping Prack -- not a server Dialog\");\n            return false;\n        }\n        SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this\n                .getFirstTransaction();\n        SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse();\n\n        if (sipResponse == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger()\n                        .logDebug(\"Dropping Prack -- ReliableResponse not found\");\n            return false;\n        }\n\n        RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME);\n\n        if (rack == null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Dropping Prack -- rack header not found\");\n            return false;\n        }\n        CSeq cseq = (CSeq) sipResponse.getCSeq();\n\n        if (!rack.getMethod().equals(cseq.getMethod())) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"Dropping Prack -- CSeq Header does not match PRACK\");\n            return false;\n        }\n\n        if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"Dropping Prack -- CSeq Header does not match PRACK\");\n            return false;\n        }\n\n        RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME);\n\n        if (rack.getRSequenceNumber() != rseq.getSeqNumber()) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                        \"Dropping Prack -- RSeq Header does not match PRACK\");\n            return false;\n        }\n\n        return sipServerTransaction.prackRecieved();\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#sendReliableProvisionalResponse(javax2.sip.message.Response)\n     */\n    public void sendReliableProvisionalResponse(Response relResponse) throws SipException {\n        if (!this.isServer()) {\n            throw new SipException(\"Not a Server Dialog\");\n        }\n\n        SIPResponse sipResponse = (SIPResponse) relResponse;\n\n        if (relResponse.getStatusCode() == 100)\n            throw new SipException(\"Cannot send 100 as a reliable provisional response\");\n\n        if (relResponse.getStatusCode() / 100 > 2)\n            throw new SipException(\n                    \"Response code is not a 1xx response - should be in the range 101 to 199 \");\n\n        /*\n         * Do a little checking on the outgoing response.\n         */\n        if (sipResponse.getToTag() == null) {\n            throw new SipException(\n                    \"Badly formatted response -- To tag mandatory for Reliable Provisional Response\");\n        }\n        ListIterator requireList = (ListIterator) relResponse.getHeaders(RequireHeader.NAME);\n        boolean found = false;\n\n        if (requireList != null) {\n\n            while (requireList.hasNext() && !found) {\n                RequireHeader rh = (RequireHeader) requireList.next();\n                if (rh.getOptionTag().equalsIgnoreCase(\"100rel\")) {\n                    found = true;\n                }\n            }\n        }\n\n        if (!found) {\n            Require require = new Require(\"100rel\");\n            relResponse.addHeader(require);\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"Require header with optionTag 100rel is needed -- adding one\");\n            }\n\n        }\n\n        SIPServerTransaction serverTransaction = (SIPServerTransaction) this\n                .getFirstTransaction();\n        /*\n         * put into the dialog table before sending the response so as to avoid race condition\n         * with PRACK\n         */\n        this.setLastResponse(serverTransaction, sipResponse);\n\n        this.setDialogId(sipResponse.getDialogId(true));\n\n        serverTransaction.sendReliableProvisionalResponse(relResponse);\n\n        this.startRetransmitTimer(serverTransaction, relResponse);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see javax2.sip.Dialog#terminateOnBye(boolean)\n     */\n    public void terminateOnBye(boolean terminateFlag) throws SipException {\n\n        this.terminateOnBye = terminateFlag;\n    }\n\n    /**\n     * Set the \"assigned\" flag to true. We do this when inserting the dialog into the dialog table\n     * of the stack.\n     * \n     */\n    public void setAssigned() {\n        this.isAssigned = true;\n    }\n\n    /**\n     * Return true if the dialog has already been mapped to a transaction.\n     * \n     */\n\n    public boolean isAssigned() {\n        return this.isAssigned;\n    }\n\n    /**\n     * Get the contact header that the owner of this dialog assigned. Subsequent Requests are\n     * considered to belong to the dialog if the dialog identifier matches and the contact header\n     * matches the ip address and port on which the request is received.\n     * \n     * @return contact header belonging to the dialog.\n     */\n    public Contact getMyContactHeader() {\n    \treturn contactHeader;\n    }\n\n    /**\n     * Do the necessary processing to handle an ACK directed at this Dialog.\n     * \n     * @param ackTransaction -- the ACK transaction that was directed at this dialog.\n     * @return -- true if the ACK was successfully consumed by the Dialog and resulted in the\n     *         dialog state being changed.\n     */\n    public boolean handleAck(SIPServerTransaction ackTransaction) {\n        SIPRequest sipRequest = ackTransaction.getOriginalRequest();\n\n        if (isAckSeen() && getRemoteSeqNumber() == sipRequest.getCSeq().getSeqNumber()) {\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"ACK already seen by dialog -- dropping Ack\" + \" retransmission\");\n            }\n            acquireTimerTaskSem();\n            try {\n            \tif (this.timerTask != null) {            \t\n\t                this.timerTask.cancel();\n\t                this.timerTask = null;\n            \t} \n            } finally {\n        \t\treleaseTimerTaskSem();\n        \t}\n            return false;\n        } else if (this.getState() == DialogState.TERMINATED) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Dialog is terminated -- dropping ACK\");\n            return false;\n\n        } else {\n\n            /*\n             * This could be a re-invite processing. check to see if the ack matches with the last\n             * transaction. s\n             */\n\n            SIPServerTransaction tr = getInviteTransaction();\n\n            SIPResponse sipResponse = (tr != null ? tr.getLastResponse() : null);\n\n            // Idiot check for sending ACK from the wrong side!\n            if (tr != null\n                    && sipResponse != null\n                    && sipResponse.getStatusCode() / 100 == 2\n                    && sipResponse.getCSeq().getMethod().equals(Request.INVITE)\n                    && sipResponse.getCSeq().getSeqNumber() == sipRequest.getCSeq()\n                            .getSeqNumber()) {\n\n                ackTransaction.setDialog(this, sipResponse.getDialogId(false));\n                /*\n                 * record that we already saw an ACK for this dialog.\n                 */\n\n                ackReceived(sipRequest);\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logDebug(\"ACK for 2XX response --- sending to TU \");\n                return true;\n\n            } else {\n                /*\n                 * This happens when the ACK is re-transmitted and arrives too late to be\n                 * processed.\n                 */\n\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\n                            \" INVITE transaction not found  -- Discarding ACK\");\n                return false;\n            }\n        }\n    }\n\n    void setEarlyDialogId(String earlyDialogId) {\n        this.earlyDialogId = earlyDialogId;\n    }\n\n    String getEarlyDialogId() {\n        return earlyDialogId;\n    }\n\n    /**\n     * Release the semaphore for ACK processing so the next re-INVITE may proceed.\n     */\n    void releaseAckSem() {\n        if (this.isBackToBackUserAgent) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"releaseAckSem]\" + this);\n            }\n            this.ackSem.release();\n        }\n\n    }\n\n    boolean takeAckSem() {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"[takeAckSem \" + this);\n        }\n        try {\n            if (!this.ackSem.tryAcquire(2, TimeUnit.SECONDS)) {\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logError(\"Cannot aquire ACK semaphore\");\n                }\n\n                if ( sipStack.isLoggingEnabled() ) {\n                    sipStack.getStackLogger().logDebug(\"Semaphore previously acquired at \" + this.stackTrace);\n                    sipStack.getStackLogger().logStackTrace();\n                    \n                }\n                return false;\n            }\n            \n            if ( sipStack.isLoggingEnabled() ) {\n                \n                this.recordStackTrace();\n            }\n            \n        } catch (InterruptedException ex) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logError(\"Cannot aquire ACK semaphore\");\n            return false;\n\n        }\n        return true;\n\n    }\n\n    /**\n     * @param lastAckReceived the lastAckReceived to set\n     */\n    private void setLastAckReceived(SIPRequest lastAckReceived) {\n        this.lastAckReceived = lastAckReceived;\n    }\n\n    /**\n     * @return the lastAckReceived\n     */\n    protected SIPRequest getLastAckReceived() {\n        return lastAckReceived;\n    }\n\n    /**\n     * @param lastAckSent the lastAckSent to set\n     */\n    private void setLastAckSent(SIPRequest lastAckSent) {\n        this.lastAckSent = lastAckSent;\n    }\n    \n    /**\n     * @return true if an ack was ever sent for this Dialog\n     */\n    public boolean isAtleastOneAckSent() {\n        return this.isAcknowledged;\n    }\n\n    \n    \n    public boolean isBackToBackUserAgent() {\n        return this.isBackToBackUserAgent;\n    }\n    \n    public synchronized void doDeferredDeleteIfNoAckSent(long seqno) {\n\t\tif (sipStack.getTimer() == null) {\n\t\t\tthis.setState(TERMINATED_STATE);\n\t\t} else if(dialogDeleteIfNoAckSentTask == null){\n\t\t\t// Delete the transaction after the max ack timeout.\n\t\t\tdialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno);\n\t\t\tsipStack.getTimer().schedule(\n\t\t\t\t\tdialogDeleteIfNoAckSentTask,\n\t\t\t\t\tSIPTransaction.TIMER_J\n\t\t\t\t\t\t\t* SIPTransactionStack.BASE_TIMER_INTERVAL);\n\t\t}\n\t}\n\n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.DialogExt#setBackToBackUserAgent(boolean)\n     */\n    public void setBackToBackUserAgent() {\n        this.isBackToBackUserAgent = true;   \n    }\n\n\t/**\n\t * @return the eventHeader\n\t */\n\tEventHeader getEventHeader() {\n\t\treturn eventHeader;\n\t}\n\n\t/**\n\t * @param eventHeader the eventHeader to set\n\t */\n\tvoid setEventHeader(EventHeader eventHeader) {\n\t\tthis.eventHeader = eventHeader;\n\t}\t\n\n\t/**\n\t * @param serverTransactionFlag the serverTransactionFlag to set\n\t */\n\tvoid setServerTransactionFlag(boolean serverTransactionFlag) {\n\t\tthis.serverTransactionFlag = serverTransactionFlag;\n\t}\n\n\t/**\n\t * @param reInviteFlag the reinviteFlag to set\n\t */\n\tvoid setReInviteFlag(boolean reInviteFlag) {\n\t\tthis.reInviteFlag = reInviteFlag;\n\t}\n\n  \n\tpublic boolean isSequnceNumberValidation() {\n\t    return this.sequenceNumberValidation;\n\t}\n   \n    public void disableSequenceNumberValidation() {\n        this.sequenceNumberValidation = false;\n    }\n    \n   \n    public void acquireTimerTaskSem() {\n    \tboolean acquired = false;\n        try {\n            acquired = this.timerTaskLock.tryAcquire(10, TimeUnit.SECONDS);\n        } catch ( InterruptedException ex) {\n            acquired = false;\n        }\n        if(!acquired) {\n        \tthrow new IllegalStateException(\"Impossible to acquire the dialog timer task lock\");\n        }\n    }\n    \n    public void releaseTimerTaskSem() {\n        this.timerTaskLock.release();\n    }    \n    \n\t\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPDialogErrorEvent.java",
    "content": "/*\n * This source code has been contributed to the public domain by Mobicents\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.javax2.sip.stack;\n\n\nimport java.util.EventObject;\n\n/**\n * An event that indicates that a dialog has encountered an error.\n *\n * @author jean deruelle\n * @since 2.0\n */\npublic class SIPDialogErrorEvent extends EventObject {\n\n\n    /**\n     * This event ID indicates that the transaction has timed out.\n     */\n    public static final int DIALOG_ACK_NOT_RECEIVED_TIMEOUT = 1;\n\n    /**\n     * This event ID indicates that there was an error sending a message using\n     * the underlying transport.\n     */\n    public static final int DIALOG_ACK_NOT_SENT_TIMEOUT = 2;\n    \n    /**\n     * This event ID indicates a timeout occured waiting to send re-INVITE ( for B2BUA)\n     */\n    public static final int DIALOG_REINVITE_TIMEOUT = 3;\n    \n\n    // ID of this error event\n    private int errorID;\n\n    /**\n     * Creates a dialog error event.\n     *\n     * @param sourceDialog Dialog which is raising the error.\n     * @param dialogErrorID ID of the error that has ocurred.\n     */\n    SIPDialogErrorEvent(\n        SIPDialog sourceDialog,\n        int dialogErrorID) {\n\n        super(sourceDialog);\n        errorID = dialogErrorID;\n\n    }\n\n    /**\n     * Returns the ID of the error.\n     *\n     * @return Error ID.\n     */\n    public int getErrorID() {\n        return errorID;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPDialogEventListener.java",
    "content": "/*\n * This source code has been contributed to the public domain by Mobicents\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement.\n */\npackage gov2.nist.javax2.sip.stack;\n\nimport java.util.EventListener;\n\n/**\n * Interface implemented by classes that want to be notified of asynchronous\n * dialog events.\n *\n * @author jean deruelle\n * @since 2.0 \n */\npublic interface SIPDialogEventListener extends EventListener {\n\n    /**\n     * Invoked when an error has ocurred with a dialog.\n     *\n     * @param dialogErrorEvent Error event.\n     */\n    public void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPServerTransaction.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.ServerTransactionExt;\nimport gov2.nist.javax2.sip.SipProviderImpl;\nimport gov2.nist.javax2.sip.Utils;\nimport gov2.nist.javax2.sip.header.Expires;\nimport gov2.nist.javax2.sip.header.ParameterNames;\nimport gov2.nist.javax2.sip.header.RSeq;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.util.TimerTask;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\n\nimport javax2.sip.Dialog;\nimport javax2.sip.DialogState;\nimport javax2.sip.DialogTerminatedEvent;\nimport javax2.sip.ObjectInUseException;\nimport javax2.sip.SipException;\nimport javax2.sip.Timeout;\nimport javax2.sip.TimeoutEvent;\nimport javax2.sip.TransactionState;\nimport javax2.sip.address.Hop;\nimport javax2.sip.header.ContactHeader;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.RSeqHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/*\n * Bug fixes / enhancements:Emil Ivov, Antonis Karydas, Daniel J. Martinez Manzano, Daniel, Hagai\n * Sela, Vazques-Illa, Bill Roome, Thomas Froment and Pierre De Rop, Christophe Anzille and Jeroen\n * van Bemmel, Frank Reif.\n * Carolyn Beeton ( Avaya ).\n *\n */\n\n/**\n * Represents a server transaction. Implements the following state machines.\n *\n * <pre>\n *\n *\n *\n *                                                                      |INVITE\n *                                                                      |pass INV to TU\n *                                                   INVITE             V send 100 if TU won't in 200ms\n *                                                   send response+-----------+\n *                                                       +--------|           |--------+101-199 from TU\n *                                                       |        | Proceeding|        |send response\n *                                                       +-------&gt;|           |&lt;-------+\n *                                                                |           |          Transport Err.\n *                                                                |           |          Inform TU\n *                                                                |           |---------------&gt;+\n *                                                                +-----------+                |\n *                                                   300-699 from TU |     |2xx from TU        |\n *                                                   send response   |     |send response      |\n *                                                                   |     +------------------&gt;+\n *                                                                   |                         |\n *                                                   INVITE          V          Timer G fires  |\n *                                                   send response+-----------+ send response  |\n *                                                       +--------|           |--------+       |\n *                                                       |        | Completed |        |       |\n *                                                       +-------&gt;|           |&lt;-------+       |\n *                                                                +-----------+                |\n *                                                                   |     |                   |\n *                                                               ACK |     |                   |\n *                                                               -   |     +------------------&gt;+\n *                                                                   |        Timer H fires    |\n *                                                                   V        or Transport Err.|\n *                                                                +-----------+  Inform TU     |\n *                                                                |           |                |\n *                                                                | Confirmed |                |\n *                                                                |           |                |\n *                                                                +-----------+                |\n *                                                                      |                      |\n *                                                                      |Timer I fires         |\n *                                                                      |-                     |\n *                                                                      |                      |\n *                                                                      V                      |\n *                                                                +-----------+                |\n *                                                                |           |                |\n *                                                                | Terminated|&lt;---------------+\n *                                                                |           |\n *                                                                +-----------+\n *\n *                                                     Figure 7: INVITE server transaction\n *                                                         Request received\n *                                                                         |pass to TU\n *\n *                                                                         V\n *                                                                   +-----------+\n *                                                                   |           |\n *                                                                   | Trying    |-------------+\n *                                                                   |           |             |\n *                                                                   +-----------+             |200-699 from TU\n *                                                                         |                   |send response\n *                                                                         |1xx from TU        |\n *                                                                         |send response      |\n *                                                                         |                   |\n *                                                      Request            V      1xx from TU  |\n *                                                      send response+-----------+send response|\n *                                                          +--------|           |--------+    |\n *                                                          |        | Proceeding|        |    |\n *                                                          +-------&gt;|           |&lt;-------+    |\n *                                                   +&lt;--------------|           |             |\n *                                                   |Trnsprt Err    +-----------+             |\n *                                                   |Inform TU            |                   |\n *                                                   |                     |                   |\n *                                                   |                     |200-699 from TU    |\n *                                                   |                     |send response      |\n *                                                   |  Request            V                   |\n *                                                   |  send response+-----------+             |\n *                                                   |      +--------|           |             |\n *                                                   |      |        | Completed |&lt;------------+\n *                                                   |      +-------&gt;|           |\n *                                                   +&lt;--------------|           |\n *                                                   |Trnsprt Err    +-----------+\n *                                                   |Inform TU            |\n *                                                   |                     |Timer J fires\n *                                                   |                     |-\n *                                                   |                     |\n *                                                   |                     V\n *                                                   |               +-----------+\n *                                                   |               |           |\n *                                                   +--------------&gt;| Terminated|\n *                                                                   |           |\n *                                                                   +-----------+\n *\n *\n *\n *\n *\n * </pre>\n *\n * @version 1.2 $Revision: 1.118 $ $Date: 2010/01/10 00:13:14 $\n * @author M. Ranganathan\n *\n */\npublic class SIPServerTransaction extends SIPTransaction implements ServerRequestInterface,\n        javax2.sip.ServerTransaction, ServerTransactionExt {\n\n    // force the listener to see transaction\n\n    private int rseqNumber;\n\n    // private LinkedList pendingRequests;\n\n    // Real RequestInterface to pass messages to\n    private transient ServerRequestInterface requestOf;\n\n    private SIPDialog dialog;\n\n    // the unacknowledged SIPResponse\n\n    private SIPResponse pendingReliableResponse;\n\n    // The pending reliable Response Timer\n    private ProvisionalResponseTask provisionalResponseTask;\n\n    private boolean retransmissionAlertEnabled;\n\n    private RetransmissionAlertTimerTask retransmissionAlertTimerTask;\n\n    protected boolean isAckSeen;\n\n    private SIPClientTransaction pendingSubscribeTransaction;\n\n    private SIPServerTransaction inviteTransaction;\n    \n    private Semaphore provisionalResponseSem = new Semaphore(1);\n\n    /**\n     * This timer task is used for alerting the application to send retransmission alerts.\n     *\n     *\n     */\n    class RetransmissionAlertTimerTask extends SIPStackTimerTask {\n\n        String dialogId;\n\n        int ticks;\n\n        int ticksLeft;\n\n        public RetransmissionAlertTimerTask(String dialogId) {\n\n            this.ticks = SIPTransaction.T1;\n            this.ticksLeft = this.ticks;\n\n            // Fix from http://java.net/jira/browse/JSIP-443\n            // by mitchell.c.ackerman\n            this.dialogId = dialogId;\n\n            setTaskOutdatedTime(ticks);\n        }\n\n        protected void runTask() {\n            SIPServerTransaction serverTransaction = SIPServerTransaction.this;\n            ticksLeft--;\n            if (ticksLeft == -1 || isTaskOutdated()) {\n                serverTransaction.fireRetransmissionTimer();\n                this.ticksLeft = 2 * ticks;\n            }\n\n        }\n\n    }\n\n    class ProvisionalResponseTask extends SIPStackTimerTask {\n\n        int ticks;\n\n        int ticksLeft;\n\n        public ProvisionalResponseTask() {\n            this.ticks = SIPTransaction.T1;\n            this.ticksLeft = this.ticks;\n\n            setTaskOutdatedTime(ticks);\n        }\n\n        protected void runTask() {\n            SIPServerTransaction serverTransaction = SIPServerTransaction.this;\n            /*\n             * The reliable provisional response is passed to the transaction layer periodically\n             * with an interval that starts at T1 seconds and doubles for each retransmission (T1\n             * is defined in Section 17 of RFC 3261). Once passed to the server transaction, it is\n             * added to an internal list of unacknowledged reliable provisional responses. The\n             * transaction layer will forward each retransmission passed from the UAS core.\n             *\n             * This differs from retransmissions of 2xx responses, whose intervals cap at T2\n             * seconds. This is because retransmissions of ACK are triggered on receipt of a 2xx,\n             * but retransmissions of PRACK take place independently of reception of 1xx.\n             */\n            // If the transaction has terminated,\n            if (serverTransaction.isTerminated()) {\n\n                this.cancel();\n\n            } else {\n                ticksLeft--;\n                if (ticksLeft == -1 || isTaskOutdated()) {\n                    serverTransaction.fireReliableResponseRetransmissionTimer();\n                    this.ticksLeft = 2 * ticks;\n                    this.ticks = this.ticksLeft;\n                    // timer H MUST be set to fire in 64*T1 seconds for all transports. Timer H\n                    // determines when the server\n                    // transaction abandons retransmitting the response\n                    if (this.ticksLeft >= SIPTransaction.TIMER_H) {\n                        this.cancel();\n                        setState(TERMINATED_STATE);\n                        fireTimeoutTimer();\n                    }\n                }\n\n            }\n\n        }\n\n    }\n\n    /**\n     * This timer task will terminate the transaction if the listener does not respond in a\n     * pre-determined time period. This helps prevent buggy listeners (who fail to respond) from\n     * causing memory leaks. This allows a container to protect itself from buggy code ( that\n     * fails to respond to a server transaction).\n     *\n     */\n    class ListenerExecutionMaxTimer extends SIPStackTimerTask {\n        SIPServerTransaction serverTransaction = SIPServerTransaction.this;\n\n        ListenerExecutionMaxTimer() {\n        }\n\n        protected void runTask() {\n            try {\n                if (serverTransaction.getState() == null) {\n                    serverTransaction.terminate();\n                    SIPTransactionStack sipStack = serverTransaction.getSIPStack();\n                    sipStack.removePendingTransaction(serverTransaction);\n                    sipStack.removeTransaction(serverTransaction);\n\n                }\n            } catch (Exception ex) {\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logError(\"unexpected exception\", ex);\n            }\n        }\n    }\n\n    /**\n     * This timer task is for INVITE server transactions. It will send a trying in 200 ms. if the\n     * TU does not do so.\n     *\n     */\n    class SendTrying extends SIPStackTimerTask {\n\n        protected SendTrying() {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"scheduled timer for \" + SIPServerTransaction.this);\n\n        }\n\n        protected void runTask() {\n            SIPServerTransaction serverTransaction = SIPServerTransaction.this;\n\n            TransactionState realState = serverTransaction.getRealState();\n\n            if (realState == null || TransactionState.TRYING == realState) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\" sending Trying current state = \"\n                            + serverTransaction.getRealState());\n                try {\n                    serverTransaction.sendMessage(serverTransaction.getOriginalRequest()\n                            .createResponse(100, \"Trying\"));\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\" trying sent \"\n                                + serverTransaction.getRealState());\n                } catch (IOException ex) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logError(\"IO error sending  TRYING\");\n                }\n            }\n\n        }\n    }\n\n    class TransactionTimer extends SIPStackTimerTask {\n\n        public TransactionTimer() {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"TransactionTimer() : \" + getTransactionId());\n            }\n\n        }\n\n        protected void runTask() {\n            // If the transaction has terminated,\n            if (isTerminated()) {\n                // Keep the transaction hanging around in the transaction table\n                // to catch the incoming ACK -- this is needed for tcp only.\n                // Note that the transaction record is actually removed in\n                // the connection linger timer.\n                try {\n                    this.cancel();\n                } catch (IllegalStateException ex) {\n                    if (!sipStack.isAlive())\n                        return;\n                }\n\n                // Oneshot timer that garbage collects the SeverTransaction\n                // after a scheduled amount of time. The linger timer allows\n                // the client side of the tx to use the same connection to\n                // send an ACK and prevents a race condition for creation\n                // of new server tx\n                TimerTask myTimer = new LingerTimer();\n\n                sipStack.getTimer().schedule(myTimer,\n                        SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);\n\n            } else {\n                // Add to the fire list -- needs to be moved\n                // outside the synchronized block to prevent\n                // deadlock.\n                fireTimer();\n\n            }\n        }\n\n    }\n\n    /**\n     * Send a response.\n     *\n     * @param transactionResponse -- the response to send\n     *\n     */\n\n    private void sendResponse(SIPResponse transactionResponse) throws IOException {\n\n        try {\n            // RFC18.2.2. Sending Responses\n            // The server transport uses the value of the top Via header field\n            // in\n            // order\n            // to determine where to send a response.\n            // It MUST follow the following process:\n            // If the \"sent-protocol\" is a reliable transport\n            // protocol such as TCP or SCTP,\n            // or TLS over those, the response MUST be\n            // sent using the existing connection\n            // to the source of the original request\n            // that created the transaction, if that connection is still open.\n            if (isReliable()) {\n\n                getMessageChannel().sendMessage(transactionResponse);\n\n                // TODO If that connection attempt fails, the server SHOULD\n                // use SRV 3263 procedures\n                // for servers in order to determine the IP address\n                // and port to open the connection and send the response to.\n\n            } else {\n                Via via = transactionResponse.getTopmostVia();\n                String transport = via.getTransport();\n                if (transport == null)\n                    throw new IOException(\"missing transport!\");\n                // @@@ hagai Symmetric NAT support\n                int port = via.getRPort();\n                if (port == -1)\n                    port = via.getPort();\n                if (port == -1) {\n                    if (transport.equalsIgnoreCase(\"TLS\"))\n                        port = 5061;\n                    else\n                        port = 5060;\n                }\n\n                // Otherwise, if the Via header field value contains a\n                // \"maddr\" parameter, the response MUST be forwarded to\n                // the address listed there, using the port indicated in\n                // \"sent-by\",\n                // or port 5060 if none is present. If the address is a\n                // multicast\n                // address, the response SHOULD be sent using\n                // the TTL indicated in the \"ttl\" parameter, or with a\n                // TTL of 1 if that parameter is not present.\n                String host = null;\n                if (via.getMAddr() != null) {\n                    host = via.getMAddr();\n                } else {\n                    // Otherwise (for unreliable unicast transports),\n                    // if the top Via has a \"received\" parameter, the response\n                    // MUST\n                    // be sent to the\n                    // address in the \"received\" parameter, using the port\n                    // indicated\n                    // in the\n                    // \"sent-by\" value, or using port 5060 if none is specified\n                    // explicitly.\n                    host = via.getParameter(Via.RECEIVED);\n                    if (host == null) {\n                        // Otherwise, if it is not receiver-tagged, the response\n                        // MUST be\n                        // sent to the address indicated by the \"sent-by\" value,\n                        // using the procedures in Section 5\n                        // RFC 3263 PROCEDURE TO BE DONE HERE\n                        host = via.getHost();\n                    }\n                }\n\n                Hop hop = sipStack.addressResolver.resolveAddress(new HopImpl(host, port,\n                        transport));\n\n                MessageChannel messageChannel = ((SIPTransactionStack) getSIPStack())\n                        .createRawMessageChannel(this.getSipProvider().getListeningPoint(\n                                hop.getTransport()).getIPAddress(), this.getPort(), hop);\n                if (messageChannel != null)\n                    messageChannel.sendMessage(transactionResponse);\n                else\n                    throw new IOException(\"Could not create a message channel for \" + hop);\n\n            }\n        } finally {\n            this.startTransactionTimer();\n        }\n    }\n\n    /**\n     * Creates a new server transaction.\n     *\n     * @param sipStack Transaction stack this transaction belongs to.\n     * @param newChannelToUse Channel to encapsulate.\n     */\n    protected SIPServerTransaction(SIPTransactionStack sipStack, MessageChannel newChannelToUse) {\n\n        super(sipStack, newChannelToUse);\n\n        if (sipStack.maxListenerResponseTime != -1) {\n            sipStack.getTimer().schedule(new ListenerExecutionMaxTimer(),\n                    sipStack.maxListenerResponseTime * 1000);\n        }\n\n        this.rseqNumber = (int) (Math.random() * 1000);\n        // Only one outstanding request for a given server tx.\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"Creating Server Transaction\" + this.getBranchId());\n            sipStack.getStackLogger().logStackTrace();\n        }\n\n    }\n\n    /**\n     * Sets the real RequestInterface this transaction encapsulates.\n     *\n     * @param newRequestOf RequestInterface to send messages to.\n     */\n    public void setRequestInterface(ServerRequestInterface newRequestOf) {\n\n        requestOf = newRequestOf;\n\n    }\n\n    /**\n     * Returns this transaction.\n     */\n    public MessageChannel getResponseChannel() {\n\n        return this;\n\n    }\n\n    \n    \n    /**\n     * Determines if the message is a part of this transaction.\n     *\n     * @param messageToTest Message to check if it is part of this transaction.\n     *\n     * @return True if the message is part of this transaction, false if not.\n     */\n    public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {\n\n        // List of Via headers in the message to test\n        ViaList viaHeaders;\n        // Topmost Via header in the list\n        Via topViaHeader;\n        // Branch code in the topmost Via header\n        String messageBranch;\n        // Flags whether the select message is part of this transaction\n        boolean transactionMatches;\n\n        transactionMatches = false;\n\n        String method = messageToTest.getCSeq().getMethod();\n        // Invite Server transactions linger in the terminated state in the\n        // transaction\n        // table and are matched to compensate for\n        // http://bugs.sipit.net/show_bug.cgi?id=769\n        if ((method.equals(Request.INVITE) || !isTerminated())) {\n\n            // Get the topmost Via header and its branch parameter\n            viaHeaders = messageToTest.getViaHeaders();\n            if (viaHeaders != null) {\n\n                topViaHeader = (Via) viaHeaders.getFirst();\n                messageBranch = topViaHeader.getBranch();\n                if (messageBranch != null) {\n\n                    // If the branch parameter exists but\n                    // does not start with the magic cookie,\n                    if (!messageBranch.toLowerCase().startsWith(\n                            SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {\n\n                        // Flags this as old\n                        // (RFC2543-compatible) client\n                        // version\n                        messageBranch = null;\n\n                    }\n\n                }\n\n                // If a new branch parameter exists,\n                if (messageBranch != null && this.getBranch() != null) {\n                    if (method.equals(Request.CANCEL)) {\n                        // Cancel is handled as a special case because it\n                        // shares the same same branch id of the invite\n                        // that it is trying to cancel.\n                        transactionMatches = this.getMethod().equals(Request.CANCEL)\n                                && getBranch().equalsIgnoreCase(messageBranch)\n                                && topViaHeader.getSentBy().equals(\n                                        ((Via) getOriginalRequest().getViaHeaders().getFirst())\n                                                .getSentBy());\n\n                    } else {\n                        // Matching server side transaction with only the\n                        // branch parameter.\n                        transactionMatches = getBranch().equalsIgnoreCase(messageBranch)\n                                && topViaHeader.getSentBy().equals(\n                                        ((Via) getOriginalRequest().getViaHeaders().getFirst())\n                                                .getSentBy());\n\n                    }\n\n                } else {\n                    // This is an RFC2543-compliant message; this code is here\n                    // for backwards compatibility.\n                    // It is a weak check.\n                    // If RequestURI, To tag, From tag, CallID, CSeq number, and\n                    // top Via headers are the same, the\n                    // SIPMessage matches this transaction. An exception is for\n                    // a CANCEL request, which is not deemed\n                    // to be part of an otherwise-matching INVITE transaction.\n                    String originalFromTag = super.fromTag;\n\n                    String thisFromTag = messageToTest.getFrom().getTag();\n\n                    boolean skipFrom = (originalFromTag == null || thisFromTag == null);\n\n                    String originalToTag = super.toTag;\n\n                    String thisToTag = messageToTest.getTo().getTag();\n\n                    boolean skipTo = (originalToTag == null || thisToTag == null);\n                    boolean isResponse = (messageToTest instanceof SIPResponse);\n                    // Issue #96: special case handling for a CANCEL request -\n                    // the CSeq method of the original request must\n                    // be CANCEL for it to have a chance at matching.\n                    if (messageToTest.getCSeq().getMethod().equalsIgnoreCase(Request.CANCEL)\n                            && !getOriginalRequest().getCSeq().getMethod().equalsIgnoreCase(\n                                    Request.CANCEL)) {\n                        transactionMatches = false;\n                    } else if ((isResponse || getOriginalRequest().getRequestURI().equals(\n                            ((SIPRequest) messageToTest).getRequestURI()))\n                            && (skipFrom || originalFromTag != null && originalFromTag.equalsIgnoreCase(thisFromTag))\n                            && (skipTo || originalToTag != null && originalToTag.equalsIgnoreCase(thisToTag))\n                            && getOriginalRequest().getCallId().getCallId().equalsIgnoreCase(\n                                    messageToTest.getCallId().getCallId())\n                            && getOriginalRequest().getCSeq().getSeqNumber() == messageToTest\n                                    .getCSeq().getSeqNumber()\n                            && ((!messageToTest.getCSeq().getMethod().equals(Request.CANCEL)) || getOriginalRequest()\n                                    .getMethod().equals(messageToTest.getCSeq().getMethod()))\n                            && topViaHeader.equals(getOriginalRequest().getViaHeaders()\n                                    .getFirst())) {\n\n                        transactionMatches = true;\n                    }\n\n                }\n\n            }\n\n        }\n        return transactionMatches;\n\n    }\n\n    /**\n     * Send out a trying response (only happens when the transaction is mapped). Otherwise the\n     * transaction is not known to the stack.\n     */\n    protected void map() {\n        // note that TRYING is a pseudo-state for invite transactions\n\n        TransactionState realState = getRealState();\n\n        if (realState == null || realState == TransactionState.TRYING) {\n            // JvB: Removed the condition 'dialog!=null'. Trying should also\n            // be\n            // sent by intermediate proxies. This fixes some TCK tests\n            // null check added as the stack may be stopped.\n            if (isInviteTransaction() && !this.isMapped && sipStack.getTimer() != null) {\n                this.isMapped = true;\n                // Schedule a timer to fire in 200 ms if the\n                // TU did not send a trying in that time.\n                sipStack.getTimer().schedule(new SendTrying(), 200);\n\n            } else {\n                isMapped = true;\n            }\n        }\n\n        // Pull it out of the pending transactions list.\n        sipStack.removePendingTransaction(this);\n    }\n\n    /**\n     * Return true if the transaction is known to stack.\n     */\n    public boolean isTransactionMapped() {\n        return this.isMapped;\n    }\n\n    /**\n     * Process a new request message through this transaction. If necessary, this message will\n     * also be passed onto the TU.\n     *\n     * @param transactionRequest Request to process.\n     * @param sourceChannel Channel that received this message.\n     */\n    public void processRequest(SIPRequest transactionRequest, MessageChannel sourceChannel) {\n        boolean toTu = false;\n\n        // Can only process a single request directed to the\n        // transaction at a time. For a given server transaction\n        // the listener sees only one event at a time.\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"processRequest: \" + transactionRequest.getFirstLine());\n            sipStack.getStackLogger().logDebug(\"tx state = \" + this.getRealState());\n        }\n\n        try {\n\n            // If this is the first request for this transaction,\n            if (getRealState() == null) {\n                // Save this request as the one this\n                // transaction is handling\n                setOriginalRequest(transactionRequest);\n                this.setState(TransactionState.TRYING);\n                toTu = true;\n                this.setPassToListener();\n\n                // Rsends the TRYING on retransmission of the request.\n                if (isInviteTransaction() && this.isMapped) {\n                    // JvB: also\n                    // proxies need\n                    // to do this\n\n                    // Has side-effect of setting\n                    // state to \"Proceeding\"\n                    sendMessage(transactionRequest.createResponse(100, \"Trying\"));\n\n                }\n                // If an invite transaction is ACK'ed while in\n                // the completed state,\n            } else if (isInviteTransaction() && TransactionState.COMPLETED == getRealState()\n                    && transactionRequest.getMethod().equals(Request.ACK)) {\n\n                // @jvB bug fix\n                this.setState(TransactionState.CONFIRMED);\n                disableRetransmissionTimer();\n                if (!isReliable()) {\n                    enableTimeoutTimer(TIMER_I);\n\n                } else {\n\n                    this.setState(TransactionState.TERMINATED);\n\n                }\n\n                // JvB: For the purpose of testing a TI, added a property to\n                // pass it anyway\n                if (sipStack.isNon2XXAckPassedToListener()) {\n                    // This is useful for test applications that want to see\n                    // all messages.\n                    requestOf.processRequest(transactionRequest, this);\n                } else {\n                    // According to RFC3261 Application should not Ack in\n                    // CONFIRMED state\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\"ACK received for server Tx \"\n                                + this.getTransactionId() + \" not delivering to application!\");\n\n                    }\n\n                    this.semRelease();\n                }\n                return;\n\n                // If we receive a retransmission of the original\n                // request,\n            } else if (transactionRequest.getMethod().equals(getOriginalRequest().getMethod())) {\n\n                if (TransactionState.PROCEEDING == getRealState()\n                        || TransactionState.COMPLETED == getRealState()) {\n                    this.semRelease();\n                    // Resend the last response to\n                    // the client\n                    if (lastResponse != null) {\n\n                        // Send the message to the client\n                        super.sendMessage(lastResponse);\n\n                    }\n                } else if (transactionRequest.getMethod().equals(Request.ACK)) {\n                    // This is passed up to the TU to suppress\n                    // retransmission of OK\n                    if (requestOf != null)\n                        requestOf.processRequest(transactionRequest, this);\n                    else\n                        this.semRelease();\n                }\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logDebug(\"completed processing retransmitted request : \"\n                        + transactionRequest.getFirstLine() + this + \" txState = \"\n                        + this.getState() + \" lastResponse = \" + this.getLastResponse());\n                return;\n\n            }\n\n            // Pass message to the TU\n            if (TransactionState.COMPLETED != getRealState()\n                    && TransactionState.TERMINATED != getRealState() && requestOf != null) {\n                if (getOriginalRequest().getMethod().equals(transactionRequest.getMethod())) {\n                    // Only send original request to TU once!\n                    if (toTu) {\n                        requestOf.processRequest(transactionRequest, this);\n                    } else\n                        this.semRelease();\n                } else {\n                    if (requestOf != null)\n                        requestOf.processRequest(transactionRequest, this);\n                    else\n                        this.semRelease();\n                }\n            } else {\n                // This seems like a common bug so I am allowing it through!\n                if (((SIPTransactionStack) getSIPStack()).isDialogCreated(getOriginalRequest()\n                        .getMethod())\n                        && getRealState() == TransactionState.TERMINATED\n                        && transactionRequest.getMethod().equals(Request.ACK)\n                        && requestOf != null) {\n                    SIPDialog thisDialog = (SIPDialog) this.dialog;\n\n                    if (thisDialog == null || !thisDialog.ackProcessed) {\n                        // Filter out duplicate acks\n                        if (thisDialog != null) {\n                            thisDialog.ackReceived(transactionRequest);\n                            thisDialog.ackProcessed = true;\n                        }\n                        requestOf.processRequest(transactionRequest, this);\n                    } else {\n                        this.semRelease();\n                    }\n\n                } else if (transactionRequest.getMethod().equals(Request.CANCEL)) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\"Too late to cancel Transaction\");\n                    this.semRelease();\n                    // send OK and just ignore the CANCEL.\n                    try {\n                        this.sendMessage(transactionRequest.createResponse(Response.OK));\n                    } catch (IOException ex) {\n                        // Transaction is already terminated\n                        // just ignore the IOException.\n                    }\n                }\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logDebug(\"Dropping request \" + getRealState());\n            }\n\n        } catch (IOException e) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logError(\"IOException \" ,e);\n            this.semRelease();\n            this.raiseIOExceptionEvent();\n        }\n\n    }\n\n    /**\n     * Send a response message through this transactionand onto the client. The response drives\n     * the state machine.\n     *\n     * @param messageToSend Response to process and send.\n     */\n    public void sendMessage(SIPMessage messageToSend) throws IOException {\n        try {\n            // Message typecast as a response\n            SIPResponse transactionResponse;\n            // Status code of the response being sent to the client\n            int statusCode;\n\n            // Get the status code from the response\n            transactionResponse = (SIPResponse) messageToSend;\n            statusCode = transactionResponse.getStatusCode();\n\n            try {\n                // Provided we have set the banch id for this we set the BID for\n                // the\n                // outgoing via.\n                if (this.getOriginalRequest().getTopmostVia().getBranch() != null)\n                    transactionResponse.getTopmostVia().setBranch(this.getBranch());\n                else\n                    transactionResponse.getTopmostVia().removeParameter(ParameterNames.BRANCH);\n\n                // Make the topmost via headers match identically for the\n                // transaction rsponse.\n                if (!this.getOriginalRequest().getTopmostVia().hasPort())\n                    transactionResponse.getTopmostVia().removePort();\n            } catch (ParseException ex) {\n                ex.printStackTrace();\n            }\n\n            // Method of the response does not match the request used to\n            // create the transaction - transaction state does not change.\n            if (!transactionResponse.getCSeq().getMethod().equals(\n                    getOriginalRequest().getMethod())) {\n                sendResponse(transactionResponse);\n                return;\n            }\n\n            // If the TU sends a provisional response while in the\n            // trying state,\n\n            if (getRealState() == TransactionState.TRYING) {\n                if (statusCode / 100 == 1) {\n                    this.setState(TransactionState.PROCEEDING);\n                } else if (200 <= statusCode && statusCode <= 699) {\n                    // INVITE ST has TRYING as a Pseudo state\n                    // (See issue 76). We are using the TRYING\n                    // pseudo state invite Transactions\n                    // to signal if the application\n                    // has sent trying or not and hence this\n                    // check is necessary.\n                    if (!isInviteTransaction()) {\n                        if (!isReliable()) {\n                            // Linger in the completed state to catch\n                            // retransmissions if the transport is not\n                            // reliable.\n                            this.setState(TransactionState.COMPLETED);\n                            // Note that Timer J is only set for Unreliable\n                            // transports -- see Issue 75.\n                            /*\n                             * From RFC 3261 Section 17.2.2 (non-invite server transaction)\n                             *\n                             * When the server transaction enters the \"Completed\" state, it MUST\n                             * set Timer J to fire in 64*T1 seconds for unreliable transports, and\n                             * zero seconds for reliable transports. While in the \"Completed\"\n                             * state, the server transaction MUST pass the final response to the\n                             * transport layer for retransmission whenever a retransmission of the\n                             * request is received. Any other final responses passed by the TU to\n                             * the server transaction MUST be discarded while in the \"Completed\"\n                             * state. The server transaction remains in this state until Timer J\n                             * fires, at which point it MUST transition to the \"Terminated\" state.\n                             */\n                            enableTimeoutTimer(TIMER_J);\n                        } else {\n                            this.setState(TransactionState.TERMINATED);\n                        }\n                    } else {\n                        // This is the case for INVITE server transactions.\n                        // essentially, it duplicates the code in the\n                        // PROCEEDING case below. There is no TRYING state for INVITE\n                        // transactions in the RFC. We are using it to signal whether the\n                        // application has sent a provisional response or not. Hence\n                        // this is treated the same as as Proceeding.\n                        if (statusCode / 100 == 2) {\n                            // Status code is 2xx means that the\n                            // transaction transitions to TERMINATED\n                            // for both Reliable as well as unreliable\n                            // transports. Note that the dialog layer\n                            // takes care of retransmitting 2xx final\n                            // responses.\n                            /*\n                             * RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server\n                             * transaction will be destroyed as soon as it receives this final\n                             * response and passes it to the transport. Therefore, it is necessary\n                             * to periodically pass the response directly to the transport until\n                             * the ACK arrives. The 2xx response is passed to the transport with\n                             * an interval that starts at T1 seconds and doubles for each\n                             * retransmission until it reaches T2 seconds (T1 and T2 are defined\n                             * in Section 17). Response retransmissions cease when an ACK request\n                             * for the response is received. This is independent of whatever\n                             * transport protocols are used to send the response.\n                             */\n                            this.disableRetransmissionTimer();\n                            this.disableTimeoutTimer();\n                            this.collectionTime = TIMER_J;\n                            this.setState(TransactionState.TERMINATED);\n                            if (this.dialog != null)\n                                this.dialog.setRetransmissionTicks();\n                        } else {\n                            // This an error final response.\n                            this.setState(TransactionState.COMPLETED);\n                            if (!isReliable()) {\n                                /*\n                                 * RFC 3261\n                                 *\n                                 * While in the \"Proceeding\" state, if the TU passes a response\n                                 * with status code from 300 to 699 to the server transaction, the\n                                 * response MUST be passed to the transport layer for\n                                 * transmission, and the state machine MUST enter the \"Completed\"\n                                 * state. For unreliable transports, timer G is set to fire in T1\n                                 * seconds, and is not set to fire for reliable transports.\n                                 */\n\n                                enableRetransmissionTimer();\n\n                            }\n                            enableTimeoutTimer(TIMER_H);\n                        }\n                    }\n\n                }\n\n                // If the transaction is in the proceeding state,\n            } else if (getRealState() == TransactionState.PROCEEDING) {\n\n                if (isInviteTransaction()) {\n\n                    // If the response is a failure message,\n                    if (statusCode / 100 == 2) {\n                        // Set up to catch returning ACKs\n                        // The transaction lingers in the\n                        // terminated state for some time\n                        // to catch retransmitted INVITEs\n                        this.disableRetransmissionTimer();\n                        this.disableTimeoutTimer();\n                        this.collectionTime = TIMER_J;\n                        this.setState(TransactionState.TERMINATED);\n                        if (this.dialog != null)\n                            this.dialog.setRetransmissionTicks();\n\n                    } else if (300 <= statusCode && statusCode <= 699) {\n\n                        // Set up to catch returning ACKs\n                        this.setState(TransactionState.COMPLETED);\n                        if (!isReliable()) {\n                            /*\n                             * While in the \"Proceeding\" state, if the TU passes a response with\n                             * status code from 300 to 699 to the server transaction, the response\n                             * MUST be passed to the transport layer for transmission, and the\n                             * state machine MUST enter the \"Completed\" state. For unreliable\n                             * transports, timer G is set to fire in T1 seconds, and is not set to\n                             * fire for reliable transports.\n                             */\n\n                            enableRetransmissionTimer();\n\n                        }\n                        enableTimeoutTimer(TIMER_H);\n\n                    }\n\n                    // If the transaction is not an invite transaction\n                    // and this is a final response,\n                } else if (200 <= statusCode && statusCode <= 699) {\n                    // This is for Non-invite server transactions.\n\n                    // Set up to retransmit this response,\n                    // or terminate the transaction\n                    this.setState(TransactionState.COMPLETED);\n                    if (!isReliable()) {\n\n                        disableRetransmissionTimer();\n                        enableTimeoutTimer(TIMER_J);\n\n                    } else {\n\n                        this.setState(TransactionState.TERMINATED);\n\n                    }\n\n                }\n\n                // If the transaction has already completed,\n            } else if (TransactionState.COMPLETED == this.getRealState()) {\n\n                return;\n            }\n\n            try {\n                // Send the message to the client.\n                // Record the last message sent out.\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\n                            \"sendMessage : tx = \" + this + \" getState = \" + this.getState());\n                }\n                lastResponse = transactionResponse;\n                this.sendResponse(transactionResponse);\n\n            } catch (IOException e) {\n\n                this.setState(TransactionState.TERMINATED);\n                this.collectionTime = 0;\n                throw e;\n\n            }\n        } finally {\n            this.startTransactionTimer();\n        }\n\n    }\n\n    public String getViaHost() {\n\n        return getMessageChannel().getViaHost();\n\n    }\n\n    public int getViaPort() {\n\n        return getMessageChannel().getViaPort();\n\n    }\n\n    /**\n     * Called by the transaction stack when a retransmission timer fires. This retransmits the\n     * last response when the retransmission filter is enabled.\n     */\n    protected void fireRetransmissionTimer() {\n\n        try {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"fireRetransmissionTimer() -- \");\n            }\n            // Resend the last response sent by this transaction\n            if (isInviteTransaction() && lastResponse != null) {\n                // null can happen if this is terminating when the timer fires.\n                if (!this.retransmissionAlertEnabled || sipStack.isTransactionPendingAck(this) ) {\n                    // Retransmit last response until ack.\n                    if (lastResponse.getStatusCode() / 100 > 2 && !this.isAckSeen)\n                        super.sendMessage(lastResponse);\n                } else {\n                    // alert the application to retransmit the last response\n                    SipProviderImpl sipProvider = (SipProviderImpl) this.getSipProvider();\n                    TimeoutEvent txTimeout = new TimeoutEvent(sipProvider, this,\n                            Timeout.RETRANSMIT);\n                    sipProvider.handleEvent(txTimeout, this);\n                }\n\n            }\n        } catch (IOException e) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(e);\n            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);\n\n        }\n\n    }\n\n    private void fireReliableResponseRetransmissionTimer() {\n        try {\n\n            super.sendMessage(this.pendingReliableResponse);\n\n        } catch (IOException e) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(e);\n            this.setState(TransactionState.TERMINATED);\n            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);\n\n        }\n    }\n\n    /**\n     * Called by the transaction stack when a timeout timer fires.\n     */\n    protected void fireTimeoutTimer() {\n\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"SIPServerTransaction.fireTimeoutTimer this = \" + this\n                    + \" current state = \" + this.getRealState() + \" method = \"\n                    + this.getOriginalRequest().getMethod());\n\n        if ( this.getMethod().equals(Request.INVITE) && sipStack.removeTransactionPendingAck(this) ) {\n            if ( sipStack.isLoggingEnabled() ) {\n                sipStack.getStackLogger().logDebug(\"Found tx pending ACK - returning\");\n            }\n            return;\n            \n        }\n        SIPDialog dialog = (SIPDialog) this.dialog;\n        if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this.getOriginalRequest()\n                .getMethod())\n                && (TransactionState.CALLING == this.getRealState() || TransactionState.TRYING == this\n                        .getRealState())) {\n            dialog.setState(SIPDialog.TERMINATED_STATE);\n        } else if (getOriginalRequest().getMethod().equals(Request.BYE)) {\n            if (dialog != null && dialog.isTerminatedOnBye())\n                dialog.setState(SIPDialog.TERMINATED_STATE);\n        }\n\n        if (TransactionState.COMPLETED == this.getRealState() && isInviteTransaction()) {\n            raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);\n            this.setState(TransactionState.TERMINATED);\n            sipStack.removeTransaction(this);\n\n        } else if (TransactionState.COMPLETED == this.getRealState() && !isInviteTransaction()) {\n            this.setState(TransactionState.TERMINATED);\n            sipStack.removeTransaction(this);\n\n        } else if (TransactionState.CONFIRMED == this.getRealState() && isInviteTransaction()) {\n            // TIMER_I should not generate a timeout\n            // exception to the application when the\n            // Invite transaction is in Confirmed state.\n            // Just transition to Terminated state.\n            this.setState(TransactionState.TERMINATED);\n            sipStack.removeTransaction(this);\n        } else if (!isInviteTransaction()\n                && (TransactionState.COMPLETED == this.getRealState() || TransactionState.CONFIRMED == this\n                        .getRealState())) {\n            this.setState(TransactionState.TERMINATED);\n        } else if (isInviteTransaction() && TransactionState.TERMINATED == this.getRealState()) {\n            // This state could be reached when retransmitting\n\n            raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);\n            if (dialog != null)\n                dialog.setState(SIPDialog.TERMINATED_STATE);\n        }\n\n    }\n\n    /**\n     * Get the last response.\n     */\n    public SIPResponse getLastResponse() {\n        return this.lastResponse;\n    }\n\n    /**\n     * Set the original request.\n     */\n    public void setOriginalRequest(SIPRequest originalRequest) {\n        super.setOriginalRequest(originalRequest);\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.ServerTransaction#sendResponse(javax2.sip.message.Response)\n     */\n    public void sendResponse(Response response) throws SipException {\n        SIPResponse sipResponse = (SIPResponse) response;\n\n        SIPDialog dialog = this.dialog;\n        if (response == null)\n            throw new NullPointerException(\"null response\");\n\n        try {\n            sipResponse.checkHeaders();\n        } catch (ParseException ex) {\n            throw new SipException(ex.getMessage());\n        }\n\n        // check for meaningful response.\n        if (!sipResponse.getCSeq().getMethod().equals(this.getMethod())) {\n            throw new SipException(\n                    \"CSeq method does not match Request method of request that created the tx.\");\n        }\n\n        /*\n         * 200-class responses to SUBSCRIBE requests also MUST contain an \"Expires\" header. The\n         * period of time in the response MAY be shorter but MUST NOT be longer than specified in\n         * the request.\n         */\n        if (this.getMethod().equals(Request.SUBSCRIBE) && response.getStatusCode() / 100 == 2) {\n\n            if (response.getHeader(ExpiresHeader.NAME) == null) {\n                throw new SipException(\"Expires header is mandatory in 2xx response of SUBSCRIBE\");\n            } else {\n                Expires requestExpires = (Expires) this.getOriginalRequest().getExpires();\n                Expires responseExpires = (Expires) response.getExpires();\n                /*\n                 * If no \"Expires\" header is present in a SUBSCRIBE request, the implied default\n                 * is defined by the event package being used.\n                 */\n                if (requestExpires != null\n                        && responseExpires.getExpires() > requestExpires.getExpires()) {\n                    throw new SipException(\n                            \"Response Expires time exceeds request Expires time : See RFC 3265 3.1.1\");\n                }\n            }\n\n        }\n\n        // Check for mandatory header.\n        if (sipResponse.getStatusCode() == 200\n                && sipResponse.getCSeq().getMethod().equals(Request.INVITE)\n                && sipResponse.getHeader(ContactHeader.NAME) == null)\n            throw new SipException(\"Contact Header is mandatory for the OK to the INVITE\");\n\n        if (!this.isMessagePartOfTransaction((SIPMessage) response)) {\n            throw new SipException(\"Response does not belong to this transaction.\");\n        }\n\n        // Fix up the response if the dialog has already been established.\n        try {\n            /*\n             * The UAS MAY send a final response to the initial request before\n             * having received PRACKs for all unacknowledged reliable provisional responses,\n             * unless the final response is 2xx and any of the unacknowledged reliable provisional\n             * responses contained a session description. In that case, it MUST NOT send a final\n             * response until those provisional responses are acknowledged.\n             */\n            if (this.pendingReliableResponse != null\n                    && this.getDialog() != null \n                    && this.getState() != TransactionState.TERMINATED\n                    && ((SIPResponse)response).getContentTypeHeader() != null \n                    && response.getStatusCode() / 100 == 2\n                    && ((SIPResponse)response).getContentTypeHeader().getContentType()\n                            .equalsIgnoreCase(\"application\")\n                    && ((SIPResponse)response).getContentTypeHeader().getContentSubType()\n                            .equalsIgnoreCase(\"sdp\")) {\n                try {\n                    boolean acquired = this.provisionalResponseSem.tryAcquire(1,TimeUnit.SECONDS);\n                    if (!acquired ) {\n                        throw new SipException(\"cannot send response -- unacked povisional\");\n                    }\n                } catch (Exception ex) {\n                \tif (sipStack.isLoggingEnabled())\n                \t\tsipStack.getStackLogger().logError(\"Could not acquire PRACK sem \", ex);\n                }\n            } else {\n                // Sending the final response cancels the\n                // pending response task.\n                if (this.pendingReliableResponse != null && sipResponse.isFinalResponse()) {\n                    this.provisionalResponseTask.cancel();\n                    this.provisionalResponseTask = null;\n                }\n            }\n\n            // Dialog checks. These make sure that the response\n            // being sent makes sense.\n            if (dialog != null) {\n                if (sipResponse.getStatusCode() / 100 == 2\n                        && sipStack.isDialogCreated(sipResponse.getCSeq().getMethod())) {\n                    if (dialog.getLocalTag() == null && sipResponse.getTo().getTag() == null) {\n                        // Trying to send final response and user forgot to set\n                        // to\n                        // tag on the response -- be nice and assign the tag for\n                        // the user.\n                        sipResponse.getTo().setTag(Utils.getInstance().generateTag());\n                    } else if (dialog.getLocalTag() != null && sipResponse.getToTag() == null) {\n                        sipResponse.setToTag(dialog.getLocalTag());\n                    } else if (dialog.getLocalTag() != null && sipResponse.getToTag() != null\n                            && !dialog.getLocalTag().equals(sipResponse.getToTag())) {\n                        throw new SipException(\"Tag mismatch dialogTag is \"\n                                + dialog.getLocalTag() + \" responseTag is \"\n                                + sipResponse.getToTag());\n                    }\n                }\n\n                if (!sipResponse.getCallId().getCallId().equals(dialog.getCallId().getCallId())) {\n                    throw new SipException(\"Dialog mismatch!\");\n                }\n            }\n\n\n\n            // Backward compatibility slippery slope....\n            // Only set the from tag in the response when the\n            // incoming request has a from tag.\n            String fromTag = ((SIPRequest) this.getRequest()).getFrom().getTag();\n            if (fromTag != null && sipResponse.getFromTag() != null\n                    && !sipResponse.getFromTag().equals(fromTag)) {\n                throw new SipException(\"From tag of request does not match response from tag\");\n            } else if (fromTag != null) {\n                sipResponse.getFrom().setTag(fromTag);\n            } else {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"WARNING -- Null From tag in request!!\");\n            }\n\n\n\n            // See if the dialog needs to be inserted into the dialog table\n            // or if the state of the dialog needs to be changed.\n            if (dialog != null && response.getStatusCode() != 100) {\n                dialog.setResponseTags(sipResponse);\n                DialogState oldState = dialog.getState();\n                dialog.setLastResponse(this, (SIPResponse) response);\n                if (oldState == null && dialog.getState() == DialogState.TERMINATED) {\n                    DialogTerminatedEvent event = new DialogTerminatedEvent(dialog\n                            .getSipProvider(), dialog);\n\n                    // Provide notification to the listener that the dialog has\n                    // ended.\n                    dialog.getSipProvider().handleEvent(event, this);\n\n                }\n\n            } else if (dialog == null && this.getMethod().equals(Request.INVITE)\n                    && this.retransmissionAlertEnabled\n                    && this.retransmissionAlertTimerTask == null\n                    && response.getStatusCode() / 100 == 2) {\n                String dialogId = ((SIPResponse) response).getDialogId(true);\n\n                this.retransmissionAlertTimerTask = new RetransmissionAlertTimerTask(dialogId);\n                sipStack.retransmissionAlertTransactions.put(dialogId, this);\n                sipStack.getTimer().schedule(this.retransmissionAlertTimerTask, 0,\n                        SIPTransactionStack.BASE_TIMER_INTERVAL);\n\n            }\n\n            // Send message after possibly inserting the Dialog\n            // into the dialog table to avoid a possible race condition.\n\n            this.sendMessage((SIPResponse) response);\n            \n            if ( dialog != null ) {\n                dialog.startRetransmitTimer(this, (SIPResponse)response);\n            }\n\n        } catch (IOException ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(ex);\n            this.setState(TransactionState.TERMINATED);\n            raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);\n            throw new SipException(ex.getMessage());\n        } catch (java.text.ParseException ex1) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logException(ex1);\n            this.setState(TransactionState.TERMINATED);\n            throw new SipException(ex1.getMessage());\n        }\n    }\n\n    /**\n     * Return the book-keeping information that we actually use.\n     */\n    private TransactionState getRealState() {\n        return super.getState();\n    }\n\n    /**\n     * Return the current transaction state according to the RFC 3261 transaction state machine.\n     * Invite transactions do not have a trying state. We just use this as a pseudo state for\n     * processing requests.\n     *\n     * @return the state of the transaction.\n     */\n    public TransactionState getState() {\n        // Trying is a pseudo state for INVITE transactions.\n        if (this.isInviteTransaction() && TransactionState.TRYING == super.getState())\n            return TransactionState.PROCEEDING;\n        else\n            return super.getState();\n    }\n\n    /**\n     * Sets a timeout after which the connection is closed (provided the server does not use the\n     * connection for outgoing requests in this time period) and calls the superclass to set\n     * state.\n     */\n    public void setState(TransactionState newState) {\n        // Set this timer for connection caching\n        // of incoming connections.\n        if (newState == TransactionState.TERMINATED && this.isReliable()\n                && (!getSIPStack().cacheServerConnections)) {\n            // Set a time after which the connection\n            // is closed.\n            this.collectionTime = TIMER_J;\n        }\n\n        super.setState(newState);\n\n    }\n\n    /**\n     * Start the timer task.\n     */\n    protected void startTransactionTimer() {\n        if (this.transactionTimerStarted.compareAndSet(false, true)) {\n        \tif (sipStack.getTimer() != null) {\n                // The timer is set to null when the Stack is\n                // shutting down.\n                TimerTask myTimer = new TransactionTimer();\n                sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);\n            }\n        }        \n    }\n\n    public boolean equals(Object other) {\n        if (!other.getClass().equals(this.getClass())) {\n            return false;\n        }\n        SIPServerTransaction sst = (SIPServerTransaction) other;\n        return this.getBranch().equalsIgnoreCase(sst.getBranch());\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see gov2.nist.javax2.sip.stack.SIPTransaction#getDialog()\n     */\n    public Dialog getDialog() {\n\n        return this.dialog;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see gov2.nist.javax2.sip.stack.SIPTransaction#setDialog(gov2.nist.javax2.sip.stack.SIPDialog,\n     *      gov2.nist.javax2.sip.message.SIPMessage)\n     */\n    public void setDialog(SIPDialog sipDialog, String dialogId) {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"setDialog \" + this + \" dialog = \" + sipDialog);\n        this.dialog = sipDialog;\n        if (dialogId != null)\n            this.dialog.setAssigned();\n        if (this.retransmissionAlertEnabled && this.retransmissionAlertTimerTask != null) {\n            this.retransmissionAlertTimerTask.cancel();\n            if (this.retransmissionAlertTimerTask.dialogId != null) {\n                sipStack.retransmissionAlertTransactions\n                        .remove(this.retransmissionAlertTimerTask.dialogId);\n            }\n            this.retransmissionAlertTimerTask = null;\n        }\n\n        this.retransmissionAlertEnabled = false;\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.Transaction#terminate()\n     */\n    public void terminate() throws ObjectInUseException {\n        this.setState(TransactionState.TERMINATED);\n        if (this.retransmissionAlertTimerTask != null) {\n            this.retransmissionAlertTimerTask.cancel();\n            if (retransmissionAlertTimerTask.dialogId != null) {\n                this.sipStack.retransmissionAlertTransactions\n                        .remove(retransmissionAlertTimerTask.dialogId);\n            }\n            this.retransmissionAlertTimerTask = null;\n\n        }\n\n    }\n\n    protected void sendReliableProvisionalResponse(Response relResponse) throws SipException {\n\n        /*\n         * After the first reliable provisional response for a request has been acknowledged, the\n         * UAS MAY send additional reliable provisional responses. The UAS MUST NOT send a second\n         * reliable provisional response until the first is acknowledged.\n         */\n        if (this.pendingReliableResponse != null) {\n            throw new SipException(\"Unacknowledged response\");\n\n        } else\n            this.pendingReliableResponse = (SIPResponse) relResponse;\n        /*\n         * In addition, it MUST contain a Require header field containing the option tag 100rel,\n         * and MUST include an RSeq header field.\n         */\n        RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME);\n        if (relResponse.getHeader(RSeqHeader.NAME) == null) {\n            rseq = new RSeq();\n            relResponse.setHeader(rseq);\n        }\n\n        try {\n            this.rseqNumber++;\n            rseq.setSeqNumber(this.rseqNumber);\n\n            // start the timer task which will retransmit the reliable response\n            // until the PRACK is received\n            this.lastResponse = (SIPResponse) relResponse;\n            if ( this.getDialog() != null ) {\n                boolean acquired = this.provisionalResponseSem.tryAcquire(1, TimeUnit.SECONDS);\n                if (!acquired) {\n                    throw new SipException(\"Unacknowledged response\");\n                }\n            }\n            this.sendMessage((SIPMessage) relResponse);\n            this.provisionalResponseTask = new ProvisionalResponseTask();\n            this.sipStack.getTimer().schedule(provisionalResponseTask, 0,\n                    SIPTransactionStack.BASE_TIMER_INTERVAL);\n            \n\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n\n    }\n\n    public SIPResponse getReliableProvisionalResponse() {\n\n        return this.pendingReliableResponse;\n    }\n\n    /**\n     * Cancel the retransmit timer for the provisional response task.\n     *\n     * @return true if the tx has seen the prack for the first time and false otherwise.\n     *\n     */\n    public boolean prackRecieved() {\n\n        if (this.pendingReliableResponse == null)\n            return false;\n        if(provisionalResponseTask != null)\n        \tthis.provisionalResponseTask.cancel();\n        this.pendingReliableResponse = null;\n        this.provisionalResponseSem.release();\n        return true;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.ServerTransaction#enableRetransmissionAlerts()\n     */\n\n    public void enableRetransmissionAlerts() throws SipException {\n        if (this.getDialog() != null)\n            throw new SipException(\"Dialog associated with tx\");\n\n        else if (!this.getMethod().equals(Request.INVITE))\n            throw new SipException(\"Request Method must be INVITE\");\n\n        this.retransmissionAlertEnabled = true;\n\n    }\n\n    public boolean isRetransmissionAlertEnabled() {\n        return this.retransmissionAlertEnabled;\n    }\n\n    /**\n     * Disable retransmission Alerts and cancel associated timers.\n     *\n     */\n    public void disableRetransmissionAlerts() {\n        if (this.retransmissionAlertTimerTask != null && this.retransmissionAlertEnabled) {\n            this.retransmissionAlertTimerTask.cancel();\n            this.retransmissionAlertEnabled = false;\n\n            String dialogId = this.retransmissionAlertTimerTask.dialogId;\n            if (dialogId != null) {\n                sipStack.retransmissionAlertTransactions.remove(dialogId);\n            }\n            this.retransmissionAlertTimerTask = null;\n        }\n    }\n\n    /**\n     * This is book-keeping for retransmission filter management.\n     */\n    public void setAckSeen() {\n        this.isAckSeen = true;\n    }\n\n    /**\n     * This is book-keeping for retransmission filter management.\n     */\n    public boolean ackSeen() {\n        return this.isAckSeen;\n    }\n\n    public void setMapped(boolean b) {\n        this.isMapped = true;\n\n    }\n\n    public void setPendingSubscribe(SIPClientTransaction pendingSubscribeClientTx) {\n        this.pendingSubscribeTransaction = pendingSubscribeClientTx;\n\n    }\n\n    public void releaseSem() {\n        if (this.pendingSubscribeTransaction != null) {\n            /*\n             * When a notify is being processed we take a lock on the subscribe to avoid racing\n             * with the OK of the subscribe.\n             */\n            pendingSubscribeTransaction.releaseSem();\n        } else if (this.inviteTransaction != null && this.getMethod().equals(Request.CANCEL)) {\n            /*\n             * When a CANCEL is being processed we take a nested lock on the associated INVITE\n             * server tx.\n             */\n            this.inviteTransaction.releaseSem();\n        }\n        super.releaseSem();\n    }\n\n    /**\n     * The INVITE Server Transaction corresponding to a CANCEL Server Transaction.\n     *\n     * @param st -- the invite server tx corresponding to the cancel server transaction.\n     */\n    public void setInviteTransaction(SIPServerTransaction st) {\n        this.inviteTransaction = st;\n\n    }\n\n    /**\n     * TODO -- this method has to be added to the api.\n     *\n     * @return\n     */\n    public SIPServerTransaction getCanceledInviteTransaction() {\n        return this.inviteTransaction;\n    }\n\n    public void scheduleAckRemoval() throws IllegalStateException {\n        if (this.getMethod() == null || !this.getMethod().equals(Request.ACK)) {\n            throw new IllegalStateException(\"Method is null[\" + (getMethod() == null)\n                    + \"] or method is not ACK[\" + this.getMethod() + \"]\");\n        }\n\n        this.startTransactionTimer();\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPStackTimerTask.java",
    "content": "/*\n * @author:     Brett Buckingham\n * @author:     Last modified by: $Author: emcho $\n * @version:    $Date: 2009/07/17 18:58:14 $ $Revision: 1.3 $\n *\n * This source code has been contributed to the public domain.\n */\n\npackage gov2.nist.javax2.sip.stack;\n\nimport android.os.SystemClock;\n\nimport java.util.TimerTask;\n\n/**\n * A subclass of TimerTask which runs TimerTask code within a try/catch block to\n * avoid killing the SIPTransactionStack timer thread. Note: subclasses MUST not\n * override run(); instead they should override runTask().\n *\n * @author Brett Buckingham\n *\n */\npublic abstract class SIPStackTimerTask extends TimerTask {\n    long taskOutdatedTime;\n\n    // / Implements code to be run when the SIPStackTimerTask is executed.\n    protected abstract void runTask();\n\n    // / The run() method is final to ensure that all subclasses inherit the\n    // exception handling.\n    public final void run() {\n        try {\n            runTask();\n        } catch (Throwable e) {\n            System.out.println(\"SIP stack timer task failed due to exception:\");\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Set the number of ticks after which the timer is considered to be expired (i.e. outdated).\n     *\n     * A tick is a period of {@link gov2.nist.javax2.sip.stack.SIPTransactionStack#BASE_TIMER_INTERVAL} milliseconds.\n     *\n     * @param ticks number of ticks after which the timer is expired\n     *\n     * @see #isTaskOutdated()\n     */\n    protected void setTaskOutdatedTime(int ticks) {\n        taskOutdatedTime = SystemClock.elapsedRealtime() + ticks * SIPTransactionStack.BASE_TIMER_INTERVAL;\n    }\n\n    /**\n     * Check whether the task is still valid or already outdated.\n     *\n     * Ticks may not be processed as regularly and timely as scheduled if device is sleeping.\n     * This may result in the fact that there are still ticks left although the initial expiry time\n     * (start time + number of ticks * waiting period * per tick) is already exceeded.\n     *\n     * @return <code>true</code> if the task is outdated, i.e. its validity has expired\n     */\n    protected boolean isTaskOutdated() {\n        return SystemClock.elapsedRealtime() > taskOutdatedTime;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPTransaction.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip.stack;\n\nimport android.os.SystemClock;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.SipProviderImpl;\nimport gov2.nist.javax2.sip.header.CallID;\nimport gov2.nist.javax2.sip.header.Event;\nimport gov2.nist.javax2.sip.header.From;\nimport gov2.nist.javax2.sip.header.To;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.concurrent.Semaphore;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport javax.net.ssl.SSLPeerUnverifiedException;\nimport javax2.sip.Dialog;\nimport javax2.sip.IOExceptionEvent;\nimport javax2.sip.ServerTransaction;\nimport javax2.sip.TransactionState;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/*\n * Modifications for TLS Support added by Daniel J. Martinez Manzano\n * <dani@dif.um.es> Bug fixes by Jeroen van Bemmel (JvB) and others.\n */\n\n/**\n * Abstract class to support both client and server transactions. Provides an\n * encapsulation of a message channel, handles timer events, and creation of the\n * Via header for a message.\n *\n * @author Jeff Keyser\n * @author M. Ranganathan\n *\n *\n * @version 1.2 $Revision: 1.71 $ $Date: 2009/11/29 04:31:29 $\n */\npublic abstract class SIPTransaction extends MessageChannel implements\n        javax2.sip.Transaction, gov2.nist.javax2.sip.TransactionExt {\n\n    /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 1L;\n\n\tprotected boolean toListener; // Flag to indicate that the listener gets\n\n    // to see the event.\n\n    protected int BASE_TIMER_INTERVAL = SIPTransactionStack.BASE_TIMER_INTERVAL;\n    /**\n     * 5 sec Maximum duration a message will remain in the network\n     */\n    protected int T4 = 5000 / BASE_TIMER_INTERVAL;\n\n    /**\n     * The maximum retransmit interval for non-INVITE requests and INVITE\n     * responses\n     */\n    protected int T2 = 4000 / BASE_TIMER_INTERVAL;\n    protected int TIMER_I = T4;\n\n    protected int TIMER_K = T4;\n\n    protected int TIMER_D = 32000 / BASE_TIMER_INTERVAL;\n\n    // protected static final int TIMER_C = 3 * 60 * 1000 / BASE_TIMER_INTERVAL;\n\n    /**\n     * One timer tick.\n     */\n    protected static final int T1 = 1;\n\n    /**\n     * INVITE request retransmit interval, for UDP only\n     */\n    protected static final int TIMER_A = 1;\n\n    /**\n     * INVITE transaction timeout timer\n     */\n    protected static final int TIMER_B = 64;\n\n    protected static final int TIMER_J = 64;\n\n    protected static final int TIMER_F = 64;\n\n    protected static final int TIMER_H = 64;\n\n    // Proposed feature for next release.\n    protected transient Object applicationData;\n\n    protected SIPResponse lastResponse;\n\n    // private SIPDialog dialog;\n\n    protected boolean isMapped;\n\n    private Semaphore semaphore;\n\n    protected boolean isSemaphoreAquired;\n\n    // protected boolean eventPending; // indicate that an event is pending\n    // here.\n\n    protected String transactionId; // Transaction Id.\n\n    // Audit tag used by the SIP Stack audit\n    public long auditTag = 0;\n\n    /**\n     * Initialized but no state assigned.\n     */\n    public static final TransactionState INITIAL_STATE = null;\n\n    /**\n     * Trying state.\n     */\n    public static final TransactionState TRYING_STATE = TransactionState.TRYING;\n\n    /**\n     * CALLING State.\n     */\n    public static final TransactionState CALLING_STATE = TransactionState.CALLING;\n\n    /**\n     * Proceeding state.\n     */\n    public static final TransactionState PROCEEDING_STATE = TransactionState.PROCEEDING;\n\n    /**\n     * Completed state.\n     */\n    public static final TransactionState COMPLETED_STATE = TransactionState.COMPLETED;\n\n    /**\n     * Confirmed state.\n     */\n    public static final TransactionState CONFIRMED_STATE = TransactionState.CONFIRMED;\n\n    /**\n     * Terminated state.\n     */\n    public static final TransactionState TERMINATED_STATE = TransactionState.TERMINATED;\n\n    /**\n     * Maximum number of ticks between retransmissions.\n     */\n    protected static final int MAXIMUM_RETRANSMISSION_TICK_COUNT = 8;\n\n    // Parent stack for this transaction\n    protected transient SIPTransactionStack sipStack;\n\n    // Original request that is being handled by this transaction\n    protected SIPRequest originalRequest;\n\n    // Underlying channel being used to send messages for this transaction\n    private transient MessageChannel encapsulatedChannel;\n\n    // Port of peer\n    protected int peerPort;\n\n    // Address of peer\n    protected InetAddress peerInetAddress;\n\n    // Address of peer as a string\n    protected String peerAddress;\n\n    // Protocol of peer\n    protected String peerProtocol;\n\n    // @@@ hagai - NAT changes\n    // Source port extracted from peer packet\n    protected int peerPacketSourcePort;\n\n    protected InetAddress peerPacketSourceAddress;\n\n    protected AtomicBoolean transactionTimerStarted = new AtomicBoolean(false);\n\n    // Transaction branch ID\n    private String branch;\n\n    // Method of the Request used to create the transaction.\n    private String method;\n\n    // Sequence number of request used to create the transaction\n    private long cSeq;\n\n    // Current transaction state\n    private TransactionState currentState;\n\n    // Number of ticks the retransmission timer was set to last\n    private transient int retransmissionTimerLastTickCount;\n\n    // Number of ticks before the message is retransmitted\n    private transient int retransmissionTimerTicksLeft;\n\n    // Number of ticks before the transaction times out\n    protected int timeoutTimerTicksLeft;\n\n    // List of event listeners for this transaction\n    private transient Set<SIPTransactionEventListener> eventListeners;\n\n    // Hang on to these - we clear out the request URI after\n    // transaction goes to final state. Pointers to these are kept around\n    // for transaction matching as long as the transaction is in\n    // the transaction table.\n    protected From from;\n\n    protected To to;\n\n    protected Event event;\n\n    protected CallID callId;\n\n    // Back ptr to the JAIN layer.\n    // private Object wrapper;\n\n    // Counter for caching of connections.\n    // Connection lingers for collectionTime\n    // after the Transaction goes to terminated state.\n    protected int collectionTime;\n\n    protected String toTag;\n\n    protected String fromTag;\n\n    private boolean terminatedEventDelivered;\n\n    // Timestamps by when timer tasks and retransmission tasks are considered outdated\n    // Rational: As the timer tick mechanism may not work as timely as expected if the device is sleeping\n    // timer tasks may be outdated even though ticks are still left\n    private long timerOutdatedTime;\n    private long retransmissionOutdatedTime;\n\n    public String getBranchId() {\n        return this.branch;\n    }\n\n    /**\n     * The linger timer is used to remove the transaction from the transaction\n     * table after it goes into terminated state. This allows connection caching\n     * and also takes care of race conditins.\n     *\n     *\n     */\n    class LingerTimer extends SIPStackTimerTask {\n\n        public LingerTimer() {\n            SIPTransaction sipTransaction = SIPTransaction.this;\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"LingerTimer : \"\n                        + sipTransaction.getTransactionId());\n            }\n\n        }\n\n        protected void runTask() {\n            SIPTransaction transaction = SIPTransaction.this;\n            // release the connection associated with this transaction.\n            SIPTransactionStack sipStack = transaction.getSIPStack();\n\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"LingerTimer: run() : \"\n                        + getTransactionId());\n            }\n\n            if (transaction instanceof SIPClientTransaction) {\n                sipStack.removeTransaction(transaction);\n                transaction.close();\n\n            } else if (transaction instanceof ServerTransaction) {\n                // Remove it from the set\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"removing\" + transaction);\n                sipStack.removeTransaction(transaction);\n                if ((!sipStack.cacheServerConnections)\n                        && --transaction.encapsulatedChannel.useCount <= 0) {\n                    // Close the encapsulated socket if stack is configured\n                    transaction.close(); \n                } else {\n                    if (sipStack.isLoggingEnabled()\n                            && (!sipStack.cacheServerConnections)\n                            && transaction.isReliable()) {\n                        int useCount = transaction.encapsulatedChannel.useCount;\n                        sipStack.getStackLogger().logDebug(\"Use Count = \" + useCount);\n                    }\n                }\n            }\n\n        }\n    }\n\n    /**\n     * Transaction constructor.\n     *\n     * @param newParentStack\n     *            Parent stack for this transaction.\n     * @param newEncapsulatedChannel\n     *            Underlying channel for this transaction.\n     */\n    protected SIPTransaction(SIPTransactionStack newParentStack,\n            MessageChannel newEncapsulatedChannel) {\n\n        sipStack = newParentStack;\n        this.semaphore = new Semaphore(1,true);\n\n        encapsulatedChannel = newEncapsulatedChannel;\n        // Record this to check if the address has changed before sending\n        // message to avoid possible race condition.\n        this.peerPort = newEncapsulatedChannel.getPeerPort();\n        this.peerAddress = newEncapsulatedChannel.getPeerAddress();\n        this.peerInetAddress = newEncapsulatedChannel.getPeerInetAddress();\n        // @@@ hagai\n        this.peerPacketSourcePort = newEncapsulatedChannel\n                .getPeerPacketSourcePort();\n        this.peerPacketSourceAddress = newEncapsulatedChannel\n                .getPeerPacketSourceAddress();\n        this.peerProtocol = newEncapsulatedChannel.getPeerProtocol();\n        if (this.isReliable()) {            \n                encapsulatedChannel.useCount++;\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger()\n                            .logDebug(\"use count for encapsulated channel\"\n                                    + this\n                                    + \" \"\n                                    + encapsulatedChannel.useCount );\n        }\n\n        this.currentState = null;\n\n        disableRetransmissionTimer();\n        disableTimeoutTimer();\n        eventListeners = Collections.synchronizedSet(new HashSet<SIPTransactionEventListener>());\n\n        // Always add the parent stack as a listener\n        // of this transaction\n        addEventListener(newParentStack);\n\n    }\n\n    /**\n     * Sets the request message that this transaction handles.\n     *\n     * @param newOriginalRequest\n     *            Request being handled.\n     */\n    public void setOriginalRequest(SIPRequest newOriginalRequest) {\n\n        // Branch value of topmost Via header\n        String newBranch;\n\n        if (this.originalRequest != null\n                && (!this.originalRequest.getTransactionId().equals(\n                        newOriginalRequest.getTransactionId()))) {\n            sipStack.removeTransactionHash(this);\n        }\n        // This will be cleared later.\n\n        this.originalRequest = newOriginalRequest;\n\n        // just cache the control information so the\n        // original request can be released later.\n        this.method = newOriginalRequest.getMethod();\n        this.from = (From) newOriginalRequest.getFrom();\n        this.to = (To) newOriginalRequest.getTo();\n        // Save these to avoid concurrent modification exceptions!\n        this.toTag = this.to.getTag();\n        this.fromTag = this.from.getTag();\n        this.callId = (CallID) newOriginalRequest.getCallId();\n        this.cSeq = newOriginalRequest.getCSeq().getSeqNumber();\n        this.event = (Event) newOriginalRequest.getHeader(\"Event\");\n        this.transactionId = newOriginalRequest.getTransactionId();\n\n        originalRequest.setTransaction(this);\n\n        // If the message has an explicit branch value set,\n        newBranch = ((Via) newOriginalRequest.getViaHeaders().getFirst())\n                .getBranch();\n        if (newBranch != null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Setting Branch id : \" + newBranch);\n\n            // Override the default branch with the one\n            // set by the message\n            setBranch(newBranch);\n\n        } else {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Branch id is null - compute TID!\"\n                        + newOriginalRequest.encode());\n            setBranch(newOriginalRequest.getTransactionId());\n        }\n    }\n\n    /**\n     * Gets the request being handled by this transaction.\n     *\n     * @return -- the original Request associated with this transaction.\n     */\n    public SIPRequest getOriginalRequest() {\n        return originalRequest;\n    }\n\n    /**\n     * Get the original request but cast to a Request structure.\n     *\n     * @return the request that generated this transaction.\n     */\n    public Request getRequest() {\n        return (Request) originalRequest;\n    }\n\n    /**\n     * Returns a flag stating whether this transaction is for an INVITE request\n     * or not.\n     *\n     * @return -- true if this is an INVITE request, false if not.\n     */\n    public final boolean isInviteTransaction() {\n        return getMethod().equals(Request.INVITE);\n    }\n\n    /**\n     * Return true if the transaction corresponds to a CANCEL message.\n     *\n     * @return -- true if the transaciton is a CANCEL transaction.\n     */\n    public final boolean isCancelTransaction() {\n        return getMethod().equals(Request.CANCEL);\n    }\n\n    /**\n     * Return a flag that states if this is a BYE transaction.\n     *\n     * @return true if the transaciton is a BYE transaction.\n     */\n    public final boolean isByeTransaction() {\n        return getMethod().equals(Request.BYE);\n    }\n\n    /**\n     * Returns the message channel used for transmitting/receiving messages for\n     * this transaction. Made public in support of JAIN dual transaction model.\n     *\n     * @return Encapsulated MessageChannel.\n     *\n     */\n    public MessageChannel getMessageChannel() {\n        return encapsulatedChannel;\n    }\n\n    /**\n     * Sets the Via header branch parameter used to identify this transaction.\n     *\n     * @param newBranch\n     *            New string used as the branch for this transaction.\n     */\n    public final void setBranch(String newBranch) {\n        branch = newBranch;\n    }\n\n    /**\n     * Gets the current setting for the branch parameter of this transaction.\n     *\n     * @return Branch parameter for this transaction.\n     */\n    public final String getBranch() {\n        if (this.branch == null) {\n            this.branch = getOriginalRequest().getTopmostVia().getBranch();\n        }\n        return branch;\n    }\n\n    /**\n     * Get the method of the request used to create this transaction.\n     *\n     * @return the method of the request for the transaction.\n     */\n    public final String getMethod() {\n        return this.method;\n    }\n\n    /**\n     * Get the Sequence number of the request used to create the transaction.\n     *\n     * @return the cseq of the request used to create the transaction.\n     */\n    public final long getCSeq() {\n        return this.cSeq;\n    }\n\n    /**\n     * Changes the state of this transaction.\n     *\n     * @param newState\n     *            New state of this transaction.\n     */\n    public void setState(TransactionState newState) {\n        // PATCH submitted by sribeyron\n        if (currentState == TransactionState.COMPLETED) {\n            if (newState != TransactionState.TERMINATED\n                    && newState != TransactionState.CONFIRMED)\n                newState = TransactionState.COMPLETED;\n        }\n        if (currentState == TransactionState.CONFIRMED) {\n            if (newState != TransactionState.TERMINATED)\n                newState = TransactionState.CONFIRMED;\n        }\n        if (currentState != TransactionState.TERMINATED)\n            currentState = newState;\n        else\n            newState = currentState;\n        // END OF PATCH\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"Transaction:setState \" + newState\n                    + \" \" + this + \" branchID = \" + this.getBranch()\n                    + \" isClient = \" + (this instanceof SIPClientTransaction));\n            sipStack.getStackLogger().logStackTrace();\n        }\n    }\n\n    /**\n     * Gets the current state of this transaction.\n     *\n     * @return Current state of this transaction.\n     */\n    public TransactionState getState() {\n        return this.currentState;\n    }\n\n    /**\n     * Enables retransmission timer events for this transaction to begin in one\n     * tick.\n     */\n    protected final void enableRetransmissionTimer() {\n        enableRetransmissionTimer(1);\n    }\n\n    /**\n     * Enables retransmission timer events for this transaction to begin after\n     * the number of ticks passed to this routine.\n     *\n     * @param tickCount\n     *            Number of ticks before the next retransmission timer event\n     *            occurs.\n     */\n    protected final void enableRetransmissionTimer(int tickCount) {\n        // For INVITE Client transactions, double interval each time\n        if (isInviteTransaction() && (this instanceof SIPClientTransaction)) {\n            retransmissionTimerTicksLeft = tickCount;\n        } else {\n            // non-INVITE transactions and 3xx-6xx responses are capped at T2\n            retransmissionTimerTicksLeft = Math.min(tickCount,\n                    MAXIMUM_RETRANSMISSION_TICK_COUNT);\n        }\n        retransmissionTimerLastTickCount = retransmissionTimerTicksLeft;\n\n        // set the timestamp by when the retransmission timer is considered outdated no matter\n        // how many ticks are still left\n        retransmissionOutdatedTime = SystemClock.elapsedRealtime() + retransmissionTimerTicksLeft * BASE_TIMER_INTERVAL;\n    }\n\n    /**\n     * Turns off retransmission events for this transaction.\n     */\n    protected final void disableRetransmissionTimer() {\n        retransmissionTimerTicksLeft = -1;\n    }\n\n    /**\n     * Enables a timeout event to occur for this transaction after the number of\n     * ticks passed to this method.\n     *\n     * @param tickCount\n     *            Number of ticks before this transaction times out.\n     */\n    protected final void enableTimeoutTimer(int tickCount) {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"enableTimeoutTimer \" + this\n                    + \" tickCount \" + tickCount + \" currentTickCount = \"\n                    + timeoutTimerTicksLeft);\n\n        timeoutTimerTicksLeft = tickCount;\n\n        // set the timestamp by when the timer is considered outdated no matter how many\n        // ticks are still left\n        timerOutdatedTime = SystemClock.elapsedRealtime() + tickCount * BASE_TIMER_INTERVAL;\n    }\n\n    /**\n     * Disabled the timeout timer.\n     */\n    protected final void disableTimeoutTimer() {\n        timeoutTimerTicksLeft = -1;\n    }\n\n    /**\n     * Fired after each timer tick. Checks the retransmission and timeout timers\n     * of this transaction, and fired these events if necessary.\n     */\n    final void fireTimer() {\n        // If the timeout timer is enabled,\n\n        if (timeoutTimerTicksLeft != -1) {\n            // Count down the timer, and if it has run out,\n            // (or time limit has exceeded (e.g. due to timer thread was sleeping too long))\n            if (--timeoutTimerTicksLeft == 0 || SystemClock.elapsedRealtime() > timerOutdatedTime) {\n                // Fire the timeout timer\n                fireTimeoutTimer();\n            }\n        }\n\n        // If the retransmission timer is enabled,\n        if (retransmissionTimerTicksLeft != -1) {\n            // Count down the timer, and if it has run out,\n            // (or time limit has exceeded (e.g. due to timer thread was sleeping too long))\n            if (--retransmissionTimerTicksLeft == 0 || SystemClock.elapsedRealtime() > retransmissionOutdatedTime) {\n                // Enable this timer to fire again after\n                // twice the original time\n                enableRetransmissionTimer(retransmissionTimerLastTickCount * 2);\n                // Fire the timeout timer\n                fireRetransmissionTimer();\n            }\n        } \n    }\n\n    /**\n     * Tests if this transaction has terminated.\n     *\n     * @return Trus if this transaction is terminated, false if not.\n     */\n    public final boolean isTerminated() {\n        return getState() == TERMINATED_STATE;\n    }\n\n    public String getHost() {\n        return encapsulatedChannel.getHost();\n    }\n\n    public String getKey() {\n        return encapsulatedChannel.getKey();\n    }\n\n    public int getPort() {\n        return encapsulatedChannel.getPort();\n    }\n\n    public SIPTransactionStack getSIPStack() {\n        return (SIPTransactionStack) sipStack;\n    }\n\n    public String getPeerAddress() {\n        return this.peerAddress;\n    }\n\n    public int getPeerPort() {\n        return this.peerPort;\n    }\n\n    // @@@ hagai\n    public int getPeerPacketSourcePort() {\n        return this.peerPacketSourcePort;\n    }\n\n    public InetAddress getPeerPacketSourceAddress() {\n        return this.peerPacketSourceAddress;\n    }\n\n    protected InetAddress getPeerInetAddress() {\n        return this.peerInetAddress;\n    }\n\n    protected String getPeerProtocol() {\n        return this.peerProtocol;\n    }\n\n    public String getTransport() {\n        return encapsulatedChannel.getTransport();\n    }\n\n    public boolean isReliable() {\n        return encapsulatedChannel.isReliable();\n    }\n\n    /**\n     * Returns the Via header for this channel. Gets the Via header of the\n     * underlying message channel, and adds a branch parameter to it for this\n     * transaction.\n     */\n    public Via getViaHeader() {\n        // Via header of the encapulated channel\n        Via channelViaHeader;\n\n        // Add the branch parameter to the underlying\n        // channel's Via header\n        channelViaHeader = super.getViaHeader();\n        try {\n            channelViaHeader.setBranch(branch);\n        } catch (java.text.ParseException ex) {\n        }\n        return channelViaHeader;\n\n    }\n\n    /**\n     * Process the message through the transaction and sends it to the SIP peer.\n     *\n     * @param messageToSend\n     *            Message to send to the SIP peer.\n     */\n    public void sendMessage(SIPMessage messageToSend) throws IOException {\n        // Use the peer address, port and transport\n        // that was specified when the transaction was\n        // created. Bug was noted by Bruce Evangelder\n        // soleo communications.\n        try {\n            encapsulatedChannel.sendMessage(messageToSend,\n                    this.peerInetAddress, this.peerPort);\n        } finally {\n            this.startTransactionTimer();\n        }\n    }\n\n    /**\n     * Parse the byte array as a message, process it through the transaction,\n     * and send it to the SIP peer. This is just a placeholder method -- calling\n     * it will result in an IO exception.\n     *\n     * @param message\n     *            the message to send.\n     * @param receiverAddress\n     *            Address of the target peer.\n     * @param receiverPort\n     *            Network port of the target peer.\n     *\n     * @throws IOException\n     *             If called.\n     */\n    protected void sendMessage(SIPMessage message,\n            InetAddress receiverAddress, int receiverPort, boolean retry)\n            throws IOException {\n        throw new IOException(\n                \"Cannot send unparsed message through Transaction Channel!\");\n    }\n\n    /**\n     * Adds a new event listener to this transaction.\n     *\n     * @param newListener\n     *            Listener to add.\n     */\n    public void addEventListener(SIPTransactionEventListener newListener) {\n        eventListeners.add(newListener);\n    }\n\n    /**\n     * Removed an event listener from this transaction.\n     *\n     * @param oldListener\n     *            Listener to remove.\n     */\n    public void removeEventListener(SIPTransactionEventListener oldListener) {\n        eventListeners.remove(oldListener);\n    }\n\n    /**\n     * Creates a SIPTransactionErrorEvent and sends it to all of the listeners\n     * of this transaction. This method also flags the transaction as\n     * terminated.\n     *\n     * @param errorEventID\n     *            ID of the error to raise.\n     */\n    protected void raiseErrorEvent(int errorEventID) {\n\n        // Error event to send to all listeners\n        SIPTransactionErrorEvent newErrorEvent;\n        // Iterator through the list of listeners\n        Iterator<SIPTransactionEventListener> listenerIterator;\n        // Next listener in the list\n        SIPTransactionEventListener nextListener;\n\n        // Create the error event\n        newErrorEvent = new SIPTransactionErrorEvent(this, errorEventID);\n\n        // Loop through all listeners of this transaction\n        synchronized (eventListeners) {\n            listenerIterator = eventListeners.iterator();\n            while (listenerIterator.hasNext()) {\n                // Send the event to the next listener\n                nextListener = (SIPTransactionEventListener) listenerIterator\n                        .next();\n                nextListener.transactionErrorEvent(newErrorEvent);\n            }\n        }\n        // Clear the event listeners after propagating the error.\n        // Retransmit notifications are just an alert to the\n        // application (they are not an error).\n        if (errorEventID != SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) {\n            eventListeners.clear();\n\n            // Errors always terminate a transaction\n            this.setState(TransactionState.TERMINATED);\n\n            if (this instanceof SIPServerTransaction && this.isByeTransaction()\n                    && this.getDialog() != null)\n                ((SIPDialog) this.getDialog())\n                        .setState(SIPDialog.TERMINATED_STATE);\n        }\n    }\n\n    /**\n     * A shortcut way of telling if we are a server transaction.\n     */\n    protected boolean isServerTransaction() {\n        return this instanceof SIPServerTransaction;\n    }\n\n    /**\n     * Gets the dialog object of this Transaction object. This object returns\n     * null if no dialog exists. A dialog only exists for a transaction when a\n     * session is setup between a User Agent Client and a User Agent Server,\n     * either by a 1xx Provisional Response for an early dialog or a 200OK\n     * Response for a committed dialog.\n     *\n     * @return the Dialog Object of this Transaction object.\n     * @see Dialog\n     */\n    public abstract Dialog getDialog();\n\n    /**\n     * set the dialog object.\n     *\n     * @param sipDialog --\n     *            the dialog to set.\n     * @param dialogId --\n     *            the dialog id ot associate with the dialog.s\n     */\n    public abstract void setDialog(SIPDialog sipDialog, String dialogId);\n\n    /**\n     * Returns the current value of the retransmit timer in milliseconds used to\n     * retransmit messages over unreliable transports.\n     *\n     * @return the integer value of the retransmit timer in milliseconds.\n     */\n    public int getRetransmitTimer() {\n        return SIPTransactionStack.BASE_TIMER_INTERVAL;\n    }\n\n    /**\n     * Get the host to assign for an outgoing Request via header.\n     */\n    public String getViaHost() {\n        return this.getViaHeader().getHost();\n\n    }\n\n    /**\n     * Get the last response. This is used internally by the implementation.\n     * Dont rely on it.\n     *\n     * @return the last response received (for client transactions) or sent (for\n     *         server transactions).\n     */\n    public SIPResponse getLastResponse() {\n        return this.lastResponse;\n    }\n\n    /**\n     * Get the JAIN interface response\n     */\n    public Response getResponse() {\n        return (Response) this.lastResponse;\n    }\n\n    /**\n     * Get the transaction Id.\n     */\n    public String getTransactionId() {\n        return this.transactionId;\n    }\n\n    /**\n     * Hashcode method for fast hashtable lookup.\n     */\n    public int hashCode() {\n        if (this.transactionId == null)\n            return -1;\n        else\n            return this.transactionId.hashCode();\n    }\n\n    /**\n     * Get the port to assign for the via header of an outgoing message.\n     */\n    public int getViaPort() {\n        return this.getViaHeader().getPort();\n    }\n\n    /**\n     * A method that can be used to test if an incoming request belongs to this\n     * transction. This does not take the transaction state into account when\n     * doing the check otherwise it is identical to isMessagePartOfTransaction.\n     * This is useful for checking if a CANCEL belongs to this transaction.\n     *\n     * @param requestToTest\n     *            is the request to test.\n     * @return true if the the request belongs to the transaction.\n     *\n     */\n    public boolean doesCancelMatchTransaction(SIPRequest requestToTest) {\n\n        // List of Via headers in the message to test\n        ViaList viaHeaders;\n        // Topmost Via header in the list\n        Via topViaHeader;\n        // Branch code in the topmost Via header\n        String messageBranch;\n        // Flags whether the select message is part of this transaction\n        boolean transactionMatches;\n\n        transactionMatches = false;\n\n        if (this.getOriginalRequest() == null\n                || this.getOriginalRequest().getMethod().equals(Request.CANCEL))\n            return false;\n        // Get the topmost Via header and its branch parameter\n        viaHeaders = requestToTest.getViaHeaders();\n        if (viaHeaders != null) {\n\n            topViaHeader = (Via) viaHeaders.getFirst();\n            messageBranch = topViaHeader.getBranch();\n            if (messageBranch != null) {\n\n                // If the branch parameter exists but\n                // does not start with the magic cookie,\n                if (!messageBranch.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {\n\n                    // Flags this as old\n                    // (RFC2543-compatible) client\n                    // version\n                    messageBranch = null;\n\n                }\n\n            }\n\n            // If a new branch parameter exists,\n            if (messageBranch != null && this.getBranch() != null) {\n\n                // If the branch equals the branch in\n                // this message,\n                if (getBranch().equalsIgnoreCase(messageBranch)\n                        && topViaHeader.getSentBy().equals(\n                                ((Via) getOriginalRequest().getViaHeaders()\n                                        .getFirst()).getSentBy())) {\n                    transactionMatches = true;\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger().logDebug(\"returning  true\");\n                }\n\n            } else {\n                // If this is an RFC2543-compliant message,\n                // If RequestURI, To tag, From tag,\n                // CallID, CSeq number, and top Via\n                // headers are the same,\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"testing against \"\n                            + getOriginalRequest());\n\n                if (getOriginalRequest().getRequestURI().equals(\n                        requestToTest.getRequestURI())\n                        && getOriginalRequest().getTo().equals(\n                                requestToTest.getTo())\n                        && getOriginalRequest().getFrom().equals(\n                                requestToTest.getFrom())\n                        && getOriginalRequest().getCallId().getCallId().equals(\n                                requestToTest.getCallId().getCallId())\n                        && getOriginalRequest().getCSeq().getSeqNumber() == requestToTest\n                                .getCSeq().getSeqNumber()\n                        && topViaHeader.equals(getOriginalRequest()\n                                .getViaHeaders().getFirst())) {\n\n                    transactionMatches = true;\n                }\n\n            }\n\n        }\n\n        // JvB: Need to pass the CANCEL to the listener! Retransmitted INVITEs\n        // set it to false\n        if (transactionMatches) {\n            this.setPassToListener();\n        }\n        return transactionMatches;\n    }\n\n    /**\n     * Sets the value of the retransmit timer to the newly supplied timer value.\n     * The retransmit timer is expressed in milliseconds and its default value\n     * is 500ms. This method allows the application to change the transaction\n     * retransmit behavior for different networks. Take the gateway proxy as an\n     * example. The internal intranet is likely to be reatively uncongested and\n     * the endpoints will be relatively close. The external network is the\n     * general Internet. This functionality allows different retransmit times\n     * for either side.\n     *\n     * @param retransmitTimer -\n     *            the new integer value of the retransmit timer in milliseconds.\n     */\n    public void setRetransmitTimer(int retransmitTimer) {\n\n        if (retransmitTimer <= 0)\n            throw new IllegalArgumentException(\n                    \"Retransmit timer must be positive!\");\n        if (this.transactionTimerStarted.get())\n            throw new IllegalStateException(\n                    \"Transaction timer is already started\");\n        BASE_TIMER_INTERVAL = retransmitTimer;\n        T4 = 5000 / BASE_TIMER_INTERVAL;\n\n        T2 = 4000 / BASE_TIMER_INTERVAL;\n        TIMER_I = T4;\n\n        TIMER_K = T4;\n\n        TIMER_D = 32000 / BASE_TIMER_INTERVAL;\n\n    }\n\n    /**\n     * Sets timers value. Bug fix OrangeLabs, JOGUET Benoit.\n     *\n     * @param timer_T1\n     * @param timer_T2\n     * @param timer_T4\n     */\n    public void setRetransmitTimers(int timer_T1, int timer_T2, int timer_T4) {\n        if ((timer_T1 <= 0) || (timer_T2 <= 0) || (timer_T4 <= 0)) {\n            throw new IllegalArgumentException(\"Retransmit timers must be positives!\");\n        }\n        if (this.transactionTimerStarted.get()) {\n            throw new IllegalStateException(\"Transaction timer is already started\");\n        }\n        BASE_TIMER_INTERVAL = timer_T1;\n        T4 = timer_T4 / BASE_TIMER_INTERVAL;\n        T2 = timer_T2 / BASE_TIMER_INTERVAL;\n        TIMER_I = T4;\n        TIMER_K = T4;\n        TIMER_D = 32000 / BASE_TIMER_INTERVAL;\n    }\n\n    /**\n     * Close the encapsulated channel.\n     */\n    public void close() {\n        this.encapsulatedChannel.close();\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"Closing \" + this.encapsulatedChannel);\n\n    }\n\n    public boolean isSecure() {\n        return encapsulatedChannel.isSecure();\n    }\n\n    public MessageProcessor getMessageProcessor() {\n        return this.encapsulatedChannel.getMessageProcessor();\n    }\n\n    /**\n     * Set the application data pointer. This is un-interpreted by the stack.\n     * This is provided as a conveniant way of keeping book-keeping data for\n     * applications. Note that null clears the application data pointer\n     * (releases it).\n     *\n     * @param applicationData --\n     *            application data pointer to set. null clears the applicationd\n     *            data pointer.\n     *\n     */\n\n    public void setApplicationData(Object applicationData) {\n        this.applicationData = applicationData;\n    }\n\n    /**\n     * Get the application data associated with this transaction.\n     *\n     * @return stored application data.\n     */\n    public Object getApplicationData() {\n        return this.applicationData;\n    }\n\n    /**\n     * Set the encapsuated channel. The peer inet address and port are set equal\n     * to the message channel.\n     */\n    public void setEncapsulatedChannel(MessageChannel messageChannel) {\n        this.encapsulatedChannel = messageChannel;\n        this.peerInetAddress = messageChannel.getPeerInetAddress();\n        this.peerPort = messageChannel.getPeerPort();\n    }\n\n    /**\n     * Return the SipProvider for which the transaction is assigned.\n     *\n     * @return the SipProvider for the transaction.\n     */\n    public SipProviderImpl getSipProvider() {\n\n        return this.getMessageProcessor().getListeningPoint().getProvider();\n    }\n\n    /**\n     * Raise an IO Exception event - this is used for reporting asynchronous IO\n     * Exceptions that are attributable to this transaction.\n     *\n     */\n    public void raiseIOExceptionEvent() {\n        setState(TransactionState.TERMINATED);\n        String host = getPeerAddress();\n        int port = getPeerPort();\n        String transport = getTransport();\n        IOExceptionEvent exceptionEvent = new IOExceptionEvent(this, host,\n                port, transport);\n        getSipProvider().handleEvent(exceptionEvent, this);\n    }\n\n    /**\n     * A given tx can process only a single outstanding event at a time. This\n     * semaphore gaurds re-entrancy to the transaction.\n     *\n     */\n    public boolean acquireSem() {\n        boolean retval = false;\n        try {\n            if (sipStack.getStackLogger().isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"acquireSem [[[[\" + this);\n                sipStack.getStackLogger().logStackTrace();\n            }\n            retval = this.semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS);\n            if ( sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\n                    \"acquireSem() returning : \" + retval);\n            return retval;\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Unexpected exception acquiring sem\",\n                    ex);\n            InternalErrorHandler.handleException(ex);\n            return false;\n        } finally {\n            this.isSemaphoreAquired = retval;\n        }\n\n    }\n\n    /**\n     * Release the transaction semaphore.\n     *\n     */\n    public void releaseSem() {\n        try {\n\n            this.toListener = false;\n            this.semRelease();\n\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Unexpected exception releasing sem\",\n                    ex);\n\n        }\n\n    }\n\n    protected void semRelease() {\n        try {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"semRelease ]]]]\" + this);\n                sipStack.getStackLogger().logStackTrace();\n            }\n            this.isSemaphoreAquired = false;\n            this.semaphore.release();\n\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"Unexpected exception releasing sem\",\n                    ex);\n\n        }\n    }\n\n    /**\n     * Set true to pass the request up to the listener. False otherwise.\n     *\n     */\n\n    public boolean passToListener() {\n        return toListener;\n    }\n\n    /**\n     * Set the passToListener flag to true.\n     */\n    public void setPassToListener() {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"setPassToListener()\");\n        }\n        this.toListener = true;\n\n    }\n\n    /**\n     * Flag to test if the terminated event is delivered.\n     *\n     * @return\n     */\n    protected synchronized boolean testAndSetTransactionTerminatedEvent() {\n        boolean retval = !this.terminatedEventDelivered;\n        this.terminatedEventDelivered = true;\n        return retval;\n    }\n    \n    public String getCipherSuite() throws UnsupportedOperationException {\n        if (this.getMessageChannel() instanceof TLSMessageChannel ) {\n            if (  ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) \n                return null;\n            else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null)\n                return null;\n            else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getCipherSuite();\n        } else throw new UnsupportedOperationException(\"Not a TLS channel\");\n\n    }\n\n    \n    public java.security.cert.Certificate[] getLocalCertificates() throws UnsupportedOperationException {\n         if (this.getMessageChannel() instanceof TLSMessageChannel ) {\n            if (  ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) \n                return null;\n            else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null)\n                return null;\n            else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getLocalCertificates();\n        } else throw new UnsupportedOperationException(\"Not a TLS channel\");\n    }\n\n    \n    public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {\n        if (this.getMessageChannel() instanceof TLSMessageChannel ) {\n            if (  ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) \n                return null;\n            else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null)\n                return null;\n            else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getPeerCertificates();\n        } else throw new UnsupportedOperationException(\"Not a TLS channel\");\n\n    }\n\n\n    /**\n     * Start the timer that runs the transaction state machine.\n     *\n     */\n\n    protected abstract void startTransactionTimer();\n\n    /**\n     * Tests a message to see if it is part of this transaction.\n     *\n     * @return True if the message is part of this transaction, false if not.\n     */\n    public abstract boolean isMessagePartOfTransaction(SIPMessage messageToTest);\n\n    /**\n     * This method is called when this transaction's retransmission timer has\n     * fired.\n     */\n    protected abstract void fireRetransmissionTimer();\n\n    /**\n     * This method is called when this transaction's timeout timer has fired.\n     */\n    protected abstract void fireTimeoutTimer();    \n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPTransactionErrorEvent.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.stack;\n\n\nimport java.util.EventObject;\n\n/**\n * An event that indicates that a transaction has encountered an error.\n *\n *\n * @author Jeff Keyser\n * @author M. Ranganathan\n *\n *\n *\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:15 $\n */\npublic class SIPTransactionErrorEvent extends EventObject {\n\n    /**\n     * Comment for <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = -2713188471978065031L;\n\n    /**\n     * This event ID indicates that the transaction has timed out.\n     */\n    public static final int TIMEOUT_ERROR = 1;\n\n    /**\n     * This event ID indicates that there was an error sending a message using\n     * the underlying transport.\n     */\n    public static final int TRANSPORT_ERROR = 2;\n\n    /**\n     * Retransmit signal to application layer.\n     */\n    public static final int TIMEOUT_RETRANSMIT = 3;\n\n\n\n    // ID of this error event\n    private int errorID;\n\n    /**\n     * Creates a transaction error event.\n     *\n     * @param sourceTransaction Transaction which is raising the error.\n     * @param transactionErrorID ID of the error that has ocurred.\n     */\n    SIPTransactionErrorEvent(\n        SIPTransaction sourceTransaction,\n        int transactionErrorID) {\n\n        super(sourceTransaction);\n        errorID = transactionErrorID;\n\n    }\n\n    /**\n     * Returns the ID of the error.\n     *\n     * @return Error ID.\n     */\n    public int getErrorID() {\n        return errorID;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPTransactionEventListener.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\npackage gov2.nist.javax2.sip.stack;\n\nimport java.util.EventListener;\n\n/**\n * Interface implemented by classes that want to be notified of asynchronous\n * transacion events.\n *\n * @author Jeff Keyser\n * @version 1.2 $Revision: 1.7 $ $Date: 2009/07/17 18:58:15 $\n */\npublic interface SIPTransactionEventListener extends EventListener {\n\n    /**\n     * Invoked when an error has ocurred with a transaction.\n     *\n     * @param transactionErrorEvent Error event.\n     */\n    public void transactionErrorEvent(SIPTransactionErrorEvent transactionErrorEvent);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/SIPTransactionStack.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.Host;\nimport gov2.nist.core.HostPort;\nimport gov2.nist.core.ServerLogger;\nimport gov2.nist.core.StackLogger;\nimport gov2.nist.core.ThreadAuditor;\nimport gov2.nist.core.net.AddressResolver;\nimport gov2.nist.core.net.DefaultNetworkLayer;\nimport gov2.nist.core.net.NetworkLayer;\nimport gov2.nist.javax2.sip.DefaultAddressResolver;\nimport gov2.nist.javax2.sip.ListeningPointImpl;\nimport gov2.nist.javax2.sip.LogRecordFactory;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.SipListenerExt;\nimport gov2.nist.javax2.sip.SipProviderImpl;\nimport gov2.nist.javax2.sip.SipStackImpl;\nimport gov2.nist.javax2.sip.header.Event;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.extensions.JoinHeader;\nimport gov2.nist.javax2.sip.header.extensions.ReplacesHeader;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketAddress;\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.Set;\nimport java.util.Timer;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport javax2.sip.ClientTransaction;\nimport javax2.sip.Dialog;\nimport javax2.sip.DialogState;\nimport javax2.sip.DialogTerminatedEvent;\nimport javax2.sip.ServerTransaction;\nimport javax2.sip.SipException;\nimport javax2.sip.SipListener;\nimport javax2.sip.TransactionState;\nimport javax2.sip.TransactionTerminatedEvent;\nimport javax2.sip.address.Hop;\nimport javax2.sip.address.Router;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.EventHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\n/*\n * Jeff Keyser : architectural suggestions and contributions. Pierre De Rop and Thomas Froment :\n * Bug reports. Jeyashankher < jai@lucent.com > : bug reports. Jeroen van Bemmel : Bug fixes.\n *\n *\n */\n\n/**\n *\n * This is the sip stack. It is essentially a management interface. It manages the resources for\n * the JAIN-SIP implementation. This is the structure that is wrapped by the SipStackImpl.\n *\n * @see gov2.nist.javax2.sip.SipStackImpl\n *\n * @author M. Ranganathan <br/>\n *\n * @version 1.2 $Revision: 1.141 $ $Date: 2009/12/17 23:38:27 $\n */\npublic abstract class SIPTransactionStack implements SIPTransactionEventListener, SIPDialogEventListener {\n\n    /*\n     * Number of milliseconds between timer ticks (500).\n     */\n    public static final int BASE_TIMER_INTERVAL = 500;\n\n    /*\n     * Connection linger time (seconds) this is the time (in seconds) for which we linger the TCP\n     * connection before closing it.\n     */\n    public static final int CONNECTION_LINGER_TIME = 8;\n\n    /*\n     * Table of retransmission Alert timers.\n     */\n    protected ConcurrentHashMap<String, SIPServerTransaction> retransmissionAlertTransactions;\n\n    // Table of early dialogs ( to keep identity mapping )\n    protected ConcurrentHashMap<String, SIPDialog> earlyDialogTable;\n\n    // Table of dialogs.\n    protected ConcurrentHashMap<String, SIPDialog> dialogTable;\n\n    // A set of methods that result in dialog creations.\n    protected static final Set<String> dialogCreatingMethods = new HashSet<String>();\n\n    // Global timer. Use this for all timer tasks.\n\n    private Timer timer;\n\n    // List of pending server transactions\n    private ConcurrentHashMap<String, SIPServerTransaction> pendingTransactions;\n\n    // hashtable for fast lookup\n    private ConcurrentHashMap<String, SIPClientTransaction> clientTransactionTable;\n\n    // Set to false if you want hiwat and lowat to be consulted.\n    protected boolean unlimitedServerTransactionTableSize = true;\n\n    // Set to false if you want unlimited size of client trnansactin table.\n    protected boolean unlimitedClientTransactionTableSize = true;\n\n    // High water mark for ServerTransaction Table\n    // after which requests are dropped.\n    protected int serverTransactionTableHighwaterMark = 5000;\n\n    // Low water mark for Server Tx table size after which\n    // requests are selectively dropped\n    protected int serverTransactionTableLowaterMark = 4000;\n\n    // Hiwater mark for client transaction table. These defaults can be\n    // overriden by stack\n    // configuration.\n    protected int clientTransactionTableHiwaterMark = 1000;\n\n    // Low water mark for client tx table.\n    protected int clientTransactionTableLowaterMark = 800;\n\n    private AtomicInteger activeClientTransactionCount = new AtomicInteger(0);\n\n    // Hashtable for server transactions.\n    private ConcurrentHashMap<String, SIPServerTransaction> serverTransactionTable;\n\n    // A table of ongoing transactions indexed by mergeId ( for detecting merged\n    // requests.\n    private ConcurrentHashMap<String, SIPServerTransaction> mergeTable;\n    \n    private ConcurrentHashMap<String,SIPServerTransaction> terminatedServerTransactionsPendingAck;\n    \n    private ConcurrentHashMap<String,SIPClientTransaction> forkedClientTransactionTable;\n\n    /*\n     * A wrapper around differnt logging implementations (log4j, commons logging, slf4j, ...) to help log debug.\n     */\n    private StackLogger stackLogger;\n\n    /*\n     * ServerLog is used just for logging stack message tracecs.\n     */\n    protected ServerLogger serverLogger;\n\n    /*\n     * We support UDP on this stack.\n     */\n    boolean udpFlag;\n\n    /*\n     * Internal router. Use this for all sip: request routing.\n     *\n     */\n    protected DefaultRouter defaultRouter;\n\n    /*\n     * Global flag that turns logging off\n     */\n    protected boolean needsLogging;\n\n    /*\n     * Flag used for testing TI, bypasses filtering of ACK to non-2xx\n     */\n    private boolean non2XXAckPassedToListener;\n\n    /*\n     * Class that handles caching of TCP/TLS connections.\n     */\n    protected IOHandler ioHandler;\n\n    /*\n     * Flag that indicates that the stack is active.\n     */\n    protected boolean toExit;\n\n    /*\n     * Name of the stack.\n     */\n    protected String stackName;\n\n    /*\n     * IP address of stack -- this can be re-written by stun.\n     *\n     * @deprecated\n     */\n    protected String stackAddress;\n\n    /*\n     * INET address of stack (cached to avoid repeated lookup)\n     *\n     * @deprecated\n     */\n    protected InetAddress stackInetAddress;\n\n    // Changed by Deutsche Telekom\n    /**\n     * Default SIP port\n     */\n    public final static int DEFAULT_MTU_SIZE = 1500;\n\n    // Changed by Deutsche Telekom\n    /**\n     * MTU size\n     */\n    private int mtuSize = DEFAULT_MTU_SIZE;\n\n    /*\n     * Request factory interface (to be provided by the application)\n     */\n    protected StackMessageFactory sipMessageFactory;\n\n    /*\n     * Router to determine where to forward the request.\n     */\n    protected javax2.sip.address.Router router;\n\n    /*\n     * Number of pre-allocated threads for processing udp messages. -1 means no preallocated\n     * threads ( dynamically allocated threads).\n     */\n    protected int threadPoolSize;\n\n    /*\n     * max number of simultaneous connections.\n     */\n    protected int maxConnections;\n\n    /*\n     * Close accept socket on completion.\n     */\n    protected boolean cacheServerConnections;\n\n    /*\n     * Close connect socket on Tx termination.\n     */\n    protected boolean cacheClientConnections;\n\n    /*\n     * Use the user supplied router for all out of dialog requests.\n     */\n    protected boolean useRouterForAll;\n\n    /*\n     * Max size of message that can be read from a TCP connection.\n     */\n    protected int maxContentLength;\n\n    /*\n     * Max # of headers that a SIP message can contain.\n     */\n    protected int maxMessageSize;\n\n    /*\n     * A collection of message processors.\n     */\n    private Collection<MessageProcessor> messageProcessors;\n\n    /*\n     * Read timeout on TCP incoming sockets -- defines the time between reads for after delivery\n     * of first byte of message.\n     */\n    protected int readTimeout;\n\n    /*\n     * The socket factory. Can be overriden by applications that want direct access to the\n     * underlying socket.\n     */\n\n    protected NetworkLayer networkLayer;\n\n    /*\n     * Outbound proxy String ( to be handed to the outbound proxy class on creation).\n     */\n    protected String outboundProxy;\n\n    protected String routerPath;\n\n    // Flag to indicate whether the stack will provide dialog\n    // support.\n    protected boolean isAutomaticDialogSupportEnabled;\n\n    // The set of events for which subscriptions can be forked.\n\n    protected HashSet<String> forkedEvents;\n\n    // Generate a timestamp header for retransmitted requests.\n    protected boolean generateTimeStampHeader;\n\n    protected AddressResolver addressResolver;\n\n    // Max time that the listener is allowed to take to respond to a\n    // request. Default is \"infinity\". This property allows\n    // containers to defend against buggy clients (that do not\n    // want to respond to requests).\n    protected int maxListenerResponseTime;\n\n  \n    // A flag that indicates whether or not RFC 2543 clients are fully supported.\n    // If this is set to true, then To tag checking on the Dialog layer is\n    // disabled in a few places - resulting in possible breakage of forked dialogs.\n    protected boolean rfc2543Supported = true;\n\n    // / Provides a mechanism for applications to check the health of threads in\n    // the stack\n    protected ThreadAuditor threadAuditor = new ThreadAuditor();\n\n    protected LogRecordFactory logRecordFactory;\n\n    // Set to true if the client CANCEL transaction should be checked before sending\n    // it out.\n    protected boolean cancelClientTransactionChecked = true;\n\n    // Is to tag reassignment allowed.\n    protected boolean remoteTagReassignmentAllowed = true;\n\n    protected boolean logStackTraceOnMessageSend = true;\n   \n    // Receive UDP buffer size\n    protected int receiveUdpBufferSize;\n    \n    // Send UDP buffer size\n    protected int sendUdpBufferSize;\n\n    protected boolean stackDoesCongestionControl = true;\n\n    protected boolean isBackToBackUserAgent = false;\n\n    protected boolean checkBranchId;\n\n\tprotected boolean isAutomaticDialogErrorHandlingEnabled = true;\n\t\n\tprotected boolean isDialogTerminatedEventDeliveredForNullDialog = false;\n\t\n\t// Max time for a forked response to arrive. After this time, the original dialog\n\t// is not tracked. If you want to track the original transaction you need to specify\n\t// the max fork time with a stack init property.\n\tprotected int maxForkTime = 0;\n\n   \n    // / Timer to regularly ping the thread auditor (on behalf of the timer\n    // thread)\n    class PingTimer extends SIPStackTimerTask {\n        // / Timer thread handle\n        ThreadAuditor.ThreadHandle threadHandle;\n\n        // / Constructor\n        public PingTimer(ThreadAuditor.ThreadHandle a_oThreadHandle) {\n            threadHandle = a_oThreadHandle;\n        }\n\n        protected void runTask() {\n            // Check if we still have a timer (it may be null after shutdown)\n            if (getTimer() != null) {\n                // Register the timer task if we haven't done so\n                if (threadHandle == null) {\n                    // This happens only once since the thread handle is passed\n                    // to the next scheduled ping timer\n                    threadHandle = getThreadAuditor().addCurrentThread();\n                }\n\n                // Let the thread auditor know that the timer task is alive\n                threadHandle.ping();\n\n                // Schedule the next ping\n                getTimer().schedule(new PingTimer(threadHandle),\n                        threadHandle.getPingIntervalInMillisecs());\n            }\n        }\n\n    }\n    \n    \n    class RemoveForkedTransactionTimerTask extends SIPStackTimerTask {\n        \n        private SIPClientTransaction clientTransaction;\n\n        public RemoveForkedTransactionTimerTask(SIPClientTransaction sipClientTransaction ) {\n            this.clientTransaction = sipClientTransaction;\n        }\n\n        @Override\n        protected void runTask() {\n           forkedClientTransactionTable.remove(clientTransaction.getTransactionId()); \n        }\n        \n    }\n\n    static {\n    \t// Standard set of methods that create dialogs.\n    \tdialogCreatingMethods.add(Request.REFER);\n        dialogCreatingMethods.add(Request.INVITE);\n        dialogCreatingMethods.add(Request.SUBSCRIBE);\n    }\n    \n    /**\n     * Default constructor.\n     */\n    protected SIPTransactionStack() {\n        this.toExit = false;\n        this.forkedEvents = new HashSet<String>();\n        // set of events for which subscriptions can be forked.\n        // Set an infinite thread pool size.\n        this.threadPoolSize = -1;\n        // Close response socket after infinte time.\n        // for max performance\n        this.cacheServerConnections = true;\n        // Close the request socket after infinite time.\n        // for max performance\n        this.cacheClientConnections = true;\n        // Max number of simultaneous connections.\n        this.maxConnections = -1;\n        // Array of message processors.\n        messageProcessors = new ArrayList<MessageProcessor>();\n        // Handle IO for this process.\n        this.ioHandler = new IOHandler(this);\n\n        // The read time out is infinite.\n        this.readTimeout = -1;\n\n        this.maxListenerResponseTime = -1;\n\n        // The default (identity) address lookup scheme\n\n        this.addressResolver = new DefaultAddressResolver();\n\n        // Notify may or may not create a dialog. This is handled in\n        // the code.\n        // Create the transaction collections\n\n        // Dialog dable.\n        this.dialogTable = new ConcurrentHashMap<String, SIPDialog>();\n        this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>();\n\n        clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>();\n        serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>();\n        this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String, SIPServerTransaction>();\n        mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>();\n        retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();\n\n        // Start the timer event thread.\n\n        this.timer = new Timer();\n        this.pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();\n        \n        \n        this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>();\n\n        if (getThreadAuditor().isEnabled()) {\n            // Start monitoring the timer thread\n            timer.schedule(new PingTimer(null), 0);\n        }\n    }\n\n    /**\n     * Re Initialize the stack instance.\n     */\n    protected void reInit() {\n        if (isLoggingEnabled())\n            stackLogger.logDebug(\"Re-initializing !\");\n\n        // Array of message processors.\n        messageProcessors = new ArrayList<MessageProcessor>();\n        // Handle IO for this process.\n        this.ioHandler = new IOHandler(this);\n        // clientTransactions = new ConcurrentLinkedQueue();\n        // serverTransactions = new ConcurrentLinkedQueue();\n        pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();\n        clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>();\n        serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>();\n        retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();\n        mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>();\n        // Dialog dable.\n        this.dialogTable = new ConcurrentHashMap<String, SIPDialog>();\n        this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>();\n        this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String,SIPServerTransaction>();\n        this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>();\n\n        this.timer = new Timer();\n\n        this.activeClientTransactionCount = new AtomicInteger(0);\n\n    }\n\n    /**\n     * Creates and binds, if necessary, a socket connected to the specified\n     * destination address and port and then returns its local address.\n     *\n     * @param dst the destination address that the socket would need to connect\n     *            to.\n     * @param dstPort the port number that the connection would be established\n     * with.\n     * @param localAddress the address that we would like to bind on\n     * (null for the \"any\" address).\n     * @param localPort the port that we'd like our socket to bind to (0 for a\n     * random port).\n     *\n     * @return the SocketAddress that this handler would use when connecting to\n     * the specified destination address and port.\n     *\n     * @throws IOException\n     */\n    public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort,\n                    InetAddress localAddress, int localPort)\n        throws IOException\n    {\n        return this.ioHandler.obtainLocalAddress(\n                        dst, dstPort, localAddress, localPort);\n\n    }\n\n    /**\n     * For debugging -- allows you to disable logging or enable logging selectively.\n     *\n     *\n     */\n    public void disableLogging() {\n        getStackLogger().disableLogging();\n    }\n\n    /**\n     * Globally enable message logging ( for debugging)\n     *\n     */\n    public void enableLogging() {\n        getStackLogger().enableLogging();\n    }\n\n    /**\n     * Print the dialog table.\n     *\n     */\n    public void printDialogTable() {\n        if (isLoggingEnabled()) {\n            getStackLogger().logDebug(\"dialog table  = \" + this.dialogTable);\n            System.out.println(\"dialog table = \" + this.dialogTable);\n        }\n    }\n\n    /**\n     * Retrieve a transaction from our table of transactions with pending retransmission alerts.\n     *\n     * @param dialogId\n     * @return -- the RetransmissionAlert enabled transaction corresponding to the given dialog\n     *         ID.\n     */\n    public SIPServerTransaction getRetransmissionAlertTransaction(String dialogId) {\n        return (SIPServerTransaction) this.retransmissionAlertTransactions.get(dialogId);\n    }\n\n    /**\n     * Return true if extension is supported.\n     *\n     * @return true if extension is supported and false otherwise.\n     */\n    public static boolean isDialogCreated(String method) {\n    \treturn dialogCreatingMethods.contains(method);\n    }\n\n    /**\n     * Add an extension method.\n     *\n     * @param extensionMethod -- extension method to support for dialog creation\n     */\n    public void addExtensionMethod(String extensionMethod) {\n        if (extensionMethod.equals(Request.NOTIFY)) {\n            if (isLoggingEnabled())\n                stackLogger.logDebug(\"NOTIFY Supported Natively\");\n        } else {\n            dialogCreatingMethods.add(extensionMethod.trim().toUpperCase());\n        }\n    }\n\n    /**\n     * Put a dialog into the dialog table.\n     *\n     * @param dialog -- dialog to put into the dialog table.\n     *\n     */\n    public void putDialog(SIPDialog dialog) {\n        String dialogId = dialog.getDialogId();\n        if (dialogTable.containsKey(dialogId)) {\n            if (isLoggingEnabled()) {\n                stackLogger.logDebug(\"putDialog: dialog already exists\" + dialogId + \" in table = \"\n                        + dialogTable.get(dialogId));\n            }\n            return;\n        }\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"putDialog dialogId=\" + dialogId + \" dialog = \" + dialog);\n        }\n        dialog.setStack(this);\n        if (isLoggingEnabled())\n            stackLogger.logStackTrace();\n        dialogTable.put(dialogId, dialog);\n\n    }\n\n    /**\n     * Create a dialog and add this transaction to it.\n     *\n     * @param transaction -- tx to add to the dialog.\n     * @return the newly created Dialog.\n     */\n    public SIPDialog createDialog(SIPTransaction transaction) {\n\n        SIPDialog retval = null;\n\n        if (transaction instanceof SIPClientTransaction) {\n            String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);\n            if (this.earlyDialogTable.get(dialogId) != null) {\n                SIPDialog dialog = this.earlyDialogTable.get(dialogId);\n                if (dialog.getState() == null || dialog.getState() == DialogState.EARLY) {\n                    retval = dialog;\n                } else {\n                    retval = new SIPDialog(transaction);\n                    this.earlyDialogTable.put(dialogId, retval);\n                }\n            } else {\n                retval = new SIPDialog(transaction);\n                this.earlyDialogTable.put(dialogId, retval);\n            }\n        } else {\n            retval = new SIPDialog(transaction);\n        }\n\n        return retval;\n\n    }\n\n    /**\n     * Create a Dialog given a client tx and response.\n     *\n     * @param transaction\n     * @param sipResponse\n     * @return\n     */\n\n    public SIPDialog createDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {\n        String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);\n        SIPDialog retval = null;\n        if (this.earlyDialogTable.get(dialogId) != null) {\n            retval = this.earlyDialogTable.get(dialogId);\n            if (sipResponse.isFinalResponse()) {\n                this.earlyDialogTable.remove(dialogId);\n            }\n\n        } else {\n            retval = new SIPDialog(transaction, sipResponse);\n        }\n        return retval;\n\n    }\n    /**\n     * Create a Dialog given a sip provider and response.\n     *\n     * @param sipProvider\n     * @param sipResponse\n     * @return\n     */\n    public SIPDialog createDialog(SipProviderImpl sipProvider,\n\t\t\tSIPResponse sipResponse) {\n\t\treturn new SIPDialog(sipProvider, sipResponse);\n\t}\n\n    /**\n     * Remove the dialog from the dialog table.\n     *\n     * @param dialog -- dialog to remove.\n     */\n    public void removeDialog(SIPDialog dialog) {\n\n        String id = dialog.getDialogId();\n\n        String earlyId = dialog.getEarlyDialogId();\n\n        if (earlyId != null) {\n            this.earlyDialogTable.remove(earlyId);\n            this.dialogTable.remove(earlyId);\n        }\n\n        if (id != null) {\n\n            // FHT: Remove dialog from table only if its associated dialog is the same as the one\n            // specified\n\n            Object old = this.dialogTable.get(id);\n\n            if (old == dialog) {\n                this.dialogTable.remove(id);\n            }\n       \n            // We now deliver DTE even when the dialog is not originally present in the Dialog\n            // Table\n            // This happens before the dialog state is assigned.\n\n            if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) {\n                DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(),\n                        dialog);\n\n                // Provide notification to the listener that the dialog has\n                // ended.\n                dialog.getSipProvider().handleEvent(event, null);\n\n            }\n\n        } else if ( this.isDialogTerminatedEventDeliveredForNullDialog ) {\n            if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) {\n                DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(),\n                        dialog);\n\n                // Provide notification to the listener that the dialog has\n                // ended.\n                dialog.getSipProvider().handleEvent(event, null);\n\n            }\n        }\n\n    }\n\n    /**\n     * Return the dialog for a given dialog ID. If compatibility is enabled then we do not assume\n     * the presence of tags and hence need to add a flag to indicate whether this is a server or\n     * client transaction.\n     *\n     * @param dialogId is the dialog id to check.\n     */\n\n    public SIPDialog getDialog(String dialogId) {\n\n        SIPDialog sipDialog = (SIPDialog) dialogTable.get(dialogId);\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"getDialog(\" + dialogId + \") : returning \" + sipDialog);\n        }\n        return sipDialog;\n\n    }\n\n    /**\n     * Remove the dialog given its dialog id. This is used for dialog id re-assignment only.\n     *\n     * @param dialogId is the dialog Id to remove.\n     */\n    public void removeDialog(String dialogId) {\n        if (isLoggingEnabled()) {\n            stackLogger.logWarning(\"Silently removing dialog from table\");\n        }\n        dialogTable.remove(dialogId);\n    }\n\n    /**\n     * Find a matching client SUBSCRIBE to the incoming notify. NOTIFY requests are matched to\n     * such SUBSCRIBE requests if they contain the same \"Call-ID\", a \"To\" header \"tag\" parameter\n     * which matches the \"From\" header \"tag\" parameter of the SUBSCRIBE, and the same \"Event\"\n     * header field. Rules for comparisons of the \"Event\" headers are described in section 7.2.1.\n     * If a matching NOTIFY request contains a \"Subscription-State\" of \"active\" or \"pending\", it\n     * creates a new subscription and a new dialog (unless they have already been created by a\n     * matching response, as described above).\n     *\n     * @param notifyMessage\n     * @return -- the matching ClientTransaction with semaphore aquired or null if no such client\n     *         transaction can be found.\n     */\n    public SIPClientTransaction findSubscribeTransaction(SIPRequest notifyMessage,\n            ListeningPointImpl listeningPoint) {\n        SIPClientTransaction retval = null;\n        try {\n            Iterator it = clientTransactionTable.values().iterator();\n            if (isLoggingEnabled())\n            \tstackLogger.logDebug(\"ct table size = \" + clientTransactionTable.size());\n            String thisToTag = notifyMessage.getTo().getTag();\n            if (thisToTag == null) {\n                return retval;\n            }\n            Event eventHdr = (Event) notifyMessage.getHeader(EventHeader.NAME);\n            if (eventHdr == null) {\n                if (isLoggingEnabled()) {\n                    stackLogger.logDebug(\"event Header is null -- returning null\");\n                }\n\n                return retval;\n            }\n            while (it.hasNext()) {\n                SIPClientTransaction ct = (SIPClientTransaction) it.next();\n                if (!ct.getMethod().equals(Request.SUBSCRIBE))\n                    continue;\n\n                // if ( sipProvider.getListeningPoint(transport) == null)\n                String fromTag = ct.from.getTag();\n                Event hisEvent = ct.event;\n                // Event header is mandatory but some slopply clients\n                // dont include it.\n                if (hisEvent == null)\n                    continue;\n                if (isLoggingEnabled()) {\n                    stackLogger.logDebug(\"ct.fromTag = \" + fromTag);\n                    stackLogger.logDebug(\"thisToTag = \" + thisToTag);\n                    stackLogger.logDebug(\"hisEvent = \" + hisEvent);\n                    stackLogger.logDebug(\"eventHdr \" + eventHdr);\n                }\n\n                if (  fromTag.equalsIgnoreCase(thisToTag)\n                      && hisEvent != null\n                      && eventHdr.match(hisEvent)\n                      && notifyMessage.getCallId().getCallId().equalsIgnoreCase(\n                                ct.callId.getCallId())) {\n                    if (ct.acquireSem())\n                        retval = ct;\n                    return retval;\n                }\n            }\n\n            return retval;\n        } finally {\n        \tif (isLoggingEnabled())\n                stackLogger.logDebug(\"findSubscribeTransaction : returning \" + retval);\n\n        }\n\n    }\n    \n    /**\n     * Add entry to \"Transaction Pending ACK\" table.\n     * \n     * @param serverTransaction\n     */\n    public void addTransactionPendingAck(SIPServerTransaction serverTransaction) {\n        String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();\n        if ( branchId != null ) {\n            this.terminatedServerTransactionsPendingAck.put(branchId, serverTransaction);\n        }\n        \n    }\n    \n    /**\n     * Get entry in the server transaction pending ACK table corresponding to an ACK.\n     * \n     * @param ackMessage\n     * @return\n     */\n    public SIPServerTransaction findTransactionPendingAck(SIPRequest ackMessage) {\n        return this.terminatedServerTransactionsPendingAck.get(ackMessage.getTopmostVia().getBranch());\n    }\n    \n    /**\n     * Remove entry from \"Transaction Pending ACK\" table.\n     * \n     * @param serverTransaction\n     * @return\n     */\n    \n    public boolean removeTransactionPendingAck(SIPServerTransaction serverTransaction) {\n        String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();\n        if ( branchId != null && this.terminatedServerTransactionsPendingAck.containsKey(branchId) ) {\n            this.terminatedServerTransactionsPendingAck.remove(branchId);\n            return true;\n        } else {\n            return false;\n        }\n    }\n    \n    /**\n     * Check if this entry exists in the \"Transaction Pending ACK\" table.\n     * \n     * @param serverTransaction\n     * @return\n     */\n    public boolean isTransactionPendingAck(SIPServerTransaction serverTransaction) {\n        String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();\n        return this.terminatedServerTransactionsPendingAck.contains(branchId); \n    }\n    \n    /**\n     * Find the transaction corresponding to a given request.\n     *\n     * @param sipMessage request for which to retrieve the transaction.\n     *\n     * @param isServer search the server transaction table if true.\n     *\n     * @return the transaction object corresponding to the request or null if no such mapping\n     *         exists.\n     */\n    public SIPTransaction findTransaction(SIPMessage sipMessage, boolean isServer) {\n        SIPTransaction retval = null;\n        try {\n            if (isServer) {\n                Via via = sipMessage.getTopmostVia();\n                if (via.getBranch() != null) {\n                    String key = sipMessage.getTransactionId();\n\n                    retval = (SIPTransaction) serverTransactionTable.get(key);\n                    // Changed by Deutsche Telekom\n                    if (isLoggingEnabled())\n                        getStackLogger().logDebug(\n                                \"serverTx: looking for key \" + key + \" existing=\"\n                                + serverTransactionTable);\n                    if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {\n                        return retval;\n                    }\n\n                }\n                // Need to scan the table for old style transactions (RFC 2543\n                // style)\n                Iterator<SIPServerTransaction> it = serverTransactionTable.values().iterator();\n                while (it.hasNext()) {\n                    SIPServerTransaction sipServerTransaction = (SIPServerTransaction) it.next();\n                    if (sipServerTransaction.isMessagePartOfTransaction(sipMessage)) {\n                        retval = sipServerTransaction;\n                        return retval;\n                    }\n                }\n\n            } else {\n                Via via = sipMessage.getTopmostVia();\n                if (via.getBranch() != null) {\n                    String key = sipMessage.getTransactionId();\n                    // Changed by Deutsche Telekom\n                    if (isLoggingEnabled())\n                        getStackLogger().logDebug(\"clientTx: looking for key \" + key);\n                    retval = (SIPTransaction) clientTransactionTable.get(key);\n                    if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {\n                        return retval;\n                    }\n\n                }\n                // Need to scan the table for old style transactions (RFC 2543\n                // style). This is terribly slow but we need to do this\n                // for backasswords compatibility.\n                Iterator<SIPClientTransaction> it = clientTransactionTable.values().iterator();\n                while (it.hasNext()) {\n                    SIPClientTransaction clientTransaction = (SIPClientTransaction) it.next();\n                    if (clientTransaction.isMessagePartOfTransaction(sipMessage)) {\n                        retval = clientTransaction;\n                        return retval;\n                    }\n                }\n\n            }\n        } finally {\n        \t// Changed by Deutsche Telekom\n        \tif (isLoggingEnabled()) {\n        \t  getStackLogger().logDebug(\"findTransaction: returning  : \" + retval);\n        \t}\n        }\n        return retval;\n\n    }\n\n    /**\n     * Get the transaction to cancel. Search the server transaction table for a transaction that\n     * matches the given transaction.\n     */\n    public SIPTransaction findCancelTransaction(SIPRequest cancelRequest, boolean isServer) {\n\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"findCancelTransaction request= \\n\" + cancelRequest\n                    + \"\\nfindCancelRequest isServer=\" + isServer);\n        }\n\n        if (isServer) {\n            Iterator<SIPServerTransaction> li = this.serverTransactionTable.values().iterator();\n            while (li.hasNext()) {\n                SIPTransaction transaction = (SIPTransaction) li.next();\n\n                SIPServerTransaction sipServerTransaction = (SIPServerTransaction) transaction;\n                if (sipServerTransaction.doesCancelMatchTransaction(cancelRequest))\n                    return sipServerTransaction;\n            }\n\n        } else {\n            Iterator<SIPClientTransaction> li = this.clientTransactionTable.values().iterator();\n            while (li.hasNext()) {\n                SIPTransaction transaction = (SIPTransaction) li.next();\n\n                SIPClientTransaction sipClientTransaction = (SIPClientTransaction) transaction;\n                if (sipClientTransaction.doesCancelMatchTransaction(cancelRequest))\n                    return sipClientTransaction;\n\n            }\n\n        }\n        if (isLoggingEnabled())\n            stackLogger.logDebug(\"Could not find transaction for cancel request\");\n        return null;\n    }\n\n    /**\n     * Construcor for the stack. Registers the request and response factories for the stack.\n     *\n     * @param messageFactory User-implemented factory for processing messages.\n     */\n    protected SIPTransactionStack(StackMessageFactory messageFactory) {\n        this();\n        this.sipMessageFactory = messageFactory;\n    }\n\n    /**\n     * Finds a pending server transaction. Since each request may be handled either statefully or\n     * statelessly, we keep a map of pending transactions so that a duplicate transaction is not\n     * created if a second request is recieved while the first one is being processed.\n     *\n     * @param requestReceived\n     * @return -- the pending transaction or null if no such transaction exists.\n     */\n    public SIPServerTransaction findPendingTransaction(SIPRequest requestReceived) {\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"looking for pending tx for :\"\n                    + requestReceived.getTransactionId());\n        }\n        return (SIPServerTransaction) pendingTransactions.get(requestReceived.getTransactionId());\n\n    }\n\n    /**\n     * See if there is a pending transaction with the same Merge ID as the Merge ID obtained from\n     * the SIP Request. The Merge table is for handling the following condition: If the request\n     * has no tag in the To header field, the UAS core MUST check the request against ongoing\n     * transactions. If the From tag, Call-ID, and CSeq exactly match those associated with an\n     * ongoing transaction, but the request does not match that transaction (based on the matching\n     * rules in Section 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and\n     * pass it to the server transaction.\n     */\n    public SIPServerTransaction findMergedTransaction(SIPRequest sipRequest) {\n        if (! sipRequest.getMethod().equals(Request.INVITE)) {\n            /*\n             * Dont need to worry about request merging for Non-INVITE transactions.\n             */\n            return null;\n        }\n        String mergeId = sipRequest.getMergeId();\n        SIPServerTransaction mergedTransaction = (SIPServerTransaction) this.mergeTable.get(mergeId);\n        if (mergeId == null ) {\n            return null;\n        } else if (mergedTransaction != null && !mergedTransaction.isMessagePartOfTransaction(sipRequest) ) {\n            return mergedTransaction;\n        } else {\n            /*\n             * Check the server transactions that have resulted in dialogs.\n             */\n           for (Dialog dialog: this.dialogTable.values() ) {\n               SIPDialog sipDialog = (SIPDialog) dialog ;\n               if (sipDialog.getFirstTransaction()  != null && \n                   sipDialog.getFirstTransaction() instanceof ServerTransaction) {\n                   SIPServerTransaction serverTransaction = ((SIPServerTransaction) sipDialog.getFirstTransaction());\n                   SIPRequest transactionRequest = ((SIPServerTransaction) sipDialog.getFirstTransaction()).getOriginalRequest();\n                   if ( (! serverTransaction.isMessagePartOfTransaction(sipRequest))\n                           && sipRequest.getMergeId().equals(transactionRequest.getMergeId())) {\n                           return (SIPServerTransaction) sipDialog.getFirstTransaction();  \n                   }\n               }\n           } \n           return null;\n        }\n    }\n\n    /**\n     * Remove a pending Server transaction from the stack. This is called after the user code has\n     * completed execution in the listener.\n     *\n     * @param tr -- pending transaction to remove.\n     */\n    public void removePendingTransaction(SIPServerTransaction tr) {\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"removePendingTx: \" + tr.getTransactionId());\n        }\n        this.pendingTransactions.remove(tr.getTransactionId());\n\n    }\n\n    /**\n     * Remove a transaction from the merge table.\n     *\n     * @param tr -- the server transaction to remove from the merge table.\n     *\n     */\n    public void removeFromMergeTable(SIPServerTransaction tr) {\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"Removing tx from merge table \");\n        }\n        String key = ((SIPRequest) tr.getRequest()).getMergeId();\n        if (key != null) {\n            this.mergeTable.remove(key);\n        }\n    }\n\n    /**\n     * Put this into the merge request table.\n     *\n     * @param sipTransaction -- transaction to put into the merge table.\n     *\n     */\n    public void putInMergeTable(SIPServerTransaction sipTransaction, SIPRequest sipRequest) {\n        String mergeKey = sipRequest.getMergeId();\n        if (mergeKey != null) {\n            this.mergeTable.put(mergeKey, sipTransaction);\n        }\n    }\n\n    /**\n     * Map a Server transaction (possibly sending out a 100 if the server tx is an INVITE). This\n     * actually places it in the hash table and makes it known to the stack.\n     *\n     * @param transaction -- the server transaction to map.\n     */\n    public void mapTransaction(SIPServerTransaction transaction) {\n        if (transaction.isMapped)\n            return;\n        addTransactionHash(transaction);\n        // transaction.startTransactionTimer();\n        transaction.isMapped = true;\n    }\n\n    /**\n     * Handles a new SIP request. It finds a server transaction to handle this message. If none\n     * exists, it creates a new transaction.\n     *\n     * @param requestReceived Request to handle.\n     * @param requestMessageChannel Channel that received message.\n     *\n     * @return A server transaction.\n     */\n    public ServerRequestInterface newSIPServerRequest(SIPRequest requestReceived,\n            MessageChannel requestMessageChannel) {\n        // Iterator through all server transactions\n        Iterator<SIPServerTransaction> transactionIterator;\n        // Next transaction in the set\n        SIPServerTransaction nextTransaction;\n        // Transaction to handle this request\n        SIPServerTransaction currentTransaction;\n\n        String key = requestReceived.getTransactionId();\n\n        requestReceived.setMessageChannel(requestMessageChannel);\n\n        currentTransaction = (SIPServerTransaction) serverTransactionTable.get(key);\n\n        // Got to do this for bacasswards compatibility.\n        if (currentTransaction == null\n                || !currentTransaction.isMessagePartOfTransaction(requestReceived)) {\n\n            // Loop through all server transactions\n            transactionIterator = serverTransactionTable.values().iterator();\n            currentTransaction = null;\n            if (!key.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {\n                while (transactionIterator.hasNext() && currentTransaction == null) {\n\n                    nextTransaction = (SIPServerTransaction) transactionIterator.next();\n\n                    // If this transaction should handle this request,\n                    if (nextTransaction.isMessagePartOfTransaction(requestReceived)) {\n                        // Mark this transaction as the one\n                        // to handle this message\n                        currentTransaction = nextTransaction;\n                    }\n                }\n            }\n\n            // If no transaction exists to handle this message\n            if (currentTransaction == null) {\n                currentTransaction = findPendingTransaction(requestReceived);\n                if (currentTransaction != null) {\n                    // Associate the tx with the received request.\n                    requestReceived.setTransaction(currentTransaction);\n                    if (currentTransaction != null && currentTransaction.acquireSem())\n                        return currentTransaction;\n                    else\n                        return null;\n\n                }\n                // Creating a new server tx. May fail under heavy load.\n                currentTransaction = createServerTransaction(requestMessageChannel);\n                if (currentTransaction != null) {\n                    // currentTransaction.setPassToListener();\n                    currentTransaction.setOriginalRequest(requestReceived);\n                    // Associate the tx with the received request.\n                    requestReceived.setTransaction(currentTransaction);\n                }\n\n            }\n\n        }\n\n        // Set ths transaction's encapsulated request\n        // interface from the superclass\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"newSIPServerRequest( \" + requestReceived.getMethod() + \":\"\n                    + requestReceived.getTopmostVia().getBranch() + \"):\" + currentTransaction);\n        }\n\n        if (currentTransaction != null)\n            currentTransaction.setRequestInterface(sipMessageFactory.newSIPServerRequest(\n                    requestReceived, currentTransaction));\n\n        if (currentTransaction != null && currentTransaction.acquireSem()) {\n            return currentTransaction;\n        } else if (currentTransaction != null) {\n            try {\n                /*\n                 * Already processing a message for this transaction.\n                 * SEND a trying ( message already being processed ).\n                 */\n                if (currentTransaction.isMessagePartOfTransaction(requestReceived) &&\n                    currentTransaction.getMethod().equals(requestReceived.getMethod())) {\n                    SIPResponse trying = requestReceived.createResponse(Response.TRYING);\n                    trying.removeContent();\n                    currentTransaction.getMessageChannel().sendMessage(trying);\n                }\n            } catch (Exception ex) {\n            \tif (isLoggingEnabled())\n            \t\tstackLogger.logError(\"Exception occured sending TRYING\");\n            }\n            return null;\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Handles a new SIP response. It finds a client transaction to handle this message. If none\n     * exists, it sends the message directly to the superclass.\n     *\n     * @param responseReceived Response to handle.\n     * @param responseMessageChannel Channel that received message.\n     *\n     * @return A client transaction.\n     */\n    public ServerResponseInterface newSIPServerResponse(SIPResponse responseReceived,\n            MessageChannel responseMessageChannel) {\n\n        // Iterator through all client transactions\n        Iterator<SIPClientTransaction> transactionIterator;\n        // Next transaction in the set\n        SIPClientTransaction nextTransaction;\n        // Transaction to handle this request\n        SIPClientTransaction currentTransaction;\n\n        String key = responseReceived.getTransactionId();\n\n        // Note that for RFC 3261 compliant operation, this lookup will\n        // return a tx if one exists and hence no need to search through\n        // the table.\n        currentTransaction = (SIPClientTransaction) clientTransactionTable.get(key);\n\n        if (currentTransaction == null\n                || (!currentTransaction.isMessagePartOfTransaction(responseReceived) && !key\n                        .startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE))) {\n            // Loop through all client transactions\n\n            transactionIterator = clientTransactionTable.values().iterator();\n            currentTransaction = null;\n            while (transactionIterator.hasNext() && currentTransaction == null) {\n\n                nextTransaction = (SIPClientTransaction) transactionIterator.next();\n\n                // If this transaction should handle this request,\n                if (nextTransaction.isMessagePartOfTransaction(responseReceived)) {\n\n                    // Mark this transaction as the one to\n                    // handle this message\n                    currentTransaction = nextTransaction;\n\n                }\n\n            }\n\n            // If no transaction exists to handle this message,\n            if (currentTransaction == null) {\n                // JvB: Need to log before passing the response to the client\n                // app, it\n                // gets modified!\n                if (isLoggingEnabled(StackLogger.TRACE_INFO)) {\n                    responseMessageChannel.logResponse(responseReceived, System\n                            .currentTimeMillis(), \"before processing\");\n                }\n\n                // Pass the message directly to the TU\n                return sipMessageFactory.newSIPServerResponse(responseReceived,\n                        responseMessageChannel);\n\n            }\n        }\n\n        // Aquire the sem -- previous request may still be processing.\n        boolean acquired = currentTransaction.acquireSem();\n        // Set ths transaction's encapsulated response interface\n        // from the superclass\n        if (isLoggingEnabled(StackLogger.TRACE_INFO)) {\n            currentTransaction.logResponse(responseReceived, System.currentTimeMillis(),\n                    \"before processing\");\n        }\n\n        if (acquired) {\n            ServerResponseInterface sri = sipMessageFactory.newSIPServerResponse(\n                    responseReceived, currentTransaction);\n            if (sri != null) {\n                currentTransaction.setResponseInterface(sri);\n            } else {\n                if (isLoggingEnabled()) {\n                    stackLogger.logDebug(\"returning null - serverResponseInterface is null!\");\n                }\n                currentTransaction.releaseSem();\n                return null;\n            }\n        } else {\n        \tif (isLoggingEnabled())\n        \t\tstackLogger.logDebug(\"Could not aquire semaphore !!\");\n        }\n\n        if (acquired)\n            return currentTransaction;\n        else\n            return null;\n\n    }\n\n    /**\n     * Creates a client transaction to handle a new request. Gets the real message channel from\n     * the superclass, and then creates a new client transaction wrapped around this channel.\n     *\n     * @param nextHop Hop to create a channel to contact.\n     */\n    public MessageChannel createMessageChannel(SIPRequest request, MessageProcessor mp,\n            Hop nextHop) throws IOException {\n        // New client transaction to return\n        SIPTransaction returnChannel;\n\n        // Create a new client transaction around the\n        // superclass' message channel\n        // Create the host/port of the target hop\n        Host targetHost = new Host();\n        targetHost.setHostname(nextHop.getHost());\n        HostPort targetHostPort = new HostPort();\n        targetHostPort.setHost(targetHost);\n        targetHostPort.setPort(nextHop.getPort());\n        MessageChannel mc = mp.createMessageChannel(targetHostPort);\n\n        // Superclass will return null if no message processor\n        // available for the transport.\n        if (mc == null)\n            return null;\n\n        returnChannel = createClientTransaction(request, mc);\n\n        ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort());\n        ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost());\n        addTransactionHash(returnChannel);\n        // clientTransactionTable.put(returnChannel.getTransactionId(),\n        // returnChannel);\n        // Add the transaction timer for the state machine.\n        // returnChannel.startTransactionTimer();\n        return returnChannel;\n\n    }\n\n    /**\n     * Creates a client transaction that encapsulates a MessageChannel. Useful for implementations\n     * that want to subclass the standard\n     *\n     * @param encapsulatedMessageChannel Message channel of the transport layer.\n     */\n    public SIPClientTransaction createClientTransaction(SIPRequest sipRequest,\n            MessageChannel encapsulatedMessageChannel) {\n        SIPClientTransaction ct = new SIPClientTransaction(this, encapsulatedMessageChannel);\n        ct.setOriginalRequest(sipRequest);\n        return ct;\n    }\n\n    /**\n     * Creates a server transaction that encapsulates a MessageChannel. Useful for implementations\n     * that want to subclass the standard\n     *\n     * @param encapsulatedMessageChannel Message channel of the transport layer.\n     */\n    public SIPServerTransaction createServerTransaction(MessageChannel encapsulatedMessageChannel) {\n    \t// Issue 256 : be consistent with createClientTransaction, if unlimitedServerTransactionTableSize is true,\n    \t// a new Server Transaction is created no matter what\n        if (unlimitedServerTransactionTableSize) {                \n            return new SIPServerTransaction(this, encapsulatedMessageChannel);\n        } else {\n            float threshold = ((float) (serverTransactionTable.size() - serverTransactionTableLowaterMark))\n                    / ((float) (serverTransactionTableHighwaterMark - serverTransactionTableLowaterMark));\n            boolean decision = Math.random() > 1.0 - threshold;\n            if (decision) {\n                return null;\n            } else {\n                return new SIPServerTransaction(this, encapsulatedMessageChannel);\n            }\n\n        }\n\n    }\n\n    /**\n     * Get the size of the client transaction table.\n     *\n     * @return -- size of the ct table.\n     */\n    public int getClientTransactionTableSize() {\n        return this.clientTransactionTable.size();\n    }\n    \n    /**\n     * Get the size of the server transaction table.\n     *\n     * @return -- size of the server table.\n     */\n    public int getServerTransactionTableSize() {\n        return this.serverTransactionTable.size();\n    }\n\n    /**\n     * Add a new client transaction to the set of existing transactions. Add it to the top of the\n     * list so an incoming response has less work to do in order to find the transaction.\n     *\n     * @param clientTransaction -- client transaction to add to the set.\n     */\n    public void addTransaction(SIPClientTransaction clientTransaction) {\n        if (isLoggingEnabled())\n            stackLogger.logDebug(\"added transaction \" + clientTransaction);\n        addTransactionHash(clientTransaction);\n       \n    }\n\n    /**\n     * Remove transaction. This actually gets the tx out of the search structures which the stack\n     * keeps around. When the tx\n     */\n    public void removeTransaction(SIPTransaction sipTransaction) {\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"Removing Transaction = \" + sipTransaction.getTransactionId()\n                    + \" transaction = \" + sipTransaction);\n        }\n        if (sipTransaction instanceof SIPServerTransaction) {\n            if (isLoggingEnabled())\n                stackLogger.logStackTrace();\n            String key = sipTransaction.getTransactionId();\n            Object removed = serverTransactionTable.remove(key);\n            String method = sipTransaction.getMethod();\n            this.removePendingTransaction((SIPServerTransaction) sipTransaction);\n            this.removeTransactionPendingAck((SIPServerTransaction) sipTransaction);\n            if (method.equalsIgnoreCase(Request.INVITE)) {\n                this.removeFromMergeTable((SIPServerTransaction) sipTransaction);\n            }\n            // Send a notification to the listener.\n            SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider();\n            if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) {\n                TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider,\n                        (ServerTransaction) sipTransaction);\n\n                sipProvider.handleEvent(event, sipTransaction);\n\n            }\n        } else {\n\n            String key = sipTransaction.getTransactionId();\n            Object removed = clientTransactionTable.remove(key);\n\n            if (isLoggingEnabled()) {\n                stackLogger.logDebug(\"REMOVED client tx \" + removed + \" KEY = \" + key);\n                if ( removed != null ) {\n                   SIPClientTransaction clientTx = (SIPClientTransaction)removed;\n                   if ( clientTx.getMethod().equals(Request.INVITE) && this.maxForkTime != 0 ) {\n                       RemoveForkedTransactionTimerTask ttask = new RemoveForkedTransactionTimerTask(clientTx);\n                       this.timer.schedule(ttask, this.maxForkTime * 1000);\n                   }\n                }\n            }\n\n            // Send a notification to the listener.\n            if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) {\n                SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider();\n                TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider,\n                        (ClientTransaction) sipTransaction);\n\n                sipProvider.handleEvent(event, sipTransaction);\n            }\n\n        }\n    }\n\n    /**\n     * Add a new server transaction to the set of existing transactions. Add it to the top of the\n     * list so an incoming ack has less work to do in order to find the transaction.\n     *\n     * @param serverTransaction -- server transaction to add to the set.\n     */\n    public void addTransaction(SIPServerTransaction serverTransaction) throws IOException {\n        if (isLoggingEnabled())\n            stackLogger.logDebug(\"added transaction \" + serverTransaction);\n        serverTransaction.map();\n\n        addTransactionHash(serverTransaction);\n      \n    }\n\n    /**\n     * Hash table for quick lookup of transactions. Here we wait for room if needed.\n     */\n    private void addTransactionHash(SIPTransaction sipTransaction) {\n        SIPRequest sipRequest = sipTransaction.getOriginalRequest();\n        if (sipTransaction instanceof SIPClientTransaction) {\n            if (!this.unlimitedClientTransactionTableSize) {\n                if (this.activeClientTransactionCount.get() > clientTransactionTableHiwaterMark) {\n                    try {\n                        synchronized (this.clientTransactionTable) {\n                            this.clientTransactionTable.wait();\n                            this.activeClientTransactionCount.incrementAndGet();\n                        }\n\n                    } catch (Exception ex) {\n                        if (isLoggingEnabled()) {\n                            stackLogger.logError(\"Exception occured while waiting for room\", ex);\n                        }\n\n                    }\n                }\n            } else {\n                this.activeClientTransactionCount.incrementAndGet();\n            }\n            String key = sipRequest.getTransactionId();\n            clientTransactionTable.put(key, (SIPClientTransaction) sipTransaction);\n            \n            if (isLoggingEnabled()) {\n                stackLogger.logDebug(\" putTransactionHash : \" + \" key = \" + key);\n            }\n        } else {\n            String key = sipRequest.getTransactionId();\n\n            if (isLoggingEnabled()) {\n                stackLogger.logDebug(\" putTransactionHash : \" + \" key = \" + key);\n            }\n            serverTransactionTable.put(key, (SIPServerTransaction) sipTransaction);\n\n        }\n\n    }\n\n    /**\n     * This method is called when a client tx transitions to the Completed or Terminated state.\n     *\n     */\n    protected void decrementActiveClientTransactionCount() {\n\n        if (this.activeClientTransactionCount.decrementAndGet() <= this.clientTransactionTableLowaterMark\n                && !this.unlimitedClientTransactionTableSize) {\n            synchronized (this.clientTransactionTable) {\n\n                clientTransactionTable.notify();\n\n            }\n        }\n    }\n\n    /**\n     * Remove the transaction from transaction hash.\n     */\n    protected void removeTransactionHash(SIPTransaction sipTransaction) {\n        SIPRequest sipRequest = sipTransaction.getOriginalRequest();\n        if (sipRequest == null)\n            return;\n        if (sipTransaction instanceof SIPClientTransaction) {\n            String key = sipTransaction.getTransactionId();\n            if (isLoggingEnabled()) {\n                stackLogger.logStackTrace();\n                stackLogger.logDebug(\"removing client Tx : \" + key);\n            }\n            clientTransactionTable.remove(key);\n\n        } else if (sipTransaction instanceof SIPServerTransaction) {\n            String key = sipTransaction.getTransactionId();\n            serverTransactionTable.remove(key);\n            if (isLoggingEnabled()) {\n                stackLogger.logDebug(\"removing server Tx : \" + key);\n            }\n        }\n    }\n\n    /**\n     * Invoked when an error has ocurred with a transaction.\n     *\n     * @param transactionErrorEvent Error event.\n     */\n    public synchronized void transactionErrorEvent(SIPTransactionErrorEvent transactionErrorEvent) {\n        SIPTransaction transaction = (SIPTransaction) transactionErrorEvent.getSource();\n\n        if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {\n            // Kill scanning of this transaction.\n            transaction.setState(SIPTransaction.TERMINATED_STATE);\n            if (transaction instanceof SIPServerTransaction) {\n                // let the reaper get him\n                ((SIPServerTransaction) transaction).collectionTime = 0;\n            }\n            transaction.disableTimeoutTimer();\n            transaction.disableRetransmissionTimer();\n            // Send a IO Exception to the Listener.\n        }\n    }\n    \n    /*\n     * (non-Javadoc)\n     * @see gov2.nist.javax2.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov2.nist.javax2.sip.stack.SIPDialogErrorEvent)\n     */\n    public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) {\n        SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource();\n        SipListener sipListener = ((SipStackImpl)this).getSipListener();\n        // if the app is not implementing the SipListenerExt interface we delete the dialog to avoid leaks\n        if(sipDialog != null && !(sipListener instanceof SipListenerExt)) {\n        \tsipDialog.delete();\n        }\n    }\n\n    /**\n     * Stop stack. Clear all the timer stuff. Make the stack close all accept connections and\n     * return. This is useful if you want to start/stop the stack several times from your\n     * application. Caution : use of this function could cause peculiar bugs as messages are\n     * prcessed asynchronously by the stack.\n     */\n    public void stopStack() {\n        // Prevent NPE on two concurrent stops\n        if (this.timer != null)\n            this.timer.cancel();\n\n        // JvB: set it to null, SIPDialog tries to schedule things after stop\n        timer = null;\n        this.pendingTransactions.clear();\n        this.toExit = true;\n        synchronized (this) {\n            this.notifyAll();\n        }\n        synchronized (this.clientTransactionTable) {\n            clientTransactionTable.notifyAll();\n        }\n\n        synchronized (this.messageProcessors) {\n            // Threads must periodically check this flag.\n            MessageProcessor[] processorList;\n            processorList = getMessageProcessors();\n            for (int processorIndex = 0; processorIndex < processorList.length; processorIndex++) {\n                removeMessageProcessor(processorList[processorIndex]);\n            }\n            this.ioHandler.closeAll();\n            // Let the processing complete.\n\n        }\n        try {\n\n            Thread.sleep(1000);\n\n        } catch (InterruptedException ex) {\n        }\n        this.clientTransactionTable.clear();\n        this.serverTransactionTable.clear();\n\n        this.dialogTable.clear();\n        this.serverLogger.closeLogFile();\n\n    }\n\n    /**\n     * Put a transaction in the pending transaction list. This is to avoid a race condition when a\n     * duplicate may arrive when the application is deciding whether to create a transaction or\n     * not.\n     */\n    public void putPendingTransaction(SIPServerTransaction tr) {\n        if (isLoggingEnabled())\n            stackLogger.logDebug(\"putPendingTransaction: \" + tr);\n\n        this.pendingTransactions.put(tr.getTransactionId(), tr);\n\n    }\n\n    /**\n     * Return the network layer (i.e. the interface for socket creation or the socket factory for\n     * the stack).\n     *\n     * @return -- the registered Network Layer.\n     */\n    public NetworkLayer getNetworkLayer() {\n        if (networkLayer == null) {\n            return DefaultNetworkLayer.SINGLETON;\n        } else {\n            return networkLayer;\n        }\n    }\n\n    /**\n     * Return true if logging is enabled for this stack.\n     *\n     * @return true if logging is enabled for this stack instance.\n     */\n    public boolean isLoggingEnabled() {\n        return this.stackLogger == null ? false : this.stackLogger.isLoggingEnabled();\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Return true if logging is enabled for this stack for the according logLevel.\n     *\n     * @return true if logging is enabled for this stack instance for the according logLevel.\n     */\n    public boolean isLoggingEnabled(int logLevel) {\n        return this.stackLogger == null ? false : this.stackLogger.isLoggingEnabled(logLevel);\n    }\n\n    /**\n     * Get the logger.\n     *\n     * @return --the logger for the sip stack. Each stack has its own logger instance.\n     */\n    public StackLogger getStackLogger() {\n        return this.stackLogger;\n    }\n\n    /**\n     * Server log is the place where we log messages for the signaling trace viewer.\n     *\n     * @return -- the log file where messages are logged for viewing by the trace viewer.\n     */\n    public ServerLogger getServerLogger() {\n        return this.serverLogger;\n    }\n\n    /**\n     * Maximum size of a single TCP message. Limiting the size of a single TCP message prevents\n     * flooding attacks.\n     *\n     * @return the size of a single TCP message.\n     */\n    public int getMaxMessageSize() {\n        return this.maxMessageSize;\n    }\n\n    /**\n     * Set the flag that instructs the stack to only start a single thread for sequentially\n     * processing incoming udp messages (thus serializing the processing). Same as setting thread\n     * pool size to 1.\n     */\n    public void setSingleThreaded() {\n        this.threadPoolSize = 1;\n    }\n\n    /**\n     * Set the thread pool size for processing incoming UDP messages. Limit the total number of\n     * threads for processing udp messages.\n     *\n     * @param size -- the thread pool size.\n     *\n     */\n    public void setThreadPoolSize(int size) {\n        this.threadPoolSize = size;\n    }\n\n    /**\n     * Set the max # of simultaneously handled TCP connections.\n     *\n     * @param nconnections -- the number of connections to handle.\n     */\n    public void setMaxConnections(int nconnections) {\n        this.maxConnections = nconnections;\n    }\n\n    /**\n     * Get the default route string.\n     *\n     * @param sipRequest is the request for which we want to compute the next hop.\n     * @throws SipException\n     */\n    public Hop getNextHop(SIPRequest sipRequest) throws SipException {\n        if (this.useRouterForAll) {\n            // Use custom router to route all messages.\n            if (router != null)\n                return router.getNextHop(sipRequest);\n            else\n                return null;\n        } else {\n            // Also non-SIP request containing Route headers goes to the default\n            // router\n            if (sipRequest.getRequestURI().isSipURI() || sipRequest.getRouteHeaders() != null) {\n                return defaultRouter.getNextHop(sipRequest);\n            } else if (router != null) {\n                return router.getNextHop(sipRequest);\n            } else\n                return null;\n        }\n    }\n\n    /**\n     * Set the descriptive name of the stack.\n     *\n     * @param stackName -- descriptive name of the stack.\n     */\n    public void setStackName(String stackName) {\n        this.stackName = stackName;\n    }\n\n\n\n    /**\n     * Set my address.\n     *\n     * @param stackAddress -- A string containing the stack address.\n     */\n    protected void setHostAddress(String stackAddress) throws UnknownHostException {\n        if (stackAddress.indexOf(':') != stackAddress.lastIndexOf(':')\n                && stackAddress.trim().charAt(0) != '[')\n            this.stackAddress = '[' + stackAddress + ']';\n        else\n            this.stackAddress = stackAddress;\n        this.stackInetAddress = InetAddress.getByName(stackAddress);\n        \n        // Changed by Deutsche Telekom\n        try{\n            this.mtuSize = NetworkInterface.getByInetAddress(stackInetAddress).getMTU();\n            if (stackLogger.isLoggingEnabled()) {\n                stackLogger.logInfo(\"MTU size: \"+ this.mtuSize);\n            } \n        } catch (Exception e) {\n            this.mtuSize = DEFAULT_MTU_SIZE;\n            if (stackLogger.isLoggingEnabled()) {\n                stackLogger.logError(\"Unable to determine MTU size: \", e);\n            }            \n        }\n        if (stackLogger.isLoggingEnabled()) {\n            stackLogger.logDebug(\"Current MTU size: \" + this.mtuSize);\n        }            \n    }\n\n    /**\n     * Get my address.\n     *\n     * @return hostAddress - my host address or null if no host address is defined.\n     * @deprecated\n     */\n    public String getHostAddress() {\n\n        // JvB: for 1.2 this may return null...\n        return this.stackAddress;\n    }\n\n    // Changed by Deutsche Telekom\n    /**\n     * Return the MTU size\n     *\n     * @return MTU size\n     */\n    public int getMtuSize() {\n        return mtuSize;\n    }\n\n    /**\n     * Set the router algorithm. This is meant for routing messages out of dialog or for non-sip\n     * uri's.\n     *\n     * @param router A class that implements the Router interface.\n     */\n    protected void setRouter(Router router) {\n        this.router = router;\n    }\n\n    /**\n     * Get the router algorithm.\n     *\n     * @return Router router\n     */\n    public Router getRouter(SIPRequest request) {\n        if (request.getRequestLine() == null) {\n            return this.defaultRouter;\n        } else if (this.useRouterForAll) {\n            return this.router;\n        } else {\n            if (request.getRequestURI().getScheme().equals(\"sip\")\n                    || request.getRequestURI().getScheme().equals(\"sips\")) {\n                return this.defaultRouter;\n            } else {\n                if (this.router != null)\n                    return this.router;\n                else\n                    return defaultRouter;\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see javax2.sip.SipStack#getRouter()\n     */\n    public Router getRouter() {\n        return this.router;\n    }\n\n    /**\n     * return the status of the toExit flag.\n     *\n     * @return true if the stack object is alive and false otherwise.\n     */\n    public boolean isAlive() {\n        return !toExit;\n    }\n\n    /**\n     * Adds a new MessageProcessor to the list of running processors for this SIPStack and starts\n     * it. You can use this method for dynamic stack configuration.\n     */\n    protected void addMessageProcessor(MessageProcessor newMessageProcessor) throws IOException {\n        synchronized (messageProcessors) {\n            // Suggested changes by Jeyashankher, jai@lucent.com\n            // newMessageProcessor.start() can fail\n            // because a local port is not available\n            // This throws an IOException.\n            // We should not add the message processor to the\n            // local list of processors unless the start()\n            // call is successful.\n            // newMessageProcessor.start();\n            messageProcessors.add(newMessageProcessor);\n\n        }\n    }\n\n    /**\n     * Removes a MessageProcessor from this SIPStack.\n     *\n     * @param oldMessageProcessor\n     */\n    protected void removeMessageProcessor(MessageProcessor oldMessageProcessor) {\n        synchronized (messageProcessors) {\n            if (messageProcessors.remove(oldMessageProcessor)) {\n                oldMessageProcessor.stop();\n            }\n        }\n    }\n\n    /**\n     * Gets an array of running MessageProcessors on this SIPStack. Acknowledgement: Jeff Keyser\n     * suggested that applications should have access to the running message processors and\n     * contributed this code.\n     *\n     * @return an array of running message processors.\n     */\n    protected MessageProcessor[] getMessageProcessors() {\n        synchronized (messageProcessors) {\n            return (MessageProcessor[]) messageProcessors.toArray(new MessageProcessor[0]);\n        }\n    }\n\n    /**\n     * Creates the equivalent of a JAIN listening point and attaches to the stack.\n     *\n     * @param ipAddress -- ip address for the listening point.\n     * @param port -- port for the listening point.\n     * @param transport -- transport for the listening point.\n     */\n    protected MessageProcessor createMessageProcessor(InetAddress ipAddress, int port,\n            String transport) throws java.io.IOException {\n        if (transport.equalsIgnoreCase(\"udp\")) {\n            UDPMessageProcessor udpMessageProcessor = new UDPMessageProcessor(ipAddress, this,\n                    port);\n            this.addMessageProcessor(udpMessageProcessor);\n            this.udpFlag = true;\n            return udpMessageProcessor;\n        } else if (transport.equalsIgnoreCase(\"tcp\")) {\n            TCPMessageProcessor tcpMessageProcessor = new TCPMessageProcessor(ipAddress, this,\n                    port);\n            this.addMessageProcessor(tcpMessageProcessor);\n            // this.tcpFlag = true;\n            return tcpMessageProcessor;\n        } else if (transport.equalsIgnoreCase(\"tls\")) {\n            TLSMessageProcessor tlsMessageProcessor = new TLSMessageProcessor(ipAddress, this,\n                    port);\n            this.addMessageProcessor(tlsMessageProcessor);\n            // this.tlsFlag = true;\n            return tlsMessageProcessor;\n        } else if (transport.equalsIgnoreCase(\"sctp\")) {\n        \t\n        \t// Need Java 7 for this, so these classes are packaged in a separate jar\n        \t// Try to load it indirectly, if fails report an error\n        \ttry {\n\t\t\t\tClass<?> mpc = ClassLoader.getSystemClassLoader().loadClass( \"gov2.nist.javax2.sip.stack.sctp.SCTPMessageProcessor\" );\n\t\t\t\tMessageProcessor mp = (MessageProcessor) mpc.newInstance();\n\t\t\t\tmp.initialize( ipAddress, port, this );\n\t\t\t\tthis.addMessageProcessor(mp);\n\t\t\t\treturn mp;\n\t\t\t} catch (ClassNotFoundException e) {\n\t\t\t\tthrow new IllegalArgumentException(\"SCTP not supported (needs Java 7 and SCTP jar in classpath)\");\n\t\t\t} catch ( InstantiationException ie ) {\n\t\t\t\tthrow new IllegalArgumentException(\"Error initializing SCTP\", ie);\t\t\t\t\n\t\t\t} catch ( IllegalAccessException ie ) {\n\t\t\t\tthrow new IllegalArgumentException(\"Error initializing SCTP\", ie);\t\t\t\t\n\t\t\t}\n        } else {\n            throw new IllegalArgumentException(\"bad transport\");\n        }\n\n    }\n\n    /**\n     * Set the message factory.\n     *\n     * @param messageFactory -- messageFactory to set.\n     */\n    protected void setMessageFactory(StackMessageFactory messageFactory) {\n        this.sipMessageFactory = messageFactory;\n    }\n\n    /**\n     * Creates a new MessageChannel for a given Hop.\n     *\n     * @param sourceIpAddress - Ip address of the source of this message.\n     *\n     * @param sourcePort - source port of the message channel to be created.\n     *\n     * @param nextHop Hop to create a MessageChannel to.\n     *\n     * @return A MessageChannel to the specified Hop, or null if no MessageProcessors support\n     *         contacting that Hop.\n     *\n     * @throws UnknownHostException If the host in the Hop doesn't exist.\n     */\n    public MessageChannel createRawMessageChannel(String sourceIpAddress, int sourcePort,\n            Hop nextHop) throws UnknownHostException {\n        Host targetHost;\n        HostPort targetHostPort;\n        Iterator processorIterator;\n        MessageProcessor nextProcessor;\n        MessageChannel newChannel;\n\n        // Create the host/port of the target hop\n        targetHost = new Host();\n        targetHost.setHostname(nextHop.getHost());\n        targetHostPort = new HostPort();\n        targetHostPort.setHost(targetHost);\n        targetHostPort.setPort(nextHop.getPort());\n\n        // Search each processor for the correct transport\n        newChannel = null;\n        processorIterator = messageProcessors.iterator();\n        while (processorIterator.hasNext() && newChannel == null) {\n            nextProcessor = (MessageProcessor) processorIterator.next();\n            // If a processor that supports the correct\n            // transport is found,\n            if (nextHop.getTransport().equalsIgnoreCase(nextProcessor.getTransport())\n                    && sourceIpAddress.equals(nextProcessor.getIpAddress().getHostAddress())\n                    && sourcePort == nextProcessor.getPort()) {\n                try {\n                    // Create a channel to the target\n                    // host/port\n                    newChannel = nextProcessor.createMessageChannel(targetHostPort);\n                } catch (UnknownHostException ex) {\n                    if (isLoggingEnabled())\n                        stackLogger.logException(ex);\n                    throw ex;\n                } catch (IOException e) {\n                    if (isLoggingEnabled())\n                        stackLogger.logException(e);\n                    // Ignore channel creation error -\n                    // try next processor\n                }\n            }\n        }\n        // Return the newly-created channel\n        return newChannel;\n    }\n\n    /**\n     * Return true if a given event can result in a forked subscription. The stack is configured\n     * with a set of event names that can result in forked subscriptions.\n     *\n     * @param ename -- event name to check.\n     *\n     */\n    public boolean isEventForked(String ename) {\n        if (isLoggingEnabled()) {\n            stackLogger.logDebug(\"isEventForked: \" + ename + \" returning \"\n                    + this.forkedEvents.contains(ename));\n        }\n        return this.forkedEvents.contains(ename);\n    }\n\n    /**\n     * get the address resolver interface.\n     *\n     * @return -- the registered address resolver.\n     */\n    public AddressResolver getAddressResolver() {\n        return this.addressResolver;\n    }\n\n    /**\n     * Set the address resolution interface\n     *\n     * @param addressResolver -- the address resolver to set.\n     */\n    public void setAddressResolver(AddressResolver addressResolver) {\n        this.addressResolver = addressResolver;\n    }\n\n    /**\n     * Set the logger factory.\n     *\n     * @param logRecordFactory -- the log record factory to set.\n     */\n    public void setLogRecordFactory(LogRecordFactory logRecordFactory) {\n        this.logRecordFactory = logRecordFactory;\n    }\n\n    /**\n     * get the thread auditor object\n     *\n     * @return -- the thread auditor of the stack\n     */\n    public ThreadAuditor getThreadAuditor() {\n        return this.threadAuditor;\n    }\n\n    // /\n    // / Stack Audit methods\n    // /\n\n    /**\n     * Audits the SIP Stack for leaks\n     *\n     * @return Audit report, null if no leaks were found\n     */\n    public String auditStack(Set activeCallIDs, long leakedDialogTimer,\n            long leakedTransactionTimer) {\n        String auditReport = null;\n        String leakedDialogs = auditDialogs(activeCallIDs, leakedDialogTimer);\n        String leakedServerTransactions = auditTransactions(serverTransactionTable,\n                leakedTransactionTimer);\n        String leakedClientTransactions = auditTransactions(clientTransactionTable,\n                leakedTransactionTimer);\n        if (leakedDialogs != null || leakedServerTransactions != null\n                || leakedClientTransactions != null) {\n            auditReport = \"SIP Stack Audit:\\n\" + (leakedDialogs != null ? leakedDialogs : \"\")\n                    + (leakedServerTransactions != null ? leakedServerTransactions : \"\")\n                    + (leakedClientTransactions != null ? leakedClientTransactions : \"\");\n        }\n        return auditReport;\n    }\n\n    /**\n     * Audits SIP dialogs for leaks - Compares the dialogs in the dialogTable with a list of Call\n     * IDs passed by the application. - Dialogs that are not known by the application are leak\n     * suspects. - Kill the dialogs that are still around after the timer specified.\n     *\n     * @return Audit report, null if no dialog leaks were found\n     */\n    private String auditDialogs(Set activeCallIDs, long leakedDialogTimer) {\n        String auditReport = \"  Leaked dialogs:\\n\";\n        int leakedDialogs = 0;\n        long currentTime = System.currentTimeMillis();\n\n        // Make a shallow copy of the dialog list.\n        // This copy will remain intact as leaked dialogs are removed by the\n        // stack.\n        LinkedList dialogs;\n        synchronized (dialogTable) {\n            dialogs = new LinkedList(dialogTable.values());\n        }\n\n        // Iterate through the dialogDialog, get the callID of each dialog and\n        // check if it's in the\n        // list of active calls passed by the application. If it isn't, start\n        // the timer on it.\n        // If the timer has expired, kill the dialog.\n        Iterator it = dialogs.iterator();\n        while (it.hasNext()) {\n            // Get the next dialog\n            SIPDialog itDialog = (SIPDialog) it.next();\n\n            // Get the call id associated with this dialog\n            CallIdHeader callIdHeader = (itDialog != null ? itDialog.getCallId() : null);\n            String callID = (callIdHeader != null ? callIdHeader.getCallId() : null);\n\n            // Check if the application knows about this call id\n            if (itDialog != null && callID != null && !activeCallIDs.contains(callID)) {\n                // Application doesn't know anything about this dialog...\n                if (itDialog.auditTag == 0) {\n                    // Mark this dialog as suspect\n                    itDialog.auditTag = currentTime;\n                } else {\n                    // We already audited this dialog before. Check if his\n                    // time's up.\n                    if (currentTime - itDialog.auditTag >= leakedDialogTimer) {\n                        // Leaked dialog found\n                        leakedDialogs++;\n\n                        // Generate report\n                        DialogState dialogState = itDialog.getState();\n                        String dialogReport = \"dialog id: \" + itDialog.getDialogId()\n                                + \", dialog state: \"\n                                + (dialogState != null ? dialogState.toString() : \"null\");\n                        auditReport += \"    \" + dialogReport + \"\\n\";\n\n                        // Kill it\n                        itDialog.setState(SIPDialog.TERMINATED_STATE);\n                        if (isLoggingEnabled())\n                        \tstackLogger.logDebug(\"auditDialogs: leaked \" + dialogReport);\n                    }\n                }\n            }\n        }\n\n        // Return final report\n        if (leakedDialogs > 0) {\n            auditReport += \"    Total: \" + Integer.toString(leakedDialogs)\n                    + \" leaked dialogs detected and removed.\\n\";\n        } else {\n            auditReport = null;\n        }\n        return auditReport;\n    }\n\n    /**\n     * Audits SIP transactions for leaks\n     *\n     * @return Audit report, null if no transaction leaks were found\n     */\n    private String auditTransactions(ConcurrentHashMap transactionsMap,\n            long a_nLeakedTransactionTimer) {\n        String auditReport = \"  Leaked transactions:\\n\";\n        int leakedTransactions = 0;\n        long currentTime = System.currentTimeMillis();\n\n        // Make a shallow copy of the transaction list.\n        // This copy will remain intact as leaked transactions are removed by\n        // the stack.\n        LinkedList transactionsList = new LinkedList(transactionsMap.values());\n\n        // Iterate through our copy\n        Iterator it = transactionsList.iterator();\n        while (it.hasNext()) {\n            SIPTransaction sipTransaction = (SIPTransaction) it.next();\n            if (sipTransaction != null) {\n                if (sipTransaction.auditTag == 0) {\n                    // First time we see this transaction. Mark it as audited.\n                    sipTransaction.auditTag = currentTime;\n                } else {\n                    // We've seen this transaction before. Check if his time's\n                    // up.\n                    if (currentTime - sipTransaction.auditTag >= a_nLeakedTransactionTimer) {\n                        // Leaked transaction found\n                        leakedTransactions++;\n\n                        // Generate some report\n                        TransactionState transactionState = sipTransaction.getState();\n                        SIPRequest origRequest = sipTransaction.getOriginalRequest();\n                        String origRequestMethod = (origRequest != null ? origRequest.getMethod()\n                                : null);\n                        String transactionReport = sipTransaction.getClass().getName()\n                                + \", state: \"\n                                + (transactionState != null ? transactionState.toString()\n                                        : \"null\") + \", OR: \"\n                                + (origRequestMethod != null ? origRequestMethod : \"null\");\n                        auditReport += \"    \" + transactionReport + \"\\n\";\n\n                        // Kill it\n                        removeTransaction(sipTransaction);\n                        if (isLoggingEnabled())\n                        \tstackLogger.logDebug(\"auditTransactions: leaked \" + transactionReport);\n                    }\n                }\n            }\n        }\n\n        // Return final report\n        if (leakedTransactions > 0) {\n            auditReport += \"    Total: \" + Integer.toString(leakedTransactions)\n                    + \" leaked transactions detected and removed.\\n\";\n        } else {\n            auditReport = null;\n        }\n        return auditReport;\n    }\n\n    public void setNon2XXAckPassedToListener(boolean passToListener) {\n        this.non2XXAckPassedToListener = passToListener;\n    }\n\n    /**\n     * @return the non2XXAckPassedToListener\n     */\n    public boolean isNon2XXAckPassedToListener() {\n        return non2XXAckPassedToListener;\n    }\n\n    /**\n     * Get the count of client transactions that is not in the completed or terminated state.\n     *\n     * @return the activeClientTransactionCount\n     */\n    public int getActiveClientTransactionCount() {\n        return activeClientTransactionCount.get();\n    }\n\n    public boolean isRfc2543Supported() {\n\n        return this.rfc2543Supported;\n    }\n\n    public boolean isCancelClientTransactionChecked() {\n        return this.cancelClientTransactionChecked;\n    }\n\n    public boolean isRemoteTagReassignmentAllowed() {\n        return this.remoteTagReassignmentAllowed;\n    }\n\n    /**\n     * This method is slated for addition to the next spec revision.\n     *\n     *\n     * @return -- the collection of dialogs that is being managed by the stack.\n     */\n    public Collection<Dialog> getDialogs() {\n        HashSet<Dialog> dialogs = new HashSet<Dialog>();\n        dialogs.addAll(this.dialogTable.values());\n        dialogs.addAll(this.earlyDialogTable.values());\n        return dialogs;\n    }\n\n    /**\n     *\n     * @return -- the collection of dialogs matching the state that is being managed by the stack.\n     */\n    public Collection<Dialog> getDialogs(DialogState state) {\n        HashSet<Dialog> matchingDialogs = new HashSet<Dialog>();\n        if (DialogState.EARLY.equals(state)) {\n            matchingDialogs.addAll(this.earlyDialogTable.values());\n        } else {\n            Collection<SIPDialog> dialogs = dialogTable.values();\n            for (SIPDialog dialog : dialogs) {\n                if (dialog.getState() != null && dialog.getState().equals(state)) {\n                    matchingDialogs.add(dialog);\n                }\n            }\n        }\n        return matchingDialogs;\n    }\n\n    /**\n     * Get the Replaced Dialog from the stack.\n     *\n     * @param replacesHeader -- the header that references the dialog being replaced.\n     */\n    public Dialog getReplacesDialog(ReplacesHeader replacesHeader) {\n        String cid = replacesHeader.getCallId();\n        String fromTag = replacesHeader.getFromTag();\n        String toTag = replacesHeader.getToTag();\n\n        StringBuffer dialogId = new StringBuffer(cid);\n\n        // retval.append(COLON).append(to.getUserAtHostPort());\n        if (toTag != null) {\n            dialogId.append(\":\");\n            dialogId.append(toTag);\n        }\n        // retval.append(COLON).append(from.getUserAtHostPort());\n        if (fromTag != null) {\n            dialogId.append(\":\");\n            dialogId.append(fromTag);\n        }\n        String did = dialogId.toString().toLowerCase();\n        if (isLoggingEnabled())\n        \tstackLogger.logDebug(\"Looking for dialog \" + did);\n        /*\n         * Check if we can find this dialog in our dialog table.\n         */\n        Dialog replacesDialog =  this.dialogTable.get(did);\n        /*\n         * This could be a forked dialog. Search for it.\n         */\n        if ( replacesDialog == null ) {\n           for ( SIPClientTransaction ctx : this.clientTransactionTable.values()) {\n               if ( ctx.getDialog(did) != null ) {\n                   replacesDialog = ctx.getDialog(did);\n                   break;\n               }\n           }\n        }\n\n        return replacesDialog;\n    }\n\n    /**\n     * Get the Join Dialog from the stack.\n     *\n     * @param joinHeader -- the header that references the dialog being joined.\n     */\n    public Dialog getJoinDialog(JoinHeader joinHeader) {\n        String cid = joinHeader.getCallId();\n        String fromTag = joinHeader.getFromTag();\n        String toTag = joinHeader.getToTag();\n\n        StringBuffer retval = new StringBuffer(cid);\n\n        // retval.append(COLON).append(to.getUserAtHostPort());\n        if (toTag != null) {\n            retval.append(\":\");\n            retval.append(toTag);\n        }\n        // retval.append(COLON).append(from.getUserAtHostPort());\n        if (fromTag != null) {\n            retval.append(\":\");\n            retval.append(fromTag);\n        }\n        return this.dialogTable.get(retval.toString().toLowerCase());\n    }\n\n    /**\n     * @param timer the timer to set\n     */\n    public void setTimer(Timer timer) {\n        this.timer = timer;\n    }\n\n    /**\n     * @return the timer\n     */\n    public Timer getTimer() {\n        return timer;\n    }\n\n    \n    /**\n     * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer\n     * is better under load.\n     * \n     * @return\n     */\n\tpublic int getReceiveUdpBufferSize() {\n\t\treturn receiveUdpBufferSize;\n\t}\n\n    /**\n     * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer\n     * is better under load.\n     * \n     * @return\n     */\n\tpublic void setReceiveUdpBufferSize(int receiveUdpBufferSize) {\n\t\tthis.receiveUdpBufferSize = receiveUdpBufferSize;\n\t}\n\n    /**\n     * Size of the send UDP buffer. This property affects performance under load. Bigger buffer\n     * is better under load.\n     * \n     * @return\n     */\n\tpublic int getSendUdpBufferSize() {\n\t\treturn sendUdpBufferSize;\n\t}\n\n    /**\n     * Size of the send UDP buffer. This property affects performance under load. Bigger buffer\n     * is better under load.\n     * \n     * @return\n     */\n\tpublic void setSendUdpBufferSize(int sendUdpBufferSize) {\n\t\tthis.sendUdpBufferSize = sendUdpBufferSize;\n\t}\n\n\t/**\n\t * @param stackLogger the stackLogger to set\n\t */\n\tpublic void setStackLogger(StackLogger stackLogger) {\t\t\n\t\tthis.stackLogger = stackLogger;\n\t}\n\t\n\t /**\n\t  * Flag that reqests checking of branch IDs on responses.\n\t  * \n\t  * @return\n\t  */\n\t public boolean checkBranchId() {\n\t       return this.checkBranchId;\n\t }\n\n    /**\n     * @param logStackTraceOnMessageSend the logStackTraceOnMessageSend to set\n     */\n    public void setLogStackTraceOnMessageSend(boolean logStackTraceOnMessageSend) {\n        this.logStackTraceOnMessageSend = logStackTraceOnMessageSend;\n    }\n\n    /**\n     * @return the logStackTraceOnMessageSend\n     */\n    public boolean isLogStackTraceOnMessageSend() {\n        return logStackTraceOnMessageSend;\n    }\n    \n    public void setDeliverDialogTerminatedEventForNullDialog() {\n        this.isDialogTerminatedEventDeliveredForNullDialog = true;\n    }\n    \n    public void addForkedClientTransaction(SIPClientTransaction clientTransaction) {\n        this.forkedClientTransactionTable.put(clientTransaction.getTransactionId(), clientTransaction );\n    }\n\n    public SIPClientTransaction getForkedTransaction(String transactionId) {\n        return this.forkedClientTransactionTable.get(transactionId);\n    }\n\t\n\t\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/ServerLog.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *\n ******************************************************************************/\n\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.ServerLogger;\nimport gov2.nist.core.StackLogger;\nimport gov2.nist.javax2.sip.LogRecord;\nimport gov2.nist.javax2.sip.header.CallID;\nimport gov2.nist.javax2.sip.message.SIPMessage;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.Properties;\n\nimport javax2.sip.SipStack;\nimport javax2.sip.header.TimeStampHeader;\n\n// BEGIN android-deleted\n// import org.apache.log4j.Level;\n// import org.apache.log4j.Logger;\n// END android-deleted\n\n/**\n * Log file wrapper class. Log messages into the message trace file and also write the log into\n * the debug file if needed. This class keeps an XML formatted trace around for later access via\n * RMI. The trace can be viewed with a trace viewer (see tools.traceviewerapp).\n *\n * @version 1.2 $Revision: 1.39 $ $Date: 2009/11/11 14:00:58 $\n *\n * @author M. Ranganathan <br/>\n *\n *\n */\npublic class ServerLog implements ServerLogger {\n\n    private boolean logContent;\n\n    protected StackLogger stackLogger;\n\n    /**\n     * Name of the log file in which the trace is written out (default is null)\n     */\n    private String logFileName;\n\n    /**\n     * Print writer that is used to write out the log file.\n     */\n    private PrintWriter printWriter;\n\n    /**\n     * Set auxililary information to log with this trace.\n     */\n    private String auxInfo;\n\n    private String description;\n\n    private String stackIpAddress;\n\n    private SIPTransactionStack sipStack;\n\n    private Properties configurationProperties;\n\n    public ServerLog() {\n        // Debug log file. Whatever gets logged by us also makes its way into debug log.\n    }\n\n    private void setProperties(Properties configurationProperties) {\n        this.configurationProperties = configurationProperties;\n        // Set a descriptive name for the message trace logger.\n        this.description = configurationProperties.getProperty(\"javax2.sip.STACK_NAME\");\n        this.stackIpAddress = configurationProperties.getProperty(\"javax2.sip.IP_ADDRESS\");\n        this.logFileName = configurationProperties.getProperty(\"gov2.nist.javax2.sip.SERVER_LOG\");\n        String logLevel = configurationProperties.getProperty(\"gov2.nist.javax2.sip.TRACE_LEVEL\");\n        String logContent = configurationProperties\n                .getProperty(\"gov2.nist.javax2.sip.LOG_MESSAGE_CONTENT\");\n\n        this.logContent = (logContent != null && logContent.equals(\"true\"));\n\n        if (logLevel != null) {\n            if (logLevel.equals(\"LOG4J\")) {\n                // if TRACE_LEVEL property is specified as\n                // \"LOG4J\" then, set the traceLevel based on\n                // the log4j effective log level.\n\n                // check whether a Log4j logger name has been\n                // specified. if not, use the stack name as the default\n                // logger name.\n\n                // BEGIN android-deleted\n                /*\n                Logger logger = Logger.getLogger(configurationProperties.getProperty(\n                        \"gov2.nist.javax2.sip.LOG4J_LOGGER_NAME\", this.description));\n                Level level = logger.getEffectiveLevel();\n                if (level == Level.OFF) {\n                    this.setTraceLevel(0);\n                } else if (level.isGreaterOrEqual(Level.DEBUG)) {\n                    this.setTraceLevel(TRACE_DEBUG);\n                } else if (level.isGreaterOrEqual(Level.INFO)) {\n                    this.setTraceLevel(TRACE_MESSAGES);\n                } else if (level.isGreaterOrEqual(Level.WARN)) {\n                    this.setTraceLevel(TRACE_EXCEPTION);\n                }\n                */\n                // END android-deleted\n            } else {\n                try {\n                    int ll;\n                    if (logLevel.equals(\"DEBUG\")) {\n                        ll = TRACE_DEBUG;\n                    } else if (logLevel.equals(\"INFO\")) {\n                        ll = TRACE_MESSAGES;\n                    } else if (logLevel.equals(\"ERROR\")) {\n                        ll = TRACE_EXCEPTION;\n                    } else if (logLevel.equals(\"NONE\") || logLevel.equals(\"OFF\")) {\n                        ll = TRACE_NONE;\n                    } else {\n                        ll = Integer.parseInt(logLevel);\n                    }\n\n                    this.setTraceLevel(ll);\n                } catch (NumberFormatException ex) {\n                    System.out.println(\"ServerLog: WARNING Bad integer \" + logLevel);\n                    System.out.println(\"logging dislabled \");\n                    this.setTraceLevel(0);\n                }\n            }\n        }\n        checkLogFile();\n\n    }\n\n    public void setStackIpAddress(String ipAddress) {\n        this.stackIpAddress = ipAddress;\n    }\n\n    // public static boolean isWebTesterCatchException=false;\n    // public static String webTesterLogFile=null;\n\n    /**\n     * default trace level\n     */\n    protected int traceLevel = TRACE_MESSAGES;\n\n    public synchronized void closeLogFile() {\n        if (printWriter != null) {\n            printWriter.close();\n            printWriter = null;\n        }\n    }\n\n    public void checkLogFile() {\n        if (logFileName == null || traceLevel < TRACE_MESSAGES) {\n            // Dont create a log file if tracing is\n            // disabled.\n            return;\n        }\n        try {\n            File logFile = new File(logFileName);\n            if (!logFile.exists()) {\n                logFile.createNewFile();\n                printWriter = null;\n            }\n            // Append buffer to the end of the file unless otherwise specified\n            // by the user.\n            if (printWriter == null) {\n                boolean overwrite = Boolean.valueOf(\n                    configurationProperties.getProperty(\n                        \"gov2.nist.javax2.sip.SERVER_LOG_OVERWRITE\"));\n\n                FileWriter fw = new FileWriter(logFileName, !overwrite);\n\n                printWriter = new PrintWriter(fw, true);\n                if (auxInfo != null) {\n\n                    if (sipStack.isLoggingEnabled()) {\n                        stackLogger\n                                .logDebug(\"Here are the stack configuration properties \\n\"\n                                        + \"javax2.sip.IP_ADDRESS= \"\n                                        + configurationProperties\n                                                .getProperty(\"javax2.sip.IP_ADDRESS\")\n                                        + \"\\n\"\n                                        + \"javax2.sip.ROUTER_PATH= \"\n                                        + configurationProperties\n                                                .getProperty(\"javax2.sip.ROUTER_PATH\")\n                                        + \"\\n\"\n                                        + \"javax2.sip.OUTBOUND_PROXY= \"\n                                        + configurationProperties\n                                                .getProperty(\"javax2.sip.OUTBOUND_PROXY\")\n                                        + \"\\n\"\n                                        + \"gov2.nist.javax2.sip.CACHE_CLIENT_CONNECTIONS= \"\n                                        + configurationProperties\n                                                .getProperty(\"gov2.nist.javax2.sip.CACHE_CLIENT_CONNECTIONS\")\n                                        + \"\\n\"\n                                        + \"gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS= \"\n                                        + configurationProperties\n                                                .getProperty(\"gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS\")\n                                        + \"\\n\"\n                                        + \"gov2.nist.javax2.sip.REENTRANT_LISTENER= \"\n                                        + configurationProperties\n                                                .getProperty(\"gov2.nist.javax2.sip.REENTRANT_LISTENER\")\n                                        + \"gov2.nist.javax2.sip.THREAD_POOL_SIZE= \"\n                                        + configurationProperties\n                                                .getProperty(\"gov2.nist.javax2.sip.THREAD_POOL_SIZE\")\n                                        + \"\\n\");\n                        stackLogger.logDebug(\" ]]> \");\n                        stackLogger.logDebug(\"</debug>\");\n                        stackLogger.logDebug(\"<description\\n logDescription=\\\"\" + description\n                                + \"\\\"\\n name=\\\"\" + stackIpAddress + \"\\\"\\n auxInfo=\\\"\" + auxInfo\n                                + \"\\\"/>\\n \");\n                        stackLogger.logDebug(\"<debug>\");\n                        stackLogger.logDebug(\"<![CDATA[ \");\n                    }\n                } else {\n\n                    if (sipStack.isLoggingEnabled()) {\n                        stackLogger.logDebug(\"Here are the stack configuration properties \\n\"\n                                + configurationProperties + \"\\n\");\n                        stackLogger.logDebug(\" ]]>\");\n                        stackLogger.logDebug(\"</debug>\");\n                        stackLogger.logDebug(\"<description\\n logDescription=\\\"\" + description\n                                + \"\\\"\\n name=\\\"\" + stackIpAddress + \"\\\" />\\n\");\n                        stackLogger.logDebug(\"<debug>\");\n                        stackLogger.logDebug(\"<![CDATA[ \");\n                    }\n                }\n            }\n        } catch (IOException ex) {\n\n        }\n    }\n\n    /**\n     * Global check for whether to log or not. To minimize the time return false here.\n     *\n     * @return true -- if logging is globally enabled and false otherwise.\n     *\n     */\n    public boolean needsLogging() {\n        return logFileName != null;\n    }\n\n    /**\n     * Set the log file name\n     *\n     * @param name is the name of the log file to set.\n     */\n    public void setLogFileName(String name) {\n        logFileName = name;\n    }\n\n    /**\n     * return the name of the log file.\n     */\n    public String getLogFileName() {\n        return logFileName;\n    }\n\n    /**\n     * Log a message into the log file.\n     *\n     * @param message message to log into the log file.\n     */\n    private void logMessage(String message) {\n        // String tname = Thread.currentThread().getName();\n        checkLogFile();\n        String logInfo = message;\n        if (printWriter != null) {\n            printWriter.println(logInfo);\n        }\n        if (sipStack.isLoggingEnabled()) {\n            stackLogger.logInfo(logInfo);\n\n        }\n    }\n\n    private void logMessage(String message, String from, String to, boolean sender,\n            String callId, String firstLine, String status, String tid, long time,\n            long timestampVal) {\n\n        LogRecord log = this.sipStack.logRecordFactory.createLogRecord(message, from, to, time,\n                sender, firstLine, tid, callId, timestampVal);\n        if (log != null)\n            logMessage(log.toString());\n    }\n\n    /**\n     * Log a message into the log directory.\n     *\n     * @param message a SIPMessage to log\n     * @param from from header of the message to log into the log directory\n     * @param to to header of the message to log into the log directory\n     * @param sender is the server the sender\n     * @param time is the time to associate with the message.\n     */\n    public void logMessage(SIPMessage message, String from, String to, boolean sender, long time) {\n        checkLogFile();\n        if (message.getFirstLine() == null)\n            return;\n        CallID cid = (CallID) message.getCallId();\n        String callId = null;\n        if (cid != null)\n            callId = cid.getCallId();\n        String firstLine = message.getFirstLine().trim();\n        String inputText = (logContent ? message.encode() : message.encodeMessage());\n        String tid = message.getTransactionId();\n        TimeStampHeader tsHdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME);\n        long tsval = tsHdr == null ? 0 : tsHdr.getTime();\n        logMessage(inputText, from, to, sender, callId, firstLine, null, tid, time, tsval);\n    }\n\n    /**\n     * Log a message into the log directory.\n     *\n     * @param message a SIPMessage to log\n     * @param from from header of the message to log into the log directory\n     * @param to to header of the message to log into the log directory\n     * @param status the status to log.\n     * @param sender is the server the sender or receiver (true if sender).\n     * @param time is the reception time.\n     */\n    public void logMessage(SIPMessage message, String from, String to, String status,\n            boolean sender, long time) {\n        checkLogFile();\n        CallID cid = (CallID) message.getCallId();\n        String callId = null;\n        if (cid != null)\n            callId = cid.getCallId();\n        String firstLine = message.getFirstLine().trim();\n        String encoded = (logContent ? message.encode() : message.encodeMessage());\n        String tid = message.getTransactionId();\n        TimeStampHeader tshdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME);\n        long tsval = tshdr == null ? 0 : tshdr.getTime();\n        logMessage(encoded, from, to, sender, callId, firstLine, status, tid, time, tsval);\n    }\n\n    /**\n     * Log a message into the log directory. Time stamp associated with the message is the current\n     * time.\n     *\n     * @param message a SIPMessage to log\n     * @param from from header of the message to log into the log directory\n     * @param to to header of the message to log into the log directory\n     * @param status the status to log.\n     * @param sender is the server the sender or receiver (true if sender).\n     */\n    public void logMessage(SIPMessage message, String from, String to, String status,\n            boolean sender) {\n        logMessage(message, from, to, status, sender, System.currentTimeMillis());\n    }\n\n    /**\n     * Log an exception stack trace.\n     *\n     * @param ex Exception to log into the log file\n     */\n\n    public void logException(Exception ex) {\n        if (traceLevel >= TRACE_EXCEPTION) {\n            checkLogFile();\n            ex.printStackTrace();\n            if (printWriter != null)\n                ex.printStackTrace(printWriter);\n\n        }\n    }\n\n    /**\n     * Set the trace level for the stack.\n     *\n     * @param level -- the trace level to set. The following trace levels are supported:\n     *        <ul>\n     *        <li> 0 -- no tracing </li>\n     *\n     * <li> 16 -- trace messages only </li>\n     *\n     * <li> 32 Full tracing including debug messages. </li>\n     *\n     * </ul>\n     */\n    public void setTraceLevel(int level) {\n        traceLevel = level;\n    }\n\n    /**\n     * Get the trace level for the stack.\n     *\n     * @return the trace level\n     */\n    public int getTraceLevel() {\n        return traceLevel;\n    }\n\n    /**\n     * Set aux information. Auxiliary information may be associated with the log file. This is\n     * useful for remote logs.\n     *\n     * @param auxInfo -- auxiliary information.\n     */\n    public void setAuxInfo(String auxInfo) {\n        this.auxInfo = auxInfo;\n    }\n\n\tpublic void setSipStack(SipStack sipStack) {\n\t\tif(sipStack instanceof SIPTransactionStack) {\n\t\t\tthis.sipStack = (SIPTransactionStack)sipStack;\n\t        this.stackLogger = this.sipStack.getStackLogger();\n\t\t}\n\t\telse\n\t\t\tthrow new IllegalArgumentException(\"sipStack must be a SIPTransactionStack\");\n\t}\n\n\tpublic void setStackProperties(Properties stackProperties) {\n\t\tsetProperties(stackProperties);\n\t}\n\t\n\tpublic void setLevel(int jsipLoggingLevel) {\n\t    \n\t}\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/ServerRequestInterface.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.javax2.sip.message.*;\n\n/**\n * An interface for a genereic message processor for SIP Request messages.\n * This is implemented by the application. The stack calls the message\n * factory with a pointer to the parsed structure to create one of these\n * and then calls processRequest on the newly created SIPServerRequest\n * It is the applications responsibility to take care of what needs to be\n * done to actually process the request.\n *\n * @version 1.2 $Revision: 1.4 $ $Date: 2009/07/17 18:58:15 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic interface ServerRequestInterface {\n\n    /**\n     * Process the message.  This incorporates a feature request\n     * by Salvador Rey Calatayud <salreyca@TELECO.UPV.ES>\n     * @param sipRequest is the incoming SIP Request.\n     * @param  incomingChannel is the incoming message channel (parameter\n     * added in response to a request by Salvador Rey Calatayud.)\n     */\n    public void processRequest(\n        SIPRequest sipRequest,\n        MessageChannel incomingChannel);\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/ServerResponseInterface.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\nimport gov2.nist.javax2.sip.message.*;\n\n/*\n *  Salvador Rey Calatayud suggested adding a parameter to the processRequest/processResponse\n *  methods.\n */\n\n/**\n * An interface for a genereic message processor for SIP Response messages.\n * This is implemented by the application. The stack calls the message\n * factory with a pointer to the parsed structure to create one of these\n * and then calls processResponse on the newly created SIPServerResponse\n * It is the applications responsibility to take care of what needs to be\n * done to actually process the response.\n *\n * @version 1.2 $Revision: 1.4 $ $Date: 2009/07/17 18:58:15 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic interface ServerResponseInterface {\n    /**\n     * Process the Response.\n     * @param  incomingChannel is the incoming message channel\n     * @param sipResponse is the responseto process.\n     * @param sipDialog -- dialog for this response\n     */\n    public void processResponse(\n        SIPResponse sipResponse,\n        MessageChannel incomingChannel,\n        SIPDialog sipDialog);\n\n\n\n\n    /**\n     * This method is called prior to dialog assignment.\n     * @param sipResponse\n     * @param incomingChannel\n     */\n    public void processResponse(\n            SIPResponse sipResponse,\n            MessageChannel incomingChannel);\n\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/StackMessageFactory.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *\n*******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\nimport gov2.nist.javax2.sip.message.*;\n\n/**\n * An interface for generating new requests and responses. This is implemented\n * by the application and called by the stack for processing requests\n * and responses. When a Request comes in off the wire, the stack calls\n * newSIPServerRequest which is then responsible for processing the request.\n * When a response comes off the wire, the stack calls newSIPServerResponse\n * to process the response.\n *\n * @version 1.2 $Revision: 1.5 $ $Date: 2009/07/17 18:58:15 $\n *\n * @author M. Ranganathan   <br/>\n *\n *\n *\n */\npublic interface StackMessageFactory {\n    /**\n     * Make a new SIPServerResponse given a SIPRequest and a message\n     * channel.\n     *\n     * @param sipRequest is the incoming request.\n     * @param msgChan is the message channel on which this request was\n     *  received.\n     */\n    public ServerRequestInterface newSIPServerRequest(\n        SIPRequest sipRequest,\n        MessageChannel msgChan);\n\n    /**\n     * Generate a new server response for the stack.\n     *\n     * @param sipResponse is the incoming response.\n     * @param msgChan is the message channel on which the response was\n     * received.\n     */\n    public ServerResponseInterface newSIPServerResponse(\n        SIPResponse sipResponse,\n        MessageChannel msgChan);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/TCPMessageChannel.java",
    "content": "/*\n * Conditions Of Use \n * \n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n * \n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *  \n * .\n * \n */\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.message.*;\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.net.*;\nimport java.io.*;\nimport java.text.ParseException;\nimport java.util.TimerTask;\n\nimport javax2.sip.address.Hop;\n\n/*\n * Ahmet Uyar <auyar@csit.fsu.edu>sent in a bug report for TCP operation of the JAIN sipStack.\n * Niklas Uhrberg suggested that a mechanism be added to limit the number of simultaneous open\n * connections. The TLS Adaptations were contributed by Daniel Martinez. Hagai Sela contributed a\n * bug fix for symmetric nat. Jeroen van Bemmel added compensation for buggy clients ( Microsoft\n * RTC clients ). Bug fixes by viswashanti.kadiyala@antepo.com, Joost Yervante Damand\n */\n\n/**\n * This is a stack abstraction for TCP connections. This abstracts a stream of parsed messages.\n * The SIP sipStack starts this from the main SIPStack class for each connection that it accepts.\n * It starts a message parser in its own thread and talks to the message parser via a pipe. The\n * message parser calls back via the parseError or processMessage functions that are defined as\n * part of the SIPMessageListener interface.\n * \n * @see gov2.nist.javax2.sip.parser.PipelinedMsgParser\n * \n * \n * @author M. Ranganathan <br/>\n * \n * @version 1.2 $Revision: 1.59 $ $Date: 2009/11/20 04:45:53 $\n */\npublic class TCPMessageChannel extends MessageChannel implements SIPMessageListener, Runnable,\n        RawMessageChannel {\n\n    private Socket mySock;\n\n    private PipelinedMsgParser myParser;\n\n    protected InputStream myClientInputStream; // just to pass to thread.\n\n    protected OutputStream myClientOutputStream;\n\n    protected String key;\n\n    protected boolean isCached;\n\n    protected boolean isRunning;\n\n    private Thread mythread;\n\n    protected SIPTransactionStack sipStack;\n\n    protected String myAddress;\n\n    protected int myPort;\n\n    protected InetAddress peerAddress;\n\n    protected int peerPort;\n\n    protected String peerProtocol;\n\n    // Incremented whenever a transaction gets assigned\n    // to the message channel and decremented when\n    // a transaction gets freed from the message channel.\n    // protected int useCount;\n\n    private TCPMessageProcessor tcpMessageProcessor;\n\n    protected TCPMessageChannel(SIPTransactionStack sipStack) {\n        this.sipStack = sipStack;\n\n    }\n\n    /**\n     * Constructor - gets called from the SIPStack class with a socket on accepting a new client.\n     * All the processing of the message is done here with the sipStack being freed up to handle\n     * new connections. The sock input is the socket that is returned from the accept. Global data\n     * that is shared by all threads is accessible in the Server structure.\n     * \n     * @param sock Socket from which to read and write messages. The socket is already connected\n     *        (was created as a result of an accept).\n     * \n     * @param sipStack Ptr to SIP Stack\n     */\n\n    protected TCPMessageChannel(Socket sock, SIPTransactionStack sipStack,\n            TCPMessageProcessor msgProcessor) throws IOException {\n\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"creating new TCPMessageChannel \");\n            sipStack.getStackLogger().logStackTrace();\n        }\n        mySock = sock;\n        peerAddress = mySock.getInetAddress();\n        myAddress = msgProcessor.getIpAddress().getHostAddress();\n        myClientInputStream = mySock.getInputStream();\n        myClientOutputStream = mySock.getOutputStream();\n        mythread = new Thread(this);\n        mythread.setDaemon(true);\n        mythread.setName(\"TCPMessageChannelThread\");\n        // Stash away a pointer to our sipStack structure.\n        this.sipStack = sipStack;\n        this.peerPort = mySock.getPort();\n\n        this.tcpMessageProcessor = msgProcessor;\n        this.myPort = this.tcpMessageProcessor.getPort();\n        // Bug report by Vishwashanti Raj Kadiayl\n        super.messageProcessor = msgProcessor;\n        // Can drop this after response is sent potentially.\n        mythread.start();\n    }\n\n    /**\n     * Constructor - connects to the given inet address. Acknowledgement -- Lamine Brahimi (IBM\n     * Zurich) sent in a bug fix for this method. A thread was being uncessarily created.\n     * \n     * @param inetAddr inet address to connect to.\n     * @param sipStack is the sip sipStack from which we are created.\n     * @throws IOException if we cannot connect.\n     */\n    protected TCPMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack,\n            TCPMessageProcessor messageProcessor) throws IOException {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"creating new TCPMessageChannel \");\n            sipStack.getStackLogger().logStackTrace();\n        }\n        this.peerAddress = inetAddr;\n        this.peerPort = port;\n        this.myPort = messageProcessor.getPort();\n        this.peerProtocol = \"TCP\";\n        this.sipStack = sipStack;\n        this.tcpMessageProcessor = messageProcessor;\n        this.myAddress = messageProcessor.getIpAddress().getHostAddress();\n        // Bug report by Vishwashanti Raj Kadiayl\n        this.key = MessageChannel.getKey(peerAddress, peerPort, \"TCP\");\n        super.messageProcessor = messageProcessor;\n\n    }\n\n    /**\n     * Returns \"true\" as this is a reliable transport.\n     */\n    public boolean isReliable() {\n        return true;\n    }\n\n    /**\n     * Close the message channel.\n     */\n    public void close() {\n        try {\n            if (mySock != null) {\n                mySock.close();\n                mySock = null;\n            }\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Closing message Channel \" + this);\n        } catch (IOException ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Error closing socket \" + ex);\n        }\n    }\n\n    /**\n     * Get my SIP Stack.\n     * \n     * @return The SIP Stack for this message channel.\n     */\n    public SIPTransactionStack getSIPStack() {\n        return sipStack;\n    }\n\n    /**\n     * get the transport string.\n     * \n     * @return \"tcp\" in this case.\n     */\n    public String getTransport() {\n        return \"TCP\";\n    }\n\n    /**\n     * get the address of the client that sent the data to us.\n     * \n     * @return Address of the client that sent us data that resulted in this channel being\n     *         created.\n     */\n    public String getPeerAddress() {\n        if (peerAddress != null) {\n            return peerAddress.getHostAddress();\n        } else\n            return getHost();\n    }\n\n    protected InetAddress getPeerInetAddress() {\n        return peerAddress;\n    }\n\n    public String getPeerProtocol() {\n        return this.peerProtocol;\n    }\n\n    /**\n     * Send message to whoever is connected to us. Uses the topmost via address to send to.\n     * \n     * @param message is the message to send.\n     * @param retry\n     */\n    private void sendMessage(SIPMessage message, boolean retry) throws IOException {\n\n        /*\n         * Patch from kircuv@dev.java.net (Issue 119 ) This patch avoids the case where two\n         * TCPMessageChannels are now pointing to the same socket.getInputStream().\n         * \n         * JvB 22/5 removed\n         */\n       // Socket s = this.sipStack.ioHandler.getSocket(IOHandler.makeKey(\n       // this.peerAddress, this.peerPort));\n        Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(),\n                this.peerAddress, this.peerPort, this.peerProtocol, message, retry, this);\n\n        // Created a new socket so close the old one and stick the new\n        // one in its place but dont do this if it is a datagram socket.\n        // (could have replied via udp but received via tcp!).\n        // if (mySock == null && s != null) {\n        // this.uncache();\n        // } else\n        if (sock != mySock && sock != null) {\n            try {\n                if (mySock != null)\n                    mySock.close();\n            } catch (IOException ex) {\n            }\n            mySock = sock;\n            this.myClientInputStream = mySock.getInputStream();\n            this.myClientOutputStream = mySock.getOutputStream();\n            Thread thread = new Thread(this);\n            thread.setDaemon(true);\n            thread.setName(\"TCPMessageChannelThread\");\n            thread.start();\n        }\n\n    }\n\n    /**\n     * Return a formatted message to the client. We try to re-connect with the peer on the other\n     * end if possible.\n     * \n     * @param sipMessage Message to send.\n     * @throws IOException If there is an error sending the message\n     */\n    public void sendMessage(SIPMessage sipMessage) throws IOException {\n\n        long time = System.currentTimeMillis();\n\n        // JvB: also retry for responses, if the connection is gone we should\n        // try to reconnect\n        this.sendMessage(sipMessage, /* sipMessage instanceof SIPRequest */true);\n\n        if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))\n            logMessage(sipMessage, peerAddress, peerPort, time);\n    }\n\n    /**\n     * Send a message to a specified address.\n     * \n     * @param message message to send.\n     * @param receiverAddress Address to send it to.\n     * @param receiverPort Receiver port.\n     * @throws IOException If there is a problem connecting or sending.\n     */\n    public void sendMessage(SIPMessage message, InetAddress receiverAddress, int receiverPort,\n            boolean retry) throws IOException {\n        if (message == null || receiverAddress == null)\n            throw new IllegalArgumentException(\"Null argument\");\n         Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(),\n                receiverAddress, receiverPort, \"TCP\", message, retry, this);\n        if (sock != mySock && sock != null) {\n            if (mySock != null) {\n                /*\n                 * Delay the close of the socket for some time in case it is being used.\n                 */\n                sipStack.getTimer().schedule(new TimerTask() {\n                    @Override\n                    public boolean cancel() {\n                        try {\n                            if (mySock != null) {\n                                mySock.close();\n                            }\n                            super.cancel();\n                        } catch (IOException ex) {\n\n                        }\n                        return true;\n                    }\n\n                    @Override\n                    public void run() {\n                        try {\n                            if (mySock != null) {\n                                mySock.close();\n                            }\n                        } catch (IOException ex) {\n\n                        }\n                    }\n                }, 8000);\n            }\n\n            mySock = sock;\n            this.myClientInputStream = mySock.getInputStream();\n            this.myClientOutputStream = mySock.getOutputStream();\n            // start a new reader on this end of the pipe.\n            Thread mythread = new Thread(this);\n            mythread.setDaemon(true);\n            mythread.setName(\"TCPMessageChannelThread\");\n            mythread.start();\n        }\n\n    }\n\n    /**\n     * Exception processor for exceptions detected from the parser. (This is invoked by the parser\n     * when an error is detected).\n     * \n     * @param sipMessage -- the message that incurred the error.\n     * @param ex -- parse exception detected by the parser.\n     * @param header -- header that caused the error.\n     * @throws ParseException Thrown if we want to reject the message.\n     */\n    public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass,\n            String header, String message) throws ParseException {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logException(ex);\n        // Log the bad message for later reference.\n        if ((hdrClass != null)\n                && (hdrClass.equals(From.class) || hdrClass.equals(To.class)\n                        || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class)\n                        || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass\n                        .equals(StatusLine.class))) {\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\n                        \"Encountered Bad Message \\n\" + sipMessage.toString());\n            }\n\n            // JvB: send a 400 response for requests (except ACK)\n            // Currently only UDP, @todo also other transports\n            String msgString = sipMessage.toString();\n            if (!msgString.startsWith(\"SIP/\") && !msgString.startsWith(\"ACK \")) {\n\n                SIPMessage badReqRes = createBadReqRes(msgString, ex);\n                if (badReqRes != null) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\"Sending automatic 400 Bad Request:\");\n                        sipStack.getStackLogger().logDebug(msgString);\n                    }\n                    try {\n                        this.sendMessage(badReqRes, this.getPeerInetAddress(), this\n                                .getPeerPort(), false);\n                    } catch (IOException e) {\n                        if (sipStack.isLoggingEnabled())\n                        \tthis.sipStack.getStackLogger().logException(e);\n                    }\n                } else {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Could not formulate automatic 400 Bad Request\");\n                    }\n                }\n            }\n\n            throw ex;\n        } else {\n            sipMessage.addUnparsed(header);\n        }\n    }\n\n    /**\n     * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser\n     * errors).\n     * \n     * @param sipMessage Mesage to process (this calls the application for processing the\n     *        message).\n     */\n    public void processMessage(SIPMessage sipMessage) throws Exception {\n        try {\n            if (sipMessage.getFrom() == null\n                    || // sipMessage.getFrom().getTag()\n                    // == null ||\n                    sipMessage.getTo() == null || sipMessage.getCallId() == null\n                    || sipMessage.getCSeq() == null || sipMessage.getViaHeaders() == null) {\n                String badmsg = sipMessage.encode();\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\">>> Dropped Bad Msg\");\n                    sipStack.getStackLogger().logDebug(badmsg);\n                }\n\n                return;\n            }\n\n            ViaList viaList = sipMessage.getViaHeaders();\n            // For a request\n            // first via header tells where the message is coming from.\n            // For response, this has already been recorded in the outgoing\n            // message.\n            if (sipMessage instanceof SIPRequest) {\n                Via v = (Via) viaList.getFirst();\n                Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());\n                this.peerProtocol = v.getTransport();\n                try {\n                    this.peerAddress = mySock.getInetAddress();\n                    // Check to see if the received parameter matches\n                    // the peer address and tag it appropriately.\n\n                    // JvB: dont do this. It is both costly and incorrect\n                    // Must set received also when it is a FQDN, regardless\n                    // whether\n                    // it resolves to the correct IP address\n                    // InetAddress sentByAddress =\n                    // InetAddress.getByName(hop.getHost());\n                    // JvB: if sender added 'rport', must always set received\n                    if (v.hasParameter(Via.RPORT)\n                            || !hop.getHost().equals(this.peerAddress.getHostAddress())) {\n                        v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress());\n                    }\n                    // @@@ hagai\n                    // JvB: technically, may only do this when Via already\n                    // contains\n                    // rport\n                    v.setParameter(Via.RPORT, Integer.toString(this.peerPort));\n                } catch (java.text.ParseException ex) {\n                    InternalErrorHandler.handleException(ex, sipStack.getStackLogger());\n                }\n                // Use this for outgoing messages as well.\n                if (!this.isCached) {\n                    ((TCPMessageProcessor) this.messageProcessor).cacheMessageChannel(this);\n                    this.isCached = true;\n                    int remotePort = ((java.net.InetSocketAddress) mySock.getRemoteSocketAddress()).getPort();\n                    String key = IOHandler.makeKey(mySock.getInetAddress(), remotePort);\n                    sipStack.ioHandler.putSocket(key, mySock);\n                }\n            }\n\n         \n            // Foreach part of the request header, fetch it and process it\n\n            long receptionTime = System.currentTimeMillis();\n\n            if (sipMessage instanceof SIPRequest) {\n                // This is a request - process the request.\n                SIPRequest sipRequest = (SIPRequest) sipMessage;\n                // Create a new sever side request processor for this\n                // message and let it handle the rest.\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\"----Processing Message---\");\n                }\n\n                // Check for reasonable size - reject message\n                // if it is too long.\n                if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {\n                    sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(),\n                            this.getMessageProcessor().getIpAddress().getHostAddress() + \":\"\n                                    + this.getMessageProcessor().getPort(), false, receptionTime);\n\n                }\n\n                if (sipStack.getMaxMessageSize() > 0\n                        && sipRequest.getSize()\n                                + (sipRequest.getContentLength() == null ? 0 : sipRequest\n                                        .getContentLength().getContentLength()) > sipStack\n                                .getMaxMessageSize()) {\n                    SIPResponse sipResponse = sipRequest\n                            .createResponse(SIPResponse.MESSAGE_TOO_LARGE);\n                    this.sendMessage(sipResponse, false);\n                    throw new Exception(\"Message size exceeded\");\n                }\n\n                ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest(\n                        sipRequest, this);\n\n                if (sipServerRequest != null) {\n                    try {\n                        sipServerRequest.processRequest(sipRequest, this);\n                    } finally {\n                        if (sipServerRequest instanceof SIPTransaction) {\n                            SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;\n                            if (!sipServerTx.passToListener())\n                                ((SIPTransaction) sipServerRequest).releaseSem();\n                        }\n                    }\n                } else {\n                \tif (sipStack.isLoggingEnabled())\n                \t\tthis.sipStack.getStackLogger()\n                            .logWarning(\"Dropping request -- could not acquire semaphore in 10 sec\");\n                }\n\n            } else {\n                SIPResponse sipResponse = (SIPResponse) sipMessage;\n                // JvB: dont do this\n                // if (sipResponse.getStatusCode() == 100)\n                // sipResponse.getTo().removeParameter(\"tag\");\n                try {\n                    sipResponse.checkHeaders();\n                } catch (ParseException ex) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger()\n                                .logError(\"Dropping Badly formatted response message >>> \"\n                                        + sipResponse);\n                    return;\n                }\n                // This is a response message - process it.\n                // Check the size of the response.\n                // If it is too large dump it silently.\n                if (sipStack.getMaxMessageSize() > 0\n                        && sipResponse.getSize()\n                                + (sipResponse.getContentLength() == null ? 0 : sipResponse\n                                        .getContentLength().getContentLength()) > sipStack\n                                .getMaxMessageSize()) {\n                    if (sipStack.isLoggingEnabled())\n                        this.sipStack.getStackLogger().logDebug(\"Message size exceeded\");\n                    return;\n\n                }\n                ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse(\n                        sipResponse, this);\n                if (sipServerResponse != null) {\n                    try {\n                        if (sipServerResponse instanceof SIPClientTransaction\n                                && !((SIPClientTransaction) sipServerResponse)\n                                        .checkFromTag(sipResponse)) {\n                            if (sipStack.isLoggingEnabled())\n                                sipStack.getStackLogger()\n                                        .logError(\"Dropping response message with invalid tag >>> \"\n                                                + sipResponse);\n                            return;\n                        }\n\n                        sipServerResponse.processResponse(sipResponse, this);\n                    } finally {\n                        if (sipServerResponse instanceof SIPTransaction\n                                && !((SIPTransaction) sipServerResponse).passToListener())\n                            ((SIPTransaction) sipServerResponse).releaseSem();\n                    }\n                } else {\n                    sipStack\n                            .getStackLogger()\n                            .logWarning(\n                                    \"Application is blocked -- could not acquire semaphore -- dropping response\");\n                }\n            }\n        } finally {\n        }\n    }\n\n    /**\n     * This gets invoked when thread.start is called from the constructor. Implements a message\n     * loop - reading the tcp connection and processing messages until we are done or the other\n     * end has closed.\n     */\n    public void run() {\n        Pipeline hispipe = null;\n        // Create a pipeline to connect to our message parser.\n        hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout,\n                ((SIPTransactionStack) sipStack).getTimer());\n        // Create a pipelined message parser to read and parse\n        // messages that we write out to him.\n        myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize());\n        // Start running the parser thread.\n        myParser.processInput();\n        // bug fix by Emmanuel Proulx\n        int bufferSize = 4096;\n        this.tcpMessageProcessor.useCount++;\n        this.isRunning = true;\n        try {\n            while (true) {\n                try {\n                    byte[] msg = new byte[bufferSize];\n                    int nbytes = myClientInputStream.read(msg, 0, bufferSize);\n                    // no more bytes to read...\n                    if (nbytes == -1) {\n                        hispipe.write(\"\\r\\n\\r\\n\".getBytes(\"UTF-8\"));\n                        try {\n                            if (sipStack.maxConnections != -1) {\n                                synchronized (tcpMessageProcessor) {\n                                    tcpMessageProcessor.nConnections--;\n                                    tcpMessageProcessor.notify();\n                                }\n                            }\n                            hispipe.close();\n                            mySock.close();\n                        } catch (IOException ioex) {\n                        }\n                        return;\n                    }\n                    hispipe.write(msg, 0, nbytes);\n\n                } catch (IOException ex) {\n                    // Terminate the message.\n                    try {\n                        hispipe.write(\"\\r\\n\\r\\n\".getBytes(\"UTF-8\"));\n                    } catch (Exception e) {\n                        // InternalErrorHandler.handleException(e);\n                    }\n\n                    try {\n                        if (sipStack.isLoggingEnabled())\n                            sipStack.getStackLogger().logDebug(\"IOException  closing sock \" + ex);\n                        try {\n                            if (sipStack.maxConnections != -1) {\n                                synchronized (tcpMessageProcessor) {\n                                    tcpMessageProcessor.nConnections--;\n                                    // System.out.println(\"Notifying!\");\n                                    tcpMessageProcessor.notify();\n                                }\n                            }\n                            mySock.close();\n                            hispipe.close();\n                        } catch (IOException ioex) {\n                        }\n                    } catch (Exception ex1) {\n                        // Do nothing.\n                    }\n                    return;\n                } catch (Exception ex) {\n                    InternalErrorHandler.handleException(ex, sipStack.getStackLogger());\n                }\n            }\n        } finally {\n            this.isRunning = false;\n            this.tcpMessageProcessor.remove(this);\n            this.tcpMessageProcessor.useCount--;\n            myParser.close();\n        }\n\n    }\n\n    protected void uncache() {\n    \tif (isCached && !isRunning) {\n    \t\tthis.tcpMessageProcessor.remove(this);\n    \t}\n    }\n\n    /**\n     * Equals predicate.\n     * \n     * @param other is the other object to compare ourselves to for equals\n     */\n\n    public boolean equals(Object other) {\n\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        else {\n            TCPMessageChannel that = (TCPMessageChannel) other;\n            if (this.mySock != that.mySock)\n                return false;\n            else\n                return true;\n        }\n    }\n\n    /**\n     * Get an identifying key. This key is used to cache the connection and re-use it if\n     * necessary.\n     */\n    public String getKey() {\n        if (this.key != null) {\n            return this.key;\n        } else {\n            this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, \"TCP\");\n            return this.key;\n        }\n    }\n\n    /**\n     * Get the host to assign to outgoing messages.\n     * \n     * @return the host to assign to the via header.\n     */\n    public String getViaHost() {\n        return myAddress;\n    }\n\n    /**\n     * Get the port for outgoing messages sent from the channel.\n     * \n     * @return the port to assign to the via header.\n     */\n    public int getViaPort() {\n        return myPort;\n    }\n\n    /**\n     * Get the port of the peer to whom we are sending messages.\n     * \n     * @return the peer port.\n     */\n    public int getPeerPort() {\n        return peerPort;\n    }\n\n    public int getPeerPacketSourcePort() {\n        return this.peerPort;\n    }\n\n    public InetAddress getPeerPacketSourceAddress() {\n        return this.peerAddress;\n    }\n\n    /**\n     * TCP Is not a secure protocol.\n     */\n    public boolean isSecure() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/TCPMessageProcessor.java",
    "content": "/*\n * Conditions Of Use \n * \n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n * \n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n * \n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *  \n * .\n * \n */\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport java.net.Socket;\nimport java.net.ServerSocket;\nimport java.io.IOException;\nimport java.net.SocketException;\n\nimport gov2.nist.core.*;\n\nimport java.net.*;\nimport java.util.*;\n\n/*\n * Acknowledgement: Jeff Keyser suggested that a Stop mechanism be added to this. Niklas Uhrberg\n * suggested that a means to limit the number of simultaneous active connections should be added.\n * Mike Andrews suggested that the thread be accessible so as to implement clean stop using\n * Thread.join(). Roger M. Persson contributed a bug fix for cleanup on stop().\n * \n */\n\n/**\n * Sit in a loop waiting for incoming tcp connections and start a new thread to handle each new\n * connection. This is the active object that creates new TCP MessageChannels (one for each new\n * accept socket).\n * \n * @version 1.2 $Revision: 1.31 $ $Date: 2009/08/31 16:18:00 $\n * \n * @author M. Ranganathan <br/>\n * \n * \n */\npublic class TCPMessageProcessor extends MessageProcessor {\n\n    protected int nConnections;\n\n    private boolean isRunning;\n\n    private Hashtable tcpMessageChannels;\n\n    private ArrayList<TCPMessageChannel> incomingTcpMessageChannels;\n\n    private ServerSocket sock;\n\n    protected int useCount;\n\n    /**\n     * Constructor.\n     * \n     * @param sipStack SIPStack structure.\n     * @param port port where this message processor listens.\n     */\n    protected TCPMessageProcessor(InetAddress ipAddress, SIPTransactionStack sipStack, int port) {\n        super(ipAddress, port, \"tcp\",sipStack);\n\n        this.sipStack = sipStack;\n\n        this.tcpMessageChannels = new Hashtable();\n        this.incomingTcpMessageChannels = new ArrayList<TCPMessageChannel>();\n    }\n\n    /**\n     * Start the processor.\n     */\n    public void start() throws IOException {\n        Thread thread = new Thread(this);\n        thread.setName(\"TCPMessageProcessorThread\");\n        thread.setPriority(Thread.MAX_PRIORITY);\n        thread.setDaemon(true);\n        this.sock = sipStack.getNetworkLayer().createServerSocket(getPort(), 0, getIpAddress());\n        if (getIpAddress().getHostAddress().equals(IN_ADDR_ANY)\n                || getIpAddress().getHostAddress().equals(IN6_ADDR_ANY)) {\n            // Store the address to which we are actually bound\n            super.setIpAddress(sock.getInetAddress());\n\n        }\n        this.isRunning = true;\n        thread.start();\n\n    }\n\n    /**\n     * Run method for the thread that gets created for each accept socket.\n     */\n    public void run() {\n        // Accept new connectins on our socket.\n        while (this.isRunning) {\n            try {\n                synchronized (this) {\n                    // sipStack.maxConnections == -1 means we are\n                    // willing to handle an \"infinite\" number of\n                    // simultaneous connections (no resource limitation).\n                    // This is the default behavior.\n                    while (sipStack.maxConnections != -1\n                            && this.nConnections >= sipStack.maxConnections) {\n                        try {\n                            this.wait();\n\n                            if (!this.isRunning)\n                                return;\n                        } catch (InterruptedException ex) {\n                            break;\n                        }\n                    }\n                    this.nConnections++;\n                }\n\n                Socket newsock = sock.accept();\n                if (sipStack.isLoggingEnabled()) {\n                    getSIPStack().getStackLogger().logDebug(\"Accepting new connection!\");\n                }\n                // Note that for an incoming message channel, the\n                // thread is already running\n               \n                incomingTcpMessageChannels.add(new TCPMessageChannel(newsock, sipStack, this));\n            } catch (SocketException ex) {\n                this.isRunning = false;\n            } catch (IOException ex) {\n                // Problem accepting connection.\n                if (sipStack.isLoggingEnabled())\n                    getSIPStack().getStackLogger().logException(ex);\n                continue;\n            } catch (Exception ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n        }\n    }\n\n    /**\n     * Return the transport string.\n     * \n     * @return the transport string\n     */\n    public String getTransport() {\n        return \"tcp\";\n    }\n\n    /**\n     * Returns the stack.\n     * \n     * @return my sip stack.\n     */\n    public SIPTransactionStack getSIPStack() {\n        return sipStack;\n    }\n\n    /**\n     * Stop the message processor. Feature suggested by Jeff Keyser.\n     */\n    public synchronized void stop() {\n        isRunning = false;\n        // this.listeningPoint = null;\n        try {\n            sock.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        Collection en = tcpMessageChannels.values();\n        for (Iterator it = en.iterator(); it.hasNext();) {\n            TCPMessageChannel next = (TCPMessageChannel) it.next();\n            next.close();\n        }\n        // RRPN: fix\n        for (Iterator incomingMCIterator = incomingTcpMessageChannels.iterator(); incomingMCIterator\n                .hasNext();) {\n            TCPMessageChannel next = (TCPMessageChannel) incomingMCIterator.next();\n            next.close();\n        }\n\n        this.notify();\n    }\n\n    protected synchronized void remove(TCPMessageChannel tcpMessageChannel) {\n\n        String key = tcpMessageChannel.getKey();\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(Thread.currentThread() + \" removing \" + key);\n        }\n\n        /** May have been removed already */\n        if (tcpMessageChannels.get(key) == tcpMessageChannel) {\n            this.tcpMessageChannels.remove(key);\n        }\n\n        incomingTcpMessageChannels.remove(tcpMessageChannel);\n    }\n\n    public synchronized MessageChannel createMessageChannel(HostPort targetHostPort)\n            throws IOException {\n        String key = MessageChannel.getKey(targetHostPort, \"TCP\");\n        if (tcpMessageChannels.get(key) != null) {\n            return (TCPMessageChannel) this.tcpMessageChannels.get(key);\n        } else {\n            TCPMessageChannel retval = new TCPMessageChannel(targetHostPort.getInetAddress(),\n                    targetHostPort.getPort(), sipStack, this);\n            this.tcpMessageChannels.put(key, retval);\n            retval.isCached = true;\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"key \" + key);\n                sipStack.getStackLogger().logDebug(\"Creating \" + retval);\n            }\n            return retval;\n        }\n    }\n\n    protected synchronized void cacheMessageChannel(TCPMessageChannel messageChannel) {\n        String key = messageChannel.getKey();\n        TCPMessageChannel currentChannel = (TCPMessageChannel) tcpMessageChannels.get(key);\n        if (currentChannel != null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Closing \" + key);\n            currentChannel.close();\n        }\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"Caching \" + key);\n        this.tcpMessageChannels.put(key, messageChannel);\n\n    }\n\n    public synchronized MessageChannel createMessageChannel(InetAddress host, int port)\n            throws IOException {\n        try {\n            String key = MessageChannel.getKey(host, port, \"TCP\");\n            if (tcpMessageChannels.get(key) != null) {\n                return (TCPMessageChannel) this.tcpMessageChannels.get(key);\n            } else {\n                TCPMessageChannel retval = new TCPMessageChannel(host, port, sipStack, this);\n                this.tcpMessageChannels.put(key, retval);\n                retval.isCached = true;\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\"key \" + key);\n                    sipStack.getStackLogger().logDebug(\"Creating \" + retval);\n                }\n                return retval;\n            }\n        } catch (UnknownHostException ex) {\n            throw new IOException(ex.getMessage());\n        }\n    }\n\n    /**\n     * TCP can handle an unlimited number of bytes.\n     */\n    public int getMaximumMessageSize() {\n        return Integer.MAX_VALUE;\n    }\n\n    public boolean inUse() {\n        return this.useCount != 0;\n    }\n\n    /**\n     * Default target port for TCP\n     */\n    public int getDefaultTargetPort() {\n        return 5060;\n    }\n\n    /**\n     * TCP is not a secure protocol.\n     */\n    public boolean isSecure() {\n        return false;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/TLSMessageChannel.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/* This class is entirely derived from TCPMessageChannel,\n * by making some minor changes. Daniel J. Martinez Manzano <dani@dif.um.es>\n * made these changes. Ahmet Uyar\n * <auyar@csit.fsu.edu>sent in a bug report for TCP operation of the\n * JAIN sipStack. Niklas Uhrberg suggested that a mechanism be added to\n * limit the number of simultaneous open connections. The TLS\n * Adaptations were contributed by Daniel Martinez. Hagai Sela\n * contributed a bug fix for symmetric nat. Jeroen van Bemmel\n * added compensation for buggy clients ( Microsoft RTC clients ).\n * Bug fixes by viswashanti.kadiyala@antepo.com, Joost Yervante Damand\n * Lamine Brahimi (IBM Zurich) sent in a bug fix - a thread was being uncessarily created.\n */\n\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.*;\nimport gov2.nist.javax2.sip.header.*;\nimport gov2.nist.javax2.sip.message.*;\nimport gov2.nist.javax2.sip.parser.*;\n\nimport java.net.*;\nimport java.io.*;\nimport java.text.ParseException;\n\nimport javax.net.ssl.HandshakeCompletedListener;\nimport javax.net.ssl.SSLSocket;\nimport javax2.sip.address.Hop;\nimport javax2.sip.message.Response;\n\n/**\n * This is sipStack for TLS connections. This abstracts a stream of parsed messages. The SIP\n * sipStack starts this from the main SIPStack class for each connection that it accepts. It\n * starts a message parser in its own thread and talks to the message parser via a pipe. The\n * message parser calls back via the parseError or processMessage functions that are defined as\n * part of the SIPMessageListener interface.\n *\n * @see gov2.nist.javax2.sip.parser.PipelinedMsgParser\n *\n *\n * @author M. Ranganathan\n *\n *\n * @version 1.2 $Revision: 1.27 $ $Date: 2010/01/10 00:13:14 $\n */\npublic final class TLSMessageChannel extends MessageChannel implements SIPMessageListener,\n        Runnable, RawMessageChannel {\n\n    private Socket mySock;\n\n    private PipelinedMsgParser myParser;\n\n    private InputStream myClientInputStream; // just to pass to thread.\n\n    private String key;\n\n    protected boolean isCached;\n\n    protected boolean isRunning;\n\n    private Thread mythread;\n\n    private String myAddress;\n\n    private int myPort;\n\n    private InetAddress peerAddress;\n\n    private int peerPort;\n\n    private String peerProtocol;\n\n    // Incremented whenever a transaction gets assigned\n    // to the message channel and decremented when\n    // a transaction gets freed from the message channel.\n    // protected int useCount = 0;\n\n    private TLSMessageProcessor tlsMessageProcessor;\n\n    private SIPTransactionStack sipStack;\n\n    private HandshakeCompletedListener handshakeCompletedListener;\n\n    /**\n     * Constructor - gets called from the SIPStack class with a socket on accepting a new client.\n     * All the processing of the message is done here with the sipStack being freed up to handle\n     * new connections. The sock input is the socket that is returned from the accept. Global data\n     * that is shared by all threads is accessible in the Server structure.\n     *\n     * @param sock Socket from which to read and write messages. The socket is already connected\n     *        (was created as a result of an accept).\n     *\n     * @param sipStack Ptr to SIP Stack\n     *\n     * @param msgProcessor -- the message processor that created us.\n     */\n\n    protected TLSMessageChannel(Socket sock, SIPTransactionStack sipStack,\n            TLSMessageProcessor msgProcessor) throws IOException {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"creating new TLSMessageChannel (incoming)\");\n            sipStack.getStackLogger().logStackTrace();\n        }\n\n        mySock = (SSLSocket) sock;\n        if ( sock instanceof SSLSocket ) {\n            \n            SSLSocket sslSock = (SSLSocket) sock;\n            sslSock.setNeedClientAuth(true);\n            this.handshakeCompletedListener = new HandshakeCompletedListenerImpl(this);\n            sslSock.addHandshakeCompletedListener(this.handshakeCompletedListener);\n            sslSock.startHandshake();\n       \n        }\n        \n        peerAddress = mySock.getInetAddress();\n        myAddress = msgProcessor.getIpAddress().getHostAddress();\n        myClientInputStream = mySock.getInputStream();\n\n        mythread = new Thread(this);\n        mythread.setDaemon(true);\n        mythread.setName(\"TLSMessageChannelThread\");\n        // Stash away a pointer to our sipStack structure.\n        this.sipStack = sipStack;\n\n        this.tlsMessageProcessor = msgProcessor;\n        this.myPort = this.tlsMessageProcessor.getPort();\n        this.peerPort = mySock.getPort();\n        // Bug report by Vishwashanti Raj Kadiayl\n        super.messageProcessor = msgProcessor;\n        // Can drop this after response is sent potentially.\n        mythread.start();\n    }\n\n    /**\n     * Constructor - connects to the given inet address.\n     *\n     * @param inetAddr inet address to connect to.\n     * @param sipStack is the sip sipStack from which we are created.\n     * @param messageProcessor -- the message processor that created us.\n     * @throws IOException if we cannot connect.\n     */\n    protected TLSMessageChannel(InetAddress inetAddr, int port, SIPTransactionStack sipStack,\n            TLSMessageProcessor messageProcessor) throws IOException {\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(\"creating new TLSMessageChannel (outgoing)\");\n            sipStack.getStackLogger().logStackTrace();\n        }\n        this.peerAddress = inetAddr;\n        this.peerPort = port;\n        this.myPort = messageProcessor.getPort();\n        this.peerProtocol = \"TLS\";\n        this.sipStack = sipStack;\n        this.tlsMessageProcessor = messageProcessor;\n        this.myAddress = messageProcessor.getIpAddress().getHostAddress();\n        this.key = MessageChannel.getKey(peerAddress, peerPort, \"TLS\");\n        super.messageProcessor = messageProcessor;\n\n    }\n\n    /**\n     * Returns \"true\" as this is a reliable transport.\n     */\n    public boolean isReliable() {\n        return true;\n    }\n\n    /**\n     * Close the message channel.\n     */\n    public void close() {\n        try {\n            if (mySock != null)\n                mySock.close();\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Closing message Channel \" + this);\n        } catch (IOException ex) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Error closing socket \" + ex);\n        }\n    }\n\n    /**\n     * Get my SIP Stack.\n     *\n     * @return The SIP Stack for this message channel.\n     */\n    public SIPTransactionStack getSIPStack() {\n        return sipStack;\n    }\n\n    /**\n     * get the transport string.\n     *\n     * @return \"tcp\" in this case.\n     */\n    public String getTransport() {\n        return \"tls\";\n    }\n\n    /**\n     * get the address of the client that sent the data to us.\n     *\n     * @return Address of the client that sent us data that resulted in this channel being\n     *         created.\n     */\n    public String getPeerAddress() {\n        if (peerAddress != null) {\n            return peerAddress.getHostAddress();\n        } else\n            return getHost();\n    }\n\n    protected InetAddress getPeerInetAddress() {\n        return peerAddress;\n    }\n\n    public String getPeerProtocol() {\n        return this.peerProtocol;\n    }\n\n    /**\n     * Send message to whoever is connected to us. Uses the topmost via address to send to.\n     *\n     * @param message is the message to send.\n     * @param retry\n     */\n    private void sendMessage(SIPMessage message, boolean retry) throws IOException {\n        Socket sock = this.sipStack.ioHandler.sendBytes(\n                this.getMessageProcessor().getIpAddress(), this.peerAddress, this.peerPort,\n                this.peerProtocol, message, retry,this);\n        // Created a new socket so close the old one and stick the new\n        // one in its place but dont do this if it is a datagram socket.\n        // (could have replied via udp but received via tcp!).\n        if (sock != mySock && sock != null) {\n            try {\n                if (mySock != null)\n                    mySock.close();\n            } catch (IOException ex) {\n            }\n            mySock = sock;\n            this.myClientInputStream = mySock.getInputStream();\n\n            Thread thread = new Thread(this);\n            thread.setDaemon(true);\n            thread.setName(\"TLSMessageChannelThread\");\n            thread.start();\n        }\n\n    }\n\n    /**\n     * Return a formatted message to the client. We try to re-connect with the peer on the other\n     * end if possible.\n     *\n     * @param sipMessage Message to send.\n     * @throws IOException If there is an error sending the message\n     */\n    public void sendMessage(SIPMessage sipMessage) throws IOException {\n\n        long time = System.currentTimeMillis();\n\n        this.sendMessage(sipMessage, sipMessage instanceof SIPRequest);\n\n        if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES))\n            logMessage(sipMessage, peerAddress, peerPort, time);\n    }\n\n    /**\n     * Send a message to a specified address.\n     *\n     * @param message message to send.\n     * @param receiverAddress Address to send it to.\n     * @param receiverPort Receiver port.\n     * @throws IOException If there is a problem connecting or sending.\n     */\n    public void sendMessage(SIPMessage message, InetAddress receiverAddress, int receiverPort,\n            boolean retry) throws IOException {\n        if (message == null || receiverAddress == null)\n            throw new IllegalArgumentException(\"Null argument\");\n        Socket sock = this.sipStack.ioHandler.sendBytes(this.messageProcessor.getIpAddress(),\n                receiverAddress, receiverPort, \"TLS\", message, retry, this);\n        //\n        // Created a new socket so close the old one and s\n        // Check for null (bug fix sent in by Christophe)\n        if (sock != mySock && sock != null) {\n            try {\n                if (mySock != null)\n                    mySock.close();\n            } catch (IOException ex) {\n                /* ignore */\n            }\n            mySock = sock;\n            this.myClientInputStream = mySock.getInputStream();\n\n            // start a new reader on this end of the pipe.\n            Thread mythread = new Thread(this);\n            mythread.setDaemon(true);\n            mythread.setName(\"TLSMessageChannelThread\");\n            mythread.start();\n        }\n\n    }\n\n    /**\n     * Exception processor for exceptions detected from the parser. (This is invoked by the parser\n     * when an error is detected).\n     *\n     * @param sipMessage -- the message that incurred the error.\n     * @param ex -- parse exception detected by the parser.\n     * @param header -- header that caused the error.\n     * @throws ParseException Thrown if we want to reject the message.\n     */\n    public void handleException(ParseException ex, SIPMessage sipMessage, Class hdrClass,\n            String header, String message) throws ParseException {\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logException(ex);\n        // Log the bad message for later reference.\n        if ((hdrClass != null)\n                && (hdrClass.equals(From.class) || hdrClass.equals(To.class)\n                        || hdrClass.equals(CSeq.class) || hdrClass.equals(Via.class)\n                        || hdrClass.equals(CallID.class) || hdrClass.equals(RequestLine.class) || hdrClass\n                        .equals(StatusLine.class))) {\n        \tif (sipStack.isLoggingEnabled())\n        \t\tsipStack.getStackLogger().logDebug(\"Encountered bad message \\n\" + message);\n            // JvB: send a 400 response for requests (except ACK)\n            String msgString = sipMessage.toString();\n            if (!msgString.startsWith(\"SIP/\") && !msgString.startsWith(\"ACK \")) {\n\n                SIPMessage badReqRes = createBadReqRes(msgString, ex);\n                if (badReqRes != null) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\"Sending automatic 400 Bad Request:\");\n                        sipStack.getStackLogger().logDebug(msgString);\n                    }\n                    try {\n                        this.sendMessage(badReqRes, this.getPeerInetAddress(), this\n                                .getPeerPort(), false);\n                    } catch (IOException e) {\n                        if (sipStack.isLoggingEnabled())\n                        \tthis.sipStack.getStackLogger().logException(e);\n                    }\n                } else {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Could not formulate automatic 400 Bad Request\");\n                    }\n                }\n            }\n            throw ex;\n        } else {\n            sipMessage.addUnparsed(header);\n        }\n    }\n\n    /**\n     * Gets invoked by the parser as a callback on successful message parsing (i.e. no parser\n     * errors).\n     *\n     * @param sipMessage Message to process (this calls the application for processing the\n     *        message).\n     *\n     * Jvb: note that this code is identical to TCPMessageChannel, refactor some day\n     */\n    public void processMessage(SIPMessage sipMessage) throws Exception {\n        try {\n            if (sipMessage.getFrom() == null || sipMessage.getTo() == null\n                    || sipMessage.getCallId() == null || sipMessage.getCSeq() == null\n                    || sipMessage.getViaHeaders() == null) {\n                String badmsg = sipMessage.encode();\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logError(\"bad message \" + badmsg);\n                    sipStack.getStackLogger().logError(\">>> Dropped Bad Msg\");\n                }\n                return;\n            }\n\n            ViaList viaList = sipMessage.getViaHeaders();\n            // For a request\n            // first via header tells where the message is coming from.\n            // For response, this has already been recorded in the outgoing\n            // message.\n\n            if (sipMessage instanceof SIPRequest) {\n                Via v = (Via) viaList.getFirst();\n                // the peer address and tag it appropriately.\n                Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());\n                this.peerProtocol = v.getTransport();\n                try {\n                    this.peerAddress = mySock.getInetAddress();\n                    // Check to see if the received parameter matches\n                    // JvB: dont do this. It is both costly and incorrect\n                    // Must set received also when it is a FQDN, regardless whether\n                    // it resolves to the correct IP address\n                    // InetAddress sentByAddress = InetAddress.getByName(hop.getHost());\n                    // JvB: if sender added 'rport', must always set received\n                    if (v.hasParameter(Via.RPORT)\n                            || !hop.getHost().equals(this.peerAddress.getHostAddress())) {\n                        v.setParameter(Via.RECEIVED, this.peerAddress.getHostAddress());\n                    }\n                    // @@@ hagai\n                    // JvB: technically, may only do this when Via already contains\n                    // rport\n                    v.setParameter(Via.RPORT, Integer.toString(this.peerPort));\n                } catch (java.text.ParseException ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n                // Use this for outgoing messages as well.\n                if (!this.isCached) {\n                    ((TLSMessageProcessor) this.messageProcessor).cacheMessageChannel(this);\n                    this.isCached = true;\n                    String key = IOHandler.makeKey(mySock.getInetAddress(), this.peerPort);\n                    sipStack.ioHandler.putSocket(key, mySock);\n                }\n            }\n\n            // Foreach part of the request header, fetch it and process it\n\n            long receptionTime = System.currentTimeMillis();\n            //\n\n            if (sipMessage instanceof SIPRequest) {\n                // This is a request - process the request.\n                SIPRequest sipRequest = (SIPRequest) sipMessage;\n                // Create a new sever side request processor for this\n                // message and let it handle the rest.\n\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\"----Processing Message---\");\n                }\n                if (this.sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {\n\n                    sipStack.serverLogger.logMessage(sipMessage, this.getPeerHostPort().toString(),\n                            this.messageProcessor.getIpAddress().getHostAddress() + \":\"\n                                    + this.messageProcessor.getPort(), false, receptionTime);\n\n                }\n                // Check for reasonable size - reject message\n                // if it is too long.\n                if (sipStack.getMaxMessageSize() > 0\n                        && sipRequest.getSize()\n                                + (sipRequest.getContentLength() == null ? 0 : sipRequest\n                                        .getContentLength().getContentLength()) > sipStack\n                                .getMaxMessageSize()) {\n                    SIPResponse sipResponse = sipRequest\n                            .createResponse(SIPResponse.MESSAGE_TOO_LARGE);\n                    this.sendMessage(sipResponse, false);\n                    throw new Exception(\"Message size exceeded\");\n                }\n\n                // Stack could not create a new server request interface.\n                // maybe not enough resources.\n                ServerRequestInterface sipServerRequest = sipStack.newSIPServerRequest(\n                        sipRequest, this);\n                if (sipServerRequest != null) {\n                    try {\n                        sipServerRequest.processRequest(sipRequest, this);\n                    } finally {\n                        if (sipServerRequest instanceof SIPTransaction) {\n                            SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;\n                            if (!sipServerTx.passToListener())\n                                ((SIPTransaction) sipServerRequest).releaseSem();\n                        }\n                    }\n                } else {\n                    SIPResponse response = sipRequest\n                            .createResponse(Response.SERVICE_UNAVAILABLE);\n\n                    RetryAfter retryAfter = new RetryAfter();\n\n                    // Be a good citizen and send a decent response code back.\n                    try {\n                        retryAfter.setRetryAfter((int) (10 * (Math.random())));\n                        response.setHeader(retryAfter);\n                        this.sendMessage(response);\n                    } catch (Exception e) {\n                        // IGNore\n                    }\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger()\n                            .logWarning(\"Dropping message -- could not acquire semaphore\");\n                }\n            } else {\n                SIPResponse sipResponse = (SIPResponse) sipMessage;\n                try {\n                    sipResponse.checkHeaders();\n                } catch (ParseException ex) {\n                    if (sipStack.isLoggingEnabled())\n                        sipStack.getStackLogger()\n                                .logError(\"Dropping Badly formatted response message >>> \"\n                                        + sipResponse);\n                    return;\n                }\n                // This is a response message - process it.\n                // Check the size of the response.\n                // If it is too large dump it silently.\n                if (sipStack.getMaxMessageSize() > 0\n                        && sipResponse.getSize()\n                                + (sipResponse.getContentLength() == null ? 0 : sipResponse\n                                        .getContentLength().getContentLength()) > sipStack\n                                .getMaxMessageSize()) {\n                    if (sipStack.isLoggingEnabled())\n                        this.sipStack.getStackLogger().logDebug(\"Message size exceeded\");\n                    return;\n\n                }\n                ServerResponseInterface sipServerResponse = sipStack.newSIPServerResponse(\n                        sipResponse, this);\n                if (sipServerResponse != null) {\n                    try {\n                        if (sipServerResponse instanceof SIPClientTransaction\n                                && !((SIPClientTransaction) sipServerResponse)\n                                        .checkFromTag(sipResponse)) {\n                            if (sipStack.isLoggingEnabled())\n                                sipStack.getStackLogger()\n                                        .logError(\"Dropping response message with invalid tag >>> \"\n                                                + sipResponse);\n                            return;\n                        }\n\n                        sipServerResponse.processResponse(sipResponse, this);\n                    } finally {\n                        if (sipServerResponse instanceof SIPTransaction\n                                && !((SIPTransaction) sipServerResponse).passToListener()) {\n                            // Note that the semaphore is released in event\n                            // scanner if the\n                            // request is actually processed by the Listener.\n                            ((SIPTransaction) sipServerResponse).releaseSem();\n                        }\n                    }\n                } else {\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger().logWarning(\"Could not get semaphore... dropping response\");\n                }\n            }\n        } finally {\n        }\n    }\n\n    /**\n     * This gets invoked when thread.start is called from the constructor. Implements a message\n     * loop - reading the tcp connection and processing messages until we are done or the other\n     * end has closed.\n     */\n    public void run() {\n        Pipeline hispipe = null;\n        // Create a pipeline to connect to our message parser.\n        hispipe = new Pipeline(myClientInputStream, sipStack.readTimeout,\n                ((SIPTransactionStack) sipStack).getTimer());\n        // Create a pipelined message parser to read and parse\n        // messages that we write out to him.\n        myParser = new PipelinedMsgParser(this, hispipe, this.sipStack.getMaxMessageSize());\n        // Start running the parser thread.\n        myParser.processInput();\n        // bug fix by Emmanuel Proulx\n        int bufferSize = 4096;\n        this.tlsMessageProcessor.useCount++;\n        this.isRunning = true;\n        try {\n            while (true) {\n                try {\n                    byte[] msg = new byte[bufferSize];\n                    int nbytes = myClientInputStream.read(msg, 0, bufferSize);\n                    // no more bytes to read...\n                    if (nbytes == -1) {\n                        hispipe.write(\"\\r\\n\\r\\n\".getBytes(\"UTF-8\"));\n                        try {\n                            if (sipStack.maxConnections != -1) {\n                                synchronized (tlsMessageProcessor) {\n                                    tlsMessageProcessor.nConnections--;\n                                    tlsMessageProcessor.notify();\n                                }\n                            }\n                            hispipe.close();\n                            mySock.close();\n                        } catch (IOException ioex) {\n                        }\n                        return;\n                    }\n                    hispipe.write(msg, 0, nbytes);\n\n                } catch (IOException ex) {\n                    // Terminate the message.\n                    try {\n                        hispipe.write(\"\\r\\n\\r\\n\".getBytes(\"UTF-8\"));\n                    } catch (Exception e) {\n                        // InternalErrorHandler.handleException(e);\n                    }\n\n                    try {\n                        if (sipStack.isLoggingEnabled())\n                            sipStack.getStackLogger().logDebug(\"IOException  closing sock \" + ex);\n                        try {\n                            if (sipStack.maxConnections != -1) {\n                                synchronized (tlsMessageProcessor) {\n                                    tlsMessageProcessor.nConnections--;\n                                    tlsMessageProcessor.notify();\n                                }\n                            }\n                            mySock.close();\n                            hispipe.close();\n                        } catch (IOException ioex) {\n                        }\n                    } catch (Exception ex1) {\n                        // Do nothing.\n                    }\n                    return;\n                } catch (Exception ex) {\n                    InternalErrorHandler.handleException(ex);\n                }\n            }\n        } finally {\n            this.isRunning = false;\n            this.tlsMessageProcessor.remove(this);\n            this.tlsMessageProcessor.useCount--;\n            this.myParser.close();\n        }\n\n    }\n\n    protected void uncache() {\n    \tif (isCached && !isRunning) {    \t\n    \t\tthis.tlsMessageProcessor.remove(this);\n    \t}\n    }\n\n    /**\n     * Equals predicate.\n     *\n     * @param other is the other object to compare ourselves to for equals\n     */\n\n    public boolean equals(Object other) {\n\n        if (!this.getClass().equals(other.getClass()))\n            return false;\n        else {\n            TLSMessageChannel that = (TLSMessageChannel) other;\n            if (this.mySock != that.mySock)\n                return false;\n            else\n                return true;\n        }\n    }\n\n    /**\n     * Get an identifying key. This key is used to cache the connection and re-use it if\n     * necessary.\n     */\n    public String getKey() {\n        if (this.key != null) {\n            return this.key;\n        } else {\n            this.key = MessageChannel.getKey(this.peerAddress, this.peerPort, \"TLS\");\n            return this.key;\n        }\n    }\n\n    /**\n     * Get the host to assign to outgoing messages.\n     *\n     * @return the host to assign to the via header.\n     */\n    public String getViaHost() {\n        return myAddress;\n    }\n\n    /**\n     * Get the port for outgoing messages sent from the channel.\n     *\n     * @return the port to assign to the via header.\n     */\n    public int getViaPort() {\n        return myPort;\n    }\n\n    /**\n     * Get the port of the peer to whom we are sending messages.\n     *\n     * @return the peer port.\n     */\n    public int getPeerPort() {\n        return peerPort;\n    }\n\n    public int getPeerPacketSourcePort() {\n        return this.peerPort;\n    }\n\n    public InetAddress getPeerPacketSourceAddress() {\n        return this.peerAddress;\n    }\n\n    /**\n     * TLS Is a secure protocol.\n     */\n    public boolean isSecure() {\n        return true;\n    }\n\n    public void setHandshakeCompletedListener(\n            HandshakeCompletedListener handshakeCompletedListenerImpl) {\n        this.handshakeCompletedListener = handshakeCompletedListenerImpl;\n    }\n\n    /**\n     * @return the handshakeCompletedListener\n     */\n    public HandshakeCompletedListenerImpl getHandshakeCompletedListener() {\n        return (HandshakeCompletedListenerImpl) handshakeCompletedListener;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/TLSMessageProcessor.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/* This class is entirely derived from TCPMessageProcessor,\n *  by making some minor changes.\n *\n *               Daniel J. Martinez Manzano <dani@dif.um.es>\n * Acknowledgement: Jeff Keyser suggested that a\n * Stop mechanism be added to this. Niklas Uhrberg suggested that\n * a means to limit the number of simultaneous active connections\n * should be added. Mike Andrews suggested that the thread be\n * accessible so as to implement clean stop using Thread.join().\n *\n */\n\n/******************************************************************************\n * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).      *\n ******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.HostPort;\nimport gov2.nist.javax2.sip.SipStackImpl;\n\nimport javax.net.ssl.SSLException;\nimport javax.net.ssl.SSLServerSocket;\nimport javax.net.ssl.SSLSocket;\n\nimport java.io.IOException;\nimport java.net.*;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Hashtable;\nimport java.util.Iterator;\n\n/**\n * Sit in a loop waiting for incoming tls connections and start a new thread to handle each new\n * connection. This is the active object that creates new TLS MessageChannels (one for each new\n * accept socket).\n * \n * @version 1.2 $Revision: 1.23 $ $Date: 2009/12/06 15:58:39 $\n * \n * @author M. Ranganathan <br/>\n * \n */\npublic class TLSMessageProcessor extends MessageProcessor {\n\n    protected int nConnections;\n\n    private boolean isRunning;\n\n    private Hashtable<String, TLSMessageChannel> tlsMessageChannels;\n\n    private ServerSocket sock;\n\n    protected int useCount = 0;\n\n    private ArrayList<TLSMessageChannel> incomingTlsMessageChannels;\n\n    /**\n     * Constructor.\n     * \n     * @param ipAddress -- inet address where I am listening.\n     * @param sipStack SIPStack structure.\n     * @param port port where this message processor listens.\n     */\n    protected TLSMessageProcessor(InetAddress ipAddress, SIPTransactionStack sipStack, int port) {\n        super(ipAddress, port, \"tls\",sipStack);\n        this.sipStack = sipStack;\n        this.tlsMessageChannels = new Hashtable<String, TLSMessageChannel>();\n        this.incomingTlsMessageChannels = new ArrayList<TLSMessageChannel>();\n\n    }\n\n    /**\n     * Start the processor.\n     */\n    public void start() throws IOException {\n        Thread thread = new Thread(this);\n        thread.setName(\"TLSMessageProcessorThread\");\n        // ISSUE 184\n        thread.setPriority(Thread.MAX_PRIORITY);\n        thread.setDaemon(true);\n\n        this.sock = sipStack.getNetworkLayer().createSSLServerSocket(this.getPort(), 0,\n                this.getIpAddress());\n        ((SSLServerSocket) this.sock).setNeedClientAuth(false);\n        ((SSLServerSocket) this.sock).setUseClientMode(false);\n        ((SSLServerSocket) this.sock).setWantClientAuth(true);\n        String []enabledCiphers = ((SipStackImpl)sipStack).getEnabledCipherSuites();\n        ((SSLServerSocket) this.sock).setEnabledCipherSuites(enabledCiphers);\n        ((SSLServerSocket)this.sock).setWantClientAuth(true);\n\n\n        this.isRunning = true;\n        thread.start();\n\n    }\n\n    /**\n     * Run method for the thread that gets created for each accept socket.\n     */\n    public void run() {\n        // Accept new connectins on our socket.\n        while (this.isRunning) {\n            try {\n                synchronized (this) {\n                    // sipStack.maxConnections == -1 means we are\n                    // willing to handle an \"infinite\" number of\n                    // simultaneous connections (no resource limitation).\n                    // This is the default behavior.\n                    while (sipStack.maxConnections != -1\n                            && this.nConnections >= sipStack.maxConnections) {\n                        try {\n                            this.wait();\n\n                            if (!this.isRunning)\n                                return;\n                        } catch (InterruptedException ex) {\n                            break;\n                        }\n                    }\n                    this.nConnections++;\n                }\n\n                Socket newsock = sock.accept();\n               \n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger().logDebug(\"Accepting new connection!\");\n\n                \n               // Note that for an incoming message channel, the\n               // thread is already running\n\n                incomingTlsMessageChannels.add(new TLSMessageChannel(newsock, sipStack, this));\n            } catch (SocketException ex) {\n                if ( this.isRunning ) {\n                    if (sipStack.isLoggingEnabled())\n                    \tsipStack.getStackLogger().logError(\n                    \t\t\t\"Fatal - SocketException occured while Accepting connection\", ex);\n                  this.isRunning = false;\n                  break;\n                }\n            } catch (SSLException ex) {\n                this.isRunning = false;\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logError(\n                        \"Fatal - SSSLException occured while Accepting connection\", ex);\n                break;\n            } catch (IOException ex) {\n                // Problem accepting connection.\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logError(\"Problem Accepting Connection\", ex);\n                continue;\n            } catch (Exception ex) {\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logError(\"Unexpected Exception!\", ex);\n            }\n        }\n    }\n\n    /**\n     * Returns the stack.\n     * \n     * @return my sip stack.\n     */\n    public SIPTransactionStack getSIPStack() {\n        return sipStack;\n    }\n\n    /**\n     * Stop the message processor. Feature suggested by Jeff Keyser.\n     */\n    public synchronized void stop() {\n        if (!isRunning)\n            return;\n\n        isRunning = false;\n        try {\n            sock.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        Collection en = tlsMessageChannels.values();\n        for (Iterator it = en.iterator(); it.hasNext();) {\n            TLSMessageChannel next = (TLSMessageChannel) it.next();\n            next.close();\n        }\n        for (Iterator incomingMCIterator = incomingTlsMessageChannels.iterator(); incomingMCIterator\n                .hasNext();) {\n            TLSMessageChannel next = (TLSMessageChannel) incomingMCIterator.next();\n            next.close();\n        }\n        this.notify();\n\n    }\n\n    protected synchronized void remove(TLSMessageChannel tlsMessageChannel) {\n\n        String key = tlsMessageChannel.getKey();\n        if (sipStack.isLoggingEnabled()) {\n            sipStack.getStackLogger().logDebug(Thread.currentThread() + \" removing \" + key);\n        }\n\n        /** May have been removed already */\n        if (tlsMessageChannels.get(key) == tlsMessageChannel)\n            this.tlsMessageChannels.remove(key);\n        \n        incomingTlsMessageChannels.remove(tlsMessageChannel);\n    }\n\n    public synchronized MessageChannel createMessageChannel(HostPort targetHostPort)\n            throws IOException {\n        String key = MessageChannel.getKey(targetHostPort, \"TLS\");\n        if (tlsMessageChannels.get(key) != null) {\n            return (TLSMessageChannel) this.tlsMessageChannels.get(key);\n        } else {\n            TLSMessageChannel retval = new TLSMessageChannel(targetHostPort.getInetAddress(),\n                    targetHostPort.getPort(), sipStack, this);\n            this.tlsMessageChannels.put(key, retval);\n            retval.isCached = true;\n            if (sipStack.isLoggingEnabled()) {\n                sipStack.getStackLogger().logDebug(\"key \" + key);\n                sipStack.getStackLogger().logDebug(\"Creating \" + retval);\n            }\n            return retval;\n        }\n    }\n\n    protected synchronized void cacheMessageChannel(TLSMessageChannel messageChannel) {\n        String key = messageChannel.getKey();\n        TLSMessageChannel currentChannel = (TLSMessageChannel) tlsMessageChannels.get(key);\n        if (currentChannel != null) {\n            if (sipStack.isLoggingEnabled())\n                sipStack.getStackLogger().logDebug(\"Closing \" + key);\n            currentChannel.close();\n        }\n        if (sipStack.isLoggingEnabled())\n            sipStack.getStackLogger().logDebug(\"Caching \" + key);\n        this.tlsMessageChannels.put(key, messageChannel);\n\n    }\n\n    public synchronized MessageChannel createMessageChannel(InetAddress host, int port)\n            throws IOException {\n        try {\n            String key = MessageChannel.getKey(host, port, \"TLS\");\n            if (tlsMessageChannels.get(key) != null) {\n                return (TLSMessageChannel) this.tlsMessageChannels.get(key);\n            } else {\n                TLSMessageChannel retval = new TLSMessageChannel(host, port, sipStack, this);\n                this.tlsMessageChannels.put(key, retval);\n                retval.isCached = true;\n                if (sipStack.isLoggingEnabled()) {\n                    sipStack.getStackLogger().logDebug(\"key \" + key);\n                    sipStack.getStackLogger().logDebug(\"Creating \" + retval);\n                }\n                return retval;\n            }\n        } catch (UnknownHostException ex) {\n            throw new IOException(ex.getMessage());\n        }\n    }\n\n    /**\n     * TLS can handle an unlimited number of bytes.\n     */\n    public int getMaximumMessageSize() {\n        return Integer.MAX_VALUE;\n    }\n\n    public boolean inUse() {\n        return this.useCount != 0;\n    }\n\n    /**\n     * Default target port for TLS\n     */\n    public int getDefaultTargetPort() {\n        return 5061;\n    }\n\n    /**\n     * TLS is a secure protocol.\n     */\n    public boolean isSecure() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/UDPMessageChannel.java",
    "content": "/*\n * Conditions Of Use\n *\n * This software was developed by employees of the National Institute of\n * Standards and Technology (NIST), an agency of the Federal Government.\n * Pursuant to title 15 Untied States Code Section 105, works of NIST\n * employees are not subject to copyright protection in the United States\n * and are considered to be in the public domain.  As a result, a formal\n * license is not needed to use the software.\n *\n * This software is provided by NIST as a service and is expressly\n * provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n * AND DATA ACCURACY.  NIST does not warrant or make any representations\n * regarding the use of the software or the results thereof, including but\n * not limited to the correctness, accuracy, reliability or usefulness of\n * the software.\n *\n * Permission to use this software is contingent upon your acceptance\n * of the terms of this agreement\n *\n * .\n *\n */\n/*****************************************************************************\n *   Product of NIST/ITL Advanced Networking Technologies Division (ANTD).    *\n *****************************************************************************/\n\npackage gov2.nist.javax2.sip.stack;\n\nimport gov2.nist.core.InternalErrorHandler;\nimport gov2.nist.core.ServerLogger;\nimport gov2.nist.core.StackLogger;\nimport gov2.nist.core.ThreadAuditor;\nimport gov2.nist.javax2.sip.SIPConstants;\nimport gov2.nist.javax2.sip.header.CSeq;\nimport gov2.nist.javax2.sip.header.CallID;\nimport gov2.nist.javax2.sip.header.From;\nimport gov2.nist.javax2.sip.header.RequestLine;\nimport gov2.nist.javax2.sip.header.StatusLine;\nimport gov2.nist.javax2.sip.header.To;\nimport gov2.nist.javax2.sip.header.Via;\nimport gov2.nist.javax2.sip.header.ViaList;\nimport gov2.nist.javax2.sip.message.SIPMessage;\nimport gov2.nist.javax2.sip.message.SIPRequest;\nimport gov2.nist.javax2.sip.message.SIPResponse;\nimport gov2.nist.javax2.sip.parser.ParseExceptionListener;\nimport gov2.nist.javax2.sip.parser.StringMsgParser;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\nimport java.text.ParseException;\nimport java.util.Hashtable;\nimport java.util.TimerTask;\n\nimport javax2.sip.address.Hop;\n\n/*\n * Kim Kirby (Keyvoice) suggested that duplicate checking should be added to the\n * stack (later removed). Lamine Brahimi suggested a single threaded behavior\n * flag be added to this. Niklas Uhrberg suggested that thread pooling support\n * be added to this for performance and resource management. Peter Parnes found\n * a bug with this code that was sending it into an infinite loop when a bad\n * incoming message was parsed. Bug fix by viswashanti.kadiyala@antepo.com.\n * Hagai Sela addded fixes for NAT traversal. Jeroen van Bemmel fixed up for\n * buggy clients (such as windows messenger) and added code to return\n * BAD_REQUEST. David Alique fixed an address recording bug. Jeroen van Bemmel\n * fixed a performance issue where the stack was doing DNS lookups (potentially\n * unnecessary). Ricardo Bora (Natural Convergence ) added code that prevents\n * the stack from exitting when an exception is encountered.\n *\n */\n\n/**\n * This is the UDP Message handler that gets created when a UDP message needs to\n * be processed. The message is processed by creating a String Message parser\n * and invoking it on the message read from the UDP socket. The parsed structure\n * is handed off via a SIP stack request for further processing. This stack\n * structure isolates the message handling logic from the mechanics of sending\n * and recieving messages (which could be either udp or tcp.\n *\n *\n * @author M. Ranganathan <br/>\n *\n *\n *\n * @version 1.2 $Revision: 1.66 $ $Date: 2010/01/14 05:15:49 $\n */\npublic class UDPMessageChannel extends MessageChannel implements\n        ParseExceptionListener, Runnable, RawMessageChannel {\n    \n\n    /**\n     * SIP Stack structure for this channel.\n     */\n    protected SIPTransactionStack sipStack;\n\n    /**\n     * The parser we are using for messages received from this channel.\n     */\n    protected StringMsgParser myParser;\n\n    /**\n     * Where we got the stuff from\n     */\n    private InetAddress peerAddress;\n\n    private String myAddress;\n\n    private int peerPacketSourcePort;\n\n    private InetAddress peerPacketSourceAddress;\n\n    /**\n     * Reciever port -- port of the destination.\n     */\n    private int peerPort;\n\n    /**\n     * Protocol to use when talking to receiver (i.e. when sending replies).\n     */\n    private String peerProtocol;\n\n    protected int myPort;\n\n    private DatagramPacket incomingPacket;\n\n    private long receptionTime;\n    \n    /*\n     * A table that keeps track of when the last pingback was sent to a given remote IP address\n     * and port. This is for NAT compensation. This stays in the table for 1 seconds and prevents \n     * infinite loop. If a second pingback happens in that period of time, it will be dropped.\n     */\n    private Hashtable<String,PingBackTimerTask> pingBackRecord = new Hashtable<String,PingBackTimerTask>();\n    \n    class PingBackTimerTask extends TimerTask {\n        String ipAddress;\n        int port;\n        \n        public PingBackTimerTask(String ipAddress, int port) {\n            this.ipAddress = ipAddress;\n            this.port = port;\n            pingBackRecord.put(ipAddress + \":\" + port, this);\n        }\n        @Override\n        public void run() {\n           pingBackRecord.remove(ipAddress + \":\" + port);\n        }\n        @Override\n        public int hashCode() {\n            return (ipAddress + \":\" + port).hashCode();\n        }\n    }\n\n    /**\n     * Constructor - takes a datagram packet and a stack structure Extracts the\n     * address of the other from the datagram packet and stashes away the\n     * pointer to the passed stack structure.\n     *\n     * @param stack\n     *            is the shared SIPStack structure\n     * @param messageProcessor\n     *            is the creating message processor.\n     */\n    protected UDPMessageChannel(SIPTransactionStack stack,\n            UDPMessageProcessor messageProcessor) {\n        super.messageProcessor = messageProcessor;\n        this.sipStack = stack;\n\n        Thread mythread = new Thread(this);\n\n        this.myAddress = messageProcessor.getIpAddress().getHostAddress();\n        this.myPort = messageProcessor.getPort();\n\n        mythread.setName(\"UDPMessageChannelThread\");\n        mythread.setDaemon(true);\n        mythread.start();\n\n    }\n\n    /**\n     * Constructor. We create one of these in order to process an incoming\n     * message.\n     *\n     * @param stack\n     *            is the SIP sipStack.\n     * @param messageProcessor\n     *            is the creating message processor.\n     * @param packet\n     *            is the incoming datagram packet.\n     */\n    protected UDPMessageChannel(SIPTransactionStack stack,\n            UDPMessageProcessor messageProcessor, DatagramPacket packet) {\n\n        this.incomingPacket = packet;\n        super.messageProcessor = messageProcessor;\n        this.sipStack = stack;\n\n        this.myAddress = messageProcessor.getIpAddress().getHostAddress();\n        this.myPort = messageProcessor.getPort();\n        Thread mythread = new Thread(this);\n        mythread.setDaemon(true);\n        mythread.setName(\"UDPMessageChannelThread\");\n\n        mythread.start();\n\n    }\n\n    /**\n     * Constructor. We create one of these when we send out a message.\n     *\n     * @param targetAddr\n     *            INET address of the place where we want to send messages.\n     * @param port\n     *            target port (where we want to send the message).\n     * @param sipStack\n     *            our SIP Stack.\n     */\n    protected UDPMessageChannel(InetAddress targetAddr, int port,\n            SIPTransactionStack sipStack, UDPMessageProcessor messageProcessor) {\n        peerAddress = targetAddr;\n        peerPort = port;\n        peerProtocol = \"UDP\";\n        super.messageProcessor = messageProcessor;\n        this.myAddress = messageProcessor.getIpAddress().getHostAddress();\n        this.myPort = messageProcessor.getPort();\n        this.sipStack = sipStack;\n        if (sipStack.isLoggingEnabled()) {\n            this.sipStack.getStackLogger().logDebug(\"Creating message channel \"\n                    + targetAddr.getHostAddress() + \"/\" + port);\n        }\n    }\n\n    /**\n     * Run method specified by runnnable.\n     */\n    public void run() {\n        // Assume no thread pooling (bug fix by spierhj)\n        ThreadAuditor.ThreadHandle threadHandle = null;\n\n        while (true) {\n            // Create a new string message parser to parse the list of messages.\n            if (myParser == null) {\n                myParser = new StringMsgParser();\n                myParser.setParseExceptionListener(this);\n            }\n            // messages that we write out to him.\n            DatagramPacket packet;\n\n            if (sipStack.threadPoolSize != -1) {\n                synchronized (((UDPMessageProcessor) messageProcessor).messageQueue) {\n                    while (((UDPMessageProcessor) messageProcessor).messageQueue\n                            .isEmpty()) {\n                        // Check to see if we need to exit.\n                        if (!((UDPMessageProcessor) messageProcessor).isRunning)\n                            return;\n                        try {\n                            // We're part of a thread pool. Ask the auditor to\n                            // monitor this thread.\n                            if (threadHandle == null) {\n                                threadHandle = sipStack.getThreadAuditor()\n                                        .addCurrentThread();\n                            }\n\n                            // Send a heartbeat to the thread auditor\n                            threadHandle.ping();\n\n                            // Wait for packets\n                            // Note: getPingInterval returns 0 (infinite) if the\n                            // thread auditor is disabled.\n                            ((UDPMessageProcessor) messageProcessor).messageQueue\n                                    .wait(threadHandle\n                                            .getPingIntervalInMillisecs());\n                        } catch (InterruptedException ex) {\n                            if (!((UDPMessageProcessor) messageProcessor).isRunning)\n                                return;\n                        }\n                    }\n                    packet = (DatagramPacket) ((UDPMessageProcessor) messageProcessor).messageQueue\n                            .removeFirst();\n\n                }\n                this.incomingPacket = packet;\n            } else {\n                packet = this.incomingPacket;\n            }\n\n            // Process the packet. Catch and log any exception we may throw.\n            try {\n                processIncomingDataPacket(packet);\n            } catch (Exception e) {\n\n                if (sipStack.isLoggingEnabled())\n                \tsipStack.getStackLogger().logError(\n                        \"Error while processing incoming UDP packet\", e);\n            }\n\n            if (sipStack.threadPoolSize == -1) {\n                return;\n            }\n        }\n    }\n\n    /**\n     * Process an incoming datagram\n     *\n     * @param packet\n     *            is the incoming datagram packet.\n     */\n    private void processIncomingDataPacket(DatagramPacket packet)\n            throws Exception {\n        this.peerAddress = packet.getAddress();\n        int packetLength = packet.getLength();\n        // Read bytes and put it in a eueue.\n        byte[] bytes = packet.getData();\n        byte[] msgBytes = new byte[packetLength];\n        System.arraycopy(bytes, 0, msgBytes, 0, packetLength);\n\n        // Do debug logging.\n        if (sipStack.isLoggingEnabled()) {\n            this.sipStack.getStackLogger()\n                    .logDebug(\"UDPMessageChannel: processIncomingDataPacket : peerAddress = \"\n                            + peerAddress.getHostAddress() + \"/\"\n                            + packet.getPort() + \" Length = \" + packetLength);\n\n        }\n\n        SIPMessage sipMessage = null;\n        try {\n            this.receptionTime = System.currentTimeMillis();\n            sipMessage = myParser.parseSIPMessage(msgBytes);\n            myParser = null;\n        } catch (ParseException ex) {\n            myParser = null; // let go of the parser reference.\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logDebug(\"Rejecting message !  \"\n                        + new String(msgBytes));\n                this.sipStack.getStackLogger().logDebug(\"error message \"\n                        + ex.getMessage());\n                this.sipStack.getStackLogger().logException(ex);\n            }\n\n\n            // JvB: send a 400 response for requests (except ACK)\n            // Currently only UDP, @todo also other transports\n            String msgString = new String(msgBytes, 0, packetLength);\n            if (!msgString.startsWith(\"SIP/\") && !msgString.startsWith(\"ACK \")) {\n\n                SIPMessage badReqRes = createBadReqRes(msgString, ex);\n                if (badReqRes != null) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\n                                \"Sending automatic 400 Bad Request:\");\n                        sipStack.getStackLogger().logDebug(msgString);\n                    }\n                    try {\n                        this.sendMessage(badReqRes, peerAddress,\n                                packet.getPort(), \"UDP\", false);\n                    } catch (IOException e) {\n                        if (sipStack.isLoggingEnabled())\n                        \tthis.sipStack.getStackLogger().logException(e);\n                    }\n                } else {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack\n                                .getStackLogger()\n                                .logDebug(\n                                        \"Could not formulate automatic 400 Bad Request\");\n                    }\n                }\n            }\n\n            return;\n        }\n        // No parse exception but null message - reject it and\n        // march on (or return).\n        // exit this message processor if the message did not parse.\n\n        if (sipMessage == null) {\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logDebug(\"Rejecting message !  + Null message parsed.\");\n            }\n            if (pingBackRecord.get(packet.getAddress().getHostAddress() + \":\" + packet.getPort()) == null ) {\n                byte[] retval = \"\\r\\n\\r\\n\".getBytes();\n                DatagramPacket keepalive = new DatagramPacket(retval,0,retval.length,packet.getAddress(),packet.getPort());\n                ((UDPMessageProcessor)this.messageProcessor).sock.send(keepalive);\n                this.sipStack.getTimer().schedule(new PingBackTimerTask(packet.getAddress().getHostAddress(), \n                            packet.getPort()), 1000);                \n            }\n            return;\n        }\n        ViaList viaList = sipMessage.getViaHeaders();\n        // Check for the required headers.\n        if (sipMessage.getFrom() == null || sipMessage.getTo() == null\n                || sipMessage.getCallId() == null\n                || sipMessage.getCSeq() == null\n                || sipMessage.getViaHeaders() == null) {\n            String badmsg = new String(msgBytes);\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logError(\"bad message \" + badmsg);\n                this.sipStack.getStackLogger().logError(\">>> Dropped Bad Msg \"\n                        + \"From = \" + sipMessage.getFrom() + \"To = \"\n                        + sipMessage.getTo() + \"CallId = \"\n                        + sipMessage.getCallId() + \"CSeq = \"\n                        + sipMessage.getCSeq() + \"Via = \"\n                        + sipMessage.getViaHeaders());\n            }\n            return;\n        }\n        // For a request first via header tells where the message\n        // is coming from.\n        // For response, just get the port from the packet.\n        if (sipMessage instanceof SIPRequest) {\n            Via v = (Via) viaList.getFirst();\n            Hop hop = sipStack.addressResolver.resolveAddress(v.getHop());\n            this.peerPort = hop.getPort();\n            this.peerProtocol = v.getTransport();\n\n            this.peerPacketSourceAddress = packet.getAddress();\n            this.peerPacketSourcePort = packet.getPort();\n            try {\n                this.peerAddress = packet.getAddress();\n                // Check to see if the received parameter matches\n                // the peer address and tag it appropriately.\n\n\n                boolean hasRPort = v.hasParameter(Via.RPORT);\n                if (hasRPort\n                        || !hop.getHost().equals(\n                                this.peerAddress.getHostAddress())) {\n                    v.setParameter(Via.RECEIVED, this.peerAddress\n                            .getHostAddress());\n                }\n\n                if (hasRPort) {\n                    v.setParameter(Via.RPORT, Integer\n                            .toString(this.peerPacketSourcePort));\n                }\n            } catch (java.text.ParseException ex1) {\n                InternalErrorHandler.handleException(ex1);\n            }\n\n        } else {\n\n            this.peerPacketSourceAddress = packet.getAddress();\n            this.peerPacketSourcePort = packet.getPort();\n            this.peerAddress = packet.getAddress();\n            this.peerPort = packet.getPort();\n            this.peerProtocol = ((Via) viaList.getFirst()).getTransport();\n        }\n\n        this.processMessage(sipMessage);\n\n    }\n\n    /**\n     * Actually proces the parsed message.\n     *\n     * @param sipMessage\n     */\n    public void processMessage(SIPMessage sipMessage) {\n\n        if (sipMessage instanceof SIPRequest) {\n            SIPRequest sipRequest = (SIPRequest) sipMessage;\n\n            // This is a request - process it.\n            // So far so good -- we will commit this message if\n            // all processing is OK.\n            if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {\n\n                this.sipStack.serverLogger.logMessage(sipMessage, this\n                        .getPeerHostPort().toString(), this.getHost() + \":\"\n                        + this.myPort, false, receptionTime);\n\n            }\n            ServerRequestInterface sipServerRequest = sipStack\n                    .newSIPServerRequest(sipRequest, this);\n            // Drop it if there is no request returned\n            if (sipServerRequest == null) {\n                if (sipStack.isLoggingEnabled()) {\n                    this.sipStack.getStackLogger()\n                            .logWarning(\"Null request interface returned -- dropping request\");\n                }\n\n\n                return;\n            }\n            if (sipStack.isLoggingEnabled())\n                this.sipStack.getStackLogger().logDebug(\"About to process \"\n                        + sipRequest.getFirstLine() + \"/\" + sipServerRequest);\n            try {\n                sipServerRequest.processRequest(sipRequest, this);\n            } finally {\n                if (sipServerRequest instanceof SIPTransaction) {\n                    SIPServerTransaction sipServerTx = (SIPServerTransaction) sipServerRequest;\n                    if (!sipServerTx.passToListener()) {\n                        ((SIPTransaction) sipServerRequest).releaseSem();\n                    }\n                }\n            }\n            if (sipStack.isLoggingEnabled())\n                this.sipStack.getStackLogger().logDebug(\"Done processing \"\n                        + sipRequest.getFirstLine() + \"/\" + sipServerRequest);\n\n            // So far so good -- we will commit this message if\n            // all processing is OK.\n\n        } else {\n            // Handle a SIP Reply message.\n            SIPResponse sipResponse = (SIPResponse) sipMessage;\n            try {\n                sipResponse.checkHeaders();\n            } catch (ParseException ex) {\n                if (sipStack.isLoggingEnabled())\n                    sipStack.getStackLogger()\n                            .logError(\"Dropping Badly formatted response message >>> \"\n                                    + sipResponse);\n                return;\n            }\n            ServerResponseInterface sipServerResponse = sipStack\n                    .newSIPServerResponse(sipResponse, this);\n            if (sipServerResponse != null) {\n                try {\n                    if (sipServerResponse instanceof SIPClientTransaction\n                            && !((SIPClientTransaction) sipServerResponse)\n                                    .checkFromTag(sipResponse)) {\n                        if (sipStack.isLoggingEnabled())\n                            sipStack.getStackLogger()\n                                    .logError(\"Dropping response message with invalid tag >>> \"\n                                            + sipResponse);\n                        return;\n                    }\n\n                    sipServerResponse.processResponse(sipResponse, this);\n                } finally {\n                    if (sipServerResponse instanceof SIPTransaction\n                            && !((SIPTransaction) sipServerResponse)\n                                    .passToListener())\n                        ((SIPTransaction) sipServerResponse).releaseSem();\n                }\n\n                // Normal processing of message.\n            } else {\n                if (sipStack.isLoggingEnabled()) {\n                    this.sipStack.getStackLogger().logDebug(\"null sipServerResponse!\");\n                }\n            }\n\n        }\n    }\n\n    /**\n     * JvB: added method to check for known buggy clients (Windows Messenger) to\n     * fix the port to which responses are sent\n     *\n     * checks for User-Agent: RTC/1.3.5470 (Messenger 5.1.0701)\n     *\n     * JvB 22/7/2006 better to take this out for the moment, it is only a\n     * problem in rare cases (unregister)\n     *\n     * private final boolean isBuggyClient( SIPRequest r ) { UserAgent uah =\n     * (UserAgent) r.getHeader( UserAgent.NAME ); if (uah!=null) {\n     * java.util.ListIterator i = uah.getProduct(); if (i.hasNext()) { String p =\n     * (String) uah.getProduct().next(); return p.startsWith( \"RTC\" ); } }\n     * return false; }\n     */\n\n    /**\n     * Implementation of the ParseExceptionListener interface.\n     *\n     * @param ex\n     *            Exception that is given to us by the parser.\n     * @throws ParseException\n     *             If we choose to reject the header or message.\n     */\n    public void handleException(ParseException ex, SIPMessage sipMessage,\n            Class hdrClass, String header, String message)\n            throws ParseException {\n        if (sipStack.isLoggingEnabled())\n            this.sipStack.getStackLogger().logException(ex);\n        // Log the bad message for later reference.\n        if ((hdrClass != null)\n                && (hdrClass.equals(From.class) || hdrClass.equals(To.class)\n                        || hdrClass.equals(CSeq.class)\n                        || hdrClass.equals(Via.class)\n                        || hdrClass.equals(CallID.class)\n                        || hdrClass.equals(RequestLine.class) || hdrClass\n                        .equals(StatusLine.class))) {\n        \tif (sipStack.isLoggingEnabled()) {\n        \t\tsipStack.getStackLogger().logError(\"BAD MESSAGE!\");\n            \tsipStack.getStackLogger().logError(message);\n        \t}\n            throw ex;\n        } else {\n            sipMessage.addUnparsed(header);\n        }\n    }\n\n    /**\n     * Return a reply from a pre-constructed reply. This sends the message back\n     * to the entity who caused us to create this channel in the first place.\n     *\n     * @param sipMessage\n     *            Message string to send.\n     * @throws IOException\n     *             If there is a problem with sending the message.\n     */\n    public void sendMessage(SIPMessage sipMessage) throws IOException {\n        if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend()) {\n            if ( sipMessage instanceof SIPRequest &&\n                    ((SIPRequest)sipMessage).getRequestLine() != null) {\n                /*\n                 * We dont want to log empty trace messages.\n                 */\n                this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);\n            } else {\n                this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);\n            }\n        }\n\n        // Test and see where we are going to send the messsage. If the message\n        // is sent back to oursleves, just\n        // shortcircuit processing.\n        long time = System.currentTimeMillis();\n        try {\n            for (MessageProcessor messageProcessor : sipStack\n                    .getMessageProcessors()) {\n                if (messageProcessor.getIpAddress().equals(this.peerAddress)\n                        && messageProcessor.getPort() == this.peerPort\n                        && messageProcessor.getTransport().equals(\n                                this.peerProtocol)) {\n                    MessageChannel messageChannel = messageProcessor\n                            .createMessageChannel(this.peerAddress,\n                                    this.peerPort);\n                    if (messageChannel instanceof RawMessageChannel) {\n                        ((RawMessageChannel) messageChannel)\n                                .processMessage(sipMessage);\n                        if (sipStack.isLoggingEnabled())\n                        \tsipStack.getStackLogger().logDebug(\"Self routing message\");\n                        return;\n                    }\n\n                }\n            }\n\n            sendMessage(sipMessage, peerAddress, peerPort, peerProtocol,\n                    sipMessage instanceof SIPRequest);\n\n        } catch (IOException ex) {\n            throw ex;\n        } catch (Exception ex) {\n            if (sipStack.isLoggingEnabled())\n            \tsipStack.getStackLogger().logError(\"An exception occured while sending message\",ex);\n            throw new IOException(\n                    \"An exception occured while sending message\");\n        } finally {\n            if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_MESSAGES) && !sipMessage.isNullRequest())\n                logMessage(sipMessage, peerAddress, peerPort, time);\n            else if (sipStack.getStackLogger().isLoggingEnabled(ServerLogger.TRACE_DEBUG))\n                sipStack.getStackLogger().logDebug(\"Sent EMPTY Message\");\n        }\n    }\n\n    /**\n     * Send a message to a specified receiver address.\n     *\n     * @param message\n     *            string to send.\n     * @param peerAddress\n     *            Address of the place to send it to.\n     * @param peerPort\n     *            the port to send it to.\n     * @throws IOException\n     *             If there is trouble sending this message.\n     */\n    protected void sendMessage(SIPMessage message, InetAddress peerAddress,\n            int peerPort, boolean reConnect) throws IOException {\n        // Via is not included in the request so silently drop the reply.\n        if (sipStack.isLoggingEnabled() && this.sipStack.isLogStackTraceOnMessageSend() ) {\n            this.sipStack.getStackLogger().logStackTrace(StackLogger.TRACE_INFO);\n        }\n        if (peerPort == -1) {\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logDebug(getClass().getName()\n                        + \":sendMessage: Dropping reply!\");\n            }\n            throw new IOException(\"Receiver port not set \");\n        } else {\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logDebug(\"sendMessage \" + peerAddress.getHostAddress() + \"/\"\n                        + peerPort + \"\\n\" ) ;\n                this.sipStack.getStackLogger().logDebug(\"*******************\\n\");\n            }\n\n        }\n        byte[] msg = message.encodeAsBytes(\"udp\");\n        DatagramPacket reply = new DatagramPacket(msg, msg.length, peerAddress,\n                peerPort);\n        try {\n            DatagramSocket sock;\n            boolean created = false;\n\n            if (sipStack.udpFlag) {\n                // Use the socket from the message processor (for firewall\n                // support use the same socket as the message processor\n                // socket -- feature request # 18 from java.net). This also\n                // makes the whole thing run faster!\n                sock = ((UDPMessageProcessor) messageProcessor).sock;\n\n                // Bind the socket to the stack address in case there\n                // are multiple interfaces on the machine (feature reqeust\n                // by Will Scullin) 0 binds to an ephemeral port.\n                // sock = new DatagramSocket(0,sipStack.stackInetAddress);\n            } else {\n                // bind to any interface and port.\n                sock = new DatagramSocket();\n                created = true;\n            }\n            sock.send(reply);\n            if (created)\n                sock.close();\n        } catch (IOException ex) {\n            throw ex;\n        } catch (Exception ex) {\n            InternalErrorHandler.handleException(ex);\n        }\n    }\n\n    /**\n     * Send a message to a specified receiver address.\n     *\n     * @param message\n     *            message string to send.\n     * @param peerAddress\n     *            Address of the place to send it to.\n     * @param peerPort\n     *            the port to send it to.\n     * @param peerProtocol\n     *            protocol to use to send.\n     * @throws IOException\n     *             If there is trouble sending this message.\n     */\n    protected void sendMessage(SIPMessage message, InetAddress peerAddress,\n            int peerPort, String peerProtocol, boolean retry)\n            throws IOException {\n        // Via is not included in the request so silently drop the reply.\n        if (peerPort == -1) {\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logDebug(getClass().getName()\n                        + \":sendMessage: Dropping reply!\");\n            }\n            throw new IOException(\"Receiver port not set \");\n        } else {\n            if (sipStack.isLoggingEnabled()) {\n                this.sipStack.getStackLogger().logDebug( \":sendMessage \" + peerAddress.getHostAddress() + \"/\"\n                        + peerPort + \"\\n\");\n            }\n        }\n        if (peerProtocol.compareToIgnoreCase(\"UDP\") == 0) {\n        \tbyte[] msg = message.encodeAsBytes(\"udp\");\n            DatagramPacket reply = new DatagramPacket(msg, msg.length,\n                    peerAddress, peerPort);\n\n            try {\n                DatagramSocket sock;\n                if (sipStack.udpFlag) {\n                    sock = ((UDPMessageProcessor) messageProcessor).sock;\n\n                } else {\n                    // bind to any interface and port.\n                    sock = sipStack.getNetworkLayer().createDatagramSocket();\n                }\n                if (sipStack.isLoggingEnabled()) {\n                    this.sipStack.getStackLogger().logDebug(\"sendMessage \"\n                            + peerAddress.getHostAddress() + \"/\" + peerPort\n                            + \"\\n\" + new String(msg));\n                }\n                sock.send(reply);\n                if (!sipStack.udpFlag)\n                    sock.close();\n            } catch (IOException ex) {\n                throw ex;\n            } catch (Exception ex) {\n                InternalErrorHandler.handleException(ex);\n            }\n\n        } else {\n            // Use TCP to talk back to the sender.\n            sipStack.ioHandler.sendBytes(\n                    this.messageProcessor.getIpAddress(), peerAddress,\n                    peerPort, \"tcp\", message, retry,this);\n        }\n    }\n\n    /**\n     * get the stack pointer.\n     *\n     * @return The sip stack for this channel.\n     */\n    public SIPTransactionStack getSIPStack() {\n        return sipStack;\n    }\n\n    /**\n     * Return a transport string.\n     *\n     * @return the string \"udp\" in this case.\n     */\n    public String getTransport() {\n        return SIPConstants.UDP;\n    }\n\n    /**\n     * get the stack address for the stack that received this message.\n     *\n     * @return The stack address for our sipStack.\n     */\n    public String getHost() {\n        return messageProcessor.getIpAddress().getHostAddress();\n    }\n\n    /**\n     * get the port.\n     *\n     * @return Our port (on which we are getting datagram packets).\n     */\n    public int getPort() {\n        return ((UDPMessageProcessor) messageProcessor).getPort();\n    }\n\n    /**\n     * get the name (address) of the host that sent me the message\n     *\n     * @return The name of the sender (from the datagram packet).\n     */\n    public String getPeerName() {\n        return peerAddress.getHostName();\n    }\n\n    /**\n     * get the address of the host that sent me the message\n     *\n     * @return The senders ip address.\n     */\n    public String getPeerAddress() {\n        return peerAddress.getHostAddress();\n    }\n\n    protected InetAddress getPeerInetAddress() {\n        return peerAddress;\n    }\n\n    /**\n     * Compare two UDP Message channels for equality.\n     *\n     * @param other\n     *            The other message channel with which to compare oursleves.\n     */\n    public boolean equals(Object other) {\n\n        if (other == null)\n            return false;\n        boolean retval;\n        if (!this.getClass().equals(other.getClass())) {\n            retval = false;\n        } else {\n            UDPMessageChannel that = (UDPMessageChannel) other;\n            retval = this.getKey().equals(that.getKey());\n        }\n\n        return retval;\n    }\n\n    public String getKey() {\n        return getKey(peerAddress, peerPort, \"UDP\");\n    }\n\n    public int getPeerPacketSourcePort() {\n        return peerPacketSourcePort;\n    }\n\n    public InetAddress getPeerPacketSourceAddress() {\n        return peerPacketSourceAddress;\n    }\n\n    /**\n     * Get the logical originator of the message (from the top via header).\n     *\n     * @return topmost via header sentby field\n     */\n    public String getViaHost() {\n        return this.myAddress;\n    }\n\n    /**\n     * Get the logical port of the message orginator (from the top via hdr).\n     *\n     * @return the via port from the topmost via header.\n     */\n    public int getViaPort() {\n        return this.myPort;\n    }\n\n    /**\n     * Returns \"false\" as this is an unreliable transport.\n     */\n    public boolean isReliable() {\n        return false;\n    }\n\n    /**\n     * UDP is not a secure protocol.\n     */\n    public boolean isSecure() {\n        return false;\n    }\n\n    public int getPeerPort() {\n        return peerPort;\n    }\n\n    public String getPeerProtocol() {\n        return this.peerProtocol;\n    }\n\n    /**\n     * Close the message channel.\n     */\n    public void close() {\n    }\n\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/gov2/nist/javax2/sip/stack/UDPMessageProcessor.java",
    "content": "/*\n* Conditions Of Use\n*\n* This software was developed by employees of the National Institute of\n* Standards and Technology (NIST), an agency of the Federal Government.\n* Pursuant to title 15 Untied States Code Section 105, works of NIST\n* employees are not subject to copyright protection in the United States\n* and are considered to be in the public domain.  As a result, a formal\n* license is not needed to use the software.\n*\n* This software is provided by NIST as a service and is expressly\n* provided \"AS IS.\"  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED\n* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF\n* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT\n* AND DATA ACCURACY.  NIST does not warrant or make any representations\n* regarding the use of the software or the results thereof, including but\n* not limited to the correctness, accuracy, reliability or usefulness of\n* the software.\n*\n* Permission to use this software is contingent upon your acceptance\n* of the terms of this agreement\n*\n* .\n*\n*/\n/*******************************************************************************\n *   Product of NIST/ITL Advanced Networking Technologies Division (ANTD).     *\n *******************************************************************************/\npackage gov2.nist.javax2.sip.stack;\n\nimport java.io.IOException;\nimport java.util.LinkedList;\nimport java.net.*;\n\nimport gov2.nist.core.*;\n\n/**\n * Sit in a loop and handle incoming udp datagram messages. For each Datagram\n * packet, a new UDPMessageChannel is created (upto the max thread pool size).\n * Each UDP message is processed in its own thread).\n *\n * @version 1.2 $Revision: 1.37 $ $Date: 2009/11/14 20:06:16 $\n *\n * @author M. Ranganathan  <br/>\n *\n *\n *\n * <a href=\"{@docRoot}/../uml/udp-request-processing-sequence-diagram.jpg\">\n * See the implementation sequence diagram for processing incoming requests.\n * </a>\n *\n *\n * Acknowledgement: Jeff Keyser contributed ideas on starting and stoppping the\n * stack that were incorporated into this code. Niklas Uhrberg suggested that\n * thread pooling be added to limit the number of threads and improve\n * performance.\n */\npublic class UDPMessageProcessor extends MessageProcessor {\n    /**\n     * The Mapped port (in case STUN suport is enabled)\n     */\n    private int port;\n\n    /**\n     * Incoming messages are queued here.\n     */\n    protected LinkedList messageQueue;\n\n    /**\n     * A list of message channels that we have started.\n     */\n    protected LinkedList messageChannels;\n\n    /**\n     * Max # of udp message channels\n     */\n    protected int threadPoolSize;\n\n    protected DatagramSocket sock;\n\n    /**\n     * A flag that is set to false to exit the message processor (suggestion by\n     * Jeff Keyser).\n     */\n    protected boolean isRunning;\n    \n    private static final int HIGHWAT=5000;\n    \n    private static final int LOWAT=2500;\n\n    /**\n     * Constructor.\n     *\n     * @param sipStack\n     *            pointer to the stack.\n     */\n    protected UDPMessageProcessor(InetAddress ipAddress,\n            SIPTransactionStack sipStack, int port) throws IOException {\n        super(ipAddress, port, \"udp\",sipStack);\n\n        this.sipStack = sipStack;\n\n        this.messageQueue = new LinkedList();\n\n        this.port = port;\n        try {\n            this.sock = sipStack.getNetworkLayer().createDatagramSocket(port,\n                    ipAddress);\n            // Create a new datagram socket.\n            sock.setReceiveBufferSize(sipStack.getReceiveUdpBufferSize());\n            sock.setSendBufferSize(sipStack.getSendUdpBufferSize());\n\n            /**\n             * If the thread auditor is enabled, define a socket timeout value in order to\n             * prevent sock.receive() from blocking forever\n             */\n            if (sipStack.getThreadAuditor().isEnabled()) {\n                sock.setSoTimeout((int) sipStack.getThreadAuditor().getPingIntervalInMillisecs());\n            }\n            if ( ipAddress.getHostAddress().equals(IN_ADDR_ANY)  ||\n                 ipAddress.getHostAddress().equals(IN6_ADDR_ANY)){\n                // Store the address to which we are actually bound\n                // Note that on WINDOWS this is actually broken. It will\n                // return IN_ADDR_ANY again. On linux it will return the\n                // address to which the socket was actually bound.\n                super.setIpAddress( sock.getLocalAddress() );\n\n            }\n        } catch (SocketException ex) {\n            throw new IOException(ex.getMessage());\n        }\n    }\n\n\n\n    /**\n     * Get port on which to listen for incoming stuff.\n     *\n     * @return port on which I am listening.\n     */\n    public int getPort() {\n        return this.port;\n    }\n\n    /**\n     * Start our processor thread.\n     */\n    public void start() throws IOException {\n\n\n        this.isRunning = true;\n        Thread thread = new Thread(this);\n        thread.setDaemon(true);\n        // Issue #32 on java.net\n        thread.setName(\"UDPMessageProcessorThread\");\n        // Issue #184\n        thread.setPriority(Thread.MAX_PRIORITY);\n        thread.start();\n    }\n\n    /**\n     * Thread main routine.\n     */\n    public void run() {\n        // Check for running flag.\n        this.messageChannels = new LinkedList();\n        // start all our messageChannels (unless the thread pool size is\n        // infinity.\n        if (sipStack.threadPoolSize != -1) {\n            for (int i = 0; i < sipStack.threadPoolSize; i++) {\n                UDPMessageChannel channel = new UDPMessageChannel(sipStack,\n                        this);\n                this.messageChannels.add(channel);\n\n            }\n        }\n\n        // Ask the auditor to monitor this thread\n        ThreadAuditor.ThreadHandle threadHandle = sipStack.getThreadAuditor().addCurrentThread();\n\n        // Somebody asked us to exit. if isRunnning is set to false.\n        while (this.isRunning) {\n\n            try {\n                // Let the thread auditor know we're up and running\n                threadHandle.ping();\n\n                int bufsize = sock.getReceiveBufferSize();\n                byte message[] = new byte[bufsize];\n                DatagramPacket packet = new DatagramPacket(message, bufsize);\n                sock.receive(packet);\n\n           \n             \n             // This is a simplistic congestion control algorithm.\n             // It accepts packets if queuesize is < LOWAT. It drops\n             // requests if the queue size exceeds a HIGHWAT and accepts\n             // requests with probability p proportional to the difference\n             // between current queue size and LOWAT in the range\n             // of queue sizes between HIGHWAT and LOWAT.\n             // TODO -- penalize spammers by looking at the source\n             // port and IP address.\n             if ( sipStack.stackDoesCongestionControl ) {  \n             if ( this.messageQueue.size() >= HIGHWAT) {\n                    if (sipStack.isLoggingEnabled()) {\n                        sipStack.getStackLogger().logDebug(\"Dropping message -- queue length exceeded\");\n\n                    }\n                    //System.out.println(\"HIGHWAT Drop!\");\n                    continue;\n                } else if ( this.messageQueue.size() > LOWAT && this .messageQueue.size() < HIGHWAT ) {\n                    // Drop the message with a probabilty that is linear in the range 0 to 1\n                    float threshold = ((float)(messageQueue.size() - LOWAT))/ ((float)(HIGHWAT - LOWAT));\n                    boolean decision = Math.random() > 1.0 - threshold;\n                    if ( decision ) {\n                        if (sipStack.isLoggingEnabled()) {\n                            sipStack.getStackLogger().logDebug(\"Dropping message with probability  \" + (1.0 - threshold));\n\n                        }\n                        //System.out.println(\"RED Drop!\");\n                        continue;\n                    }\n\n                }\n             }\n                \n                \n                \n                // Count of # of packets in process.\n                // this.useCount++;\n                if (sipStack.threadPoolSize != -1) {\n                    // Note: the only condition watched for by threads\n                    // synchronizing on the messageQueue member is that it is\n                    // not empty. As soon as you introduce some other\n                    // condition you will have to call notifyAll instead of\n                    // notify below.\n\n                    synchronized (this.messageQueue) {\n                        // was addLast\n                        this.messageQueue.add(packet);\n                        this.messageQueue.notify();\n                    }\n                } else {\n                    new UDPMessageChannel(sipStack, this, packet);\n                }\n            } catch (SocketTimeoutException ex) {\n              // This socket timeout alows us to ping the thread auditor periodically\n            } catch (SocketException ex) {\n                if (sipStack.isLoggingEnabled())\n                    getSIPStack().getStackLogger()\n                            .logDebug(\"UDPMessageProcessor: Stopping\");\n                isRunning = false;\n                // The notifyAll should be in a synchronized block.\n                // ( bug report by Niklas Uhrberg ).\n                synchronized (this.messageQueue) {\n                    this.messageQueue.notifyAll();\n                }\n            } catch (IOException ex) {\n                isRunning = false;\n                ex.printStackTrace();\n                if (sipStack.isLoggingEnabled())\n                    getSIPStack().getStackLogger()\n                            .logDebug(\"UDPMessageProcessor: Got an IO Exception\");\n            } catch (Exception ex) {\n                if (sipStack.isLoggingEnabled())\n                    getSIPStack().getStackLogger()\n                            .logDebug(\"UDPMessageProcessor: Unexpected Exception - quitting\");\n                InternalErrorHandler.handleException(ex);\n                return;\n            }\n        }\n    }\n\n    /**\n     * Shut down the message processor. Close the socket for recieving incoming\n     * messages.\n     */\n    public void stop() {\n        synchronized (this.messageQueue) {\n            this.isRunning = false;\n            this.messageQueue.notifyAll();\n            sock.close();\n\n\n        }\n    }\n\n    /**\n     * Return the transport string.\n     *\n     * @return the transport string\n     */\n    public String getTransport() {\n        return \"udp\";\n    }\n\n    /**\n     * Returns the stack.\n     *\n     * @return my sip stack.\n     */\n    public SIPTransactionStack getSIPStack() {\n        return sipStack;\n    }\n\n    /**\n     * Create and return new TCPMessageChannel for the given host/port.\n     */\n    public MessageChannel createMessageChannel(HostPort targetHostPort)\n            throws UnknownHostException {\n        return new UDPMessageChannel(targetHostPort.getInetAddress(),\n                targetHostPort.getPort(), sipStack, this);\n    }\n\n    public MessageChannel createMessageChannel(InetAddress host, int port)\n            throws IOException {\n        return new UDPMessageChannel(host, port, sipStack, this);\n    }\n\n    /**\n     * Default target port for UDP\n     */\n    public int getDefaultTargetPort() {\n        return 5060;\n    }\n\n    /**\n     * UDP is not a secure protocol.\n     */\n    public boolean isSecure() {\n        return false;\n    }\n\n    /**\n     * UDP can handle a message as large as the MAX_DATAGRAM_SIZE.\n     */\n    public int getMaximumMessageSize() {\n        return 8*1024;\n    }\n\n    /**\n     * Return true if there are any messages in use.\n     */\n    public boolean inUse() {\n        synchronized (messageQueue) {\n            return messageQueue.size() != 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/ClientTransaction.java",
    "content": "package javax2.sip;\n\nimport javax2.sip.address.Hop;\nimport javax2.sip.message.Request;\n\npublic interface ClientTransaction extends Transaction {\n    /**\n     * @deprecated\n     * For 2xx response, use {@link Dialog.createAck(long)}. The application\n     * should not need to handle non-2xx responses.\n     */\n    Request createAck() throws SipException;\n\n    Request createCancel() throws SipException;\n    void sendRequest() throws SipException;\n\n    void alertIfStillInCallingStateBy(int count);\n\n    Hop getNextHop();\n\n    void setNotifyOnRetransmit(boolean notifyOnRetransmit);\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/Dialog.java",
    "content": "package javax2.sip;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\nimport java.util.Iterator;\n\nimport javax2.sip.address.Address;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\npublic interface Dialog extends Serializable {\n    Object getApplicationData();\n    void setApplicationData(Object applicationData);\n\n    CallIdHeader getCallId();\n    String getDialogId();\n\n    /**\n     * @deprecated\n     */\n    Transaction getFirstTransaction();\n\n    Address getLocalParty();\n\n    /**\n     * @deprecated\n     * @see #getLocalSeqNumber()\n     */\n    int getLocalSequenceNumber();\n\n    long getLocalSeqNumber();\n\n    String getLocalTag();\n\n    Address getRemoteParty();\n\n    /**\n     * @deprecated\n     * @see #getRemoteSeqNumber()\n     */\n    int getRemoteSequenceNumber();\n\n    long getRemoteSeqNumber();\n\n    String getRemoteTag();\n\n    Address getRemoteTarget();\n\n    Iterator getRouteSet();\n\n    SipProvider getSipProvider();\n\n    DialogState getState();\n\n    boolean isSecure();\n\n    boolean isServer();\n\n    void delete();\n\n    void incrementLocalSequenceNumber();\n\n    Request createRequest(String method) throws SipException;\n    Request createAck(long cseq) throws InvalidArgumentException, SipException;\n    Request createPrack(Response relResponse)\n            throws DialogDoesNotExistException, SipException;\n    Response createReliableProvisionalResponse(int statusCode)\n            throws InvalidArgumentException, SipException;\n\n\n    void sendRequest(ClientTransaction clientTransaction)\n            throws TransactionDoesNotExistException, SipException;\n    void sendAck(Request ackRequest) throws SipException;\n    void sendReliableProvisionalResponse(Response relResponse)\n            throws SipException;\n\n    void setBackToBackUserAgent();\n\n    void terminateOnBye(boolean terminateFlag) throws SipException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/DialogDoesNotExistException.java",
    "content": "package javax2.sip;\n\npublic class DialogDoesNotExistException extends SipException {\n    public DialogDoesNotExistException(){\n    }\n\n    public DialogDoesNotExistException(String message) {\n        super(message);\n    }\n\n    public DialogDoesNotExistException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/DialogState.java",
    "content": "package javax2.sip;\n\npublic enum DialogState {\n    EARLY,\n    CONFIRMED,\n    TERMINATED;\n\n    public static final int _EARLY = EARLY.ordinal();\n    public static final int _CONFIRMED = CONFIRMED.ordinal();\n    public static final int _TERMINATED = TERMINATED.ordinal();\n\n    public static DialogState getObject(int state) {\n        try {\n            return values()[state];\n        } catch (IndexOutOfBoundsException e) {\n            throw new IllegalArgumentException(\n                    \"Invalid dialog state: \" + state);\n        }\n    }\n\n    public int getValue() {\n        return ordinal();\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/DialogTerminatedEvent.java",
    "content": "package javax2.sip;\n\nimport java.util.EventObject;\n\npublic class DialogTerminatedEvent extends EventObject {\n    private Dialog mDialog;\n\n    public DialogTerminatedEvent(Object source, Dialog dialog) {\n        super(source);\n        mDialog = dialog;\n    }\n\n    public Dialog getDialog() {\n        return mDialog;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/IOExceptionEvent.java",
    "content": "package javax2.sip;\n\nimport java.util.EventObject;\n\npublic class IOExceptionEvent extends EventObject {\n    private String mHost;\n    private int mPort;\n    private String mTransport;\n\n    public IOExceptionEvent(Object source, String host, int port,\n            String transport) {\n        super(source);\n        mHost = host;\n        mPort = port;\n        mTransport = transport;\n    }\n\n    public String getHost() {\n        return mHost;\n    }\n\n    public int getPort() {\n        return mPort;\n    }\n\n    public String getTransport() {\n        return mTransport;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/InvalidArgumentException.java",
    "content": "package javax2.sip;\n\npublic class InvalidArgumentException extends SipException {\n    public InvalidArgumentException() {\n    }\n\n    public InvalidArgumentException(String message) {\n        super(message);\n    }\n\n    public InvalidArgumentException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/ListeningPoint.java",
    "content": "package javax2.sip;\n\nimport java.io.IOException;\nimport java.text.ParseException;\n\nimport javax2.sip.header.ContactHeader;\n\npublic interface ListeningPoint extends Cloneable {\n    String TCP = \"TCP\";\n    String UDP = \"UDP\";\n    String SCTP = \"SCTP\";\n    String TLS = \"TLS\";\n    int PORT_5060 = 5060;\n    int PORT_5061 = 5061;\n\n    String getIPAddress();\n    int getPort();\n    String getTransport();\n\n    String getSentBy();\n    void setSentBy(String sentBy) throws ParseException;\n\n    ContactHeader createContactHeader();\n\n    void sendHeartbeat(String s, int i) throws IOException;\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/ObjectInUseException.java",
    "content": "package javax2.sip;\n\npublic class ObjectInUseException extends SipException {\n    public ObjectInUseException() {\n    }\n\n    public ObjectInUseException(String message) {\n        super(message);\n    }\n\n    public ObjectInUseException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/PeerUnavailableException.java",
    "content": "package javax2.sip;\n\npublic class PeerUnavailableException extends SipException {\n    public PeerUnavailableException() {\n    }\n\n    public PeerUnavailableException(String message) {\n        super(message);\n    }\n\n    public PeerUnavailableException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/ProviderDoesNotExistException.java",
    "content": "package javax2.sip;\n\npublic class ProviderDoesNotExistException extends SipException {\n    public ProviderDoesNotExistException(){\n    }\n\n    public ProviderDoesNotExistException(String message) {\n        super(message);\n    }\n\n    public ProviderDoesNotExistException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/RequestEvent.java",
    "content": "package javax2.sip;\n\nimport java.util.EventObject;\n\nimport javax2.sip.message.Request;\n\npublic class RequestEvent extends EventObject {\n    private Dialog mDialog;\n    private Request mRequest;\n    private ServerTransaction mServerTransaction;\n\n    public RequestEvent(Object source, ServerTransaction serverTransaction,\n            Dialog dialog, Request request) {\n        super(source);\n        mDialog  = dialog;\n        mRequest = request;\n        mServerTransaction = serverTransaction;\n    }\n\n    public Dialog getDialog() {\n        return mDialog;\n    }\n\n    public Request getRequest() {\n        return mRequest;\n    }\n\n    public ServerTransaction getServerTransaction() {\n        return mServerTransaction;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/ResponseEvent.java",
    "content": "package javax2.sip;\n\nimport java.util.EventObject;\n\nimport javax2.sip.message.Response;\n\npublic class ResponseEvent extends EventObject {\n    private Dialog mDialog;\n    private Response mResponse;\n    private ClientTransaction mClientTransaction;\n\n    public ResponseEvent(Object source, ClientTransaction clientTransaction,\n            Dialog dialog, Response response) {\n        super(source);\n        mDialog = dialog;\n        mResponse = response;\n        mClientTransaction = clientTransaction;\n    }\n\n    public Dialog getDialog() {\n        return mDialog;\n    }\n\n    public Response getResponse() {\n        return mResponse;\n    }\n\n    public ClientTransaction getClientTransaction(){\n        return mClientTransaction;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/ServerTransaction.java",
    "content": "package javax2.sip;\n\nimport javax2.sip.message.Response;\n\npublic interface ServerTransaction extends Transaction {\n    void sendResponse(Response response)\n            throws SipException, InvalidArgumentException;\n\n    void enableRetransmissionAlerts() throws SipException;\n\n    ServerTransaction getCanceledInviteTransaction();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/SipException.java",
    "content": "package javax2.sip;\n\npublic class SipException extends Exception {\n    public SipException() {\n    }\n\n    public SipException(String message) {\n        super(message);\n    }\n\n    public SipException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/SipFactory.java",
    "content": "package javax2.sip;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Properties;\n\nimport javax2.sip.address.AddressFactory;\nimport javax2.sip.header.HeaderFactory;\nimport javax2.sip.message.MessageFactory;\n\npublic class SipFactory {\n    private static final String IP_ADDRESS_PROP = \"javax2.sip.IP_ADDRESS\";\n    private static final String STACK_NAME_PROP = \"javax2.sip.STACK_NAME\";\n\n    private static SipFactory sSipFactory = null;\n\n    public static synchronized SipFactory getInstance() {\n        if (sSipFactory == null) sSipFactory = new SipFactory();\n        return sSipFactory;\n    }\n\n    // name-to-SipStack map; name could be IP address for backward compatibility\n    private Map<String, SipStack> mNameSipStackMap =\n            new HashMap<String, SipStack>();\n\n    private SipFactory() {\n    }\n\n    public synchronized void resetFactory() {\n        mNameSipStackMap.clear();\n    }\n\n    public synchronized SipStack createSipStack(Properties properties)\n            throws PeerUnavailableException {\n        // for backward compatibility, if IP_ADDRESS_PROP exists, use it and\n        // ignore STACK_NAME_PROP.\n        String name = properties.getProperty(IP_ADDRESS_PROP);\n        if (name == null) {\n            name = properties.getProperty(STACK_NAME_PROP);\n            if (name == null ) {\n                throw new PeerUnavailableException(\n                        STACK_NAME_PROP + \" property not found\");\n            }\n        }\n\n        SipStack sipStack = mNameSipStackMap.get(name);\n        if (sipStack == null) {\n            String implClassName = \"gov2.nist.\"\n                    + SipStack.class.getCanonicalName() + \"Impl\";\n            try {\n                sipStack = Class.forName(implClassName)\n                        .asSubclass(SipStack.class)\n                        .getConstructor(new Class[] {Properties.class})\n                        .newInstance(new Object[] {properties});\n            } catch (Exception e) {\n                throw new PeerUnavailableException(\n                        \"Failed to initiate \" + implClassName, e);\n            }\n            mNameSipStackMap.put(name, sipStack);\n        }\n        return sipStack;\n    }\n\n    public AddressFactory createAddressFactory()\n            throws PeerUnavailableException {\n        try {\n            return new gov2.nist.javax2.sip.address.AddressFactoryImpl();\n        } catch (Exception e) {\n            if (e instanceof PeerUnavailableException) {\n                throw (PeerUnavailableException) e;\n            } else {\n                throw new PeerUnavailableException(\n                        \"Failed to create AddressFactory\", e);\n            }\n        }\n    }\n\n    public HeaderFactory createHeaderFactory() throws PeerUnavailableException {\n        try {\n            return new gov2.nist.javax2.sip.header.HeaderFactoryImpl();\n        } catch (Exception e) {\n            if (e instanceof PeerUnavailableException) {\n                throw (PeerUnavailableException) e;\n            } else {\n                throw new PeerUnavailableException(\n                        \"Failed to create HeaderFactory\", e);\n            }\n        }\n    }\n\n    public MessageFactory createMessageFactory()\n            throws PeerUnavailableException {\n        try {\n            return new gov2.nist.javax2.sip.message.MessageFactoryImpl();\n        } catch (Exception e) {\n            if (e instanceof PeerUnavailableException) {\n                throw (PeerUnavailableException) e;\n            } else {\n                throw new PeerUnavailableException(\n                        \"Failed to create MessageFactory\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/SipListener.java",
    "content": "package javax2.sip;\n\npublic interface SipListener {\n    void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent);\n    void processIOException(IOExceptionEvent exceptionEvent);\n    void processRequest(RequestEvent requestEvent);\n    void processResponse(ResponseEvent responseEvent);\n    void processTimeout(TimeoutEvent timeoutEvent);\n    void processTransactionTerminated(\n            TransactionTerminatedEvent transactionTerminatedEvent);\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/SipProvider.java",
    "content": "package javax2.sip;\n\nimport java.util.TooManyListenersException;\n\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.message.Request;\nimport javax2.sip.message.Response;\n\npublic interface SipProvider {\n    /**\n     * @deprecated\n     * @see #addListeningPoint(ListeningPoint)\n     */\n    void setListeningPoint(ListeningPoint listeningPoint)\n            throws ObjectInUseException;\n    void addListeningPoint(ListeningPoint listeningPoint)\n            throws ObjectInUseException;\n    void removeListeningPoint(ListeningPoint listeningPoint)\n            throws ObjectInUseException;\n    void removeListeningPoints();\n\n    /**\n     * @deprecated\n     * @see #getListeningPoints()\n     */\n    ListeningPoint getListeningPoint();\n    ListeningPoint getListeningPoint(String transport);\n    ListeningPoint[] getListeningPoints();\n\n    void addSipListener(SipListener sipListener)\n            throws TooManyListenersException;\n    void removeSipListener(SipListener sipListener);\n\n    CallIdHeader getNewCallId();\n\n    ClientTransaction getNewClientTransaction(Request request)\n            throws TransactionUnavailableException;\n    ServerTransaction getNewServerTransaction(Request request)\n            throws TransactionAlreadyExistsException,\n            TransactionUnavailableException;\n\n    Dialog getNewDialog(Transaction transaction) throws SipException;\n\n    boolean isAutomaticDialogSupportEnabled();\n    void setAutomaticDialogSupportEnabled(boolean flag);\n\n    SipStack getSipStack();\n\n    void sendRequest(Request request) throws SipException;\n    void sendResponse(Response response) throws SipException;\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/SipStack.java",
    "content": "package javax2.sip;\n\nimport gov2.nist.javax2.sip.ListeningPointImpl;\nimport gov2.nist.javax2.sip.SipProviderImpl;\n\nimport java.util.Collection;\nimport java.util.Iterator;\n\nimport javax2.sip.address.Router;\n\npublic interface SipStack {\n    /**\n     * Deprecated. Use {@link #createListeningPoint(String, int, String)}\n     * instead.\n     */\n    ListeningPoint createListeningPoint(int port, String transport)\n            throws TransportNotSupportedException, InvalidArgumentException;\n    ListeningPoint createListeningPoint(String ipAddress, int port,\n            String transport) throws TransportNotSupportedException,\n            InvalidArgumentException;\n    void deleteListeningPoint(ListeningPoint listeningPoint)\n            throws ObjectInUseException;\n\n    SipProvider createSipProvider(ListeningPoint listeningPoint)\n            throws ObjectInUseException;\n    void deleteSipProvider(SipProvider sipProvider) throws ObjectInUseException;\n\n    Collection<Dialog> getDialogs();\n    String getIPAddress();\n    Iterator<ListeningPointImpl> getListeningPoints();\n    Router getRouter();\n    Iterator<SipProviderImpl> getSipProviders();\n    String getStackName();\n    \n    // Changed by Deutsche Telekom\n     int getMtuSize();\n     \n    /**\n     * @deprecated\n     * Use {@link ServerTransaction#enableRetransmissionAlerts()} to enable\n     * retransmission alerts instead.\n     */\n    boolean isRetransmissionFilterActive();\n\n    void start() throws ProviderDoesNotExistException, SipException;\n    void stop();\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/Timeout.java",
    "content": "package javax2.sip;\n\npublic enum Timeout {\n    RETRANSMIT,\n    TRANSACTION;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TimeoutEvent.java",
    "content": "package javax2.sip;\n\npublic class TimeoutEvent extends TransactionTerminatedEvent {\n    private Timeout mTimeout;\n\n    public TimeoutEvent(Object source, ServerTransaction serverTransaction,\n            Timeout timeout) {\n        super(source, serverTransaction);\n        mTimeout = timeout;\n    }\n\n    public TimeoutEvent(Object source, ClientTransaction clientTransaction,\n            Timeout timeout) {\n        super(source, clientTransaction);\n        mTimeout = timeout;\n    }\n\n    public Timeout getTimeout() {\n        return mTimeout;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/Transaction.java",
    "content": "package javax2.sip;\n\nimport java.io.Serializable;\n\nimport javax2.sip.message.Request;\n\npublic interface Transaction extends Serializable {\n    Object getApplicationData();\n    void setApplicationData (Object applicationData);\n\n    String getBranchId();\n    Dialog getDialog();\n    String getHost();\n    String getPeerAddress();\n    int getPeerPort();\n    int getPort();\n    Request getRequest();\n    SipProvider getSipProvider();\n    TransactionState getState();\n    String getTransport();\n\n    int getRetransmitTimer() throws UnsupportedOperationException;\n    void setRetransmitTimer(int retransmitTimer)\n            throws UnsupportedOperationException;\n    void setRetransmitTimers(int timer_T1, int timer_T2, int timer_T4)\n            throws UnsupportedOperationException; \t// Bug fix OrangeLabs, JOGUET Benoit\n\n    void terminate() throws ObjectInUseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TransactionAlreadyExistsException.java",
    "content": "package javax2.sip;\n\npublic class TransactionAlreadyExistsException extends SipException {\n    public TransactionAlreadyExistsException(){\n    }\n\n    public TransactionAlreadyExistsException(String message) {\n        super(message);\n    }\n\n    public TransactionAlreadyExistsException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TransactionDoesNotExistException.java",
    "content": "package javax2.sip;\n\npublic class TransactionDoesNotExistException extends SipException {\n    public TransactionDoesNotExistException(){\n    }\n\n    public TransactionDoesNotExistException(String message) {\n        super(message);\n    }\n\n    public TransactionDoesNotExistException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TransactionState.java",
    "content": "package javax2.sip;\n\npublic enum TransactionState {\n    CALLING,\n    TRYING,\n    PROCEEDING,\n    COMPLETED,\n    CONFIRMED,\n    TERMINATED;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TransactionTerminatedEvent.java",
    "content": "package javax2.sip;\n\nimport java.util.EventObject;\n\npublic class TransactionTerminatedEvent extends EventObject {\n    private boolean mIsServerTransaction;\n    private ServerTransaction mServerTransaction;\n    private ClientTransaction mClientTransaction;\n\n    public TransactionTerminatedEvent(\n            Object source, ServerTransaction serverTransaction) {\n        super(source);\n        mServerTransaction = serverTransaction;\n\n        mIsServerTransaction = true;\n    }\n\n    public TransactionTerminatedEvent(\n            Object source, ClientTransaction clientTransaction) {\n        super(source);\n        mClientTransaction = clientTransaction;\n\n        mIsServerTransaction = false;\n    }\n\n    public boolean isServerTransaction() {\n        return mIsServerTransaction;\n    }\n\n    public ClientTransaction getClientTransaction() {\n        return mClientTransaction;\n    }\n\n    public ServerTransaction getServerTransaction() {\n        return mServerTransaction;\n    }\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TransactionUnavailableException.java",
    "content": "package javax2.sip;\n\npublic class TransactionUnavailableException extends SipException {\n    public TransactionUnavailableException() {\n    }\n\n    public TransactionUnavailableException(String message) {\n        super(message);\n    }\n\n    public TransactionUnavailableException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/TransportNotSupportedException.java",
    "content": "package javax2.sip;\n\npublic class TransportNotSupportedException extends SipException {\n    public TransportNotSupportedException() {\n    }\n\n    public TransportNotSupportedException(String message) {\n        super(message);\n    }\n\n    public TransportNotSupportedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/Address.java",
    "content": "package javax2.sip.address;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\n\npublic interface Address extends Cloneable, Serializable {\n\tString getDisplayName();\n\n\tvoid setDisplayName(String displayName) throws ParseException;\n\n\tboolean hasDisplayName();\n\n\tString getHost();\n\n\tint getPort();\n\n\tvoid setPort(int port);\n\t\n\tString getUserAtHostPort();\n\n\tboolean isSIPAddress();\n\n\tURI getURI();\n\n\tvoid setURI(URI uri);\n\n\tboolean isWildcard();\n\n\tvoid setWildCardFlag();\n\n\tboolean equals(Object obj);\n\n\tint hashCode();\n\n\tObject clone();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/AddressFactory.java",
    "content": "package javax2.sip.address;\n\nimport java.text.ParseException;\n\npublic interface AddressFactory {\n    Address createAddress();\n    Address createAddress(String address) throws ParseException;\n    Address createAddress(URI uri);\n    Address createAddress(String displayName, URI uri)\n            throws ParseException;\n    SipURI createSipURI(String uri) throws ParseException;\n    SipURI createSipURI(String user, String host) throws ParseException;\n    TelURL createTelURL(String uri) throws ParseException;\n    URI createURI(String uri) throws ParseException;\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/Hop.java",
    "content": "package javax2.sip.address;\n\npublic interface Hop {\n    String getHost();\n    int getPort();\n    String getTransport();\n\n    boolean isURIRoute();\n    void setURIRouteFlag();\n\n    String toString();\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/Router.java",
    "content": "package javax2.sip.address;\n\nimport java.util.ListIterator;\n\nimport javax2.sip.SipException;\nimport javax2.sip.message.Request;\n\npublic interface Router {\n    Hop getNextHop(Request request) throws SipException;\n    ListIterator getNextHops(Request request);\n    Hop getOutboundProxy();\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/SipURI.java",
    "content": "package javax2.sip.address;\n\nimport java.text.ParseException;\nimport java.util.Iterator;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.header.Parameters;\n\npublic interface SipURI extends URI, Parameters {\n    boolean isSecure();\n    void setSecure(boolean secure);\n\n    String getHeader(String name);\n    void setHeader(String name, String value);\n    Iterator getHeaderNames();\n\n    String getHost();\n    void setHost(String host) throws ParseException;\n\n    String getLrParam();\n    void setLrParam();\n    boolean hasLrParam();\n\n    String getMAddrParam();\n    void setMAddrParam(String mAddrParam) throws ParseException;\n\n    int getPort();\n    void setPort(int port) throws InvalidArgumentException;\n\n    int getTTLParam();\n    void setTTLParam(int ttlParam);\n\n    String getTransportParam();\n    void setTransportParam(String transportParam) throws ParseException;\n    boolean hasTransport();\n\n    String getUser();\n    void setUser(String user);\n    String getUserParam();\n    void setUserParam(String userParam);\n\n    String getUserType();\n    void removeUserType();\n\n    String getUserPassword();\n    void setUserPassword(String userPassword);\n\n    String getUserAtHost();\n    String getUserAtHostPort();\n\n    String getMethodParam();\n    void setMethodParam(String methodParam) throws ParseException;\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/TelURL.java",
    "content": "package javax2.sip.address;\n\nimport java.text.ParseException;\n\nimport javax2.sip.header.Parameters;\n\npublic interface TelURL extends URI, Parameters {\n    String getIsdnSubAddress();\n    void setIsdnSubAddress(String isdnSubAddress) throws ParseException;\n\n    String getPhoneContext();\n    void setPhoneContext(String phoneContext) throws ParseException;\n\n    String getPhoneNumber();\n    void setPhoneNumber(String phoneNumber) throws ParseException;\n\n    String getPostDial();\n    void setPostDial(String postDial) throws ParseException;\n\n    boolean isGlobal();\n    void setGlobal(boolean global);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/address/URI.java",
    "content": "package javax2.sip.address;\n\nimport java.io.Serializable;\n\npublic interface URI extends Cloneable, Serializable {\n    String getScheme();\n    boolean isSipURI();\n\n    Object clone();\n    String toString();\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AcceptEncodingHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface AcceptEncodingHeader extends Encoding, Header, Parameters {\n    String NAME = \"Accept-Encoding\";\n\n    float getQValue();\n    void setQValue(float qValue) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AcceptHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface AcceptHeader extends Header, MediaType, Parameters {\n    String NAME = \"Accept\";\n\n    boolean allowsAllContentSubTypes();\n    boolean allowsAllContentTypes();\n\n    float getQValue();\n    void setQValue(float qValue) throws InvalidArgumentException;\n    boolean hasQValue();\n    void removeQValue();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AcceptLanguageHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.util.Locale;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface AcceptLanguageHeader extends Header, Parameters {\n    String NAME = \"Accept-Language\";\n\n    Locale getAcceptLanguage();\n    void setAcceptLanguage(Locale acceptLanguage);\n    void setLanguageRange(String languageRange);\n\n    float getQValue();\n    void setQValue(float qValue) throws InvalidArgumentException;\n    boolean hasQValue();\n    void removeQValue();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AlertInfoHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.address.URI;\n\npublic interface AlertInfoHeader extends Header, Parameters {\n    String NAME = \"Alert-Info\";\n\n    URI getAlertInfo();\n    void setAlertInfo(URI alertInfo);\n    void setAlertInfo(String alertInfo);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AllowEventsHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface AllowEventsHeader extends Header {\n    String NAME = \"Allow-Events\";\n\n    String getEventType();\n    void setEventType(String eventType) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AllowHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface AllowHeader extends Header {\n    String NAME = \"Allow\";\n\n    String getMethod();\n    void setMethod(String method) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AuthenticationInfoHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface AuthenticationInfoHeader extends Header, Parameters {\n    String NAME = \"Authentication-Info\";\n\n    String getCNonce();\n    void setCNonce(String cNonce) throws ParseException;\n\n    String getNextNonce();\n    void setNextNonce(String nextNonce) throws ParseException;\n\n    int getNonceCount();\n    void setNonceCount(int nonceCount) throws ParseException;\n\n    String getQop();\n    void setQop(String qop) throws ParseException;\n\n    String getResponse();\n    void setResponse(String response) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/AuthorizationHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.address.URI;\n\npublic interface AuthorizationHeader extends Header, Parameters {\n    String NAME = \"Authorization\";\n\n    String getAlgorithm();\n    void setAlgorithm(String algorithm) throws ParseException;\n\n    String getCNonce();\n    void setCNonce(String cNonce) throws ParseException;\n\n    String getNonce();\n    void setNonce(String nonce) throws ParseException;\n\n    int getNonceCount();\n    void setNonceCount(int nonceCount) throws ParseException;\n\n    String getOpaque();\n    void setOpaque(String opaque) throws ParseException;\n\n    String getQop();\n    void setQop(String qop) throws ParseException;\n\n    String getRealm();\n    void setRealm(String realm) throws ParseException;\n\n    String getResponse();\n    void setResponse(String response) throws ParseException;\n\n    String getScheme();\n    void setScheme(String scheme);\n\n    boolean isStale();\n    void setStale(boolean stale);\n\n    URI getURI();\n    void setURI(URI uri);\n\n    String getUsername();\n    void setUsername(String username) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/CSeqHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface CSeqHeader extends AllowHeader, RSeqHeader {\n    String NAME = \"CSeq\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/CallIdHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface CallIdHeader extends Header {\n    String NAME = \"Call-ID\";\n\n    String getCallId();\n    void setCallId(String callId) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/CallInfoHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.address.URI;\n\npublic interface CallInfoHeader extends Header, Parameters {\n    String NAME = \"Call-Info\";\n\n    URI getInfo();\n    void setInfo(URI info);\n\n    String getPurpose();\n    void setPurpose(String purpose);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ContactHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface ContactHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"Contact\";\n\n    int getExpires();\n    void setExpires(int expires) throws InvalidArgumentException;\n\n    float getQValue();\n    void setQValue(float qValue) throws InvalidArgumentException;\n\n    boolean isWildCard();\n    void setWildCard();\n    void setWildCardFlag(boolean wildCardFlag);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ContentDispositionHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface ContentDispositionHeader extends Header, Parameters {\n    String NAME = \"Content-Disposition\";\n\n    String RENDER = \"Render\";\n    String SESSION = \"Session\";\n    String ICON = \"Icon\";\n    String ALERT = \"Alert\";\n\n    String getDispositionType();\n    void setDispositionType(String dispositionType) throws ParseException;\n\n    String getHandling();\n    void setHandling(String handling) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ContentEncodingHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface ContentEncodingHeader extends Encoding, Header {\n    String NAME = \"Content-Encoding\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ContentLanguageHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.util.Locale;\n\npublic interface ContentLanguageHeader extends Header {\n    String NAME = \"Content-Language\";\n\n    Locale getContentLanguage();\n    void setContentLanguage(Locale language);\n\n    String getLanguageTag();\n    void setLanguageTag(String languageTag);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ContentLengthHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface ContentLengthHeader extends Header {\n    String NAME = \"Content-Length\";\n\n    int getContentLength();\n    void setContentLength(int contentLength) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ContentTypeHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface ContentTypeHeader extends Header, MediaType, Parameters {\n    String NAME = \"Content-Type\";\n\n    String getCharset();\n    void setContentType(String contentType, String contentSubType)\n            throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/DateHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.util.Calendar;\n\npublic interface DateHeader extends Header {\n    String NAME = \"Date\";\n\n    Calendar getDate();\n    void setDate(Calendar date);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/Encoding.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface Encoding {\n    String getEncoding();\n    void setEncoding(String encoding) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ErrorInfoHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.address.URI;\n\npublic interface ErrorInfoHeader extends Header, Parameters {\n    String NAME = \"Error-Info\";\n\n    URI getErrorInfo();\n    void setErrorInfo(URI errorInfo);\n\n    String getErrorMessage();\n    void setErrorMessage(String errorMessage) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/EventHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface EventHeader extends Header, Parameters {\n    String NAME = \"Event\";\n\n    String getEventId();\n    void setEventId(String eventId) throws ParseException;\n\n    String getEventType();\n    void setEventType(String eventType) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ExpiresHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface ExpiresHeader extends Header {\n    String NAME = \"Expires\";\n\n    int getExpires();\n    void setExpires(int expires) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ExtensionHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface ExtensionHeader extends Header {\n    String getValue();\n    void setValue(String value) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/FromHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface FromHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"From\";\n\n    String getTag();\n    void setTag(String tag) throws ParseException;\n    boolean hasTag();\n    void removeTag();\n\n    String getDisplayName();\n    String getUserAtHostPort();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/Header.java",
    "content": "package javax2.sip.header;\n\nimport java.io.Serializable;\n\npublic interface Header extends Cloneable, Serializable {\n    String getName();\n\n    Object clone();\n    boolean equals(Object obj);\n    int hashCode();\n    String toString();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/HeaderAddress.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.address.Address;\n\npublic interface HeaderAddress {\n    Address getAddress();\n    void setAddress(Address address);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/HeaderFactory.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\nimport java.util.Calendar;\nimport java.util.List;\nimport java.util.Locale;\n\nimport javax2.sip.InvalidArgumentException;\nimport javax2.sip.address.Address;\nimport javax2.sip.address.URI;\n\npublic interface HeaderFactory {\n    void setPrettyEncoding(boolean flag);\n\n    AcceptEncodingHeader createAcceptEncodingHeader(String encoding)\n            throws ParseException;\n\n    AcceptHeader createAcceptHeader(String contentType, String contentSubType)\n            throws ParseException;\n\n    AcceptLanguageHeader createAcceptLanguageHeader(Locale language);\n\n    AlertInfoHeader createAlertInfoHeader(URI alertInfo);\n\n    AllowEventsHeader createAllowEventsHeader(String eventType)\n            throws ParseException;\n\n    AllowHeader createAllowHeader(String method) throws ParseException;\n\n    AuthenticationInfoHeader createAuthenticationInfoHeader(String response)\n            throws ParseException;\n\n    AuthorizationHeader createAuthorizationHeader(String scheme)\n            throws ParseException;\n\n    CallIdHeader createCallIdHeader(String callId) throws ParseException;\n\n    CallInfoHeader createCallInfoHeader(URI callInfo);\n\n    ContactHeader createContactHeader();\n\n    ContactHeader createContactHeader(Address address);\n\n    ContentDispositionHeader createContentDispositionHeader(\n            String contentDispositionType) throws ParseException;\n\n    ContentEncodingHeader createContentEncodingHeader(String encoding)\n            throws ParseException;\n\n    ContentLanguageHeader createContentLanguageHeader(Locale contentLanguage);\n\n    ContentLengthHeader createContentLengthHeader(int contentLength)\n            throws InvalidArgumentException;\n\n    ContentTypeHeader createContentTypeHeader(String contentType,\n            String contentSubType) throws ParseException;\n\n    /**\n     * @deprecated\n     * @see #createCSeqHeader(long, String)\n     */\n    CSeqHeader createCSeqHeader(int sequenceNumber, String method)\n            throws ParseException, InvalidArgumentException;\n\n    CSeqHeader createCSeqHeader(long sequenceNumber, String method)\n            throws ParseException, InvalidArgumentException;\n\n    DateHeader createDateHeader(Calendar date);\n\n    ErrorInfoHeader createErrorInfoHeader(URI errorInfo);\n\n    EventHeader createEventHeader(String eventType) throws ParseException;\n\n    ExpiresHeader createExpiresHeader(int expires)\n            throws InvalidArgumentException;\n\n    ExtensionHeader createExtensionHeader(String name, String value)\n            throws ParseException;\n\n    FromHeader createFromHeader(Address address, String tag)\n            throws ParseException;\n\n    Header createHeader(String name, String value) throws ParseException;\n    Header createHeader(String headerText) throws ParseException;\n\n    List createHeaders(String headers) throws ParseException;\n\n    InReplyToHeader createInReplyToHeader(String callId) throws ParseException;\n\n    MaxForwardsHeader createMaxForwardsHeader(int maxForwards)\n            throws InvalidArgumentException;\n\n    MimeVersionHeader createMimeVersionHeader(int majorVersion,\n            int minorVersion) throws InvalidArgumentException;\n\n    MinExpiresHeader createMinExpiresHeader(int minExpires)\n            throws InvalidArgumentException;\n\n    OrganizationHeader createOrganizationHeader(String organization)\n            throws ParseException;\n\n    PriorityHeader createPriorityHeader(String priority) throws ParseException;\n\n    ProxyAuthenticateHeader createProxyAuthenticateHeader(String scheme)\n            throws ParseException;\n\n    ProxyAuthorizationHeader createProxyAuthorizationHeader(String scheme)\n            throws ParseException;\n\n    ProxyRequireHeader createProxyRequireHeader(String optionTag)\n            throws ParseException;\n\n    RAckHeader createRAckHeader(long rSeqNumber, long cSeqNumber, String method)\n            throws InvalidArgumentException, ParseException;\n\n    /**\n     * @deprecated\n     * @see #createRAckHeader(long, long, String)\n     */\n    RAckHeader createRAckHeader(int rSeqNumber, int cSeqNumber, String method)\n            throws InvalidArgumentException, ParseException;\n\n    ReasonHeader createReasonHeader(String protocol, int cause, String text)\n            throws InvalidArgumentException, ParseException;\n\n    RecordRouteHeader createRecordRouteHeader(Address address);\n\n    ReferToHeader createReferToHeader(Address address);\n\n    ReplyToHeader createReplyToHeader(Address address);\n\n    RequireHeader createRequireHeader(String optionTag) throws ParseException;\n\n    RetryAfterHeader createRetryAfterHeader(int retryAfter)\n            throws InvalidArgumentException;\n\n    RouteHeader createRouteHeader(Address address);\n\n    RSeqHeader createRSeqHeader(long sequenceNumber)\n            throws InvalidArgumentException;\n\n    /**\n     * @deprecated\n     * @see #createRSeqHeader(long)\n     */\n    RSeqHeader createRSeqHeader(int sequenceNumber)\n            throws InvalidArgumentException;\n\n    ServerHeader createServerHeader(List product) throws ParseException;\n\n    SIPETagHeader createSIPETagHeader(String etag) throws ParseException;\n\n    SIPIfMatchHeader createSIPIfMatchHeader(String etag) throws ParseException;\n\n    SubjectHeader createSubjectHeader(String subject) throws ParseException;\n\n    SubscriptionStateHeader createSubscriptionStateHeader(\n            String subscriptionState) throws ParseException;\n\n    SupportedHeader createSupportedHeader(String optionTag)\n            throws ParseException;\n\n    TimeStampHeader createTimeStampHeader(float timeStamp)\n            throws InvalidArgumentException;\n\n    ToHeader createToHeader(Address address, String tag) throws ParseException;\n\n    UnsupportedHeader createUnsupportedHeader(String optionTag)\n            throws ParseException;\n\n    UserAgentHeader createUserAgentHeader(List product) throws ParseException;\n\n    ViaHeader createViaHeader(String host, int port, String transport,\n            String branch) throws InvalidArgumentException, ParseException;\n\n    WarningHeader createWarningHeader(String agent, int code, String comment)\n            throws InvalidArgumentException, ParseException;\n\n    WWWAuthenticateHeader createWWWAuthenticateHeader(String scheme)\n            throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/InReplyToHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface InReplyToHeader extends CallIdHeader {\n    String NAME = \"In-Reply-To\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/MaxForwardsHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface MaxForwardsHeader extends Header {\n    String NAME = \"Max-Forwards\";\n\n    void decrementMaxForwards() throws TooManyHopsException;\n\n    int getMaxForwards();\n    void setMaxForwards(int maxForwards) throws InvalidArgumentException;\n\n    boolean hasReachedZero();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/MediaType.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface MediaType {\n    String getContentSubType();\n    void setContentSubType(String contentSubType) throws ParseException;\n\n    String getContentType();\n    void setContentType(String contentType) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/MimeVersionHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface MimeVersionHeader extends Header {\n    String NAME = \"MIME-Version\";\n\n    int getMajorVersion();\n    void setMajorVersion(int majorVersion) throws InvalidArgumentException;\n\n    int getMinorVersion();\n    void setMinorVersion(int minorVersion) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/MinExpiresHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface MinExpiresHeader extends ExpiresHeader {\n    String NAME = \"Min-Expires\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/OptionTag.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface OptionTag {\n    String getOptionTag();\n    void setOptionTag(String optionTag) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/OrganizationHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface OrganizationHeader extends Header {\n    String NAME = \"Organization\";\n\n    String getOrganization();\n    void setOrganization(String organization) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/Parameters.java",
    "content": "package javax2.sip.header;\n\nimport gov2.nist.core.NameValue;\n\nimport java.text.ParseException;\nimport java.util.Iterator;\n\npublic interface Parameters {\n    String getParameter(String name);\n    void setParameter(String name, String value) throws ParseException;\n    void setParameter(NameValue nameValue) throws ParseException;\n\n    Iterator getParameterNames();\n    void removeParameter(String name);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/PriorityHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface PriorityHeader extends Header {\n    String NAME = \"Priority\";\n\n    String NON_URGENT = \"Non-Urgent\";\n    String NORMAL = \"Normal\";\n    String URGENT = \"Urgent\";\n    String EMERGENCY = \"Emergency\";\n\n    String getPriority();\n    void setPriority(String priority) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ProxyAuthenticateHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface ProxyAuthenticateHeader extends WWWAuthenticateHeader {\n    String NAME = \"Proxy-Authenticate\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ProxyAuthorizationHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface ProxyAuthorizationHeader extends AuthorizationHeader {\n    String NAME = \"Proxy-Authorization\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ProxyRequireHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface ProxyRequireHeader extends RequireHeader {\n    String NAME = \"Proxy-Require\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/RAckHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface RAckHeader extends Header {\n    String NAME = \"RAck\";\n\n    String getMethod();\n    void setMethod(String method) throws ParseException;\n\n    long getCSequenceNumber();\n    void setCSequenceNumber(long cSequenceNumber) throws InvalidArgumentException;\n\n    long getRSequenceNumber();\n    void setRSequenceNumber(long rSequenceNumber) throws InvalidArgumentException;\n\n    /**\n     * @deprecated\n     * @see #getCSequenceNumber()\n     */\n    int getCSeqNumber();\n    /**\n     * @deprecated\n     * @see #setCSequenceNumber(long)\n     */\n    void setCSeqNumber(int cSeqNumber) throws InvalidArgumentException;\n\n    /**\n     * @deprecated\n     * @see #getRSequenceNumber()\n     */\n    int getRSeqNumber();\n    /**\n     * @deprecated\n     * @see #setRSequenceNumber(long)\n     */\n    void setRSeqNumber(int rSeqNumber) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/RSeqHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface RSeqHeader extends Header {\n    String NAME = \"RSeq\";\n\n    long getSeqNumber();\n    void setSeqNumber(long sequenceNumber) throws InvalidArgumentException;\n\n    /**\n     * @deprecated\n     * @see #getSeqNumber()\n     */\n    int getSequenceNumber();\n\n    /**\n     * @deprecated\n     * @see #setSeqNumber(long)\n     */\n    void setSequenceNumber(int sequenceNumber) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ReasonHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface ReasonHeader extends Header, Parameters {\n    String NAME = \"Reason\";\n\n    int getCause();\n    void setCause(int cause) throws InvalidArgumentException;\n\n    String getProtocol();\n    void setProtocol(String protocol) throws ParseException;\n\n    String getText();\n    void setText(String text) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/RecordRouteHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface RecordRouteHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"Record-Route\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ReferToHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface ReferToHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"Refer-To\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ReplyToHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface ReplyToHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"Reply-To\";\n\n    String getDisplayName();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/RequireHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface RequireHeader extends OptionTag, Header {\n    String NAME = \"Require\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/RetryAfterHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface RetryAfterHeader extends Header, Parameters {\n    String NAME = \"Retry-After\";\n\n    String getComment();\n    void setComment(String comment) throws ParseException;\n    boolean hasComment();\n    void removeComment();\n\n    int getDuration();\n    void setDuration(int duration) throws InvalidArgumentException;\n    void removeDuration();\n\n    int getRetryAfter();\n    void setRetryAfter(int retryAfter) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/RouteHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface RouteHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"Route\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/SIPETagHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface SIPETagHeader extends ExtensionHeader {\n    String NAME = \"SIP-ETag\";\n\n    String getETag();\n    void setETag(String etag) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/SIPIfMatchHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface SIPIfMatchHeader extends SIPETagHeader {\n    String NAME = \"SIP-If-Match\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ServerHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\nimport java.util.List;\nimport java.util.ListIterator;\n\npublic interface ServerHeader extends Header {\n    String NAME = \"Server\";\n\n    ListIterator getProduct();\n    void setProduct(List product) throws ParseException;\n    void addProductToken(String productToken);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/SubjectHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface SubjectHeader extends Header {\n    String NAME = \"Subject\";\n\n    String getSubject();\n    void setSubject(String subject) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/SubscriptionStateHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface SubscriptionStateHeader extends ExpiresHeader, Parameters {\n    String NAME = \"Subscription-State\";\n\n    String DEACTIVATED = \"Deactivated\";\n    String GIVE_UP = \"Give-Up\";\n    String NO_RESOURCE = \"No-Resource\";\n    String PROBATION = \"Probation\";\n    String REJECTED = \"Rejected\";\n    String TIMEOUT = \"Timeout\";\n    String UNKNOWN = \"Unknown\";\n\n    String ACTIVE = \"Active\";\n    String PENDING = \"Pending\";\n    String TERMINATED = \"Terminated\";\n\n    String getReasonCode();\n    void setReasonCode(String reasonCode) throws ParseException;\n\n    int getRetryAfter();\n    void setRetryAfter(int retryAfter) throws InvalidArgumentException;\n\n    String getState();\n    void setState(String state) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/SupportedHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface SupportedHeader extends OptionTag, Header {\n    String NAME = \"Supported\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/TimeStampHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface TimeStampHeader extends Header {\n    String NAME = \"Timestamp\";\n\n    float getDelay();\n    void setDelay(float delay) throws InvalidArgumentException;\n    boolean hasDelay();\n    void removeDelay();\n\n    long getTime();\n    void setTime(long timeStamp) throws InvalidArgumentException;\n\n    int getTimeDelay();\n    void setTimeDelay(int delay) throws InvalidArgumentException;\n\n    float getTimeStamp();\n    void setTimeStamp(float timeStamp) throws InvalidArgumentException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ToHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\npublic interface ToHeader extends HeaderAddress, Header, Parameters {\n    String NAME = \"To\";\n\n    String getTag();\n    void setTag(String tag) throws ParseException;\n    boolean hasTag();\n    void removeTag();\n\n    String getDisplayName();\n    String getUserAtHostPort();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/TooManyHopsException.java",
    "content": "package javax2.sip.header;\n\npublic class TooManyHopsException extends Exception {\n    public TooManyHopsException(){\n        super();\n    }\n\n    public TooManyHopsException(String message) {\n        super(message);\n    }\n\n    public TooManyHopsException(String message, Throwable cause) {\n        super(message, cause);\n    }\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/UnsupportedHeader.java",
    "content": "package javax2.sip.header;\n\npublic interface UnsupportedHeader extends OptionTag, Header {\n    String NAME = \"Unsupported\";\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/UserAgentHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\nimport java.util.List;\nimport java.util.ListIterator;\n\npublic interface UserAgentHeader extends Header {\n    String NAME = \"User-Agent\";\n\n    ListIterator getProduct();\n    void setProduct(List product) throws ParseException;\n    void addProductToken(String productToken);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/ViaHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface ViaHeader extends Header, Parameters {\n    String NAME = \"Via\";\n\n    String getBranch();\n    void setBranch(String branch) throws ParseException;\n\n    String getHost();\n    void setHost(String host) throws ParseException;\n\n    String getMAddr();\n    void setMAddr(String mAddr) throws ParseException;\n\n    int getPort();\n    void setPort(int port) throws InvalidArgumentException;\n\n    String getProtocol();\n    void setProtocol(String protocol) throws ParseException;\n\n    String getReceived();\n    void setReceived(String received) throws ParseException;\n\n    int getRPort();\n    void setRPort() throws InvalidArgumentException;\n\n    String getTransport();\n    void setTransport(String transport) throws ParseException;\n\n    int getTTL();\n    void setTTL(int ttl) throws InvalidArgumentException;\n\n    String getSentByField();\n    String getSentProtocolField();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/WWWAuthenticateHeader.java",
    "content": "package javax2.sip.header;\n\nimport javax2.sip.address.URI;\n\npublic interface WWWAuthenticateHeader extends AuthorizationHeader {\n    String NAME = \"WWW-Authenticate\";\n\n    /**\n     * @deprecated This method should return null.\n     */\n    URI getURI();\n\n    /**\n     * @deprecated This method should return immediately.\n     */\n    void setURI(URI uri);\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/header/WarningHeader.java",
    "content": "package javax2.sip.header;\n\nimport java.text.ParseException;\n\nimport javax2.sip.InvalidArgumentException;\n\npublic interface WarningHeader extends Header {\n    String NAME = \"Warning\";\n\n    int ATTRIBUTE_NOT_UNDERSTOOD = 10;\n    int INCOMPATIBLE_BANDWIDTH_UNITS = 20;\n    int INCOMPATIBLE_MEDIA_FORMAT = 21;\n    int INCOMPATIBLE_NETWORK_ADDRESS_FORMATS = 22;\n    int INCOMPATIBLE_NETWORK_PROTOCOL = 23;\n    int INCOMPATIBLE_TRANSPORT_PROTOCOL = 24;\n    int INSUFFICIENT_BANDWIDTH = 30;\n    int MEDIA_TYPE_NOT_AVAILABLE = 40;\n    int MISCELLANEOUS_WARNING = 99;\n    int MULTICAST_NOT_AVAILABLE = 50;\n    int SESSION_DESCRIPTION_PARAMETER_NOT_UNDERSTOOD = 60;\n    int UNICAST_NOT_AVAILABLE = 51;\n\n    String getAgent();\n    void setAgent(String agent) throws ParseException;\n\n    int getCode();\n    void setCode(int code) throws InvalidArgumentException;\n\n    String getText();\n    void setText(String text) throws ParseException;\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/message/Message.java",
    "content": "package javax2.sip.message;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\nimport java.util.ListIterator;\n\nimport javax2.sip.SipException;\nimport javax2.sip.header.ContentDispositionHeader;\nimport javax2.sip.header.ContentEncodingHeader;\nimport javax2.sip.header.ContentLanguageHeader;\nimport javax2.sip.header.ContentLengthHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.ExpiresHeader;\nimport javax2.sip.header.Header;\n\npublic interface Message extends Cloneable, Serializable {\n    void addFirst(Header header) throws SipException, NullPointerException;\n    void addHeader(Header header);\n    void addLast(Header header) throws SipException, NullPointerException;\n\n    Header getHeader(String headerName);\n    void setHeader(Header header);\n\n    void removeFirst(String headerName) throws NullPointerException;\n    void removeLast(String headerName) throws NullPointerException;\n    void removeHeader(String headerName);\n\n    ListIterator getHeaderNames();\n    ListIterator getHeaders(String headerName);\n    ListIterator getUnrecognizedHeaders();\n\n    Object getApplicationData();\n    void setApplicationData(Object applicationData);\n\n    ContentLengthHeader getContentLength();\n    void setContentLength(ContentLengthHeader contentLength);\n\n    ContentLanguageHeader getContentLanguage();\n    void setContentLanguage(ContentLanguageHeader contentLanguage);\n\n    ContentEncodingHeader getContentEncoding();\n    void setContentEncoding(ContentEncodingHeader contentEncoding);\n\n    ContentDispositionHeader getContentDisposition();\n    void setContentDisposition(ContentDispositionHeader contentDisposition);\n\n    Object getContent();\n    byte[] getRawContent();\n    void setContent(Object content, ContentTypeHeader contentTypeHeader)\n            throws ParseException;\n    void removeContent();\n\n\n    ExpiresHeader getExpires();\n    void setExpires(ExpiresHeader expires);\n\n    String getSIPVersion();\n    void setSIPVersion(String version) throws ParseException;\n\n    Object clone();\n    boolean equals(Object object);\n    int hashCode();\n    String toString();\n}\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/message/MessageFactory.java",
    "content": "package javax2.sip.message;\n\nimport java.text.ParseException;\nimport java.util.List;\n\nimport javax2.sip.address.URI;\nimport javax2.sip.header.CSeqHeader;\nimport javax2.sip.header.CallIdHeader;\nimport javax2.sip.header.ContentTypeHeader;\nimport javax2.sip.header.FromHeader;\nimport javax2.sip.header.MaxForwardsHeader;\nimport javax2.sip.header.ServerHeader;\nimport javax2.sip.header.ToHeader;\nimport javax2.sip.header.UserAgentHeader;\n\npublic interface MessageFactory {\n    Request createRequest(URI requestURI, String method, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            Object content) throws ParseException;\n\n    Request createRequest(URI requestURI, String method, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            byte[] content) throws ParseException;\n\n    Request createRequest(URI requestURI, String method, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards) throws ParseException;\n\n    Request createRequest(String request) throws ParseException;\n\n    Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            Object content) throws ParseException;\n\n    Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards, ContentTypeHeader contentType,\n            byte[] content) throws ParseException;\n\n    Response createResponse(int statusCode, CallIdHeader callId,\n            CSeqHeader cSeq, FromHeader from, ToHeader to, List via,\n            MaxForwardsHeader maxForwards) throws ParseException;\n\n    Response createResponse(int statusCode, Request request,\n            ContentTypeHeader contentType, Object content)\n            throws ParseException;\n\n    Response createResponse(int statusCode, Request request,\n            ContentTypeHeader contentType, byte[] content)\n            throws ParseException;\n\n    Response createResponse(int statusCode, Request request)\n            throws ParseException;\n\n    Response createResponse(String response) throws ParseException;\n\n    void setDefaultContentEncodingCharset(String defaultContentEncodingCharset)\n            throws NullPointerException, IllegalArgumentException;\n    void setDefaultServerHeader(ServerHeader defaultServerHeader);\n    void setDefaultUserAgentHeader(UserAgentHeader defaultUserAgentHeader);\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/message/Request.java",
    "content": "package javax2.sip.message;\n\nimport java.text.ParseException;\n\nimport javax2.sip.address.URI;\n\npublic interface Request extends Message {\n    String ACK = \"ACK\";\n    String BYE = \"BYE\";\n    String CANCEL = \"CANCEL\";\n    String INVITE = \"INVITE\";\n    String OPTIONS = \"OPTIONS\";\n    String REGISTER = \"REGISTER\";\n\n    String INFO = \"INFO\";\n    String MESSAGE = \"MESSAGE\";\n    String NOTIFY = \"NOTIFY\";\n    String PRACK = \"PRACK\";\n    String PUBLISH = \"PUBLISH\";\n    String REFER = \"REFER\";\n    String SUBSCRIBE = \"SUBSCRIBE\";\n    String UPDATE = \"UPDATE\";\n\n    String getMethod();\n    void setMethod(String method) throws ParseException;\n\n    URI getRequestURI();\n    void setRequestURI(URI requestURI);\n}\n\n"
  },
  {
    "path": "libs/nist_sip/src/javax2/sip/message/Response.java",
    "content": "package javax2.sip.message;\n\nimport java.text.ParseException;\n\npublic interface Response extends Message {\n    int TRYING = 100;\n    int RINGING = 180;\n    int CALL_IS_BEING_FORWARDED = 181;\n    int QUEUED = 182;\n    int SESSION_PROGRESS = 183;\n    int OK = 200;\n    int ACCEPTED = 202;\n    int MULTIPLE_CHOICES = 300;\n    int MOVED_PERMANENTLY = 301;\n    int MOVED_TEMPORARILY = 302;\n    int USE_PROXY = 305;\n    int ALTERNATIVE_SERVICE = 380;\n    int BAD_REQUEST = 400;\n    int UNAUTHORIZED = 401;\n    int PAYMENT_REQUIRED = 402;\n    int FORBIDDEN = 403;\n    int NOT_FOUND = 404;\n    int METHOD_NOT_ALLOWED = 405;\n    int NOT_ACCEPTABLE = 406;\n    int PROXY_AUTHENTICATION_REQUIRED = 407;\n    int REQUEST_TIMEOUT = 408;\n    int GONE = 410;\n    int CONDITIONAL_REQUEST_FAILED = 412;\n    int REQUEST_ENTITY_TOO_LARGE = 413;\n    int REQUEST_URI_TOO_LONG = 414;\n    int UNSUPPORTED_MEDIA_TYPE = 415;\n    int UNSUPPORTED_URI_SCHEME = 416;\n    int BAD_EXTENSION = 420;\n    int EXTENSION_REQUIRED = 421;\n    int INTERVAL_TOO_BRIEF = 423;\n    int TEMPORARILY_UNAVAILABLE = 480;\n    int CALL_OR_TRANSACTION_DOES_NOT_EXIST = 481;\n    int LOOP_DETECTED = 482;\n    int TOO_MANY_HOPS = 483;\n    int ADDRESS_INCOMPLETE = 484;\n    int AMBIGUOUS = 485;\n    int BUSY_HERE = 486;\n    int REQUEST_TERMINATED = 487;\n    int NOT_ACCEPTABLE_HERE = 488;\n    int BAD_EVENT = 489;\n    int REQUEST_PENDING = 491;\n    int UNDECIPHERABLE = 493;\n    int SERVER_INTERNAL_ERROR = 500;\n    int NOT_IMPLEMENTED = 501;\n    int BAD_GATEWAY = 502;\n    int SERVICE_UNAVAILABLE = 503;\n    int SERVER_TIMEOUT = 504;\n    int VERSION_NOT_SUPPORTED = 505;\n    int MESSAGE_TOO_LARGE = 513;\n    int BUSY_EVERYWHERE = 600;\n    int DECLINE = 603;\n    int DOES_NOT_EXIST_ANYWHERE = 604;\n    int SESSION_NOT_ACCEPTABLE = 606;\n\n    int getStatusCode();\n    void setStatusCode(int statusCode) throws ParseException;\n\n    String getReasonPhrase();\n    void setReasonPhrase(String reasonPhrase) throws ParseException;\n}\n"
  },
  {
    "path": "mediaplayer/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.orangelabs.rcs\">\n    <uses-sdk android:minSdkVersion=\"12\" />\n</manifest>"
  },
  {
    "path": "mediaplayer/build.gradle",
    "content": "//--------------------------------------------------------------------\n// Android library due to the dependecy\n//--------------------------------------------------------------------\napply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n}"
  },
  {
    "path": "mediaplayer/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "mediaplayer/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-21\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/CodecChain.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.ProcessorOutputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Codec chain\n * \n * @author jexa7410\n */\npublic class CodecChain {\n    /**\n     * List of codecs\n     */\n    private Codec[] codecs = null;\n\n    /**\n     * List of buffers\n     */\n    private Buffer[] buffers = null;\n\n    /**\n     * Renderer\n     */\n    private ProcessorOutputStream renderer;\n\n    /**\n     * Constructor\n     * \n     * @param codecs Codecs list\n     */\n    public CodecChain(Codec[] codecs, ProcessorOutputStream renderer) {\n        this.codecs = codecs;\n        this.renderer = renderer;\n\n        // Create the buffer chain\n        buffers = new Buffer[codecs.length + 1];\n        for (int i = 0; i < codecs.length; i++) {\n            buffers[i] = new Buffer();\n        }\n\n        // Prepare codecs\n        for (int i = 0; i < codecs.length; i++) {\n            codecs[i].open();\n        }\n    }\n\n    /**\n     * Codec chain processing\n     * \n     * @param input Input buffer\n     * @return Result\n     */\n    public int process(Buffer input) {\n        int codecNo = 0;\n        return doProcess(codecNo, input);\n    }\n\n    /**\n     * Recursive codec processing\n     * \n     * @param codecNo Codec index\n     * @param input Input buffer\n     * @return Result\n     */\n    private int doProcess(int codecNo, Buffer input) {\n        if (codecNo == codecs.length) {\n            // End of chain\n            try {\n                // Write data to the output stream\n                if (input.isFragmented()) {\n                    // Write data from sub-buffers to the output stream\n                    final Buffer[] fragments = input.getFragments();\n                    for (int i = 0; i < input.getFragmentsSize(); i++) {\n                        Buffer fragment = fragments[i];\n                        renderer.write(fragment);\n                        fragment.setData(null);\n                    }\n                    input.setFragments(null);\n                } else {\n                    renderer.write(input);\n                }\n                return Codec.BUFFER_PROCESSED_OK;\n            } catch (Exception e) {\n                return Codec.BUFFER_PROCESSED_FAILED;\n            }\n        } else {\n            // Process this codec\n            Codec codec = codecs[codecNo];\n            int returnVal;\n            do {\n                try {\n                    returnVal = codec.process(input, buffers[codecNo]);\n                } catch (Exception e) {\n                    return Codec.BUFFER_PROCESSED_FAILED;\n                }\n                if (returnVal == Codec.BUFFER_PROCESSED_FAILED) {\n                    return Codec.BUFFER_PROCESSED_FAILED;\n                }\n\n                if ((returnVal & Codec.OUTPUT_BUFFER_NOT_FILLED) == 0) {\n                    if (!(buffers[codecNo].isDiscard() || buffers[codecNo].isEOM())) {\n                        doProcess(codecNo + 1, buffers[codecNo]);\n                    }\n                    buffers[codecNo].setOffset(0);\n                    buffers[codecNo].setLength(0);\n                    buffers[codecNo].setFlags(0);\n                    buffers[codecNo].setFragments(null);\n                }\n            } while ((returnVal & Codec.INPUT_BUFFER_NOT_CONSUMED) != 0);\n\n            return returnVal;\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/DummyPacketGenerator.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.DummyPacketSourceStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpOutputStream;\n\n/**\n * Dummy packet generator for maintaining alive the network address in NAT\n * \n * @author jexa7410\n */\npublic class DummyPacketGenerator {\n    /**\n     * Media processor\n     */\n    private Processor processor = null;\n\n    /**\n     * RTP output stream\n     */\n    private RtpOutputStream outputStream = null;\n\n    /**\n     * DummyPacketSourceStream\n     */\n    private DummyPacketSourceStream inputStream = null;\n\n    /**\n     * Constructor\n     */\n    public DummyPacketGenerator() {\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtpStream already existing RTP input stream\n     * @throws RtpException\n     */\n    public void prepareSession(String remoteAddress, int remotePort, RtpInputStream rtpStream)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new DummyPacketSourceStream();\n            inputStream.open();\n\n            // Create the output stream\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, rtpStream);\n            outputStream.open();\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, new Codec[0]);\n\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n\n    /**\n     * Start the RTP session\n     */\n    public void startSession() {\n        // Start the media processor\n        if (processor != null) {\n            processor.startProcessing();\n        }\n    }\n\n    /**\n     * Stop the RTP session\n     */\n    public void stopSession() {\n        // Stop the media processor\n        if (processor != null) {\n            processor.stopProcessing();\n        }\n\n        if (outputStream != null)\n            outputStream.close();\n    }\n\n    /**\n     * Set incomingStarted.\n     */\n    public void incomingStarted() {\n        inputStream.incomingStarted();\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/MediaRegistry.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Vector;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.H264VideoFormat;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoFormat;\n\n/**\n * Media registry that handles the supported codecs\n * \n * @author jexa7410\n */\npublic class MediaRegistry {\n\n    /**\n     * Supported codecs\n     */\n    private static Hashtable<String, Format> SUPPORTED_CODECS = new Hashtable<String, Format>();\n    static {\n        SUPPORTED_CODECS.put(H264VideoFormat.ENCODING.toLowerCase(), new H264VideoFormat());\n    }\n\n    /**\n     * Returns the list of the supported video format\n     * \n     * @return List of video formats\n     */\n    public static Vector<VideoFormat> getSupportedVideoFormats() {\n        Vector<VideoFormat> list = new Vector<VideoFormat>();\n        for (Enumeration<Format> e = SUPPORTED_CODECS.elements(); e.hasMoreElements();) {\n            Format fmt = (Format) e.nextElement();\n            if (fmt instanceof VideoFormat) {\n                list.addElement((VideoFormat) fmt);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * Generate the format associated to the codec name\n     * \n     * @param codec Codec name\n     * @return Format\n     */\n    public static Format generateFormat(String codec) {\n        return (Format) SUPPORTED_CODECS.get(codec.toLowerCase());\n    }\n\n    /**\n     * Is codec supported\n     * \n     * @param codec Codec name\n     * @return Boolean\n     */\n    public static boolean isCodecSupported(String codec) {\n        Format format = (Format) SUPPORTED_CODECS.get(codec.toLowerCase());\n        return (format != null);\n    }\n\n    /**\n     * Generate the codec encoding chain\n     * \n     * @param encoding Encoding name\n     * @return Codec chain\n     */\n    public static Codec[] generateEncodingCodecChain(String encoding) {\n        if (encoding.equalsIgnoreCase(H264VideoFormat.ENCODING)) {\n            // Java H264 packetizer\n            Codec[] chain = {\n                    new com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer()\n            };\n            return chain;\n        } else {\n            // Codec implemented in the native part\n            return new Codec[0];\n        }\n    }\n\n    /**\n     * Generate the decoding codec chain\n     * \n     * @param encoding Encoding name\n     * @return Codec chain\n     */\n    public static Codec[] generateDecodingCodecChain(String encoding) {\n        if (encoding.equalsIgnoreCase(H264VideoFormat.ENCODING)) {\n            // Java H264 depacketizer\n            Codec[] chain = {\n                    new com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaDepacketizer()\n            };\n            return chain;\n        } else {\n            // Codec implemented in the native part\n            return new Codec[0];\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/MediaRtpReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.MediaRendererStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\n\n/**\n * Media RTP receiver\n */\npublic class MediaRtpReceiver {\n    /**\n     * Media processor\n     */\n    protected Processor processor = null;\n\n    /**\n     * Local port number (RTP listening port)\n     */\n    protected int localPort;\n\n    /**\n     * RTP Input Stream\n     */\n    protected RtpInputStream inputStream = null;\n\n    /**\n     * Constructor\n     * \n     * @param localPort Local port number\n     */\n    public MediaRtpReceiver(int localPort) {\n        this.localPort = localPort;\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param renderer Renderer\n     * @param format format\n     * @param rtpStreamListener RTP Stream listener\n     * @throws RtpException When an error occurs\n     */\n    public void prepareSession(String remoteAddress, int remotePort,\n            MediaOutput renderer, Format format, RtpStreamListener rtpStreamListener)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new RtpInputStream(remoteAddress, remotePort, localPort, format);\n            inputStream.addRtpStreamListener(rtpStreamListener);\n            inputStream.open();\n\n            // Create the output stream\n            MediaRendererStream outputStream = new MediaRendererStream(renderer);\n            outputStream.open();\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateDecodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n\n    /**\n     * Start the RTP session\n     */\n    public void startSession() {\n        // Start the media processor\n        if (processor != null) {\n            processor.startProcessing();\n        }\n    }\n\n    /**\n     * Stop the RTP session\n     */\n    public void stopSession() {\n        // Stop the media processor\n        if (processor != null) {\n            processor.stopProcessing();\n        }\n    }\n\n    /**\n     * Returns the RTP input stream\n     * \n     * @return RTP input stream\n     */\n    public RtpInputStream getInputStream() {\n        return inputStream;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/MediaRtpSender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.MediaCaptureStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpOutputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\n\n/**\n * Media RTP sender\n */\npublic class MediaRtpSender {\n    /**\n     * Format\n     */\n    protected Format format;\n\n    /**\n     * Media processor\n     */\n    protected Processor processor = null;\n\n    /**\n     * MediaCaptureStream\n     */\n    protected MediaCaptureStream inputStream = null;\n\n    /**\n     * RTP output stream\n     */\n    protected RtpOutputStream outputStream = null;\n\n    /**\n     * Local RTP port\n     */\n    protected int localRtpPort;\n\n    /**\n     * Constructor\n     * \n     * @param format Media format\n     */\n    public MediaRtpSender(Format format, int localRtpPort) {\n        this.format = format;\n        this.localRtpPort = localRtpPort;\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @throws RtpException\n     */\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpStreamListener rtpStreamListener)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new MediaCaptureStream(format, player);\n            inputStream.open();\n\n            // Create the output stream\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, localRtpPort,\n                    RtpOutputStream.RTCP_SOCKET_TIMEOUT);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n\n    /**\n     * Prepare the RTP session for a sender associated to a receiver\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @throws RtpException\n     */\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpInputStream rtpStream, RtpStreamListener rtpStreamListener)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new MediaCaptureStream(format, player);\n            inputStream.open();\n\n            // Create the output stream\n            // outputStream = new RtpOutputStream(remoteAddress, remotePort, localRtpPort,\n            // RtpOutputStream.RTCP_SOCKET_TIMEOUT);\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, rtpStream);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n\n    /**\n     * Start the RTP session\n     */\n    public void startSession() {\n\n        // Start the media processor\n        if (processor != null) {\n            processor.startProcessing();\n        }\n    }\n\n    /**\n     * Stop the RTP session\n     */\n    public void stopSession() {\n        // Stop the media processor\n        if (processor != null) {\n            processor.stopProcessing();\n        }\n\n        if (outputStream != null)\n            outputStream.close();\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/Processor.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.ProcessorInputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.ProcessorOutputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Media processor. A processor receives an input stream, use a codec chain to filter the data\n * before to send it to the output stream.\n * \n * @author jexa7410\n */\npublic class Processor extends Thread {\n    /**\n     * Processor input stream\n     */\n    private ProcessorInputStream inputStream;\n\n    /**\n     * Processor output stream\n     */\n    private ProcessorOutputStream outputStream;\n\n    /**\n     * Codec chain\n     */\n    private CodecChain codecChain;\n\n    /**\n     * Processor status flag\n     */\n    private boolean interrupted = false;\n\n    /**\n     * Constructor\n     * \n     * @param inputStream Input stream\n     * @param outputStream Output stream\n     * @param codecs List of codecs\n     */\n    public Processor(ProcessorInputStream inputStream, ProcessorOutputStream outputStream,\n            Codec[] codecs) {\n        super();\n\n        this.inputStream = inputStream;\n        this.outputStream = outputStream;\n\n        // Create the codec chain\n        codecChain = new CodecChain(codecs, outputStream);\n    }\n\n    /**\n     * Start processing\n     */\n    public void startProcessing() {\n        interrupted = false;\n        start();\n    }\n\n    /**\n     * Stop processing\n     */\n    public void stopProcessing() {\n        interrupted = true;\n\n        // Close streams\n        outputStream.close();\n        inputStream.close();\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            // Start processing\n            while (!interrupted) {\n                // Read data from the input stream\n                Buffer inBuffer = inputStream.read();\n                if (inBuffer == null) {\n                    interrupted = true;\n                    break;\n                }\n\n                // Codec chain processing\n                int result = codecChain.process(inBuffer);\n                if ((result != Codec.BUFFER_PROCESSED_OK)\n                        && (result != Codec.OUTPUT_BUFFER_NOT_FILLED)) {\n                    interrupted = true;\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Returns the input stream\n     * \n     * @return Stream\n     */\n    public ProcessorInputStream getInputStream() {\n        return inputStream;\n    }\n\n    /**\n     * Returns the output stream\n     * \n     * @return Stream\n     */\n    public ProcessorOutputStream getOutputStream() {\n        return outputStream;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/RtpException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\n/**\n * RTP exception\n * \n * @author JM. Auffret\n */\npublic class RtpException extends java.lang.Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param error Error message\n     */\n    public RtpException(String error) {\n        super(error);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/RtpUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\n/**\n * RTP utils\n * \n * @author hlxn7157\n */\npublic class RtpUtils {\n\n    /**\n     * RTP Extension ID used by the client. The extension ID is a value between 1 and 15 arbitrarily\n     * chosen by the sender, as defined in RFC5285\n     */\n    public static final int RTP_DEFAULT_EXTENSION_ID = 9;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/VideoRtpReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.VideoRendererStream;\n\n/**\n * Video RTP receiver\n * \n * @author hlxn7157\n */\npublic class VideoRtpReceiver extends MediaRtpReceiver {\n    /**\n     * Constructor\n     * \n     * @param localPort Local port number\n     */\n    public VideoRtpReceiver(int localPort) {\n        super(localPort);\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param orientationHeaderId RTP orientation extension header id\n     * @param renderer Renderer\n     * @param format Video format\n     * @param rtpStreamListener RTP Stream listener\n     * @throws RtpException When an error occurs\n     */\n    public void prepareSession(String remoteAddress, int remotePort, int orientationHeaderId,\n            MediaOutput renderer, Format format, RtpStreamListener rtpStreamListener)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new RtpInputStream(remoteAddress, remotePort, localPort, format);\n            inputStream.setExtensionHeaderId(orientationHeaderId);\n            inputStream.addRtpStreamListener(rtpStreamListener);\n            inputStream.open();\n\n            // Create the output stream\n            VideoRendererStream outputStream = new VideoRendererStream(renderer);\n            outputStream.open();\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateDecodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/VideoRtpSender.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpInputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpOutputStream;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.RtpStreamListener;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.stream.VideoCaptureStream;\n\n/**\n * Video RTP sender\n * \n * @author hlxn7157\n */\npublic class VideoRtpSender extends MediaRtpSender {\n    /**\n     * Constructor\n     * \n     * @param format Media format\n     */\n    public VideoRtpSender(Format format, int localRtpPort) {\n        super(format, localRtpPort);\n    }\n\n    /**\n     * Prepare the RTP session\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param RtpStreamListener rtp stream listener\n     * @throws RtpException\n     */\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpStreamListener rtpStreamListener)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new VideoCaptureStream(format, player);\n            inputStream.open();\n\n            // Create the output stream\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, localRtpPort,\n                    RtpOutputStream.RTCP_SOCKET_TIMEOUT);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n\n    /**\n     * Prepare the RTP session for a sender associated to a receiver\n     * \n     * @param player Media player\n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtpStream rtp input stream\n     * @param RtpStreamListener rtp stream listener\n     * @throws RtpException\n     */\n\n    public void prepareSession(MediaInput player, String remoteAddress, int remotePort,\n            RtpInputStream rtpStream, RtpStreamListener rtpStreamListener)\n            throws RtpException {\n        try {\n            // Create the input stream\n            inputStream = new VideoCaptureStream(format, player);\n            inputStream.open();\n\n            // Create the output stream\n            // outputStream = new RtpOutputStream(remoteAddress, remotePort, localRtpPort,\n            // RtpOutputStream.RTCP_SOCKET_TIMEOUT);\n            outputStream = new RtpOutputStream(remoteAddress, remotePort, rtpStream);\n            outputStream.addRtpStreamListener(rtpStreamListener);\n            outputStream.open();\n\n            // Create the codec chain\n            Codec[] codecChain = MediaRegistry.generateEncodingCodecChain(format.getCodec());\n\n            // Create the media processor\n            processor = new Processor(inputStream, outputStream, codecChain);\n        } catch (Exception e) {\n            throw new RtpException(\"Can't prepare resources\");\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/Codec.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Abstract codec\n * \n * @author jexa7410\n */\npublic abstract class Codec {\n\n    /**\n     * The input buffer was converted successfully to output\n     */\n    public static final int BUFFER_PROCESSED_OK = 0;\n\n    /**\n     * The input buffer could not be handled\n     */\n    public static final int BUFFER_PROCESSED_FAILED = 1 << 0;\n\n    /**\n     * The input buffer chunk was not fully consumed\n     */\n    public static final int INPUT_BUFFER_NOT_CONSUMED = 1 << 1;\n\n    /**\n     * The output buffer chunk was not filled\n     */\n    public static final int OUTPUT_BUFFER_NOT_FILLED = 1 << 2;\n\n    /**\n     * Input format\n     */\n    private Format inputFormat;\n\n    /**\n     * Ouput format\n     */\n    private Format outputFormat;\n\n    /**\n     * Set the input format\n     * \n     * @param input Input format\n     * @return New format\n     */\n    public Format setInputFormat(Format input) {\n        inputFormat = input;\n        return input;\n    }\n\n    /**\n     * Set the output format\n     * \n     * @param output Output format\n     * @return New format\n     */\n    public Format setOutputFormat(Format output) {\n        outputFormat = output;\n        return output;\n    }\n\n    /**\n     * Return the input format\n     * \n     * @return Format\n     */\n    public Format getInputFormat() {\n        return inputFormat;\n    }\n\n    /**\n     * Return the output format\n     * \n     * @return Format\n     */\n    public Format getOutputFormat() {\n        return outputFormat;\n    }\n\n    /**\n     * Reset the codec\n     */\n    public void reset() {\n    }\n\n    /**\n     * Open the codec\n     */\n    public void open() {\n    }\n\n    /**\n     * Close the codec\n     */\n    public void close() {\n    }\n\n    /**\n     * Test if it's the end of media\n     * \n     * @return Boolean\n     */\n    protected boolean isEOM(Buffer inputBuffer) {\n        return inputBuffer.isEOM();\n    }\n\n    /**\n     * Propagate EOM to the ouput buffer\n     * \n     * @param outputBuffer Ouput buffer\n     */\n    protected void propagateEOM(Buffer outputBuffer) {\n        updateOutput(outputBuffer, getOutputFormat(), 0, 0);\n        outputBuffer.setEOM(true);\n    }\n\n    /**\n     * Update the ouput buffer informations\n     * \n     * @param outputBuffer Ouput buffer\n     * @param format Ouput format\n     * @param length Ouput length\n     * @param offset Ouput offset\n     */\n    protected void updateOutput(Buffer outputBuffer, Format format, int length,\n            int offset) {\n        outputBuffer.setFormat(format);\n        outputBuffer.setLength(length);\n        outputBuffer.setOffset(offset);\n    }\n\n    /**\n     * Validate that the Buffer's data size is at least newSize\n     * \n     * @return Array with sufficient capacity\n     */\n    protected byte[] validateByteArraySize(Buffer buffer, int newSize) {\n        byte[] typedArray = (byte[]) buffer.getData();\n        if (typedArray != null) {\n            if (typedArray.length >= newSize) {\n                return typedArray;\n            }\n\n            byte[] tempArray = new byte[newSize];\n            System.arraycopy(typedArray, 0, tempArray, 0, typedArray.length);\n            typedArray = tempArray;\n        } else {\n            typedArray = new byte[newSize];\n        }\n\n        buffer.setData(typedArray);\n        return typedArray;\n    }\n\n    /**\n     * Performs the media processing defined by this codec\n     * \n     * @param input The buffer that contains the media data to be processed\n     * @param output The buffer in which to store the processed media data\n     * @return Processing result\n     */\n    public abstract int process(Buffer input, Buffer output);\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/VideoCodec.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.Codec;\n\n/**\n * Video codec abstract class\n * \n * @author jexa7410\n */\npublic abstract class VideoCodec extends Codec {\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/H264Config.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264;\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\n/**\n * Default H264 Settings\n * \n * @author hlxn7157\n * @author Deutsche Telekom AG\n */\npublic class H264Config {\n\n    /** Constant values */\n    public static final int QCIF_WIDTH = 176;\n    public static final int QCIF_HEIGHT = 144;\n\n    public static final int CIF_WIDTH = 352;\n    public static final int CIF_HEIGHT = 288;\n\n    public static final int QVGA_WIDTH = 320;\n    public static final int QVGA_HEIGHT = 240;\n\n    public static final int VGA_WIDTH = 640;\n    public static final int VGA_HEIGHT = 480;\n\n    /**\n     * Codec name\n     */\n    public final static String CODEC_NAME = \"H264\";\n\n    /**\n     * Default clock rate\n     */\n    public final static int CLOCK_RATE = 90000;\n\n    /**\n     * H264 OPTIONAL payload format parameter \"profile-level-id\" - RFC 3984\n     */\n    public static final String CODEC_PARAM_PROFILEID = \"profile-level-id\";\n\n    /**\n     * H264 OPTIONAL payload format parameter \"packetization-mode\" - RFC 3984\n     */\n    public static final String CODEC_PARAM_PACKETIZATIONMODE = \"packetization-mode\";\n\n    /**\n     * H264 OPTIONAL payload format parameter \"sprop-parameter-sets\" - RFC 3984\n     */\n    public static final String CODEC_PARAM_SPROP_PARAMETER_SETS = \"sprop-parameter-sets\";\n\n    /**\n     * Default codec params\n     */\n    public final static String CODEC_PARAMS = \"profile-level-id=42900b;packetization-mode=1\";\n\n    /**\n     * Default video width\n     */\n    public final static int VIDEO_WIDTH = QCIF_WIDTH;\n\n    /**\n     * Default video height\n     */\n    public final static int VIDEO_HEIGHT = QCIF_HEIGHT;\n\n    /**\n     * Default video frame rate\n     */\n    public final static int FRAME_RATE = 15;\n\n    /**\n     * Default video bit rate\n     */\n    public final static int BIT_RATE = 64000;\n\n    /**\n     * Get value of packetization mode\n     * \n     * @param codecParams\n     * @return\n     */\n    public static int getCodecPacketizationMode(String codecParams) {\n        int packetization_mode = 0;\n        String valPackMode = getParameterValue(CODEC_PARAM_PACKETIZATIONMODE, codecParams);\n        if (valPackMode != null) {\n            try {\n                packetization_mode = Integer.parseInt(valPackMode);\n            } catch (Exception e) {\n            }\n        }\n        return packetization_mode;\n    }\n\n    /**\n     * Get value of profile level ID\n     * \n     * @param codecParams\n     * @return\n     */\n    public static String getCodecProfileLevelId(String codecParams) {\n        return getParameterValue(CODEC_PARAM_PROFILEID, codecParams);\n    }\n\n    /**\n     * Get parameter value from SDP parameters string with parameter-value format 'key1=value1; ...\n     * keyN=valueN'\n     * \n     * @param paramKey parameter name\n     * @param params parameters string\n     * @return if parameter exists return {@link String} with value, otherwise return\n     *         <code>null</code>\n     */\n    private static String getParameterValue(String paramKey, String params) {\n        String value = null;\n        if (params != null && params.length() > 0) {\n            try {\n                Pattern p = Pattern.compile(\"(?<=\" + paramKey + \"=).*?(?=;|$)\");\n                Matcher m = p.matcher(params);\n                if (m.find()) {\n                    value = m.group(0);\n                }\n            } catch (PatternSyntaxException e) {\n                // Nothing to do\n            }\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/H264RtpHeaders.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264;\n\n/**\n * H264RtpHeaders RFC 3984: Two special headers are added to each H264 packet that immediately\n * follows the RTP header: First Header - The FU indicator octet has the following format:\n * +---------------+ |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |F|NRI| Type | +---------------+ Second\n * Header - The FU header has the following format: +---------------+ |0|1|2|3|4|5|6|7|\n * +-+-+-+-+-+-+-+-+ |S|E|R| Type | +---------------+\n * \n * @author Deutsche Telekom AG\n */\npublic class H264RtpHeaders {\n\n    /**\n     * AVC NAL picture parameter\n     */\n    public static final int AVC_NALTYPE_FUA = 28;\n\n    private final static int FU_INDICATOR_SIZE = 1;\n    private final static int FU_HEADER_SIZE = 1;\n\n    /**\n     * First Header - The FU indicator octet\n     */\n    private boolean FUI_F;\n    private int FUI_NRI;\n    private byte FUI_TYPE;\n\n    /**\n     * Second Header - The FU header\n     */\n    private boolean FUH_S;\n    private boolean FUH_E;\n    private boolean FUH_R;\n    private byte FUH_TYPE;\n\n    private boolean hasFUHeader;\n\n    /**\n     * Constructor\n     * \n     * @param rtpPacketData\n     */\n    public H264RtpHeaders(byte[] rtpPacketData) {\n        // Get FU indicator\n        byte data_FUI = rtpPacketData[0];\n        this.FUI_F = ((data_FUI >> 7) & 0x01) != 0;\n        this.FUI_NRI = ((data_FUI >> 5) & 0x07);\n        this.FUI_TYPE = (byte) (data_FUI & 0x1f);\n        this.hasFUHeader = false;\n\n        if (FUI_TYPE == AVC_NALTYPE_FUA) {\n            // Get FU header\n            byte data_FUH = rtpPacketData[1];\n            this.FUH_S = (data_FUH & 0x80) != 0;\n            this.FUH_E = (data_FUH & 0x40) != 0;\n            this.FUH_R = (data_FUH & 0x20) != 0;\n            this.FUH_TYPE = (byte) (data_FUH & 0x1f);\n            this.hasFUHeader = true;\n        }\n    }\n\n    /**\n     * Is Frame Non Interleaved\n     * \n     * @return Is Frame Non Interleaved\n     */\n    public boolean isFrameNonInterleaved() { // not fragmented\n        return (FUI_TYPE == AVC_NALTYPE_FUA);\n    }\n\n    /**\n     * Header Size\n     * \n     * @return Header Size\n     */\n    public int getHeaderSize() {\n        int headerSize = FU_INDICATOR_SIZE;\n        if (hasFUHeader) {\n            headerSize += FU_HEADER_SIZE;\n        }\n        return headerSize;\n    }\n\n    /**\n     * Get NAL Header\n     * \n     * @return NAL Header\n     */\n    public byte getNALHeader() {\n        // Compose and copy NAL header\n        if (hasFUHeader) {\n            return (byte) (((getFUI_F() ? 1 : 0) << 7) | (FUI_NRI << 5) | (FUH_TYPE & 0x1F));\n        } else {\n            return (byte) (((getFUI_F() ? 1 : 0) << 7) | (FUI_NRI << 5) | (FUI_TYPE & 0x1F));\n        }\n    }\n\n    /**\n     * Verifies if packet is a code slice of a IDR picture\n     * \n     * @param packet packet to verify\n     * @return <code>True</code> if it is, <code>false</code> otherwise\n     */\n    public boolean isIDRSlice() {\n        if (FUI_TYPE == (byte) 0x05) {\n            return true;\n        }\n\n        if (isFrameNonInterleaved() && FUH_TYPE == (byte) 0x05) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Verifies if packet is a code slice of a NON IDR picture\n     * \n     * @param packet packet to verify\n     * @return <code>True</code> if it is, <code>false</code> otherwise\n     */\n    public boolean isNonIDRSlice() {\n        if (FUI_TYPE == (byte) 0x01) {\n            return true;\n        }\n\n        if (isFrameNonInterleaved() && FUH_TYPE == (byte) 0x01) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Get FUI_F\n     * \n     * @return FUI_F\n     */\n    public boolean getFUI_F() {\n        return FUI_F;\n    }\n\n    /**\n     * Get FUI_NRI\n     * \n     * @return FUI_NRI\n     */\n    public int getFUI_NRI() {\n        return FUI_NRI;\n    }\n\n    /**\n     * Get FUI_TYPE\n     * \n     * @return FUI_TYPE\n     */\n    public byte getFUI_TYPE() {\n        return FUI_TYPE;\n    }\n\n    /**\n     * Get FUH_S\n     * \n     * @return FUH_S\n     */\n    public boolean getFUH_S() {\n        return FUH_S;\n    }\n\n    /**\n     * Get FUH_E\n     * \n     * @return FUH_E\n     */\n    public boolean getFUH_E() {\n        return FUH_E;\n    }\n\n    /**\n     * Get FUH_R\n     * \n     * @return FUH_R\n     */\n    public boolean getFUH_R() {\n        return FUH_R;\n    }\n\n    /**\n     * Get FUH_TYPE\n     * \n     * @return FUH_TYPE\n     */\n    public byte getFUH_TYPE() {\n        return FUH_TYPE;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder result = new StringBuilder();\n\n        result.append(\"[FUI_F = \" + getFUI_F() + \" \");\n        result.append(\"FUI_NRI = \" + FUI_NRI + \" \");\n        result.append(\"FUI_TYPE = \" + FUI_TYPE + \" \");\n        result.append(\"hasFUHeader = \" + hasFUHeader + \" \");\n\n        if (hasFUHeader) {\n            result.append(\"[FUH_S = \" + FUH_S + \" \");\n            result.append(\"[FUH_E = \" + FUH_E + \" \");\n            result.append(\"[FUH_R = \" + FUH_R + \" \");\n            result.append(\"[FUH_TYPE = \" + FUH_TYPE + \" \");\n        }\n\n        result.append(\"HeaderSize = \" + getHeaderSize() + \"]\");\n\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/JavaDepacketizer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.VideoCodec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Reassembles H264 RTP packets into H264 frames, as per RFC 3984 Complete frames are sent to\n * decoder once reassembled\n * \n * @author Deutsche Telekom AG\n */\npublic class JavaDepacketizer extends VideoCodec {\n\n    /**\n     * Collection of frameAssemblers. Allows the construction of several frames if incoming packets\n     * are out of order\n     */\n    private FrameAssemblerCollection assemblersCollection = new FrameAssemblerCollection();\n\n    /**\n     * Max frame size to give for next module, as some decoder have frame size limits\n     */\n    private static final int MAX_H264_FRAME_SIZE = 8192;\n\n    /**\n     * Default frame packet size\n     */\n    public static int H264_FRAME_PACKET_SIZE = 1500;\n\n    /**\n     * Video decoder max payloads chunks mask\n     */\n    private static final byte VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK = 0x1F;\n\n    /**\n     * Packet NalUnitHeader\n     */\n    private NalUnitHeader mNalUnitHeader;\n\n    /**\n     * Reading position for aggregation packet\n     */\n    private int aggregationPositon = 1;\n\n    /**\n     * Constructor\n     */\n    public JavaDepacketizer() {\n    }\n\n    /**\n     * Performs the media processing defined by this codec\n     * \n     * @param input The buffer that contains the media data to be processed\n     * @param output The buffer in which to store the processed media data\n     * @return Processing result\n     */\n    public int process(Buffer input, Buffer output) {\n        if (input == null || output == null) {\n            return BUFFER_PROCESSED_FAILED;\n        }\n\n        // Extracts the NAL Unit Header from the Input Buffer\n        extractNalUnitHeader(input);\n\n        if (mNalUnitHeader.isFragmentationUnit()) {\n            return handleFragmentationUnitPacket(input, output);\n        } else if (mNalUnitHeader.isAggregationPacket()) {\n            return handleAggregationPacket(input, output);\n        } else {\n            return handleSingleNalUnitPacket(input, output);\n        }\n\n    }\n\n    /**\n     * Extract the NAL unit header\n     * \n     * @param input\n     */\n    private void extractNalUnitHeader(Buffer input) {\n        if (mNalUnitHeader == null) {\n            mNalUnitHeader = NalUnitHeader.extract((byte[]) input.getData());\n        } else {\n            NalUnitHeader.extract((byte[]) input.getData(), mNalUnitHeader);\n        }\n    }\n\n    /**\n     * Extract the NAL unit header at position\n     * \n     * @param input\n     * @param position\n     */\n    private void extractNalUnitHeader(int position, Buffer input) {\n        if (mNalUnitHeader == null) {\n            mNalUnitHeader = NalUnitHeader.extract(position, (byte[]) input.getData());\n        } else {\n            NalUnitHeader.extract(position, (byte[]) input.getData(), mNalUnitHeader);\n        }\n    }\n\n    /**\n     * Handle single NAL Unit packet\n     * \n     * @return Processing result\n     */\n    private int handleSingleNalUnitPacket(Buffer input, Buffer output) {\n        // Create output buffer\n        byte[] bufferData = (byte[]) input.getData();\n        int bufferDataLength = bufferData.length;\n        byte[] data = new byte[bufferDataLength];\n        System.arraycopy(bufferData, 0, data, 0, bufferDataLength);\n\n        // Set buffer\n        output.setData(data);\n        output.setLength(data.length);\n        output.setOffset(0);\n        output.setTimeStamp(input.getTimeStamp());\n        output.setSequenceNumber(input.getSequenceNumber());\n        output.setVideoOrientation(input.getVideoOrientation());\n        output.setFormat(input.getFormat());\n        output.setFlags(input.getFlags());\n\n        return BUFFER_PROCESSED_OK;\n    }\n\n    /**\n     * Handle Aggregation NAL Unit packet\n     * \n     * @return Processing result\n     */\n    private int handleAggregationPacket(Buffer input, Buffer output) {\n        // Get data\n        byte[] bufferData = (byte[]) input.getData();\n        if (aggregationPositon + 1 >= bufferData.length) {\n            // No more data in aggregation packet\n            aggregationPositon = 1;\n            output.setDiscard(true);\n            return BUFFER_PROCESSED_OK;\n        }\n\n        // Get NALU size\n        int nalu_size = (((bufferData[aggregationPositon] & 0xff) << 8) | (bufferData[aggregationPositon + 1] & 0xff));\n        aggregationPositon += 2;\n        if (aggregationPositon + nalu_size > bufferData.length) {\n            // Not a correct packet\n            aggregationPositon = 1;\n            return BUFFER_PROCESSED_FAILED;\n        }\n\n        // Get NALU HDR\n        extractNalUnitHeader(aggregationPositon, input);\n        if (mNalUnitHeader.isSingleNalUnitPacket()) {\n            // Create output buffer\n            byte[] data = new byte[nalu_size];\n            System.arraycopy(bufferData, aggregationPositon, data, 0, nalu_size);\n            aggregationPositon += nalu_size;\n\n            // Set buffer\n            output.setData(data);\n            output.setLength(data.length);\n            output.setOffset(0);\n            output.setTimeStamp(input.getTimeStamp());\n            output.setSequenceNumber(input.getSequenceNumber());\n            output.setVideoOrientation(input.getVideoOrientation());\n            output.setFormat(input.getFormat());\n            output.setFlags(input.getFlags());\n\n            return INPUT_BUFFER_NOT_CONSUMED;\n        } else {\n            // Not a correct packet\n            aggregationPositon = 1;\n            return BUFFER_PROCESSED_FAILED;\n        }\n    }\n\n    /**\n     * Handle Fragmentation NAL Unit packet\n     * \n     * @return Processing result\n     */\n    private int handleFragmentationUnitPacket(Buffer input, Buffer output) {\n        if (!input.isDiscard()) {\n            assemblersCollection.put(input);\n            if (assemblersCollection.getLastActiveAssembler().complete()) {\n                assemblersCollection.getLastActiveAssembler().copyToBuffer(output);\n                assemblersCollection.removeOldestThan(input.getTimeStamp());\n                return BUFFER_PROCESSED_OK;\n            } else {\n                output.setDiscard(true);\n                return OUTPUT_BUFFER_NOT_FILLED;\n            }\n        } else {\n            output.setDiscard(true);\n            return OUTPUT_BUFFER_NOT_FILLED;\n        }\n    }\n\n    /**\n     * Used to assemble fragments with the same timestamp into a single frame.\n     */\n    public static class FrameAssembler {\n        private byte[][] reassembledData = null; // Frame sequence chunks\n        private int[] reassembledDataSize = null; // Sequence chunk size\n        private int reassembledDataFullSize = 0; // Frame sequence chunks full size\n        private boolean reassembledDataHasStart = false; // Has start chunk\n        private boolean reassembledDataHasEnd = false; // Has end chunk\n        private int reassembledDataPosSeqStart = Integer.MAX_VALUE; // Pos seq start\n        private int reassembledDataPosSeqEnd = Integer.MIN_VALUE; // Pos seq end\n        private byte reassembledDataNALHeader = 0; // Final frame NAL header\n        private long timeStamp = -1;\n        private Format format = null;\n        private long seqNumber = -1;\n        private VideoOrientation videoOrientation;\n\n        /**\n         * Add the buffer (which contains a fragment) to the assembler.\n         * \n         * @param buffer\n         */\n        public void put(Buffer buffer) {\n\n            if (buffer.getLength() <= 2) {\n                // no actual data in buffer, no need to keep. Typically\n                // happens when RTP marker is set.\n                return;\n            }\n\n            byte[] currentRtpPacketData = ((byte[]) buffer.getData());\n            H264RtpHeaders h264RtpHeaders = new H264RtpHeaders(currentRtpPacketData);\n\n            // Forbidden zero bit, must be zero for a valid stream\n            if (h264RtpHeaders.getFUI_F()) {\n                return;\n            }\n\n            if (reassembledData == null) {\n                // First packet\n                timeStamp = buffer.getTimeStamp();\n                format = buffer.getFormat();\n                seqNumber = buffer.getSequenceNumber();\n\n                // Get NAL header\n                reassembledDataNALHeader = h264RtpHeaders.getNALHeader();\n\n                // Copy packet data to reassembledData\n                reassembledData = new byte[JavaPacketizer.H264_MAX_RTP_PKTS][H264_FRAME_PACKET_SIZE];\n                reassembledDataSize = new int[JavaPacketizer.H264_MAX_RTP_PKTS];\n                reassembledDataHasStart = false;\n                reassembledDataHasEnd = false;\n            }\n\n            // Sequence position on frame\n            int posSeq = (int) (buffer.getSequenceNumber() & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK);\n\n            // Exclude header size\n            int payloadStartPosition = h264RtpHeaders.getHeaderSize();\n            // Exclude header size\n            int payloadLength = buffer.getLength() - h264RtpHeaders.getHeaderSize();\n\n            // Fragmentation Units (FU-A) have NALs separated through several\n            // RTP packets\n            if (h264RtpHeaders.getFUI_TYPE() == H264RtpHeaders.AVC_NALTYPE_FUA) {\n\n                // Fill Has Start Chunk\n                reassembledDataHasStart |= (h264RtpHeaders.getFUH_S());\n                // Fill Has End Chunk\n                reassembledDataHasEnd |= (h264RtpHeaders.getFUH_E());\n\n                // Fill Pos Seq Start\n                reassembledDataPosSeqStart = ((h264RtpHeaders.getFUH_S()) ? posSeq\n                        : reassembledDataPosSeqStart);\n                // Fill Pos Seq End\n                reassembledDataPosSeqEnd = ((h264RtpHeaders.getFUH_E()) ? posSeq\n                        : reassembledDataPosSeqEnd);\n            }\n\n            // Sequence chuck size\n            reassembledDataSize[posSeq] = payloadLength;\n\n            // Sum chucks total sizes\n            reassembledDataFullSize += payloadLength;\n\n            // Copy data\n            System.arraycopy(currentRtpPacketData, payloadStartPosition, reassembledData[posSeq],\n                    0, payloadLength);\n            videoOrientation = buffer.getVideoOrientation();\n        }\n\n        /**\n         * Is the frame complete?\n         */\n        public boolean complete() {\n\n            if (!reassembledDataHasStart || !reassembledDataHasEnd) {\n                return false; // has start and end chunk\n            }\n\n            // Validate chunk sizes between start and end pos\n            int posCurrent = reassembledDataPosSeqStart;\n            while ((posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK) != reassembledDataPosSeqEnd) {\n                // need more data?\n                if (reassembledDataSize[posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK] <= 0) {\n                    return false;\n                }\n                posCurrent++;\n            }\n            // Validate last chunk\n            if (reassembledDataSize[reassembledDataPosSeqEnd] <= 0) {\n                return false;\n            }\n\n            // TODO: if some of the last ones come in after the marker, there\n            // will be blank squares in the lower right.\n            return true;\n        }\n\n        /**\n         * Assumes that complete() has been called and returns true.\n         */\n        private void copyToBuffer(Buffer bDest) {\n\n            if (reassembledDataFullSize <= MAX_H264_FRAME_SIZE) {\n                // + 1 because of the header size\n                byte[] finalData = new byte[reassembledDataFullSize + 1];\n                int finalDataPos = 0;\n\n                // Copy NAL header\n                finalData[finalDataPos] = reassembledDataNALHeader;\n                finalDataPos += 1;\n\n                // Copy chunk data between start and end pos\n                int posCurrent = reassembledDataPosSeqStart;\n                int posSeq = 0;\n                while ((posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK) != reassembledDataPosSeqEnd) {\n                    // need more data?\n                    posSeq = posCurrent & VIDEO_DECODER_MAX_PAYLOADS_CHUNKS_MASK;\n\n                    // Copy data\n                    System.arraycopy(reassembledData[posSeq], 0, finalData, finalDataPos,\n                            reassembledDataSize[posSeq]);\n                    finalDataPos += reassembledDataSize[posSeq];\n\n                    posCurrent++;\n                }\n\n                // Copy last chunk data\n                System.arraycopy(reassembledData[reassembledDataPosSeqEnd], 0, finalData,\n                        finalDataPos, reassembledDataSize[reassembledDataPosSeqEnd]);\n\n                // If the frame data can be processed by native module, ie\n                // reassembled frame size not too big\n                // Set buffer\n                bDest.setData(finalData);\n                bDest.setLength(reassembledDataSize[reassembledDataPosSeqEnd]);\n                bDest.setOffset(0);\n                bDest.setTimeStamp(timeStamp);\n                bDest.setFormat(format);\n                bDest.setFlags(Buffer.FLAG_RTP_MARKER | Buffer.FLAG_RTP_TIME);\n                bDest.setVideoOrientation(videoOrientation);\n                bDest.setSequenceNumber(seqNumber);\n            }\n\n            // Set reassembledData to null\n            reassembledData = null;\n        }\n\n        /**\n         * Reset the FrameAssembler It as package access instead of private for improved\n         * performance. See: http://developer.android.com/guide/practices/performance.html Consider\n         * Package Instead of Private Access with Private Inner Classes\n         */\n        private void reset() {\n            reassembledData = null;\n            reassembledDataSize = null;\n            reassembledDataFullSize = 0;\n            reassembledDataHasStart = false;\n            reassembledDataHasEnd = false;\n            reassembledDataPosSeqStart = Integer.MAX_VALUE;\n            reassembledDataPosSeqEnd = Integer.MIN_VALUE;\n            reassembledDataNALHeader = 0;\n            timeStamp = -1;\n            format = null;\n        }\n\n        /**\n         * Get timestamp\n         * \n         * @return long\n         */\n        public long getTimeStamp() {\n            return timeStamp;\n        }\n    }\n\n    /**\n     * Used to manage different timestamps, as packets could be coming not in order. Data is an\n     * array of FrameAssemblers, sorted by timestamps (oldest is first, newest is last)\n     */\n    public static class FrameAssemblerCollection {\n        private final static int NUMBER_OF_ASSEMBLERS = 5;\n        private FrameAssembler[] assemblers = new FrameAssembler[NUMBER_OF_ASSEMBLERS];\n        private int activeAssembler = 0;\n        private int numberOfAssemblers = 0;\n\n        /**\n         * Add the buffer (which contains a fragment) to the right assembler.\n         * \n         * @param buffer\n         */\n        public void put(Buffer buffer) {\n            activeAssembler = getAssembler(buffer.getTimeStamp());\n            assemblers[activeAssembler].put(buffer);\n        }\n\n        /**\n         * Get the active frame assembler\n         * \n         * @return frameAssembler Last active assembler\n         */\n        public FrameAssembler getLastActiveAssembler() {\n            return assemblers[activeAssembler];\n        }\n\n        /**\n         * Create a new frame assembler for given timeStamp\n         * \n         * @param timeStamp\n         * @return assembler number Position of the assembler in the collection\n         */\n        public int createNewAssembler(long timeStamp) {\n            int spot = -1;\n            if (numberOfAssemblers < NUMBER_OF_ASSEMBLERS) {\n                // If there's enough space left to create a new assembler\n                // We search its spot\n                for (int i = 0; i < numberOfAssemblers; i++) {\n                    if (timeStamp < assemblers[i].getTimeStamp()) {\n                        spot = i;\n                    }\n                }\n                if (spot == -1) {\n                    spot = numberOfAssemblers;\n                }\n                numberOfAssemblers++;\n\n                // Store the assembler that will be \"discarded\" and can be reused\n                FrameAssembler oldAssembler = assemblers[numberOfAssemblers - 1];\n\n                // Decale all assemblers with newest timeStamp to the right\n                for (int i = numberOfAssemblers - 1; i > spot; i--) {\n                    assemblers[i] = assemblers[i - 1];\n                }\n                if (oldAssembler != null) {\n                    // Reuse and reset the discarded assembler\n                    assemblers[spot] = oldAssembler;\n                    assemblers[spot].reset();\n                } else {\n                    assemblers[spot] = new FrameAssembler();\n                }\n            } else {\n                // Store the assembler that will be \"discarded\" and can be reused\n                FrameAssembler oldAssembler = assemblers[0];\n\n                // Not enough space, we destroy the oldest assembler\n                for (int i = 1; i < NUMBER_OF_ASSEMBLERS; i++) {\n                    assemblers[i - 1] = assemblers[i];\n                }\n                // Last spot is for the new assembler\n                spot = NUMBER_OF_ASSEMBLERS - 1;\n                if (oldAssembler != null) {\n                    // Reuse and reset the discarded assembler\n                    assemblers[spot] = oldAssembler;\n                    assemblers[spot].reset();\n                } else {\n                    assemblers[spot] = new FrameAssembler();\n                }\n            }\n            return spot;\n        }\n\n        /**\n         * Get the assembler used for given timestamp\n         * \n         * @param timeStamp\n         * @return FrameAssembler associated to timeStamp\n         */\n        public int getAssembler(long timeStamp) {\n            int assemblerNumber = -1;\n            for (int i = 0; i < numberOfAssemblers; i++) {\n                if (assemblers[i].getTimeStamp() == timeStamp) {\n                    assemblerNumber = i;\n                }\n            }\n            if (assemblerNumber == -1) {\n                // Given timestamp never used, we create a new assembler\n                assemblerNumber = createNewAssembler(timeStamp);\n            }\n            return assemblerNumber;\n        }\n\n        /**\n         * Remove oldest FrameAssembler than given timeStamp (if given timeStamp has been rendered,\n         * then oldest ones are no more of no use) This also removes given timeStamp\n         * \n         * @param timeStamp\n         */\n        public void removeOldestThan(long timeStamp) {\n            // Find spot from which to remove\n            int spot = numberOfAssemblers - 1;\n            for (int i = 0; i < numberOfAssemblers; i++) {\n                if (timeStamp <= assemblers[i].getTimeStamp()) {\n                    spot = i;\n                }\n            }\n            // remove all assemblers with oldest timeStamp to the left\n            for (int i = numberOfAssemblers - 1; i > spot; i--) {\n                assemblers[i - 1] = assemblers[i];\n            }\n            numberOfAssemblers -= spot + 1;\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/JavaPacketizer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.VideoCodec;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.CameraOptions;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.Orientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Reassembles H264 RTP packets into H264 frames, as per RFC 3984\n * \n * @author Deutsche Telekom AG\n */\npublic class JavaPacketizer extends VideoCodec {\n\n    /**\n     * Packetization mode 0 -> Only Single NAL 1 -> Use FU-A if necessary Warning:\n     * packetization-mode 1 normally requires the management of STAP-A. But, this is not yet\n     * implemented in the stack. Then, there can be some IOT issues if you use this mode.\n     */\n    public static final int H264_ENABLED_PACKETIZATION_MODE = 1;\n\n    /**\n     * Max frame size to H264\n     */\n    public static int H264_MAX_PACKET_FRAME_SIZE = 1300; // TODO remove the rtp size...\n\n    /**\n     * Max number of packets to H264\n     */\n    public static final int H264_MAX_RTP_PKTS = 32;\n\n    /**\n     * Buffer size for FU Indicator and Header\n     */\n    public static final int H264_FU_HEADER_SIZE = 2;\n\n    /**\n     * AVC NAL sequence parameter\n     */\n    public static final int AVC_NALTYPE_SPS = 7;\n\n    /**\n     * AVC NAL picture parameter\n     */\n    public static final int AVC_NALTYPE_PPS = 8;\n\n    /**\n     * Full frame auxiliary buffer (No Packetization)\n     */\n    private byte fullFrameData[] = new byte[H264_MAX_PACKET_FRAME_SIZE];\n\n    /**\n     * Full frame temporary packets buffer (With Packetization)\n     */\n    private byte packetsData[][] = new byte[H264_MAX_RTP_PKTS][H264_MAX_PACKET_FRAME_SIZE];\n\n    /**\n     * Full frame final chunks buffer (With Packetization)\n     */\n    private Buffer[] outputs = new Buffer[H264_MAX_RTP_PKTS];\n\n    /**\n     * Buffer for FU Indicator and Header\n     */\n    private byte[] h264FU = new byte[H264_FU_HEADER_SIZE];\n\n    /**\n     * Previous sent orientation\n     */\n    private VideoOrientation previousOrientation = new VideoOrientation(CameraOptions.BACK,\n            Orientation.NONE);\n\n    /**\n     * Because packets can come out of order, it is possible that some packets for a newer frame may\n     * arrive while an older frame is still incomplete. However, in the case where we get nothing\n     * but incomplete frames, we don't want to keep all of them around forever.\n     */\n    public JavaPacketizer() {\n    }\n\n    public int process(Buffer input, Buffer output) {\n\n        if (input == null || output == null) {\n            return BUFFER_PROCESSED_FAILED;\n        }\n\n        if (!input.isDiscard()) {\n            byte[] bufferData = (byte[]) input.getData();\n            int bufferDataLength = input.getLength();\n            if (input.getLength() < H264_MAX_PACKET_FRAME_SIZE\n                    || H264_ENABLED_PACKETIZATION_MODE == 0) {\n                if ((fullFrameData == null) || (fullFrameData.length < bufferDataLength)) {\n                    fullFrameData = new byte[bufferDataLength];\n                }\n                System.arraycopy(bufferData, 0, fullFrameData, 0, bufferDataLength);\n                if (fullFrameData.length > 0) {\n                    // Copy to buffer\n                    output.setFormat(input.getFormat());\n                    output.setData(fullFrameData);\n                    output.setLength(bufferDataLength);\n                    output.setOffset(0);\n                    output.setTimeStamp(input.getTimeStamp());\n                    output.setFlags(Buffer.FLAG_RTP_MARKER | Buffer.FLAG_RTP_TIME);\n                    output.setVideoOrientation(null);\n                    if (isToAddOrientationHeader(bufferData, input.getVideoOrientation())) {\n                        output.setVideoOrientation(input.getVideoOrientation());\n                        previousOrientation = input.getVideoOrientation();\n                    }\n\n                }\n                return BUFFER_PROCESSED_OK;\n            }\n\n            output.setFragments(outputs);\n            output.setFragmentsSize(0);\n\n            /*\n             * First Header - The FU indicator octet has the following format: +---------------+\n             * |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |F|NRI| Type | +---------------+\n             */\n\n            // FU Indicator pos = 0\n            h264FU[0] = 0;\n            h264FU[0] |= (bufferData[0] & 0xe0);// F | NRI\n            h264FU[0] |= H264RtpHeaders.AVC_NALTYPE_FUA;\n\n            /*\n             * Second Header - The FU header has the following format: +---------------+\n             * |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+ |S|E|R| Type | +---------------+\n             */\n\n            // FU Header pos = 1\n            h264FU[1] = 0;\n            h264FU[1] |= 0x80;// for the first pkt, the start bit is on\n            // copy the original nal type from the stream\n            h264FU[1] |= (bufferData[0] & 0x1f);\n\n            // Split frame into pkts\n            // for FU-A, we need to consume the first byte with the NAL header\n            int startPosBufferData = 1;\n            int available = bufferDataLength - 1;// see comment above\n            // define max size (not counting with the fuIndicator and fuHeader)\n            int maxSize = H264_MAX_PACKET_FRAME_SIZE - h264FU.length;\n            int numberOfRtpPkts = 0;\n            while (available > maxSize) {\n\n                // >>>>>>>>>>>> create packet >>>>>>>>>>>>\n                // Write h264 payload\n                System.arraycopy(h264FU, 0, packetsData[numberOfRtpPkts], 0, h264FU.length);\n\n                // Write frame data\n                System.arraycopy(bufferData, startPosBufferData, packetsData[numberOfRtpPkts],\n                        h264FU.length, maxSize);\n\n                // Copy to buffer\n                Buffer buffer = outputs[numberOfRtpPkts];\n                if (buffer == null) {\n                    buffer = new Buffer();\n                }\n                buffer.setFormat(input.getFormat());\n                buffer.setData(packetsData[numberOfRtpPkts]);\n                buffer.setLength(H264_MAX_PACKET_FRAME_SIZE); // Max packet frame size\n                buffer.setOffset(0);\n                buffer.setTimeStamp(input.getTimeStamp());\n                buffer.setFlags(Buffer.FLAG_RTP_TIME);\n                buffer.setVideoOrientation(null);\n\n                // Add data buffer to outputs\n                outputs[numberOfRtpPkts] = buffer;\n\n                // Increment number of rtp pkts\n                numberOfRtpPkts++;\n                // <<<<<<<<<<<< create packet <<<<<<<<<<<<\n\n                // -1 to leave room for the last pkt\n                if (numberOfRtpPkts >= H264_MAX_RTP_PKTS - 1) {\n                    output.setFragments(null);\n                    output.setFragmentsSize(0);\n                    output.setData(null);\n                    output.setDiscard(true);\n                    output.setVideoOrientation(null);\n                    return OUTPUT_BUFFER_NOT_FILLED;\n                    // this frame is too big and needs to be split into more\n                    // pkts than we can buffer\n                }\n\n                // reset the start bit\n                // FU Header pos = 1\n                // we need to switch the start bit off\n                h264FU[1] &= 0x3f; // 0x7f\n\n                // update variables\n                startPosBufferData += maxSize;\n                available -= maxSize;\n            }\n\n            // write the last chunk of the FU-A\n\n            // set the end bit\n            // FU Header pos = 1\n            h264FU[1] |= 0x40;// we need to switch the end bit on\n\n            // >>>>>>>>>>>> create packet >>>>>>>>>>>>\n            // write h264 payload\n            System.arraycopy(h264FU, 0, packetsData[numberOfRtpPkts], 0, h264FU.length);\n\n            // write frame data\n            System.arraycopy(bufferData, startPosBufferData, packetsData[numberOfRtpPkts],\n                    h264FU.length, available);\n\n            // copy to buffer\n            Buffer buffer = outputs[numberOfRtpPkts];\n            if (buffer == null) {\n                buffer = new Buffer();\n            }\n            buffer.setFormat(input.getFormat());\n            buffer.setData(packetsData[numberOfRtpPkts]);\n            buffer.setLength(h264FU.length + available); // H264FU header length + remaining frame\n                                                         // chunk size\n            buffer.setOffset(0);\n            buffer.setTimeStamp(input.getTimeStamp());\n            buffer.setFlags(Buffer.FLAG_RTP_MARKER | Buffer.FLAG_RTP_TIME);\n            buffer.setVideoOrientation(null);\n            if (isToAddOrientationHeader(packetsData[numberOfRtpPkts], input.getVideoOrientation())) {\n                buffer.setVideoOrientation(input.getVideoOrientation());\n                previousOrientation = input.getVideoOrientation();\n            }\n\n            // add data buffer to outputs\n            outputs[numberOfRtpPkts] = buffer;\n\n            // increment number of rtp pkts\n            numberOfRtpPkts++;\n\n            // Set outputs size\n            output.setFragmentsSize(numberOfRtpPkts);\n            // <<<<<<<<<<<< create packet <<<<<<<<<<<<\n\n            return BUFFER_PROCESSED_OK;\n        } else {\n            output.setDiscard(true);\n            return OUTPUT_BUFFER_NOT_FILLED;\n        }\n    }\n\n    /**\n     * Verifies if we need to send the orientation header. The orientation header should be sent if\n     * it's the end packet of an I-Frame or if its the end packet of B/P Frames and the orientation\n     * has changed.\n     * \n     * @param h264Frame H264 Frame\n     * @param frameOrientation Frame orientation\n     * @return <code>True</code> if it's to add, <code>false</code> otherwise.\n     */\n    private boolean isToAddOrientationHeader(byte[] h264Frame, VideoOrientation frameOrientation) {\n        H264RtpHeaders h264Header = new H264RtpHeaders(h264Frame);\n        if (h264Header.isIDRSlice()) {\n            return true;\n        }\n\n        if ((frameOrientation != null && previousOrientation != null && h264Header != null\n                && previousOrientation.getOrientation() != frameOrientation.getOrientation())\n                && h264Header.isNonIDRSlice()) {\n            return true;\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/NalUnitHeader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264;\n\n/**\n * RFC 6184 RTP Payload Format for H.264 Video The first byte of the H264 payload represents the NAL\n * Unit which has the following format: +---------------+ |0|1|2|3|4|5|6|7| +-+-+-+-+-+-+-+-+\n * |F|NRI| Type | +---------------+ F: 1 bit forbidden_zero_bit. The H.264 specification declares a\n * value of 1 as a syntax violation. NRI: 2 bits nal_ref_idc. A value of 00 indicates that the\n * content of the NAL unit is not used to reconstruct reference pictures for inter picture\n * prediction. Such NAL units can be discarded without risking the integrity of the reference\n * pictures. Values greater than 00 indicate that the decoding of the NAL unit is required to\n * maintain the integrity of the reference pictures. Type: 5 bits nal_unit_type. This component\n * specifies the NAL unit payload type\n * \n * @author Deutsche Telekom\n */\npublic class NalUnitHeader {\n\n    /**\n     * Forbidden zero bit\n     */\n    private boolean forbiddenZeroBit;\n\n    /**\n     * NAL Reference id\n     */\n    private int nalRefId;\n\n    /**\n     * NAL Unit Type\n     */\n    private NalUnitType decodeNalUnitType;\n\n    /**\n     * Class constructor\n     * \n     * @param forbiddenZeroBit Forbidden zero bit\n     * @param nalRefId NAL Reference id\n     * @param nalUnitType NAL Unit Type value\n     */\n    private NalUnitHeader(boolean forbiddenZeroBit, int nalRefId, int nalUnitType) {\n        this.forbiddenZeroBit = forbiddenZeroBit;\n        this.nalRefId = nalRefId;\n        this.decodeNalUnitType = NalUnitType.parse(nalUnitType);\n    }\n\n    /**\n     * Checks if the Forbidden Zero Bit is set.\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isForbiddenBitSet() {\n        return forbiddenZeroBit;\n    }\n\n    /**\n     * Gets the NAL Reference ID\n     * \n     * @return NAL Reference ID\n     */\n    public int getNalRefId() {\n        return nalRefId;\n    }\n\n    /**\n     * Gets the NAL Unit Type\n     * \n     * @return\n     */\n    public NalUnitType getNalUnitType() {\n        return decodeNalUnitType;\n    }\n\n    /**\n     * Verifies if the H264 packet is Single NAL Unit\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isSingleNalUnitPacket() {\n        return decodeNalUnitType == NalUnitType.CODE_SLICE_IDR_PICTURE\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_NON_IDR_PICTURE\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_DATA_PARTITION_A\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_DATA_PARTITION_B\n                || decodeNalUnitType == NalUnitType.CODE_SLICE_DATA_PARTITION_C\n                || decodeNalUnitType == NalUnitType.SEQUENCE_PARAMETER_SET\n                || decodeNalUnitType == NalUnitType.PICTURE_PARAMETER_SET\n                || decodeNalUnitType == NalUnitType.OTHER_NAL_UNIT;\n    }\n\n    /**\n     * Verifies if the H264 packet is an Aggregation Packet\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isAggregationPacket() {\n        return decodeNalUnitType == NalUnitType.STAP_A || decodeNalUnitType == NalUnitType.STAP_B\n                || decodeNalUnitType == NalUnitType.MTAP16\n                || decodeNalUnitType == NalUnitType.MTAP24;\n    }\n\n    /**\n     * Verifies if the H264 packet is a Fragmentation Unit Packet\n     * \n     * @return <code>True</code> if it is, <code>false</code> false otherwise.\n     */\n    public boolean isFragmentationUnit() {\n        return decodeNalUnitType == NalUnitType.FU_A || decodeNalUnitType == NalUnitType.FU_B;\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet\n     * \n     * @param h264Packet H264 Packet\n     * @return {@link NalUnitHeader} Extracted NAL Unit Header\n     * @throws {@link RuntimeException} If the H264 packet data is null\n     */\n    public static NalUnitHeader extract(byte[] h264Packet) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        NalUnitHeader header = new NalUnitHeader(false, 0, 0);\n        extract(h264Packet, header);\n\n        return header;\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet. Puts the extracted info in the given header\n     * object\n     * \n     * @param h264Packet H264 packet\n     * @param header Header object to fill with data\n     * @throws {@link RuntimeException} If the H264 packet data is null or the header is null;\n     */\n    public static void extract(byte[] h264Packet, NalUnitHeader header) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        if (header == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid header packet\");\n        }\n\n        byte headerByte = h264Packet[0];\n\n        header.forbiddenZeroBit = ((headerByte & 0x80) >> 7) != 0;\n        header.nalRefId = ((headerByte & 0x60) >> 5);\n        int nalUnitType = (headerByte & 0x1f);\n        header.decodeNalUnitType = NalUnitType.parse(nalUnitType);\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet\n     * \n     * @param h264Packet H264 Packet\n     * @return {@link NalUnitHeader} Extracted NAL Unit Header\n     * @throws {@link RuntimeException} If the H264 packet data is null\n     */\n    public static NalUnitHeader extract(int position, byte[] h264Packet) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        NalUnitHeader header = new NalUnitHeader(false, 0, 0);\n        extract(position, h264Packet, header);\n\n        return header;\n    }\n\n    /**\n     * Extracts the NAL Unit header from a H264 Packet. Puts the extracted info in the given header\n     * object\n     * \n     * @param h264Packet H264 packet\n     * @param header Header object to fill with data\n     * @throws {@link RuntimeException} If the H264 packet data is null or the header is null;\n     */\n    public static void extract(int position, byte[] h264Packet, NalUnitHeader header) {\n        if (h264Packet == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid H264 packet\");\n        }\n\n        if (header == null) {\n            throw new RuntimeException(\"Cannot extract H264 header. Invalid header packet\");\n        }\n\n        byte headerByte = h264Packet[position];\n\n        header.forbiddenZeroBit = ((headerByte & 0x80) >> 7) != 0;\n        header.nalRefId = ((headerByte & 0x60) >> 5);\n        int nalUnitType = (headerByte & 0x1f);\n        header.decodeNalUnitType = NalUnitType.parse(nalUnitType);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/NalUnitType.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264;\n\n/**\n * H264 NAL Unit Types\n * \n * @author Deutsche Telekom\n */\npublic enum NalUnitType {\n\n    RESERVED,\n    CODE_SLICE_NON_IDR_PICTURE,\n    CODE_SLICE_DATA_PARTITION_A,\n    CODE_SLICE_DATA_PARTITION_B,\n    CODE_SLICE_DATA_PARTITION_C,\n    CODE_SLICE_IDR_PICTURE,\n    SEQUENCE_PARAMETER_SET,\n    PICTURE_PARAMETER_SET,\n    STAP_A,\n    STAP_B,\n    MTAP16,\n    MTAP24,\n    FU_A,\n    FU_B,\n    OTHER_NAL_UNIT;\n\n    /**\n     * Decodes the NAL Unit type\n     * \n     * @param value NAL value\n     * @return NAL Unit Type\n     */\n    public static NalUnitType parse(int value) {\n        switch (value) {\n            case 1:\n                return CODE_SLICE_NON_IDR_PICTURE;\n\n            case 2:\n                return CODE_SLICE_DATA_PARTITION_A;\n\n            case 3:\n                return CODE_SLICE_DATA_PARTITION_B;\n\n            case 4:\n                return CODE_SLICE_DATA_PARTITION_C;\n\n            case 5:\n                return CODE_SLICE_IDR_PICTURE;\n\n            case 7:\n                return SEQUENCE_PARAMETER_SET;\n\n            case 8:\n                return PICTURE_PARAMETER_SET;\n\n            case 24:\n                return STAP_A;\n\n            case 25:\n                return STAP_B;\n\n            case 26:\n                return MTAP16;\n\n            case 27:\n                return MTAP24;\n\n            case 28:\n                return FU_A;\n\n            case 29:\n                return FU_B;\n\n            case 0:\n            case 30:\n            case 31:\n                return RESERVED;\n\n            default:\n                return OTHER_NAL_UNIT;\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/decoder/NativeH264Decoder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.decoder;\n\npublic class NativeH264Decoder\n{\n\n    public NativeH264Decoder()\n    {\n    }\n\n    public static native int InitDecoder();\n\n    public static native int DeinitDecoder();\n\n    public static synchronized native int[] DecodeAndConvert(byte abyte0[], int rotateOrientation,\n            int[] dimensions);\n\n    public static synchronized native int getLastDecodeStatus();\n\n    static\n    {\n        String libname = \"H264Decoder\";\n        try\n        {\n            System.loadLibrary(libname);\n        } catch (Exception exception) {\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/encoder/NativeH264Encoder.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.encoder;\n\n/**\n * Native H264 Encoder\n * \n * @author Orange\n */\npublic class NativeH264Encoder {\n\n    public static native int InitEncoder(NativeH264EncoderParams nativeH264EncoderParams);\n\n    // Resize the frame and Encode\n    public static native byte[] ResizeAndEncodeFrame(byte abyte0[], long l, boolean mirroring,\n            int srcWidth, int srcHeight);\n\n    // Scale the frame and Encode\n    public static native byte[] EncodeFrame(byte abyte0[], long l, boolean mirroring,\n            float scalingFactor);\n\n    public static native byte[] getNAL();\n\n    public static native int DeinitEncoder();\n\n    public static native int getLastEncodeStatus();\n\n    static {\n        String libname = \"H264Encoder\";\n        try {\n            System.loadLibrary(libname);\n        } catch (UnsatisfiedLinkError unsatisfiedlinkerror) {\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/encoder/NativeH264EncoderParams.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.encoder;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264Profile;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeLevel;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeLevel.H264ConstraintSetFlagType;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeProfile;\n\n/**\n * H264 Encoder settings\n * \n * @author Deutsche Telekom AG\n */\npublic class NativeH264EncoderParams {\n\n    // ----- Contants -----\n    // This constants values must be updated with those that were in the encoder\n    // codec\n\n    // - Targeted profile to encode -\n    public static final int PROFILE_DEFAULT = 0;\n    public static final int PROFILE_BASELINE = 1;\n    public static final int PROFILE_MAIN = 2;\n    public static final int PROFILE_EXTENDED = 3;\n    public static final int PROFILE_HIGH = 4;\n    public static final int PROFILE_HIGH10 = 5;\n    public static final int PROFILE_HIGH422 = 6;\n    public static final int PROFILE_HIGH444 = 7;\n\n    // - Targeted level to encode -\n    public static final int LEVEL_AUTODETECT = 0;\n    public static final int LEVEL_1 = 1;\n    public static final int LEVEL_1B = 2;\n    public static final int LEVEL_11 = 3;\n    public static final int LEVEL_12 = 4;\n    public static final int LEVEL_13 = 5;\n    public static final int LEVEL_2 = 6;\n    public static final int LEVEL_21 = 7;\n    public static final int LEVEL_22 = 8;\n    public static final int LEVEL_3 = 9;\n    public static final int LEVEL_31 = 10;\n    public static final int LEVEL_32 = 11;\n    public static final int LEVEL_4 = 12;\n    public static final int LEVEL_41 = 13;\n    public static final int LEVEL_42 = 14;\n    public static final int LEVEL_5 = 15;\n    public static final int LEVEL_51 = 16;\n\n    // - Contains supported video input format -\n    public static final int VIDEO_FORMAT_RGB24 = 0;\n    public static final int VIDEO_FORMAT_RGB12 = 1;\n    public static final int VIDEO_FORMAT_YUV420 = 2;\n    public static final int VIDEO_FORMAT_UYVY = 3;\n    public static final int VIDEO_FORMAT_YUV420SEMIPLANAR = 4;\n\n    // - Type of contents for optimal encoding mode -\n    public static final int ENCODING_MODE_TWOWAY = 0;\n    public static final int ENCODING_MODE_RECORDER = 1;\n    public static final int ENCODING_MODE_STREAMING = 2;\n    public static final int ENCODING_MODE_DOWNLOAD = 3;\n\n    // - Output format -\n    public static final int OUTPUT_FORMAT_ANNEXB = 0;\n    public static final int OUTPUT_FORMAT_MP4 = 1;\n    public static final int OUTPUT_FORMAT_RTP = 2;\n\n    // - Rate control type -\n    public static final int RATE_CONTROL_TYPE_CONSTANT_Q = 0;\n    public static final int RATE_CONTROL_TYPE_CBR_1 = 1;\n    public static final int RATE_CONTROL_TYPE_VBR_1 = 2;\n\n    // ----- Properties -----\n\n    /**\n     * Contains the width in pixels of the input frame.\n     */\n    private int frameWidth;\n\n    /**\n     * Contains the height in pixels of the input frame.\n     */\n    private int frameHeight;\n\n    /**\n     * Contains the input frame rate in the unit of frame per second.\n     */\n    private float frameRate;\n\n    /**\n     * Contains Frame Orientation. Used for RGB input. 1 means Bottom_UP RGB, 0 means Top_Down RGB,\n     * -1 for video formats other than RGB\n     */\n    private int frameOrientation; // TODO not implemented yet on the codec side\n\n    /**\n     * Contains the format of the input video, e.g., YUV 4:2:0, UYVY, RGB24, etc.\n     */\n    private int videoFormat;\n\n    /**\n     * Specifies an ID that will be used to specify this encoder while returning the bitstream in\n     * asynchronous mode.\n     */\n\n    private int encodeID;\n    /**\n     * Specifies the targeted profile, and will also specifies available tools for iEncMode. If\n     * default is used, encoder will choose its own preferred profile. If autodetect is used,\n     * encoder will check other settings and choose the right profile that doesn't have any\n     * conflicts.\n     */\n    private int profile;\n\n    /**\n     * Specifies the targeted profile IOP, composed of the values of constraint flags\n     */\n    private byte profileIOP;\n\n    /**\n     * Specifies the target level When present, other settings will be checked against the range\n     * allowable by this target level. Fail will returned upon Initialize call. If not known, users\n     * must set it to autodetect. Encoder will calculate the right level that doesn't conflict with\n     * other settings.\n     */\n    private int level;\n\n    /**\n     * Specifies whether base only (numLayer = 1) or base + enhancement layer (numLayer =2 ) is to\n     * be used.\n     */\n    private int numLayer;\n\n    /**\n     * Specifies the bit rate in bit per second.\n     */\n    private int bitRate;\n\n    /**\n     * Specifies the encoding mode. This translates to the complexity of encoding modes and error\n     * resilient tools.\n     */\n    private int encMode;\n\n    /**\n     * Specifies that SPS and PPS are retrieved first and sent out-of-band\n     */\n    private boolean outOfBandParamSet;\n\n    /**\n     * Specifies the desired output format.\n     */\n    private int outputFormat;\n\n    /**\n     * Specifies the packet size in bytes which represents the desired number of bytes per NAL. If\n     * this number is set to 0, the encoder will encode the entire slice group as one NAL.\n     */\n    private int packetSize;\n\n    /**\n     * Specifies the rate control algorithm among one of the following constant Q, CBR and VBR.\n     */\n    private int rateControlType;\n\n    /**\n     * Specifies the VBV buffer size which determines the end-to-end delay between the encoder and\n     * the decoder. The size is in unit of seconds. For download application, the buffer size can be\n     * larger than the streaming application. For 2-way application, this buffer shall be kept\n     * minimal. For a special case, in VBR mode, iBufferDelay will be set to -1 to allow buffer\n     * underflow.\n     */\n    private float bufferDelay;\n\n    /**\n     * Specifies the initial quantization parameter for the first I-frame. If constant Q rate\n     * control is used, this QP will be used for all the I-frames. This number must be set between 1\n     * and 31, otherwise, Initialize() will fail.\n     */\n    private int iquant;\n\n    /**\n     * Specifies the initial quantization parameter for the first P-frame. If constant Q rate\n     * control is used, this QP will be used for all the P-frames. This number must be set between 1\n     * and 31, otherwise, Initialize() will fail.\n     */\n    private int pquant;\n\n    /**\n     * Specifies the initial quantization parameter for the first B-frame. If constant Q rate\n     * control is used, this QP will be used for all the B-frames. This number must be set between 1\n     * and 31, otherwise, Initialize() will fail.\n     */\n    private int bquant;\n\n    /**\n     * Specifies automatic scene detection where I-frame will be used the the first frame in a new\n     * scene.\n     */\n    private boolean sceneDetection;\n\n    /**\n     * Specifies the maximum period in seconds between 2 INTRA frames. An INTRA mode is forced to a\n     * frame once this interval is reached. When there is only one I-frame is present at the\n     * beginning of the clip, iFrameInterval should be set to -1. For all I-frames coding this\n     * number should be set to 0.\n     */\n    private int iFrameInterval;\n\n    /**\n     * According to iIFrameInterval setting, the minimum number of intra MB per frame is optimally\n     * calculated for error resiliency. However, when iIFrameInterval is set to -1,\n     * numIntraMBRefresh must be specified to guarantee the minimum number of intra macroblocks per\n     * frame.\n     */\n    private int numIntraMBRefresh;\n\n    /**\n     * Specifies the duration of the clip in millisecond, needed for VBR encode. Set to 0 if\n     * unknown.\n     */\n    private int clipDuration;\n\n    /**\n     * Specify FSI Buffer input\n     */\n    private byte[] fSIBuff;\n\n    /**\n     * Specify FSI Buffer Length\n     */\n    private int fSIBuffLength;\n\n    // ----- Constructors -----\n\n    /**\n     * Constructor for native H264Encoder parameters\n     */\n    public NativeH264EncoderParams() {\n        // Default parameter that were being used in the codec, some of them\n        // hard coded\n        this.frameWidth = 176;\n        this.frameHeight = 144;\n        this.frameRate = 15;\n        this.frameOrientation = 0;\n        this.videoFormat = VIDEO_FORMAT_YUV420SEMIPLANAR;\n        this.encodeID = 0;\n        this.profile = PROFILE_BASELINE;\n        this.profileIOP = 0;\n        this.level = LEVEL_1B;\n        this.numLayer = 1;\n        this.bitRate = 64000;\n        this.encMode = ENCODING_MODE_TWOWAY;\n        this.outOfBandParamSet = true;\n        this.outputFormat = OUTPUT_FORMAT_RTP;\n        this.packetSize = 8192;\n        this.rateControlType = RATE_CONTROL_TYPE_CBR_1;\n        this.bufferDelay = 2;\n        this.iquant = 15;\n        this.pquant = 12;\n        this.bquant = 0;\n        this.sceneDetection = false;\n        this.iFrameInterval = 1;\n        this.numIntraMBRefresh = 50;\n        this.clipDuration = 0;\n        this.fSIBuff = null;\n        this.fSIBuffLength = 0;\n    }\n\n    /**\n     * Constructor for native H264Encoder parameters\n     * \n     * @param profileType Profile type\n     * @param profileIOP Profile IOP\n     * @param levelType Profile level type\n     * @param frameWidth Width in pixels of the input frame\n     * @param frameHeight Height in pixels of the input frame\n     * @param bitRate Bit rate in bit per second\n     * @param frameRate Frame rate in the unit of frame per second\n     * @param packetSize Packet size in bytes which represents the desired number of bytes per NAL\n     */\n    public NativeH264EncoderParams(H264TypeProfile profileType, byte profileIOP,\n            H264TypeLevel levelType,\n            int frameWidth, int frameHeight,\n            int bitRate, float frameRate, int packetSize) {\n        this(); // to fill the default parameters\n\n        this.frameWidth = frameWidth;\n        this.frameHeight = frameHeight;\n        this.bitRate = bitRate;\n        this.frameRate = frameRate;\n        this.packetSize = packetSize;\n        setProfile(profileType);\n        setLevel(levelType);\n        this.profileIOP = profileIOP;\n    }\n\n    // ----- Getters and Setters -----\n\n    /**\n     * Method to set profiles and level from a given codec parameter string\n     * \n     * @param codecParams Codec parameters\n     */\n    public void setProfilesAndLevel(String codecParams) {\n        String profile_level_id = H264Config.getCodecProfileLevelId(codecParams);\n        Byte profile_idc = H264Profile.getProfileIDCFromLevelId(profile_level_id);\n        Byte profile_iop = H264Profile.getProfileIOPFromLevelId(profile_level_id);\n        Byte level_idc = H264Profile.getLevelIDCFromLevelId(profile_level_id);\n\n        if (profile_idc != null && profile_iop != null && level_idc != null) {\n            // constraintSet3Flag is the X bit on YYYX YYYY\n            int constraintSet3FlagValue = ((profile_iop >> 4) & 0x01);\n            H264ConstraintSetFlagType constraintSet3Flag = ((constraintSet3FlagValue == 1) ? H264ConstraintSetFlagType.TRUE\n                    : H264ConstraintSetFlagType.FALSE);\n\n            setProfileIOP(profile_iop < 0 ? 0 : profile_iop);\n            setProfile(H264TypeProfile.getH264ProfileType(profile_idc));\n            setLevel(H264TypeLevel.getH264LevelType(level_idc, constraintSet3Flag));\n        }\n    }\n\n    public int getFrameWidth() {\n        return frameWidth;\n    }\n\n    public void setFrameWidth(int frameWidth) {\n        this.frameWidth = frameWidth;\n    }\n\n    public int getFrameHeight() {\n        return frameHeight;\n    }\n\n    public void setFrameHeight(int frameHeight) {\n        this.frameHeight = frameHeight;\n    }\n\n    public float getFrameRate() {\n        return frameRate;\n    }\n\n    public void setFrameRate(float frameRate) {\n        this.frameRate = frameRate;\n    }\n\n    public int getFrameOrientation() {\n        return frameOrientation;\n    }\n\n    public void setFrameOrientation(int frameOrientation) {\n        this.frameOrientation = frameOrientation;\n    }\n\n    public int getVideoFormat() {\n        return videoFormat;\n    }\n\n    public void setVideoFormat(int videoFormat) {\n        this.videoFormat = videoFormat;\n    }\n\n    public int getEncodeID() {\n        return encodeID;\n    }\n\n    public void setEncodeID(int encodeID) {\n        this.encodeID = encodeID;\n    }\n\n    public int getProfile() {\n        return profile;\n    }\n\n    public void setProfile(H264TypeProfile profile) {\n        this.profile = parseH264TypeProfile(profile);\n    }\n\n    public byte getProfileIOP() {\n        return profileIOP;\n    }\n\n    public void setProfileIOP(byte profileIOP) {\n        this.profileIOP = profileIOP;\n    }\n\n    public int getLevel() {\n        return level;\n    }\n\n    public void setLevel(H264TypeLevel level) {\n        this.level = parseH264TypeLevel(level);\n    }\n\n    public int getNumLayer() {\n        return numLayer;\n    }\n\n    public void setNumLayer(int numLayer) {\n        this.numLayer = numLayer;\n    }\n\n    public int getBitRate() {\n        return bitRate;\n    }\n\n    public void setBitRate(int bitRate) {\n        this.bitRate = bitRate;\n    }\n\n    public int getEncMode() {\n        return encMode;\n    }\n\n    public void setEncMode(int encMode) {\n        this.encMode = encMode;\n    }\n\n    public boolean isOutOfBandParamSet() {\n        return outOfBandParamSet;\n    }\n\n    public void setOutOfBandParamSet(boolean outOfBandParamSet) {\n        this.outOfBandParamSet = outOfBandParamSet;\n    }\n\n    public int getOutputFormat() {\n        return outputFormat;\n    }\n\n    public void setOutputFormat(int outputFormat) {\n        this.outputFormat = outputFormat;\n    }\n\n    public int getPacketSize() {\n        return packetSize;\n    }\n\n    public void setPacketSize(int packetSize) {\n        this.packetSize = packetSize;\n    }\n\n    public int getRateControlType() {\n        return rateControlType;\n    }\n\n    public void setRateControlType(int rateControlType) {\n        this.rateControlType = rateControlType;\n    }\n\n    public float getBufferDelay() {\n        return bufferDelay;\n    }\n\n    public void setBufferDelay(float bufferDelay) {\n        this.bufferDelay = bufferDelay;\n    }\n\n    public int getIquant() {\n        return iquant;\n    }\n\n    public void setIquant(int iquant) {\n        this.iquant = iquant;\n    }\n\n    public int getPquant() {\n        return pquant;\n    }\n\n    public void setiPquant(int pquant) {\n        this.pquant = pquant;\n    }\n\n    public int getBquant() {\n        return bquant;\n    }\n\n    public void setiBquant(int bquant) {\n        this.bquant = bquant;\n    }\n\n    public boolean isSceneDetection() {\n        return sceneDetection;\n    }\n\n    public void setSceneDetection(boolean sceneDetection) {\n        this.sceneDetection = sceneDetection;\n    }\n\n    public int getIFrameInterval() {\n        return iFrameInterval;\n    }\n\n    public void setIFrameInterval(int iFrameInterval) {\n        this.iFrameInterval = iFrameInterval;\n    }\n\n    public int getNumIntraMBRefresh() {\n        return numIntraMBRefresh;\n    }\n\n    public void setNumIntraMBRefresh(int numIntraMBRefresh) {\n        this.numIntraMBRefresh = numIntraMBRefresh;\n    }\n\n    public int getClipDuration() {\n        return clipDuration;\n    }\n\n    public void setClipDuration(int clipDuration) {\n        this.clipDuration = clipDuration;\n    }\n\n    public byte[] getFSIBuff() {\n        return fSIBuff;\n    }\n\n    public void setFSIBuff(byte[] fSIBuff) {\n        this.fSIBuff = fSIBuff;\n    }\n\n    public int getFSIBuffLength() {\n        return fSIBuffLength;\n    }\n\n    public void setFSIBuffLength(int fSIBuffLength) {\n        this.fSIBuffLength = fSIBuffLength;\n    }\n\n    /**\n     * Parse {@link H264TypeLevel} to map encode parameter 'Level'\n     * \n     * @param level\n     * @return map value if valid type, otherwise return <code>-1</code>\n     */\n    public static int parseH264TypeLevel(H264TypeLevel level) {\n        if (level == H264TypeLevel.LEVEL_1) {\n            return LEVEL_1;\n        } else if (level == H264TypeLevel.LEVEL_1B) {\n            return LEVEL_1B;\n        } else if (level == H264TypeLevel.LEVEL_1_1) {\n            return LEVEL_11;\n        } else if (level == H264TypeLevel.LEVEL_1_2) {\n            return LEVEL_12;\n        } else if (level == H264TypeLevel.LEVEL_1_3) {\n            return LEVEL_13;\n        } else if (level == H264TypeLevel.LEVEL_2) {\n            return LEVEL_2;\n        } else if (level == H264TypeLevel.LEVEL_2_1) {\n            return LEVEL_21;\n        } else if (level == H264TypeLevel.LEVEL_2_2) {\n            return LEVEL_22;\n        } else if (level == H264TypeLevel.LEVEL_3) {\n            return LEVEL_3;\n        } else if (level == H264TypeLevel.LEVEL_3_1) {\n            return LEVEL_31;\n        } else if (level == H264TypeLevel.LEVEL_3_2) {\n            return LEVEL_32;\n        } else if (level == H264TypeLevel.LEVEL_4) {\n            return LEVEL_4;\n        } else if (level == H264TypeLevel.LEVEL_4_1) {\n            return LEVEL_41;\n        } else if (level == H264TypeLevel.LEVEL_4_2) {\n            return LEVEL_42;\n        } else if (level == H264TypeLevel.LEVEL_5) {\n            return LEVEL_5;\n        } else if (level == H264TypeLevel.LEVEL_5_1) {\n            return LEVEL_51;\n        } else {\n            return -1;\n        }\n    }\n\n    /**\n     * Parse {@link H264TypeProfile} to map encode parameter 'Profile'\n     * \n     * @param profile\n     * @return map value if valid type, otherwise <code>PROFILE_DEFAULT<code>\n     */\n    public static int parseH264TypeProfile(H264TypeProfile profile) {\n        if (profile == H264TypeProfile.PROFILE_BASELINE) {\n            return PROFILE_BASELINE;\n        } else if (profile == H264TypeProfile.PROFILE_MAIN) {\n            return PROFILE_MAIN;\n        } else if (profile == H264TypeProfile.PROFILE_EXTENDED) {\n            return PROFILE_EXTENDED;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH) {\n            return PROFILE_HIGH;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH10) {\n            return PROFILE_HIGH10;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH422) {\n            return PROFILE_HIGH422;\n        } else if (profile == H264TypeProfile.PROFILE_HIGH444) {\n            return PROFILE_HIGH444;\n        } else {\n            return PROFILE_DEFAULT;\n        }\n    }\n\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles.H264TypeLevel.*;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.HexadecimalUtils;\n\n/**\n * Represent H264 base Profile\n * \n * @author Deutsche Telekom AG\n */\npublic abstract class H264Profile {\n\n    /**\n     * Video width\n     */\n    private int videoWidth;\n\n    /**\n     * Video height\n     */\n    private int videoHeight;\n\n    /**\n     * Video frame rate\n     */\n    private float frameRate;\n\n    /**\n     * Video bit rate\n     */\n    private int bitRate;\n\n    /**\n     * Packet size\n     */\n    private int packetSize;\n\n    /**\n     * Level type (1, 1b, 1.1...)\n     */\n    private H264TypeLevel level;\n\n    /**\n     * Profile type (BASELINE, MAIN...)\n     */\n    private H264TypeProfile type;\n\n    /**\n     * Codec parameters\n     */\n    private String codeParams;\n\n    /**\n     * Profile level id\n     */\n    private String levelId;\n\n    /**\n     * Profile name\n     */\n    private String profileName;\n\n    /**\n     * Profile IOP\n     */\n    private Byte profileIOP;\n\n    /**\n     * Base constructor for H264 Profiles\n     * \n     * @param profileName Profile name\n     * @param level Profile level\n     * @param type Profile type\n     * @param levelId Profile level id\n     * @param videoWidth Video with\n     * @param videoHeight Video height\n     * @param frameRate Frame rate\n     * @param bitRate Bit rate\n     * @param packetSize Packet size\n     * @param codeParams Codec parameters\n     */\n    public H264Profile(String profileName,\n            H264TypeLevel level,\n            H264TypeProfile type,\n            String levelId,\n            int videoWidth,\n            int videoHeight,\n            float frameRate,\n            int bitRate,\n            int packetSize,\n            String codeParams) {\n\n        this.videoWidth = videoWidth;\n        this.videoHeight = videoHeight;\n        this.frameRate = frameRate;\n        this.bitRate = bitRate;\n        this.packetSize = packetSize;\n        this.level = level;\n        this.type = type;\n        this.codeParams = codeParams;\n        this.levelId = levelId;\n        this.profileIOP = getProfileIOPFromLevelId(levelId);\n    }\n\n    public String getCodeParams() {\n        return codeParams;\n    }\n\n    public int getVideoWidth() {\n        return videoWidth;\n    }\n\n    public int getVideoHeight() {\n        return videoHeight;\n    }\n\n    public float getFrameRate() {\n        return frameRate;\n    }\n\n    public int getBitRate() {\n        return bitRate;\n    }\n\n    public int getPacketSize() {\n        return packetSize;\n    }\n\n    public H264TypeLevel getLevel() {\n        return level;\n    }\n\n    public H264TypeProfile getType() {\n        return type;\n    }\n\n    public String getLevelId() {\n        return levelId;\n    }\n\n    public String getProfileName() {\n        return profileName;\n    }\n\n    public Byte getProfileIOP() {\n        return profileIOP;\n    }\n\n    /**\n     * Get the byte that represents the profile IDC\n     * \n     * @param profileId H264 profile-id\n     * @return profile IDC\n     */\n    public static Byte getProfileIDCFromLevelId(final String profileLevelId) {\n        return getProfileInformationFromLevelId(profileLevelId, 0);\n    }\n\n    /**\n     * Get the byte that represents the profile IOP\n     * \n     * @param profileId H264 profile-id\n     * @return profile IOP\n     */\n    public static Byte getProfileIOPFromLevelId(final String profileLevelId) {\n        return getProfileInformationFromLevelId(profileLevelId, 1);\n    }\n\n    /**\n     * Get the byte that represents the level IDC\n     * \n     * @param profileId H264 profile-id\n     * @return level IDC\n     */\n    public static Byte getLevelIDCFromLevelId(final String profileLevelId) {\n        return getProfileInformationFromLevelId(profileLevelId, 2);\n    }\n\n    /**\n     * Get informations after parse H264 profile-id\n     * \n     * @param profileId H264 profile-id\n     * @param what 0: Profile IDC, 1: Profile IOP, 2: Level IDC\n     * @return\n     */\n    private static Byte getProfileInformationFromLevelId(final String profileLevelId, int what) {\n        byte[] arrProfileId = HexadecimalUtils.hexStringToByteArray(profileLevelId);\n        if (arrProfileId == null || arrProfileId.length != 3 || what < 0 || what > 2) {\n            return null;\n        } else {\n            return arrProfileId[what];\n        }\n    }\n\n    /**\n     * Get instance of H264 profile, using profile-id\n     * \n     * @param profileId\n     * @return {@link H264Profile} if supported, otherwise <code>null</code>\n     */\n    public static H264Profile getProfile(String profileId) {\n        H264Profile profile = null;\n        try {\n\n            final Byte profileIDC = getProfileIDCFromLevelId(profileId);\n            final Byte profileIOP = getProfileIOPFromLevelId(profileId);\n            final Byte levelIDC = getLevelIDCFromLevelId(profileId);\n\n            if (profileIDC == null || profileIOP == null || levelIDC == null) {\n                return null;\n            }\n\n            // constraintSet3Flag is the X bit on YYYX YYYY\n            int constraintSet3FlagValue = ((profileIOP >> 4) & 0x01);\n            H264ConstraintSetFlagType constraintSet3Flag = ((constraintSet3FlagValue == 1) ? H264ConstraintSetFlagType.TRUE\n                    : H264ConstraintSetFlagType.FALSE);\n\n            H264TypeLevel level = H264TypeLevel.getH264LevelType(levelIDC,\n                    constraintSet3Flag);\n\n            if (H264TypeLevel.LEVEL_1 == level) {\n                profile = new H264Profile1();\n            } else if (H264TypeLevel.LEVEL_1B == level) {\n                profile = new H264Profile1b();\n            } else if (H264TypeLevel.LEVEL_1_1 == level) {\n                profile = new H264Profile1_1();\n            } else if (H264TypeLevel.LEVEL_1_2 == level) {\n                profile = new H264Profile1_2();\n            } else if (H264TypeLevel.LEVEL_1_3 == level) {\n                profile = new H264Profile1_3();\n            } else {\n                profile = null;\n            }\n\n        } catch (Exception e) {\n        }\n\n        return profile;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0a (level 1)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800a\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 64000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 80000;\n\n    private static final String base64CodeSPS = \"J0KACpY1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\" +\n                H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\" +\n                H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" +\n                base64CodeSPS + \",\" + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1() {\n        super(PROFILE_NAME,\n                H264TypeLevel.LEVEL_1,\n                H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID,\n                176, 144, 15.0f,\n                BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE,\n                profileParams);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1_1.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1.1\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1_1 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1.1\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0b (level 1.1)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800b\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 192000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 240000;\n\n    private static final String base64CodeSPS = \"J0KAC5Y1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\" +\n                H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\" +\n                H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" +\n                base64CodeSPS + \",\" + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1_1() {\n        super(PROFILE_NAME,\n                H264TypeLevel.LEVEL_1_1,\n                H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID,\n                176, 144, 15.0f,\n                BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE,\n                profileParams);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1_2.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1.2\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1_2 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1.2\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0c (level 1.2)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800c\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 384000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 480000;\n\n    private static final String base64CodeSPS = \"J0KADJY1BYnI\"; // QCIF\n    // static final String base64CodeSPS = \"J0KADJo1AoPy\"; // QVGA\n\n    private static final String base64CodePPS = \"KM4C/IA=\"; // QCIF\n    // static final String base64CodePPS = \"KM4C/IA=\"; // QVGA\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\" +\n                H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\" +\n                H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" +\n                base64CodeSPS + \",\" + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1_2() {\n        super(PROFILE_NAME,\n                H264TypeLevel.LEVEL_1_2,\n                H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID,\n                176, 144, 15.0f, // QCIF\n                // 320, 240, 20.0f, // QVGA\n                BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE,\n                profileParams);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1_3.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1.3\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1_3 extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1.3\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 80 (Constrained Baseline), 0d (level 1.3)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42800d\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 768000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 960000;\n\n    private static final String base64CodeSPS = \"J0KADZY1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\" +\n                H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\" +\n                H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" +\n                base64CodeSPS + \",\" + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1_3() {\n        super(PROFILE_NAME,\n                H264TypeLevel.LEVEL_1_3,\n                H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID,\n                176, 144, 15.0f,\n                BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE,\n                profileParams);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264Profile1b.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.H264Config;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.JavaPacketizer;\n\n/**\n * Represent H264 Profile to Level 1b\n * \n * @author Deutsche Telekom AG\n */\npublic class H264Profile1b extends H264Profile {\n\n    /**\n     * Profile name\n     */\n    public static final String PROFILE_NAME = \"H264Profile1b\";\n\n    /**\n     * Profile Id 42 (Baseline 66), 90 (Constrained baseline with level 1.b), 11 (level 1.b, because\n     * of the constraint_set3_flag)\n     */\n    public static final String BASELINE_PROFILE_ID = \"42900b\";\n\n    private static final int BASELINE_PROFILE_BITRATE = 128000;\n\n    // private static final int HIGH_PROFILE_BITRATE = 160000;\n\n    private static final String base64CodeSPS = \"J0KQCZY1BYnI\";\n\n    private static final String base64CodePPS = \"KM4C/IA=\";\n\n    private static String profileParams;\n\n    static {\n        profileParams = H264Config.CODEC_PARAM_PROFILEID + \"=\" + BASELINE_PROFILE_ID + \";\" +\n                H264Config.CODEC_PARAM_PACKETIZATIONMODE + \"=1;\" +\n                H264Config.CODEC_PARAM_SPROP_PARAMETER_SETS + \"=\" +\n                base64CodeSPS + \",\" + base64CodePPS + \";\";\n    }\n\n    /**\n     * Constructor\n     */\n    public H264Profile1b() {\n        super(PROFILE_NAME,\n                H264TypeLevel.LEVEL_1B,\n                H264TypeProfile.PROFILE_BASELINE,\n                BASELINE_PROFILE_ID,\n                176, 144, 15.0f,\n                BASELINE_PROFILE_BITRATE,\n                JavaPacketizer.H264_MAX_PACKET_FRAME_SIZE,\n                profileParams);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264TypeLevel.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\n/**\n * Targeted level to encode\n * \n * @author Deutsche Telekom AG\n */\npublic enum H264TypeLevel {\n\n    LEVEL_AUTODETECT(0, H264ConstraintSetFlagType.ANY),\n    LEVEL_1(10, H264ConstraintSetFlagType.ANY),\n    LEVEL_1B(11, H264ConstraintSetFlagType.TRUE),\n    LEVEL_1_1(11, H264ConstraintSetFlagType.FALSE),\n    LEVEL_1_2(12, H264ConstraintSetFlagType.ANY),\n    LEVEL_1_3(13, H264ConstraintSetFlagType.ANY),\n    LEVEL_2(20, H264ConstraintSetFlagType.ANY),\n    LEVEL_2_1(21, H264ConstraintSetFlagType.ANY),\n    LEVEL_2_2(22, H264ConstraintSetFlagType.ANY),\n    LEVEL_3(30, H264ConstraintSetFlagType.ANY),\n    LEVEL_3_1(31, H264ConstraintSetFlagType.ANY),\n    LEVEL_3_2(32, H264ConstraintSetFlagType.ANY),\n    LEVEL_4(40, H264ConstraintSetFlagType.ANY),\n    LEVEL_4_1(41, H264ConstraintSetFlagType.ANY),\n    LEVEL_4_2(42, H264ConstraintSetFlagType.ANY),\n    LEVEL_5(50, H264ConstraintSetFlagType.ANY),\n    LEVEL_5_1(51, H264ConstraintSetFlagType.ANY);\n\n    /**\n     * Level value\n     */\n    private int decimalValue;\n\n    /**\n     * Constraint Flag\n     */\n    private H264ConstraintSetFlagType constraintSet3Flag;\n\n    /**\n     * Constructor\n     * \n     * @param decimalValue level\n     * @param constraintSet3Flag constraint Flag\n     */\n    private H264TypeLevel(int decimalValue, H264ConstraintSetFlagType constraintSet3Flag) {\n        this.decimalValue = decimalValue;\n        this.constraintSet3Flag = constraintSet3Flag;\n    }\n\n    /**\n     * Get Level value\n     * \n     * @return level\n     */\n    public int getDecimalValue() {\n        return decimalValue;\n    }\n\n    /**\n     * Get Constraint Flag\n     * \n     * @return Constraint Flag\n     */\n    public H264ConstraintSetFlagType getH264ConstraintSet3Flag() {\n        return constraintSet3Flag;\n    }\n\n    /**\n     * Get H264TypeLevel\n     * \n     * @param decimalValue level\n     * @param constraintSet3Flag constraint Flag\n     * @return H264TypeLevel\n     */\n    public static H264TypeLevel getH264LevelType(int decimalValue,\n            H264ConstraintSetFlagType constraintSet3Flag) {\n        for (H264TypeLevel h264LevelType : H264TypeLevel.values()) {\n            if ((h264LevelType.getDecimalValue() == decimalValue) &&\n                    ((h264LevelType.getH264ConstraintSet3Flag() == H264ConstraintSetFlagType.ANY) ||\n                    (h264LevelType.getH264ConstraintSet3Flag() == constraintSet3Flag))) {\n                return h264LevelType;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Targeted constrains set flags to encode.\n     */\n    public enum H264ConstraintSetFlagType {\n        ANY(0),\n        FALSE(1),\n        TRUE(2);\n\n        /**\n         * Constraint flag value\n         */\n        private int decimalValue;\n\n        /**\n         * Constructor\n         * \n         * @param decimalValue constraint flag value\n         */\n        private H264ConstraintSetFlagType(int decimalValue) {\n            this.decimalValue = decimalValue;\n        }\n\n        /**\n         * Get constraint flag value\n         * \n         * @return constraint flag\n         */\n        public int getDecimalValue() {\n            return decimalValue;\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/codec/video/h264/profiles/H264TypeProfile.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.codec.video.h264.profiles;\n\n/**\n * Targeted profile to encode\n * \n * @author Deutsche Telekom AG\n */\npublic enum H264TypeProfile {\n\n    /* Non-scalable profile */\n    PROFILE_BASELINE(66),\n    PROFILE_MAIN(77),\n    PROFILE_EXTENDED(88),\n    PROFILE_HIGH(100),\n    PROFILE_HIGH10(110),\n    PROFILE_HIGH422(122),\n    PROFILE_HIGH444(244),\n    PROFILE_CAVLC444(44);\n\n    /**\n     * Type value\n     */\n    public int decimalValue;\n\n    /**\n     * Constructor\n     * \n     * @param decimalValue type\n     */\n    private H264TypeProfile(int decimalValue) {\n        this.decimalValue = decimalValue;\n    }\n\n    /**\n     * Get Type\n     * \n     * @return type value\n     */\n    public int getDecimalValue() {\n        return decimalValue;\n    }\n\n    /**\n     * Get instance of {@link H264TypeProfile}, using decimal value\n     * \n     * @param decimalValue\n     * @return {@link H264TypeProfile} if valid decimal, otherwise <code>null</code>\n     */\n    public static H264TypeProfile getH264ProfileType(int decimalValue) {\n        for (H264TypeProfile h264ProfileType : H264TypeProfile.values()) {\n            if (h264ProfileType.getDecimalValue() == decimalValue) {\n                return h264ProfileType;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/ReceptionReport.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * ReceptionReport based on RFC 3550 specification\n * \n * @author Deutsche Telekom\n */\npublic class ReceptionReport {\n\n    /**\n     * The SSRC identifier of the source to which the information in this reception report block\n     * pertains\n     */\n    private int ssrc;\n\n    /**\n     * The fraction of RTP data packets from source SSRC lost since the previous SR or RR packet was\n     * sent\n     */\n    private double fractionLost;\n\n    /**\n     * The total number of RTP data packets from source SSRC_n that have been lost since the\n     * beginning of reception\n     */\n    private int cumulativeNumberOfPacketsLost;\n\n    /**\n     * The low 16 bits contain the highest sequence number received in an RTP data packet from\n     * source SSRC, and the most significant 16 bits extend that sequence number with the\n     * corresponding count of sequence number cycles\n     */\n    private long extendedHighestSequenceNumberReceived;\n\n    /**\n     * An estimate of the statistical variance of the RTP data packet interarrival time, measured in\n     * timestamp units and expressed as anunsigned integer\n     */\n    private long interarrivalJitter;\n\n    /**\n     * The middle 32 bits out of 64 in the NTP timestamp received as part of the most recent RTCP\n     * sender report (SR) packet from source SSRC. If no SR has been received yet, the field is set\n     * to zero\n     */\n    private long lastSenderReport;\n\n    /**\n     * The delay, expressed in units of 1/65536 seconds, between receiving the last SR packet from\n     * source SSRC and sending this reception report block\n     */\n    private long delaySinceLastSenderReport;\n\n    /**\n     * Default constructor\n     * \n     * @param ssrc Source identifier\n     */\n    public ReceptionReport(int ssrc) {\n        this.ssrc = ssrc;\n    }\n\n    public long getSsrc() {\n        return ssrc;\n    }\n\n    public int setSsrc(int ssrc) {\n        return ssrc;\n    }\n\n    public double getFractionLost() {\n        return fractionLost;\n    }\n\n    public void setFractionLost(double fractionLost) {\n        this.fractionLost = fractionLost;\n    }\n\n    public int getCumulativeNumberOfPacketsLost() {\n        return cumulativeNumberOfPacketsLost;\n    }\n\n    public void setCumulativeNumberOfPacketsLost(int cumulativeNumberOfPacketsLost) {\n        this.cumulativeNumberOfPacketsLost = cumulativeNumberOfPacketsLost;\n    }\n\n    public long getExtendedHighestSequenceNumberReceived() {\n        return extendedHighestSequenceNumberReceived;\n    }\n\n    public void setExtendedHighestSequenceNumberReceived(long extendedHighestSequenceNumberReceived) {\n        this.extendedHighestSequenceNumberReceived = extendedHighestSequenceNumberReceived;\n    }\n\n    public long getInterarrivalJitter() {\n        return interarrivalJitter;\n    }\n\n    public void setInterarrivalJitter(long interarrivalJitter) {\n        this.interarrivalJitter = interarrivalJitter;\n    }\n\n    public long getLastSenderReport() {\n        return lastSenderReport;\n    }\n\n    public void setLastSenderReport(long lastSenderReport) {\n        this.lastSenderReport = lastSenderReport;\n    }\n\n    public long getDelaySinceLastSenderReport() {\n        return delaySinceLastSenderReport;\n    }\n\n    public void setDelaySinceLastSenderReport(long delaySinceLastSenderReport) {\n        this.delaySinceLastSenderReport = delaySinceLastSenderReport;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpAppPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RTCP APP packet\n * \n * @author jexa7410\n */\npublic class RtcpAppPacket extends RtcpPacket {\n    public int ssrc;\n    public int name;\n    public int subtype;\n\n    public RtcpAppPacket(RtcpPacket parent) {\n        super(parent);\n\n        super.type = 204;\n    }\n\n    public RtcpAppPacket(int ssrc, int name, int subtype, byte data[]) {\n        this.ssrc = ssrc;\n        this.name = name;\n        this.subtype = subtype;\n        this.data = data;\n        super.type = 204;\n\n        if ((data.length & 3) != 0) {\n            throw new IllegalArgumentException(\"Bad data length\");\n        }\n        if (subtype < 0 || subtype > 31) {\n            throw new IllegalArgumentException(\"Bad subtype\");\n        } else {\n            return;\n        }\n    }\n\n    public int calcLength() {\n        return 12 + data.length;\n    }\n\n    public void assemble(DataOutputStream out) throws IOException {\n        out.writeByte(128 + subtype);\n        out.writeByte(204);\n        out.writeShort(2 + (data.length >> 2));\n        out.writeInt(ssrc);\n        out.writeInt(name);\n        out.write(data);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpByePacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RTCP BYE packet\n * \n * @author jexa7410\n */\npublic class RtcpByePacket extends RtcpPacket {\n\n    public int ssrc[];\n    public byte reason[];\n\n    public RtcpByePacket(RtcpPacket parent) {\n        super(parent);\n        super.type = 203;\n    }\n\n    public RtcpByePacket(int ssrc[], byte reason[]) {\n        this.ssrc = ssrc;\n        if (reason != null) {\n            this.reason = reason;\n        } else {\n            this.reason = new byte[0];\n        }\n        if (ssrc.length > 31) {\n            throw new IllegalArgumentException(\"Too many SSRCs\");\n        } else {\n            return;\n        }\n    }\n\n    public int calcLength() {\n        return 4 + (ssrc.length << 2)\n                + (reason.length <= 0 ? 0 : reason.length + 4 & -4);\n    }\n\n    public void assemble(DataOutputStream out) throws IOException {\n        out.writeByte(128 + ssrc.length);\n        out.writeByte(203);\n        out.writeShort(ssrc.length\n                + (reason.length <= 0 ? 0 : reason.length + 4 >> 2));\n        for (int i = 0; i < ssrc.length; i++) {\n            out.writeInt(ssrc[i]);\n        }\n\n        if (reason.length > 0) {\n            out.writeByte(reason.length);\n            out.write(reason);\n            for (int i = (reason.length + 4 & -4) - reason.length - 1; i > 0; i--) {\n                out.writeByte(0);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpCompoundPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Packet;\n\n/**\n * RTCP compound packet\n * \n * @author jexa7410\n */\npublic class RtcpCompoundPacket extends RtcpPacket {\n    public RtcpPacket[] packets;\n\n    public RtcpCompoundPacket(Packet packet) {\n        super(packet);\n        type = -1;\n    }\n\n    public RtcpCompoundPacket(RtcpPacket[] rtcppackets) {\n        packets = rtcppackets;\n        type = -1;\n    }\n\n    public void assemble(int i, boolean bool) {\n        length = i;\n        offset = 0;\n        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(\n                i);\n        DataOutputStream dataoutputstream = new DataOutputStream(\n                bytearrayoutputstream);\n        int i_0_;\n        try {\n            if (bool)\n                offset += 4;\n            i_0_ = offset;\n            for (int i_1_ = 0; i_1_ < packets.length; i_1_++) {\n                i_0_ = bytearrayoutputstream.size();\n                packets[i_1_].assemble(dataoutputstream);\n            }\n        } catch (IOException ioexception) {\n            throw new NullPointerException(\"Impossible IO Exception\");\n        }\n        int i_2_ = bytearrayoutputstream.size();\n        data = bytearrayoutputstream.toByteArray();\n        if (i_2_ > i)\n            throw new NullPointerException(\"RTCP Packet overflow\");\n        if (i_2_ < i) {\n            if (data.length < i)\n                System.arraycopy(data, 0, data = new byte[i], 0, i_2_);\n            data[i_0_] |= 0x20;\n            data[i - 1] = (byte) (i - i_2_);\n            int i_3_ = (data[i_0_ + 3] & 0xff) + (i - i_2_ >> 2);\n            if (i_3_ >= 256)\n                data[i_0_ + 2] += i - i_2_ >> 10;\n            data[i_0_ + 3] = (byte) i_3_;\n        }\n    }\n\n    public void assemble(DataOutputStream dataoutputstream) throws IOException {\n        throw new IllegalArgumentException(\"Recursive Compound Packet\");\n    }\n\n    public int calcLength() {\n        int i = 0;\n        if (packets == null || packets.length < 1)\n            throw new IllegalArgumentException(\"Bad RTCP Compound Packet\");\n        for (int i_4_ = 0; i_4_ < packets.length; i_4_++)\n            i += packets[i_4_].calcLength();\n        return i;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Packet;\n\n/**\n * Abstract RCTP packet\n * \n * @author jexa7410\n */\npublic abstract class RtcpPacket extends Packet {\n    /**\n     * Version =2\n     */\n    public static final byte VERSION = 2;\n\n    /**\n     * Padding =0\n     */\n    public static final byte PADDING = 0;\n\n    /**\n     * RTCP SR\n     */\n    public static final int RTCP_SR = 200;\n\n    /**\n     * RTCP RR\n     */\n    public static final int RTCP_RR = 201;\n\n    /**\n     * RTCP SDES\n     */\n    public static final int RTCP_SDES = 202;\n\n    /**\n     * RTCP BYE\n     */\n    public static final int RTCP_BYE = 203;\n\n    /**\n     * RTCP APP\n     */\n    public static final int RTCP_APP = 204;\n\n    /**\n     * RTCP APP\n     */\n    public static final int RTCP_COMPOUND = -1;\n\n    public Packet base;\n\n    public int type;\n\n    public RtcpPacket() {\n    }\n\n    public RtcpPacket(RtcpPacket rtcppacket) {\n        super((Packet) rtcppacket);\n\n        base = rtcppacket.base;\n    }\n\n    public RtcpPacket(Packet packet) {\n        super(packet);\n\n        base = packet;\n    }\n\n    public abstract void assemble(DataOutputStream dataoutputstream) throws IOException;\n\n    public abstract int calcLength();\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpPacketReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.net.SocketTimeoutException;\nimport java.util.Vector;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpApplicationEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpByeEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpEventListener;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpReceiverReportEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpSdesEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpSenderReportEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.AndroidDatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.DatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Packet;\n\n/**\n * RTCP packet receiver\n * \n * @author jexa7410\n */\npublic class RtcpPacketReceiver extends Thread {\n    /**\n     * Datagram connection\n     */\n    public DatagramConnection datagramConnection = null;\n\n    /**\n     * Statistics\n     */\n    private RtcpStatisticsReceiver stats = new RtcpStatisticsReceiver();\n\n    /**\n     * RTCP event listeners\n     */\n    private Vector<RtcpEventListener> listeners = new Vector<RtcpEventListener>();\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * Constructor\n     * \n     * @param port Listening port\n     * @param rtcpSession the RTCP session\n     * @param socketTimeout\n     * @throws IOException\n     */\n    public RtcpPacketReceiver(int port, RtcpSession rtcpSession, int socketTimeout)\n            throws IOException {\n        super();\n\n        this.rtcpSession = rtcpSession;\n\n        // Create the UDP server\n        datagramConnection = new AndroidDatagramConnection(socketTimeout);\n        datagramConnection.open(port);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param port Listening port\n     * @param rtcpSession the RTCP session\n     * @throws IOException\n     */\n    public RtcpPacketReceiver(int port, RtcpSession rtcpSession) throws IOException {\n        this(port, rtcpSession, 0);\n    }\n\n    /**\n     * Close the receiver\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        // Interrupt the current thread processing\n        try {\n            interrupt();\n        } catch (Exception e) {\n        }\n\n        // Close the datagram connection\n        if (datagramConnection != null) {\n            datagramConnection.close();\n            datagramConnection = null;\n        }\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            while (datagramConnection != null) {\n                // Wait a packet\n                byte[] data = datagramConnection.receive();\n\n                // Create a packet object\n                Packet packet = new Packet();\n                packet.data = data;\n                packet.length = data.length;\n                packet.offset = 0;\n                packet.receivedAt = System.currentTimeMillis();\n\n                // Process the received packet\n                handlePacket(packet);\n            }\n        } catch (SocketTimeoutException ex) {\n            notifyRtcpListenersOfTimeout();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Handle the received packet\n     * \n     * @param packet Packet\n     * @return RTCP packet\n     */\n    public RtcpPacket handlePacket(Packet p) {\n        // Update statistics\n        stats.numRtcpPkts++;\n        stats.numRtcpBytes += p.length;\n\n        // Parse the RTCP packet\n        RtcpPacket result;\n        try {\n            result = parseRtcpPacket(p);\n        } catch (Exception e) {\n            stats.numBadRtcpPkts++;\n            return null;\n        }\n        return result;\n    }\n\n    /**\n     * Parse the RTCP packet\n     * \n     * @param packet RTCP packet not yet parsed\n     * @return RTCP packet\n     */\n    public RtcpPacket parseRtcpPacket(Packet packet) {\n        RtcpCompoundPacket compoundPacket = new RtcpCompoundPacket(packet);\n        Vector<RtcpPacket> subpackets = new Vector<RtcpPacket>();\n        DataInputStream in = new DataInputStream(\n                new ByteArrayInputStream(compoundPacket.data,\n                        compoundPacket.offset,\n                        compoundPacket.length));\n        try {\n            rtcpSession.updateavgrtcpsize(compoundPacket.length);\n            int length = 0;\n            for (int offset = 0; offset < compoundPacket.length; offset += length) {\n                // Read first byte\n                int firstbyte = in.readUnsignedByte();\n                if ((firstbyte & 0xc0) != 128) {\n                    return null;\n                }\n\n                // Read type of subpacket\n                int type = in.readUnsignedByte();\n\n                // Read length of subpacket\n                length = in.readUnsignedShort();\n                length = length + 1 << 2;\n                int padlen = 0;\n                if (offset + length > compoundPacket.length) {\n                    return null;\n                }\n                if (offset + length == compoundPacket.length) {\n                    if ((firstbyte & 0x20) != 0) {\n                        padlen = compoundPacket.data[compoundPacket.offset + compoundPacket.length\n                                - 1] & 0xff;\n                        if (padlen == 0) {\n                            return null;\n                        }\n                    }\n                } else if ((firstbyte & 0x20) != 0) {\n                    return null;\n                }\n                int inlength = length - padlen;\n                firstbyte &= 0x1f;\n\n                // Parse subpacket\n                RtcpPacket subpacket;\n                switch (type) {\n                // RTCP SR event\n                    case RtcpPacket.RTCP_SR:\n                        stats.numSrPkts++;\n                        if (inlength != 28 + 24 * firstbyte) {\n                            stats.numMalformedRtcpPkts++;\n                            return null;\n                        }\n                        RtcpSenderReportPacket srp = new RtcpSenderReportPacket(compoundPacket);\n                        subpacket = srp;\n                        srp.ssrc = in.readInt();\n                        srp.ntptimestampmsw = (long) in.readInt() & 0xffffffffL;\n                        srp.ntptimestamplsw = (long) in.readInt() & 0xffffffffL;\n                        srp.rtptimestamp = (long) in.readInt() & 0xffffffffL;\n                        srp.packetcount = (long) in.readInt() & 0xffffffffL;\n                        srp.octetcount = (long) in.readInt() & 0xffffffffL;\n                        srp.reports = new RtcpReport[firstbyte];\n\n                        RtpSource sourceSR = rtcpSession.getMySource();\n                        if (sourceSR != null) {\n                            sourceSR.receivedSenderReport(srp);\n                        }\n\n                        for (int i = 0; i < srp.reports.length; i++) {\n                            RtcpReport report = new RtcpReport();\n                            srp.reports[i] = report;\n                            report.ssrc = in.readInt();\n                            long val = in.readInt();\n                            val &= 0xffffffffL;\n                            report.fractionlost = (int) (val >> 24);\n                            report.packetslost = (int) (val & 0xffffffL);\n                            report.lastseq = (long) in.readInt() & 0xffffffffL;\n                            report.jitter = in.readInt();\n                            report.lsr = (long) in.readInt() & 0xffffffffL;\n                            report.dlsr = (long) in.readInt() & 0xffffffffL;\n                        }\n\n                        // Notify event listeners\n                        notifyRtcpListeners(new RtcpSenderReportEvent(srp));\n                        break;\n\n                    // RTCP RR event\n                    case RtcpPacket.RTCP_RR:\n                        if (inlength != 8 + 24 * firstbyte) {\n                            stats.numMalformedRtcpPkts++;\n                            return null;\n                        }\n                        RtcpReceiverReportPacket rrp = new RtcpReceiverReportPacket(compoundPacket);\n                        subpacket = rrp;\n                        rrp.ssrc = in.readInt();\n                        rrp.reports = new RtcpReport[firstbyte];\n\n                        for (int i = 0; i < rrp.reports.length; i++) {\n                            RtcpReport report = new RtcpReport();\n                            rrp.reports[i] = report;\n                            report.ssrc = in.readInt();\n                            long val = in.readInt();\n                            val &= 0xffffffffL;\n                            report.fractionlost = (int) (val >> 24);\n                            report.packetslost = (int) (val & 0xffffffL);\n                            report.lastseq = (long) in.readInt() & 0xffffffffL;\n                            report.jitter = in.readInt();\n                            report.lsr = (long) in.readInt() & 0xffffffffL;\n                            report.dlsr = (long) in.readInt() & 0xffffffffL;\n                        }\n\n                        // Notify event listeners\n                        notifyRtcpListeners(new RtcpReceiverReportEvent(rrp));\n                        break;\n\n                    // RTCP SDES event\n                    case RtcpPacket.RTCP_SDES:\n                        RtcpSdesPacket sdesp = new RtcpSdesPacket(compoundPacket);\n                        subpacket = sdesp;\n                        sdesp.sdes = new RtcpSdesBlock[firstbyte];\n                        int sdesoff = 4;\n                        for (int i = 0; i < sdesp.sdes.length; i++) {\n                            RtcpSdesBlock chunk = new RtcpSdesBlock();\n                            sdesp.sdes[i] = chunk;\n                            chunk.ssrc = in.readInt();\n                            sdesoff += 5;\n                            Vector<RtcpSdesItem> items = new Vector<RtcpSdesItem>();\n                            boolean gotcname = false;\n                            int j;\n                            while ((j = in.readUnsignedByte()) != 0) {\n                                if (j < 1 || j > 8) {\n                                    stats.numMalformedRtcpPkts++;\n                                    return null;\n                                }\n                                if (j == 1) {\n                                    gotcname = true;\n                                }\n                                RtcpSdesItem item = new RtcpSdesItem();\n                                items.addElement(item);\n                                item.type = j;\n                                int sdeslen = in.readUnsignedByte();\n                                item.data = new byte[sdeslen];\n                                in.readFully(item.data);\n                                sdesoff += 2 + sdeslen;\n                            }\n                            if (!gotcname) {\n                                stats.numMalformedRtcpPkts++;\n                                return null;\n                            }\n                            chunk.items = new RtcpSdesItem[items.size()];\n                            items.copyInto(chunk.items);\n                            if ((sdesoff & 3) != 0) {\n                                if (in.skip(4 - (sdesoff & 3)) != 4 - (sdesoff & 3)) {\n                                    return null;\n                                }\n                                sdesoff = sdesoff + 3 & -4;\n                            }\n                        }\n\n                        if (inlength != sdesoff) {\n                            stats.numMalformedRtcpPkts++;\n                            return null;\n                        }\n\n                        // Notify event listeners\n                        notifyRtcpListeners(new RtcpSdesEvent(sdesp));\n                        break;\n\n                    // RTCP BYE event\n                    case RtcpPacket.RTCP_BYE:\n                        RtcpByePacket byep = new RtcpByePacket(compoundPacket);\n                        subpacket = byep;\n                        byep.ssrc = new int[firstbyte];\n                        for (int i = 0; i < byep.ssrc.length; i++) {\n                            byep.ssrc[i] = in.readInt();\n                        }\n\n                        int reasonlen;\n                        if (inlength > 4 + 4 * firstbyte) {\n                            reasonlen = in.readUnsignedByte();\n                            byep.reason = new byte[reasonlen];\n                            reasonlen++;\n                        } else {\n                            reasonlen = 0;\n                            byep.reason = new byte[0];\n                        }\n                        reasonlen = reasonlen + 3 & -4;\n                        if (inlength != 4 + 4 * firstbyte + reasonlen) {\n                            stats.numMalformedRtcpPkts++;\n                            return null;\n                        }\n                        in.readFully(byep.reason);\n                        int skipBye = reasonlen - byep.reason.length;\n                        if (in.skip(skipBye) != skipBye) {\n                            return null;\n                        }\n\n                        // Notify event listeners\n                        notifyRtcpListeners(new RtcpByeEvent(byep));\n                        break;\n\n                    // RTCP APP event\n                    case RtcpPacket.RTCP_APP:\n                        if (inlength < 12) {\n                            return null;\n                        }\n                        RtcpAppPacket appp = new RtcpAppPacket(compoundPacket);\n                        subpacket = appp;\n                        appp.ssrc = in.readInt();\n                        appp.name = in.readInt();\n                        appp.subtype = firstbyte;\n                        appp.data = new byte[inlength - 12];\n                        in.readFully(appp.data);\n                        int skipApp = inlength - 12 - appp.data.length;\n                        if (in.skip(skipApp) != skipApp) {\n                            return null;\n                        }\n\n                        // Notify event listeners\n                        notifyRtcpListeners(new RtcpApplicationEvent(appp));\n                        break;\n\n                    // RTCP unknown event\n                    default:\n                        stats.numUnknownTypes++;\n                        return null;\n                }\n                subpacket.offset = offset;\n                subpacket.length = length;\n                subpackets.addElement(subpacket);\n                if (in.skipBytes(padlen) != padlen) {\n                    return null;\n                }\n            }\n\n        } catch (Exception e) {\n            return null;\n        }\n        compoundPacket.packets = new RtcpPacket[subpackets.size()];\n        subpackets.copyInto(compoundPacket.packets);\n        return compoundPacket;\n    }\n\n    /**\n     * Add a RTCP event listener\n     * \n     * @param listener Listener\n     */\n    public void addRtcpListener(RtcpEventListener listener) {\n        listeners.addElement(listener);\n    }\n\n    /**\n     * Remove a RTCP event listener\n     * \n     * @param listener Listener\n     */\n    public void removeRtcpListener(RtcpEventListener listener) {\n        listeners.removeElement(listener);\n    }\n\n    /**\n     * Notify RTCP event listeners\n     * \n     * @param event RTCP event\n     */\n    public void notifyRtcpListeners(RtcpEvent event) {\n        for (int i = 0; i < listeners.size(); i++) {\n            RtcpEventListener listener = (RtcpEventListener) listeners.elementAt(i);\n            listener.receiveRtcpEvent(event);\n        }\n    }\n\n    /**\n     * Notify timeout on RTCP listener\n     */\n    private void notifyRtcpListenersOfTimeout() {\n        for (RtcpEventListener listener : listeners) {\n            listener.connectionTimeout();\n        }\n    }\n\n    /**\n     * Returns the statistics of RTCP reception\n     * \n     * @return Statistics\n     */\n    public RtcpStatisticsReceiver getRtcpReceptionStats() {\n        return stats;\n    }\n\n    /**\n     * Returns the DatagramConnection of RTCP\n     * \n     * @return DatagramConnection\n     */\n    public DatagramConnection getConnection() {\n        return datagramConnection;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpPacketTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.IOException;\nimport java.util.Random;\nimport java.util.Vector;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.AndroidDatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.DatagramConnection;\n\n/**\n * RTCP packet transmitter\n * \n * @author jexa7410\n */\npublic class RtcpPacketTransmitter extends Thread {\n    /**\n     * Remote address\n     */\n    private String remoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int remotePort;\n\n    /**\n     * Statistics\n     */\n    private RtcpStatisticsTransmitter stats = new RtcpStatisticsTransmitter();\n\n    /**\n     * Datagram connection\n     */\n    public DatagramConnection datagramConnection = null;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * Flag used to determine when to terminate after sending a BYE\n     */\n    private boolean waitingForByeBackoff = false;\n\n    /**\n     * Flag used to properly close\n     */\n    private boolean closed = false;\n\n    /**\n     * Random value\n     */\n    private Random rand = new Random();\n\n    /**\n     * Constructor\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession the RTCP session\n     * @throws IOException\n     */\n    public RtcpPacketTransmitter(String address, int port, RtcpSession rtcpSession)\n            throws IOException {\n        super();\n\n        this.remoteAddress = address;\n        this.remotePort = port;\n        this.rtcpSession = rtcpSession;\n\n        // Open the connection\n        datagramConnection = new AndroidDatagramConnection();\n        datagramConnection.open();\n    }\n\n    /**\n     * Constructor - used for SYMETRIC_RTP\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession the RTCP session\n     * @param DatagramConnection datagram connection of the RtpPacketReceiver\n     * @throws IOException\n     */\n    public RtcpPacketTransmitter(String address, int port, RtcpSession rtcpSession,\n            DatagramConnection connection) throws IOException {\n        super();\n\n        this.remoteAddress = address;\n        this.remotePort = port;\n        this.rtcpSession = rtcpSession;\n\n        // Open the connection\n        if (connection != null) {\n            this.datagramConnection = connection;\n        } else {\n            this.datagramConnection = new AndroidDatagramConnection();\n            this.datagramConnection.open();\n        }\n    }\n\n    /**\n     * Close the transmitter\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (closed) {\n            return;\n        }\n\n        rtcpSession.isByeRequested = true;\n        closed = true;\n\n        // Close the datagram connection\n        if (datagramConnection != null) {\n            datagramConnection.close();\n        }\n\n        // If the method start() was never invoked this Thread will be on NEW\n        // state and the resources won't be freed. We need to force the start()\n        // to allow it to die gracefully\n        if (this.getState() == State.NEW) {\n            this.start();\n        }\n\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        if (closed) {\n            return;\n        }\n\n        try {\n            // Send a SDES packet\n            sendSdesPacket();\n\n            boolean terminate = false;\n            while (!terminate) {\n                try {\n                    // Wait the RTCP report interval.\n                    Thread.sleep((long) rtcpSession.getReportInterval());\n\n                    // Right time to send a RTCP packet or reschedule ?\n                    if ((rtcpSession.timeOfLastRTCPSent + rtcpSession.T) <= rtcpSession\n                            .currentTime()) {\n                        // We know that it is time to send a RTCP packet, is it\n                        // a BYE packet\n                        if ((rtcpSession.isByeRequested && waitingForByeBackoff)) {\n                            // If it is bye then did we ever sent anything\n                            if (rtcpSession.timeOfLastRTCPSent > 0\n                                    && rtcpSession.timeOfLastRTPSent > 0) {\n                                rtcpSession.getMySource().activeSender = false;\n                                rtcpSession.timeOfLastRTCPSent = rtcpSession.currentTime();\n                            } else {\n                                // We never sent anything and we have to quit :(\n                                // do not send BYE\n                                terminate = true;\n                            }\n                        } else {\n                            if (!closed) {\n                                transmit(assembleRtcpPacket());\n                                if (rtcpSession.isByeRequested && !waitingForByeBackoff) {\n                                    // We have sent a BYE packet, so terminate\n                                    terminate = true;\n                                } else {\n                                    rtcpSession.timeOfLastRTCPSent = rtcpSession.currentTime();\n                                }\n                            } else {\n                                terminate = true;\n                            }\n\n                        }\n                    }\n                    waitingForByeBackoff = false;\n\n                } catch (InterruptedException e) {\n                    waitingForByeBackoff = true;\n                    rtcpSession.isByeRequested = true;\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * assemble RTCP packet\n     */\n    private byte[] assembleRtcpPacket() {\n        byte data[] = new byte[0];\n\n        // Sender or receiver packet\n        RtpSource s = rtcpSession.getMySource();\n        if ((s.activeSender) && (rtcpSession.timeOfLastRTCPSent < rtcpSession.timeOfLastRTPSent)) {\n            data = RtcpPacketUtils.append(data, assembleSenderReportPacket());\n        } else {\n            data = RtcpPacketUtils.append(data, assembleReceiverReportPacket());\n        }\n\n        // SDES packets\n        Vector<RtcpSdesPacket> repvec = makereports();\n        for (int i = 0; i < repvec.size(); i++) {\n            if (repvec.elementAt(i).data != null)\n                data = RtcpPacketUtils.append(data, repvec.elementAt(i).data);\n        }\n\n        // BYE packet\n        RtcpByePacket byepacket = null;\n        if (rtcpSession.isByeRequested) {\n            int ssrc[] = {\n                    rtcpSession.SSRC\n            };\n            byepacket = new RtcpByePacket(ssrc, null);\n            data = RtcpPacketUtils.append(data, byepacket.data);\n        }\n\n        return data;\n    }\n\n    /**\n     * assemble RTCP SR packet\n     * \n     * @return packet data\n     */\n    private byte[] assembleSenderReportPacket() {\n        final int FIXED_HEADER_SIZE = 4;\n        byte V_P_RC = (byte) ((RtcpPacket.VERSION << 6) | (RtcpPacket.PADDING << 5) | (0x00));\n        byte ss[] = RtcpPacketUtils.longToBytes(rtcpSession.SSRC, 4);\n        byte PT[] = RtcpPacketUtils.longToBytes((long) RtcpPacket.RTCP_SR, 1);\n        byte NTP_TimeStamp[] = RtcpPacketUtils.longToBytes(rtcpSession.currentTime(), 8);\n        short randomOffset = (short) Math.abs(rand.nextInt() & 0x000000FF);\n        byte RTP_TimeStamp[] = RtcpPacketUtils.longToBytes((long) rtcpSession.tc\n                + randomOffset, 4);\n        byte SenderPacketCount[] = RtcpPacketUtils.longToBytes(rtcpSession.packetCount, 4);\n        byte SenderOctetCount[] = RtcpPacketUtils.longToBytes(rtcpSession.octetCount, 4);\n\n        // report block\n        byte receptionReportBlocks[] = new byte[0];\n        receptionReportBlocks = RtcpPacketUtils.append(receptionReportBlocks,\n                assembleRTCPReceptionReport());\n        byte receptionReports = (byte) (receptionReportBlocks.length / 24);\n        V_P_RC = (byte) (V_P_RC | (byte) (receptionReports & 0x1F));\n\n        // Length is 32 bit words contained in the packet -1\n        byte length[] = RtcpPacketUtils.longToBytes((FIXED_HEADER_SIZE + ss.length\n                + NTP_TimeStamp.length + RTP_TimeStamp.length + SenderPacketCount.length\n                + SenderOctetCount.length + receptionReportBlocks.length) / 4 - 1, 2);\n\n        // Build RTCP SR Packet\n        byte rtcpSRPacket[] = new byte[1];\n        rtcpSRPacket[0] = V_P_RC;\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, PT);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, length);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, ss);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, NTP_TimeStamp);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, RTP_TimeStamp);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, SenderPacketCount);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, SenderOctetCount);\n        rtcpSRPacket = RtcpPacketUtils.append(rtcpSRPacket, receptionReportBlocks);\n\n        return rtcpSRPacket;\n    }\n\n    /**\n     * assemble RTCP RR packet\n     * \n     * @return packet data\n     */\n    private byte[] assembleReceiverReportPacket() {\n        final int FIXED_HEADER_SIZE = 4;\n        byte V_P_RC = (byte) ((RtcpPacket.VERSION << 6) | (RtcpPacket.PADDING << 5) | (0x00));\n        byte ss[] = RtcpPacketUtils.longToBytes(rtcpSession.SSRC, 4);\n        byte PT[] = RtcpPacketUtils.longToBytes((long) RtcpPacket.RTCP_RR, 1);\n\n        // report block\n        byte receptionReportBlocks[] = new byte[0];\n        receptionReportBlocks = RtcpPacketUtils.append(receptionReportBlocks,\n                assembleRTCPReceptionReport());\n        byte receptionReports = (byte) (receptionReportBlocks.length / 24);\n        V_P_RC = (byte) (V_P_RC | (byte) (receptionReports & 0x1F));\n\n        byte length[] = RtcpPacketUtils.longToBytes(\n                (FIXED_HEADER_SIZE + ss.length + receptionReportBlocks.length) / 4 - 1, 2);\n\n        // Build RTCP RR Packet\n        byte RRPacket[] = new byte[1];\n        RRPacket[0] = V_P_RC;\n        RRPacket = RtcpPacketUtils.append(RRPacket, PT);\n        RRPacket = RtcpPacketUtils.append(RRPacket, length);\n        RRPacket = RtcpPacketUtils.append(RRPacket, ss);\n        RRPacket = RtcpPacketUtils.append(RRPacket, receptionReportBlocks);\n        return RRPacket;\n    }\n\n    /**\n     * assemble RTCP Reception report block\n     * \n     * @return report data\n     */\n    private byte[] assembleRTCPReceptionReport() {\n        byte reportBlock[] = new byte[0];\n        RtpSource source = rtcpSession.getMySource();\n\n        ReceptionReport rr = source.generateReceptionReport();\n        byte SSRC[] = RtcpPacketUtils.longToBytes((long) rr.getSsrc(), 4);\n        byte fraction_lost[] = RtcpPacketUtils.longToBytes((long) rr.getFractionLost(), 1);\n        byte pkts_lost[] = RtcpPacketUtils.longToBytes(\n                (long) rr.getCumulativeNumberOfPacketsLost(), 3);\n        byte last_seq[] = RtcpPacketUtils.longToBytes(\n                (long) rr.getExtendedHighestSequenceNumberReceived(), 4);\n        byte jitter[] = RtcpPacketUtils.longToBytes((long) rr.getInterarrivalJitter(), 4);\n        byte lst[] = RtcpPacketUtils.longToBytes((long) rr.getLastSenderReport(), 4);\n        byte dlsr[] = RtcpPacketUtils.longToBytes((long) rr.getDelaySinceLastSenderReport(), 4);\n\n        reportBlock = RtcpPacketUtils.append(reportBlock, SSRC);\n        reportBlock = RtcpPacketUtils.append(reportBlock, fraction_lost);\n        reportBlock = RtcpPacketUtils.append(reportBlock, pkts_lost);\n        reportBlock = RtcpPacketUtils.append(reportBlock, last_seq);\n        reportBlock = RtcpPacketUtils.append(reportBlock, jitter);\n        reportBlock = RtcpPacketUtils.append(reportBlock, lst);\n        reportBlock = RtcpPacketUtils.append(reportBlock, dlsr);\n\n        return reportBlock;\n    }\n\n    /**\n     * Send a BYE packet\n     */\n    public void sendByePacket() {\n        // Create a report\n        Vector<RtcpSdesPacket> repvec = makereports();\n        RtcpPacket[] packets = new RtcpPacket[repvec.size() + 1];\n        repvec.copyInto(packets);\n\n        // Create a RTCP bye packet\n        int ssrc[] = {\n                rtcpSession.SSRC\n        };\n        RtcpByePacket rtcpbyepacket = new RtcpByePacket(ssrc, null);\n        packets[packets.length - 1] = rtcpbyepacket;\n\n        // Create a RTCP compound packet\n        RtcpCompoundPacket cp = new RtcpCompoundPacket(packets);\n\n        rtcpSession.getMySource().activeSender = false;\n\n        // Send the RTCP packet\n        transmit(cp);\n    }\n\n    /**\n     * Generate a RTCP report\n     * \n     * @return Vector\n     */\n    public Vector<RtcpSdesPacket> makereports() {\n        Vector<RtcpSdesPacket> packets = new Vector<RtcpSdesPacket>();\n\n        RtcpSdesPacket rtcpsdespacket = new RtcpSdesPacket(new RtcpSdesBlock[1]);\n        rtcpsdespacket.sdes[0] = new RtcpSdesBlock();\n        rtcpsdespacket.sdes[0].ssrc = rtcpSession.SSRC;\n\n        Vector<RtcpSdesItem> vector = new Vector<RtcpSdesItem>();\n        vector.addElement(new RtcpSdesItem(1, RtpSource.CNAME));\n        rtcpsdespacket.sdes[0].items = new RtcpSdesItem[vector.size()];\n        vector.copyInto(rtcpsdespacket.sdes[0].items);\n\n        packets.addElement(rtcpsdespacket);\n        return packets;\n    }\n\n    /**\n     * Transmit a RTCP compound packet to the remote destination\n     * \n     * @param packet Compound packet to be sent\n     */\n    private void transmit(RtcpCompoundPacket packet) {\n        // Prepare data to be sent\n        byte[] data = packet.data;\n        if (packet.offset > 0) {\n            System.arraycopy(data, packet.offset,\n                    data = new byte[packet.length], 0, packet.length);\n        }\n\n        // Update statistics\n        stats.numBytes += packet.length;\n        stats.numPackets++;\n        rtcpSession.updateavgrtcpsize(packet.length);\n        rtcpSession.timeOfLastRTCPSent = rtcpSession.currentTime();\n        // Send data over UDP\n        try {\n            datagramConnection.send(remoteAddress, remotePort, data);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Transmit a RTCP compound packet to the remote destination\n     * \n     * @param packet Compound packet to be sent\n     */\n    private void transmit(byte packet[]) {\n        // Update statistics\n        stats.numBytes += packet.length;\n        stats.numPackets++;\n        rtcpSession.updateavgrtcpsize(packet.length);\n        rtcpSession.timeOfLastRTCPSent = rtcpSession.currentTime();\n        // Send data over UDP\n        try {\n            datagramConnection.send(remoteAddress, remotePort, packet);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Returns the statistics of RTCP transmission\n     * \n     * @return Statistics\n     */\n    public RtcpStatisticsTransmitter getStatistics() {\n        return stats;\n    }\n\n    /**\n     * Send a SDES packet\n     */\n    private void sendSdesPacket() {\n        // Create a report\n        Vector<RtcpSdesPacket> repvec = makereports();\n        RtcpPacket packets[] = new RtcpPacket[repvec.size()];\n        repvec.copyInto(packets);\n\n        // Create a RTCP compound packet\n        RtcpCompoundPacket cp = new RtcpCompoundPacket(packets);\n\n        // Assemble the RTCP packet\n        int i = cp.calcLength();\n        cp.assemble(i, false);\n\n        // Send the RTCP packet\n        transmit(cp);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpPacketUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP utils.\n * \n * @author hlxn7157\n */\npublic class RtcpPacketUtils {\n\n    /**\n     * Convert 64 bit long to n bytes.\n     * \n     * @param data data\n     * @param n desired number of bytes to convert the long to.\n     * @return buffer\n     */\n    public static byte[] longToBytes(long data, int n) {\n        byte buf[] = new byte[n];\n        for (int i = n - 1; i >= 0; i--) {\n            buf[i] = (byte) data;\n            data = data >> 8;\n        }\n        return buf;\n    }\n\n    /**\n     * Append two byte arrays.\n     * \n     * @param pck1 first packet.\n     * @param pck2 second packet.\n     * @return concatenated packet.\n     */\n    public static byte[] append(byte[] pck1, byte[] pck2) {\n        byte packet[] = new byte[pck1.length + pck2.length];\n        for (int i = 0; i < pck1.length; i++)\n            packet[i] = pck1[i];\n        for (int i = 0; i < pck2.length; i++)\n            packet[i + pck1.length] = pck2[i];\n        return packet;\n    }\n};\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpReceiverReportPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RCTP RR packet\n * \n * @author jexa7410\n */\npublic class RtcpReceiverReportPacket extends RtcpPacket {\n    public int ssrc;\n    public RtcpReport[] reports;\n\n    public RtcpReceiverReportPacket(int i, RtcpReport[] rtcpreportblocks) {\n        ssrc = i;\n        reports = rtcpreportblocks;\n        if (rtcpreportblocks.length > 31)\n            throw new IllegalArgumentException(\"Too many reports\");\n    }\n\n    public RtcpReceiverReportPacket(RtcpPacket rtcppacket) {\n        super(rtcppacket);\n        type = 201;\n    }\n\n    public void assemble(DataOutputStream dataoutputstream) throws IOException {\n        dataoutputstream.writeByte(128 + reports.length);\n        dataoutputstream.writeByte(201);\n        dataoutputstream.writeShort(1 + reports.length * 6);\n        dataoutputstream.writeInt(ssrc);\n        for (int i = 0; i < reports.length; i++) {\n            dataoutputstream.writeInt(reports[i].ssrc);\n            dataoutputstream.writeInt((reports[i].packetslost & 0xffffff)\n                    + (reports[i].fractionlost << 24));\n            dataoutputstream.writeInt((int) reports[i].lastseq);\n            dataoutputstream.writeInt(reports[i].jitter);\n            dataoutputstream.writeInt((int) reports[i].lsr);\n            dataoutputstream.writeInt((int) reports[i].dlsr);\n        }\n    }\n\n    public int calcLength() {\n        return 8 + reports.length * 24;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpReport.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP report\n * \n * @author jexa7410\n */\npublic class RtcpReport {\n    public int ssrc;\n    public int fractionlost;\n    public int packetslost;\n    public long lastseq;\n    public int jitter;\n    public long lsr;\n    public long dlsr;\n    public long receiptTime;\n\n    public long getDLSR() {\n        return dlsr;\n    }\n\n    public int getFractionLost() {\n        return fractionlost;\n    }\n\n    public long getJitter() {\n        return (long) jitter;\n    }\n\n    public long getLSR() {\n        return lsr;\n    }\n\n    public long getNumLost() {\n        return (long) packetslost;\n    }\n\n    public long getSSRC() {\n        return (long) ssrc;\n    }\n\n    public long getXtndSeqNum() {\n        return lastseq;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpSdesBlock.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RCTP SDES block\n * \n * @author jexa7410\n */\npublic class RtcpSdesBlock {\n    public int ssrc;\n\n    public RtcpSdesItem[] items;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpSdesItem.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RCTP SDES item\n * \n * @author jexa7410\n */\npublic class RtcpSdesItem {\n    public int type;\n    public byte[] data;\n\n    public RtcpSdesItem() {\n    }\n\n    public RtcpSdesItem(int i, String string) {\n        type = i;\n        data = string.getBytes();\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpSdesPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RCTP SDES packet\n * \n * @author jexa7410\n */\npublic class RtcpSdesPacket extends RtcpPacket {\n\n    public RtcpSdesBlock sdes[];\n\n    public RtcpSdesPacket(RtcpPacket parent) {\n        super(parent);\n        super.type = 202;\n    }\n\n    public RtcpSdesPacket(RtcpSdesBlock sdes[]) {\n        this.sdes = sdes;\n        if (sdes.length > 31) {\n            throw new IllegalArgumentException(\"Too many SDESs\");\n        } else {\n            return;\n        }\n    }\n\n    public int calcLength() {\n        int len = 4;\n        for (int i = 0; i < sdes.length; i++) {\n            int sublen = 5;\n            for (int j = 0; j < sdes[i].items.length; j++) {\n                sublen += 2 + sdes[i].items[j].data.length;\n            }\n\n            sublen = sublen + 3 & -4;\n            len += sublen;\n        }\n\n        return len;\n    }\n\n    public void assemble(DataOutputStream out) throws IOException {\n        out.writeByte(128 + sdes.length);\n        out.writeByte(202);\n        out.writeShort(calcLength() - 4 >> 2);\n        for (int i = 0; i < sdes.length; i++) {\n            out.writeInt(sdes[i].ssrc);\n            int sublen = 0;\n            for (int j = 0; j < sdes[i].items.length; j++) {\n                out.writeByte(sdes[i].items[j].type);\n                out.writeByte(sdes[i].items[j].data.length);\n                out.write(sdes[i].items[j].data);\n                sublen += 2 + sdes[i].items[j].data.length;\n            }\n\n            for (int j = (sublen + 4 & -4) - sublen; j > 0; j--) {\n                out.writeByte(0);\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpSenderReportPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\n/**\n * RCTP SR packet\n * \n * @author jexa7410\n */\npublic class RtcpSenderReportPacket extends RtcpPacket {\n    public int ssrc;\n    public long ntptimestampmsw;\n    public long ntptimestamplsw;\n    public long rtptimestamp;\n    public long packetcount;\n    public long octetcount;\n    public RtcpReport[] reports;\n\n    public RtcpSenderReportPacket(int i, RtcpReport[] rtcpreportblocks) {\n        ssrc = i;\n        reports = rtcpreportblocks;\n        if (rtcpreportblocks.length > 31)\n            throw new IllegalArgumentException(\"Too many reports\");\n    }\n\n    public RtcpSenderReportPacket(RtcpPacket rtcppacket) {\n        super(rtcppacket);\n        type = 200;\n    }\n\n    public void assemble(DataOutputStream dataoutputstream) throws IOException {\n        dataoutputstream.writeByte(128 + reports.length);\n        dataoutputstream.writeByte(200);\n        dataoutputstream.writeShort(6 + reports.length * 6);\n        dataoutputstream.writeInt(ssrc);\n        dataoutputstream.writeInt((int) ntptimestampmsw);\n        dataoutputstream.writeInt((int) ntptimestamplsw);\n        dataoutputstream.writeInt((int) rtptimestamp);\n        dataoutputstream.writeInt((int) packetcount);\n        dataoutputstream.writeInt((int) octetcount);\n        for (int i = 0; i < reports.length; i++) {\n            dataoutputstream.writeInt(reports[i].ssrc);\n            dataoutputstream.writeInt((reports[i].packetslost & 0xffffff)\n                    + (reports[i].fractionlost << 24));\n            dataoutputstream.writeInt((int) reports[i].lastseq);\n            dataoutputstream.writeInt(reports[i].jitter);\n            dataoutputstream.writeInt((int) reports[i].lsr);\n            dataoutputstream.writeInt((int) reports[i].dlsr);\n        }\n    }\n\n    public int calcLength() {\n        return 28 + reports.length * 24;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpSession.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.util.Random;\n\n/**\n * RTCP Session Information\n * \n * @author hlxn7157\n */\npublic class RtcpSession {\n\n    /**\n     * Default minimum time between RTCP message (ms)\n     */\n    private static final int DEFAULT_RTCP_MIN_TIME = 5000;\n\n    /**\n     * Fraction of RTCP sender messages\n     */\n    private static final double RTCP_SENDER_BW_FRACTION = 0.25;\n\n    /**\n     * Fraction of RTCP receiver messages\n     */\n    private static final double RTCP_RCVR_BW_FRACTION = 0.75;\n\n    /**\n     * Bandwidth\n     */\n    private double bandwidth;\n\n    /**\n     * RTCP bandwidth\n     */\n    private double rtcpBandwidth;\n\n    /**\n     * Minimum time between RTCP message (ms)\n     */\n    private int rtcp_min_time = DEFAULT_RTCP_MIN_TIME;\n\n    /**\n     * RTCP average packet size\n     */\n    private int avgrtcpsize;\n\n    /**\n     * Number of members\n     */\n    private int members;\n\n    /**\n     * Number of senders\n     */\n    private int senders;\n\n    /**\n     * Initial state\n     */\n    private boolean initial;\n\n    /**\n     * Is a sender\n     */\n    private boolean isSender;\n\n    /**\n     * True if session instantiator requested a close.\n     */\n    public boolean isByeRequested = false;\n\n    /**\n     * Time this source last sent an RTP Packet\n     */\n    public double timeOfLastRTPSent = 0;\n\n    /**\n     * The last time an RTCP packet was transmitted.\n     */\n    public double timeOfLastRTCPSent = 0;\n\n    /**\n     * The startup time for the application.\n     */\n    public long appStartupTime;\n\n    /**\n     * Ramdomized time interval for next RTCP transmission.\n     */\n    public double T = 0;\n\n    /**\n     * Synchronization Source identifier for this source.\n     */\n    public int SSRC;\n\n    /**\n     * RTP Source\n     */\n    private RtpSource rtpSource;\n\n    /**\n     * The current time.\n     */\n    public double tc = 0;\n\n    /**\n     * Total Number of RTP data packets sent out by this source since starting transmission.\n     */\n    public long packetCount;\n\n    /**\n     * Total Number of payload octets (i.e not including header or padding) sent out by this source\n     * since starting transmission.\n     */\n    public long octetCount;\n\n    /**\n     * Initialize the Random Number Generator.\n     */\n    private Random rnd = new Random();\n\n    /**\n     * Constructor.\n     * \n     * @param isSender is sender\n     * @param bandwidth bandwidth (can set 16000 (16kops 128kbps))\n     */\n    public RtcpSession(boolean isSender, double bandwidth) {\n        this.isSender = isSender;\n        members = 2;\n        senders = 1;\n        this.bandwidth = bandwidth;\n        rtcpBandwidth = 0.05 * bandwidth;\n        avgrtcpsize = 128;\n        initial = true;\n\n        // Initialize the Session level variables\n        appStartupTime = currentTime();\n        timeOfLastRTCPSent = appStartupTime;\n        tc = appStartupTime;\n        SSRC = rnd.nextInt();\n        packetCount = 0;\n        octetCount = 0;\n\n        // Init RTP source\n        rtpSource = new RtpSource(SSRC);\n    }\n\n    /**\n     * Setter of members\n     * \n     * @param members no of members\n     */\n    public void setMembers(int members) {\n        this.members = members;\n    }\n\n    /**\n     * Setter of senders\n     * \n     * @param senders no of senders\n     */\n    public void setSenders(int senders) {\n        this.senders = senders;\n    }\n\n    /**\n     * Get the interval of RTCP message\n     * \n     * @return interval\n     */\n    public double getReportInterval() {\n        // Interval\n        double t;\n        // no. of members for computation\n        double n;\n\n        // initial half the min delay for quicker notification\n        if (initial) {\n            initial = false;\n            rtcp_min_time /= 2;\n        }\n\n        // If there were active senders, give them at least a minimum share of\n        // the RTCP bandwidth. Otherwise all participants share the RTCP\n        // bandwidth equally.\n        n = members;\n        if (senders > 0 && senders < members * RTCP_SENDER_BW_FRACTION) {\n            if (isSender) {\n                rtcpBandwidth *= RTCP_SENDER_BW_FRACTION;\n                n = senders;\n            } else {\n                rtcpBandwidth *= RTCP_RCVR_BW_FRACTION;\n                n -= senders;\n            }\n        }\n\n        // get interval\n        t = (double) avgrtcpsize * n / bandwidth;\n        if (t < rtcp_min_time)\n            t = rtcp_min_time;\n\n        // add noise to avoid traffic bursts\n        t *= (Math.random() + 0.5);\n\n        T = t;\n        return t;\n    }\n\n    /**\n     * Update the average RTCP packet size\n     * \n     * @param size\n     */\n    public void updateavgrtcpsize(int size) {\n        avgrtcpsize = (int) (0.0625 * (double) size + 0.9375 * (double) avgrtcpsize);\n    }\n\n    /**\n     * Returns a self source object.\n     * \n     * @return My source object.\n     */\n    public RtpSource getMySource() {\n        return rtpSource;\n    }\n\n    /**\n     * Returns current time from the Date().getTime() function.\n     * \n     * @return The current time.\n     */\n    public long currentTime() {\n        tc = System.currentTimeMillis();\n        return (long) tc;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpStatisticsReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP packet statistics receiver\n * \n * @author jexa7410\n */\npublic class RtcpStatisticsReceiver {\n    /**\n     * Number of RTCP packets received\n     */\n    public int numRtcpPkts = 0;\n\n    /**\n     * Number of RTCP bytes received\n     */\n    public int numRtcpBytes = 0;\n\n    /**\n     * Number of RTCP SR packets received\n     */\n    public int numSrPkts = 0;\n\n    /**\n     * Number of bad RTCP packets received\n     */\n    public int numBadRtcpPkts = 0;\n\n    /**\n     * Number of unknown RTCP packets received\n     */\n    public int numUnknownTypes = 0;\n\n    /**\n     * Number of malformed RTCP packets received\n     */\n    public int numMalformedRtcpPkts = 0;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtcpStatisticsTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTCP packet statistics transmitter\n * \n * @author jexa7410\n */\npublic class RtcpStatisticsTransmitter {\n    /**\n     * Total number of packets sent\n     */\n    public int numPackets = 0;\n\n    /**\n     * Total number of bytes sent\n     */\n    public int numBytes = 0;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpExtensionHeader.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * Represent a RTP extension header\n * \n * @author Deutsche Telekom\n */\npublic class RtpExtensionHeader implements Iterable<RtpExtensionHeader.ExtensionElement> {\n    /**\n     * Allowed extension header id for RCS video orientation\n     */\n    public static final int RTP_EXTENSION_HEADER_ID = ((0xbe << 8) | 0xde);\n\n    /**\n     * elements list\n     */\n    private List<RtpExtensionHeader.ExtensionElement> elements = new ArrayList<RtpExtensionHeader.ExtensionElement>(\n            0);\n\n    /**\n     * Default constructor\n     */\n    public RtpExtensionHeader() {\n    }\n\n    /**\n     * Add header element.\n     * \n     * @param id Element id\n     * @param data Element data\n     */\n    public void addElement(int id, byte[] data) {\n        elements.add(new ExtensionElement(id, data));\n    }\n\n    /**\n     * Get ExtensionHeader element by id.\n     * \n     * @param id ID to search for\n     * @return Element data\n     */\n    public ExtensionElement getElementById(int id) {\n        for (ExtensionElement element : elements) {\n            if (element.id == id) {\n                return element;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Counts the number of elements in the header\n     * \n     * @return Number of elements\n     */\n    public int elementsCount() {\n        return elements.size();\n    }\n\n    @Override\n    public Iterator<ExtensionElement> iterator() {\n        return this.elements.iterator();\n    }\n\n    /**\n     * Extension Header Element\n     */\n    public static class ExtensionElement {\n        public final int id;\n        public final byte[] data;\n\n        public ExtensionElement(int id, byte[] data) {\n            this.id = id;\n            this.data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpPacket.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Packet;\n\n/**\n * Abstract RTP packet\n * \n * @author jexa7410\n * @author Deutsche Telekom\n */\npublic class RtpPacket extends Packet {\n    public Packet base;\n    public int marker;\n    public int payloadType;\n    public int seqnum;\n    public long timestamp;\n    public int ssrc;\n    public int payloadoffset;\n    public int payloadlength;\n    public boolean extension;\n    public RtpExtensionHeader extensionHeader;\n\n    public RtpPacket() {\n        super();\n    }\n\n    public RtpPacket(Packet packet) {\n        super(packet);\n\n        base = packet;\n    }\n\n    public void assemble(int length) throws IOException {\n        this.length = length;\n        this.offset = 0;\n\n        ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(length);\n        DataOutputStream dataoutputstream = new DataOutputStream(bytearrayoutputstream);\n        if (extension) {\n            dataoutputstream.writeByte(144);\n        } else {\n            dataoutputstream.writeByte(128);\n        }\n\n        int i = payloadType;\n        if (marker == 1) {\n            i = payloadType | 0x80;\n        }\n        dataoutputstream.writeByte((byte) i);\n        dataoutputstream.writeShort(seqnum);\n        dataoutputstream.writeInt((int) timestamp);\n        dataoutputstream.writeInt(ssrc);\n\n        if (extension && extensionHeader != null) {\n            // Write extension header id\n            dataoutputstream.writeShort(RtpExtensionHeader.RTP_EXTENSION_HEADER_ID);\n            // Write extension header length\n            dataoutputstream.writeShort(extensionHeader.elementsCount());\n            // Write extension element. For now we will only support the orientation element\n            for (RtpExtensionHeader.ExtensionElement element : extensionHeader) {\n                int orientationElement = (((((element.id & 0xff) << 4) | ((element.data.length - 1) & 0xff)) << 8)\n                        | (element.data[0] & 0xff)) << 16;\n                dataoutputstream.writeInt(orientationElement);\n            }\n        }\n        dataoutputstream.write(base.data, base.offset, base.length);\n        data = bytearrayoutputstream.toByteArray();\n    }\n\n    public int calcLength() {\n        return payloadlength + 12;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpPacketReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.IOException;\nimport java.net.SocketTimeoutException;\nimport java.util.concurrent.TimeoutException;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.AndroidDatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.DatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.FifoBuffer;\n\n/**\n * RTP packet receiver\n * \n * @author jexa7410\n */\npublic class RtpPacketReceiver extends Thread {\n    /**\n     * Statistics\n     */\n    private RtpStatisticsReceiver stats = new RtpStatisticsReceiver();\n\n    /**\n     * Datagram connection\n     */\n    public DatagramConnection datagramConnection = null;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * Signals that connection is closed\n     */\n    private boolean isClosed = false;\n\n    /**\n     * Fifo buffer for received packet\n     */\n    private FifoBuffer fifo = new FifoBuffer();\n\n    /**\n     * Max size for the fifo\n     */\n    private static final int FIFO_MAX_NUMBER = 100;\n\n    /**\n     * Number of element to clean in the fifo\n     */\n    private static final int FIFO_CLEAN_NUMBER = 20;\n\n    /**\n     * Last sequence number\n     */\n    private int lastSeqnum = 0;\n\n    /**\n     * timeout\n     */\n    private int timeout = 0;\n\n    /**\n     * Constructor\n     * \n     * @param port Listenning port\n     * @param rtcpSession\n     * @param socketTimeout\n     * @throws IOException\n     */\n    public RtpPacketReceiver(int port, RtcpSession rtcpSession, int socketTimeout)\n            throws IOException {\n        super();\n\n        this.rtcpSession = rtcpSession;\n        this.timeout = socketTimeout;\n        // Create the UDP server\n        datagramConnection = new AndroidDatagramConnection(socketTimeout);\n        datagramConnection.open(port);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param port Listenning port\n     * @param rtcpSession\n     * @throws IOException\n     */\n    public RtpPacketReceiver(int port, RtcpSession rtcpSession) throws IOException {\n        this(port, rtcpSession, 0);\n    }\n\n    /**\n     * Close the receiver\n     */\n    public void close() {\n        // Interrupt the current thread processing\n        try {\n            interrupt();\n        } catch (Exception e) {\n            // Nothing to do\n        }\n\n        // Close the datagram connection\n        if (datagramConnection != null) {\n            try {\n                isClosed = true;\n                datagramConnection.close();\n            } catch (Exception e) {\n            }\n            datagramConnection = null;\n        }\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        try {\n            while (datagramConnection != null) {\n                // Wait a new packet\n                byte[] data = datagramConnection.receive();\n\n                if (data.length >= 12) {\n                    // Drop empty packet (payload 20)\n                    int payloadType = (byte) ((data[1] & 0xff) & 0x7f);\n                    if (payloadType != 20) {\n                        // Drop too old packet\n                        int seqnum = (char) ((data[2] << 8) | (data[3] & 0xff));\n                        if (seqnum > lastSeqnum - 10) {\n                            // Clean the FIFO if full\n                            if (fifo.size() >= FIFO_MAX_NUMBER) {\n                                fifo.clean(FIFO_CLEAN_NUMBER);\n                            }\n                            fifo.addObject(data);\n                            lastSeqnum = seqnum;\n                        } else {\n                            stats.numBadRtpPkts++;\n                        }\n                    }\n                }\n            }\n        } catch (SocketTimeoutException ex) {\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Read a RTP packet (blocking method)\n     * \n     * @return RTP packet\n     */\n    public RtpPacket readRtpPacket() throws TimeoutException {\n        try {\n            // Get a new packet in FIFO\n            byte[] data = (byte[]) fifo.getObject(timeout);\n            if (data == null) {\n                throw new TimeoutException();\n            }\n\n            // Parse the RTP packet\n            RtpPacket pkt = parseRtpPacket(data);\n\n            if (pkt != null) {\n                // Update statistics\n                stats.numPackets++;\n                stats.numBytes += data.length;\n\n                RtpSource s = rtcpSession.getMySource();\n                s.setSsrc(pkt.ssrc);\n                s.activeSender = true;\n                s.receiveRtpPacket(pkt);\n                pkt.seqnum = s.generateExtendedSequenceNumber(pkt.seqnum);\n\n                return pkt;\n            } else {\n                return readRtpPacket();\n            }\n\n        } catch (Exception e) {\n            if (!isClosed) {\n                // if (logger.isActivated()) {\n                // logger.error(\"Can't parse the RTP packet\", e);\n                // }\n                stats.numBadRtpPkts++;\n            }\n            return null;\n        }\n    }\n\n    /**\n     * Parse the RTP packet\n     * \n     * @param data RTP packet not yet parsed\n     * @return RTP packet\n     */\n    private RtpPacket parseRtpPacket(byte[] data) {\n        RtpPacket packet = new RtpPacket();\n        try {\n            // Read RTP packet length\n            packet.length = data.length;\n\n            // Set received timestamp\n            packet.receivedAt = System.currentTimeMillis();\n\n            // Read extension bit\n            packet.extension = (data[0] & 0x10) > 0;\n\n            // Read marker\n            if ((byte) ((data[1] & 0xff) & 0x80) == (byte) 0x80) {\n                packet.marker = 1;\n            } else {\n                packet.marker = 0;\n            }\n\n            // Read payload type\n            packet.payloadType = (byte) ((data[1] & 0xff) & 0x7f);\n\n            // Read sequence number (it's a unsigned 16 bit value. Because Java only supports\n            // signed values for int and short we use char to do the correct conversion.)\n            packet.seqnum = (char) ((data[2] << 8) | (data[3] & 0xff));\n\n            // Read timestamp\n            packet.timestamp = (((data[4] & 0xff) << 24) | ((data[5] & 0xff) << 16)\n                    | ((data[6] & 0xff) << 8) | (data[7] & 0xff));\n\n            // Read SSRC\n            packet.ssrc = (((data[8] & 0xff) << 24) | ((data[9] & 0xff) << 16)\n                    | ((data[10] & 0xff) << 8) | (data[11] & 0xff));\n\n            // Extract the extension header\n            if (packet.extension) {\n                int dataId = 11;\n                int extensionHeaderId = ((data[++dataId] & 0xff) << 8) | (data[++dataId] & 0xff);\n                int length = ((data[++dataId] & 0xff) << 8) | (data[++dataId] & 0xff);\n\n                if (extensionHeaderId == RtpExtensionHeader.RTP_EXTENSION_HEADER_ID) {\n                    extractExtensionHeader(data, length, dataId, packet);\n                }\n\n                // increment payload offset = RtpHeader size (12) + Extension Header ID (2) + Header\n                // Length (2) +\n                // elements * 4 (32 bits each) + 1 (to set at correct index)\n                packet.payloadoffset = 16 + length * 4;\n            } else {\n                packet.payloadoffset = 12;\n            }\n            packet.payloadlength = packet.length - packet.payloadoffset;\n            packet.data = new byte[packet.payloadlength];\n            System.arraycopy(data, packet.payloadoffset, packet.data, 0, packet.payloadlength);\n        } catch (Exception e) {\n            return null;\n        }\n        return packet;\n    }\n\n    /**\n     * Returns the statistics of RTP reception\n     * \n     * @return Statistics\n     */\n    public RtpStatisticsReceiver getRtpReceptionStats() {\n        return stats;\n    }\n\n    /**\n     * Returns the DatagramConnection of RTP\n     * \n     * @return DatagramConnection\n     */\n    public DatagramConnection getConnection() {\n        return datagramConnection;\n    }\n\n    /**\n     * Extract Extension Header\n     * \n     * @param data\n     * @param length\n     * @param dataId\n     * @param packet\n     */\n    private void extractExtensionHeader(byte[] data, int length, int dataId, RtpPacket packet) {\n        byte[] extensionHeaderData = new byte[length * 4];\n        System.arraycopy(data, ++dataId, extensionHeaderData, 0, extensionHeaderData.length);\n        packet.extensionHeader = new RtpExtensionHeader();\n\n        int i = 0;\n        while (packet.extensionHeader.elementsCount() < length) {\n            byte idAndLength = extensionHeaderData[i];\n            if (idAndLength == 0x00) {\n                // its a padding byte, skip it\n                i = i + 1;\n                continue;\n            }\n\n            int elementId = (idAndLength & 0xf0) >>> 4;\n\n            // Each extension element id must have a value between 1 and 14 inclusive\n            if (elementId > 0 && elementId < 15) {\n                int elementLength = (idAndLength & 0x0f);\n                byte[] elementData = new byte[elementLength + 1];\n                System.arraycopy(extensionHeaderData, i + 1, elementData, 0, elementData.length);\n                packet.extensionHeader.addElement(elementId, elementData);\n                i = i + elementData.length + 1;\n            } else {\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpPacketTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\nimport java.io.IOException;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.AndroidDatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.DatagramConnection;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Packet;\n\n/**\n * RTP packet transmitter\n * \n * @author jexa7410\n */\npublic class RtpPacketTransmitter {\n\n    /**\n     * Sequence number\n     */\n    private int seqNumber = 0;\n\n    /**\n     * Remote address\n     */\n    private String remoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int remotePort;\n\n    /**\n     * Statistics\n     */\n    private RtpStatisticsTransmitter stats = new RtpStatisticsTransmitter();\n\n    /**\n     * Datagram connection\n     */\n    private DatagramConnection datagramConnection = null;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * Constructor\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession RTCP session\n     * @throws IOException\n     */\n    public RtpPacketTransmitter(String address, int port, RtcpSession rtcpSession)\n            throws IOException {\n        this.remoteAddress = address;\n        this.remotePort = port;\n        this.rtcpSession = rtcpSession;\n\n        datagramConnection = new AndroidDatagramConnection();\n        datagramConnection.open();\n    }\n\n    /**\n     * Constructor used for symetric RTP\n     * \n     * @param address Remote address\n     * @param port Remote port\n     * @param rtcpSession RTCP session\n     * @param connection Connection from RTP receiver\n     * @throws IOException\n     */\n    public RtpPacketTransmitter(String address, int port, RtcpSession rtcpSession,\n            DatagramConnection connection)\n            throws IOException {\n        this.remoteAddress = address;\n        this.remotePort = port;\n        this.rtcpSession = rtcpSession;\n\n        if (connection != null) {\n            this.datagramConnection = connection;\n        } else {\n            this.datagramConnection = new AndroidDatagramConnection();\n            this.datagramConnection.open();\n        }\n    }\n\n    /**\n     * Close the transmitter\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        // Close the datagram connection\n        if (datagramConnection != null) {\n            datagramConnection.close();\n        }\n    }\n\n    /**\n     * Send a RTP packet\n     * \n     * @param buffer Input buffer\n     * @throws IOException\n     */\n    public void sendRtpPacket(Buffer buffer) throws IOException {\n        // Build a RTP packet\n        RtpPacket packet = buildRtpPacket(buffer);\n        if (packet == null) {\n            return;\n        }\n\n        // Assemble RTP packet\n        int size = packet.calcLength();\n        packet.assemble(size);\n\n        // Send the RTP packet to the remote destination\n        transmit(packet);\n    }\n\n    /**\n     * Build a RTP packet\n     * \n     * @param buffer Input buffer\n     * @return RTP packet\n     */\n    private RtpPacket buildRtpPacket(Buffer buffer) {\n        byte data[] = (byte[]) buffer.getData();\n        if (data == null) {\n            return null;\n        }\n        Packet packet = new Packet();\n        packet.data = data;\n        packet.offset = 0;\n        packet.length = buffer.getLength();\n\n        RtpPacket rtppacket = new RtpPacket(packet);\n        if (buffer.isRTPMarkerSet()) {\n            rtppacket.marker = 1;\n        } else {\n            rtppacket.marker = 0;\n        }\n\n        rtppacket.payloadType = buffer.getFormat().getPayload();\n        rtppacket.seqnum = seqNumber++;\n        rtppacket.timestamp = buffer.getTimeStamp();\n        rtppacket.ssrc = rtcpSession.SSRC;\n        rtppacket.payloadoffset = buffer.getOffset();\n        rtppacket.payloadlength = buffer.getLength();\n        if (buffer.getVideoOrientation() != null) {\n            rtppacket.extension = true;\n            rtppacket.extensionHeader = new RtpExtensionHeader();\n            rtppacket.extensionHeader.addElement(\n                    buffer.getVideoOrientation().getHeaderId(),\n                    new byte[] {\n                        buffer.getVideoOrientation().getVideoOrientation()\n                    });\n        }\n        return rtppacket;\n    }\n\n    /**\n     * Transmit a RTCP compound packet to the remote destination\n     * \n     * @param packet RTP packet\n     * @throws IOException\n     */\n    private void transmit(Packet packet) {\n        // Prepare data to be sent\n        byte[] data = packet.data;\n        if (packet.offset > 0) {\n            System.arraycopy(data, packet.offset, data = new byte[packet.length], 0, packet.length);\n        }\n\n        // Update statistics\n        stats.numBytes += packet.length;\n        stats.numPackets++;\n\n        // Send data over UDP\n        try {\n            datagramConnection.send(remoteAddress, remotePort, data);\n\n            RtpSource s = rtcpSession.getMySource();\n            s.activeSender = true;\n            rtcpSession.timeOfLastRTPSent = rtcpSession.currentTime();\n            rtcpSession.packetCount++;\n            rtcpSession.octetCount += data.length;\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * Returns the statistics of RTP transmission\n     * \n     * @return Statistics\n     */\n    public RtpStatisticsTransmitter getStatistics() {\n        return stats;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpSource.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTP source\n * \n * @author jexa7410\n * @author Deutsche Telekom\n */\npublic class RtpSource {\n    /**\n     * RFC 3550: The dropout parameter MAX_DROPOUT should be a small fraction of the 16-bit sequence\n     * number space to give a reasonable probability that new sequence numbers after a restart will\n     * not fall in the acceptable range for sequence numbers from before the restart.\n     */\n    private static final int MAX_DROPOUT = 3000;\n\n    /**\n     * RFC 3550: the sequence number is considered valid if it is no more than MAX_DROPOUT ahead of\n     * maxSeq nor more than MAX_MISORDER behind\n     */\n    private static final int MAX_MISORDER = 100;\n\n    /**\n     * RFC 3550: RTP sequence number module\n     */\n    private static final int RTP_SEQ_MOD = (1 << 16);\n\n    /**\n     * CNAME value\n     */\n    public static String CNAME = \"anonymous@127.0.0.1\";\n\n    /**\n     * Source is not valid until MIN_SEQUENTIAL packets with sequential sequence numbers have been\n     * received.\n     */\n    private static int MIN_SEQUENCIAL = 0;\n\n    /**\n     * Is this source and ActiveSender.\n     */\n    public boolean activeSender;\n\n    /**\n     * Source description\n     */\n    public int ssrc;\n\n    /**\n     * Highest Sequence number received from this source\n     */\n    private int maxSeq;\n\n    /**\n     * Keep track of the wrapping around of RTP sequence numbers, since RTP Seq No. are only 16 bits\n     */\n    private int cycles;\n\n    /**\n     * Sequence Number of the first RTP packet received from this source\n     */\n    private int baseSeq;\n\n    /**\n     * Last 'bad' sequence number + 1\n     */\n    private int badSeq;\n\n    /**\n     * Sequence packets till source is valid\n     */\n    private int probation;\n\n    /**\n     * Packets received\n     */\n    private int received;\n\n    /**\n     * Packet expected at last interval\n     */\n    private int expectedPrior;\n\n    /**\n     * Packet received at last interval\n     */\n    private int receivedPrior;\n\n    /**\n     * Estimated jitter.\n     */\n    public long jitter;\n\n    /**\n     * Last SR Packet timestamp\n     */\n    private long lastSenderReport;\n\n    /**\n     * Constructor requires an SSRC for it to be a valid source. The constructor initializes all the\n     * source class members to a default value\n     * \n     * @param sourceSSRC SSRC of the new source\n     */\n    RtpSource(int sourceSSRC) {\n        ssrc = sourceSSRC;\n        lastSenderReport = 0;\n        probation = MIN_SEQUENCIAL;\n        jitter = 0;\n        initSeq(-1);\n    }\n\n    /**\n     * Generates the extended sequence number.\n     * \n     * @param seq Original sequence number\n     * @return Extended sequence number\n     */\n    public int generateExtendedSequenceNumber(int seq) {\n        return seq + (RTP_SEQ_MOD * cycles);\n    }\n\n    /**\n     * Updates the statistics related to Sender Reports. Should be invoked when a RTCP Sender Report\n     * is received.\n     * \n     * @param srp Sender Report\n     */\n    public void receivedSenderReport(RtcpSenderReportPacket srp) {\n        // RFC 3550: last SR timestamp (LSR): 32 bits - The middle 32 bits out\n        // of 64 in the NTP timestamp received as part of the most recent RTCP\n        // sender report\n        lastSenderReport = (((srp.ntptimestampmsw << 32) | srp.ntptimestamplsw) & 0x0000ffffffff0000L) >>> 16;\n    }\n\n    /**\n     * Updates the statistics related to RTP packets Should be invoked every time this source\n     * receive an RTP Packet .\n     * \n     * @param packet\n     */\n    public void receiveRtpPacket(RtpPacket packet) {\n        if (baseSeq == -1) {\n            // First packet received\n            initSeq(packet.seqnum);\n        }\n        updateSeq(packet.seqnum);\n    }\n\n    /**\n     * Generate the Reception Report\n     * \n     * @return ReceptionReport\n     */\n    public ReceptionReport generateReceptionReport() {\n        ReceptionReport report = new ReceptionReport(ssrc);\n        updateReceptionReport(report);\n        return report;\n    }\n\n    /**\n     * Updates the reception report with latest data. The statistics calculation is based on the\n     * algorithms present in RFC 3550\n     * \n     * @param report Reception report to update\n     */\n    public void updateReceptionReport(ReceptionReport report) {\n        // Calculate the number of packets lost\n        int extendedMax = getExtendedSequenceNumber();\n        int expected = extendedMax - baseSeq + 1;\n        report.setCumulativeNumberOfPacketsLost(expected - received);\n\n        // TODO : Calculate the delay after last sender report received\n        report.setDelaySinceLastSenderReport(0);\n        report.setExtendedHighestSequenceNumberReceived(getExtendedSequenceNumber());\n\n        // Calculate the fraction lost\n        long expectedInterval = expected - expectedPrior;\n        expectedPrior = expected;\n        int receivedInterval = received - receivedPrior;\n        receivedPrior = received;\n        long lostInterval = expectedInterval - receivedInterval;\n        if (expectedInterval == 0 || lostInterval <= 0) {\n            report.setFractionLost(0);\n        } else {\n            report.setFractionLost((lostInterval << 8) / (double) expectedInterval);\n        }\n\n        // TODO : Calculate jitter\n        report.setInterarrivalJitter(0);\n\n        report.setLastSenderReport(lastSenderReport);\n        report.setSsrc(ssrc);\n    }\n\n    /**\n     * Set the Source description\n     * \n     * @param ssrc\n     */\n    public void setSsrc(int ssrc) {\n        this.ssrc = ssrc;\n    }\n\n    /**\n     * Initiate sequence. RFC 3550\n     * \n     * @param sequenceNumber\n     */\n    private void initSeq(int sequenceNumber) {\n        baseSeq = sequenceNumber;\n        maxSeq = sequenceNumber;\n        badSeq = RTP_SEQ_MOD + 1; // so seq == bad_seq is false\n        cycles = 0;\n        received = 0;\n        receivedPrior = 0;\n        expectedPrior = 0;\n    }\n\n    /**\n     * Ensures that a source is declared valid only after MIN_SEQUENTIAL packets have been received\n     * in sequence.It also validates the sequence number seq of a newly received packet and updates\n     * the sequence state. Algorithm in the RFC 3550 (Appendix A.1)\n     * \n     * @param seq Sequence Number\n     */\n    private int updateSeq(int seq) {\n        long udelta = seq - maxSeq;\n\n        // Source is not valid until MIN_SEQUENTIAL packets with sequential\n        // sequence numbers have been received.\n        if (probation > 0) {\n            if (seq == maxSeq + 1) {\n                probation--;\n                maxSeq = seq;\n                if (probation == 0) {\n                    initSeq(seq);\n                    received++;\n                    return 1;\n                }\n            } else {\n                probation = MIN_SEQUENCIAL - 1;\n                maxSeq = seq;\n                return 1;\n            }\n            return 0;\n        } else if (udelta < MAX_DROPOUT) {\n            // in order, with permissible gap\n            if (seq < maxSeq && (udelta >= (MAX_MISORDER * -1))) {\n                // late packet within interval\n                received++;\n                return 1;\n            }\n\n            if (seq < maxSeq) {\n                // Sequence number wrapped - count another 64K cycle.\n                cycles++;\n            }\n            maxSeq = seq;\n        } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {\n            // the sequence number made a very large jump\n            if (seq == badSeq) {\n                // Two sequential packets -- assume that the other side\n                // restarted without telling us so just re-sync\n                // (i.e., pretend this was the first packet).\n                initSeq(seq);\n            } else {\n                badSeq = (seq + 1) & (RTP_SEQ_MOD - 1);\n                return 0;\n            }\n        } else {\n            // duplicate or reordered packet\n        }\n        received++;\n        return 1;\n    }\n\n    /**\n     * Return the extended sequence number for a source considering that sequences cycle.\n     * \n     * @return Extended sequence number\n     */\n    private int getExtendedSequenceNumber() {\n        return generateExtendedSequenceNumber(maxSeq);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpStatisticsReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTP statistics receiver\n * \n * @author jexa7410\n */\npublic class RtpStatisticsReceiver {\n    /**\n     * Number of RTP packets received\n     */\n    public int numPackets = 0;\n\n    /**\n     * Number of RTP bytes received\n     */\n    public int numBytes = 0;\n\n    /**\n     * Number of bad RTP packet received\n     */\n    public int numBadRtpPkts = 0;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/core/RtpStatisticsTransmitter.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.core;\n\n/**\n * RTP statistics transmitter\n * \n * @author jexa7410\n */\npublic class RtpStatisticsTransmitter {\n    /**\n     * Total number of packets sent\n     */\n    public int numPackets = 0;\n\n    /**\n     * Total number of bytes sent\n     */\n    public int numBytes = 0;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpApplicationEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpAppPacket;\n\n/**\n * RTCP application event\n * \n * @author jexa7410\n */\npublic class RtcpApplicationEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP APP packet\n     */\n    public RtcpApplicationEvent(RtcpAppPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpByeEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpByePacket;\n\n/**\n * RTCP bye event\n * \n * @author jexa7410\n */\npublic class RtcpByeEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP BYE packet\n     */\n    public RtcpByeEvent(RtcpByePacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpPacket;\n\n/**\n * Abstract RTCP event\n * \n * @author jexa7410\n */\npublic abstract class RtcpEvent {\n    /**\n     * RTCP packet\n     */\n    private RtcpPacket packet;\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP packet\n     */\n    public RtcpEvent(RtcpPacket packet) {\n        this.packet = packet;\n    }\n\n    /**\n     * Returns the RTCP packet\n     * \n     * @return Packet\n     */\n    public RtcpPacket getPacket() {\n        return packet;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpEventListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\n/**\n * RTCP events listener interface\n * \n * @author jexa7410\n */\npublic interface RtcpEventListener {\n    /**\n     * Receive RTCP event\n     * \n     * @param event RTCP event\n     */\n    void receiveRtcpEvent(RtcpEvent event);\n\n    /**\n     * Invoked when the RTCP connection times out\n     */\n    void connectionTimeout();\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpReceiverReportEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpReceiverReportPacket;\n\n/**\n * RTCP receiver report event\n * \n * @author jexa7410\n */\npublic class RtcpReceiverReportEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP RR packet\n     */\n    public RtcpReceiverReportEvent(RtcpReceiverReportPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpSdesEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpSdesPacket;\n\n/**\n * RTCP session description event\n * \n * @author jexa7410\n */\npublic class RtcpSdesEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP SDES packet\n     */\n    public RtcpSdesEvent(RtcpSdesPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/event/RtcpSenderReportEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.event;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpSenderReportPacket;\n\n/**\n * RTCP sender report event\n * \n * @author jexa7410\n */\npublic class RtcpSenderReportEvent extends RtcpEvent {\n\n    /**\n     * Constructor\n     * \n     * @param packet RTCP SR packet\n     */\n    public RtcpSenderReportEvent(RtcpSenderReportPacket packet) {\n        super(packet);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/DummyFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format;\n\n/**\n * Dummy format\n * \n * @author jexa7410\n */\npublic class DummyFormat extends Format {\n\n    /**\n     * Encoding name\n     */\n    public static final String ENCODING = \"dummy\";\n\n    /**\n     * Payload type\n     */\n    public static final int PAYLOAD = 20;\n\n    /**\n     * Constructor\n     */\n    public DummyFormat() {\n        super(ENCODING, PAYLOAD);\n    }\n\n    /**\n     * Get the size of a chunk of data from the source\n     * \n     * @return The minimum size of the buffer needed to read a chunk of data\n     */\n    public int getDataChunkSize() {\n        return 0;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/Format.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format;\n\n/**\n * Abstract format\n * \n * @author jexa7410\n */\npublic abstract class Format {\n    /**\n     * Unknown payload\n     */\n    public static final int UNKNOWN_PAYLOAD = -1;\n\n    /**\n     * Codec\n     */\n    private String codec;\n\n    /**\n     * Payload type\n     */\n    private int payload;\n\n    /**\n     * Constructor\n     * \n     * @param codec Codec\n     * @param payload Payload type\n     */\n    public Format(String codec, int payload) {\n        this.codec = codec;\n        this.payload = payload;\n    }\n\n    /**\n     * Get the codec name\n     * \n     * @return Name\n     */\n    public String getCodec() {\n        return codec;\n    }\n\n    /**\n     * Get the type of payload\n     * \n     * @return Payload type\n     */\n    public int getPayload() {\n        return payload;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/video/CameraOptions.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format.video;\n\n/**\n * Represents the available camera options\n * \n * @author Deutsche Telekom\n */\npublic enum CameraOptions {\n\n    /**\n     * Cameras value\n     */\n    FRONT(0),\n    BACK(1);\n\n    /**\n     * Private value\n     */\n    private int value;\n\n    /**\n     * Default constructor\n     * \n     * @param value Camera ID\n     */\n    private CameraOptions(int value) {\n        this.value = value;\n    }\n\n    /**\n     * Gets the camera int value\n     * \n     * @return value\n     */\n    public int getValue() {\n        return this.value;\n    }\n\n    /**\n     * Converts the given value in to a Camera\n     * \n     * @param value value\n     * @return Camera\n     */\n    public static CameraOptions convert(int value) {\n        if (value == FRONT.value) {\n            return FRONT;\n        }\n        return BACK;\n    }\n\n    /**\n     * Verifies if it's a front camera\n     * \n     * @return <code>True</code> if it is, <code>false</code> otherwise.\n     */\n    public boolean isFrontCamera() {\n        return this.value == FRONT.value;\n    }\n\n    /**\n     * Verifies if it's a back camera\n     * \n     * @return <code>True</code> if it is, <code>false</code> otherwise.\n     */\n    public boolean isBackCamera() {\n        return this.value == BACK.value;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/video/H264VideoFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format.video;\n\n/**\n * H264 video format\n * \n * @author jexa7410\n */\npublic class H264VideoFormat extends VideoFormat {\n\n    /**\n     * Encoding name\n     */\n    public static final String ENCODING = \"H264\";\n\n    /**\n     * Payload type\n     */\n    public static final int PAYLOAD = 96;\n\n    /**\n     * Constructor\n     */\n    public H264VideoFormat() {\n        super(ENCODING, PAYLOAD);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/video/Orientation.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format.video;\n\n/**\n * Represents the Video frame orientation\n * \n * @author Deutsche Telekom\n */\npublic enum Orientation {\n    /**\n     * Orientation values\n     */\n    NONE(0),\n    ROTATE_90_CW(1),\n    ROTATE_180(2),\n    ROTATE_90_CCW(3),\n    FLIP_HORIZONTAL(4),\n    ROTATE_90_CW_FLIP_HORIZONTAL(5),\n    ROTATE_180_FLIP_HORIZONTAL(6),\n    ROTATE_90_CCW_FLIP_HORIZONTAL(7);\n\n    /**\n     * Private value\n     */\n    private int value;\n\n    /**\n     * Constructor\n     * \n     * @param value Enum value\n     */\n    private Orientation(int value) {\n        this.value = value;\n    }\n\n    /**\n     * Return the value of the Orientation\n     * \n     * @return Orientation value\n     */\n    public int getValue() {\n        return this.value;\n    }\n\n    /**\n     * Converts the Value into an Orientation\n     * \n     * @param value value to convert\n     * @return Orientation\n     */\n    public static Orientation convert(int value) {\n        if (NONE.value == value) {\n            return NONE;\n        } else if (ROTATE_90_CW.value == value) {\n            return ROTATE_90_CW;\n        } else if (ROTATE_180.value == value) {\n            return ROTATE_180;\n        } else if (ROTATE_90_CCW.value == value) {\n            return ROTATE_90_CCW;\n        } else if (FLIP_HORIZONTAL.value == value) {\n            return FLIP_HORIZONTAL;\n        } else if (ROTATE_90_CW_FLIP_HORIZONTAL.value == value) {\n            return ROTATE_90_CW_FLIP_HORIZONTAL;\n        } else if (ROTATE_180_FLIP_HORIZONTAL.value == value) {\n            return ROTATE_180_FLIP_HORIZONTAL;\n        } else if (ROTATE_90_CCW_FLIP_HORIZONTAL.value == value) {\n            return ROTATE_90_CCW_FLIP_HORIZONTAL;\n        }\n        return NONE;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/video/VideoFormat.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format.video;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\n\n/**\n * Video format\n */\npublic class VideoFormat extends Format {\n    /**\n     * Constructor\n     * \n     * @param codec Codec\n     * @param payload Payload type\n     */\n    public VideoFormat(String codec, int payload) {\n        super(codec, payload);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/format/video/VideoOrientation.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.format.video;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.RtpUtils;\n\n/**\n * RCS Video orientation\n * \n * @author Deutsche Telekom\n */\npublic class VideoOrientation {\n\n    /**\n     * Header Id\n     */\n    private int headerId = RtpUtils.RTP_DEFAULT_EXTENSION_ID;\n\n    /**\n     * Camera\n     */\n    private CameraOptions camera;\n\n    /**\n     * Camera orientation\n     */\n    private Orientation orientation;\n\n    /**\n     * Constructor\n     * \n     * @param headerId Orientation header id\n     * @param camera Camera\n     * @param orientation Orientation\n     */\n    public VideoOrientation(int headerId, CameraOptions camera, Orientation orientation) {\n        this.headerId = headerId;\n        this.camera = camera;\n        this.orientation = orientation;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param camera Camera\n     * @param orientation Orientation\n     */\n    public VideoOrientation(CameraOptions camera, Orientation orientation) {\n        this.camera = camera;\n        this.orientation = orientation;\n    }\n\n    /**\n     * Gets the VideoOrientation camera\n     * \n     * @return Camera\n     */\n    public CameraOptions getCamera() {\n        return this.camera;\n    }\n\n    /**\n     * Gets the VideoOrientation orientation\n     * \n     * @return Orientation\n     */\n    public Orientation getOrientation() {\n        return this.orientation;\n    }\n\n    /**\n     * Converts the video orientation into the byte used to transmit int RTP header\n     * \n     * @return Byte representing the video orientation\n     */\n    public byte getVideoOrientation() {\n        return (byte) ((camera.getValue() << 3) | orientation.getValue());\n    }\n\n    /**\n     * Gets the negotiated header ID.\n     * \n     * @return Header id\n     */\n    public int getHeaderId() {\n        return headerId;\n    }\n\n    /**\n     * Parses the byte into a VideoOrientation object\n     * \n     * @param videoOrientation Byte representing the video Orientation\n     * @return VideoOrientation object\n     */\n    public static VideoOrientation parse(byte videoOrientation) {\n        return new VideoOrientation(CameraOptions.convert((videoOrientation & 0x08) >>> 3),\n                Orientation.convert(videoOrientation & 0x07));\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/media/MediaException.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media exception\n * \n * @author JM. Auffret\n */\npublic class MediaException extends java.lang.Exception {\n    static final long serialVersionUID = 1L;\n\n    /**\n     * Constructor\n     * \n     * @param error Error message\n     */\n    public MediaException(String error) {\n        super(error);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/media/MediaInput.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media input (e.g. camera, microphone)\n * \n * @author jexa7410\n */\npublic interface MediaInput {\n    /**\n     * Open the player\n     * \n     * @throws MediaException\n     */\n    public void open() throws MediaException;\n\n    /**\n     * Close the player\n     */\n    public void close();\n\n    /**\n     * Read a media sample (blocking method)\n     * \n     * @return Media sample\n     * @throws MediaException\n     */\n    public MediaSample readSample() throws MediaException;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/media/MediaListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media listener\n * \n * @author jexa7410\n */\npublic interface MediaListener {\n    /**\n     * Media is started\n     */\n    public void mediaStarted();\n\n    /**\n     * Media is stopped\n     */\n    public void mediaStopped();\n\n    /**\n     * Media has failed\n     * \n     * @param error Error code\n     */\n    public void mediaError(String error);\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/media/MediaOutput.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media output (e.g. screen, headset)\n * \n * @author jexa7410\n */\npublic interface MediaOutput {\n    /**\n     * Open the renderer\n     * \n     * @throws MediaException\n     */\n    public void open() throws MediaException;\n\n    /**\n     * Close the renderer\n     */\n    public void close();\n\n    /**\n     * Write a media sample\n     * \n     * @param sample Media sample\n     * @throws MediaException\n     */\n    public void writeSample(MediaSample sample) throws MediaException;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/media/MediaSample.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.media;\n\n/**\n * Media sample\n * \n * @author jexa7410\n */\npublic class MediaSample {\n\n    /**\n     * Data\n     */\n    private byte[] data;\n\n    /**\n     * Time stamp\n     */\n    private long time;\n\n    /**\n     * RTP marker bit\n     */\n    private boolean marker = false;\n\n    /**\n     * Sequence number\n     */\n    private long sequenceNumber;\n\n    // TODO: remove after implement receiver buffer\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param time Time stamp\n     * @Param sequenceNumber Packet sequence number\n     */\n    public MediaSample(byte[] data, long time, long sequenceNumber) {\n        this.data = data;\n        this.time = time;\n        this.sequenceNumber = sequenceNumber;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param time Time stamp\n     */\n    public MediaSample(byte[] data, long time) {\n        this.data = data;\n        this.time = time;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param time Time stamp\n     * @param marker Marker bit\n     */\n    public MediaSample(byte[] data, long time, boolean marker) {\n        this.data = data;\n        this.time = time;\n        this.marker = marker;\n    }\n\n    /**\n     * Returns the data sample\n     * \n     * @return Byte array\n     */\n    public byte[] getData() {\n        return data;\n    }\n\n    /**\n     * Returns the length of the data sample\n     * \n     * @return Data sample length\n     */\n    public int getLength() {\n        if (data != null) {\n            return data.length;\n        } else {\n            return 0;\n        }\n    }\n\n    /**\n     * Returns the time stamp of the sample\n     * \n     * @return Time in microseconds\n     */\n    public long getTimeStamp() {\n        return time;\n    }\n\n    /**\n     * Is RTP marker bit\n     * \n     * @return Boolean\n     */\n    public boolean isMarker() {\n        return marker;\n    }\n\n    /**\n     * Get the sequence number\n     * \n     * @return sequence number\n     */\n    public long getSequenceNumber() {\n        return this.sequenceNumber;\n    }\n\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/media/VideoSample.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.media;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\n\n/**\n * Video sample\n * \n * @author hlxn7157\n */\npublic class VideoSample extends MediaSample {\n\n    /**\n     * Video Orientation\n     */\n    private VideoOrientation videoOrientation;\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param time Time stamp\n     * @param videoOrientation Video orientation\n     */\n    public VideoSample(byte[] data, long time, VideoOrientation videoOrientation) {\n        super(data, time);\n        this.videoOrientation = videoOrientation;\n    }\n\n    /**\n     * Constructor\n     * \n     * @param data Data\n     * @param time Time stamp\n     * @Param sequenceNumber Packet sequence number\n     * @param videoOrientation Video orientation\n     */\n    public VideoSample(byte[] data, long time, long sequenceNumber,\n            VideoOrientation videoOrientation) {\n        super(data, time, sequenceNumber);\n        this.videoOrientation = videoOrientation;\n    }\n\n    /**\n     * Gets the video orientation\n     * \n     * @return VideoOrientation\n     */\n    public VideoOrientation getVideoOrientation() {\n        return videoOrientation;\n    }\n\n    /**\n     * Sets the video orientation\n     * \n     * @param videoOrientation VideoOrientation\n     */\n    public void setVideoOrientation(VideoOrientation orientation) {\n        this.videoOrientation = orientation;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/DummyPacketSourceStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.DummyFormat;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.FifoBuffer;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.SystemTimeBase;\n\n/**\n * Dummy packet source stream (used to pass NAT)\n * \n * @author jexa7410\n */\npublic class DummyPacketSourceStream extends Thread implements ProcessorInputStream {\n\n    /**\n     * Source period for the opening phase (in milliseconds)\n     */\n    public final static int DUMMY_SOURCE_OPENING_PERIOD = 100;\n\n    /**\n     * Source period (in milliseconds)\n     */\n    public final static int DUMMY_SOURCE_PERIOD = 15000;\n\n    /**\n     * Input format\n     */\n    private DummyFormat format = new DummyFormat();\n\n    /**\n     * Time base\n     */\n    private SystemTimeBase systemTimeBase = new SystemTimeBase();\n\n    /**\n     * Sequence number\n     */\n    private long seqNo = 0;\n\n    /**\n     * Message buffer\n     */\n    private FifoBuffer fifo = new FifoBuffer();\n\n    /**\n     * Interruption flag\n     */\n    private boolean interrupted = false;\n\n    /**\n     * Incoming stream is started ?\n     */\n    private boolean incomingStarted = false;\n\n    /**\n     * Constructor\n     */\n    public DummyPacketSourceStream() {\n    }\n\n    /**\n     * Open the input stream\n     */\n    public void open() {\n        start();\n    }\n\n    /**\n     * Close the input stream\n     */\n    public void close() {\n        interrupted = true;\n        try {\n            fifo.close();\n        } catch (Exception e) {\n            // Intentionally blank\n        }\n    }\n\n    /**\n     * Format of the data provided by the source stream\n     * \n     * @return Format\n     */\n    public Format getFormat() {\n        return format;\n    }\n\n    /**\n     * Background processing\n     */\n    public void run() {\n        while (!interrupted) {\n            try {\n                // Build a new dummy packet\n                Buffer packet = new Buffer();\n                packet.setData(new byte[0]);\n                packet.setLength(0);\n                packet.setFormat(format);\n                packet.setSequenceNumber(seqNo++);\n                packet.setTimeStamp(systemTimeBase.getTime());\n\n                // Post the packet in the FIFO\n                fifo.addObject(packet);\n\n                // Make a pause\n                if (!incomingStarted) {\n                    Thread.sleep(DUMMY_SOURCE_OPENING_PERIOD);\n                } else {\n                    Thread.sleep(DUMMY_SOURCE_PERIOD);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * Read from the stream\n     * \n     * @return Buffer\n     * @throws Exception\n     */\n    public Buffer read() throws Exception {\n        // Read the FIFO the buffer\n        Buffer buffer = (Buffer) fifo.getObject();\n        return buffer;\n    }\n\n    /**\n     * Set incomingStarted.\n     */\n    public void incomingStarted() {\n        incomingStarted = true;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/MediaCaptureStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Media capture stream\n * \n * @author jexa7410\n */\npublic class MediaCaptureStream implements ProcessorInputStream {\n    /**\n     * Media player\n     */\n    private MediaInput player;\n\n    /**\n     * Media format\n     */\n    private Format format;\n\n    /**\n     * Sequence number\n     */\n    protected long seqNo = 0;\n\n    /**\n     * Input buffer\n     */\n    protected Buffer buffer = new Buffer();\n\n    /**\n     * Constructor\n     * \n     * @param format Input format\n     * @param player Media player\n     */\n    public MediaCaptureStream(Format format, MediaInput player) {\n        this.format = format;\n        this.player = player;\n    }\n\n    /**\n     * Open the input stream\n     * \n     * @throws Exception\n     */\n    public void open() throws Exception {\n        try {\n            player.open();\n        } catch (Exception e) {\n            throw e;\n        }\n    }\n\n    /**\n     * Close the input stream\n     */\n    public void close() {\n        player.close();\n    }\n\n    /**\n     * Format of the data provided by the source stream\n     * \n     * @return Format\n     */\n    public Format getFormat() {\n        return format;\n    }\n\n    /**\n     * returns the MediaInput\n     * \n     * @return MediaInput\n     */\n    public MediaInput getPlayer() {\n        return player;\n    }\n\n    /**\n     * Read from the stream\n     * \n     * @return Buffer\n     * @throws Exception\n     */\n    public Buffer read() throws Exception {\n        // Read a new sample from the media player\n        MediaSample sample = player.readSample();\n        if (sample == null) {\n            return null;\n        }\n\n        // Create a buffer\n        buffer.setData(sample.getData());\n        buffer.setLength(sample.getLength());\n        buffer.setFormat(format);\n        buffer.setSequenceNumber(seqNo++);\n        if (sample.isMarker()) {\n            buffer.setFlags(Buffer.FLAG_RTP_MARKER);\n        }\n        buffer.setTimeStamp(sample.getTimeStamp());\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/MediaRendererStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Media renderer stream\n * \n * @author jexa7410\n */\npublic class MediaRendererStream implements ProcessorOutputStream {\n    /**\n     * Media renderer\n     */\n    private MediaOutput renderer;\n\n    /**\n     * Constructor\n     * \n     * @param renderer Media renderer\n     */\n    public MediaRendererStream(MediaOutput renderer) {\n        this.renderer = renderer;\n    }\n\n    /**\n     * Get Media renderer\n     * \n     * @return renderer Media renderer\n     */\n    public MediaOutput getRenderer() {\n        return renderer;\n    }\n\n    /**\n     * Open the output stream\n     * \n     * @throws Exception\n     */\n    public void open() throws Exception {\n        try {\n            renderer.open();\n        } catch (Exception e) {\n            throw e;\n        }\n    }\n\n    /**\n     * Close the output stream\n     */\n    public void close() {\n        renderer.close();\n    }\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     * @throws Exception\n     */\n    public void write(Buffer buffer) throws Exception {\n        MediaSample sample = new MediaSample((byte[]) buffer.getData(), buffer.getTimeStamp(),\n                buffer.getSequenceNumber());\n        renderer.writeSample(sample);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/ProcessorInputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Processor input stream\n */\npublic interface ProcessorInputStream {\n\n    /**\n     * Open the input stream\n     * \n     * @throws Exception\n     */\n    public void open() throws Exception;\n\n    /**\n     * Close the input stream\n     */\n    public void close();\n\n    /**\n     * Read from the input stream without blocking\n     * \n     * @return Buffer\n     * @throws Exception\n     */\n    public Buffer read() throws Exception;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/ProcessorOutputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Processor output stream\n */\npublic interface ProcessorOutputStream {\n    /**\n     * Open the output stream\n     * \n     * @throws Exception\n     */\n    public void open() throws Exception;\n\n    /**\n     * Close from the output stream\n     */\n    public void close();\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     * @throws Exception\n     */\n    public void write(Buffer buffer) throws Exception;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/RtpInputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport java.util.Comparator;\nimport java.util.PriorityQueue;\nimport java.util.concurrent.TimeoutException;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.RtpUtils;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpPacketReceiver;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpPacketTransmitter;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpSession;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtpExtensionHeader.ExtensionElement;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtpPacket;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtpPacketReceiver;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * RTP input stream\n * \n * @author jexa7410\n */\npublic class RtpInputStream implements ProcessorInputStream {\n    /**\n     * RTP Socket Timeout Used a 20s timeout value because the RTP packets can have a delay\n     */\n    private static final int RTP_SOCKET_TIMEOUT = 20000;\n\n    /**\n     * Remote address\n     */\n    private String remoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int remotePort;\n\n    /**\n     * Local port\n     */\n    private int localPort;\n\n    /**\n     * RTP receiver\n     */\n    private RtpPacketReceiver rtpReceiver = null;\n\n    /**\n     * RTCP receiver\n     */\n    private RtcpPacketReceiver rtcpReceiver = null;\n\n    /**\n     * RTCP transmitter\n     */\n    private RtcpPacketTransmitter rtcpTransmitter = null;\n\n    /**\n     * Input buffer\n     */\n    private Buffer buffer = new Buffer();\n\n    /**\n     * Input format\n     */\n    private Format inputFormat = null;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * RTP stream listener\n     */\n    private RtpStreamListener rtpStreamListener;\n\n    /**\n     * The negotiated orientation extension header id\n     */\n    private int extensionHeaderId = RtpUtils.RTP_DEFAULT_EXTENSION_ID;\n\n    /**\n     * Indicates if the stream was closed\n     */\n    private boolean isClosed = false;\n\n    /**\n     * Sequence RTP packets buffer\n     */\n    private PriorityQueue<RtpPacket> rtpPacketsBuffer;\n\n    /**\n     * Constructor\n     * \n     * @param localPort Local port\n     * @param inputFormat Input format\n     */\n    public RtpInputStream(String remoteAddress, int remotePort, int localPort, Format inputFormat) {\n        this.remoteAddress = remoteAddress;\n        this.remotePort = remotePort;\n        this.localPort = localPort;\n        this.inputFormat = inputFormat;\n\n        rtcpSession = new RtcpSession(false, 16000);\n\n        rtpPacketsBuffer = new PriorityQueue<RtpPacket>(10, new Comparator<RtpPacket>() {\n            @Override\n            public int compare(RtpPacket object1, RtpPacket object2) {\n                if (object1.seqnum == object2.seqnum) {\n                    return 0;\n                } else if (object1.seqnum < object2.seqnum) {\n                    return -1;\n                }\n                return 1;\n            }\n        });\n\n    }\n\n    /**\n     * Open the input stream\n     * \n     * @throws Exception\n     */\n    public void open() throws Exception {\n        // Create the RTP receiver\n        rtpReceiver = new RtpPacketReceiver(localPort, rtcpSession, RTP_SOCKET_TIMEOUT);\n        rtpReceiver.start();\n\n        // Create the RTCP receiver\n        rtcpReceiver = new RtcpPacketReceiver(localPort + 1, rtcpSession);\n        rtcpReceiver.start();\n\n        // Create the RTCP transmitter\n        rtcpTransmitter = new RtcpPacketTransmitter(remoteAddress,\n                remotePort + 1,\n                rtcpSession,\n                rtcpReceiver.getConnection());\n        rtcpTransmitter.start();\n\n        isClosed = false;\n    }\n\n    /**\n     * Close the input stream\n     */\n    public void close() {\n        try {\n            isClosed = true;\n\n            // Close the RTCP transmitter\n            if (rtcpTransmitter != null)\n                rtcpTransmitter.close();\n\n            // Close the RTP receiver\n            if (rtpReceiver != null) {\n                rtpReceiver.close();\n            }\n\n            // Close the RTCP receiver\n            if (rtcpReceiver != null) {\n                rtcpReceiver.close();\n            }\n            rtpStreamListener = null;\n        } catch (Exception e) {\n        }\n    }\n\n    /**\n     * Returns the RTP receiver\n     * \n     * @return RTP receiver\n     */\n    public RtpPacketReceiver getRtpReceiver() {\n        return rtpReceiver;\n    }\n\n    /**\n     * Returns the RTCP receiver\n     * \n     * @return RTCP receiver\n     */\n    public RtcpPacketReceiver getRtcpReceiver() {\n        return rtcpReceiver;\n    }\n\n    /**\n     * Read from the input stream without blocking\n     * \n     * @return Buffer\n     * @throws Exception\n     */\n    public Buffer read() throws Exception {\n        try {\n            do {\n                // Wait and read a RTP packet\n                RtpPacket rtpPacket = rtpReceiver.readRtpPacket();\n                if (rtpPacket == null) {\n                    return null;\n                }\n\n                // Add the buffer in queue\n                rtpPacketsBuffer.add(rtpPacket);\n            } while (rtpPacketsBuffer.size() <= 5);\n\n            RtpPacket packet = rtpPacketsBuffer.poll();\n\n            // Create a buffer\n            buffer.setData(packet.data);\n            buffer.setLength(packet.payloadlength);\n            buffer.setOffset(0);\n            buffer.setFormat(inputFormat);\n            buffer.setSequenceNumber(packet.seqnum);\n            buffer.setRTPMarker(packet.marker != 0);\n            buffer.setTimeStamp(packet.timestamp);\n\n            if (packet.extensionHeader != null) {\n                ExtensionElement element = packet.extensionHeader.getElementById(extensionHeaderId);\n                if (element != null) {\n                    buffer.setVideoOrientation(VideoOrientation.parse(element.data[0]));\n                }\n            }\n\n            // Set inputFormat back to null\n            inputFormat = null;\n            return buffer;\n        } catch (TimeoutException ex) {\n            if (!isClosed) {\n                if (rtpStreamListener != null) {\n                    rtpStreamListener.rtpStreamAborted();\n                }\n            }\n            return null;\n        }\n    }\n\n    /**\n     * Adds the RTP stream listener\n     * \n     * @param rtpStreamListener\n     */\n    public void addRtpStreamListener(RtpStreamListener rtpStreamListener) {\n        this.rtpStreamListener = rtpStreamListener;\n    }\n\n    /**\n     * Sets the negotiated orientation extension header id\n     * \n     * @param extensionHeaderId Header id\n     */\n    public void setExtensionHeaderId(int extensionHeaderId) {\n        this.extensionHeaderId = extensionHeaderId;\n    }\n\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/RtpOutputStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpPacketReceiver;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpPacketTransmitter;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtcpSession;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtpPacketReceiver;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.core.RtpPacketTransmitter;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpEvent;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.event.RtcpEventListener;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\nimport java.io.IOException;\n\n/**\n * RTP output stream\n * \n * @author jexa7410\n */\npublic class RtpOutputStream implements ProcessorOutputStream, RtcpEventListener {\n    /**\n     * RTCP Socket Timeout\n     */\n    public static final int RTCP_SOCKET_TIMEOUT = 20000;\n\n    /**\n     * Remote address\n     */\n    private String remoteAddress;\n\n    /**\n     * Remote port\n     */\n    private int remotePort;\n\n    /**\n     * Local port\n     */\n    private int localRtpPort = -1;\n\n    /**\n     * RTP receiver\n     */\n    private RtpPacketReceiver rtpReceiver = null;\n\n    /**\n     * RTCP receiver\n     */\n    private RtcpPacketReceiver rtcpReceiver = null;\n\n    /**\n     * RTP transmitter\n     */\n    private RtpPacketTransmitter rtpTransmitter = null;\n\n    /**\n     * RTCP transmitter\n     */\n    private RtcpPacketTransmitter rtcpTransmitter = null;\n\n    /**\n     * RTCP Session\n     */\n    private RtcpSession rtcpSession = null;\n\n    /**\n     * RTCP socket timeout\n     */\n    private int rtcpSocketTimeout = 0;\n\n    /**\n     * RTP stream listener\n     */\n    private RtpStreamListener rtpStreamListener;\n\n    /**\n     * RTP Input stream\n     */\n    private RtpInputStream rtpInputStream = null;\n\n    /**\n     * Constructor\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     */\n    public RtpOutputStream(String remoteAddress, int remotePort) {\n        this.remoteAddress = remoteAddress;\n        this.remotePort = remotePort;\n\n        rtcpSession = new RtcpSession(true, 16000);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtpInputStream RTP input stream\n     */\n    public RtpOutputStream(String remoteAddress, int remotePort, RtpInputStream rtpInputStream) {\n        this.remoteAddress = remoteAddress;\n        this.remotePort = remotePort;\n        this.rtpInputStream = rtpInputStream;\n\n        rtcpSession = new RtcpSession(true, 16000);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param remoteAddress Remote address\n     * @param remotePort Remote port\n     * @param rtcpTimeout RTCP timeout\n     */\n    public RtpOutputStream(String remoteAddress, int remotePort, int localRtpPort, int rtcpTimeout) {\n        this.remoteAddress = remoteAddress;\n        this.remotePort = remotePort;\n        this.localRtpPort = localRtpPort;\n        this.rtcpSocketTimeout = rtcpTimeout;\n\n        rtcpSession = new RtcpSession(true, 16000);\n    }\n\n    /**\n     * Open the output stream\n     * \n     * @throws Exception\n     */\n    public void open() throws Exception {\n        if (localRtpPort != -1) {\n            // Create the RTP receiver\n            rtpReceiver = new RtpPacketReceiver(localRtpPort, rtcpSession);\n            rtpReceiver.start();\n\n            // Create the RTCP receiver\n            rtcpReceiver = new RtcpPacketReceiver(localRtpPort + 1, rtcpSession, rtcpSocketTimeout);\n            rtcpReceiver.addRtcpListener(this);\n            rtcpReceiver.start();\n\n            // Create the RTP transmitter\n            rtpTransmitter = new RtpPacketTransmitter(remoteAddress,\n                    remotePort,\n                    rtcpSession,\n                    rtpReceiver.getConnection());\n\n            // Create the RTCP transmitter\n            rtcpTransmitter = new RtcpPacketTransmitter(remoteAddress,\n                    remotePort + 1,\n                    rtcpSession,\n                    rtcpReceiver.getConnection());\n            rtcpTransmitter.start();\n        } else if (rtpInputStream != null) {\n            // Create the RTP transmitter\n            rtpTransmitter = new RtpPacketTransmitter(remoteAddress, remotePort, rtcpSession,\n                    rtpInputStream.getRtpReceiver().getConnection());\n\n            // Create the RTCP transmitter\n            rtcpTransmitter = new RtcpPacketTransmitter(remoteAddress, remotePort + 1, rtcpSession,\n                    rtpInputStream.getRtpReceiver().getConnection());\n        } else {\n            // Create the RTP transmitter\n            rtpTransmitter = new RtpPacketTransmitter(remoteAddress, remotePort, rtcpSession);\n\n            // Create the RTCP transmitter\n            rtcpTransmitter = new RtcpPacketTransmitter(remoteAddress, remotePort + 1, rtcpSession);\n        }\n    }\n\n    /**\n     * Close the output stream\n     */\n    public void close() {\n        try {\n            // Close the RTP transmitter\n            if (rtpTransmitter != null)\n                rtpTransmitter.close();\n\n            // Close the RTCP transmitter\n            if (rtcpTransmitter != null)\n                rtcpTransmitter.close();\n\n            // Close the RTP receiver\n            if (rtpReceiver != null)\n                rtpReceiver.close();\n\n            // Close the RTCP receiver\n            if (rtcpReceiver != null)\n                rtcpReceiver.close();\n\n            // Remove rtpStreamListener\n            rtpStreamListener = null;\n        } catch (Exception e) {\n        }\n    }\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     * @throws IOException\n     */\n    public void write(Buffer buffer) throws IOException {\n        rtpTransmitter.sendRtpPacket(buffer);\n    }\n\n    @Override\n    public void receiveRtcpEvent(RtcpEvent event) {\n        // Nothing to do\n    }\n\n    @Override\n    public void connectionTimeout() {\n        if (rtpStreamListener != null) {\n            rtpStreamListener.rtpStreamAborted();\n        }\n    }\n\n    /**\n     * Adds the RTP stream listener\n     * \n     * @param rtpStreamListener\n     */\n    public void addRtpStreamListener(RtpStreamListener rtpStreamListener) {\n        this.rtpStreamListener = rtpStreamListener;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/RtpStreamListener.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\n/**\n * RTP Stream listener interface\n * \n * @author Deutsche Telekom\n */\npublic interface RtpStreamListener {\n    /**\n     * Invoked when the RTP stream was aborted.\n     */\n    void rtpStreamAborted();\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/VideoCaptureStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaInput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.VideoSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Video capture stream\n * \n * @author hlxn7157\n */\npublic class VideoCaptureStream extends MediaCaptureStream {\n    /**\n     * Constructor\n     * \n     * @param format Input format\n     * @param player Media player\n     */\n    public VideoCaptureStream(Format format, MediaInput player) {\n        super(format, player);\n    }\n\n    /**\n     * Read from the stream\n     * \n     * @return Buffer\n     * @throws Exception\n     */\n    public Buffer read() throws Exception {\n        // Read a new sample from the media player\n        VideoSample sample = (VideoSample) getPlayer().readSample();\n        if (sample == null) {\n            return null;\n        }\n\n        // Create a buffer\n        buffer.setData(sample.getData());\n        buffer.setLength(sample.getLength());\n        buffer.setFormat(getFormat());\n        buffer.setSequenceNumber(seqNo++);\n        if (sample.isMarker()) {\n            buffer.setFlags(Buffer.FLAG_RTP_MARKER);\n        }\n        buffer.setTimeStamp(sample.getTimeStamp());\n        buffer.setVideoOrientation(sample.getVideoOrientation());\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/stream/VideoRendererStream.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.stream;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.MediaOutput;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.media.VideoSample;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.util.Buffer;\n\n/**\n * Video renderer stream\n * \n * @author hlxn7157\n */\npublic class VideoRendererStream extends MediaRendererStream {\n    /**\n     * Constructor\n     * \n     * @param renderer Media renderer\n     */\n    public VideoRendererStream(MediaOutput renderer) {\n        super(renderer);\n    }\n\n    /**\n     * Write to the stream without blocking\n     * \n     * @param buffer Input buffer\n     * @throws Exception\n     */\n    public void write(Buffer buffer) throws Exception {\n        VideoSample sample = new VideoSample((byte[]) buffer.getData(), buffer.getTimeStamp(),\n                buffer.getSequenceNumber(), buffer.getVideoOrientation());\n        getRenderer().writeSample(sample);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/AndroidDatagramConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.DatagramSocket;\nimport java.net.InetAddress;\n\n/**\n * Android datagram server connection\n * \n * @author Jean-Marc AUFFRET\n */\npublic class AndroidDatagramConnection implements DatagramConnection {\n    /**\n     * Datagram connection\n     */\n    private DatagramSocket connection = null;\n\n    /**\n     * Datagram Packet\n     */\n    private DatagramPacket packet = null;\n\n    /**\n     * Connection timeout\n     */\n    private int timeout = 0;\n\n    /**\n     * Constructor\n     */\n    public AndroidDatagramConnection() {\n        packet = new DatagramPacket(new byte[DatagramConnection.DEFAULT_DATAGRAM_SIZE],\n                DatagramConnection.DEFAULT_DATAGRAM_SIZE);\n    }\n\n    /**\n     * Constructor\n     * \n     * @param timeout SO Timeout\n     */\n    public AndroidDatagramConnection(int timeout) {\n        this();\n        this.timeout = timeout;\n    }\n\n    /**\n     * Open the datagram connection\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException {\n        connection = new DatagramSocket();\n        connection.setSoTimeout(timeout);\n    }\n\n    /**\n     * Open the datagram connection\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException {\n        connection = new DatagramSocket(port);\n        connection.setSoTimeout(timeout);\n    }\n\n    /**\n     * Close the datagram connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException {\n        if (connection != null) {\n            connection.close();\n            connection = null;\n        }\n    }\n\n    /**\n     * Receive data with a specific buffer size\n     * \n     * @return Byte array\n     * @throws IOException\n     */\n    public byte[] receive() throws IOException {\n        if (connection != null) {\n            packet.setLength(DatagramConnection.DEFAULT_DATAGRAM_SIZE);\n            connection.receive(packet);\n\n            int packetLength = packet.getLength();\n            byte[] data = new byte[packetLength];\n            System.arraycopy(packet.getData(), 0, data, 0, packetLength);\n            return data;\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n\n    /**\n     * Send data\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @param data Data as byte array\n     * @throws IOException\n     */\n    public void send(String remoteAddr, int remotePort, byte[] data) throws IOException {\n        if (data == null) {\n            return;\n        }\n\n        if (connection != null) {\n            InetAddress address = InetAddress.getByName(remoteAddr);\n            DatagramPacket packet = new DatagramPacket(data, data.length, address, remotePort);\n            connection.send(packet);\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n\n    /**\n     * Returns the local address\n     * \n     * @return Address\n     * @throws IOException\n     */\n    public String getLocalAddress() throws IOException {\n        if ((connection != null) && (connection.getLocalAddress() != null)) {\n            return connection.getLocalAddress().getHostAddress();\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n\n    /**\n     * Returns the local port\n     * \n     * @return Port\n     * @throws IOException\n     */\n    public int getLocalPort() throws IOException {\n        if (connection != null) {\n            return connection.getLocalPort();\n        } else {\n            throw new IOException(\"Connection not openned\");\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/Buffer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.Format;\nimport com.orangelabs.rcs.core.ims.protocol.rtp.format.video.VideoOrientation;\n\n/**\n * Buffer\n * \n * @author jexa7410\n */\npublic class Buffer {\n    /**\n     * Indicates that this buffer marks the end of media for the data stream\n     */\n    public final static int FLAG_EOM = (1 << 0);\n\n    /**\n     * Indicates that the media data should be ignored\n     */\n    public final static int FLAG_DISCARD = (1 << 1);\n\n    /**\n     * This is a marker bit for RTP\n     */\n    public final static int FLAG_RTP_MARKER = (1 << 11);\n\n    /**\n     * Indicates that the buffer carries a time stamp that's in RTP (NTP) time units\n     */\n    public final static int FLAG_RTP_TIME = (1 << 12);\n\n    /**\n     * Default value if the time stamp of the media is not known\n     */\n    public final static long TIME_UNKNOWN = -1L;\n\n    /**\n     * Default value if the sequence number is not known\n     */\n    public final static long SEQUENCE_UNKNOWN = Long.MAX_VALUE - 1;\n\n    /**\n     * The time stamp of the data in nanoseconds\n     */\n    protected long timeStamp = TIME_UNKNOWN;\n\n    /**\n     * The format of the data chunk\n     */\n    protected Format format = null;\n\n    /**\n     * States how many samples are valid in the array of data\n     */\n    protected int length = 0;\n\n    /**\n     * Starting point (offset) into the array where the valid data begins\n     */\n    protected int offset = 0;\n\n    /**\n     * A flag mask that describes the boolean attributes of the buffer\n     */\n    protected int flags = 0;\n\n    /**\n     * The duration of the data in the buffer in nanoseconds\n     */\n    protected long duration = TIME_UNKNOWN;\n\n    /**\n     * Media data chunk\n     */\n    protected Object data = null;\n\n    /**\n     * The sequence number\n     */\n    protected long sequenceNumber = SEQUENCE_UNKNOWN;\n\n    /**\n     * The array of buffer fragments\n     */\n    protected Buffer[] fragments = null;\n\n    /**\n     * The size of used items from array of buffer fragments\n     */\n    protected int fragmentsSize = 0;\n\n    /**\n     * Video orientation\n     */\n    private VideoOrientation videoOrientation;\n\n    /**\n     * Get the data format\n     * \n     * @return Format\n     */\n    public Format getFormat() {\n        return format;\n    }\n\n    /**\n     * Set the data format\n     * \n     * @param format New format\n     */\n    public void setFormat(Format format) {\n        this.format = format;\n    }\n\n    /**\n     * Get the flag mask\n     * \n     * @return Flag\n     */\n    public int getFlags() {\n        return flags;\n    }\n\n    /**\n     * Set the flag mask\n     * \n     * @param flags New flags\n     */\n    public void setFlags(int flags) {\n        this.flags = flags;\n    }\n\n    /**\n     * Check if it's the end of the media stream\n     * \n     * @return Boolean\n     */\n    public boolean isEOM() {\n        return (flags & FLAG_EOM) != 0;\n    }\n\n    /**\n     * Set the EOM flag\n     * \n     * @param eom EOM status flag\n     */\n    public void setEOM(boolean eom) {\n        if (eom)\n            flags |= FLAG_EOM;\n        else\n            flags &= ~FLAG_EOM;\n    }\n\n    /**\n     * Check if the RTP marker is set\n     * \n     * @return Boolean\n     */\n    public boolean isRTPMarkerSet() {\n        return (flags & FLAG_RTP_MARKER) != 0;\n    }\n\n    /**\n     * Set the RTP marker\n     * \n     * @param marker RTP marker flag\n     */\n    public void setRTPMarker(boolean marker) {\n        if (marker)\n            flags |= FLAG_RTP_MARKER;\n        else\n            flags &= ~FLAG_RTP_MARKER;\n    }\n\n    /**\n     * Check whether or not this buffer is to be discarded\n     * \n     * @return Boolean\n     */\n    public boolean isDiscard() {\n        return (flags & FLAG_DISCARD) != 0;\n    }\n\n    /**\n     * Set the discard flag\n     * \n     * @param discard Discard flag.\n     */\n    public void setDiscard(boolean discard) {\n        if (discard)\n            flags |= FLAG_DISCARD;\n        else\n            flags &= ~FLAG_DISCARD;\n    }\n\n    /**\n     * Get the internal data that holds the media chunk\n     * \n     * @return Data\n     */\n    public Object getData() {\n        return data;\n    }\n\n    /**\n     * Set the internal data that holds the media chunk\n     * \n     * @param data Data\n     */\n    public void setData(Object data) {\n        this.data = data;\n    }\n\n    /**\n     * Get the length of the valid data in the buffer\n     * \n     * @return The length of the valid data\n     */\n    public int getLength() {\n        return length;\n    }\n\n    /**\n     * Set the length of the valid data stored in the buffer\n     * \n     * @param length The length of the valid data\n     */\n    public void setLength(int length) {\n        this.length = length;\n    }\n\n    /**\n     * Get the offset into the data array where the valid data begins\n     * \n     * @return Offset\n     */\n    public int getOffset() {\n        return offset;\n    }\n\n    /**\n     * Set the offset\n     * \n     * @param offset The starting point for the valid data\n     */\n    public void setOffset(int offset) {\n        this.offset = offset;\n    }\n\n    /**\n     * Get the time stamp\n     * \n     * @return Time stamp in nanoseconds.\n     */\n    public long getTimeStamp() {\n        return timeStamp;\n    }\n\n    /**\n     * Set the time stamp\n     * \n     * @param timeStamp Time stamp in nanoseconds\n     */\n    public void setTimeStamp(long timeStamp) {\n        this.timeStamp = timeStamp;\n    }\n\n    /**\n     * Get the duration\n     * \n     * @return Duration in nanoseconds\n     */\n    public long getDuration() {\n        return duration;\n    }\n\n    /**\n     * Set the duration\n     * \n     * @param duration Duration\n     */\n    public void setDuration(long duration) {\n        this.duration = duration;\n    }\n\n    /**\n     * Set the sequence number\n     * \n     * @param number Sequence number\n     */\n    public void setSequenceNumber(long number) {\n        sequenceNumber = number;\n    }\n\n    /**\n     * Ges the sequence number\n     * \n     * @return Sequence number\n     */\n    public long getSequenceNumber() {\n        return sequenceNumber;\n    }\n\n    /**\n     * Get the buffer fragments\n     * \n     * @return the fragments\n     */\n    public Buffer[] getFragments() {\n        return fragments;\n    }\n\n    /**\n     * Set the buffer fragments\n     * \n     * @param fragments the fragments to set\n     */\n    public void setFragments(Buffer[] fragments) {\n        this.fragments = fragments;\n    }\n\n    /**\n     * Get the buffer fragments size\n     * \n     * @return the fragments size\n     */\n    public int getFragmentsSize() {\n        return fragmentsSize;\n    }\n\n    /**\n     * Set the buffer fragments size\n     * \n     * @param fragments the fragments size to set\n     */\n    public void setFragmentsSize(int fragmentsSize) {\n        this.fragmentsSize = fragmentsSize;\n    }\n\n    /**\n     * Get the sub buffers\n     * \n     * @return <code>true</code> in case of fragmented buffer, otherwise <code>false</code>\n     */\n    public boolean isFragmented() {\n        return (fragments != null && fragments.length > 0 && fragmentsSize > 0);\n    }\n\n    /**\n     * Gets the VideoOrientation\n     * \n     * @return Video orientation\n     */\n    public VideoOrientation getVideoOrientation() {\n        return videoOrientation;\n    }\n\n    /**\n     * Sets the video orientation\n     * \n     * @param videoOrientation VideoOrientation\n     */\n    public void setVideoOrientation(VideoOrientation videoOrientation) {\n        this.videoOrientation = videoOrientation;\n    }\n\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/DatagramConnection.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\nimport java.io.IOException;\n\n/**\n * Datagram connection\n * \n * @author Jean-Marc AUFFRET\n */\npublic interface DatagramConnection {\n    /**\n     * Default datagram packet size\n     */\n    public static int DEFAULT_DATAGRAM_SIZE = 4096 * 8;\n\n    /**\n     * Open the datagram connection\n     * \n     * @throws IOException\n     */\n    public void open() throws IOException;\n\n    /**\n     * Open the datagram connection\n     * \n     * @param port Local port\n     * @throws IOException\n     */\n    public void open(int port) throws IOException;\n\n    /**\n     * Close the datagram connection\n     * \n     * @throws IOException\n     */\n    public void close() throws IOException;\n\n    /**\n     * Send data\n     * \n     * @param remoteAddr Remote address\n     * @param remotePort Remote port\n     * @param data Data as byte array\n     * @throws IOException\n     */\n    public void send(String remoteAddr, int remotePort, byte[] data) throws IOException;\n\n    /**\n     * Receive data\n     * \n     * @return Byte array\n     * @throws IOException\n     */\n    public byte[] receive() throws IOException;\n\n    /**\n     * Returns the local address\n     * \n     * @return Address\n     * @throws IOException\n     */\n    public String getLocalAddress() throws IOException;\n\n    /**\n     * Returns the local port\n     * \n     * @return Port\n     * @throws IOException\n     */\n    public int getLocalPort() throws IOException;\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/FifoBuffer.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\nimport java.util.Vector;\n\n/**\n * FIFO buffer\n * \n * @author JM. Auffret\n */\npublic class FifoBuffer {\n    /**\n     * Number of objects in the buffer\n     */\n    private int nbObjects = 0;\n\n    /**\n     * Buffer of objects\n     */\n    private Vector<Object> fifo = new Vector<Object>();\n\n    /**\n     * Add an object in the buffer\n     * \n     * @param obj Message\n     */\n    public synchronized void addObject(Object obj) {\n        fifo.addElement(obj);\n        nbObjects++;\n        notifyAll();\n    }\n\n    /**\n     * Read an object in the buffer. This is a blocking method until an object is read.\n     * \n     * @return Object\n     */\n    public synchronized Object getObject() {\n        Object obj = null;\n        if (nbObjects == 0) {\n            try {\n                wait();\n            } catch (InterruptedException e) {\n                // Nothing to do\n            }\n        }\n        if (nbObjects != 0) {\n            obj = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            nbObjects--;\n            notifyAll();\n        }\n        return obj;\n    }\n\n    /**\n     * Read an object in the buffer. This is a blocking method until a timeout occurs or an object\n     * is read.\n     * \n     * @param timeout Timeout\n     * @return Message\n     */\n    public synchronized Object getObject(int timeout) {\n        Object obj = null;\n        if (nbObjects == 0) {\n            try {\n                wait(timeout);\n            } catch (InterruptedException e) {\n                // Nothing to do\n            }\n        }\n        if (nbObjects != 0) {\n            obj = fifo.elementAt(0);\n            fifo.removeElementAt(0);\n            nbObjects--;\n            notifyAll();\n        }\n        return obj;\n    }\n\n    /**\n     * Close the buffer\n     */\n    public synchronized void close() {\n        // Free the semaphore\n        this.notifyAll();\n    }\n\n    /**\n     * Get FIFO size\n     * \n     * @return size of the FIFO\n     */\n    public int size() {\n        return fifo.size();\n    }\n\n    /**\n     * clean FIFO\n     * \n     * @return size of the FIFO\n     */\n    public void clean(int size) {\n        if (fifo.size() > size) {\n            while (size > 0) {\n                fifo.removeElementAt(0);\n                nbObjects--;\n                size--;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/HexadecimalUtils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\n/**\n * Hexadecimal utils\n * \n * @author Deutsche Telekom AG\n */\npublic class HexadecimalUtils {\n\n    /**\n     * Decode hex string to a byte array\n     * \n     * @param s hexadecimal encoded string\n     * @return array of bytes\n     */\n    public static byte[] hexStringToByteArray(String s) {\n\n        if (s == null || s.length() == 0) {\n            return null;\n        }\n\n        int len = s.length();\n\n        // '111' is not a valid hex encoding.\n        if (len % 2 != 0) {\n            throw new IllegalArgumentException();\n        }\n\n        byte[] data = new byte[len / 2];\n        for (int i = 0; i < len; i += 2) {\n            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)\n                    + Character.digit(s.charAt(i + 1), 16));\n        }\n        return data;\n    }\n\n    /**\n     * Convert byte array into Hexadecimal string\n     * \n     * @param bytes\n     * @return {@link String} if valid byte array, otherwise <code>null</code>\n     */\n    public static String byteArrayToHexString(byte[] bytes) {\n\n        if (bytes == null || bytes.length == 0) {\n            return null;\n        }\n\n        final char[] hexArray = {\n                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\n        };\n        char[] hexChars = new char[bytes.length * 2];\n        int value;\n        for (int j = 0; j < bytes.length; j++) {\n            value = bytes[j] & 0xFF;\n            hexChars[j * 2] = hexArray[value >>> 4];\n            hexChars[j * 2 + 1] = hexArray[value & 0x0F];\n        }\n        return new String(hexChars);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/NetworkRessourceManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\nimport java.io.IOException;\n\n/**\n * Network ressource manager\n * \n * @author Jean-Marc AUFFRET\n */\npublic class NetworkRessourceManager {\n    /**\n     * Default RTP port base\n     */\n    public static final int DEFAULT_LOCAL_RTP_PORT_BASE = 5000;\n\n    /**\n     * Generate a default free RTP port number\n     * \n     * @return Local RTP port\n     */\n    public static synchronized int generateLocalRtpPort() {\n        return generateLocalUdpPort(DEFAULT_LOCAL_RTP_PORT_BASE);\n    }\n\n    /**\n     * Generate a free UDP port number from a specific port base\n     * \n     * @param portBase UDP port base\n     * @return Local UDP port\n     */\n    private static int generateLocalUdpPort(int portBase) {\n        int resp = -1;\n        int port = portBase;\n        while ((resp == -1) && (port < Integer.MAX_VALUE)) {\n            if (isLocalUdpPortFree(port)) {\n                // Free UDP port found\n                resp = port;\n            } else {\n                // +2 needed for RTCP port\n                port += 2;\n            }\n        }\n        return resp;\n    }\n\n    /**\n     * Test if the given local UDP port is really free (not used by other applications)\n     * \n     * @param port Port to check\n     * @return Boolean\n     */\n    private static boolean isLocalUdpPortFree(int port) {\n        boolean res = false;\n        try {\n            DatagramConnection conn = NetworkRessourceManager.createDatagramConnection();\n            conn.open(port);\n            conn.close();\n            res = true;\n        } catch (IOException e) {\n            res = false;\n        }\n        return res;\n    }\n\n    /**\n     * Create a datagram connection\n     * \n     * @return Datagram connection\n     */\n    public static DatagramConnection createDatagramConnection() {\n        return new AndroidDatagramConnection();\n    }\n\n    /**\n     * Create a datagram connection with a specific SO timeout\n     * \n     * @param timeout SO timeout\n     * @return Datagram connection\n     */\n    public static DatagramConnection createDatagramConnection(int timeout) {\n        return new AndroidDatagramConnection(timeout);\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/Packet.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\n/**\n * Generic packet\n * \n * @author jexa7410\n */\npublic class Packet {\n    /**\n     * Data\n     */\n    public byte[] data;\n\n    /**\n     * Packet length\n     */\n    public int length;\n\n    /**\n     * Offset\n     */\n    public int offset;\n\n    /**\n     * Received at\n     */\n    public long receivedAt;\n\n    /**\n     * Constructor\n     */\n    public Packet() {\n    }\n\n    /**\n     * Constructor\n     * \n     * @param packet Packet\n     */\n    public Packet(Packet packet) {\n        data = packet.data;\n        length = packet.length;\n        offset = packet.offset;\n        receivedAt = packet.receivedAt;\n    }\n}\n"
  },
  {
    "path": "mediaplayer/src/com/orangelabs/rcs/core/ims/protocol/rtp/util/SystemTimeBase.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.core.ims.protocol.rtp.util;\n\n/**\n * Time base\n */\npublic class SystemTimeBase {\n\n    /**\n     * Offset time (start-up time)\n     */\n    private static long offset = System.currentTimeMillis() * 1000000L;\n\n    /**\n     * Returns a time base value in nanoseconds\n     * \n     * @return Time\n     */\n    public long getTime() {\n        return (System.currentTimeMillis() * 1000000L) - offset;\n    }\n}\n"
  },
  {
    "path": "samples/api/extension/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.services.rcs.samples.extension\"\n    android:versionCode=\"1\"\n    android:versionName=\"2.0\" >\n\n\t\n\t<uses-sdk android:minSdkVersion=\"12\"\n\t\tandroid:targetSdkVersion=\"22\"/>\n\t\n    <application android:icon=\"@drawable/app_icon\" android:label=\"@string/label_app_name\">\n        <meta-data android:name=\"com.gsma.services.rcs.capability.EXTENSION\"\n             android:value=\"ext.demo1;mnc01.mcc208.demo2;gsma.demo3\" />\n        \n        <activity android:name=\".Main\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n</manifest>\n"
  },
  {
    "path": "samples/api/extension/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "samples/api/extension/README.md",
    "content": "# RCS extension\n\nThis application declares some RCS extensions in its manifest file.\n\n##Build instruction:\n\n<code>../../gradlew :extension:build</code>\n"
  },
  {
    "path": "samples/api/extension/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.gsma.services.rcs.samples.extension\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"2.0\"\n        archivesBaseName = \"extension\"\n    }\n}\n"
  },
  {
    "path": "samples/api/extension/default.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system use,\n# \"build.properties\", and override values to adapt the script to your\n# project structure.\n\n# Project target.\ntarget=android-8\n"
  },
  {
    "path": "samples/api/extension/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "samples/api/extension/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-23\n"
  },
  {
    "path": "samples/api/extension/res/layout/main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    >\n    <TextView android:text=\"@string/label_app_desc\"\n\t\tandroid:layout_marginRight=\"5dip\"\n\t\tandroid:layout_marginLeft=\"5dip\"\n\t\tandroid:layout_width=\"fill_parent\"\n\t\tandroid:layout_height=\"wrap_content\"\n     \tandroid:gravity=\"center\"/>\n</LinearLayout>\n"
  },
  {
    "path": "samples/api/extension/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"label_app_name\">Capabilities extension demo</string>\n    <string name=\"label_app_desc\">Demo which demonstrates how to define a new capabilities or extension for a new service. See the Manifest file of the application where the extension is defined.</string>\n</resources>\n"
  },
  {
    "path": "samples/api/extension/src/com/gsma/services/rcs/samples/extension/Main.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.services.rcs.samples.extension;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\npublic class Main extends Activity {\n    /** Called when the activity is first created. */\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.main);\n    }\n}\n"
  },
  {
    "path": "samples/api/tts/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      package=\"com.orangelabs.rcs.tts\"\n      android:versionCode=\"1\"\n      android:versionName=\"1.0\">\n\n\t<uses-sdk android:minSdkVersion=\"12\"\n\t\tandroid:targetSdkVersion=\"23\"/>\n\n    <uses-permission android:name=\"android.permission.READ_CONTACTS\" />\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\" />\n\n    <application android:icon=\"@drawable/app_icon\" android:label=\"@string/app_name\">\n        <activity android:name=\".Main\" android:label=\"@string/app_name\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <service android:name=\".PlayTextToSpeech\" />\n\n        <receiver android:name=\"com.orangelabs.rcs.tts.ChatEvent\">\n            <intent-filter>\n\t\t    \t<action android:name=\"com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE\"/>\n            </intent-filter>\n        </receiver>\n\n    </application>\n\n</manifest> \n"
  },
  {
    "path": "samples/api/tts/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "samples/api/tts/README.md",
    "content": "# RCS sample tts\n\nTBC\n\n##Build instruction:\n\n<code>../../gradlew :tts:build</code>\n\nAdditional steps for Eclipse compatibility:\n\n<code>ant libs</code>\n\nThis will create the following jar files under the \"libs\" folder:\n- api.jar\n"
  },
  {
    "path": "samples/api/tts/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.orangelabs.rcs.tts\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"2.0\"\n        archivesBaseName = \"tts\"\n    }\n}\n\ndependencies {\n    compile project(':api')\n    compile 'com.android.support:support-v4:25.0.1'\n}\n\n//Below install dependecy was added to always install RCS service before\n//a RCS client to secure that Android handles RCS permissions correctly.\ntask installServiceFirst(dependsOn: ':core:installDebug') << {\n    println 'RCS core service was installed first!'\n}\ntasks.whenTaskAdded { task ->\n    if (task.name == 'installDebug') {\n        task.dependsOn installServiceFirst\n    }\n}"
  },
  {
    "path": "samples/api/tts/build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"tts\" default=\"help\">\n\n\t<!-- This script to populate ./libs folder with generated jar files for building compatibility with Eclipse.\n\tThis script must be executed after dependent libraries have been generated by gradle.\n\tThis script must be removed after migration to Android Studio.\n\t-->\n\t<property name=\"terminal.root\" value=\".\" />\n\t<property name=\"terminal.lib_dst\" value=\"${terminal.root}/libs\" />\n\t<property name=\"terminal.lib_src1\" value=\"${terminal.root}/../../../libs/api/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.target1\" value=\"api.jar\" />\n\n\t<target name=\"libs\">\n\t\t<echo>Copy ${terminal.target1} file</echo>\n\t\t<copy file=\"${terminal.lib_src1}\" tofile=\"${terminal.lib_dst}/${terminal.target1}\" />\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<echo>Delete library files</echo>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target1}\"/>\n\t</target>\n\n\t<target name=\"all\" depends=\"clean,libs\" />\n\n\t<target name=\"help\">\n\t\t<echo>Library Ant Build. Available targets:</echo>\n\t\t<echo> help: Displays this help.</echo>\n\t\t<echo> clean: Removes output files created by other targets.</echo>\n\t\t<echo> libs: Generate input libraries.</echo>\n\t\t<echo> all: Deletes then copy input libraries.</echo>\n\t</target>\n\n</project>\n"
  },
  {
    "path": "samples/api/tts/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "samples/api/tts/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-23\n"
  },
  {
    "path": "samples/api/tts/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">TTS</string>\n    <string name=\"app_title\">Text-To-Speech</string>\n    <string name=\"label_activate\">Chat messages</string>\n\t<string name=\"label_summary_activate_on\">Select to turn off the speech synthesis</string>\n\t<string name=\"label_summary_activate_off\">Select to turn on the speech synthesis</string>\n\t<string name=\"label_new_msg\">New chat</string>\n</resources>\n"
  },
  {
    "path": "samples/api/tts/res/xml/tts_preferences.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n\t<CheckBoxPreference\n\t\tandroid:key=\"activate\"\n\t\tandroid:title=\"@string/label_activate\"\n\t\tandroid:summaryOn=\"@string/label_summary_activate_on\"\n\t\tandroid:summaryOff=\"@string/label_summary_activate_off\"/>\n    \n</PreferenceScreen>"
  },
  {
    "path": "samples/api/tts/src/com/orangelabs/rcs/tts/ChatEvent.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.tts;\n\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.OneToOneChatIntent;\n\nimport android.app.Activity;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.SharedPreferences;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.text.TextUtils;\n\nimport java.util.ArrayList;\n\n/**\n * Chat invitation event receiver\n * \n * @author jexa7410\n */\npublic class ChatEvent extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        // Check activation state before to continue\n        SharedPreferences preferences = context.getSharedPreferences(Registry.REGISTRY,\n                Activity.MODE_PRIVATE);\n        boolean flag = Registry.readBoolean(preferences, Registry.ACTIVATE_TTS, false);\n        if (flag) {\n            // Get the chat message ID from the Intent\n            String msgId = intent.getStringExtra(OneToOneChatIntent.EXTRA_MESSAGE_ID);\n\n            // Get the message content associated to the message ID from the database\n            Cursor cursor = null;\n            String content = null;\n            try {\n                cursor = context.getContentResolver().query(Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, msgId),\n                        null, null, null, null);\n                if (!cursor.moveToFirst()) {\n                    // Failed to find message from its ID\n                    return;\n                }\n                content = cursor.getString(cursor.getColumnIndexOrThrow(ChatLog.Message.CONTENT));\n            } finally {\n                if (cursor != null) {\n                    cursor.close();\n                }\n            }            \n            \n            if (!TextUtils.isEmpty(content)) {\n                // Play TTS on the chat message\n                ArrayList<String> messages = new ArrayList<String>();\n                messages.add(context.getString(R.string.label_new_msg));\n                messages.add(content);\n                Intent serviceIntent = new Intent(context, PlayTextToSpeech.class);\n                serviceIntent.putStringArrayListExtra(\"messages\", messages);\n                context.startService(serviceIntent);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "samples/api/tts/src/com/orangelabs/rcs/tts/Main.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.tts;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.content.SharedPreferences;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.preference.CheckBoxPreference;\nimport android.preference.Preference;\nimport android.preference.PreferenceActivity;\nimport android.util.Log;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Text-To-Speech for incoming chat and group chat invitation\n * \n * @author jexa7410\n */\npublic class Main extends PreferenceActivity implements Preference.OnPreferenceChangeListener {\n\n    private CheckBoxPreference activateCheck;\n    /**\n     * List of permissions needed for service Just need to ask one permission per dangerous group\n     */\n    private static final Set<String> sAllPermissionsList = new HashSet<>(\n            Arrays.asList(Manifest.permission.READ_CONTACTS));\n\n    private static final int MY_PERMISSION_REQUEST_ALL = 5428;\n    private Set<String> mPermissionsToAsk;\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        askPermissions();\n        // Set title\n        setTitle(R.string.app_title);\n\n        // Set preferences\n        addPreferencesFromResource(R.xml.tts_preferences);\n        activateCheck = (CheckBoxPreference) getPreferenceScreen().findPreference(\"activate\");\n        activateCheck.setOnPreferenceChangeListener(this);\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n\n        // Load preferences\n        SharedPreferences preferences = getApplicationContext().getSharedPreferences(\n                Registry.REGISTRY, Activity.MODE_PRIVATE);\n        boolean flag = Registry.readBoolean(preferences, Registry.ACTIVATE_TTS, false);\n        activateCheck.setChecked(flag);\n    }\n\n    public boolean onPreferenceChange(Preference preference, Object objValue) {\n        // Update preferences\n        SharedPreferences preferences = getApplicationContext().getSharedPreferences(\n                Registry.REGISTRY, Activity.MODE_PRIVATE);\n        if (preference.getKey().equals(\"activate\")) {\n            boolean flag = !activateCheck.isChecked();\n            Registry.writeBoolean(preferences, Registry.ACTIVATE_TTS, flag);\n        }\n        return true;\n    }\n\n    /**\n     * Main function to ask permissions\n     */\n    private void askPermissions() {\n        mPermissionsToAsk = getNotGrantedPermissions();\n        if (mPermissionsToAsk.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            requestPermissions(mPermissionsToAsk.toArray(new String[mPermissionsToAsk.size()]),\n                    MY_PERMISSION_REQUEST_ALL);\n        }\n    }\n\n    /**\n     * Check all permissions's status\n     * \n     * @return Set of permissions that are not granted\n     */\n    private Set<String> getNotGrantedPermissions() {\n        Set<String> permissionsToAsk = new HashSet<>();\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            return permissionsToAsk;\n        }\n        for (String permission : sAllPermissionsList) {\n            if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(permission)) {\n                permissionsToAsk.add(permission);\n            }\n        }\n        return permissionsToAsk;\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        switch (requestCode) {\n            case MY_PERMISSION_REQUEST_ALL:\n                Set<String> grantedPermissions = new HashSet<>();\n                for (int i = 0; i < permissions.length; i++) {\n                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {\n                        grantedPermissions.add(permissions[i]);\n                    } else if (grantResults[i] == PackageManager.PERMISSION_DENIED) {\n                        Log.w(\"Permissions\", \"Permission Denied: \" + permissions[i]);\n                    }\n                }\n                if (!grantedPermissions.equals(mPermissionsToAsk)) {\n                    finish();\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/api/tts/src/com/orangelabs/rcs/tts/PlayTextToSpeech.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.tts;\n\nimport java.util.ArrayList;\n\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.IBinder;\nimport android.speech.tts.TextToSpeech;\nimport android.speech.tts.TextToSpeech.OnInitListener;\nimport android.util.Log;\n\n/**\n * Play text-to-speech\n * \n * @author jexa7410\n */\npublic class PlayTextToSpeech extends Service implements OnInitListener {\n    private static final String TAG = \"PlayTextToSpeech\";\n\n    /**\n     * TTS engine\n     */\n    private TextToSpeech tts = null;\n\n    /**\n     * List of messages to be played\n     */\n    private ArrayList<String> messages = null;\n\n    @Override\n    public void onCreate() {\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public void onStart(Intent intent, int startId) {\n        Log.v(TAG, \"Start TTS\");\n\n        // Get parameters\n        messages = intent.getStringArrayListExtra(\"messages\");\n\n        // Instanciate the TTS engine\n        try {\n            tts = new TextToSpeech(getApplicationContext(), this);\n        } catch (Exception e) {\n            Log.v(TAG, \"Can't instanciate TTS engine\");\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n\n        // Deallocate TTS engine\n        Log.v(TAG, \"Shutdown TTS\");\n        if (tts != null) {\n            tts.shutdown();\n        }\n    }\n\n    /**\n     * TTS engine init\n     * \n     * @param status Status\n     */\n    public void onInit(int status) {\n        if ((tts != null) && (status == TextToSpeech.SUCCESS)) {\n            Log.v(TAG, \"TTS engine initialized with success\");\n            if ((messages != null) && (messages.size() > 0)) {\n                // Speak\n                Log.v(TAG, \"Start TTS session: play \" + messages.size() + \" messages\");\n                tts.speak(messages.get(0), TextToSpeech.QUEUE_FLUSH, null);\n                if (messages.size() > 1) {\n                    for (int i = 1; i < messages.size(); i++) {\n                        tts.speak(messages.get(i), TextToSpeech.QUEUE_ADD, null);\n                    }\n                }\n\n                // Wait end of speech\n                while (tts.isSpeaking()) {\n                    try {\n                        Thread.sleep(500);\n                    } catch (Exception e) {\n                    }\n                }\n\n                // Stop the service\n                Log.v(TAG, \"Exit TTS session\");\n                this.stopSelf();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "samples/api/tts/src/com/orangelabs/rcs/tts/Registry.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.orangelabs.rcs.tts;\n\nimport android.content.SharedPreferences;\n\n/**\n * Application registry\n * \n * @author jexa7410\n */\npublic class Registry {\n    /**\n     * Registry name\n     */\n    public static final String REGISTRY = \"RcsTTS\";\n\n    /**\n     * Registry key names\n     */\n    public static final String ACTIVATE_TTS = \"Activated\";\n\n    /**\n     * Read a string value in the registry\n     * \n     * @param preferences Preferences\n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return String\n     */\n    public static String readString(SharedPreferences preferences, String key, String defaultValue) {\n        return preferences.getString(key, defaultValue);\n    }\n\n    /**\n     * Write a string value in the registry\n     * \n     * @param preferences Preferences\n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public static void writeString(SharedPreferences preferences, String key, String value) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putString(key, value);\n        editor.commit();\n    }\n\n    /**\n     * Read a boolean value in the registry\n     * \n     * @param preferences Preferences\n     * @param key Key name to be read\n     * @param defaultValue Default value\n     * @return Boolean\n     */\n    public static boolean readBoolean(SharedPreferences preferences, String key,\n            boolean defaultValue) {\n        return preferences.getBoolean(key, defaultValue);\n    }\n\n    /**\n     * Write a boolean value in the registry\n     * \n     * @param preferences Preferences\n     * @param key Key name to be updated\n     * @param value New value\n     */\n    public static void writeBoolean(SharedPreferences preferences, String key, boolean value) {\n        SharedPreferences.Editor editor = preferences.edit();\n        editor.putBoolean(key, value);\n        editor.commit();\n    }\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':bouncycastle'\ninclude ':api_cnx'\ninclude ':nist_sip'\ninclude ':api'\ninclude ':core'\ninclude ':mediaplayer'\ninclude ':RI'\ninclude ':settings'\ninclude ':notification'\ninclude ':provisioning'\ninclude ':extension'\ninclude ':tts'\ninclude ':cts_provider'\ninclude ':cts_signature'\n\n\n// Project location (if not directly below root)\nproject(':bouncycastle').projectDir=new File('libs/bouncycastle')\nproject(':nist_sip').projectDir=new File('libs/nist_sip')\nproject(':settings').projectDir=new File('tools/settings')\nproject(':notification').projectDir=new File('tools/notification')\nproject(':provisioning').projectDir=new File('tools/provisioning')\nproject(':extension').projectDir=new File('samples/api/extension')\nproject(':tts').projectDir=new File('samples/api/tts')\nproject(':api').projectDir=new File('libs/api')\nproject(':api_cnx').projectDir=new File('libs/api_cnx')\nproject(':cts_provider').projectDir=new File('tests/cts/provider')\nproject(':cts_signature').projectDir=new File('tests/cts/signature')\n"
  },
  {
    "path": "studio/README.md",
    "content": "# Android Studio\n\nHow to set up the project under Android Studio.\n\n* Check that your JDK location is **JDK 1.7** (*File -> Project Structure*)\n* From Android Studio menu \"*File -> New -> Import Project*\" select the root directory of your RCSJTA GIT branch.\n\n**Warning: under Android Studio you need also to remove the extension\"rcs\" or \"RCS\" from the list \"Ignore files and folder\" in the menu \"Settings / Editor / File Types\".**\n\n<img src='https://github.com/android-rcs/rcsjta/blob/master/studio/ignored.jpg'>\n\n\n* Import the Eclipse code formatter plugin to format Java code accroding to project's rules defined in the directory *eclipse*.\n\nFrom \"*File -> Settings*\" menu choose *Plugins* and click \"*-> Install JetBrains plugin...*\". Find and install the plugin \"Eclipse Code Formatter\".\n\nAfter installation plugin, select \"*File -> Settings*\" again and navigate to \"*Other Settings -> Eclipse Code Formatter*\" to enable \"Use the Eclipse code formatter\". \n\nIn \"Eclipse java Formatter config file\" click browse and find path to \"**eclipse/android-eclipse-formatting.xml**\". After configuration press Apply.\n\nFinally edit the manual configuration for \"*Import order*\" to set \"**com.gsma;com;android;dalvik;gov;junit;libcore;net;org;java;javax**\" and click Enable.\n\nNow you can use formatter in file editor: CTRL+ALT+L.\n\nThe \"Eclipse Code Formatter\" configuration in the \"Settings\" window should look like this:\n\n<img src='https://github.com/android-rcs/rcsjta/blob/master/studio/AndroidStudioFormatCode.jpg'>\n"
  },
  {
    "path": "templates-sdk/assets/android-developer-core.css",
    "content": "/* file: android-developer-core.css\n   author: smain\n   date: september 2008\n   info: core developer styles (developer.android.com)\n*/\n\n\n/* RESET STYLES */\n\nhtml,body,div,h1,h2,h3,h4,h5,h6,p,img,\ndl,dt,dd,ol,ul,li,table,caption,tbody,\ntfoot,thead,tr,th,td,form,fieldset,\nembed,object,applet {\n  margin: 0;\n  padding: 0;\n  border: 0;\n}\n\n.rebox {\n  background:#daf3fc;\n  margin-bottom:1.5em;\n  -moz-border-radius:5px;\n  -webkit-border-radius:5px;\n}\n.rebox.lil p img {\n  display:block;\n  margin-bottom:2em;\n}\n\n.rebox .p {\n  padding:1.5em;\n  line-height:1.25em;\n}\n\n.p-r {\n  padding-right:1.5em;\n}\n\n.rebox h2, .rebox h3 {\n  font-size:16px;\n  color:#fff;\n  display:block;\n  background:url('/assets/images/rebox-gradient.gif') no-repeat center bottom #95c0d0;\n  padding:.5em .5em .5em .75em;\n  -moz-border-radius-topright:5px;\n  -moz-border-radius-topleft:5px;\n  -webkit-border-top-right-radius:5px;\n  -webkit-border-top-left-radius:5px;\n}\n\n.rebox.lil {\n}\n.rebox.lil img {\n  float:left;\n  margin:0 1em 0 0;\n  padding:0 0 3em 0;\n}\n\n.rebox.green {\n  background:#d4e9a9;\n}\n\n.rebox.green h2, .rebox.green h3 {\n  background:url('images/rebox-gradient-green.gif') no-repeat center bottom #aaca46;\n  font-weight:bold;\n}\n\n.rebox.green a:link, .rebox.green a:visited {\n  color:#360;\n}\n\n/* BASICS */\n\nhtml, body {\n  overflow:visible; /* keeps scrollbar off IE */\n  background-color:#fff;\n}\n\nbody {\n  font-family:arial,sans-serif;\n  color:#000;\n  font-size:13px;\n  color:#333;\n  background-image:url(images/bg_fade.jpg); \n  background-repeat:repeat-x;\n}\n\na, a code { \n  color:#006699;\n} \n\n\na:active,\na:active code { \n  color:#f00;\n} \n\na:visited,\na:visited code { \n  color:#006699;\n}\n\ninput, select,\ntextarea, option {\n  font-family:inherit;\n  font-size:inherit;\n  padding:0;\n  margin:0;\n}\n\noption {\n  padding:0 4px;\n}\n\np {\n  padding:0;\n  margin:0 0 1em;\n}\n\ncode, pre {\n  color:#007000;\n  font-family:monospace;\n  line-height:1em;\n}\n\nvar {\n  color:#007000;\n  font-style:italic;\n}\n\npre {\n  border:1px solid #ccc;\n  background-color:#fafafa;\n  padding:10px;\n  margin:0 0 1em 1em;\n  overflow:auto;\n  line-height:inherit; /* fixes vertical scrolling in webkit */\n}\n\nh1,h2,h3,h4,h5 {\n  margin:1em 0;\n  padding:0;\n}\n\np,ul,ol,dl,dd,dt,li {\n  line-height:1.3em;\n}\n\nul,ol {\n  margin:0 0 .8em;\n  padding:0 0 0 2em;\n}\n\nli {\n  padding:0 0 .5em;\n}\n\ndl {\n  margin:0 0 1em 0;\n  padding:0;\n}\n\ndt {  \n  margin:0;\n  padding:0;\n}\n\ndd {\n  margin:0 0 1em;\n  padding:0 0 0 2em;\n}\n\nli p {\n  margin:.5em 0 0;\n}\n\ndd p {\n  margin:1em 0 0;\n}\n\nli pre, li table, li img {\n  margin:.5em 0 0 1em;\n}\n\ndd pre, dd table, dd img {\n  margin:1em 0 0 1em;\n}\n\nli ul,\nli ol,\ndd ul,\ndd ol {\n  margin:0;\n  padding: 0 0 0 2em;\n}\n\nli li,\ndd li {\n  margin:0;\n  padding:.5em 0 0;\n}\n\ndl dl,\nol dl,\nul dl {\n  margin:0 0 1em;\n  padding:0;\n}\n\ntable {\n  font-size:1em;\n  margin:0 0 1em;\n  padding:0;\n  border-collapse:collapse;\n  border-width:0;\n  empty-cells:show;\n}\n\ntd,th {\n  border:1px solid #ccc;\n  padding:6px 12px;\n  text-align:left;\n  vertical-align:top;\n  background-color:inherit;\n}\n\nth {\n  background-color:#dee8f1;\n}\n\nhr.blue {\n  background-color:#DDF0F2;\n  border:none;\n  height:5px;\n  margin:20px 0 10px;\n}\n\n/* LAYOUT */\n#body-content {\n  /* \"Preliminary\" watermark for preview releases and interim builds.\n  background:transparent url(images/preliminary.png) repeat scroll 0 0;  */\n  margin:0;\n  position:relative;\n  width:100%;\n  display:inline-block;\n  background-color: rgb(249, 249, 249);\n}\n\n#header {\n  position:relative;\n  z-index:100;\n\nwidth: 1000px;\nmargin-left: 165px;\n}\n\n#headerLeft{\n  padding: 25px 0 0;\n}\n\n#headerLeft img{\n  height:50px;\n  width:65px;\n  margin-left: 35px;\n  vertical-align: middle;\n  margin-right: 10px;\n}\n#headerLeft a{\ncolor : black;\n\nfont-size:20px;\n}\n\n\n#headerRight {\nposition: absolute;\ntop: 87px;\nright: -15px;\n}\n\n/* Tabs in the header */\n#header ul {\n  list-style: none;\n  margin: 7px 0 0 35px;  \n  padding: 0;\n  height: 29px;\n}\n\n#header li {\n  float: left;\n  margin: 0px 2px 0px 0px;\n  padding:0;\n}\n\n#header li a {\n  text-decoration: none;\n  display: block;\n  background-image: url(images/bg_images_sprite.png);\n  background-position: 0 -58px;\n  background-repeat: no-repeat;\n  color: #666;\n  font-size: 13px;\n  font-weight: bold;\n  width: 94px;\n  height: 29px;\n  text-align: center;\n  margin: 0px;\n}\n\n#header li a:hover {\n  background-image: url(images/bg_images_sprite.png);\n  background-position: 0 -29px;\n  background-repeat: no-repeat;\n}\n\n#header li a span {\n  position:relative;\n  top:7px;\n}\n\n#header li a span+span {\n  display:none;\n}\n\n/* TAB HIGHLIGHTING */\n.home #home-link a,\n.guides #guides-link a,\n.samples #samples-link a,\n.source #source-link a,\n.download #download-link a,\n.faq #faq-link a,\n.tools #tools-link a,\n.tutorials #tutorials-link a,\n.videos #videos-link a {\n  background-image: url(images/bg_images_sprite.png);\n  background-position: 0 0;\n  background-repeat: no-repeat;\n  color: #fff;\n  font-weight: bold;\n  cursor:default;\n}\n\n.home #home-link a:hover,\n.guides #guides-link a:hover,\n.home #home-link a:hover,\n.samples #samples-link a:hover,\n.porting #porting-link a:hover,\n.source #source-link a:hover,\n.download #download-link a:hover,\n.faq #faq-link a:hover,\n.tools #tools-link a:hover,\n.tutorials #tutorials-link a:hover,\n.videos #videos-link  a:hover {\n  background-image: url(images/bg_images_sprite.png);\n  background-position: 0 0;\n}\n\n#headerLinks {\n  margin:10px 10px 0 0;\n  height:13px;\n  font-size: 11px;\n  vertical-align: top;\n}\n\n#headerLinks a {\n  color: #7FA9B5;\n}\n\n#headerLinks img {\n  vertical-align:middle;\n}\n\n#language {\n  margin:0 10px 0 4px;\n}\n\n#search {\n float:right;\n}\n\n/* main */\n\n#mainBodyFluid {\n  margin: 20px 10px;\n  color:#333;\n}\n\n#mainBodyFixed {\n  margin: 20px 10px;\n  color: #333;\n  width:930px;\n  position:relative;\n}\n\n#mainBodyFixed h3,\n#mainBodyFluid h3 {\n  color:#336666;\n  font-size:1.25em;\n  margin: 0em 0em 0em 0em;\n  padding-bottom:.5em;\n}\n\n#mainBodyFixed h2,\n#mainBodyFluid h2 { \n  color:#336666;\n  font-size:1.25em;\n  margin: 0;\n  padding-bottom:.5em;\n}\n\n#mainBodyFixed h1,\n#mainBodyFluid h1 { \n  color:#435A6E;\n  font-size:1.7em;\n  margin: 1em 0;\n}\n\n#mainBodyFixed .green,\n#mainBodyFluid .green,\n#jd-content .green { \n  color:#7BB026;\n  background-color:none;\n}\n\n#mainBodyLeft {\n  float: left;\n  width: 600px;\n  margin-right: 20px;  \n  color: #333;\n  position:relative;\n}\n\ndiv.indent {\n  margin-left: 40px;  \n  margin-right: 70px;\n}\n\n#mainBodyLeft p {\n  color: #333;\n  font-size: 13px;\n}\n\n#mainBodyLeft p.blue {\n  color: #669999;\n}\n\n#mainBodyLeft #communityDiv {\n  float: left;\n  background-image:url(images/bg_community_leftDiv.jpg);\n  background-repeat: no-repeat;\n  width: 581px;\n  height: 347px;\n  padding: 20px 0px 0px 20px;\n}\n\n#mainBodyRight {\n  float: left;\n  width: 300px;\n  color: #333;\n}\n\n#mainBodyRight p {\n  padding-right: 50px;\n  color: #333;\n}\n\n#mainBodyRight table {\n  width: 100%;\n}\n\n#mainBodyRight td {\n  border:0px solid #666;\n  padding:0px 5px;\n  text-align:left;\n}\n\n#mainBodyRight .blueBorderBox {\n  border:5px solid #ddf0f2;\n  padding:18px 18px 18px 18px;\n  text-align:left;\n}\n\n#mainBodyFixed .seperator {\n  background-image:url(images/hr_gray_side.jpg);\n  background-repeat:no-repeat;\n  width: 100%;\n  float: left;\n  clear: both;\n}\n\n#mainBodyBottom {\n  float: left;\n  width: 100%;\n  clear:both;\n  color: #333;\n}\n\n#mainBodyBottom .seperator {\n  background-image:url(images/hr_gray_main.jpg);\n  background-repeat:no-repeat;\n  width: 100%;\n  float: left;\n  clear: both;\n}\n\n/* Footer */\n#footer {\n  float: left;\n  width: 100%;\n  color: #aaa;\n  font-size: 11px;\n  margin:auto;\n  \n}\n\n#footer a {\n  color: #aaa;\n  font-size: 11px;\n}\n\n#footer a:hover {\n  text-decoration: underline;\n  color:#aaa;\n}\n\n#footerlinks {\n  margin-top:2px;\n}\n\n#footerlinks a,\n#footerlinks a:visited {\n  color:#006699;\n}\n\n#homeBottom td {\n  border:0px solid #666;\n  padding: 8px 18px 8px 18px;\n}\n\n#homeBottom table {\n  width: 100%;\n}\n\n\n#homeBottom {\n  padding: 0px 0px 0px 0px;\n  float: left;\n  width: 585px;\n  height: 165px;\n  background-image:url(images/home/bg_home_bottom.jpg);\n  background-repeat: no-repeat;\n}\n\n.groupTable {\n  width: 100%;\n}\n\n.groupTable th {\n  padding: 10px;\n  color: #ffffff;\n  background-color: #6D8293;\n  border: 2px solid #fff;\n}\n\n.groupTable td {\n  padding: 10px;\n  color: #333333;\n  background-color: #d9d9d9;\n  border: 2px solid #fff;\n}\n\n.groupTable .evenRow td {  \n  background-color: #ededed;\n}\n\nspan.BigBlue {\n  color:#336666;\n  font-size:1.25em;\n  margin: 0em 0em 0em 0em;\n  padding-bottom:.5em;\n  font-weight: bold;\n}\n\nspan.emBlue {\n  color: #336666;\n  font-style:italic;\n}\n\n.pageTable {\n  width: 95%;\n  border: none;\n}\n\n.pageTable img {\nvertical-align: bottom;\n}\n\n.pageTable td {\n  border: none;\n}\n\n.pageTable td.leftNav {\n  width: 100px;\n}\n\n.greenBox {\n  margin: 10px 30px 10px 30px;\n  padding: 10px 20px 10px 20px;\n  background-color: #EBF3DB;\n  width: 75%;\n}\n\n.blueBox {\n  margin: 10px 30px 10px 30px;\n  padding: 10px 20px 10px 20px;\n  background-color: #DDF0F2;\n  width: 75%;\n}\n\n.blueHR {\n  margin: 10px 30px 10px 30px;\n  height: 5px;\n  background-color: #DDF0F2;\n  width: 75%;\n}\n\n/* SEARCH FILTER */\n#search_autocomplete {\n  color:#aaa;\n}\n\n#search-button {\n  display:inline;\n}\n\n#search_filtered_div {\n  position:absolute;\n  margin-top:-1px;\n  z-index:101;\n  border:1px solid #BCCDF0;\n  background-color:#fff;\n}\n\n#search_filtered {\n  min-width:100%;\n}\n#search_filtered td{\n  background-color:#fff;\n  border-bottom: 1px solid #669999;\n  line-height:1.5em;\n}\n\n#search_filtered .jd-selected {\n  background-color: #ff6600;\n  cursor:pointer;\n}\n#search_filtered .jd-selected,\n#search_filtered .jd-selected a {\n  color:#fff;\n}\n\n.no-display {\n  display: none;\n}\n\n.jd-autocomplete {\n  font-family: Arial, sans-serif;\n  padding-left: 6px;\n  padding-right: 6px;\n  padding-top: 1px;\n  padding-bottom: 1px;\n  font-size: .8em;\n  border: none;\n  margin: 0;\n  line-height: 1.05em;\n}\n\n.show-row {\n  display: table-row;\n}\n.hide-row {\n  display: hidden;\n}\n\n/* SEARCH */\n\n/* restrict global search form width */\n#searchForm {\n  width:200px;\n}\n\n#searchTxt {\n  width:150px;\n}\n\n/* disable twiddle and size selectors for left column */\n#leftSearchControl div {\n  width: 100%;\n}\n\n#leftSearchControl .gsc-twiddle {\n  background-image : none;\n}\n\n#leftSearchControl td, #searchForm td {\n  border: 0px solid #000;\n}\n\n#leftSearchControl .gsc-resultsHeader .gsc-title {\n  padding-left : 0px;\n  font-weight : bold;\n  font-size : 13px;\n  color:#006699;\n  display : none;\n}\n\n#leftSearchControl .gsc-resultsHeader div.gsc-results-selector {\n  display : none;\n}\n\n#leftSearchControl .gsc-resultsRoot {\n  padding-top : 6px;\n}\n\n#leftSearchControl div.gs-visibleUrl-long {\n  display : block;\n  color:#006699;\n}\n\n.gsc-webResult div.gs-visibleUrl-short,\ntable.gsc-branding,\n.gsc-clear-button {\n  display : none;\n}\n\n.gsc-cursor-box .gsc-cursor div.gsc-cursor-page,\n.gsc-cursor-box .gsc-trailing-more-results a.gsc-trailing-more-results,\n#leftSearchControl a, \n#leftSearchControl a b {\n  color:#006699;\n}\n\n.gsc-resultsHeader {\n  display: none;\n}\n\n/* Disable built in search forms */\n.gsc-control form.gsc-search-box {\n  display : none;\n}\ntable.gsc-search-box {\n  margin:6px 0 0 0;\n  border-collapse:collapse;\n}\n\ntd.gsc-input {\n  padding:0 2px;\n  width:100%;\n  vertical-align:middle;\n}\n\ninput.gsc-input {\n  border:1px solid #BCCDF0;\n  width:99%;\n  padding-left:2px;\n  font-size:.95em;\n}\n\ntd.gsc-search-button {\n  text-align: right;\n  padding:0;\n  vertical-align:top;\n}\n\n#search-button {\n  margin:0 0 0 2px;\n  font-size:11px;\n}\n\n/* search result tabs */\n\n#doc-content .gsc-control {\n  position:relative;\n}\n\n#doc-content .gsc-tabsArea {\n  position:relative;\n  white-space:nowrap;\n}\n\n#doc-content .gsc-tabHeader {\n  padding: 3px 6px;\n  position:relative;\n}\n\n#doc-content .gsc-tabHeader.gsc-tabhActive {\n  border-top: 2px solid #94B922;\n}\n\n#doc-content h2#searchTitle {\n  padding:0;\n}\n\n#doc-content .gsc-resultsbox-visible {\n  padding:1em 0 0 6px;\n}\n\n/* CAROUSEL */\n\n#homeMiddle {\n  padding: 0px 0px 0px 0px;\n  float: left;\n  width: 584px;\n  height: 580px;\n  position:relative;\n}\n\n#topAnnouncement {\n  background:url(images/home/bg_home_announcement.png) no-repeat 0 0;\n}\n  \n#homeTitle {\n  padding:15px 15px 0;\n  height:30px;  \n}\n\n#homeTitle h2 {\n  padding:0;\n}\n\n#announcement-block {\n  padding:0 15px 0;\n  overflow:hidden;\n  background: url(images/hr_gray_side.jpg) no-repeat 15px 0;\n  zoom:1;\n}\n\n#announcement-block>* {\n  padding:15px 0 0;\n}\n\n#announcement-block img {\n  float:left;\n  margin:0 30px 0 0;\n}\n\n#announcement {\n  float:left;\n  margin:0;\n}\n\n#carousel {\n  background:url(images/home/bg_home_carousel.png) no-repeat 0 0;\n  position:relative;\n  height:400px;\n}\n\n#carouselMain {\n\tbackground: url(images/home/bg_home_carousel_board.png) 0 0 no-repeat;\n\theight:auto;\n  padding: 25px 21px 0;\n  overflow:hidden;\n  position:relative;\n  zoom:1; /*IE6*/\n}\n\n#carouselMain img {\n  margin:0;\n}\n\n#carouselMain .bulletinDesc h3 {\n\tmargin:0;\n\tpadding:0;\n}\n\n#carouselMain .bulletinDesc p {\n\tmargin:0;\n\tpadding:0.7em 0 0;\n}\n\n#carouselWheel {\n\tbackground: url(images/home/bg_home_carousel_wheel.png) 0 0 no-repeat;\n\tpadding-top:40px;\n\theight:150px;\n}\n\n.clearer { clear:both; }\n\na#arrow-left, a#arrow-right {\n  float:left;\n  width:42px;\n  height:42px;\n  background-image:url(images/home/carousel_buttons_sprite.png);\n  background-repeat:no-repeat;\n}\na#arrow-left {\n  margin:35px 3px 0 10px;\n}\na#arrow-right {\n  margin:35px 10px 0 0;\n}\na.arrow-left-off,\na#arrow-left.arrow-left-off:hover { \n  background-position:0 0;\n}\na.arrow-right-off, \na#arrow-right.arrow-right-off:hover { \n  background-position:-42px 0;\n}\na#arrow-left:hover { \n  background-position:0 -42px;\n}\na#arrow-right:hover { \n  background-position:-42px -42px;\n}\na.arrow-left-on {\n  background-position:0 0;\n}\na.arrow-right-on {\n  background-position:-42px 0;\n}\na.arrow-right-off,\na.arrow-left-off {\n  cursor:default;\n}\n\n.app-list-container {\n  margin:0 20px;\n  position:relative;\n  width:100%;\n}\n\ndiv#list-clip { \n  height:110px; \n  width:438px;\n  overflow:hidden; \n  position:relative; \n  float:left; \n}\n\ndiv#app-list { \n  left:0; \n  z-index:1; \n  position:absolute;\n  margin:11px 0 0;\n  _margin-top:13px;\n  width:1000%;\n}\n\n#app-list a {\n  display:block;\n  float:left;\n  height:90px;\n  width:90px;\n  margin:0 24px 0;\n  padding:3px;\n  background:#99cccc;\n  -webkit-border-radius:7px;\n  -moz-border-radius:7px;\n  border-radius:7px;\n  text-decoration:none;\n  text-align:center;\n  font-size:11px;\n  line-height:11px;\n}\n\n#app-list a span {\n  position:relative;\n  top:-4px;\n}\n\n#app-list img {  \n  width:90px;\n  height:70px;\n  margin:0;\n}\n\n#app-list a.selected, \n#app-list a:active.selected, \n#app-list a:hover.selected {\n  background:#A4C639;\n  color:#fff;\n  cursor:default;\n  text-decoration:none;\n}\n\n#app-list a:hover, \n#app-list a:active {\n  background:#ff9900;\n}\n\n#app-list a:hover span, \n#app-list a:active span {\n  text-decoration:underline;\n}\n\n#droid-name {\n  padding-top:.5em;\n  color:#666;\n  padding-bottom:.25em;\n}\n\n/*IE6*/\n* html #app-list a { zoom: 1; margin:0 24px 0 15px;}\n\n* html #list-clip { \n  width:430px !important;\n}\n\n/*carousel bulletin layouts*/\n/*460px width*/\n/*185px height*/\n.img-left {\n  float:left;\n  width:230px;\n  overflow:hidden;\n  padding:8px 0 8px 8px;\n}\n.desc-right {\n  float:left;\n  width:270px;\n  padding:10px;\n}\n.img-right {\n  float:right;\n  width:220px;\n  overflow:hidden;\n  padding:8px 8px 8px 0;\n}\n.desc-left {\n  float:right;\n  width:280px;\n  padding:10px;\n  text-align:right;\n}\n.img-top {\n  padding:20px 20px 0;\n}\n.desc-bottom {\n  padding:10px;\n}\n\n\n/* VIDEO PAGE */\n\n#mainBodyLeft.videoPlayer {\n  width:570px;\n}\n\n#mainBodyRight.videoPlayer {\n  width:330px;\n}\n\n/* player */\n\n#videoPlayerBox {\n  background-color: #DAF3FC;\n  border-radius:7px;\n  -moz-border-radius:7px;\n  -webkit-border-radius:7px;\n  width:530px;\n  padding:20px;\n  border:1px solid #d3ecf5;\n  box-shadow:2px 3px 1px #eee;\n  -moz-box-shadow:2px 3px 1px #eee;\n  -webkit-box-shadow:2px 3px 1px #eee;\n}\n\n#videoBorder {\n  background-color: #FFF;\n  min-height:399px;\n  height:auto !important;\n  border:1px solid #ccdada;\n  border-radius:7px 7px 0 0;\n  -moz-border-radius:7px 7px 0 0;\n  -webkit-border-top-left-radius:7px;\n  -webkit-border-top-right-radius:7px;\n}\n\n#videoPlayerTitle {\n  width:500px;\n  padding:15px 15px 0;\n}\n\n#videoPlayerTitle h2 {\n  font-weight:bold;\n  font-size:1.2em;\n  color:#336666;\n  margin:0;\n  padding:0;\n}\n\n#objectWrapper {\n  padding:15px 15px;\n  height:334px;\n  width:500px;\n}\n\n/* playlist tabs */\n\nul#videoTabs {\n  list-style-type:none;\n  padding:0;\n  clear:both;\n  margin:0;\n  padding: 20px 0 0 15px;\n  zoom:1; /* IE7/8, otherwise top-padding is double */\n}\n\nul#videoTabs li {\n  display:inline;\n  padding:0;\n  margin:0 3px 0 0;\n  line-height:2em;\n}\n\nul#videoTabs li a {\n  border-radius:7px 7px 0 0;\n  -moz-border-radius:7px 7px 0 0;\n  -webkit-border-top-left-radius:7px;\n  -webkit-border-top-right-radius:7px;\n  background:#95c0d0;\n  color:#fff;\n  text-decoration:none;\n  padding:.45em 1.5em;\n  font-weight:bold;\n}\n\nul#videoTabs li.selected a {\n  font-weight:bold;\n  text-decoration:none;\n  color:#555;\n  background:#daf3fc;\n  border-bottom:1px solid #daf3fc;\n}\n\nul#videoTabs li:hover a {\n  background:#85acba;\n}\n\nul#videoTabs li.selected:hover a {\n  background:#daf3fc;\n}\n\n/* playlists */\n\n#videos {\n  background:#daf3fc;\n  margin-bottom:1.5em;\n  padding:15px;\n  border-radius:5px;\n  -moz-border-radius:5px;\n  -webkit-border-radius:5px;\n  box-shadow:2px 3px 1px #eee;\n  -moz-box-shadow:2px 3px 1px #eee;\n  -webkit-box-shadow:2px 3px 1px #eee;\n}\n\n#videos div {\n  display:none;\n}\n\n#videos div.selected {\n  display:block;\n}\n\nul.videoPreviews {\n  list-style:none;\n  padding:0;\n  margin:0;\n  zoom:1; /* IE, otherwise, layout doesn't update when showing 'more' */\n}\n\nul.videoPreviews li {\n  margin:0 0 5px;\n  padding:0;\n  overflow:hidden;\n  position:relative;\n}\n\n#mainBodyFixed ul.videoPreviews h3 {\n  font-size: 12px;\n  margin:0 0 1em 130px;\n  padding:0;\n  font-weight:bold;\n  color:inherit;\n}\n\nul.videoPreviews a {\n  margin:1px;\n  padding:10px;\n  text-decoration:none;\n  height:90px;\n  display:block;\n  border-radius:5px;\n  -moz-border-radius:5px;\n  -webkit-border-radius:5px;\n  background-color:transparent;\n}\n\nul.videoPreviews a:hover {\n  background-color:#FFF;\n  border:none; /* IE8, otherwise, bg doesn't work */\n}\n\nul.videoPreviews a.selected {\n  background-color: #FF9900;\n}\n\nul.videoPreviews img {\n  float:left;\n  clear:left;\n  margin:0;\n}\n\nul.videoPreviews h3 {\n  font-size:12px;\n  font-weight:bold;\n  text-decoration:none;\n  margin:0 0 1em 130px;\n  padding:0;\n}\n\nul.videoPreviews p {\n  font-size: 12px;\n  text-decoration:none;\n  margin:0 0 1.2em 130px;\n}\n\nul.videoPreviews p.full {\n  display:none;\n}\n\nul.videoPreviews span.more {\n  padding:0 0 0 12px;\n  background:url(images/arrow_bluelink_down.png) 0 2px no-repeat;\n}\n\nul.videoPreviews span.less {\n  padding:0 0 0 12px;\n  background:url(images/arrow_bluelink_up.png) 0 2px no-repeat;\n  display:none;\n}\n\nul.videoPreviews p.toggle {\n  position:absolute;\n  margin:0;\n  margin-top:-23px; /* instead of bottom:23px, because IE won't do it correctly */\n  left:140px;\n}\n\nul.videoPreviews p.toggle a {\n  height:auto;\n  margin:0;\n  padding:0;\n  zoom:1; /* IE6, otherwise the margin considers the img on redraws */\n}\n\nul.videoPreviews p.toggle a:hover {\n  text-decoration:underline;\n  background:transparent; /* IE6, otherwise it inherits white */\n}\n\n/* featured videos */\n\n#mainBodyRight h2 {\n  padding:0 0 5px;\n}\n\n#mainBodyRight ul.videoPreviews {\n  margin:10px 0 0;\n}\n\n#mainBodyRight ul.videoPreviews li {\n  font-size:11px;\n  line-height:13px;\n  margin:0 0 5px;\n  padding:0;\n}\n\n#mainBodyRight ul.videoPreviews h3 {\n  padding:0;\n  margin:0;\n}\n\n#mainBodyRight ul.videoPreviews a {\n  text-decoration:none;\n  height:108px;\n  border:1px solid #FFF;\n}\n\n#mainBodyRight ul.videoPreviews a:hover {\n  border:1px solid #CCDADA;\n}\n\n#mainBodyRight ul.videoPreviews a.selected {\n  border:1px solid #FFF;\n}\n\n#mainBodyRight ul.videoPreviews p {\n\tline-height:1.2em;\n  padding:0;\n  margin:4px 0 0 130px;\n}\n\n#mainBodyRight ul.videoPreviews img {\n\tmargin-top:5px;\n}\n"
  },
  {
    "path": "templates-sdk/assets/android-developer-docs-devguide.css",
    "content": "\n@import url(\"android-developer-docs.css\");\n\n/* Page title */\n\n#jd-header h1 {\n  padding: 8px 0 0 0;\n}\n\n/* Page content container */\n\n#jd-header table {\nmargin: 0 0 1em 1em;\n}\n\n#jd-content table table,\n#jd-content table img {\n  margin:1em 0;\n}"
  },
  {
    "path": "templates-sdk/assets/android-developer-docs.css",
    "content": "/* file: android-developer-docs.css\n   author: smain\n   date: september 2008\n   info: developer doc styles (developer.android.com)\n*/\n\n@import url(\"android-developer-core.css\");\n\n#title {\n  border-bottom: 4px solid #ccc;\n  display:none;\n}\n\n#title h1 {\n  color:#336666;\n  margin:0;\n  padding: 5px 10px;\n  font-size: 1em;\n  line-height: 15px;\n}\n\n#title h1 .small{\n  color:#000;\n  margin:0;\n  font-size: 13px;\n  padding:0 0 0 15px;\n}\n\n/* SIDE NAVIGATION */\n\n#side-nav {\n  padding:0 6px 0 0;\n  background-color: #fff;\n  font-size:12px;\n}\n\n#resize-packages-nav {\n/* keeps the resize handle below the h-scroll handle */\n  height:270px;\n  overflow:hidden;\n  max-height:100%;\n}\n\n#packages-nav {\n  height:270px;\n  max-height:inherit;\n  position:relative;\n  overflow:auto;\n}\n\n#classes-nav,\n#devdoc-nav {\n  overflow:auto;\n  position:relative;\n}\n\n#side-nav ul {\n  list-style: none;\n  margin: 0;\n  padding:5px 0;\n}\n\n#side-nav ul ul {\n  margin: .35em 0 0 0;\n  padding: 0;\n}\n\n#side-nav li {\n  padding:0;\n  line-height:16px;\n  white-space:nowrap;\n  zoom:1;\n}\n\n#side-nav li h2 {\n  font-size:12px;\n  font-weight: bold;\n  margin:.5em 0 0 0;\n  padding: 3px 0 1px 9px;\n}\n\n#side-nav li a {\n  text-decoration:none;\n  padding: 0 0 0 18px;\n  zoom:1;\n}\n\n#side-nav li a span+span {\n  display:none;\n}\n\n#side-nav li a:hover {\n  text-decoration:underline;\n}\n\n#side-nav li a+a {\n  padding: 0;\n}\n/*second level (nested) list*/\n#side-nav li li li a {\n  padding: 0 0 0 28px;\n}\n/*third level (nested) list*/\n#side-nav li li li li a {\n  padding: 0 0 0 38px;\n}\n\n#side-nav .selected {\n  background-color: #435a6e;\n  color: #fff;\n  font-weight:bold;\n}\n\n#side-nav .selected a {\n  color: #fff;\n  text-decoration:none;\n}\n\n#side-nav strong {\n  display:block;\n}\n\n#side-nav .toggle-list .toggle-img {\n  margin:0;\n  padding:0;\n  position:absolute;\n  top:0;\n  left:0;\n  height:16px;\n  width:15px;\n  outline-style:none;\n}\n/* second-level toggle */\n#side-nav .toggle-list .toggle-list .toggle-img {\n  left:10px;\n}\n\n#side-nav .closed .toggle-img,\n#side-nav .open .closed .toggle-img {\n  background:url('images/triangle-closed-small.png') 7px 4px no-repeat;\n}\n#side-nav .open .toggle-img {\n  background:url('images/triangle-opened-small.png') 7px 4px no-repeat;\n}\n\n#side-nav .toggle-list {\n  position:relative;\n}\n\n#side-nav .toggle-list ul {\n  margin:0;\n  display:none;\n}\n\n#side-nav .toggle-list div {\n  display:block;\n}\n\n#index-links .selected {\n  background-color: #fff;\n  color: #000;\n  font-weight:normal;\n  text-decoration:none;\n}\n\n#index-links {\n  padding:7px 0 4px 10px;\n}\n\n/* nav tree */\n\n#nav-tree ul {\n  padding:5px 0 1.5em;\n}\n\n#side-nav #nav-tree ul li a,\n#side-nav #nav-tree ul li span.no-children {\n  padding: 0 0 0 0;\n  margin: 0;\n}\n\n#nav-tree .plus {\n  margin: 0 3px 0 0;\n}\n\n#nav-tree ul ul {\n  list-style: none;\n  margin: 0;\n  padding: 0 0 0 0;\n}\n\n#nav-tree ul li {\n  margin: 0;\n  padding: 0 0 0 0;\n  white-space: nowrap;\n}\n\n#nav-tree .children_ul {\n  margin:0;\n}\n\n#nav-tree a.nolink {\n  color: black;\n  text-decoration: none;\n}\n\n#nav-tree span.label {\n  width: 100%;\n}\n\n#nav-tree {\n  overflow-x: auto;\n  overflow-y: scroll;\n}\n\n#nav-swap {\n  font-size:10px;\n  line-height:10px;\n  margin-left:1em;\n  text-decoration:none;\n  display:block;\n}\n\n#tree-link {\n\n}\n\n/* DOCUMENT BODY */\n\n#doc-content {\n}\n\n#jd-header {\n  background-color: #E2E2E2;\n  padding: 7px 15px;\n}\n\n#jd-header h1 {\n  margin: 0 0 10px;\n  font-size:1.7em;\n}\n\n#jd-header .crumb {\n  font-size:.9em;\n  line-height:1em;\n  color:#777;\n}\n\n#jd-header .crumb a,\n#jd-header .crumb a:visited {\n  text-decoration:none;\n  color:#777;\n}\n\n#jd-header .crumb a:hover {\n  text-decoration:underline;\n}\n\n#jd-header table {\n  margin:0;\n  padding:0;\n}\n\n#jd-header td {\n  border:none;\n  padding:0;\n  vertical-align:top;\n}\n\n#jd-header.guide-header {\n  background-color:#fff;\n  color:#435a6e;\n  height:50px;\n}\n\n#jd-descr {\n  position:relative;\n}\n\n/* summary tables for reference pages */\n.jd-sumtable {\n  margin: .5em 1em 1em 1em;\n  width:95%; /* consistent table widths; within IE's quirks */\n  font-size:.9em;\n}\n\n.jd-sumtable a {\n  text-decoration:none;\n}\n\n.jd-sumtable a:hover {\n  text-decoration:underline;\n}\n\n/* the link inside a sumtable for \"Show All/Hide All\" */\n.toggle-all {\n  display:block;\n  float:right;\n  font-weight:normal;\n  font-size:0.9em;\n}\n\n/* adjustments for in/direct subclasses tables */\n.jd-sumtable-subclasses {\n  margin: 1em 0 0 0;\n  max-width:968px;\n}\n\n/* extra space between end of method name and open-paren */\n.sympad {\n  margin-right: 2px;\n}\n\n/* right alignment for the return type in sumtable */\n.jd-sumtable .jd-typecol {\n  text-align:right;\n}\n\n/* adjustments for the expando table-in-table */\n.jd-sumtable-expando {\n  margin:.5em 0;\n  padding:0;\n}\n\n/* a div that holds a short description */\n.jd-descrdiv {\n  padding:3px 1em 0 1em;\n  margin:0;\n  border:0;\n}\n\n/* page-top-right container for reference pages (holds\nlinks to summary tables) */\n#api-info-block {\n  font-size:.8em;\n  padding:6px 10px;\n  font-weight:normal;\n  float:right;\n  text-align:right;\n  color:#999;\n  max-width:70%;\n}\n\n#api-level-toggle {\n  padding:0 10px;\n  font-size:11px;\n  position: absolute;\n  top: -17px;\n  left: -90px;\n}\n\n#api-level-toggle label.disabled {\n  color:#999;\n}\n\ndiv.api-level {\n  font-size:.8em;\n  font-weight:normal;\n  color:#999;\n  float:right;\n  padding:0 7px 0;\n  margin-top:-25px;\n}\n\n#api-info-block div.api-level {\n  font-size:1.3em;\n  font-weight:bold;\n  float:none;\n  color:#444;\n  padding:0;\n  margin:0;\n}\n\n/* Force link colors for IE6 */\ndiv.api-level a {\n  color:#999;\n}\n#api-info-block div.api-level a:link {\n  color:#444;\n}\n#api-level-toggle a {\n  color:#999;\n}\n\ndiv#naMessage {\n  display:none;\n  width:555px;\n  height:0;\n  margin:0 auto;\n}\n\ndiv#naMessage div {\n  width:450px;\n  position:fixed;\n  margin:50px 0;\n  padding:4em 4em 3em;\n  background:#FFF;\n  background:rgba(255,255,255,0.7);\n  border:1px solid #dddd00;\n}\n/* IE6 can't position fixed */\n* html div#naMessage div { position:absolute; }\n\ndiv#naMessage strong {\n  font-size:1.1em;\n}\n\n.absent,\n.absent a:link,\n.absent a:visited,\n.absent a:hover,\n.absent * {\n  color:#bbb !important;\n  cursor:default !important;\n  text-decoration:none !important;\n}\n\n#api-level-toggle a,\n.api-level a {\n  color:inherit;\n  text-decoration:none;\n}\n\n#api-level-toggle a:hover,\n.api-level a:hover {\n  color:inherit;\n  text-decoration:underline !important;\n  cursor:pointer !important;\n}\n\n#side-nav li.absent.selected,\n#side-nav li.absent.selected *,\n#side-nav div.label.absent.selected,\n#side-nav div.label.absent.selected * {\n  background-color:#eaeaea !important;\n}\n/* IE6 quirk (won't chain classes, so just keep background blue) */\n* html #side-nav li.selected,\n* html #side-nav li.selected *,\n* html #side-nav div.label.selected,\n* html #side-nav div.label.selected * {\n  background-color: #435a6e !important;\n}\n\n\n.absent h4.jd-details-title,\n.absent h4.jd-details-title * {\n  background-color:#f6f6f6 !important;\n}\n\n.absent img {\n  opacity: .3;\n  filter: alpha(opacity=30);\n  -ms-filter:\"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)\";\n}\n\n\n/* applies to a div containing links to summary tables */\n.sum-details-links {\n  padding:0;\n  font-weight:normal;\n}\n\n.sum-details-links a {\n  text-decoration:none;\n}\n\n.sum-details-links a:hover {\n  text-decoration:underline;\n}\n\n\n/* inheritance table */\n.jd-inheritance-table {\n  border-spacing:0;\n  margin:0;\n  padding:0;\n  font-size:.9em;\n}\n.jd-inheritance-table td {\n  border: none;\n  margin: 0;\n  padding: 0;\n}\n.jd-inheritance-table .jd-inheritance-space {\n  font-weight:bold;\n  width:1em;\n}\n.jd-inheritance-table .jd-inheritance-interface-cell {\n  padding-left: 17px;\n}\n\n#jd-content {\n  padding: 18px 15px;\n}\n\nhr {\n  background-color:#ccc;\n  border-color:#fff;\n  margin:2em 0 1em;\n}\n\n/* DOC CLASSES */\n\n#jd-content h1 {\n/*sdk page*/\n  font-size:1.6em;\n  color:#336666;\n  margin:0 0 .5em;\n}\n\n#jd-content h2 {\n  font-size:1.45em;\n  color:#111;\n  border-top:2px solid #ccc;\n  padding: .5em 0 0;\n  margin: 2em 0 1em 0;\n}\n\n#jd-content h3 {\n  font-size:1.2em;\n  color:#222;\n  padding: .75em 0 .65em 0;\n  margin:0;\n}\n\n#jd-content h4 {\n  font-size:1.1em;\n  margin-bottom:.5em;\n  color:#222;\n}\n\n#jd-content .small-header {\n  font-size:1em;\n  color:#000;\n  font-weight:bold;\n  border:none;\n  padding:0;\n  margin:1em 0 .5em;\n  position:inherit;\n}\n\n#jd-content table {\n  margin: 0 0 1em 1em;\n}\n\n#jd-content img {\n  margin: 0 0 1em 1em;\n}\n\n#jd-content li img,\n#jd-content dd img {\n  margin:.5em 0 0 1em;\n}\n\n.nolist {\n  list-style:none;\n  padding:0;\n  margin:0 0 1em 1em;\n}\n\n.nolist li {\n  padding:0 0 2px;\n  margin:0;\n}\n\nh4 .normal {\n  font-size:.9em;\n  font-weight:normal;\n}\n\n.caps {\n  font-variant:small-caps;\n  font-size:1.2em;\n}\n\ndl.tag-list dl.atn-list {\n  padding:0 0 0 2em;\n}\n\n.jd-details {\n/*  border:1px solid #669999;\n  padding:4px; */\n  margin:0 0 1em;\n}\n\n/* API reference: a container for the\n.tagdata blocks that make up the detailed\ndescription */\n.jd-details-descr {\n  padding:0;\n  margin:.5em .25em;\n}\n\n/* API reference: a block containing\na detailed description, a params table,\nseealso list, etc */\n.jd-tagdata {\n  margin:.5em 1em;\n}\n\n.jd-tagdata p {\n  margin:0 0 1em 1em;\n}\n\n/* API reference: adjustments to\nthe detailed description block */\n.jd-tagdescr {\n  margin:.25em 0 .75em 0;\n  line-height:1em;\n}\n\n.jd-tagdescr p {\n  margin:.5em 0;\n  padding:0;\n\n}\n\n.jd-tagdescr ol,\n.jd-tagdescr ul {\n  margin:0 2.5em;\n  padding:0;\n}\n\n.jd-tagdescr table,\n.jd-tagdescr img {\n  margin:.25em 1em;\n}\n\n.jd-tagdescr li {\nmargin:0 0 .25em 0;\npadding:0;\n}\n\n/* API reference: heading marking\nthe details section for constants,\nattrs, methods, etc. */\nh4.jd-details-title {\n  font-size:1.15em;\n  background-color: #E2E2E2;\n  margin:1.5em 0 .6em;\n  padding:3px 95px 3px 3px; /* room for api-level */\n}\n\nh4.jd-tagtitle {\n  margin:0;\n}\n\n/* API reference: heading for \"Parameters\", \"See Also\", etc.,\nin details sections */\nh5.jd-tagtitle {\n  margin:0 0 .25em 0;\n  font-size:1em;\n}\n\n.jd-tagtable {\n  margin:0;\n}\n\n.jd-tagtable td,\n.jd-tagtable th {\n  border:none;\n  background-color:#fff;\n  vertical-align:top;\n  font-weight:normal;\n  padding:2px 10px;\n}\n\n.jd-tagtable th {\n  font-style:italic;\n}\n\n#jd-content table h2 {\n  background-color: #d6d6d6;\n  font-size: 1.1em;\n  margin:0 0 10px;\n  padding:5px;\n  left:0;\n  width:auto;\n}\n\ndiv.special {\n  padding: .5em 1em 1em 1em;\n  margin: 0 0 1em;\n  background-color: #DAF3FC;\n  border:1px solid #d3ecf5;\n  border-radius:5px;\n  -moz-border-radius:5px;\n  -webkit-border-radius:5px;\n}\n\n.toggle-content-toggleme {\n  display:none;\n}\n\n.toggle-content-button {\n  font-size:.9em;\n  line-height:.9em;\n  text-decoration:none;\n  position:relative;\n  top:5px;\n}\n\n.toggle-content-button:hover {\n  text-decoration:underline;\n}\n\ndiv.special p {\n  margin: .5em 0 0 0;\n}\n\ndiv.special ol {\n  margin: 0;\n}\n\ndiv.special ol li {\n  margin: 0;\n  padding: 0;\n}\n\n#jd-content div.special h2,\n#jd-content div.special h3 {\n  color:#669999;\n  font-size:1.2em;\n  border:none;\n  margin:0 0 .5em;\n  padding:0;\n}\n\np.note, div.note,\np.caution, div.caution,\np.warning, div.warning {\n  margin: 1em;\n  padding: 0 0 0 .5em;\n  border-left: 4px solid;\n}\n\np.special-note,\ndiv.special-note {\n  background-color:#EBF3DB;\n  padding:10px 20px;\n  margin:0 0 1em;\n}\n\np.note,\ndiv.note {\n border-color: #99aacc;\n}\n\np.warning,\ndiv.warning {\n  border-color: #aa0033;\n}\n\np.caution,\ndiv.caution {\n  border-color: #ffcf00;\n}\n\nli p.note, li p.warning {\n  margin: .5em 0 0 0;\n  padding: .2em .5em .2em .9em;\n}\n\ndl.xml dt {\n  font-variant:small-caps;\n  font-size:1.2em;\n}\n\ndl.xml dl {\n  padding:0;\n}\n\ndl.xml dl dt {\n  font-variant:normal;\n  font-size:1em;\n}\n\n.listhead li {\n  font-weight: bold;\n}\n\n.listhead li *, /*ie*/.listhead li li {\n  font-weight: normal;\n}\n\nol.no-style,\nul.no-style {\n  list-style:none;\n  padding-left:1em;\n}\n\n.new {\n  font-size: .78em;\n  font-weight: bold;\n  color: #ff3d3d;\n  text-decoration: none;\n  vertical-align:top;\n  line-height:.9em;\n}\n\npre.classic {\n  background-color:transparent;\n  border:none;\n  padding:0;\n}\n\np.img-caption {\n  margin: -0.5em 0 1em 1em; /* matches default img left-margin */\n}\n\ndiv.figure {\n  float:right;\n  clear:right;\n  margin:1em 0 0 0;\n  padding:0 0 0 3em;\n  background-color:#fff;\n  /* width must be defined w/ an inline style matching the image width */\n}\n\n#jd-content\ndiv.figure img {\n  margin: 0 0 1em;\n}\n\ndiv.figure p.img-caption {\n  margin: -0.5em 0 1em 0;\n}\n\np.table-caption {\n  margin: 0 0 0.5em 1em; /* matches default table left-margin */\n}\n\n/* BEGIN quickview sidebar element styles */\n\n#qv-wrapper {\n  float: right;\n  width:310px; /* +35px padding */\n  background-color:#fff;\n  margin:-48px 0 2px 0;\n  padding:0 0 20px 35px;\n}\n\n#qv {\n  background-color:#fff;\n  border:4px solid #dee8f1;\n  margin:0;\n  padding:0 5px 5px;\n  width:292px; /* +10px padding; +8px border */\n  font-size:.9em;\n}\n\n#qv ol {\n  list-style:none;\n  padding: 0;\n}\n\n#qv ol ol{\n  list-style:none;\n  padding: 0 0 0 12px;\n  margin:0;\n}\n\n#qv ul {\n  padding: 0 10px 0 2em;\n}\n\n#qv li {\n  padding: 0 10px 3px;\n  line-height: 1.2em;\n}\n\n#qv li li {\n  padding: 3px 10px 0;\n}\n\n#qv ul li {\n  padding: 0 10px 0 0;\n}\n\n#qv li.selected a {\n  color:#555;\n  text-decoration:none;\n}\n\n#qv a,\n#qv a code {\n  color:#cc6600;\n}\n\n#qv p {\n  margin:8px 0 0;\n  padding:0 10px;\n}\n\n#qv-extra #rule {\n  padding: 0 10px;\n  margin: 0;\n}\n\n#qv-sub-rule {\n  padding: 6px 20px;\n  margin: 0;\n}\n\n#qv-sub-rule p {\n  margin: 0;\n}\n\n#jd-content #qv h2 {\n  font-size:1.05em;\n  font-weight:bold;\n  margin:12px 0 .25em 0;\n  padding:0 10px;\n  background-color:transparent;\n  color:#7BB026;\n  border:none;\n  left:0;\n  z-index:1;\n}\n\n/* END quickview sidebar element styles */\n\n/* Begin sidebox sidebar element styles */\n\n.sidebox-wrapper {\n  float:right;\n  clear:right;\n  width:310px; /* +35px padding */\n  background-color:#fff;\n  margin:0;\n  padding:0 0 20px 35px;\n}\n\n.sidebox {\n  border-left:1px solid #dee8f1;\n  background-color:#ffffee;\n  margin:0;\n  padding:8px 12px;\n  font-size:0.9em;\n  width:285px; /* +24px padding; +1px border */\n}\n\n.sidebox p {\n  margin-bottom: .75em;\n}\n\n.sidebox ul {\n  padding: 0 0 0 1.5em;\n}\n\n.sidebox li ul {\n  margin-top:0;\n  margin-bottom:.1em;\n}\n\n.sidebox li {\npadding:0 0 0 0em;\n}\n\n#jd-content .sidebox h2,\n#jd-content .sidebox h3,\n#jd-content .sidebox h4,\n#jd-content .sidebox h5 {\n  border:none;\n  font-size:1em;\n  margin:0;\n  padding:0 0 8px;\n  left:0;\n  z-index:0;\n}\n\n.sidebox hr {\n  background-color:#ccc;\n  border:none;\n}\n\n/* End sidebox sidebar element styles */\n\n/* BEGIN image and caption styles (originally for UI Guidelines docs) */\n\ntable.image-caption {\n  padding:0;\n  margin:.5em 0;\n  border:0;\n}\n\ntd.image-caption-i {\n  font-size:92%;\n  padding:0 5px;\n  margin:0;\n  border:0;\n}\n\ntd.image-caption-i img {\n  padding:0 1em;\n  margin:0;\n}\n\n.image-list {\n  width:24px;\n  text-align:center;\n}\n\ntd.image-caption-c {\n  font-size:92%;\n  padding:1em 2px 2px 2px;\n  margin:0;\n  border:0;\n  width:350px;\n}\n\n.grad-rule-top {\nbackground-image:url(images/grad-rule-qv.png);\nbackground-repeat:no-repeat;\npadding-top:1em;\nmargin-top:0;\n}\n\n.image-caption-nested {\n  margin-top:0;\n  padding:0 0 0 1em;\n}\n\n.image-caption-nested td {\n  padding:0 4px 2px 0;\n  margin:0;\n  border:0;\n}\n\n/* END image and caption styles */\n\n/* table of contents */\n\nol.toc {\n  margin: 0 0 1em 0;\n  padding: 0;\n  list-style: none;\n  font-size:95%;\n}\n\nol.toc li {\n  font-weight: bold;\n  margin: 0 0 .5em 1em;\n  padding: 0;\n}\n\nol.toc li p {\n  font-weight: normal;\n}\n\nol.toc li ol {\n  margin: 0;\n  padding: 0;\n}\n\nol.toc li li {\n  padding: 0;\n  margin: 0 0 0 1em;\n  font-weight: normal;\n  list-style: none;\n}\n\ntable ol.toc {\n  margin-left: 0;\n}\n\n.columns td {\n  padding:0 5px;\n  border:none;\n}\n\n/* link table */\n.jd-linktable {\n  margin: 0 0 1em;\n  border-bottom: 1px solid #888;\n}\n.jd-linktable th,\n.jd-linktable td {\n  padding: 3px 5px;\n  vertical-align: top;\n  text-align: left;\n  border:none;\n}\n.jd-linktable tr {\n  background-color: #fff;\n}\n.jd-linktable td {\n  border-top: 1px solid #888;\n  background-color: inherit;\n}\n.jd-linktable td  p {\n  padding: 0 0 5px;\n}\n.jd-linktable .jd-linkcol {\n}\n.jd-linktable .jd-descrcol {\n}\n.jd-linktable .jd-typecol {\n  text-align:right;\n}\n.jd-linktable .jd-valcol {\n}\n.jd-linktable .jd-commentrow {\n  border-top:none;\n  padding-left:25px;\n}\n.jd-deprecated-warning {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\n\ntr.alt-color {\n  background-color: #f6f6f6;\n}\n\n/* expando trigger */\n#jd-content .jd-expando-trigger-img {\n  margin:0;\n}\n\n/* jd-expando */\n.jd-inheritedlinks {\n  padding:0 0 0 13px\n}\n\n/* SDK PAGE */\ntable.download tr {\n  background-color:#d9d9d9;\n}\n\ntable.download tr.alt-color {\n  background-color:#ededed;\n}\n\ntable.download td,\ntable.download th {\n  border:2px solid #fff;\n  padding:10px 5px;\n}\n\ntable.download th {\n  background-color:#6d8293;\n  color:#fff;\n}\n\n/* INLAY 180 COPY and 240PX EXTENSION */\n/* modified to 43px so that all browsers eliminate the package panel h-scroll */\n.g-tpl-240 .g-unit,\n.g-unit .g-tpl-240 .g-unit,\n.g-unit .g-unit .g-tpl-240 .g-unit {\n  display: block;\n  margin: 0 0 0 243px;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-240 .g-first,\n.g-unit .g-tpl-240 .g-first,\n.g-tpl-240 .g-first {\n  display: block;\n  margin: 0;\n  width: 243px;\n  float: left;\n}\n/* 240px alt */\n.g-tpl-240-alt .g-unit,\n.g-unit .g-tpl-240-alt .g-unit,\n.g-unit .g-unit .g-tpl-240-alt .g-unit {\n  display: block;\n  margin: 0 243px 0 0;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-240-alt .g-first,\n.g-unit .g-tpl-240-alt .g-first,\n.g-tpl-240-alt .g-first {\n  display: block;\n  margin: 0;\n  width: 243px;\n  float: right;\n}\n\n/* 200px */\n.g-tpl-200 .g-unit,\n.g-unit .g-tpl-200 .g-unit,\n.g-unit .g-unit .g-tpl-200 .g-unit {\n  display: block;\n  margin: 0 0 0 200px;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-200 .g-first,\n.g-unit .g-tpl-200 .g-first,\n.g-tpl-200 .g-first {\n  display: block;\n  margin: 0;\n  width: 200px;\n  float: left;\n}\n/* 200px alt */\n.g-tpl-200-alt .g-unit,\n.g-unit .g-tpl-200-alt .g-unit,\n.g-unit .g-unit .g-tpl-200-alt .g-unit {\n  display: block;\n  margin: 0 200px 0 0;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-200-alt .g-first,\n.g-unit .g-tpl-200-alt .g-first,\n.g-tpl-200-alt .g-first {\n  display: block;\n  margin: 0;\n  width: 200px;\n  float: right;\n}\n\n/* 190px */\n.g-tpl-190 .g-unit,\n.g-unit .g-tpl-190 .g-unit,\n.g-unit .g-unit .g-tpl-190 .g-unit {\n  display: block;\n  margin: 0 0 0 190px;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-190 .g-first,\n.g-unit .g-tpl-190 .g-first,\n.g-tpl-190 .g-first {\n  display: block;\n  margin: 0;\n  width: 190px;\n  float: left;\n}\n/* 190px alt */\n.g-tpl-190-alt .g-unit,\n.g-unit .g-tpl-190-alt .g-unit,\n.g-unit .g-unit .g-tpl-190-alt .g-unit {\n  display: block;\n  margin: 0 190px 0 0;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-190-alt .g-first,\n.g-unit .g-tpl-190-alt .g-first,\n.g-tpl-190-alt .g-first {\n  display: block;\n  margin: 0;\n  width: 190px;\n  float: right;\n}\n\n/* 180px */\n.g-tpl-180 .g-unit,\n.g-unit .g-tpl-180 .g-unit,\n.g-unit .g-unit .g-tpl-180 .g-unit {\n  display: block;\n  margin: 0 0 0 180px;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-180 .g-first,\n.g-unit .g-tpl-180 .g-first,\n.g-tpl-180 .g-first {\n  display: block;\n  margin: 0;\n  width: 180px;\n  float: left;\n}\n/* 180px alt */\n.g-tpl-180-alt .g-unit,\n.g-unit .g-tpl-180-alt .g-unit,\n.g-unit .g-unit .g-tpl-180-alt .g-unit {\n  display: block;\n  margin: 0 180px 0 0;\n  width: auto;\n  float: none;\n}\n.g-unit .g-unit .g-tpl-180-alt .g-first,\n.g-unit .g-tpl-180-alt .g-first,\n.g-tpl-180-alt .g-first {\n  display: block;\n  margin: 0;\n  width: 180px;\n  float: right;\n}\n\n\n/* JQUERY RESIZABLE STYLES */\n.ui-resizable { position: relative; }\n.ui-resizable-handle { position: absolute; display: none; font-size: 0.1px; z-index:1; }\n.ui-resizable .ui-resizable-handle { display: block; }\nbody .ui-resizable-disabled .ui-resizable-handle { display: none; }\nbody .ui-resizable-autohide .ui-resizable-handle { display: none; }\n.ui-resizable-s { cursor: s-resize; height: 6px; width: 100%; bottom: 0px; left: 0px;\n  background: transparent url(\"images/resizable-s2.gif\") repeat scroll center top; }\n.ui-resizable-e { cursor: e-resize; width: 6px; right: 0px; top: 0px; height: 100%;\n  background: transparent url(\"images/resizable-e2.gif\") repeat scroll right center; }\n\n@media print {\n\n  body {\n    overflow:visible;\n  }\n\n  #header {\n    height:60px;\n  }\n\n  #headerLeft {\n    padding:0;\n  }\n\n  #header-tabs,\n  #headerRight,\n  #side-nav,\n  #api-info-block {\n    display:none;\n  }\n\n  #body-content {\n    position:inherit;\n  }\n\n  #doc-content {\n    margin-left:0 !important;\n    height:auto !important;\n    width:auto !important;\n    overflow:inherit;\n    display:inline;\n  }\n\n  #jd-header {\n    padding:10px 0;\n  }\n\n  #jd-content {\n    padding:15px 0 0;\n  }\n\n  #footer {\n    float:none;\n    margin:2em 0 0;\n  }\n\n  h4.jd-details-title {\n    border-bottom:1px solid #666;\n  }\n\n  pre {\n    /* these allow lines to break (if there's a white space) */\n    overflow: visible;\n    text-wrap: unrestricted;\n    white-space: -moz-pre-wrap; /* Moz */\n    white-space: -pre-wrap; /* Opera 4-6 */\n    white-space: -o-pre-wrap; /* Opera 7 */\n    white-space: pre-wrap; /* CSS3  */\n    word-wrap: break-word; /* IE 5.5+ */\n  }\n\n  h1, h2, h3, h4, h5, h6 {\n    page-break-after: avoid;\n  }\n\n  table, img {\n    page-break-inside: avoid;\n  }\n}\n"
  },
  {
    "path": "templates-sdk/assets/android-developer-docs.js",
    "content": "var resizePackagesNav;\nvar classesNav;\nvar devdocNav;\nvar sidenav;\nvar content;\nvar HEADER_HEIGHT = 117;\nvar cookie_namespace = 'android_developer';\nvar NAV_PREF_TREE = \"tree\";\nvar NAV_PREF_PANELS = \"panels\";\nvar nav_pref;\nvar toRoot;\nvar isMobile = false; // true if mobile, so we can adjust some layout\nvar isIE6 = false; // true if IE6\n\n// TODO: use $(document).ready instead\nfunction addLoadEvent(newfun) {\n  var current = window.onload;\n  if (typeof window.onload != 'function') {\n    window.onload = newfun;\n  } else {\n    window.onload = function() {\n      current();\n      newfun();\n    }\n  }\n}\n\nvar agent = navigator['userAgent'].toLowerCase();\n// If a mobile phone, set flag and do mobile setup\nif ((agent.indexOf(\"mobile\") != -1) ||      // android, iphone, ipod \n    (agent.indexOf(\"blackberry\") != -1) ||\n    (agent.indexOf(\"webos\") != -1) ||\n    (agent.indexOf(\"mini\") != -1)) {        // opera mini browsers \n  isMobile = true;\n  addLoadEvent(mobileSetup);\n// If not a mobile browser, set the onresize event for IE6, and others\n} else if (agent.indexOf(\"msie 6\") != -1) {\n  isIE6 = true;\n  addLoadEvent(function() {\n    window.onresize = resizeAll;\n  });\n} else {\n  addLoadEvent(function() {\n    window.onresize = resizeHeight;\n  });\n}\n\nfunction mobileSetup() {\n  $(\"body\").css({'overflow':'auto'});\n  $(\"html\").css({'overflow':'auto'});\n  $(\"#body-content\").css({'position':'relative', 'top':'0'});\n  $(\"#doc-content\").css({'overflow':'visible', 'border-left':'3px solid #DDD'});\n  $(\"#side-nav\").css({'padding':'0'});\n  $(\"#nav-tree\").css({'overflow-y': 'auto'});\n}\n\n/* loads the lists.js file to the page.\nLoading this in the head was slowing page load time */\naddLoadEvent( function() {\n  var lists = document.createElement(\"script\");\n  lists.setAttribute(\"type\",\"text/javascript\");\n  lists.setAttribute(\"src\", toRoot+\"javadoc/lists.js\");\n  document.getElementsByTagName(\"head\")[0].appendChild(lists);\n} );\n\naddLoadEvent( function() {\n  $(\"pre:not(.no-pretty-print)\").addClass(\"prettyprint\");\n  prettyPrint();\n} );\n\nfunction setToRoot(root) {\n  toRoot = root;\n  // note: toRoot also used by carousel.js\n}\n\nfunction restoreWidth(navWidth) {\n  var windowWidth = $(window).width() + \"px\";\n  content.css({marginLeft:parseInt(navWidth) + 6 + \"px\"}); //account for 6px-wide handle-bar\n\n  if (isIE6) {\n    content.css({width:parseInt(windowWidth) - parseInt(navWidth) - 6 + \"px\"}); // necessary in order for scrollbars to be visible\n  }\n\n  sidenav.css({width:navWidth});\n  resizePackagesNav.css({width:navWidth});\n  classesNav.css({width:navWidth});\n  $(\"#packages-nav\").css({width:navWidth});\n}\n\nfunction restoreHeight(packageHeight) {\n  var windowHeight = ($(window).height() - HEADER_HEIGHT);\n  var swapperHeight = windowHeight - 13;\n  $(\"#swapper\").css({height:swapperHeight + \"px\"});\n  sidenav.css({height:windowHeight + \"px\"});\n  content.css({height:windowHeight + \"px\"});\n  resizePackagesNav.css({maxHeight:swapperHeight + \"px\", height:packageHeight});\n  classesNav.css({height:swapperHeight - parseInt(packageHeight) + \"px\"});\n  $(\"#packages-nav\").css({height:parseInt(packageHeight) - 6 + \"px\"}); //move 6px to give space for the resize handle\n  devdocNav.css({height:sidenav.css(\"height\")});\n  $(\"#nav-tree\").css({height:swapperHeight + \"px\"});\n}\n\nfunction readCookie(cookie) {\n  var myCookie = cookie_namespace+\"_\"+cookie+\"=\";\n  if (document.cookie) {\n    var index = document.cookie.indexOf(myCookie);\n    if (index != -1) {\n      var valStart = index + myCookie.length;\n      var valEnd = document.cookie.indexOf(\";\", valStart);\n      if (valEnd == -1) {\n        valEnd = document.cookie.length;\n      }\n      var val = document.cookie.substring(valStart, valEnd);\n      return val;\n    }\n  }\n  return 0;\n}\n\nfunction writeCookie(cookie, val, section, expiration) {\n  if (val==undefined) return;\n  section = section == null ? \"_\" : \"_\"+section+\"_\";\n  if (expiration == null) {\n    var date = new Date();\n    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week\n    expiration = date.toGMTString();\n  }\n  document.cookie = cookie_namespace + section + cookie + \"=\" + val + \"; expires=\" + expiration+\"; path=/\";\n} \n\nfunction init() {\n  $(\"#side-nav\").css({position:\"absolute\",left:0});\n  content = $(\"#doc-content\");\n  resizePackagesNav = $(\"#resize-packages-nav\");\n  classesNav = $(\"#classes-nav\");\n  sidenav = $(\"#side-nav\");\n  devdocNav = $(\"#devdoc-nav\");\n\n  var cookiePath = \"\";\n  if (location.href.indexOf(\"/reference/\") != -1) {\n    cookiePath = \"reference_\";\n  } else if (location.href.indexOf(\"/guide/\") != -1) {\n    cookiePath = \"guide_\";\n  } else if (location.href.indexOf(\"/sdk/\") != -1) {\n    cookiePath = \"sdk_\";\n  } else if (location.href.indexOf(\"/resources/\") != -1) {\n    cookiePath = \"resources_\";\n  }\n\n  if (!isMobile) {\n    $(\"#resize-packages-nav\").resizable({handles: \"s\", resize: function(e, ui) { resizePackagesHeight(); } });\n    $(\"#side-nav\").resizable({handles: \"e\", resize: function(e, ui) { resizeWidth(); resizeHeight();} });\n    var cookieWidth = readCookie(cookiePath+'width');\n    var cookieHeight = readCookie(cookiePath+'height');\n    if (cookieWidth) {\n      //restoreWidth(cookieWidth);\n    } else if ($(\"#side-nav\").length) {\n      resizeWidth();\n    }\n    \n      resizeHeight();\n    \n  }\n\n  if (devdocNav.length) { // only dev guide and sdk \n    highlightNav(location.href); \n  }\n}\n\nfunction highlightNav(fullPageName) {\n  var lastSlashPos = fullPageName.lastIndexOf(\"/\");\n  var firstSlashPos;\n  if (fullPageName.indexOf(\"/guide/\") != -1) {\n    firstSlashPos = fullPageName.indexOf(\"/guide/\");\n  } else if (fullPageName.indexOf(\"/sdk/\") != -1) {\n    firstSlashPos = fullPageName.indexOf(\"/sdk/\");\n  } else if (fullPageName.indexOf(\"/resources/\") != -1) {\n    firstSlashPos = fullPageName.indexOf(\"/resources/\");\n  }\n  if (lastSlashPos == (fullPageName.length - 1)) { // if the url ends in slash (add 'index.html')\n    fullPageName = fullPageName + \"index.html\";\n  }\n  var htmlPos = fullPageName.lastIndexOf(\".html\", fullPageName.length);\n  var pathPageName = fullPageName.slice(firstSlashPos, htmlPos + 5);\n  var link = $(\"#devdoc-nav a[href$='\"+ pathPageName+\"']\");\n  if ((link.length == 0) && ((fullPageName.indexOf(\"/guide/\") != -1) || (fullPageName.indexOf(\"/resources/\") != -1))) { \n// if there's no match, then let's backstep through the directory until we find an index.html page that matches our ancestor directories (only for dev guide and resources)\n    lastBackstep = pathPageName.lastIndexOf(\"/\");\n    while (link.length == 0) {\n      backstepDirectory = pathPageName.lastIndexOf(\"/\", lastBackstep);\n      link = $(\"#devdoc-nav a[href$='\"+ pathPageName.slice(0, backstepDirectory + 1)+\"index.html']\");\n      lastBackstep = pathPageName.lastIndexOf(\"/\", lastBackstep - 1);\n      if (lastBackstep == 0) break;\n    }\n  }\n\n  // add 'selected' to the <li> or <div> that wraps this <a>\n  link.parent().addClass('selected');\n\n  // if we're in a toggleable root link (<li class=toggle-list><div><a>)\n  if (link.parent().parent().hasClass('toggle-list')) {\n    toggle(link.parent().parent(), false); // open our own list\n    // then also check if we're in a third-level nested list that's toggleable\n    if (link.parent().parent().parent().is(':hidden')) {\n      toggle(link.parent().parent().parent().parent(), false); // open the super parent list\n    }\n  }\n  // if we're in a normal nav link (<li><a>) and the parent <ul> is hidden\n  else if (link.parent().parent().is(':hidden')) {\n    toggle(link.parent().parent().parent(), false); // open the parent list\n    // then also check if the parent list is also nested in a hidden list\n    if (link.parent().parent().parent().parent().is(':hidden')) {\n      toggle(link.parent().parent().parent().parent().parent(), false); // open the super parent list\n    }\n  }\n}\n\n/* Resize the height of the nav panels in the reference,\n * and save the new size to a cookie */\nfunction resizePackagesHeight() {\n  var windowHeight = ($(window).height() - HEADER_HEIGHT);\n  var swapperHeight = windowHeight - 13; // move 13px for swapper link at the bottom\n  resizePackagesNav.css({maxHeight:swapperHeight + \"px\"});\n  classesNav.css({height:swapperHeight - parseInt(resizePackagesNav.css(\"height\")) + \"px\"});\n\n  $(\"#swapper\").css({height:swapperHeight + \"px\"});\n  $(\"#packages-nav\").css({height:parseInt(resizePackagesNav.css(\"height\")) - 6 + \"px\"}); //move 6px for handle\n\n  var basePath = getBaseUri(location.pathname);\n  var section = basePath.substring(1,basePath.indexOf(\"/\",1));\n  writeCookie(\"height\", resizePackagesNav.css(\"height\"), section, null);\n}\n\n/* Resize the height of the side-nav and doc-content divs,\n * which creates the frame effect */\nfunction resizeHeight() {\n  var docContent = $(\"#doc-content\");\n\n  // Get the window height and always resize the doc-content and side-nav divs\n  var windowHeight = ($(window).height() - HEADER_HEIGHT);\n  docContent.css({height:windowHeight + \"px\"});\n  $(\"#side-nav\").css({height:$(\"#side-nav\").parent().height()});\n\n  var href = location.href;\n  // If in the reference docs, also resize the \"swapper\", \"classes-nav\", and \"nav-tree\"  divs\n  if (href.indexOf(\"/reference/\") != -1) {\n    var swapperHeight = windowHeight - 13;\n    $(\"#swapper\").css({height:swapperHeight + \"px\"});\n    $(\"#classes-nav\").css({height:swapperHeight - parseInt(resizePackagesNav.css(\"height\")) + \"px\"});\n    $(\"#nav-tree\").css({height:swapperHeight + \"px\"});\n\n  // Also resize the \"devdoc-nav\" div\n  } else if ($(\"#devdoc-nav\").length) {\n    $(\"#devdoc-nav\").css({height:sidenav.css(\"height\")});\n  }\n\n  // Hide the \"Go to top\" link if there's no vertical scroll\n  if ( parseInt($(\"#jd-content\").css(\"height\")) <= parseInt(docContent.css(\"height\")) ) {\n    $(\"a[href='#top']\").css({'display':'none'});\n  } else {\n    $(\"a[href='#top']\").css({'display':'inline'});\n  }\n}\n\n/* Resize the width of the \"side-nav\" and the left margin of the \"doc-content\" div,\n * which creates the resizable side bar */\nfunction resizeWidth() {\n   var windowWidth = $(window).width() + \"px\";\n  if (sidenav.length) {\n    var sidenavWidth = sidenav.css(\"width\");\n  } else {\n    var sidenavWidth = 0;\n  }\n  content.css({marginLeft:parseInt(sidenavWidth) + 6 + \"px\"}); //account for 6px-wide handle-bar\n\n  if (isIE6) {\n    content.css({width:parseInt(windowWidth) - parseInt(sidenavWidth) - 6 + \"px\"}); // necessary in order to for scrollbars to be visible\n  }\n\n  resizePackagesNav.css({width:sidenavWidth});\n  classesNav.css({width:sidenavWidth});\n  $(\"#packages-nav\").css({width:sidenavWidth});\n\n \n}\n\n/* For IE6 only,\n * because it can't properly perform auto width for \"doc-content\" div,\n * avoiding this for all browsers provides better performance */\nfunction resizeAll() {\n  resizeHeight();\n  resizeWidth();\n}\n\nfunction getBaseUri(uri) {\n  var intlUrl = (uri.substring(0,6) == \"/intl/\");\n  if (intlUrl) {\n    base = uri.substring(uri.indexOf('intl/')+5,uri.length);\n    base = base.substring(base.indexOf('/')+1, base.length);\n      //alert(\"intl, returning base url: /\" + base);\n    return (\"/\" + base);\n  } else {\n      //alert(\"not intl, returning uri as found.\");\n    return uri;\n  }\n}\n\nfunction requestAppendHL(uri) {\n//append \"?hl=<lang> to an outgoing request (such as to blog)\n  var lang = getLangPref();\n  if (lang) {\n    var q = 'hl=' + lang;\n    uri += '?' + q;\n    window.location = uri;\n    return false;\n  } else {\n    return true;\n  }\n}\n\nfunction loadLast(cookiePath) {\n  var location = window.location.href;\n  if (location.indexOf(\"/\"+cookiePath+\"/\") != -1) {\n    return true;\n  }\n  var lastPage = readCookie(cookiePath + \"_lastpage\");\n  if (lastPage) {\n    window.location = lastPage;\n    return false;\n  }\n  return true;\n}\n\n$(window).unload(function(){\n  var path = getBaseUri(location.pathname);\n  if (path.indexOf(\"/reference/\") != -1) {\n    writeCookie(\"lastpage\", path, \"reference\", null);\n  } else if (path.indexOf(\"/guide/\") != -1) {\n    writeCookie(\"lastpage\", path, \"guide\", null);\n  } else if (path.indexOf(\"/resources/\") != -1) {\n    writeCookie(\"lastpage\", path, \"resources\", null);\n  }\n});\n\nfunction toggle(obj, slide) {\n  var ul = $(\"ul:first\", obj);\n  var li = ul.parent();\n  if (li.hasClass(\"closed\")) {\n    if (slide) {\n      ul.slideDown(\"fast\");\n    } else {\n      ul.show();\n    }\n    li.removeClass(\"closed\");\n    li.addClass(\"open\");\n    $(\".toggle-img\", li).attr(\"title\", \"hide pages\");\n  } else {\n    ul.slideUp(\"fast\");\n    li.removeClass(\"open\");\n    li.addClass(\"closed\");\n    $(\".toggle-img\", li).attr(\"title\", \"show pages\");\n  }\n}\n\nfunction buildToggleLists() {\n  $(\".toggle-list\").each(\n    function(i) {\n      $(\"div:first\", this).append(\"<a class='toggle-img' href='#' title='show pages' onClick='toggle(this.parentNode.parentNode, true); return false;'></a>\");\n      $(this).addClass(\"closed\");\n    });\n}\n\nfunction getNavPref() {\n  var v = readCookie('reference_nav');\n  if (v != NAV_PREF_TREE) {\n    v = NAV_PREF_PANELS;\n  }\n  return v;\n}\n\nfunction chooseDefaultNav() {\n  nav_pref = getNavPref();\n  if (nav_pref == NAV_PREF_TREE) {\n    $(\"#nav-panels\").toggle();\n    $(\"#panel-link\").toggle();\n    $(\"#nav-tree\").toggle();\n    $(\"#tree-link\").toggle();\n  }\n}\n\nfunction swapNav() {\n  if (nav_pref == NAV_PREF_TREE) {\n    nav_pref = NAV_PREF_PANELS;\n  } else {\n    nav_pref = NAV_PREF_TREE;\n    init_default_navtree(toRoot);\n  }\n  var date = new Date();\n  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years\n  writeCookie(\"nav\", nav_pref, \"reference\", date.toGMTString());\n\n  $(\"#nav-panels\").toggle();\n  $(\"#panel-link\").toggle();\n  $(\"#nav-tree\").toggle();\n  $(\"#tree-link\").toggle();\n\n  if ($(\"#nav-tree\").is(':visible')) scrollIntoView(\"nav-tree\");\n  else {\n    scrollIntoView(\"packages-nav\");\n    scrollIntoView(\"classes-nav\");\n  }\n}\n\nfunction scrollIntoView(nav) {\n  var navObj = $(\"#\"+nav);\n  if (navObj.is(':visible')) {\n    var selected = $(\".selected\", navObj);\n    if (selected.length == 0) return;\n    if (selected.is(\"div\")) selected = selected.parent();\n\n    var scrolling = document.getElementById(nav);\n    var navHeight = navObj.height();\n    var offsetTop = selected.position().top;\n    if (selected.parent().parent().is(\".toggle-list\")) offsetTop += selected.parent().parent().position().top;\n    if(offsetTop > navHeight - 92) {\n      scrolling.scrollTop = offsetTop - navHeight + 92;\n    }\n  }\n}\n\nfunction changeTabLang(lang) {\n  var nodes = $(\"#header-tabs\").find(\".\"+lang);\n  for (i=0; i < nodes.length; i++) { // for each node in this language \n    var node = $(nodes[i]);\n    node.siblings().css(\"display\",\"none\"); // hide all siblings \n    if (node.not(\":empty\").length != 0) { //if this languages node has a translation, show it \n      node.css(\"display\",\"inline\");\n    } else { //otherwise, show English instead \n      node.css(\"display\",\"none\");\n      node.siblings().filter(\".en\").css(\"display\",\"inline\");\n    }\n  }\n}\n\nfunction changeNavLang(lang) {\n  var nodes = $(\"#side-nav\").find(\".\"+lang);\n  for (i=0; i < nodes.length; i++) { // for each node in this language \n    var node = $(nodes[i]);\n    node.siblings().css(\"display\",\"none\"); // hide all siblings \n    if (node.not(\":empty\").length != 0) { // if this languages node has a translation, show it \n      node.css(\"display\",\"inline\");\n    } else { // otherwise, show English instead \n      node.css(\"display\",\"none\");\n      node.siblings().filter(\".en\").css(\"display\",\"inline\");\n    }\n  }\n}\n\nfunction changeDocLang(lang) {\n  changeTabLang(lang);\n  changeNavLang(lang);\n}\n\nfunction changeLangPref(lang, refresh) {\n  var date = new Date();\n  expires = date.toGMTString(date.setTime(date.getTime()+(10*365*24*60*60*1000))); // keep this for 50 years\n  //alert(\"expires: \" + expires)\n  writeCookie(\"pref_lang\", lang, null, expires);\n  //changeDocLang(lang);\n  if (refresh) {\n    l = getBaseUri(location.pathname);\n    window.location = l;\n  }\n}\n\nfunction loadLangPref() {\n  var lang = readCookie(\"pref_lang\");\n  if (lang != 0) {\n    $(\"#language\").find(\"option[value='\"+lang+\"']\").attr(\"selected\",true);\n  }\n}\n\nfunction getLangPref() {\n  var lang = $(\"#language\").find(\":selected\").attr(\"value\");\n  if (!lang) {\n    lang = readCookie(\"pref_lang\");\n  }\n  return (lang != 0) ? lang : 'en';\n}\n\n\nfunction toggleContent(obj) {\n  var button = $(obj);\n  var div = $(obj.parentNode);\n  var toggleMe = $(\".toggle-content-toggleme\",div);\n  if (button.hasClass(\"show\")) {\n    toggleMe.slideDown();\n    button.removeClass(\"show\").addClass(\"hide\");\n  } else {\n    toggleMe.slideUp();\n    button.removeClass(\"hide\").addClass(\"show\");\n  }\n  $(\"span\", button).toggle();\n}\n"
  },
  {
    "path": "templates-sdk/assets/android-developer-reference.js",
    "content": "var API_LEVEL_ENABLED_COOKIE = \"api_level_enabled\";\nvar API_LEVEL_INDEX_COOKIE = \"api_level_index\";\nvar minLevelIndex = 0;\n\nfunction toggleApiLevelSelector(checkbox) {\n  var date = new Date();\n  date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years\n  var expiration = date.toGMTString();\n  if (checkbox.checked) {\n    $(\"#apiLevelSelector\").removeAttr(\"disabled\");\n    $(\"#api-level-toggle label\").removeClass(\"disabled\");\n    writeCookie(API_LEVEL_ENABLED_COOKIE, 1, null, expiration);\n  } else {\n    $(\"#apiLevelSelector\").attr(\"disabled\",\"disabled\");\n    $(\"#api-level-toggle label\").addClass(\"disabled\");\n    writeCookie(API_LEVEL_ENABLED_COOKIE, 0, null, expiration);\n  }\n  changeApiLevel();\n}\n\nfunction buildApiLevelSelector() {\n  var userApiLevelEnabled = readCookie(API_LEVEL_ENABLED_COOKIE);\n  var userApiLevelIndex = readCookie(API_LEVEL_INDEX_COOKIE); // No cookie (zero) is the same as maxLevel.\n  \n  if (userApiLevelEnabled == 0) {\n    $(\"#apiLevelSelector\").attr(\"disabled\",\"disabled\");\n  } else {\n    $(\"#apiLevelCheckbox\").attr(\"checked\",\"checked\");\n    $(\"#api-level-toggle label\").removeClass(\"disabled\");\n  }\n  \n  minLevelValue = $(\"body\").attr(\"class\");\n  minLevelIndex = apiKeyToIndex(minLevelValue);\n  var select = $(\"#apiLevelSelector\").html(\"\").change(changeApiLevel);\n  for (var i = SINCE_DATA.length-1; i >= 0; i--) {\n    var option = $(\"<option />\").attr(\"value\",\"\"+SINCE_DATA[i]).append(\"\"+SINCE_LABELS[i]);\n    select.append(option);\n  }\n  \n  // get the DOM element and use setAttribute cuz IE6 fails when using jquery .attr('selected',true)\n  var selectedLevelItem = $(\"#apiLevelSelector option\").get(SINCE_DATA.length - userApiLevelIndex - 1);\n  selectedLevelItem.setAttribute('selected',true);\n}\n\nfunction changeApiLevel() {\n  var userApiLevelEnabled = readCookie(API_LEVEL_ENABLED_COOKIE);\n  var selectedLevelIndex = SINCE_DATA.length - 1;\n  \n  if (userApiLevelEnabled == 0) {\n    toggleVisisbleApis(selectedLevelIndex, \"body\");\n  } else {\n    selectedLevelIndex = getSelectedLevelIndex();\n    toggleVisisbleApis(selectedLevelIndex, \"body\");\n    \n    var date = new Date();\n    date.setTime(date.getTime()+(10*365*24*60*60*1000)); // keep this for 10 years\n    var expiration = date.toGMTString();\n    writeCookie(API_LEVEL_INDEX_COOKIE, selectedLevelIndex, null, expiration);\n  }\n  \n  var thing = ($(\"#jd-header\").html().indexOf(\"package\") != -1) ? \"package\" : \"class\";\n  showApiWarning(thing, selectedLevelIndex, minLevelIndex);\n}\n\nfunction showApiWarning(thing, selectedLevelIndex, minLevelIndex) {\n  if (selectedLevelIndex < minLevelIndex) {\n          $(\"#naMessage\").show().html(\"<div><p><strong>This \" + thing\n                  + \" is not available with API version \"\n                  + SINCE_LABELS[selectedLevelIndex] + \".</strong></p>\"\n              + \"<p>To reveal this \"\n              + \"document, change the value in the API filter above.</p>\");\n  } else {\n    $(\"#naMessage\").hide();\n  }\n}\n\nfunction toggleVisisbleApis(selectedLevelIndex, context) {\n  var apis = $(\".api\",context);\n  apis.each(function(i) {\n    var obj = $(this);\n    var className = obj.attr(\"class\");\n    var apiLevelPos = className.lastIndexOf(\"-\")+1;\n    var apiLevelEndPos = className.indexOf(\" \", apiLevelPos);\n    apiLevelEndPos = apiLevelEndPos != -1 ? apiLevelEndPos : className.length;\n    var apiLevelName = className.substring(apiLevelPos, apiLevelEndPos);\n    var apiLevelIndex = apiKeyToIndex(apiLevelName);\n    if (apiLevelIndex > selectedLevelIndex) {\n      obj.addClass(\"absent\").attr(\"title\",\"Requires API Level \"+SINCE_LABELS[apiLevelIndex]+\" or higher\");\n    } else {\n      obj.removeClass(\"absent\").removeAttr(\"title\");\n    }\n  });\n}\n\nfunction apiKeyToIndex(key) {\n  for (i = 0; i < SINCE_DATA.length; i++) {\n    if (SINCE_DATA[i] == key) {\n      return i;\n    }\n  }\n  return -1;\n}\n\nfunction getSelectedLevelIndex() {\n  return SINCE_DATA.length - $(\"#apiLevelSelector\").attr(\"selectedIndex\") - 1;\n}\n\n\n/* NAVTREE */\n\nfunction new_node(me, mom, text, link, children_data, api_level)\n{\n  var node = new Object();\n  node.children = Array();\n  node.children_data = children_data;\n  node.depth = mom.depth + 1;\n\n  node.li = document.createElement(\"li\");\n  mom.get_children_ul().appendChild(node.li);\n\n  node.label_div = document.createElement(\"div\");\n  node.label_div.className = \"label\";\n  if (api_level != null) {\n    $(node.label_div).addClass(\"api\");\n    $(node.label_div).addClass(\"api-level-\"+api_level);\n  }\n  node.li.appendChild(node.label_div);\n  node.label_div.style.paddingLeft = 10*node.depth + \"px\";\n\n  if (children_data == null) {\n    // 12 is the width of the triangle and padding extra space\n    node.label_div.style.paddingLeft = ((10*node.depth)+12) + \"px\";\n  } else {\n    node.label_div.style.paddingLeft = 10*node.depth + \"px\";\n    node.expand_toggle = document.createElement(\"a\");\n    node.expand_toggle.href = \"javascript:void(0)\";\n    node.expand_toggle.onclick = function() {\n          if (node.expanded) {\n            $(node.get_children_ul()).slideUp(\"fast\");\n            node.plus_img.src = me.toroot + \"assets/images/triangle-closed-small.png\";\n            node.expanded = false;\n          } else {\n            expand_node(me, node);\n          }\n       };\n    node.label_div.appendChild(node.expand_toggle);\n\n    node.plus_img = document.createElement(\"img\");\n    node.plus_img.src = me.toroot + \"assets/images/triangle-closed-small.png\";\n    node.plus_img.className = \"plus\";\n    node.plus_img.border = \"0\";\n    node.expand_toggle.appendChild(node.plus_img);\n\n    node.expanded = false;\n  }\n\n  var a = document.createElement(\"a\");\n  node.label_div.appendChild(a);\n  node.label = document.createTextNode(text);\n  a.appendChild(node.label);\n  if (link) {\n    a.href = me.toroot + link;\n  } else {\n    if (children_data != null) {\n      a.className = \"nolink\";\n      a.href = \"javascript:void(0)\";\n      a.onclick = node.expand_toggle.onclick;\n      // This next line shouldn't be necessary.  I'll buy a beer for the first\n      // person who figures out how to remove this line and have the link\n      // toggle shut on the first try. --joeo@android.com\n      node.expanded = false;\n    }\n  }\n  \n\n  node.children_ul = null;\n  node.get_children_ul = function() {\n      if (!node.children_ul) {\n        node.children_ul = document.createElement(\"ul\");\n        node.children_ul.className = \"children_ul\";\n        node.children_ul.style.display = \"none\";\n        node.li.appendChild(node.children_ul);\n      }\n      return node.children_ul;\n    };\n\n  return node;\n}\n\nfunction expand_node(me, node)\n{\n  if (node.children_data && !node.expanded) {\n    if (node.children_visited) {\n      $(node.get_children_ul()).slideDown(\"fast\");\n    } else {\n      get_node(me, node);\n      if ($(node.label_div).hasClass(\"absent\")) $(node.get_children_ul()).addClass(\"absent\");\n      $(node.get_children_ul()).slideDown(\"fast\");\n    }\n    node.plus_img.src = me.toroot + \"assets/images/triangle-opened-small.png\";\n    node.expanded = true;\n    \n    // perform api level toggling because new nodes are new to the DOM\n    var selectedLevel = $(\"#apiLevelSelector option:selected\").val();\n    toggleVisisbleApis(selectedLevel, \"#side-nav\");\n  }\n}\n\nfunction get_node(me, mom)\n{\n  mom.children_visited = true;\n  for (var i in mom.children_data) {\n    var node_data = mom.children_data[i];\n    mom.children[i] = new_node(me, mom, node_data[0], node_data[1],\n        node_data[2], node_data[3]);\n  }\n}\n\nfunction this_page_relative(toroot)\n{\n  var full = document.location.pathname;\n  var file = \"\";\n  if (toroot.substr(0, 1) == \"/\") {\n    if (full.substr(0, toroot.length) == toroot) {\n      return full.substr(toroot.length);\n    } else {\n      // the file isn't under toroot.  Fail.\n      return null;\n    }\n  } else {\n    if (toroot != \"./\") {\n      toroot = \"./\" + toroot;\n    }\n    do {\n      if (toroot.substr(toroot.length-3, 3) == \"../\" || toroot == \"./\") {\n        var pos = full.lastIndexOf(\"/\");\n        file = full.substr(pos) + file;\n        full = full.substr(0, pos);\n        toroot = toroot.substr(0, toroot.length-3);\n      }\n    } while (toroot != \"\" && toroot != \"/\");\n    return file.substr(1);\n  }\n}\n\nfunction find_page(url, data)\n{\n  var nodes = data;\n  var result = null;\n  for (var i in nodes) {\n    var d = nodes[i];\n    if (d[1] == url) {\n      return new Array(i);\n    }\n    else if (d[2] != null) {\n      result = find_page(url, d[2]);\n      if (result != null) {\n        return (new Array(i).concat(result));\n      }\n    }\n  }\n  return null;\n}\n\nfunction load_navtree_data(toroot) {\n  var navtreeData = document.createElement(\"script\");\n  navtreeData.setAttribute(\"type\",\"text/javascript\");\n  navtreeData.setAttribute(\"src\", toroot+\"navtree_data.js\");\n  $(\"head\").append($(navtreeData));\n}\n\nfunction init_default_navtree(toroot) {\n  init_navtree(\"nav-tree\", toroot, NAVTREE_DATA);\n  \n  // perform api level toggling because because the whole tree is new to the DOM\n  var selectedLevel = $(\"#apiLevelSelector option:selected\").val();\n  toggleVisisbleApis(selectedLevel, \"#side-nav\");\n}\n\nfunction init_navtree(navtree_id, toroot, root_nodes)\n{\n  var me = new Object();\n  me.toroot = toroot;\n  me.node = new Object();\n\n  me.node.li = document.getElementById(navtree_id);\n  me.node.children_data = root_nodes;\n  me.node.children = new Array();\n  me.node.children_ul = document.createElement(\"ul\");\n  me.node.get_children_ul = function() { return me.node.children_ul; };\n  //me.node.children_ul.className = \"children_ul\";\n  me.node.li.appendChild(me.node.children_ul);\n  me.node.depth = 0;\n\n  get_node(me, me.node);\n\n  me.this_page = this_page_relative(toroot);\n  me.breadcrumbs = find_page(me.this_page, root_nodes);\n  if (me.breadcrumbs != null && me.breadcrumbs.length != 0) {\n    var mom = me.node;\n    for (var i in me.breadcrumbs) {\n      var j = me.breadcrumbs[i];\n      mom = mom.children[j];\n      expand_node(me, mom);\n    }\n    mom.label_div.className = mom.label_div.className + \" selected\";\n    addLoadEvent(function() {\n      scrollIntoView(\"nav-tree\");\n      });\n  }\n}\n\n/* TOGGLE INHERITED MEMBERS */\n\n/* Toggle an inherited class (arrow toggle)\n * @param linkObj  The link that was clicked.\n * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.\n *                'null' to simply toggle.\n */\nfunction toggleInherited(linkObj, expand) {\n    var base = linkObj.getAttribute(\"id\");\n    var list = document.getElementById(base + \"-list\");\n    var summary = document.getElementById(base + \"-summary\");\n    var trigger = document.getElementById(base + \"-trigger\");\n    var a = $(linkObj);\n    if ( (expand == null && a.hasClass(\"closed\")) || expand ) {\n        list.style.display = \"none\";\n        summary.style.display = \"block\";\n        trigger.src = toRoot + \"assets/images/triangle-opened.png\";\n        a.removeClass(\"closed\");\n        a.addClass(\"opened\");\n    } else if ( (expand == null && a.hasClass(\"opened\")) || (expand == false) ) {\n        list.style.display = \"block\";\n        summary.style.display = \"none\";\n        trigger.src = toRoot + \"assets/images/triangle-closed.png\";\n        a.removeClass(\"opened\");\n        a.addClass(\"closed\");\n    }\n    return false;\n}\n\n/* Toggle all inherited classes in a single table (e.g. all inherited methods)\n * @param linkObj  The link that was clicked.\n * @param expand  'true' to ensure it's expanded. 'false' to ensure it's closed.\n *                'null' to simply toggle.\n */\nfunction toggleAllInherited(linkObj, expand) {\n  var a = $(linkObj);\n  var table = $(a.parent().parent().parent()); // ugly way to get table/tbody\n  var expandos = $(\".jd-expando-trigger\", table);\n  if ( (expand == null && a.text() == \"[Expand]\") || expand ) {\n    expandos.each(function(i) {\n      toggleInherited(this, true);\n    });\n    a.text(\"[Collapse]\");\n  } else if ( (expand == null && a.text() == \"[Collapse]\") || (expand == false) ) {\n    expandos.each(function(i) {\n      toggleInherited(this, false);\n    });\n    a.text(\"[Expand]\");\n  }\n  return false;\n}\n\n/* Toggle all inherited members in the class (link in the class title)\n */\nfunction toggleAllClassInherited() {\n  var a = $(\"#toggleAllClassInherited\"); // get toggle link from class title\n  var toggles = $(\".toggle-all\", $(\"#doc-content\"));\n  if (a.text() == \"[Expand All]\") {\n    toggles.each(function(i) {\n      toggleAllInherited(this, true);\n    });\n    a.text(\"[Collapse All]\");\n  } else {\n    toggles.each(function(i) {\n      toggleAllInherited(this, false);\n    });\n    a.text(\"[Expand All]\");\n  }\n  return false;\n}\n\n/* Expand all inherited members in the class. Used when initiating page search */\nfunction ensureAllInheritedExpanded() {\n  var toggles = $(\".toggle-all\", $(\"#doc-content\"));\n  toggles.each(function(i) {\n    toggleAllInherited(this, true);\n  });\n  $(\"#toggleAllClassInherited\").text(\"[Collapse All]\");\n}\n\n\n/* HANDLE KEY EVENTS\n * - Listen for Ctrl+F (Cmd on Mac) and expand all inherited members (to aid page search)\n */\nvar agent = navigator['userAgent'].toLowerCase();\nvar mac = agent.indexOf(\"macintosh\") != -1;\n\n$(document).keydown( function(e) {\nvar control = mac ? e.metaKey && !e.ctrlKey : e.ctrlKey; // get ctrl key\n  if (control && e.which == 70) {  // 70 is \"F\"\n    ensureAllInheritedExpanded();\n  }\n});"
  },
  {
    "path": "templates-sdk/assets/carousel.js",
    "content": "\n////////////////////////////////////////////////////////\n\n\n\n/*\n *  Slideshow 1.0\n *  Used on /index.html and /develop/index.html for carousel\n *\n *  Sample usage:\n *  HTML -\n *  <div class=\"slideshow-container\">\n *   <a href=\"\" class=\"slideshow-prev\">Prev</a>\n *   <a href=\"\" class=\"slideshow-next\">Next</a>\n *   <ul>\n *       <li class=\"item\"><img src=\"images/marquee1.jpg\"></li>\n *       <li class=\"item\"><img src=\"images/marquee2.jpg\"></li>\n *       <li class=\"item\"><img src=\"images/marquee3.jpg\"></li>\n *       <li class=\"item\"><img src=\"images/marquee4.jpg\"></li>\n *   </ul>\n *  </div>\n *\n *   <script type=\"text/javascript\">\n *   $('.slideshow-container').dacSlideshow({\n *       auto: true,\n *       btnPrev: '.slideshow-prev',\n *       btnNext: '.slideshow-next'\n *   });\n *   </script>\n *\n *  Options:\n *  btnPrev:    optional identifier for previous button\n *  btnNext:    optional identifier for next button\n *  btnPause:   optional identifier for pause button\n *  auto:       whether or not to auto-proceed\n *  speed:      animation speed\n *  autoTime:   time between auto-rotation\n *  easing:     easing function for transition\n *  start:      item to select by default\n *  scroll:     direction to scroll in\n *  pagination: whether or not to include dotted pagination\n *\n */\n\n (function($) {\n $.fn.dacSlideshow = function(o) {\n\n     //Options - see above\n     o = $.extend({\n         btnPrev:   null,\n         btnNext:   null,\n         btnPause:  null,\n         auto:      true,\n         speed:     500,\n         autoTime:  12000,\n         easing:    null,\n         start:     0,\n         scroll:    1,\n         pagination: true\n\n     }, o || {});\n\n     //Set up a carousel for each\n     return this.each(function() {\n\n         var running = false;\n         var animCss = o.vertical ? \"top\" : \"left\";\n         var sizeCss = o.vertical ? \"height\" : \"width\";\n         var div = $(this);\n         var ul = $(\"ul\", div);\n         var tLi = $(\"li\", ul);\n         var tl = tLi.size();\n         var timer = null;\n\n         var li = $(\"li\", ul);\n         var itemLength = li.size();\n         var curr = o.start;\n\n         li.css({float: o.vertical ? \"none\" : \"left\"});\n         ul.css({margin: \"0\", padding: \"0\", position: \"relative\", \"list-style-type\": \"none\", \"z-index\": \"1\"});\n         div.css({position: \"relative\", \"z-index\": \"2\", left: \"0px\"});\n\n         var liSize = o.vertical ? height(li) : width(li);\n         var ulSize = liSize * itemLength;\n         var divSize = liSize;\n\n         li.css({width: li.width(), height: li.height()});\n         ul.css(sizeCss, ulSize+\"px\").css(animCss, -(curr*liSize));\n\n         div.css(sizeCss, divSize+\"px\");\n\n         //Pagination\n         if (o.pagination) {\n             var pagination = $(\"<div class='pagination'></div>\");\n             var pag_ul = $(\"<ul></ul>\");\n             if (tl > 1) {\n               for (var i=0;i<tl;i++) {\n                    var li = $(\"<li>\"+i+\"</li>\");\n                    pag_ul.append(li);\n                    if (i==o.start) li.addClass('active');\n                        li.click(function() {\n                        go(parseInt($(this).text()));\n                    })\n                }\n                pagination.append(pag_ul);\n                div.append(pagination);\n             }\n         }\n\n         //Previous button\n         if(o.btnPrev)\n             $(o.btnPrev).click(function(e) {\n                 e.preventDefault();\n                 return go(curr-o.scroll);\n             });\n\n         //Next button\n         if(o.btnNext)\n             $(o.btnNext).click(function(e) {\n                 e.preventDefault();\n                 return go(curr+o.scroll);\n             });\n\n         //Pause button\n         if(o.btnPause)\n             $(o.btnPause).click(function(e) {\n                 e.preventDefault();\n                 if ($(this).hasClass('paused')) {\n                     startRotateTimer();\n                 } else {\n                     pauseRotateTimer();\n                 }\n             });\n\n         //Auto rotation\n         if(o.auto) startRotateTimer();\n\n         function startRotateTimer() {\n             clearInterval(timer);\n             timer = setInterval(function() {\n                  if (curr == tl-1) {\n                    go(0);\n                  } else {\n                    go(curr+o.scroll);\n                  }\n              }, o.autoTime);\n             $(o.btnPause).removeClass('paused');\n         }\n\n         function pauseRotateTimer() {\n             clearInterval(timer);\n             $(o.btnPause).addClass('paused');\n         }\n\n         //Go to an item\n         function go(to) {\n             if(!running) {\n\n                 if(to<0) {\n                    to = itemLength-1;\n                 } else if (to>itemLength-1) {\n                    to = 0;\n                 }\n                 curr = to;\n\n                 running = true;\n\n                 ul.animate(\n                     animCss == \"left\" ? { left: -(curr*liSize) } : { top: -(curr*liSize) } , o.speed, o.easing,\n                     function() {\n                         running = false;\n                     }\n                 );\n\n                 $(o.btnPrev + \",\" + o.btnNext).removeClass(\"disabled\");\n                 $( (curr-o.scroll<0 && o.btnPrev)\n                     ||\n                    (curr+o.scroll > itemLength && o.btnNext)\n                     ||\n                    []\n                  ).addClass(\"disabled\");\n\n\n                 var nav_items = $('li', pagination);\n                 nav_items.removeClass('active');\n                 nav_items.eq(to).addClass('active');\n\n\n             }\n             if(o.auto) startRotateTimer();\n             return false;\n         };\n     });\n };\n\n function css(el, prop) {\n     return parseInt($.css(el[0], prop)) || 0;\n };\n function width(el) {\n     return  el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');\n };\n function height(el) {\n     return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');\n };\n\n })(jQuery);\n\n\n/*\n *  dacSlideshow 1.0\n *  Used on develop/index.html for side-sliding tabs\n *\n *  Sample usage:\n *  HTML -\n *  <div class=\"slideshow-container\">\n *   <a href=\"\" class=\"slideshow-prev\">Prev</a>\n *   <a href=\"\" class=\"slideshow-next\">Next</a>\n *   <ul>\n *       <li class=\"item\"><img src=\"images/marquee1.jpg\"></li>\n *       <li class=\"item\"><img src=\"images/marquee2.jpg\"></li>\n *       <li class=\"item\"><img src=\"images/marquee3.jpg\"></li>\n *       <li class=\"item\"><img src=\"images/marquee4.jpg\"></li>\n *   </ul>\n *  </div>\n *\n *   <script type=\"text/javascript\">\n *   $('.slideshow-container').dacSlideshow({\n *       auto: true,\n *       btnPrev: '.slideshow-prev',\n *       btnNext: '.slideshow-next'\n *   });\n *   </script>\n *\n *  Options:\n *  btnPrev:    optional identifier for previous button\n *  btnNext:    optional identifier for next button\n *  auto:       whether or not to auto-proceed\n *  speed:      animation speed\n *  autoTime:   time between auto-rotation\n *  easing:     easing function for transition\n *  start:      item to select by default\n *  scroll:     direction to scroll in\n *  pagination: whether or not to include dotted pagination\n *\n */\n (function($) {\n $.fn.dacTabbedList = function(o) {\n\n     //Options - see above\n     o = $.extend({\n         speed : 250,\n         easing: null,\n         nav_id: null,\n         frame_id: null\n     }, o || {});\n\n     //Set up a carousel for each\n     return this.each(function() {\n\n         var curr = 0;\n         var running = false;\n         var animCss = \"margin-left\";\n         var sizeCss = \"width\";\n         var div = $(this);\n\n         var nav = $(o.nav_id, div);\n         var nav_li = $(\"li\", nav);\n         var nav_size = nav_li.size();\n         var frame = div.find(o.frame_id);\n         var content_width = $(frame).find('ul').width();\n         //Buttons\n         $(nav_li).click(function(e) {\n           go($(nav_li).index($(this)));\n         })\n\n         //Go to an item\n         function go(to) {\n             if(!running) {\n                 curr = to;\n                 running = true;\n\n                 frame.animate({ 'margin-left' : -(curr*content_width) }, o.speed, o.easing,\n                     function() {\n                         running = false;\n                     }\n                 );\n\n\n                 nav_li.removeClass('active');\n                 nav_li.eq(to).addClass('active');\n\n\n             }\n             return false;\n         };\n     });\n };\n\n function css(el, prop) {\n     return parseInt($.css(el[0], prop)) || 0;\n };\n function width(el) {\n     return  el[0].offsetWidth + css(el, 'marginLeft') + css(el, 'marginRight');\n };\n function height(el) {\n     return el[0].offsetHeight + css(el, 'marginTop') + css(el, 'marginBottom');\n };\n\n })(jQuery);\n\n\n"
  },
  {
    "path": "templates-sdk/assets/joyn-sdk.css",
    "content": "/*generic page style*/ \n\n.background-sdk{\n background-color: rgb(249, 249, 249);\n margin:auto;\n position:relative;\n width:100%;\n padding-bottom:20px;\n width:1402px;\n}\n\n.content-block{\nwidth:1000px;\nmargin:auto;\nmargin-left:200px;\nmargin-right:200px;\npadding-top:10px;\nborder: 1px solid #d1d1d1;\nbackground-color:white;\n}\n\n\n.center{\nwidth: 80%;\nmargin: auto;\n}\n\n.intro{\nmargin-top:10px;\n}\n\n.intro span{\n\tfont-size:17px;\n\tline-height: 20px;\n}\n\n.intro h1{\nborder-bottom : 1px solid #505050;\ncolor:#505050;\n}\n\n\n.content-body{\nmargin-top: 40px;\n}\n\n.content-body p{\n font-size:15px;\n line-height:18px\n}\n.content-body  a, a:link, a:visited, a:active, a:hover{\n\n}\n\n\n.demo-title{\nmargin: 55px 0 15px 130px\n}\n\n.video-frame-carousel{\ndisplay: block;\nmargin: auto;\nwidth: 480px;\nheight: 270px;\n}\n\n.video-frame{\ndisplay: block;\nmargin: auto;\nwidth: 320px;\nheight: 180px;\n}\n\n.video-carousel{\ndisplay: inline-block;\nposition: absolute;\nleft: 15px;\ntop: 95px;\n}\n\n\n\n/*box layout*/\n\n.demo_box{\n width:22%;\n padding:0 1% 0 2%\n}\n\n.demo_box_2{\n width:39%;\n}\n\n.demo_box span{\nfont-size:15px;\nline-height:18px;\n}\n\n.demo_box a{\nfont-size:20px;\nline-height:20px;\ncolor:#ff6600;\n}\n\n\n.seperator{\nborder-left: 1px solid grey;\nborder-right: 1px solid grey;\n}\n\n.seperator_2{\nborder-left: 1px solid grey;\n}\n\n\n/*tutorials*/\n\n.step_header{\nclear: both;\nfont-family: tahoma,verdana,arial,sans-serif;\npadding: 10px 0 5px 10%;\nmargin: 15px 0 0 0;\nwidth: 90%;\n}\n\n.step_content{\nmargin-top:15px;\nmargin-right:10%;\n}\n\n.step_header a{\ntext-decoration:underline;\ncursor: pointer\n}\n.getStarted{\nborder-top: 1px solid #ddd;\nborder-right: 1px solid #999;\nborder-left: 1px solid #ddd;\nposition: relative;\nborder-bottom: 1px solid #ff6600;\nbackground: #fff;\n}\n\n\n.getStarted  h2{\ncolor: #505050;\n}\n\n\n.guide{\n\tborder-top: 1px solid #FF6600;\n}\n\n.guide span{\ncolor: #FF6600;\n}\n\n.step_header p, h2{\nmargin:0 0 0 0;\n}\n\n.step_content p{\nmargin:10px 0;\n}\n\n\n.h_num{\ncolor: #ff6600;\ndisplay: block;\nfloat: left;\nfont-family: tahoma,verdana,arial,sans-serif;\nfont-size: 30px;\nmargin-left: -40px;\nmargin-top: -8px;\nwidth: 40px;\nposition: absolute;\ntop: 25px;\nleft: 85px;\n}\n\n\n\n\n/*lists*/\n\n.list{\nlist-style-type: none;\npadding: 0;\n}\n\n.list p {\n font-size:15px;\n line-height:18px\n}\n\n.list li{\n\tmargin-bottom: 20px;\n}\n.list div{\nbackground-color: #fff;\npadding: 10px;\nposition: relative;\nborder-right: 2px solid #dadada;\nborder-left: 1px solid #eaeaea;\nborder-bottom: 1px solid #ff6600;\nborder-top: 1px solid #eaeaea;\n}\n\n.clickable div:hover{\nbackground-color: #f1f1f1;\n}\n\n.list a{\ntext-decoration:none;\n}\n\n\n\n.list h2{\ncolor: rgb(100, 99, 96);\n}\n\n.api-list-ver{\nposition: absolute;\nright: 20px;\nfont-size: 12px;\ncolor: #666;\n}\n\n.api-list-new{\nposition: absolute;\nright: 20px;\nbottom:10px;\nfont-size: 12px;\ncolor: #f54;\n}\n\n.item-link{ \n  position:absolute; \n  width:100%;\n  height:100%;\n  top:0;\n  left: 0;\n\n  z-index: 1;\n\n} \n\n\n.question,.answer{\n\tbackground-color: #ffffff;\n\tpadding: 10px;\n\tposition:relative\n}\n\n.img-ssh{\n\twidth:20%;\n\tmargin:10px 10% 10px 5%;\n}\n\n#guide-nav{\n\n}\n\n#tutorial-nav{\n\n\n}\n\n.nav-block{\npadding:0;\nborder:0;\n\n}\n\n\n.nav{\nwidth: 180px;\npadding: 5px 1% 5px 1%;\nborder: 1px solid gainsboro;\nfloat: right;\nposition: absolute;\nleft: 60px;\nz-index: 100;\nmargin-top: 120px;\nbackground-color: white;\ndisplay:inline-block;\n}\n\n\n.nav li{\n\tlist-style-type: none;\n}\n\n.nav a{\n\ttext-decoration:none;\n}\n\n.selected a{\n\tcolor:grey;\n} \n\n.code-block{\n\tmargin: 0 2% 0 2%;\n\tpadding: 5px 1% 5px 1%;\n\tborder: 1px solid #ccc;\n\tbackground-color: #fafafa;\n\toverflow: auto;\n\tline-height: inherit;\n}\n\n.guide-block{\n\tmargin: 0 5% 0 5%;\n\tborder-top: 1px solid #ff6600;\n\tpadding-top: 10px;\n}\n\n\n.button-download{\n\t\n\tfont-size: 15px;\n\t\n\theight: 30px;\n\tmargin-bottom: 1%;\n}\n\n\n.dl-btn{\ndisplay: inline-block;\nbackground: url(./images/dl-btn.png) no-repeat 0 0;\npadding: 10px;\nborder-radius: 7px;\nfloat: right;\nfont-weight: bold;\ncolor: #FFF;\ntext-shadow: -1px -1px #000;\ntext-decoration:none;\nmargin-top:23px;\nposition: absolute;\nright: 310px;\n}\n\n.button-download p{\n\tmargin:2px;\n\tfont-size: 12px;\n}\n\n.dl-btn:hover{\n\tbackground-position-y:-143px;\n\ttext-shadow: none;\n\tcolor: #b3b3b3;\n}\n.dl-btn:visited{\n\tcolor: #fff;\n}\n\n.footer{\n\t\n\twidth: 1402px;\n\tmargin:auto;\n\tmargin-bottom:10px;\n}\n\n.list-concepts-1 li{\nline-height: 50px;\n}\n\n.list-concepts-2 li{\nline-height: 35px;\n}\n\n.content-left {\nfloat: left;\ntext-align: center;\nvertical-align: center;\nmargin: 0 0 0 35px;\nwidth:300px;\n}\n\n.content-right {\nmargin: 80px 40px 0 0;\nwidth:300px;\nfloat:right;\n}\n\n.slide-btn div{\nfloat:left;\nheight:12px;\nwidth:12px;\nborder-radius:6px;\nbackground-color:#ccc;\nfloat: left;\nmargin: 0 5px 20px;\n}\n\n.slide-btn  div:hover{\nbackground-color:rgba(255, 102, 0, 0.42);\n}\n\n.left div{\nmargin-left:308px;\n}\n.right div{\nmargin-right:200px;\n}\n\n.demo-text{\nmargin: auto;\nwidth: 480px;\nheight: 270px;\nmargin-top: 20px;\nfont-size: 15px;\n}\n\n.home-img{\nfloat:left;\nmargin: 20px 40px 0 30px;\n}\n/*Java code (generated)*/\n\n\ntd.java, td.java-ln {vertical-align:top;}\ntt.java, tt.java-ln, pre.java, pre.java-ln {line-height:1em; margin-bottom:0em;}\ntd.java-ln { text-align:right; }\ntt.java-ln, pre.java-ln { color:#888888 }\n/* Background       */ span.java0  { font-size: 10pt; color:#ffffff; }\n/* Line numbers       */ span.java1  { font-size: 10pt; color:#808080; }\n/* Multi-line comments       */ span.java2 ,span.com { font-size: 10pt; color:#3f7f5f; }\n/* Single-line comments       */ span.java3  { font-size: 10pt; color:#3f7f5f; }\n/* Keywords       */ span.java4 ,span.kwd { font-size: 10pt; color:#7f0055; font-weight:bold; }\n/* Strings       */ span.java5 ,span.str { font-size: 10pt; color:#2a00ff; }\n/* Character constants       */ span.java6  { font-size: 10pt; color:#990000; }\n/* Numeric constants       */ span.java7  { font-size: 10pt; color:#990000; }\n/* Parenthesis       */ span.java8  { font-size: 10pt; color:#000000; }\n/* Primitive Types       */ span.java9  { font-size: 10pt; color:#7f0055; font-weight:bold; }\n/* Others       */ span.java10,span.pln,span.pun,span.typ,span.lit  { font-size: 10pt; color:#000000; }\n/* Javadoc keywords       */ span.java11  { font-size: 10pt; color:#7f9fbf; }\n/* Javadoc HTML tags       */ span.java12  { font-size: 10pt; color:#7f7f9f; }\n/* Javadoc links       */ span.java13  { font-size: 10pt; color:#3f3fbf; }\n/* Javadoc others       */ span.java14  { font-size: 10pt; color:#3f5fbf; }\n/* Undefined       */ span.java15  { font-size: 10pt; color:#ff6100; }\n/* Annotation       */ span.java16  { font-size: 10pt; color:#646464; }"
  },
  {
    "path": "templates-sdk/assets/joyn-sdk.js",
    "content": "function showStep(show, hideId, stepId){\n\tshow.style.display = 'none';\n\tvar hide = document.getElementById(hideId);\n\tvar step = document.getElementById(stepId);\n\thide.style.display = 'block';\n\tstep.style.display = 'block';\n}\n\nfunction hideStep(hide, showId, stepId){\n\thide.style.display = 'none';\n\tvar show = document.getElementById(showId);\n\tvar step = document.getElementById(stepId);\n\tshow.style.display = 'block';\n\tstep.style.display = 'none';\n}"
  },
  {
    "path": "templates-sdk/assets/jquery-history.js",
    "content": "/**\n * jQuery history event v0.1\n * Copyright (c) 2008 Tom Rodenberg <tarodenberg gmail com>\n * Licensed under the GPL (http://www.gnu.org/licenses/gpl.html) license.\n */\n(function($) {\n    var currentHash, previousNav, timer, hashTrim = /^.*#/;\n\n    var msie = {\n        iframe: null,\n        getDoc: function() {\n            return msie.iframe.contentWindow.document;\n        },\n        getHash: function() {\n            return msie.getDoc().location.hash;\n        },\n        setHash: function(hash) {\n            var d = msie.getDoc();\n            d.open();\n            d.close();\n            d.location.hash = hash;\n        }\n    };\n\n    var historycheck = function() {\n        var hash = msie.iframe ? msie.getHash() : location.hash;\n        if (hash != currentHash) {\n            currentHash = hash;\n            if (msie.iframe) {\n                location.hash = currentHash;\n            }\n            var current = $.history.getCurrent();\n            $.event.trigger('history', [current, previousNav]);\n            previousNav = current;\n        }\n    };\n\n    $.history = {\n        add: function(hash) {\n            hash = '#' + hash.replace(hashTrim, '');\n            if (currentHash != hash) {\n                var previous = $.history.getCurrent();\n                location.hash = currentHash = hash;\n                if (msie.iframe) {\n                    msie.setHash(currentHash);\n                }\n                $.event.trigger('historyadd', [$.history.getCurrent(), previous]);\n            }\n            if (!timer) {\n                timer = setInterval(historycheck, 100);\n            }\n        },\n        getCurrent: function() {\n            if (currentHash) {\n              return currentHash.replace(hashTrim, '');\n            } else { \n              return \"\"; \n            }\n        }\n    };\n\n    $.fn.history = function(fn) {\n        $(this).bind('history', fn);\n    };\n\n    $.fn.historyadd = function(fn) {\n        $(this).bind('historyadd', fn);\n    };\n\n    $(function() {\n        currentHash = location.hash;\n        if ($.browser.msie) {\n            msie.iframe = $('<iframe style=\"display:none\" src=\"javascript:false;\"></iframe>').prependTo('body')[0];\n            msie.setHash(currentHash);\n            currentHash = msie.getHash();\n        }\n    });\n})(jQuery);\n"
  },
  {
    "path": "templates-sdk/assets/prettify.js",
    "content": "(function(){\nvar o=true,r=null,z=false;window.PR_SHOULD_USE_CONTINUATION=o;window.PR_TAB_WIDTH=8;window.PR_normalizedHtml=window.PR=window.prettyPrintOne=window.prettyPrint=void 0;window._pr_isIE6=function(){var N=navigator&&navigator.userAgent&&/\\bMSIE 6\\./.test(navigator.userAgent);window._pr_isIE6=function(){return N};return N};\nvar aa=\"!\",ba=\"!=\",ca=\"!==\",F=\"#\",da=\"%\",ea=\"%=\",G=\"&\",fa=\"&&\",ja=\"&&=\",ka=\"&=\",H=\"(\",la=\"*\",ma=\"*=\",na=\"+=\",oa=\",\",pa=\"-=\",qa=\"->\",ra=\"/\",sa=\"/=\",ta=\":\",ua=\"::\",va=\";\",I=\"<\",wa=\"<<\",xa=\"<<=\",ya=\"<=\",za=\"=\",Aa=\"==\",Ba=\"===\",J=\">\",Ca=\">=\",Da=\">>\",Ea=\">>=\",Fa=\">>>\",Ga=\">>>=\",Ha=\"?\",Ia=\"@\",L=\"[\",M=\"^\",Ta=\"^=\",Ua=\"^^\",Va=\"^^=\",Wa=\"{\",O=\"|\",Xa=\"|=\",Ya=\"||\",Za=\"||=\",$a=\"~\",ab=\"break\",bb=\"case\",cb=\"continue\",db=\"delete\",eb=\"do\",fb=\"else\",gb=\"finally\",hb=\"instanceof\",ib=\"return\",jb=\"throw\",kb=\"try\",lb=\"typeof\",\nmb=\"(?:^^|[+-]\",nb=\"\\\\$1\",ob=\")\\\\s*\",pb=\"&amp;\",qb=\"&lt;\",rb=\"&gt;\",sb=\"&quot;\",tb=\"&#\",ub=\"x\",vb=\"'\",wb='\"',xb=\" \",yb=\"XMP\",zb=\"</\",Ab='=\"',P=\"\",Q=\"\\\\\",Bb=\"b\",Cb=\"t\",Db=\"n\",Eb=\"v\",Fb=\"f\",Gb=\"r\",Hb=\"u\",Ib=\"0\",Jb=\"1\",Kb=\"2\",Lb=\"3\",Mb=\"4\",Nb=\"5\",Ob=\"6\",Pb=\"7\",Qb=\"\\\\x0\",Rb=\"\\\\x\",Sb=\"-\",Tb=\"]\",Ub=\"\\\\\\\\u[0-9A-Fa-f]{4}|\\\\\\\\x[0-9A-Fa-f]{2}|\\\\\\\\[0-3][0-7]{0,2}|\\\\\\\\[0-7]{1,2}|\\\\\\\\[\\\\s\\\\S]|-|[^-\\\\\\\\]\",R=\"g\",Vb=\"\\\\B\",Wb=\"\\\\b\",Xb=\"\\\\D\",Yb=\"\\\\d\",Zb=\"\\\\S\",$b=\"\\\\s\",ac=\"\\\\W\",bc=\"\\\\w\",cc=\"(?:\\\\[(?:[^\\\\x5C\\\\x5D]|\\\\\\\\[\\\\s\\\\S])*\\\\]|\\\\\\\\u[A-Fa-f0-9]{4}|\\\\\\\\x[A-Fa-f0-9]{2}|\\\\\\\\[0-9]+|\\\\\\\\[^ux0-9]|\\\\(\\\\?[:!=]|[\\\\(\\\\)\\\\^]|[^\\\\x5B\\\\x5C\\\\(\\\\)\\\\^]+)\",\ndc=\"(?:\",ec=\")\",fc=\"gi\",gc=\"PRE\",hc='<!DOCTYPE foo PUBLIC \"foo bar\">\\n<foo />',ic=\"\\t\",jc=\"\\n\",kc=\"[^<]+|<!--[\\\\s\\\\S]*?--\\>|<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?\\\\]\\\\]>|</?[a-zA-Z][^>]*>|<\",lc=\"nocode\",mc=' $1=\"$2$3$4\"',S=\"pln\",nc=\"string\",T=\"lang-\",oc=\"src\",U=\"str\",pc=\"'\\\"\",qc=\"'\\\"`\",rc=\"\\\"'\",V=\"com\",sc=\"lang-regex\",tc=\"(/(?=[^/*])(?:[^/\\\\x5B\\\\x5C]|\\\\x5C[\\\\s\\\\S]|\\\\x5B(?:[^\\\\x5C\\\\x5D]|\\\\x5C[\\\\s\\\\S])*(?:\\\\x5D|$))+/)\",uc=\"kwd\",vc=\"^(?:\",wc=\")\\\\b\",xc=\" \\r\\n\\t\\u00a0\",yc=\"lit\",zc=\"typ\",Ac=\"0123456789\",Y=\"pun\",Bc=\"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END break continue do else for if return while case done elif esac eval fi function in local set then until \",\nCc=\"</span>\",Dc='<span class=\"',Ec='\">',Fc=\"$1&nbsp;\",Gc=\"&nbsp;<br />\",Hc=\"<br />\",Ic=\"console\",Jc=\"cannot override language handler %s\",Kc=\"default-markup\",Lc=\"default-code\",Mc=\"dec\",Z=\"lang-js\",$=\"lang-css\",Nc=\"lang-in.tag\",Oc=\"htm\",Pc=\"html\",Qc=\"mxml\",Rc=\"xhtml\",Sc=\"xml\",Tc=\"xsl\",Uc=\" \\t\\r\\n\",Vc=\"atv\",Wc=\"tag\",Xc=\"atn\",Yc=\"lang-uq.val\",Zc=\"in.tag\",$c=\"uq.val\",ad=\"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try alignof align_union asm axiom bool concept concept_map const_cast constexpr decltype dynamic_cast explicit export friend inline late_check mutable namespace nullptr reinterpret_cast static_assert static_cast template typeid typename typeof using virtual wchar_t where \",\nbd=\"c\",cd=\"cc\",dd=\"cpp\",ed=\"cxx\",fd=\"cyc\",gd=\"m\",hd=\"null true false\",id=\"json\",jd=\"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient as base by checked decimal delegate descending event fixed foreach from group implicit in interface internal into is lock object out override orderby params partial readonly ref sbyte sealed stackalloc string select uint ulong unchecked unsafe ushort var \",\nkd=\"cs\",ld=\"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try boolean byte extends final finally implements import instanceof null native package strictfp super synchronized throws transient \",md=\"java\",nd=\"break continue do else for if return while case done elif esac eval fi function in local set then until \",\nod=\"bsh\",pd=\"csh\",qd=\"sh\",rd=\"break continue do else for if return while and as assert class def del elif except exec finally from global import in is lambda nonlocal not or pass print raise try with yield False True None \",sd=\"cv\",td=\"py\",ud=\"caller delete die do dump elsif eval exit foreach for goto if import last local my next no our print package redo require sub undef unless until use wantarray while BEGIN END \",vd=\"perl\",wd=\"pl\",xd=\"pm\",yd=\"break continue do else for if return while alias and begin case class def defined elsif end ensure false in module next nil not or redo rescue retry self super then true undef unless until when yield BEGIN END \",\nzd=\"rb\",Ad=\"break continue do else for if return while auto case char const default double enum extern float goto int long register short signed sizeof static struct switch typedef union unsigned void volatile catch class delete false import new operator private protected public this throw true try debugger eval export function get null set undefined var with Infinity NaN \",Bd=\"js\",Cd=\"regex\",Dd=\"pre\",Ed=\"code\",Fd=\"xmp\",Gd=\"prettyprint\",Hd=\"class\",Id=\"br\",Jd=\"\\r\";\n(function(){var N=function(){for(var a=[aa,ba,ca,F,da,ea,G,fa,ja,ka,H,la,ma,na,oa,pa,qa,ra,sa,ta,ua,va,I,wa,xa,ya,za,Aa,Ba,J,Ca,Da,Ea,Fa,Ga,Ha,Ia,L,M,Ta,Ua,Va,Wa,O,Xa,Ya,Za,$a,ab,bb,cb,db,eb,fb,gb,hb,ib,jb,kb,lb],b=mb,c=0;c<a.length;++c)b+=O+a[c].replace(/([^=<>:&a-z])/g,nb);b+=ob;return b}(),Ja=/&/g,Ka=/</g,La=/>/g,Kd=/\\\"/g;function Ld(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb).replace(Kd,sb)}function ga(a){return a.replace(Ja,pb).replace(Ka,qb).replace(La,rb)}var Md=/&lt;/g,Nd=/&gt;/g,\nOd=/&apos;/g,Pd=/&quot;/g,Qd=/&amp;/g,Rd=/&nbsp;/g;function Sd(a){var b=a.indexOf(G);if(b<0)return a;for(--b;(b=a.indexOf(tb,b+1))>=0;){var c=a.indexOf(va,b);if(c>=0){var d=a.substring(b+3,c),g=10;if(d&&d.charAt(0)===ub){d=d.substring(1);g=16}var i=parseInt(d,g);isNaN(i)||(a=a.substring(0,b)+String.fromCharCode(i)+a.substring(c+1))}}return a.replace(Md,I).replace(Nd,J).replace(Od,vb).replace(Pd,wb).replace(Qd,G).replace(Rd,xb)}function Ma(a){return yb===a.tagName}function W(a,b){switch(a.nodeType){case 1:var c=\na.tagName.toLowerCase();b.push(I,c);for(var d=0;d<a.attributes.length;++d){var g=a.attributes[d];if(g.specified){b.push(xb);W(g,b)}}b.push(J);for(var i=a.firstChild;i;i=i.nextSibling)W(i,b);if(a.firstChild||!/^(?:br|link|img)$/.test(c))b.push(zb,c,J);break;case 2:b.push(a.name.toLowerCase(),Ab,Ld(a.value),wb);break;case 3:case 4:b.push(ga(a.nodeValue));break}}function Na(a){for(var b=0,c=z,d=z,g=0,i=a.length;g<i;++g){var m=a[g];if(m.ignoreCase)d=o;else if(/[a-z]/i.test(m.source.replace(/\\\\u[0-9a-f]{4}|\\\\x[0-9a-f]{2}|\\\\[^ux]/gi,\nP))){c=o;d=z;break}}function l(j){if(j.charAt(0)!==Q)return j.charCodeAt(0);switch(j.charAt(1)){case Bb:return 8;case Cb:return 9;case Db:return 10;case Eb:return 11;case Fb:return 12;case Gb:return 13;case Hb:case ub:return parseInt(j.substring(2),16)||j.charCodeAt(1);case Ib:case Jb:case Kb:case Lb:case Mb:case Nb:case Ob:case Pb:return parseInt(j.substring(1),8);default:return j.charCodeAt(1)}}function n(j){if(j<32)return(j<16?Qb:Rb)+j.toString(16);var f=String.fromCharCode(j);if(f===Q||f===Sb||\nf===L||f===Tb)f=Q+f;return f}function q(j){for(var f=j.substring(1,j.length-1).match(new RegExp(Ub,R)),s=[],k=[],h=f[0]===M,e=h?1:0,p=f.length;e<p;++e){var t=f[e];switch(t){case Vb:case Wb:case Xb:case Yb:case Zb:case $b:case ac:case bc:s.push(t);continue}var u=l(t),x;if(e+2<p&&Sb===f[e+1]){x=l(f[e+2]);e+=2}else x=u;k.push([u,x]);if(!(x<65||u>122)){x<65||u>90||k.push([Math.max(65,u)|32,Math.min(x,90)|32]);x<97||u>122||k.push([Math.max(97,u)&-33,Math.min(x,122)&-33])}}k.sort(function(Oa,Pa){return Oa[0]-\nPa[0]||Pa[1]-Oa[1]});var B=[],E=[NaN,NaN];for(e=0;e<k.length;++e){var A=k[e];if(A[0]<=E[1]+1)E[1]=Math.max(E[1],A[1]);else B.push(E=A)}var D=[L];h&&D.push(M);D.push.apply(D,s);for(e=0;e<B.length;++e){A=B[e];D.push(n(A[0]));if(A[1]>A[0]){A[1]+1>A[0]&&D.push(Sb);D.push(n(A[1]))}}D.push(Tb);return D.join(P)}function v(j){var f=j.source.match(new RegExp(cc,R)),s=f.length,k=[],h,e=0;for(h=0;e<s;++e){var p=f[e];if(p===H)++h;else if(Q===p.charAt(0)){var t=+p.substring(1);if(t&&t<=h)k[t]=-1}}for(e=1;e<k.length;++e)if(-1===\nk[e])k[e]=++b;for(h=e=0;e<s;++e){p=f[e];if(p===H){++h;if(k[h]===undefined)f[e]=dc}else if(Q===p.charAt(0))if((t=+p.substring(1))&&t<=h)f[e]=Q+k[h]}for(h=e=0;e<s;++e)if(M===f[e]&&M!==f[e+1])f[e]=P;if(j.ignoreCase&&c)for(e=0;e<s;++e){p=f[e];var u=p.charAt(0);if(p.length>=2&&u===L)f[e]=q(p);else if(u!==Q)f[e]=p.replace(/[a-zA-Z]/g,function(x){var B=x.charCodeAt(0);return L+String.fromCharCode(B&-33,B|32)+Tb})}return f.join(P)}var w=[];g=0;for(i=a.length;g<i;++g){m=a[g];if(m.global||m.multiline)throw new Error(P+\nm);w.push(dc+v(m)+ec)}return new RegExp(w.join(O),d?fc:R)}var ha=r;function Td(a){if(r===ha){var b=document.createElement(gc);b.appendChild(document.createTextNode(hc));ha=!/</.test(b.innerHTML)}if(ha){var c=a.innerHTML;if(Ma(a))c=ga(c);return c}for(var d=[],g=a.firstChild;g;g=g.nextSibling)W(g,d);return d.join(P)}function Ud(a){var b=0;return function(c){for(var d=r,g=0,i=0,m=c.length;i<m;++i){var l=c.charAt(i);switch(l){case ic:d||(d=[]);d.push(c.substring(g,i));var n=a-b%a;for(b+=n;n>=0;n-=\"                \".length)d.push(\"                \".substring(0,\nn));g=i+1;break;case jc:b=0;break;default:++b}}if(!d)return c;d.push(c.substring(g));return d.join(P)}}var Vd=new RegExp(kc,R),Wd=/^<\\!--/,Xd=/^<\\[CDATA\\[/,Yd=/^<br\\b/i,Qa=/^<(\\/?)([a-zA-Z]+)/;function Zd(a){var b=a.match(Vd),c=[],d=0,g=[];if(b)for(var i=0,m=b.length;i<m;++i){var l=b[i];if(l.length>1&&l.charAt(0)===I){if(!Wd.test(l))if(Xd.test(l)){c.push(l.substring(9,l.length-3));d+=l.length-12}else if(Yd.test(l)){c.push(jc);++d}else if(l.indexOf(lc)>=0&&$d(l)){var n=l.match(Qa)[2],q=1,v;v=i+1;a:for(;v<\nm;++v){var w=b[v].match(Qa);if(w&&w[2]===n)if(w[1]===ra){if(--q===0)break a}else++q}if(v<m){g.push(d,b.slice(i,v+1).join(P));i=v}else g.push(d,l)}else g.push(d,l)}else{var j=Sd(l);c.push(j);d+=j.length}}return{source:c.join(P),tags:g}}function $d(a){return!!a.replace(/\\s(\\w+)\\s*=\\s*(?:\\\"([^\\\"]*)\\\"|'([^\\']*)'|(\\S+))/g,mc).match(/[cC][lL][aA][sS][sS]=\\\"[^\\\"]*\\bnocode\\b/)}function ia(a,b,c,d){if(b){var g={source:b,b:a};c(g);d.push.apply(d,g.c)}}function K(a,b){var c={},d;(function(){for(var m=a.concat(b),\nl=[],n={},q=0,v=m.length;q<v;++q){var w=m[q],j=w[3];if(j)for(var f=j.length;--f>=0;)c[j.charAt(f)]=w;var s=w[1],k=P+s;if(!n.hasOwnProperty(k)){l.push(s);n[k]=r}}l.push(/[\\0-\\uffff]/);d=Na(l)})();var g=b.length,i=function(m){for(var l=m.source,n=m.b,q=[n,S],v=0,w=l.match(d)||[],j={},f=0,s=w.length;f<s;++f){var k=w[f],h=j[k],e,p;if(typeof h===nc)p=z;else{var t=c[k.charAt(0)];if(t){e=k.match(t[1]);h=t[0]}else{for(var u=0;u<g;++u){t=b[u];if(e=k.match(t[1])){h=t[0];break}}e||(h=S)}if((p=h.length>=5&&T===\nh.substring(0,5))&&!(e&&e[1])){p=z;h=oc}p||(j[k]=h)}var x=v;v+=k.length;if(p){var B=e[1],E=k.indexOf(B),A=E+B.length,D=h.substring(5);ia(n+x,k.substring(0,E),i,q);ia(n+x+E,B,Ra(D,B),q);ia(n+x+A,k.substring(A),i,q)}else q.push(n+x,h)}m.c=q};return i}function C(a){var b=[],c=[];if(a.tripleQuotedStrings)b.push([U,/^(?:\\'\\'\\'(?:[^\\'\\\\]|\\\\[\\s\\S]|\\'{1,2}(?=[^\\']))*(?:\\'\\'\\'|$)|\\\"\\\"\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S]|\\\"{1,2}(?=[^\\\"]))*(?:\\\"\\\"\\\"|$)|\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$))/,r,pc]);\nelse a.multiLineStrings?b.push([U,/^(?:\\'(?:[^\\\\\\']|\\\\[\\s\\S])*(?:\\'|$)|\\\"(?:[^\\\\\\\"]|\\\\[\\s\\S])*(?:\\\"|$)|\\`(?:[^\\\\\\`]|\\\\[\\s\\S])*(?:\\`|$))/,r,qc]):b.push([U,/^(?:\\'(?:[^\\\\\\'\\r\\n]|\\\\.)*(?:\\'|$)|\\\"(?:[^\\\\\\\"\\r\\n]|\\\\.)*(?:\\\"|$))/,r,rc]);if(a.hashComments)a.cStyleComments?b.push([V,/^#(?:[^\\r\\n\\/]|\\/(?!\\*)|\\/\\*[^\\r\\n]*?\\*\\/)*/,r,F]):b.push([V,/^#[^\\r\\n]*/,r,F]);if(a.cStyleComments){c.push([V,/^\\/\\/[^\\r\\n]*/,r]);c.push([V,/^\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,r])}a.regexLiterals&&c.push([sc,new RegExp(M+N+tc)]);var d=\na.keywords.replace(/^\\s+|\\s+$/g,P);d.length&&c.push([uc,new RegExp(vc+d.replace(/\\s+/g,O)+wc),r]);b.push([S,/^\\s+/,r,xc]);c.push([yc,/^@[a-z_$][a-z_$@0-9]*/i,r,Ia],[zc,/^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/,r],[S,/^[a-z_$][a-z_$@0-9]*/i,r],[yc,/^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*/i,r,Ac],[Y,/^.[^\\s\\w\\.$@\\'\\\"\\`\\/\\#]*/,r]);return K(b,c)}var ae=C({keywords:Bc,hashComments:o,cStyleComments:o,multiLineStrings:o,regexLiterals:o});function be(a){var b=a.source,c=a.f,d=a.c,\ng=[],i=0,m=r,l=r,n=0,q=0,v=Ud(window.PR_TAB_WIDTH),w=/([\\r\\n ]) /g,j=/(^| ) /gm,f=/\\r\\n?|\\n/g,s=/[ \\r\\n]$/,k=o;function h(p){if(p>i){if(m&&m!==l){g.push(Cc);m=r}if(!m&&l){m=l;g.push(Dc,m,Ec)}var t=ga(v(b.substring(i,p))).replace(k?j:w,Fc);k=s.test(t);var u=window._pr_isIE6()?Gc:Hc;g.push(t.replace(f,u));i=p}}for(;1;){var e;if(e=n<c.length?q<d.length?c[n]<=d[q]:o:z){h(c[n]);if(m){g.push(Cc);m=r}g.push(c[n+1]);n+=2}else if(q<d.length){h(d[q]);l=d[q+1];q+=2}else break}h(b.length);m&&g.push(Cc);a.a=g.join(P)}\nvar X={};function y(a,b){for(var c=b.length;--c>=0;){var d=b[c];if(X.hasOwnProperty(d))Ic in window&&console.i(Jc,d);else X[d]=a}}function Ra(a,b){a&&X.hasOwnProperty(a)||(a=/^\\s*</.test(b)?Kc:Lc);return X[a]}y(ae,[Lc]);y(K([],[[S,/^[^<?]+/],[Mc,/^<!\\w[^>]*(?:>|$)/],[V,/^<\\!--[\\s\\S]*?(?:-\\->|$)/],[T,/^<\\?([\\s\\S]+?)(?:\\?>|$)/],[T,/^<%([\\s\\S]+?)(?:%>|$)/],[Y,/^(?:<[%?]|[%?]>)/],[T,/^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],[Z,/^<script\\b[^>]*>([\\s\\S]+?)<\\/script\\b[^>]*>/i],[$,/^<style\\b[^>]*>([\\s\\S]+?)<\\/style\\b[^>]*>/i],\n[Nc,/^(<\\/?[a-z][^<>]*>)/i]]),[Kc,Oc,Pc,Qc,Rc,Sc,Tc]);y(K([[S,/^[\\s]+/,r,Uc],[Vc,/^(?:\\\"[^\\\"]*\\\"?|\\'[^\\']*\\'?)/,r,rc]],[[Wc,/^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],[Xc,/^(?!style\\b|on)[a-z](?:[\\w:-]*\\w)?/],[Yc,/^=\\s*([^>\\'\\\"\\s]*(?:[^>\\'\\\"\\s\\/]|\\/(?=\\s)))/],[Y,/^[=<>\\/]+/],[Z,/^on\\w+\\s*=\\s*\\\"([^\\\"]+)\\\"/i],[Z,/^on\\w+\\s*=\\s*\\'([^\\']+)\\'/i],[Z,/^on\\w+\\s*=\\s*([^\\\"\\'>\\s]+)/i],[$,/^sty\\w+\\s*=\\s*\\\"([^\\\"]+)\\\"/i],[$,/^sty\\w+\\s*=\\s*\\'([^\\']+)\\'/i],[$,/^sty\\w+\\s*=\\s*([^\\\"\\'>\\s]+)/i]]),[Zc]);y(K([],[[Vc,/^[\\s\\S]+/]]),\n[$c]);y(C({keywords:ad,hashComments:o,cStyleComments:o}),[bd,cd,dd,ed,fd,gd]);y(C({keywords:hd}),[id]);y(C({keywords:jd,hashComments:o,cStyleComments:o}),[kd]);y(C({keywords:ld,cStyleComments:o}),[md]);y(C({keywords:nd,hashComments:o,multiLineStrings:o}),[od,pd,qd]);y(C({keywords:rd,hashComments:o,multiLineStrings:o,tripleQuotedStrings:o}),[sd,td]);y(C({keywords:ud,hashComments:o,multiLineStrings:o,regexLiterals:o}),[vd,wd,xd]);y(C({keywords:yd,hashComments:o,multiLineStrings:o,regexLiterals:o}),\n[zd]);y(C({keywords:Ad,cStyleComments:o,regexLiterals:o}),[Bd]);y(K([],[[U,/^[\\s\\S]+/]]),[Cd]);function Sa(a){var b=a.e,c=a.d;a.a=b;try{var d=Zd(b),g=d.source;a.source=g;a.b=0;a.f=d.tags;Ra(c,g)(a);be(a)}catch(i){if(Ic in window){console.log(i);console.h()}}}function ce(a,b){var c={e:a,d:b};Sa(c);return c.a}function de(a){for(var b=window._pr_isIE6(),c=[document.getElementsByTagName(Dd),document.getElementsByTagName(Ed),document.getElementsByTagName(Fd)],d=[],g=0;g<c.length;++g)for(var i=0,m=c[g].length;i<\nm;++i)d.push(c[g][i]);c=r;var l=Date;l.now||(l={now:function(){return(new Date).getTime()}});var n=0,q;function v(){for(var j=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;n<d.length&&l.now()<j;n++){var f=d[n];if(f.className&&f.className.indexOf(Gd)>=0){var s=f.className.match(/\\blang-(\\w+)\\b/);if(s)s=s[1];for(var k=z,h=f.parentNode;h;h=h.parentNode)if((h.tagName===Dd||h.tagName===Ed||h.tagName===Fd)&&h.className&&h.className.indexOf(Gd)>=0){k=o;break}if(!k){var e=Td(f);e=e.replace(/(?:\\r\\n?|\\n)$/,\nP);q={e:e,d:s,g:f};Sa(q);w()}}}if(n<d.length)setTimeout(v,250);else a&&a()}function w(){var j=q.a;if(j){var f=q.g;if(Ma(f)){for(var s=document.createElement(gc),k=0;k<f.attributes.length;++k){var h=f.attributes[k];if(h.specified){var e=h.name.toLowerCase();if(e===Hd)s.className=h.value;else s.setAttribute(h.name,h.value)}}s.innerHTML=j;f.parentNode.replaceChild(s,f);f=s}else f.innerHTML=j;if(b&&f.tagName===gc)for(var p=f.getElementsByTagName(Id),t=p.length;--t>=0;){var u=p[t];u.parentNode.replaceChild(document.createTextNode(Jd),\nu)}}}v()}window.PR_normalizedHtml=W;window.prettyPrintOne=ce;window.prettyPrint=de;window.PR={combinePrefixPatterns:Na,createSimpleLexer:K,registerLangHandler:y,sourceDecorator:C,PR_ATTRIB_NAME:Xc,PR_ATTRIB_VALUE:Vc,PR_COMMENT:V,PR_DECLARATION:Mc,PR_KEYWORD:uc,PR_LITERAL:yc,PR_NOCODE:lc,PR_PLAIN:S,PR_PUNCTUATION:Y,PR_SOURCE:oc,PR_STRING:U,PR_TAG:Wc,PR_TYPE:zc}})();\n})()\n"
  },
  {
    "path": "templates-sdk/assets/search_autocomplete.js",
    "content": "var gSelectedIndex = -1;\nvar gSelectedID = -1;\nvar gMatches = new Array();\nvar gLastText = \"\";\nvar ROW_COUNT = 20;\nvar gInitialized = false;\nvar DEFAULT_TEXT = \"search javadoc\";\n\nfunction set_row_selected(row, selected)\n{\n    var c1 = row.cells[0];\n  //  var c2 = row.cells[1];\n    if (selected) {\n        c1.className = \"jd-autocomplete jd-selected\";\n  //      c2.className = \"jd-autocomplete jd-selected jd-linktype\";\n    } else {\n        c1.className = \"jd-autocomplete\";\n  //      c2.className = \"jd-autocomplete jd-linktype\";\n    }\n}\n\nfunction set_row_values(toroot, row, match)\n{\n    var link = row.cells[0].childNodes[0];\n    link.innerHTML = match.__hilabel || match.label;\n    link.href = toroot + match.link\n  //  row.cells[1].innerHTML = match.type;\n}\n\nfunction sync_selection_table(toroot)\n{\n    var filtered = document.getElementById(\"search_filtered\");\n    var r; //TR DOM object\n    var i; //TR iterator\n    gSelectedID = -1;\n\n    filtered.onmouseover = function() { \n        if(gSelectedIndex >= 0) {\n          set_row_selected(this.rows[gSelectedIndex], false);\n          gSelectedIndex = -1;\n        }\n    }\n\n    //initialize the table; draw it for the first time (but not visible).\n    if (!gInitialized) {\n        for (i=0; i<ROW_COUNT; i++) {\n            var r = filtered.insertRow(-1);\n            var c1 = r.insertCell(-1);\n        //    var c2 = r.insertCell(-1);\n            c1.className = \"jd-autocomplete\";\n         //   c2.className = \"jd-autocomplete jd-linktype\";\n            var link = document.createElement(\"a\");\n            c1.onmousedown = function() {\n                window.location = this.firstChild.getAttribute(\"href\");\n            }\n            c1.onmouseover = function() {\n                this.className = this.className + \" jd-selected\";\n            }\n            c1.onmouseout = function() {\n                this.className = \"jd-autocomplete\";\n            }\n            c1.appendChild(link);\n        }\n  /*      var r = filtered.insertRow(-1);\n        var c1 = r.insertCell(-1);\n        c1.className = \"jd-autocomplete jd-linktype\";\n        c1.colSpan = 2; */\n        gInitialized = true;\n    }\n\n    //if we have results, make the table visible and initialize result info\n    if (gMatches.length > 0) {\n        document.getElementById(\"search_filtered_div\").className = \"showing\";\n        var N = gMatches.length < ROW_COUNT ? gMatches.length : ROW_COUNT;\n        for (i=0; i<N; i++) {\n            r = filtered.rows[i];\n            r.className = \"show-row\";\n            set_row_values(toroot, r, gMatches[i]);\n            set_row_selected(r, i == gSelectedIndex);\n            if (i == gSelectedIndex) {\n                gSelectedID = gMatches[i].id;\n            }\n        }\n        //start hiding rows that are no longer matches\n        for (; i<ROW_COUNT; i++) {\n            r = filtered.rows[i];\n            r.className = \"no-display\";\n        }\n        //if there are more results we're not showing, so say so.\n/*      if (gMatches.length > ROW_COUNT) {\n            r = filtered.rows[ROW_COUNT];\n            r.className = \"show-row\";\n            c1 = r.cells[0];\n            c1.innerHTML = \"plus \" + (gMatches.length-ROW_COUNT) + \" more\"; \n        } else {\n            filtered.rows[ROW_COUNT].className = \"hide-row\";\n        }*/\n    //if we have no results, hide the table\n    } else {\n        document.getElementById(\"search_filtered_div\").className = \"no-display\";\n    }\n}\n\nfunction search_changed(e, kd, toroot)\n{\n    var search = document.getElementById(\"search_autocomplete\");\n    var text = search.value.replace(/(^ +)|( +$)/g, '');\n\n    // 13 = enter\n    if (e.keyCode == 13) {\n        document.getElementById(\"search_filtered_div\").className = \"no-display\";\n        if (kd && gSelectedIndex >= 0) {\n            window.location = toroot + gMatches[gSelectedIndex].link;\n            return false;\n        } else if (gSelectedIndex < 0) {\n            return true;\n        }\n    }\n    // 38 -- arrow up\n    else if (kd && (e.keyCode == 38)) {\n        if (gSelectedIndex >= 0) {\n            gSelectedIndex--;\n        }\n        sync_selection_table(toroot);\n        return false;\n    }\n    // 40 -- arrow down\n    else if (kd && (e.keyCode == 40)) {\n        if (gSelectedIndex < gMatches.length-1\n                        && gSelectedIndex < ROW_COUNT-1) {\n            gSelectedIndex++;\n        }\n        sync_selection_table(toroot);\n        return false;\n    }\n    else if (!kd) {\n        gMatches = new Array();\n        matchedCount = 0;\n        gSelectedIndex = -1;\n        for (var i=0; i<DATA.length; i++) {\n            var s = DATA[i];\n            if (text.length != 0 &&\n                  s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) {\n                gMatches[matchedCount] = s;\n                matchedCount++;\n            }\n        }\n        rank_autocomplete_results(text);\n        for (var i=0; i<gMatches.length; i++) {\n            var s = gMatches[i];\n            if (gSelectedID == s.id) {\n                gSelectedIndex = i;\n            }\n        }\n        highlight_autocomplete_result_labels(text);\n        sync_selection_table(toroot);\n        return true; // allow the event to bubble up to the search api\n    }\n}\n\nfunction rank_autocomplete_results(query) {\n    query = query || '';\n    if (!gMatches || !gMatches.length)\n      return;\n\n    // helper function that gets the last occurence index of the given regex\n    // in the given string, or -1 if not found\n    var _lastSearch = function(s, re) {\n      if (s == '')\n        return -1;\n      var l = -1;\n      var tmp;\n      while ((tmp = s.search(re)) >= 0) {\n        if (l < 0) l = 0;\n        l += tmp;\n        s = s.substr(tmp + 1);\n      }\n      return l;\n    };\n\n    // helper function that counts the occurrences of a given character in\n    // a given string\n    var _countChar = function(s, c) {\n      var n = 0;\n      for (var i=0; i<s.length; i++)\n        if (s.charAt(i) == c) ++n;\n      return n;\n    };\n\n    var queryLower = query.toLowerCase();\n    var queryAlnum = (queryLower.match(/\\w+/) || [''])[0];\n    var partPrefixAlnumRE = new RegExp('\\\\b' + queryAlnum);\n    var partExactAlnumRE = new RegExp('\\\\b' + queryAlnum + '\\\\b');\n\n    var _resultScoreFn = function(result) {\n        // scores are calculated based on exact and prefix matches,\n        // and then number of path separators (dots) from the last\n        // match (i.e. favoring classes and deep package names)\n        var score = 1.0;\n        var labelLower = result.label.toLowerCase();\n        var t;\n        t = _lastSearch(labelLower, partExactAlnumRE);\n        if (t >= 0) {\n            // exact part match\n            var partsAfter = _countChar(labelLower.substr(t + 1), '.');\n            score *= 200 / (partsAfter + 1);\n        } else {\n            t = _lastSearch(labelLower, partPrefixAlnumRE);\n            if (t >= 0) {\n                // part prefix match\n                var partsAfter = _countChar(labelLower.substr(t + 1), '.');\n                score *= 20 / (partsAfter + 1);\n            }\n        }\n\n        return score;\n    };\n\n    for (var i=0; i<gMatches.length; i++) {\n        gMatches[i].__resultScore = _resultScoreFn(gMatches[i]);\n    }\n\n    gMatches.sort(function(a,b){\n        var n = b.__resultScore - a.__resultScore;\n        if (n == 0) // lexicographical sort if scores are the same\n            n = (a.label < b.label) ? -1 : 1;\n        return n;\n    });\n}\n\nfunction highlight_autocomplete_result_labels(query) {\n    query = query || '';\n    if (!gMatches || !gMatches.length)\n      return;\n\n    var queryLower = query.toLowerCase();\n    var queryAlnumDot = (queryLower.match(/[\\w\\.]+/) || [''])[0];\n    var queryRE = new RegExp(\n        '(' + queryAlnumDot.replace(/\\./g, '\\\\.') + ')', 'ig');\n    for (var i=0; i<gMatches.length; i++) {\n        gMatches[i].__hilabel = gMatches[i].label.replace(\n            queryRE, '<b>$1</b>');\n    }\n}\n\nfunction search_focus_changed(obj, focused)\n{\n    if (focused) {\n        if(obj.value == DEFAULT_TEXT){\n            obj.value = \"\";\n            obj.style.color=\"#000000\";\n        }\n    } else {\n        if(obj.value == \"\"){\n          obj.value = DEFAULT_TEXT;\n          obj.style.color=\"#aaaaaa\";\n        }\n        document.getElementById(\"search_filtered_div\").className = \"no-display\";\n    }\n}\n\nfunction submit_search() {\n  var query = document.getElementById('search_autocomplete').value;\n  document.location = toRoot + 'search.html#q=' + query + '&t=0';\n  return false;\n}\n"
  },
  {
    "path": "templates-sdk/assets/skin-carousel-home.css",
    "content": ".jcarousel-skin-home .jcarousel-container {\n\n    background: #fff;\n}\n\n.jcarousel-skin-home .jcarousel-direction-rtl {\n\tdirection: rtl;\n}\n\n.jcarousel-skin-home .jcarousel-container-horizontal {\n    width: 160px;\n    padding: 20px 40px;\n}\n\n.jcarousel-skin-home .jcarousel-container-vertical {\n    width: 160px;\n    height: 390px;\n    padding: 40px 0;\n\tbackground-color:#fcfcfc;\n}\n\n\n.jcarousel-skin-home .jcarousel-clip {\n    overflow: hidden;\n\twidth:160px;\n}\n\n.jcarousel-skin-home .jcarousel-clip-horizontal {\n   width: 160px;\nheight: 130px;\n}\n\n.jcarousel-skin-home .jcarousel-clip-vertical {\n    width:  160px;\n    height: 390px;\n\tborder-top:1px solid #505050;\n\tborder-bottom:1px solid #505050;\n\tbackground-color:#fcfcfc;\n}\n\n.jcarousel-skin-home .jcarousel-item {\n    width: 160px;\n    height: 90px;\n}\n\n.jcarousel-skin-home .jcarousel-item-horizontal {\n\tmargin-left: 0;\n    margin-right: 10px;\n}\n\n.jcarousel-skin-home .jcarousel-direction-rtl .jcarousel-item-horizontal {\n\tmargin-left: 10px;\n    margin-right: 0;\n}\n\n.jcarousel-skin-home .jcarousel-item-vertical {\n\tpadding:20px 0;\n}\n\n.jcarousel-skin-home .jcarousel-item-placeholder {\n    background: #fff;\n    color: #000;\n}\n\n/**\n *  Horizontal Buttons\n */\n.jcarousel-skin-home .jcarousel-next-horizontal {\n    position: absolute;\n    top: 250px;\n    right: 5px;\n    width: 32px;\n    height: 35px;\n    cursor: pointer;\n    background: transparent url(images/arrow-right.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-home .jcarousel-direction-rtl .jcarousel-next-horizontal {\n    left: 5px;\n    right: auto;\n    background-image: url(images/arrow-left.png);\n}\n\n.jcarousel-skin-home .jcarousel-next-horizontal:hover,\n.jcarousel-skin-home .jcarousel-next-horizontal:focus {\n    background-position: 0 -36px ;\n}\n\n.jcarousel-skin-home .jcarousel-next-horizontal:active {\n}\n\n.jcarousel-skin-home .jcarousel-next-disabled-horizontal,\n.jcarousel-skin-home .jcarousel-next-disabled-horizontal:hover,\n.jcarousel-skin-home .jcarousel-next-disabled-horizontal:focus,\n.jcarousel-skin-home .jcarousel-next-disabled-horizontal:active {\n\n    background-position:0 -72px ;\n    cursor: default;\n}\n\n.jcarousel-skin-home .jcarousel-prev-horizontal {\n    position: absolute;\n    top: 250px;\n    left: 5px;\n    width: 32px;\n    height: 35px;\n    cursor: pointer;\n    background: transparent url(images/arrow-left.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-home .jcarousel-direction-rtl .jcarousel-prev-horizontal {\n    left: auto;\n    right: 5px;\n    background-image: url(images/arrow-right.png);\n}\n\n.jcarousel-skin-home .jcarousel-prev-horizontal:hover, \n.jcarousel-skin-home .jcarousel-prev-horizontal:focus {\n    background-position: 0 -36px ;\n}\n\n.jcarousel-skin-home .jcarousel-prev-horizontal:active {\n}\n\n.jcarousel-skin-home .jcarousel-prev-disabled-horizontal,\n.jcarousel-skin-home .jcarousel-prev-disabled-horizontal:hover,\n.jcarousel-skin-home .jcarousel-prev-disabled-horizontal:focus,\n.jcarousel-skin-home .jcarousel-prev-disabled-horizontal:active {\n    cursor: default;\n    background-position:0 -72px ;\n}\n\n/**\n *  Vertical Buttons\n */\n.jcarousel-skin-home .jcarousel-next-vertical {\n    position: absolute;\n    bottom: -2px;\n    left: 62px;\n    width: 35px;\n    height: 32px;\n    cursor: pointer;\n    background: transparent url(images/arrow-down.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-home .jcarousel-next-vertical:hover,\n.jcarousel-skin-home .jcarousel-next-vertical:focus {\n    background-position:-36px 0;\n}\n\n.jcarousel-skin-home .jcarousel-next-vertical:active {\n}\n\n.jcarousel-skin-home .jcarousel-next-disabled-vertical,\n.jcarousel-skin-home .jcarousel-next-disabled-vertical:hover,\n.jcarousel-skin-home .jcarousel-next-disabled-vertical:focus,\n.jcarousel-skin-home .jcarousel-next-disabled-vertical:active {\n    cursor: default;\n    background-position:-72px 0;\n}\n\n.jcarousel-skin-home .jcarousel-prev-vertical {\n    position: absolute;\n    top: 10px;\n    left: 62px;\n    width: 35px;\n    height: 32px;\n    cursor: pointer;\n    background: transparent url(images/arrow-up.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-home .jcarousel-prev-vertical:hover,\n.jcarousel-skin-home .jcarousel-prev-vertical:focus {\n    background-position:-36px 0;\n}\n\n.jcarousel-skin-home .jcarousel-prev-vertical:active {\n}\n\n.jcarousel-skin-home .jcarousel-prev-disabled-vertical,\n.jcarousel-skin-home .jcarousel-prev-disabled-vertical:hover,\n.jcarousel-skin-home .jcarousel-prev-disabled-vertical:focus,\n.jcarousel-skin-home .jcarousel-prev-disabled-vertical:active {\n    cursor: default;\n    background-position:-72px 0;\n}\n"
  },
  {
    "path": "templates-sdk/assets/skin-carousel-ri.css",
    "content": ".jcarousel-skin-tango .jcarousel-container {\n\n    background: #fff;\n    border-top: 1px solid #ff6600;\n}\n\n.jcarousel-skin-tango .jcarousel-direction-rtl {\n\tdirection: rtl;\n}\n\n.jcarousel-skin-tango .jcarousel-container-horizontal {\n    width: 740px;\n    padding: 20px 40px;\n}\n\n.jcarousel-skin-tango .jcarousel-container-vertical {\n    width: 740px;\n    height: 500px;\n    padding: 40px 20px;\n}\n\n.jcarousel-skin-tango .jcarousel-clip {\n    overflow: hidden;\n\twidth:740px;\n}\n\n.jcarousel-skin-tango .jcarousel-clip-horizontal {\n   width: 740px;\nheight: 500px;\n}\n\n.jcarousel-skin-tango .jcarousel-clip-vertical {\n    width:  740px;\n    height: 500px;\n}\n\n.jcarousel-skin-tango .jcarousel-item {\n    width: 740px;\n    height: 500px;\n}\n\n.jcarousel-skin-tango .jcarousel-item-horizontal {\n\tmargin-left: 0;\n    margin-right: 10px;\n}\n\n.jcarousel-skin-tango .jcarousel-direction-rtl .jcarousel-item-horizontal {\n\tmargin-left: 10px;\n    margin-right: 0;\n}\n\n.jcarousel-skin-tango .jcarousel-item-vertical {\n    margin-bottom: 10px;\n}\n\n.jcarousel-skin-tango .jcarousel-item-placeholder {\n    background: #fff;\n    color: #000;\n}\n\n/**\n *  Horizontal Buttons\n */\n.jcarousel-skin-tango .jcarousel-next-horizontal {\n    position: absolute;\n    top: 250px;\n    right: 5px;\n    width: 32px;\n    height: 35px;\n    cursor: pointer;\n    background: transparent url(images/arrow-right.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-tango .jcarousel-direction-rtl .jcarousel-next-horizontal {\n    left: 5px;\n    right: auto;\n    background-image: url(images/arrow-left.png);\n}\n\n.jcarousel-skin-tango .jcarousel-next-horizontal:hover,\n.jcarousel-skin-tango .jcarousel-next-horizontal:focus {\n    background-position: 0 -36px ;\n}\n\n.jcarousel-skin-tango .jcarousel-next-horizontal:active {\n}\n\n.jcarousel-skin-tango .jcarousel-next-disabled-horizontal,\n.jcarousel-skin-tango .jcarousel-next-disabled-horizontal:hover,\n.jcarousel-skin-tango .jcarousel-next-disabled-horizontal:focus,\n.jcarousel-skin-tango .jcarousel-next-disabled-horizontal:active {\n\n    background-position:0 -72px ;\n    cursor: default;\n}\n\n.jcarousel-skin-tango .jcarousel-prev-horizontal {\n    position: absolute;\n    top: 250px;\n    left: 5px;\n    width: 32px;\n    height: 35px;\n    cursor: pointer;\n    background: transparent url(images/arrow-left.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-tango .jcarousel-direction-rtl .jcarousel-prev-horizontal {\n    left: auto;\n    right: 5px;\n    background-image: url(images/arrow-right.png);\n}\n\n.jcarousel-skin-tango .jcarousel-prev-horizontal:hover, \n.jcarousel-skin-tango .jcarousel-prev-horizontal:focus {\n    background-position: 0 -36px ;\n}\n\n.jcarousel-skin-tango .jcarousel-prev-horizontal:active {\n}\n\n.jcarousel-skin-tango .jcarousel-prev-disabled-horizontal,\n.jcarousel-skin-tango .jcarousel-prev-disabled-horizontal:hover,\n.jcarousel-skin-tango .jcarousel-prev-disabled-horizontal:focus,\n.jcarousel-skin-tango .jcarousel-prev-disabled-horizontal:active {\n    cursor: default;\n    background-position:0 -72px ;\n}\n\n/**\n *  Vertical Buttons\n */\n.jcarousel-skin-tango .jcarousel-next-vertical {\n    position: absolute;\n    bottom: 5px;\n    left: 43px;\n    width: 32px;\n    height: 32px;\n    cursor: pointer;\n    background: transparent url(images/next-vertical.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-tango .jcarousel-next-vertical:hover,\n.jcarousel-skin-tango .jcarousel-next-vertical:focus {\n    background-position: 0 -32px;\n}\n\n.jcarousel-skin-tango .jcarousel-next-vertical:active {\n    background-position: 0 -64px;\n}\n\n.jcarousel-skin-tango .jcarousel-next-disabled-vertical,\n.jcarousel-skin-tango .jcarousel-next-disabled-vertical:hover,\n.jcarousel-skin-tango .jcarousel-next-disabled-vertical:focus,\n.jcarousel-skin-tango .jcarousel-next-disabled-vertical:active {\n    cursor: default;\n    background-position: 0 -96px;\n}\n\n.jcarousel-skin-tango .jcarousel-prev-vertical {\n    position: absolute;\n    top: 5px;\n    left: 43px;\n    width: 32px;\n    height: 32px;\n    cursor: pointer;\n    background: transparent url(images/prev-vertical.png) no-repeat 0 0;\n}\n\n.jcarousel-skin-tango .jcarousel-prev-vertical:hover,\n.jcarousel-skin-tango .jcarousel-prev-vertical:focus {\n    background-position: 0 -32px;\n}\n\n.jcarousel-skin-tango .jcarousel-prev-vertical:active {\n    background-position: 0 -64px;\n}\n\n.jcarousel-skin-tango .jcarousel-prev-disabled-vertical,\n.jcarousel-skin-tango .jcarousel-prev-disabled-vertical:hover,\n.jcarousel-skin-tango .jcarousel-prev-disabled-vertical:focus,\n.jcarousel-skin-tango .jcarousel-prev-disabled-vertical:active {\n    cursor: default;\n    background-position: 0 -96px;\n}\n"
  },
  {
    "path": "templates-sdk/assets/style.css",
    "content": ".jd-toptitle {\n    padding-left: 6px;\n    margin-bottom: 30px;\n    font-size: 160%;\n    font-weight: bold;\n}\n\ndiv#jd-content table {\n    border: none;\n}\n\ndiv#jd-content td, div#jd-content th {\n    font-size: small;\n}\n\ndiv#jd-content table.jd-linktable {\n    margin-top: 3px;\n    border-spacing: 0;\n}\n\ndiv#jd-content p.jd-deprecated-warning {\n    margin-top: 0;\n    margin-bottom: 10px;\n}\n\ndiv#jd-content table.jd-linktable th {\n    vertical-align: top;\n    text-align: left;\n    padding-top: 2px;\n    padding-bottom: 2px;\n    padding-left: 7px;\n    padding-right: 7px;\n    border: none;\n    border-top: 1px solid #d2d7d0;\n    background-color: #F7FCF4;\n}\n\ndiv#jd-content table.jd-linktable td {\n    border: none;\n}\n\ndiv#jd-content table.jd-linktable td  p {\n    padding: 0;\n    margin: 0;\n    line-height: 110%;\n}\n\ndiv#jd-content table.jd-linktable .jd-linkcol {\n    vertical-align: top;\n    padding-top: 3px;\n    padding-bottom: 0;\n    padding-left: 7px;\n    padding-right: 7px;\n    border-top: 1px solid #d2d7d0;\n    background-color: #E5F1E0;\n    line-height: 110%;\n}\n\ndiv#jd-content table.jd-linktable .jd-descrcol {\n    vertical-align: top;\n    padding-top: 3px;\n    padding-bottom: 0;\n    padding-left: 7px;\n    padding-right: 7px;\n    border-top: 1px solid #d2d7d0;\n    background-color: #F7FCF4;\n    line-height: 110%;\n}\n\ndiv#jd-content table.jd-linktable .jd-descrcol p {\n    padding: 0;\n    margin: 0;\n    line-height: 110%;\n}\n\ndiv#jd-content table.jd-linktable .jd-valcol {\n    vertical-align: top;\n    padding-top: 3px;\n    padding-bottom: 0;\n    padding-left: 7px;\n    padding-right: 7px;\n    border-top: 1px solid #d2d7d0;\n    background-color: #E5F1E0;\n    line-height: 110%;\n}\n\ndiv#jd-content table.jd-linktable .jd-commentrow {\n    vertical-align: top;\n    padding-top: 3px;\n    padding-bottom: 4px;\n    padding-left: 7px;\n    padding-right: 7px;\n    background-color: #F7FCF4;\n    line-height: 110%;\n}\n\ndiv#jd-content div.jd-inheritedlinks {\n    vertical-align: top;\n    margin-top: 9px;\n    padding-left: 7px;\n    padding-right: 7px;\n    background-color: #F7FCF4;\n    line-height: 110%;\n}\n\ndiv#jd-content .jd-page_title-prefix {\n    padding-top: 2em;\n    margin-bottom: -14pt;\n}\n\ndiv#jd-content {\n    margin-left: 0;\n    margin-right: 10px;\n    margin-bottom: 0;\n}\n\ndiv#jd-content h1 {\n    padding-left: 10px;\n}\n\ndiv#jd-content h2 {\n    padding-left: 10px;\n}\n\ndiv#jd-content h4 {\n    margin-top: 9px;\n    margin-bottom: 1px;\n}\n\ndiv#jd-content .jd-descr h5 {\n    margin-bottom: 8px;\n}\n\ndiv#jd-content .sidebox h3 {\n    margin: 1em 0 0 0;\n}\n\ndiv#jd-content .jd-letterlist {\n    margin-top: 20px;\n    margin-bottom: 0;\n}\n\ndiv#jd-content .jd-lettertable {\n    margin-top: 15px;\n    margin-right: 10px;\n}\ndiv#jd-content .jd-letterentries {\n\tlist-style: none;\n\tmargin-left: 0;\n}\ndiv#jd-content .jd-letterentrycomments {\n    color: gray;\n}\n\ndiv#jd-content table.jd-inheritance-table {\n    margin-top: 0;\n    margin-left: 10px;\n    margin-right: 10px;\n    border-spacing: 0;\n}\n\ndiv#jd-content table.jd-inheritance-table td {\n    border: none;\n    margin: 0;\n    padding: 0;\n    background-color: white;\n}\n\ndiv#jd-content table.jd-inheritance-table .jd-inheritance-space {\n    width: 10px;\n}\n\ndiv#jd-content table.jd-inheritance-table .jd-inheritance-interface-cell {\n    padding-left: 17px;\n}\n\ndiv#jd-content h4.jd-details-title {\n    margin: 0;\n    background-color: #E5F1E0;\n    padding: 2px;\n    padding-left: 10px;\n    padding-right: 10px;\n    margin-top: 15px;\n}\n\ndiv#jd-content .jd-details {\n    margin-top: 0;\n    margin-left: -10px;\n}\n\ndiv#jd-content .jd-details-descr {\n    line-height: 120%;\n    padding-left: 10px;\n    padding-top: 10px;\n    padding-right: 20px;\n}\n\ndiv#jd-content .jd-descr h5,\ndiv#jd-content .jd-details h5 {\n    font-style: normal;\n    text-decoration: none;\n    font-size: 120%;\n}\n\ndiv#jd-content .jd-more {\n}\n\ndiv#jd-content .jd-descr {\n    padding-top: 0;\n}\n\ndiv#jd-content .jd-tagdata {\n    margin-top: 6px;\n    margin-bottom: 6px;\n}\n\ndiv#jd-content .jd-tagtitle {\n    margin-top: 0px;\n}\n\ndiv#jd-content .jd-tagtable {\n    margin-top: 10px;\n    border-spacing: 0;\n}\n\ndiv#jd-content .jd-tagtable th {\n    background: white;\n    padding-left: 10px;\n    padding-right: 10px;\nline-height: 120%;\n}\n\ndiv#jd-content .jd-tagtable th,\ndiv#jd-content .jd-tagtable td {\nline-height: 120%;\n    border: none;\n    margin: 0;\n    text-align: left;\n    padding-top: 0px;\n    padding-bottom: 5px;\n}\n\ndiv#jd-content .Code,code,pre,samp,var {\n    color: #004000;\n}\n\ndiv#jd-content pre.Code {\n    padding-left: 20px;\n}\n\n/* XXX I would really like to apply font-size: 9pt only if var/samp\n   is NOT inside of a .jd-descr div. */\ndiv#jd-content .jd-descr code,var,samp {\n    padding-left: 0px;\n}\n\n#search_autocomplete {\n    font-size: 80%;\n}\n\ndiv#jd-searchbox table.jd-autocomplete-table-hidden {\n    display: none;\n}\n\ndiv#jd-searchbox table.jd-autocomplete-table-showing {\n    z-index: 10;\n    border: 1px solid #3366cc;\n    position: relative;\n    top: -14px;\n    left: 5px;\n    background-color: white;\n}\n\ndiv#jd-searchbox td.jd-autocomplete {\n    font-family: Arial, sans-serif;\n    padding-left: 6px;\n    padding-right: 6px;\n    padding-top: 1px;\n    padding-bottom: 1px;\n    font-size: 80%;\n    border: none;\n    margin: 0;\n    line-height: 105%;\n}\n\ndiv#jd-searchbox td.jd-selected {\n    background-color: #E5F1E0;\n}\n\ndiv#jd-searchbox td.jd-linktype {\n    color: #999999;\n}\n\ndiv#jd-content .jd-expando-trigger {\n    margin-left: -8px;\n    margin-right: 0px;\n    border: none;\n}\n\ndiv#jd-build-id {\n    color: #666;\n    width: 100%;\n    text-align: right;\n    padding-right: 5px;\n    padding-bottom: 3px;\n}\n\n@media print {\n    #jd-searchbox, .jd-nav {\n        display: none;\n    }\n    div#jd-content {\n        margin-top: 0px;\n    }\n}\n\n"
  },
  {
    "path": "templates-sdk/assets/widget.js",
    "content": "(function(e,t){function y(e){for(var t=1,n;n=arguments[t];t++)for(var r in n)e[r]=n[r];return e}function b(e){return Array.prototype.slice.call(e)}function E(e,t){for(var n=0,r;r=e[n];n++)if(t==r)return n;return-1}function S(){var e=b(arguments),t=[];for(var n=0,r=e.length;n<r;n++)e[n].length>0&&t.push(e[n].replace(/\\/$/,\"\"));return t.join(\"/\")}function x(e,t,n){var r=t.split(\"/\"),i=e;while(r.length>1){var s=r.shift();i=i[s]=i[s]||{}}i[r[0]]=n}function T(){}function N(e,t){this.id=this.path=e,this.force=!!t}function C(e,t){this.id=e,this.body=t,typeof t==\"undefined\"&&(this.path=this.resolvePath(e))}function k(e,t){this.deps=e,this.collectResults=t,this.deps.length==0&&this.complete()}function L(e,t){this.deps=e,this.collectResults=t}function A(){for(var e in r)if(r[e].readyState==\"interactive\")return c[r[e].id]}function O(e,t){var r;return!e&&n&&(r=l||A()),r?(delete c[r.scriptId],r.body=t,r.execute()):(f=r=new C(e,t),a[r.id]=r),r}function M(){var e=b(arguments),t,n;return typeof e[0]==\"string\"&&(t=e.shift()),n=e.shift(),O(t,n)}function _(e,t){var n=t.id||\"\",r=n.split(\"/\");r.pop();var i=r.join(\"/\");return e.replace(/^\\./,i)}function D(e,t){function r(e){return C.exports[_(e,t)]}var n=[];for(var i=0,s=e.length;i<s;i++){if(e[i]==\"require\"){n.push(r);continue}if(e[i]==\"exports\"){t.exports=t.exports||{},n.push(t.exports);continue}n.push(r(e[i]))}return n}function P(){var e=b(arguments),t=[],n,r;return typeof e[0]==\"string\"&&(n=e.shift()),w(e[0])&&(t=e.shift()),r=e.shift(),O(n,function(e){function s(){var i=D(b(t),n),s;typeof r==\"function\"?s=r.apply(n,i):s=r,typeof s==\"undefined\"&&(s=n.exports),e(s)}var n=this,i=[];for(var o=0,u=t.length;o<u;o++){var a=t[o];E([\"require\",\"exports\"],a)==-1&&i.push(_(a,n))}i.length>0?H.apply(this,i.concat(s)):s()})}function H(){var e=b(arguments),t,n;typeof e[e.length-1]==\"function\"&&(t=e.pop()),typeof e[e.length-1]==\"boolean\"&&(n=e.pop());var r=new k(B(e,n),n);return t&&r.then(t),r}function B(e,t){var n=[];for(var r=0,i;i=e[r];r++)typeof i==\"string\"&&(i=j(i)),w(i)&&(i=new L(B(i,t),t)),n.push(i);return n}function j(e){var t,n;for(var r=0,i;i=H.matchers[r];r++){var s=i[0],o=i[1];if(t=e.match(s))return o(e)}throw new Error(e+\" was not recognised by loader\")}function I(){return e.using=h,e.provide=p,e.define=d,e.loadrunner=v,F}function q(e){for(var t=0;t<H.bundles.length;t++)for(var n in H.bundles[t])if(n!=e&&E(H.bundles[t][n],e)>-1)return n}var n=e.attachEvent&&!e.opera,r=t.getElementsByTagName(\"script\"),i=0,s,o=t.createElement(\"script\"),u={},a={},f,l,c={},h=e.using,p=e.provide,d=e.define,v=e.loadrunner;for(var m=0,g;g=r[m];m++)if(g.src.match(/loadrunner\\.js(\\?|#|$)/)){s=g;break}var w=Array.isArray||function(e){return e.constructor==Array};T.prototype.then=function(t){var n=this;return this.started||(this.started=!0,this.start()),this.completed?t.apply(e,this.results):(this.callbacks=this.callbacks||[],this.callbacks.push(t)),this},T.prototype.start=function(){},T.prototype.complete=function(){if(!this.completed){this.results=b(arguments),this.completed=!0;if(this.callbacks)for(var t=0,n;n=this.callbacks[t];t++)n.apply(e,this.results)}},N.loaded=[],N.prototype=new T,N.prototype.start=function(){var e=this,t,n,r;return(r=a[this.id])?(r.then(function(){e.complete()}),this):((t=u[this.id])?t.then(function(){e.loaded()}):!this.force&&E(N.loaded,this.id)>-1?this.loaded():(n=q(this.id))?H(n,function(){e.loaded()}):this.load(),this)},N.prototype.load=function(){var t=this;u[this.id]=t;var n=o.cloneNode(!1);this.scriptId=n.id=\"LR\"+ ++i,n.type=\"text/javascript\",n.async=!0,n.onerror=function(){throw new Error(t.path+\" not loaded\")},n.onreadystatechange=n.onload=function(n){n=e.event||n;if(n.type==\"load\"||E([\"loaded\",\"complete\"],this.readyState)>-1)this.onreadystatechange=null,t.loaded()},n.src=this.path,l=this,r[0].parentNode.insertBefore(n,r[0]),l=null,c[n.id]=this},N.prototype.loaded=function(){this.complete()},N.prototype.complete=function(){E(N.loaded,this.id)==-1&&N.loaded.push(this.id),delete u[this.id],T.prototype.complete.apply(this,arguments)},C.exports={},C.prototype=new N,C.prototype.resolvePath=function(e){return S(H.path,e+\".js\")},C.prototype.start=function(){var e,t,n=this,r;this.body?this.execute():(e=C.exports[this.id])?this.exp(e):(t=a[this.id])?t.then(function(e){n.exp(e)}):(bundle=q(this.id))?H(bundle,function(){n.start()}):(a[this.id]=this,this.load())},C.prototype.loaded=function(){var e,t,r=this;n?(t=C.exports[this.id])?this.exp(t):(e=a[this.id])&&e.then(function(e){r.exp(e)}):(e=f,f=null,e.id=e.id||this.id,e.then(function(e){r.exp(e)}))},C.prototype.complete=function(){delete a[this.id],N.prototype.complete.apply(this,arguments)},C.prototype.execute=function(){var e=this;typeof this.body==\"object\"?this.exp(this.body):typeof this.body==\"function\"&&this.body.apply(window,[function(t){e.exp(t)}])},C.prototype.exp=function(e){this.complete(this.exports=C.exports[this.id]=e||{})},k.prototype=new T,k.prototype.start=function(){function t(){var t=[];e.collectResults&&(t[0]={});for(var n=0,r;r=e.deps[n];n++){if(!r.completed)return;r.results.length>0&&(e.collectResults?r instanceof L?y(t[0],r.results[0]):x(t[0],r.id,r.results[0]):t=t.concat(r.results))}e.complete.apply(e,t)}var e=this;for(var n=0,r;r=this.deps[n];n++)r.then(t);return this},L.prototype=new T,L.prototype.start=function(){var e=this,t=0,n=[];return e.collectResults&&(n[0]={}),function r(){var i=e.deps[t++];i?i.then(function(t){i.results.length>0&&(e.collectResults?i instanceof L?y(n[0],i.results[0]):x(n[0],i.id,i.results[0]):n.push(i.results[0])),r()}):e.complete.apply(e,n)}(),this},P.amd={};var F=function(e){return e(H,M,F,define)};F.Script=N,F.Module=C,F.Collection=k,F.Sequence=L,F.Dependency=T,F.noConflict=I,e.loadrunner=F,e.using=H,e.provide=M,e.define=P,H.path=\"\",H.matchers=[],H.matchers.add=function(e,t){this.unshift([e,t])},H.matchers.add(/(^script!|\\.js$)/,function(e){var t=new N(e.replace(/^\\$/,H.path.replace(/\\/$/,\"\")+\"/\").replace(/^script!/,\"\"),!1);return t.id=e,t}),H.matchers.add(/^[a-zA-Z0-9_\\-\\/]+$/,function(e){return new C(e)}),H.bundles=[],s&&(H.path=s.getAttribute(\"data-path\")||s.src.split(/loadrunner\\.js/)[0]||\"\",(main=s.getAttribute(\"data-main\"))&&H.apply(e,main.split(/\\s*,\\s*/)).then(function(){}))})(this,document);window.__twttrlr = loadrunner.noConflict();__twttrlr(function(using, provide, loadrunner, define) {provide(\"util/util\",function(e){function t(e){var t=1,n,r;for(;n=arguments[t];t++)for(r in n)if(!n.hasOwnProperty||n.hasOwnProperty(r))e[r]=n[r];return e}function n(e){for(var t in e)e.hasOwnProperty(t)&&(l(e[t])&&(n(e[t]),c(e[t])&&delete e[t]),(e[t]===undefined||e[t]===null||e[t]===\"\")&&delete e[t]);return e}function r(e,t){var n=0,r;for(;r=e[n];n++)if(t==r)return n;return-1}function i(e,t){if(!e)return null;if(e.filter)return e.filter.apply(e,[t]);if(!t)return e;var n=[],r=0,i;for(;i=e[r];r++)t(i)&&n.push(i);return n}function s(e,t){if(!e)return null;if(e.map)return e.map.apply(e,[t]);if(!t)return e;var n=[],r=0,i;for(;i=e[r];r++)n.push(t(i));return n}function o(e){return e&&e.replace(/(^\\s+|\\s+$)/g,\"\")}function u(e){return{}.toString.call(e).match(/\\s([a-zA-Z]+)/)[1].toLowerCase()}function a(e){return e&&String(e).toLowerCase().indexOf(\"[native code]\")>-1}function f(e,t){if(e.contains)return e.contains(t);var n=t.parentNode;while(n){if(n===e)return!0;n=n.parentNode}return!1}function l(e){return e===Object(e)}function c(e){if(!l(e))return!1;if(Object.keys)return!Object.keys(e).length;for(var t in e)if(e.hasOwnProperty(t))return!1;return!0}e({aug:t,compact:n,containsElement:f,filter:i,map:s,trim:o,indexOf:r,isNative:a,isObject:l,isEmptyObject:c,toType:u})});\nprovide(\"util/events\",function(e){using(\"util/util\",function(t){function r(){this.completed=!1,this.callbacks=[]}var n={bind:function(e,t){return this._handlers=this._handlers||{},this._handlers[e]=this._handlers[e]||[],this._handlers[e].push(t)},unbind:function(e,n){if(!this._handlers[e])return;if(n){var r=t.indexOf(this._handlers[e],n);r>=0&&this._handlers[e].splice(r,1)}else this._handlers[e]=[]},trigger:function(e,t){var n=this._handlers&&this._handlers[e];t.type=e;if(n)for(var r=0,i;i=n[r];r++)i.call(this,t)}};r.prototype.addCallback=function(e){this.completed?e.apply(this,this.results):this.callbacks.push(e)},r.prototype.complete=function(){this.results=makeArray(arguments),this.completed=!0;for(var e=0,t;t=this.callbacks[e];e++)t.apply(this,this.results)},e({Emitter:n,Promise:r})})});\nprovide(\"util/querystring\",function(e){function t(e){return encodeURIComponent(e).replace(/\\+/g,\"%2B\")}function n(e){return decodeURIComponent(e)}function r(e){var n=[],r;for(r in e)e[r]!==null&&typeof e[r]!=\"undefined\"&&n.push(t(r)+\"=\"+t(e[r]));return n.sort().join(\"&\")}function i(e){var t={},r,i,s,o;if(e){r=e.split(\"&\");for(o=0;s=r[o];o++)i=s.split(\"=\"),i.length==2&&(t[n(i[0])]=n(i[1]))}return t}function s(e,t){var n=r(t);return n.length>0?e.indexOf(\"?\")>=0?e+\"&\"+r(t):e+\"?\"+r(t):e}function o(e){var t=e&&e.split(\"?\");return t.length==2?i(t[1]):{}}e({url:s,decodeURL:o,decode:i,encode:r,encodePart:t,decodePart:n})});\nprovide(\"util/twitter\",function(e){using(\"util/querystring\",function(t){function o(e){return typeof e==\"string\"&&n.test(e)&&RegExp.$1.length<=20}function u(e){if(o(e))return RegExp.$1}function a(e){var n=t.decodeURL(e);n.screen_name=u(e);if(n.screen_name)return t.url(\"https://twitter.com/intent/user\",n)}function f(e){return typeof e==\"string\"&&s.test(e)}function l(e,t){t=t===undefined?!0:t;if(f(e))return(t?\"#\":\"\")+RegExp.$1}function c(e){return typeof e==\"string\"&&r.test(e)}function h(e){return c(e)&&RegExp.$1}function p(e){return i.test(e)}var n=/(?:^|(?:https?\\:)?\\/\\/(?:www\\.)?twitter\\.com(?:\\:\\d+)?(?:\\/intent\\/(?:follow|user)\\/?\\?screen_name=|(?:\\/#!)?\\/))@?([\\w]+)(?:\\?|&|$)/i,r=/(?:^|(?:https?\\:)?\\/\\/(?:www\\.)?twitter\\.com(?:\\:\\d+)?\\/(?:#!\\/)?[\\w_]+\\/status(?:es)?\\/)(\\d+)/i,i=/^http(s?):\\/\\/((www\\.)?)twitter\\.com\\//,s=/^#?([^.,<>!\\s\\/#\\-\\(\\)\\'\\\"]+)$/;e({isHashTag:f,hashTag:l,isScreenName:o,screenName:u,isStatus:c,status:h,intentForProfileURL:a,isTwitterURL:p,regexen:{profile:n}})})});\nprovide(\"util/uri\",function(e){using(\"util/querystring\",\"util/util\",\"util/twitter\",function(t,n,r){function i(e,t){var n,r;return t=t||location,/^https?:\\/\\//.test(e)?e:/^\\/\\//.test(e)?t.protocol+e:(n=t.host+(t.port.length?\":\"+t.port:\"\"),e.indexOf(\"/\")!==0&&(r=t.pathname.split(\"/\"),r.pop(),r.push(e),e=\"/\"+r.join(\"/\")),[t.protocol,\"//\",n,e].join(\"\"))}function s(){var e=document.getElementsByTagName(\"link\"),t=0,n;for(;n=e[t];t++)if(n.rel==\"canonical\")return i(n.href)}function o(){var e=document.getElementsByTagName(\"a\"),t=document.getElementsByTagName(\"link\"),n=[e,t],i,s,o=0,u=0,a=/\\bme\\b/,f;for(;i=n[o];o++)for(u=0;s=i[u];u++)if(a.test(s.rel)&&(f=r.screenName(s.href)))return f}e({absolutize:i,getCanonicalURL:s,getScreenNameFromPage:o})})});\nprovide(\"util/typevalidator\",function(e){using(\"util/util\",function(t){function n(e){return e!==undefined&&e!==null&&e!==\"\"}function r(e){return s(e)&&e%1===0}function i(e){return s(e)&&!r(e)}function s(e){return n(e)&&!isNaN(e)}function o(e){return n(e)&&t.toType(e)==\"array\"}function u(e){if(!n(e))return!1;switch(e){case\"on\":case\"ON\":case\"true\":case\"TRUE\":return!0;case\"off\":case\"OFF\":case\"false\":case\"FALSE\":return!1;default:return!!e}}function a(e){if(s(e))return e}function f(e){if(i(e))return e}function l(e){if(r(e))return e}e({hasValue:n,isInt:r,isFloat:i,isNumber:s,isArray:o,asInt:l,asFloat:f,asNumber:a,asBoolean:u})})});\nprovide(\"tfw/util/globals\",function(e){using(\"util/typevalidator\",function(t){function r(){var e=document.getElementsByTagName(\"meta\"),t,r,i=0;n={};for(;t=e[i];i++){if(!/^twitter:/.test(t.name))continue;r=t.name.replace(/^twitter:/,\"\"),n[r]=t.content}}function i(e){return n[e]}function s(e){return t.asBoolean(e)&&(n.dnt=!0),t.asBoolean(n.dnt)}var n;r(),e({init:r,val:i,dnt:s})})});\nprovide(\"util/logger\",function(e){function n(e){window[t]&&window[t].log&&window[t].log(e)}function r(e){window[t]&&window[t].warn&&window[t].warn(e)}function i(e){window[t]&&window[t].error&&window[t].error(e)}var t=[\"con\",\"sole\"].join(\"\");e({info:n,warn:r,error:i})});\nprovide(\"util/domready\",function(e){function l(){t=1;for(var e=0,r=n.length;e<r;e++)n[e]()}var t=0,n=[],r,i,s=!1,o=document.createElement(\"a\"),u=\"DOMContentLoaded\",a=\"addEventListener\",f=\"onreadystatechange\";/^loade|c/.test(document.readyState)&&(t=1),document[a]&&document[a](u,i=function(){document.removeEventListener(u,i,s),l()},s),o.doScroll&&document.attachEvent(f,r=function(){/^c/.test(document.readyState)&&(document.detachEvent(f,r),l())});var c=o.doScroll?function(e){self!=top?t?e():n.push(e):!function(){try{o.doScroll(\"left\")}catch(t){return setTimeout(function(){c(e)},50)}e()}()}:function(e){t?e():n.push(e)};e(c)});\nprovide(\"util/env\",function(e){using(\"util/domready\",\"util/typevalidator\",\"util/logger\",\"tfw/util/globals\",function(t,n,r,i){function f(){return window.devicePixelRatio?window.devicePixelRatio>=1.5:window.matchMedia?window.matchMedia(\"only screen and (min-resolution: 144dpi)\").matches:!1}function l(){return/MSIE \\d/.test(s)}function c(){return/MSIE 6/.test(s)}function h(){return/MSIE 7/.test(s)}function p(){return o}function d(){return\"ontouchstart\"in window||/Opera Mini/.test(s)||navigator.msMaxTouchPoints>0}function v(){var e=document.body.style;return e.transition!==undefined||e.webkitTransition!==undefined||e.mozTransition!==undefined||e.oTransition!==undefined||e.msTransition!==undefined}var s=window.navigator.userAgent,o=!1,u=!1,a=\"twitter-csp-test\";window.twttr=window.twttr||{},twttr.verifyCSP=function(e){var t=document.getElementById(a);u=!0,o=!!e,t&&t.parentNode.removeChild(t)},t(function(){var e;if(c()||h())return o=!1;if(n.asBoolean(i.val(\"widgets:csp\")))return o=!0;e=document.createElement(\"script\"),e.id=a,e.text=\"twttr.verifyCSP(false);\",document.body.appendChild(e),window.setTimeout(function(){if(u)return;r.warn('TWITTER: Content Security Policy restrictions may be applied to your site. Add <meta name=\"twitter:widgets:csp\" content=\"on\"> to supress this warning.'),r.warn(\"TWITTER: Please note: Not all embedded timeline and embedded Tweet functionality is supported when CSP is applied.\")},5e3)}),e({retina:f,anyIE:l,ie6:c,ie7:h,cspEnabled:p,touch:d,cssTransitions:v})})});\nprovide(\"dom/delegate\",function(e){using(\"util/env\",function(t){function i(e){var t=e.getAttribute(\"data-twitter-event-id\");return t?t:(e.setAttribute(\"data-twitter-event-id\",++r),r)}function s(e,t,n){var r=0,i=e&&e.length||0;for(r=0;r<i;r++)e[r].call(t,n)}function o(e,t,n){var r=n||e.target||e.srcElement,i=r.className.split(\" \"),u=0,a,f=i.length;for(;u<f;u++)s(t[\".\"+i[u]],r,e);s(t[r.tagName],r,e);if(e.cease)return;r!==this&&o.call(this,e,t,r.parentElement||r.parentNode)}function u(e,t,n){if(e.addEventListener){e.addEventListener(t,function(r){o.call(e,r,n[t])},!1);return}e.attachEvent&&e.attachEvent(\"on\"+t,function(){o.call(e,e.ownerDocument.parentWindow.event,n[t])})}function a(e,t,r,s){var o=i(e);n[o]=n[o]||{},n[o][t]||(n[o][t]={},u(e,t,n[o])),n[o][t][r]=n[o][t][r]||[],n[o][t][r].push(s)}function f(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent(\"on\"+t,function(){n(window.event)})}function l(e,t,r){var s=i(t),u=n[s]&&n[s];o.call(t,{target:r},u[e])}function c(e){return p(e),h(e),!1}function h(e){e&&e.preventDefault?e.preventDefault():e.returnValue=!1}function p(e){e&&(e.cease=!0)&&e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}var n={},r=-1;e({stop:c,stopPropagation:p,preventDefault:h,delegate:a,on:f,simulate:l})})});\nprovide(\"tfw/util/article\",function(e){using(\"dom/delegate\",\"tfw/util/globals\",\"util/uri\",function(t,n,r){function o(){i=r.getCanonicalURL()||\"\"+document.location;if(!window.top.postMessage)return;if(window==window.top){t.on(window,\"message\",function(e){var t;if(e.data&&e.data[0]!=\"{\")return;try{t=JSON.parse(e.data)}catch(r){}t&&t.name==\"twttr:private:requestArticleUrl\"&&e.source.postMessage(JSON.stringify({name:\"twttr:private:provideArticleUrl\",data:{url:i,dnt:n.dnt()}}),\"*\")});return}t.on(window,\"message\",function(e){var t;if(e.data&&e.data[0]!=\"{\")return;try{t=JSON.parse(e.data)}catch(r){}t&&t.name==\"twttr:private:provideArticleUrl\"&&(i=t.data&&t.data.url,n.dnt(t.data.dnt),s=document.location.href)}),window.top.postMessage(JSON.stringify({name:\"twttr:private:requestArticleUrl\"}),\"*\")}var i,s=\"\";o(),e({url:function(){return i},frameUrl:function(){return s}})})});\nprovide(\"util/iframe\",function(e){e(function(e){var t=(e.replace&&e.replace.ownerDocument||document).createElement(\"div\"),n,r,i;t.innerHTML=\"<iframe allowtransparency='true' frameBorder='0' scrolling='no'></iframe>\",n=t.firstChild,n.src=e.url,n.className=e.className||\"\";if(e.css)for(r in e.css)e.css.hasOwnProperty(r)&&(n.style[r]=e.css[r]);if(e.attributes)for(i in e.attributes)e.attributes.hasOwnProperty(i)&&n.setAttribute(i,e.attributes[i]);return e.replace?e.replace.parentNode.replaceChild(n,e.replace):e.insertTarget&&e.insertTarget.appendChild(n),n})});\nprovide(\"dom/get\",function(e){using(\"util/util\",function(t){function n(e,n,r,i){var s,o,u=[],a,f,l,c,h,p;n=n||document;if(t.isNative(n.getElementsByClassName))return u=t.filter(n.getElementsByClassName(e),function(e){return!r||e.tagName.toLowerCase()==r.toLowerCase()}),[].slice.call(u,0,i||u.length);a=e.split(\" \"),c=a.length,s=n.getElementsByTagName(r||\"*\"),p=s.length;for(l=0;l<c&&p>0;l++){u=[],f=a[l];for(h=0;h<p;h++){o=s[h],~t.indexOf(o.className.split(\" \"),f)&&u.push(o);if(l+1==c&&u.length===i)break}s=u,p=s.length}return u}function r(e,t,r){return n(e,t,r,1)[0]}function i(e,n,r){var s=n&&n.parentNode,o;if(!s||s===r)return;return s.tagName==e?s:(o=s.className.split(\" \"),0===e.indexOf(\".\")&&~t.indexOf(o,e.slice(1))?s:i(e,s,r))}e({all:n,one:r,ancestor:i})})});\nprovide(\"tfw/widget/base\",function(e){using(\"util/util\",\"util/domready\",\"dom/get\",\"tfw/util/globals\",\"util/querystring\",\"util/iframe\",\"util/typevalidator\",function(t,n,r,i,s,o,u){function p(e){var t;if(!e)return;e.ownerDocument?(this.srcEl=e,this.classAttr=e.className.split(\" \")):(this.srcOb=e,this.classAttr=[]),t=this.params(),this.id=v(),this.setLanguage(),this.related=t.related||this.dataAttr(\"related\"),this.partner=t.partner||this.dataAttr(\"partner\")||i.val(\"partner\"),this.dnt=t.dnt||this.dataAttr(\"dnt\")||i.dnt()||\"\",this.styleAttr=[],this.targetEl=e.targetEl}function d(){var e=0,t;for(;t=c[e];e++)t.call()}function v(){return this.srcEl&&this.srcEl.id||\"twitter-widget-\"+a++}function m(e){if(!e)return;return e.lang?e.lang:m(e.parentNode)}var a=0,f,l={list:[],byId:{}},c=[],h={ar:{\"%{followers_count} followers\":\"Ø¹Ø¯Ø¯ Ø§Ù„Ù…ØªØ§Ø¨Ø¹ÙŠÙ† %{followers_count}\",\"100K+\":\"+100 Ø£Ù„Ù\",\"10k unit\":\"10 Ø¢Ù„Ø§Ù ÙˆØ­Ø¯Ø©\",Follow:\"ØªØ§Ø¨ÙØ¹\",\"Follow %{screen_name}\":\"ØªØ§Ø¨ÙØ¹ %{screen_name}\",K:\"Ø£Ù„Ù\",M:\"Ù…Ù„ÙŠÙˆÙ†\",Tweet:\"ØºØ±ÙÙ‘Ø¯\",\"Tweet %{hashtag}\":\"ØºØ±ÙÙ‘Ø¯ %{hashtag}\",\"Tweet to %{name}\":\"ØºØ±ÙÙ‘Ø¯ Ù„Ù€ %{name}\",\"Twitter Stream\":\"Ø®Ø·Ù‘ ØªÙˆÙŠØªØ± Ø§Ù„Ø²Ù…Ù†ÙŠÙ‘\"},da:{\"%{followers_count} followers\":\"%{followers_count} fÃ¸lgere\",\"10k unit\":\"10k enhed\",Follow:\"FÃ¸lg\",\"Follow %{screen_name}\":\"FÃ¸lg %{screen_name}\",\"Tweet to %{name}\":\"Tweet til %{name}\",\"Twitter Stream\":\"Twitter-strÃ¸m\"},de:{\"%{followers_count} followers\":\"%{followers_count} Follower\",\"100K+\":\"100Tsd+\",\"10k unit\":\"10tsd-Einheit\",Follow:\"Folgen\",\"Follow %{screen_name}\":\"%{screen_name} folgen\",K:\"Tsd\",Tweet:\"Twittern\",\"Tweet to %{name}\":\"Tweet an %{name}\"},es:{\"%{followers_count} followers\":\"%{followers_count} seguidores\",\"10k unit\":\"10k unidad\",Follow:\"Seguir\",\"Follow %{screen_name}\":\"Seguir a %{screen_name}\",Tweet:\"Twittear\",\"Tweet %{hashtag}\":\"Twittear %{hashtag}\",\"Tweet to %{name}\":\"Twittear a %{name}\",\"Twitter Stream\":\"CronologÃ­a de Twitter\"},fa:{\"%{followers_count} followers\":\"%{followers_count} Ø¯Ù†Ø¨Ø§Ù„â€ŒÚ©Ù†Ù†Ø¯Ù‡\",\"100K+\":\">Û±Û°Û°Ù‡Ø²Ø§Ø±\",\"10k unit\":\"Û±Û°Ù‡Ø²Ø§Ø± ÙˆØ§Ø­Ø¯\",Follow:\"Ø¯Ù†Ø¨Ø§Ù„ Ú©Ø±Ø¯Ù†\",\"Follow %{screen_name}\":\"Ø¯Ù†Ø¨Ø§Ù„ Ú©Ø±Ø¯Ù† %{screen_name}\",K:\"Ù‡Ø²Ø§Ø±\",M:\"Ù…ÛŒÙ„ÛŒÙˆÙ†\",Tweet:\"ØªÙˆÛŒÛŒØª\",\"Tweet %{hashtag}\":\"ØªÙˆÛŒÛŒØª Ú©Ø±Ø¯Ù† %{hashtag}\",\"Tweet to %{name}\":\"Ø¨Ù‡ %{name} ØªÙˆÛŒÛŒØª Ú©Ù†ÛŒØ¯\",\"Twitter Stream\":\"Ø¬Ø±ÛŒØ§Ù† ØªÙˆÛŒÛŒØªâ€ŒÙ‡Ø§\"},fi:{\"%{followers_count} followers\":\"%{followers_count} seuraajaa\",\"100K+\":\"100 000+\",\"10k unit\":\"10 000 yksikkÃ¶Ã¤\",Follow:\"Seuraa\",\"Follow %{screen_name}\":\"Seuraa kÃ¤yttÃ¤jÃ¤Ã¤ %{screen_name}\",K:\"tuhatta\",M:\"milj.\",Tweet:\"Twiittaa\",\"Tweet %{hashtag}\":\"Twiittaa %{hashtag}\",\"Tweet to %{name}\":\"Twiittaa kÃ¤yttÃ¤jÃ¤lle %{name}\",\"Twitter Stream\":\"Twitter-virta\"},fil:{\"%{followers_count} followers\":\"%{followers_count} mga tagasunod\",\"10k unit\":\"10k yunit\",Follow:\"Sundan\",\"Follow %{screen_name}\":\"Sundan si %{screen_name}\",Tweet:\"I-tweet\",\"Tweet %{hashtag}\":\"I-tweet ang %{hashtag}\",\"Tweet to %{name}\":\"Mag-Tweet kay %{name}\",\"Twitter Stream\":\"Stream ng Twitter\"},fr:{\"%{followers_count} followers\":\"%{followers_count} abonnÃ©s\",\"10k unit\":\"unitÃ© de 10k\",Follow:\"Suivre\",\"Follow %{screen_name}\":\"Suivre %{screen_name}\",Tweet:\"Tweeter\",\"Tweet %{hashtag}\":\"Tweeter %{hashtag}\",\"Tweet to %{name}\":\"Tweeter Ã  %{name}\",\"Twitter Stream\":\"Flux Twitter\"},he:{\"%{followers_count} followers\":\"%{followers_count} ×¢×•×§×‘×™×\",\"100K+\":\"×ž××•×ª ××œ×¤×™×\",\"10k unit\":\"×¢×©×¨×•×ª ××œ×¤×™×\",Follow:\"×ž×¢×§×‘\",\"Follow %{screen_name}\":\"×œ×¢×§×•×‘ ××—×¨ %{screen_name}\",K:\"××œ×£\",M:\"×ž×™×œ×™×•×Ÿ\",Tweet:\"×¦×™×•×¥\",\"Tweet %{hashtag}\":\"×¦×™×™×¦×• %{hashtag}\",\"Tweet to %{name}\":\"×¦×™×•×¥ ××œ %{name}\",\"Twitter Stream\":\"×”×ª×–×¨×™× ×©×œ ×˜×•×•×™×˜×¨\"},hi:{\"%{followers_count} followers\":\"%{followers_count} à¤«à¤¼à¥‰à¤²à¥‹à¤…à¤°à¥à¤¸\",\"100K+\":\"1 à¤²à¤¾à¤–+\",\"10k unit\":\"10 à¤¹à¤œà¤¾à¤° à¤‡à¤•à¤¾à¤ˆà¤¯à¤¾à¤‚\",Follow:\"à¤«à¤¼à¥‰à¤²à¥‹\",\"Follow %{screen_name}\":\"%{screen_name} à¤•à¥‹ à¤«à¤¼à¥‰à¤²à¥‹ à¤•à¤°à¥‡à¤‚\",K:\"à¤¹à¤œà¤¾à¤°\",M:\"à¤®à¤¿à¤²à¤¿à¤¯à¤¨\",Tweet:\"à¤Ÿà¥à¤µà¥€à¤Ÿ\",\"Tweet %{hashtag}\":\"à¤Ÿà¥à¤µà¥€à¤Ÿ %{hashtag}\",\"Tweet to %{name}\":\"%{name} à¤•à¥‹ à¤Ÿà¥à¤µà¥€à¤Ÿ à¤•à¤°à¥‡à¤‚\",\"Twitter Stream\":\"à¤Ÿà¥à¤µà¤¿à¤Ÿà¤° à¤¸à¥à¤Ÿà¥à¤°à¥€à¤®\"},hu:{\"%{followers_count} followers\":\"%{followers_count} kÃ¶vetÅ‘\",\"100K+\":\"100E+\",\"10k unit\":\"10E+\",Follow:\"KÃ¶vetÃ©s\",\"Follow %{screen_name}\":\"%{screen_name} kÃ¶vetÃ©se\",K:\"E\",\"Tweet %{hashtag}\":\"%{hashtag} tweetelÃ©se\",\"Tweet to %{name}\":\"Tweet kÃ¼ldÃ©se neki: %{name}\",\"Twitter Stream\":\"Twitter HÃ­rfolyam\"},id:{\"%{followers_count} followers\":\"%{followers_count} pengikut\",\"100K+\":\"100 ribu+\",\"10k unit\":\"10 ribu unit\",Follow:\"Ikuti\",\"Follow %{screen_name}\":\"Ikuti %{screen_name}\",K:\"&nbsp;ribu\",M:\"&nbsp;juta\",\"Tweet to %{name}\":\"Tweet ke %{name}\",\"Twitter Stream\":\"Aliran Twitter\"},it:{\"%{followers_count} followers\":\"%{followers_count} follower\",\"10k unit\":\"10k unitÃ \",Follow:\"Segui\",\"Follow %{screen_name}\":\"Segui %{screen_name}\",\"Tweet %{hashtag}\":\"Twitta %{hashtag}\",\"Tweet to %{name}\":\"Twitta a %{name}\"},ja:{\"%{followers_count} followers\":\"%{followers_count}äººã®ãƒ•ã‚©ãƒ­ãƒ¯ãƒ¼\",\"100K+\":\"100Kä»¥ä¸Š\",\"10k unit\":\"ä¸‡\",Follow:\"ãƒ•ã‚©ãƒ­ãƒ¼ã™ã‚‹\",\"Follow %{screen_name}\":\"%{screen_name}ã•ã‚“ã‚’ãƒ•ã‚©ãƒ­ãƒ¼\",Tweet:\"ãƒ„ã‚¤ãƒ¼ãƒˆ\",\"Tweet %{hashtag}\":\"%{hashtag} ã‚’ãƒ„ã‚¤ãƒ¼ãƒˆã™ã‚‹\",\"Tweet to %{name}\":\"%{name}ã•ã‚“ã¸ãƒ„ã‚¤ãƒ¼ãƒˆã™ã‚‹\",\"Twitter Stream\":\"Twitterã‚¹ãƒˆãƒªãƒ¼ãƒ \"},ko:{\"%{followers_count} followers\":\"%{followers_count}ëª…ì˜ íŒ”ë¡œì›Œ\",\"100K+\":\"100ë§Œ ì´ìƒ\",\"10k unit\":\"ë§Œ ë‹¨ìœ„\",Follow:\"íŒ”ë¡œìš°\",\"Follow %{screen_name}\":\"%{screen_name} ë‹˜ íŒ”ë¡œìš°í•˜ê¸°\",K:\"ì²œ\",M:\"ë°±ë§Œ\",Tweet:\"íŠ¸ìœ—\",\"Tweet %{hashtag}\":\"%{hashtag} ê´€ë ¨ íŠ¸ìœ—í•˜ê¸°\",\"Tweet to %{name}\":\"%{name}ë‹˜ì—ê²Œ íŠ¸ìœ—í•˜ê¸°\",\"Twitter Stream\":\"íŠ¸ìœ„í„° ìŠ¤íŠ¸ë¦¼\"},msa:{\"%{followers_count} followers\":\"%{followers_count} pengikut\",\"100K+\":\"100 ribu+\",\"10k unit\":\"10 ribu unit\",Follow:\"Ikut\",\"Follow %{screen_name}\":\"Ikut %{screen_name}\",K:\"ribu\",M:\"juta\",\"Tweet to %{name}\":\"Tweet kepada %{name}\",\"Twitter Stream\":\"Strim Twitter\"},nl:{\"%{followers_count} followers\":\"%{followers_count} volgers\",\"100K+\":\"100k+\",\"10k unit\":\"10k-eenheid\",Follow:\"Volgen\",\"Follow %{screen_name}\":\"%{screen_name} volgen\",K:\"k\",M:\" mln.\",Tweet:\"Tweeten\",\"Tweet %{hashtag}\":\"%{hashtag} tweeten\",\"Tweet to %{name}\":\"Tweeten naar %{name}\"},no:{\"%{followers_count} followers\":\"%{followers_count} fÃ¸lgere\",\"100K+\":\"100 K+\",\"10k unit\":\"10 K-enhet\",Follow:\"FÃ¸lg\",\"Follow %{screen_name}\":\"FÃ¸lg %{screen_name}\",\"Tweet to %{name}\":\"Send en tweet til %{name}\",\"Twitter Stream\":\"Twitter-strÃ¸m\"},pl:{\"%{followers_count} followers\":\"%{followers_count} obserwujÄ…cych\",\"100K+\":\"100 tys.+\",\"10k unit\":\"10 tys.\",Follow:\"Obserwuj\",\"Follow %{screen_name}\":\"Obserwuj %{screen_name}\",K:\"tys.\",M:\"mln\",Tweet:\"Tweetnij\",\"Tweet %{hashtag}\":\"Tweetnij %{hashtag}\",\"Tweet to %{name}\":\"Tweetnij do %{name}\",\"Twitter Stream\":\"StrumieÅ„ Twittera\"},pt:{\"%{followers_count} followers\":\"%{followers_count} seguidores\",\"100K+\":\"+100 mil\",\"10k unit\":\"10 mil unidades\",Follow:\"Seguir\",\"Follow %{screen_name}\":\"Seguir %{screen_name}\",K:\"Mil\",Tweet:\"Tweetar\",\"Tweet %{hashtag}\":\"Tweetar %{hashtag}\",\"Tweet to %{name}\":\"Tweetar para %{name}\",\"Twitter Stream\":\"TransmissÃµes do Twitter\"},ru:{\"%{followers_count} followers\":\"Ð§Ð¸Ñ‚Ð°Ñ‚ÐµÐ»Ð¸: %{followers_count} \",\"100K+\":\"100 Ñ‚Ñ‹Ñ.+\",\"10k unit\":\"Ð±Ð»Ð¾Ðº 10k\",Follow:\"Ð§Ð¸Ñ‚Ð°Ñ‚ÑŒ\",\"Follow %{screen_name}\":\"Ð§Ð¸Ñ‚Ð°Ñ‚ÑŒ %{screen_name}\",K:\"Ñ‚Ñ‹Ñ.\",M:\"Ð¼Ð»Ð½.\",Tweet:\"Ð¢Ð²Ð¸Ñ‚Ð½ÑƒÑ‚ÑŒ\",\"Tweet %{hashtag}\":\"Ð¢Ð²Ð¸Ñ‚Ð½ÑƒÑ‚ÑŒ %{hashtag}\",\"Tweet to %{name}\":\"Ð¢Ð²Ð¸Ñ‚Ð½ÑƒÑ‚ÑŒ %{name}\",\"Twitter Stream\":\"ÐŸÐ¾Ñ‚Ð¾Ðº Ð² Ð¢Ð²Ð¸Ñ‚Ñ‚ÐµÑ€Ðµ\"},sv:{\"%{followers_count} followers\":\"%{followers_count} fÃ¶ljare\",\"10k unit\":\"10k\",Follow:\"FÃ¶lj\",\"Follow %{screen_name}\":\"FÃ¶lj %{screen_name}\",Tweet:\"Tweeta\",\"Tweet %{hashtag}\":\"Tweeta %{hashtag}\",\"Tweet to %{name}\":\"Tweeta till %{name}\",\"Twitter Stream\":\"TwitterflÃ¶de\"},th:{\"%{followers_count} followers\":\"%{followers_count} à¸œà¸¹à¹‰à¸•à¸´à¸”à¸•à¸²à¸¡\",\"100K+\":\"100à¸žà¸±à¸™+\",\"10k unit\":\"à¸«à¸™à¹ˆà¸§à¸¢ 10à¸žà¸±à¸™\",Follow:\"à¸•à¸´à¸”à¸•à¸²à¸¡\",\"Follow %{screen_name}\":\"à¸•à¸´à¸”à¸•à¸²à¸¡ %{screen_name}\",K:\"à¸žà¸±à¸™\",M:\"à¸¥à¹‰à¸²à¸™\",Tweet:\"à¸—à¸§à¸µà¸•\",\"Tweet %{hashtag}\":\"à¸—à¸§à¸µà¸• %{hashtag}\",\"Tweet to %{name}\":\"à¸—à¸§à¸µà¸•à¸–à¸¶à¸‡ %{name}\",\"Twitter Stream\":\"à¸—à¸§à¸´à¸•à¹€à¸•à¸­à¸£à¹Œà¸ªà¸•à¸£à¸µà¸¡\"},tr:{\"%{followers_count} followers\":\"%{followers_count} takipÃ§i\",\"100K+\":\"+100 bin\",\"10k unit\":\"10 bin birim\",Follow:\"Takip et\",\"Follow %{screen_name}\":\"Takip et: %{screen_name}\",K:\"bin\",M:\"milyon\",Tweet:\"Tweetle\",\"Tweet %{hashtag}\":\"Tweetle: %{hashtag}\",\"Tweet to %{name}\":\"Tweetle: %{name}\",\"Twitter Stream\":\"Twitter AkÄ±ÅŸÄ±\"},ur:{\"%{followers_count} followers\":\"%{followers_count} ÙØ§Ù„ÙˆØ±Ø²\",\"100K+\":\"Ø§ÛŒÚ© Ù„Ø§Ú©Ú¾ Ø³Û’ Ø²ÛŒØ§Ø¯Û\",\"10k unit\":\"Ø¯Ø³ ÛØ²Ø§Ø± ÛŒÙˆÙ†Ù¹\",Follow:\"ÙØ§Ù„Ùˆ Ú©Ø±ÛŒÚº\",\"Follow %{screen_name}\":\"%{screen_name} Ú©Ùˆ ÙØ§Ù„Ùˆ Ú©Ø±ÛŒÚº\",K:\"ÛØ²Ø§Ø±\",M:\"Ù…Ù„ÛŒÙ†\",Tweet:\"Ù¹ÙˆÛŒÙ¹ Ú©Ø±ÛŒÚº\",\"Tweet %{hashtag}\":\"%{hashtag} Ù¹ÙˆÛŒÙ¹ Ú©Ø±ÛŒÚº\",\"Tweet to %{name}\":\"%{name} Ú©Ùˆ Ù¹ÙˆÛŒÙ¹ Ú©Ø±ÛŒÚº\",\"Twitter Stream\":\"Ù¹ÙˆØ¦Ù¹Ø± Ø³Ù¹Ø±ÛŒÙ…\"},\"zh-cn\":{\"%{followers_count} followers\":\"%{followers_count} å…³æ³¨è€…\",\"100K+\":\"10ä¸‡+\",\"10k unit\":\"1ä¸‡å•å…ƒ\",Follow:\"å…³æ³¨\",\"Follow %{screen_name}\":\"å…³æ³¨ %{screen_name}\",K:\"åƒ\",M:\"ç™¾ä¸‡\",Tweet:\"å‘æŽ¨\",\"Tweet %{hashtag}\":\"ä»¥ %{hashtag} å‘æŽ¨\",\"Tweet to %{name}\":\"å‘æŽ¨ç»™ %{name}\",\"Twitter Stream\":\"Twitter ä¿¡æ¯æµ\"},\"zh-tw\":{\"%{followers_count} followers\":\"%{followers_count} ä½è·Ÿéš¨è€…\",\"100K+\":\"è¶…éŽåè¬\",\"10k unit\":\"1è¬ å–®ä½\",Follow:\"è·Ÿéš¨\",\"Follow %{screen_name}\":\"è·Ÿéš¨ %{screen_name}\",K:\"åƒ\",M:\"ç™¾è¬\",Tweet:\"æŽ¨æ–‡\",\"Tweet %{hashtag}\":\"æŽ¨æ–‡%{hashtag}\",\"Tweet to %{name}\":\"æŽ¨æ–‡çµ¦%{name}\",\"Twitter Stream\":\"Twitter è³‡è¨Šæµ\"}};t.aug(p.prototype,{setLanguage:function(e){var t;e||(e=this.params().lang||this.dataAttr(\"lang\")||m(this.srcEl)),e=e&&e.toLowerCase();if(!e)return this.lang=\"en\";if(h[e])return this.lang=e;t=e.replace(/[\\-_].*/,\"\");if(h[t])return this.lang=t;this.lang=\"en\"},_:function(e,t){var n=this.lang;t=t||{};if(!n||!h.hasOwnProperty(n))n=this.lang=\"en\";return e=h[n]&&h[n][e]||e,this.ringo(e,t,/%\\{([\\w_]+)\\}/g)},ringo:function(e,t,n){return n=n||/\\{\\{([\\w_]+)\\}\\}/g,e.replace(n,function(e,n){return t[n]!==undefined?t[n]:e})},add:function(e){l.list.push(this),l.byId[this.id]=e},create:function(e,t,n){return n[\"data-twttr-rendered\"]=!0,o({url:e,css:t,className:this.classAttr.join(\" \"),id:this.id,attributes:n,replace:this.srcEl,insertTarget:this.targetEl})},params:function(){var e,t;return this.srcOb?t=this.srcOb:(e=this.srcEl&&this.srcEl.href&&this.srcEl.href.split(\"?\")[1],t=e?s.decode(e):{}),this.params=function(){return t},t},dataAttr:function(e){return this.srcEl&&this.srcEl.getAttribute(\"data-\"+e)},attr:function(e){return this.srcEl&&this.srcEl.getAttribute(e)},styles:{base:[[\"font\",\"normal normal normal 11px/18px 'Helvetica Neue', Arial, sans-serif\"],[\"margin\",\"0\"],[\"padding\",\"0\"],[\"whiteSpace\",\"nowrap\"]],button:[[\"fontWeight\",\"bold\"],[\"textShadow\",\"0 1px 0 rgba(255,255,255,.5)\"]],large:[[\"fontSize\",\"13px\"],[\"lineHeight\",\"26px\"]],vbubble:[[\"fontSize\",\"16px\"]]},width:function(){throw new Error(name+\" not implemented\")},height:function(){return this.size==\"m\"?20:28},minWidth:function(){},maxWidth:function(){},minHeight:function(){},maxHeight:function(){},dimensions:function(){function e(e){switch(typeof e){case\"string\":return e;case\"undefined\":return;default:return e+\"px\"}}var t,n={width:this.width(),height:this.height()};this.minWidth()&&(n[\"min-width\"]=this.minWidth()),this.maxWidth()&&(n[\"max-width\"]=this.maxWidth()),this.minHeight()&&(n[\"min-height\"]=this.minHeight()),this.maxHeight()&&(n[\"max-height\"]=this.maxHeight());for(t in n)n[t]=e(n[t]);return n},generateId:v}),p.afterLoad=function(e){c.push(e)},p.init=function(e){f=e},p.find=function(e){return e&&l.byId[e]?l.byId[e].element:null},p.embed=function(e){var t=f.widgets,n,i,s=0,o,a,c,h,p;u.isArray(e)||(e=[e||document]);for(;i=e[s];s++)for(a in t)if(t.hasOwnProperty(a)){a.match(/\\./)?(c=a.split(\".\"),n=r.all(c[1],i,c[0])):n=i.getElementsByTagName(a);for(h=0;p=n[h];h++){if(p.getAttribute(\"data-twttr-rendered\"))continue;p.setAttribute(\"data-twttr-rendered\",\"true\"),o=new t[a](p),l.list.push(o),l.byId[o.id]=o,o.render(f)}}d()},e(p)})});\nprovide(\"tfw/widget/intent\",function(e){using(\"tfw/widget/base\",\"util/util\",\"util/querystring\",\"util/uri\",function(t,n,r,i){function h(e){var t=Math.round(l/2-u/2),n=0;f>a&&(n=Math.round(f/2-a/2)),window.open(e,undefined,[o,\"width=\"+u,\"height=\"+a,\"left=\"+t,\"top=\"+n].join(\",\"))}function p(e,t){using(\"tfw/hub/client\",function(n){n.openIntent(e,t)})}function d(e){var t=\"original_referer=\"+location.href;return[e,t].join(e.indexOf(\"?\")==-1?\"?\":\"&\")}function v(e){var t,r,i,o;e=e||window.event,t=e.target||e.srcElement;if(e.altKey||e.metaKey||e.shiftKey)return;while(t){if(~n.indexOf([\"A\",\"AREA\"],t.nodeName))break;t=t.parentNode}t&&t.href&&(r=t.href.match(s),r&&(o=d(t.href),o=o.replace(/^http[:]/,\"https:\"),o=o.replace(/^\\/\\//,\"https://\"),m(o,t),e.returnValue=!1,e.preventDefault&&e.preventDefault()))}function m(e,t){if(twttr.events.hub&&t){var n=new g(c.generateId(),t);c.add(n),p(e,t),twttr.events.trigger(\"click\",{target:t,region:\"intent\",type:\"click\",data:{}})}else h(e)}function g(e,t){this.id=e,this.element=this.srcEl=t}function y(e){this.srcEl=[],this.element=e}var s=/twitter\\.com(\\:\\d{2,4})?\\/intent\\/(\\w+)/,o=\"scrollbars=yes,resizable=yes,toolbar=no,location=yes\",u=550,a=520,f=screen.height,l=screen.width,c;y.prototype=new t,n.aug(y.prototype,{render:function(e){c=this,window.__twitterIntentHandler||(document.addEventListener?document.addEventListener(\"click\",v,!1):document.attachEvent&&document.attachEvent(\"onclick\",v),window.__twitterIntentHandler=!0)}}),y.open=m,e(y)})});\nprovide(\"dom/classname\",function(e){function t(e,t){e.classList?e.classList.add(t):s(t).test(e.className)||(e.className+=\" \"+t)}function n(e,t){e.classList?e.classList.remove(t):e.className=e.className.replace(s(t),\" \")}function r(e,r,o){e.classList&&i(e,r)?(n(e,r),t(e,o)):e.className=e.className.replace(s(r),o)}function i(e,t){return e.classList?e.classList.contains(t):s(t).test(e.className)}function s(e){return new RegExp(\"\\\\b\"+e+\"\\\\b\",\"g\")}e({add:t,remove:n,replace:r,present:i})});\nprovide(\"util/throttle\",function(e){function t(e,t,n){function o(){var n=+(new Date);window.clearTimeout(s);if(n-i>t){i=n,e.call(r);return}s=window.setTimeout(o,t)}var r=n||this,i=0,s;return o}e(t)});\nprovide(\"util/insert\",function(e){e(function(e,t){if(t){if(!t.parentNode)return t;t.parentNode.replaceChild(e,t),delete t}else document.body.insertBefore(e,document.body.firstChild);return e})});\nprovide(\"util/css\",function(e){using(\"util/util\",function(t){e({sanitize:function(e,n,r){var i=/^[\\w ,%\\/\"'\\-_#]+$/,s=e&&t.map(e.split(\";\"),function(e){return t.map(e.split(\":\").slice(0,2),function(e){return t.trim(e)})}),o=0,u,a=[],f=r?\"!important\":\"\";n=n||/^(font|text\\-|letter\\-|color|line\\-)[\\w\\-]*$/;for(;s&&(u=s[o]);o++)u[0].match(n)&&u[1].match(i)&&a.push(u.join(\":\")+f);return a.join(\";\")}})})});\nprovide(\"tfw/util/params\",function(e){using(\"util/querystring\",\"util/twitter\",function(t,n){e(function(e,r){return function(i){var s,o=\"data-tw-params\",u,a=i.innerHTML;if(!i)return;if(!n.isTwitterURL(i.href))return;if(i.getAttribute(o))return;i.setAttribute(o,!0);if(typeof r==\"function\"){s=r.call(this,i);for(u in s)s.hasOwnProperty(u)&&(e[u]=s[u])}i.href=t.url(i.href,e),i.innerHTML=a}})})});\nprovide(\"$xd/json2.js\", function(exports) {window.JSON||(window.JSON={}),function(){function f(e){return e<10?\"0\"+e:e}function quote(e){return escapable.lastIndex=0,escapable.test(e)?'\"'+e.replace(escapable,function(e){var t=meta[e];return typeof t==\"string\"?t:\"\\\\u\"+(\"0000\"+e.charCodeAt(0).toString(16)).slice(-4)})+'\"':'\"'+e+'\"'}function str(e,t){var n,r,i,s,o=gap,u,a=t[e];a&&typeof a==\"object\"&&typeof a.toJSON==\"function\"&&(a=a.toJSON(e)),typeof rep==\"function\"&&(a=rep.call(t,e,a));switch(typeof a){case\"string\":return quote(a);case\"number\":return isFinite(a)?String(a):\"null\";case\"boolean\":case\"null\":return String(a);case\"object\":if(!a)return\"null\";gap+=indent,u=[];if(Object.prototype.toString.apply(a)===\"[object Array]\"){s=a.length;for(n=0;n<s;n+=1)u[n]=str(n,a)||\"null\";return i=u.length===0?\"[]\":gap?\"[\\n\"+gap+u.join(\",\\n\"+gap)+\"\\n\"+o+\"]\":\"[\"+u.join(\",\")+\"]\",gap=o,i}if(rep&&typeof rep==\"object\"){s=rep.length;for(n=0;n<s;n+=1)r=rep[n],typeof r==\"string\"&&(i=str(r,a),i&&u.push(quote(r)+(gap?\": \":\":\")+i))}else for(r in a)Object.hasOwnProperty.call(a,r)&&(i=str(r,a),i&&u.push(quote(r)+(gap?\": \":\":\")+i));return i=u.length===0?\"{}\":gap?\"{\\n\"+gap+u.join(\",\\n\"+gap)+\"\\n\"+o+\"}\":\"{\"+u.join(\",\")+\"}\",gap=o,i}}typeof Date.prototype.toJSON!=\"function\"&&(Date.prototype.toJSON=function(e){return isFinite(this.valueOf())?this.getUTCFullYear()+\"-\"+f(this.getUTCMonth()+1)+\"-\"+f(this.getUTCDate())+\"T\"+f(this.getUTCHours())+\":\"+f(this.getUTCMinutes())+\":\"+f(this.getUTCSeconds())+\"Z\":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(e){return this.valueOf()});var cx=/[\\u0000\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,escapable=/[\\\\\\\"\\x00-\\x1f\\x7f-\\x9f\\u00ad\\u0600-\\u0604\\u070f\\u17b4\\u17b5\\u200c-\\u200f\\u2028-\\u202f\\u2060-\\u206f\\ufeff\\ufff0-\\uffff]/g,gap,indent,meta={\"\\b\":\"\\\\b\",\"\t\":\"\\\\t\",\"\\n\":\"\\\\n\",\"\\f\":\"\\\\f\",\"\\r\":\"\\\\r\",'\"':'\\\\\"',\"\\\\\":\"\\\\\\\\\"},rep;typeof JSON.stringify!=\"function\"&&(JSON.stringify=function(e,t,n){var r;gap=\"\",indent=\"\";if(typeof n==\"number\")for(r=0;r<n;r+=1)indent+=\" \";else typeof n==\"string\"&&(indent=n);rep=t;if(!t||typeof t==\"function\"||typeof t==\"object\"&&typeof t.length==\"number\")return str(\"\",{\"\":e});throw new Error(\"JSON.stringify\")}),typeof JSON.parse!=\"function\"&&(JSON.parse=function(text,reviver){function walk(e,t){var n,r,i=e[t];if(i&&typeof i==\"object\")for(n in i)Object.hasOwnProperty.call(i,n)&&(r=walk(i,n),r!==undefined?i[n]=r:delete i[n]);return reviver.call(e,t,i)}var j;cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(e){return\"\\\\u\"+(\"0000\"+e.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\\],:{}\\s]*$/.test(text.replace(/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,\"@\").replace(/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,\"]\").replace(/(?:^|:|,)(?:\\s*\\[)+/g,\"\")))return j=eval(\"(\"+text+\")\"),typeof reviver==\"function\"?walk({\"\":j},\"\"):j;throw new SyntaxError(\"JSON.parse\")})}();exports();loadrunner.Script.loaded.push(\"$xd/json2.js\")});\nprovide(\"util/params\",function(e){using(\"util/querystring\",function(t){var n=function(e){var n=e.search.substr(1);return t.decode(n)},r=function(e){var n=e.href,r=n.indexOf(\"#\"),i=r<0?\"\":n.substring(r+1);return t.decode(i)},i=function(e){var t={},i=n(e),s=r(e);for(var o in i)i.hasOwnProperty(o)&&(t[o]=i[o]);for(var o in s)s.hasOwnProperty(o)&&(t[o]=s[o]);return t};e({combined:i,fromQuery:n,fromFragment:r})})});\nprovide(\"tfw/util/env\",function(e){using(\"util/params\",function(t){function r(){var e=36e5,r=t.combined(document.location)._;return n!==undefined?n:(n=!1,r&&/^\\d+$/.test(r)&&(n=+(new Date)-parseInt(r)<e),n)}var n;e({isDynamicWidget:r})})});\nprovide(\"util/decider\",function(e){function n(e){var n=t[e]||!1;if(!n)return!1;if(n===!0||n===100)return!0;var r=Math.random()*100,i=n>=r;return t[e]=i,i}var t={force_new_cookie:100,rufous_pixel:100,decider_fixture:12.34};e({isAvailable:n})});\nprovide(\"dom/cookie\",function(e){using(\"util/util\",function(t){e(function(e,n,r){var i=t.aug({},r);if(arguments.length>1&&String(n)!==\"[object Object]\"){if(n===null||n===undefined)i.expires=-1;if(typeof i.expires==\"number\"){var s=i.expires,o=new Date((new Date).getTime()+s*60*1e3);i.expires=o}return n=String(n),document.cookie=[encodeURIComponent(e),\"=\",i.raw?n:encodeURIComponent(n),i.expires?\"; expires=\"+i.expires.toUTCString():\"\",i.path?\"; path=\"+i.path:\"\",i.domain?\"; domain=\"+i.domain:\"\",i.secure?\"; secure\":\"\"].join(\"\")}i=n||{};var u,a=i.raw?function(e){return e}:decodeURIComponent;return(u=(new RegExp(\"(?:^|; )\"+encodeURIComponent(e)+\"=([^;]*)\")).exec(document.cookie))?a(u[1]):null})})});\nprovide(\"util/donottrack\",function(e){using(\"dom/cookie\",function(t){e(function(e){var n=/\\.(gov|mil)(:\\d+)?$/i,r=/https?:\\/\\/([^\\/]+).*/i;return e=e||document.referrer,e=r.test(e)&&r.exec(e)[1],t(\"dnt\")?!0:n.test(document.location.host)?!0:e&&n.test(e)?!0:document.navigator?document.navigator[\"doNotTrack\"]==1:navigator?navigator[\"doNotTrack\"]==1||navigator[\"msDoNotTrack\"]==1:!1})})});\nprovide(\"tfw/util/guest_cookie\",function(e){using(\"dom/cookie\",\"util/donottrack\",\"util/decider\",function(t,n,r){function s(){var e=t(i)||!1;if(!e)return;e.match(/^v3\\:/)||o()}function o(){t(i)&&t(i,null,{domain:\".twitter.com\",path:\"/\"})}function u(){n()&&o()}var i=\"pid\";e({set:u,destroy:o,forceNewCookie:s,guest_id_cookie:i})})});\nprovide(\"dom/sandbox\",function(e){using(\"util/domready\",\"util/env\",function(t,n){function i(e,t){var n,r,i;if(e.name){try{i=document.createElement('<iframe name=\"'+e.name+'\"></iframe>')}catch(s){i=document.createElement(\"iframe\"),i.name=e.name}delete e.name}else i=document.createElement(\"iframe\");e.id&&(i.id=e.id,delete e.id);for(n in e)e.hasOwnProperty(n)&&i.setAttribute(n,e[n]);i.allowtransparency=\"true\",i.scrolling=\"no\",i.setAttribute(\"frameBorder\",0),i.setAttribute(\"allowTransparency\",!0);for(r in t||{})t.hasOwnProperty(r)&&(i.style[r]=t[r]);return i}function s(e,t,n,r){var s;this.attrs=t||{},this.styles=n||{},this.appender=r,this.onReady=e,this.sandbox={},s=i(this.attrs,this.styles),s.onreadystatechange=s.onload=this.getCallback(this.onLoad),this.sandbox.frame=s,r?r(s):document.body.appendChild(s)}function o(e,n,r,i){t(function(){new s(e,n,r,i)})}var r=0;window.twttr=window.twttr||{},window.twttr.sandbox||(window.twttr.sandbox={}),s.prototype.getCallback=function(e){var t=this,n=!1;return function(){n||(n=!0,e.call(t))}},s.prototype.registerCallback=function(e){var t=\"cb\"+r++;return window.twttr.sandbox[t]=e,t},s.prototype.onLoad=function(){try{this.sandbox.frame.contentWindow.document}catch(e){this.setDocDomain();return}this.sandbox.win=this.sandbox.frame.contentWindow,this.sandbox.doc=this.sandbox.frame.contentWindow.document,this.writeStandardsDoc(),this.sandbox.body=this.sandbox.frame.contentWindow.document.body,this.onReady(this.sandbox)},s.prototype.setDocDomain=function(){var e,t=this.registerCallback(this.getCallback(this.onLoad));e=[\"javascript:\",'document.write(\"\");',\"try { window.parent.document; }\",\"catch (e) {\",'document.domain=\"'+document.domain+'\";',\"}\",'window.parent.twttr.sandbox[\"'+t+'\"]();'].join(\"\"),this.sandbox.frame.parentNode.removeChild(this.sandbox.frame),this.sandbox.frame=null,this.sandbox.frame=i(this.attrs,this.styles),this.sandbox.frame.src=e,this.appender?this.appender(this.sandbox.frame):document.body.appendChild(this.sandbox.frame)},s.prototype.writeStandardsDoc=function(){if(!n.anyIE()||n.cspEnabled())return;var e=[\"<!DOCTYPE html>\",\"<html>\",\"<head>\",\"<scr\",\"ipt>\",\"try { window.parent.document; }\",'catch (e) {document.domain=\"'+document.domain+'\";}',\"</scr\",\"ipt>\",\"</head>\",\"<body></body>\",\"</html>\"].join(\"\");this.sandbox.doc.write(e),this.sandbox.doc.close()},e(o)})});\nprovide(\"tfw/util/tracking\",function(e){using(\"dom/cookie\",\"dom/delegate\",\"dom/sandbox\",\"util/donottrack\",\"tfw/util/guest_cookie\",\"tfw/util/env\",\"util/util\",\"$xd/json2.js\",function(t,n,r,i,s,o,u){function E(){y=document.getElementById(\"rufous-sandbox\");if(y){g=y.contentWindow.document,m=g.body;return}r(function(e){y=e.frame,g=e.doc,m=e.doc.body,h=_(),p=D();while(d[0])C.apply(this,d.shift());v&&k()},{id:\"rufous-sandbox\"},{display:\"none\"})}function S(e,t,n,r){var i=!u.isObject(e),s=t?!u.isObject(t):!1,o,a;if(i||s)return;if(/Firefox/.test(navigator.userAgent))return;o=A(e),a=O(t,!!n,!!r),N(o,a,!0)}function x(e,n,r,a){var l=f[n],c,h,p=s.guest_id_cookie;if(!l)return;e=e||{},a=!!a,r=!!r,h=e.original_redirect_referrer||document.referrer,a=a||i(h),c=u.aug({},e),r||(T(c,\"referrer\",h),T(c,\"widget\",+o.isDynamicWidget()),T(c,\"hask\",+!!t(\"k\")),T(c,\"li\",+!!t(\"twid\")),T(c,p,t(p)||\"\")),a&&(T(c,\"dnt\",1),H(c)),P(l+\"?\"+M(c))}function T(e,t,n){var r=a+t;if(!e)return;return e[r]=n,e}function N(e,t,n){var r,i,s,o,a=b+\"?\";if(!u.isObject(e)||!u.isObject(t))return;s=u.aug({},t,{event_namespace:e}),n?(a+=M({l:B(s)}),P(a)):(r=h.firstChild,r.value=+r.value||+s.dnt,o=B(s),i=g.createElement(\"input\"),i.type=\"hidden\",i.name=\"l\",i.value=o,h.appendChild(i))}function C(e,t,n,r){var i=!u.isObject(e),s=t?!u.isObject(t):!1,o,a;if(i||s)return;if(!m||!h){d.push([e,t,n,r]);return}o=A(e),a=O(t,!!n,!!r),N(o,a)}function k(){var e;if(!h){v=!0;return}if(h.children.length<=1)return;m.appendChild(h),m.appendChild(p),e=L(h,p),n.on(p,\"load\",function(){window.setTimeout(e,0)}),h.submit(),h=_(),p=D()}function L(e,t){return function(){var n=e.parentNode;if(!n)return;n.removeChild(e),n.removeChild(t)}}function A(e){return u.aug({client:\"tfw\"},e||{})}function O(e,t,n){var r={_category_:\"tfw_client_event\"},s,o;return t=!!t,n=!!n,s=u.aug(r,e||{}),o=s.widget_origin||document.referrer,s.format_version=1,s.dnt=n=n||i(o),s.triggered_on=s.triggered_on||+(new Date),t||(s.widget_origin=o),n&&H(s),s}function M(e){var t=[],n,r,i;for(n in e)e.hasOwnProperty(n)&&(r=encodeURIComponent(n),i=encodeURIComponent(e[n]),i=i.replace(/'/g,\"%27\"),t.push(r+\"=\"+i));return t.join(\"&\")}function _(){var e=g.createElement(\"form\"),t=g.createElement(\"input\"),n=g.createElement(\"input\");return c++,e.action=b,e.method=\"POST\",e.target=\"rufous-frame-\"+c,e.id=\"rufous-form-\"+c,t.type=\"hidden\",t.name=\"dnt\",t.value=0,n.type=\"hidden\",n.name=\"tfw_redirect\",n.value=w,e.appendChild(t),e.appendChild(n),e}function D(){var e,t=\"rufous-frame-\"+c;try{e=g.createElement(\"<iframe name=\"+t+\">\")}catch(n){e=g.createElement(\"iframe\"),e.name=t}return e.id=t,e.style.display=\"none\",e.width=0,e.height=0,e.border=0,e}function P(e){var t=document.createElement(\"img\");t.src=e,t.alt=\"\",t.style.position=\"absolute\",t.style.height=\"1px\",t.style.width=\"1px\",t.style.top=\"-9999px\",t.style.left=\"-9999px\",document.body.appendChild(t)}function H(e){var t;for(t in e)~u.indexOf(l,t)&&delete e[t]}function B(e){var t=Array.prototype.toJSON,n;return delete Array.prototype.toJSON,n=JSON.stringify(e),t&&(Array.prototype.toJSON=t),n}var a=\"twttr_\",f={tweetbutton:\"//p.twitter.com/t.gif\",followbutton:\"//p.twitter.com/f.gif\",tweetembed:\"//p.twitter.com/e.gif\"},l=[\"hask\",\"li\",\"logged_in\",\"pid\",\"user_id\",s.guest_id_cookie,a+\"hask\",a+\"li\",a+s.guest_id_cookie],c=0,h,p,d=[],v,m,g,y,b=\"https://twitter.com/i/jot\",w=\"https://platform.twitter.com/jot.html\";s.forceNewCookie(),e({enqueue:C,flush:k,initPostLogging:E,addPixel:S,addLegacyPixel:x,addVar:T})})});\nprovide(\"tfw/util/data\",function(e){using(\"util/logger\",\"util/util\",\"util/querystring\",function(t,n,r){function c(e,t){return e=={}.toString.call(t).match(/\\s([a-zA-Z]+)/)[1].toLowerCase()}function h(e){return function(n){n.error?e.error&&e.error(n):n.headers&&n.headers.status!=200?(e.error&&e.error(n),t.warn(n.headers.message)):e.success&&e.success(n),e.complete&&e.complete(n),p(e)}}function p(e){var t=e.script;t&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),e.script=undefined,t=undefined),e.callbackName&&twttr.tfw.callbacks[e.callbackName]&&delete twttr.tfw.callbacks[e.callbackName]}function d(e){var t={};return e.success&&c(\"function\",e.success)&&(t.success=e.success),e.error&&c(\"function\",e.error)&&(t.error=e.error),e.complete&&c(\"function\",e.complete)&&(t.complete=e.complete),t}function v(e,t,n){var r=e.length,i={},s=0;return function(o){var u,a=[],f=[],l=[],c,h;u=n(o),i[u]=o;if(++s===r){for(c=0;c<r;c++)h=i[e[c]],a.push(h),h.error?l.push(h):f.push(h);t.error&&l.length>0&&t.error(l),t.success&&f.length>0&&t.success(f),t.complete&&t.complete(a)}}}window.twttr=window.twttr||{},twttr.tfw=twttr.tfw||{},twttr.tfw.callbacks=twttr.tfw.callbacks||{};var i=\"twttr.tfw.callbacks\",s=twttr.tfw.callbacks,o=\"cb\",u=0,a=!1,f={},l={userLookup:\"//api.twitter.com/1/users/lookup.json\",userShow:\"//cdn.api.twitter.com/1/users/show.json\",status:\"//cdn.api.twitter.com/1/statuses/show.json\",tweets:\"//syndication.twitter.com/tweets.json\",count:\"//cdn.api.twitter.com/1/urls/count.json\",friendship:\"//cdn.api.twitter.com/1/friendships/exists.json\",timeline:\"//cdn.syndication.twimg.com/widgets/timelines/\",timelinePoll:\"//syndication.twimg.com/widgets/timelines/paged/\",timelinePreview:\"//syndication.twimg.com/widgets/timelines/preview/\"};twttr.widgets&&twttr.widgets.endpoints&&n.aug(l,twttr.widgets.endpoints),f.jsonp=function(e,t,n){var f=n||o+u,l=i+\".\"+f,c=document.createElement(\"script\"),p={callback:l,suppress_response_codes:!0};s[f]=h(t);if(a||!/^https?\\:$/.test(window.location.protocol))e=e.replace(/^\\/\\//,\"https://\");c.src=r.url(e,p),c.async=\"async\",document.body.appendChild(c),t.script=c,t.callbackName=f,n||u++},f.config=function(e){if(e.forceSSL===!0||e.forceSSL===!1)a=e.forceSSL},f.user=function(){var e,t={},n,i,s;arguments.length===1?(e=arguments[0].screenName,t=d(arguments[0])):(e=arguments[0],t.success=arguments[1]),n=c(\"array\",e)?l.userLookup:l.userShow,e=c(\"array\",e)?e.join(\",\"):e,i={screen_name:e},s=r.url(n,i),this.jsonp(s,t)},f.userById=function(e){var t,n={},i,s,o;arguments.length===1?(t=e.ids,n=d(e)):(t=e,n.success=arguments[1]),i=c(\"array\",t)?l.userLookup:l.userShow,t=c(\"array\",t)?t.join(\",\"):t,s={user_id:t},o=r.url(i,s),this.jsonp(o,n)},f.status=function(){var e,t={},n,i,s,o;arguments.length===1?(e=arguments[0].id,t=d(arguments[0])):(e=arguments[0],t.success=arguments[1]);if(!c(\"array\",e))n={id:e,include_entities:!0},i=r.url(l.status,n),this.jsonp(i,t);else{s=v(e,t,function(e){return e.error?e.request.split(\"id=\")[1].split(\"&\")[0]:e.id_str});for(o=0;o<e.length;o++)n={id:e[o],include_entities:!0},i=r.url(l.status,n),this.jsonp(i,{success:s,error:s})}},f.tweets=function(e){var t=arguments[0],n=d(t),i={ids:e.ids.join(\",\"),lang:e.lang},s=r.url(l.tweets,i);this.jsonp(s,n)},f.count=function(){var e=\"\",t,n,i={};arguments.length===1?(e=arguments[0].url,i=d(arguments[0])):arguments.length===2&&(e=arguments[0],i.success=arguments[1]),n={url:e},t=r.url(l.count,n),this.jsonp(t,i)},f.friendshipExists=function(e){var t=d(e),n={screen_name_a:e.screenNameA,screen_name_b:e.screenNameB},i=r.url(l.friendship,n);this.jsonp(i,t)},f.timeline=function(e){var t=arguments[0],i=d(t),s,o=9e5,u=Math.floor(+(new Date)/o),a={lang:e.lang,t:u,domain:window.location.host,dnt:e.dnt,override_type:e.overrideType,override_id:e.overrideId,override_name:e.overrideName,override_owner_id:e.overrideOwnerId,override_owner_name:e.overrideOwnerName,with_replies:e.withReplies};n.compact(a),s=r.url(l.timeline+e.id,a),this.jsonp(s,i,\"tl_\"+e.id+\"_\"+e.instanceId)},f.timelinePoll=function(e){var t=arguments[0],i=d(t),s={lang:e.lang,since_id:e.sinceId,max_id:e.maxId,domain:window.location.host,dnt:e.dnt,override_type:e.overrideType,override_id:e.overrideId,override_name:e.overrideName,override_owner_id:e.overrideOwnerId,override_owner_name:e.overrideOwnerName,with_replies:e.withReplies},o;n.compact(s),o=r.url(l.timelinePoll+e.id,s),this.jsonp(o,i,\"tlPoll_\"+e.id+\"_\"+e.instanceId+\"_\"+(e.sinceId||e.maxId))},f.timelinePreview=function(e){var t=arguments[0],n=d(t),i=e.params,s=r.url(l.timelinePreview,i);this.jsonp(s,n)},e(f)})});\nprovide(\"anim/transition\",function(e){function t(e,t){var n;return t=t||window,n=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.msRequestAnimationFrame||t.oRequestAnimationFrame||function(n){t.setTimeout(function(){e(+(new Date))},1e3/60)},n(e)}function n(e,t){return Math.sin(Math.PI/2*t)*e}function r(e,n,r,i,s){function a(){var u=+(new Date),f=u-o,l=Math.min(f/r,1),c=i?i(n,l):n*l;e(c);if(l==1)return;t(a,s)}var o=+(new Date),u;t(a)}e({animate:r,requestAnimationFrame:t,easeOut:n})});\nprovide(\"util/datetime\",function(e){using(\"util/util\",function(t){function h(e){return e<10?\"0\"+e:e}function p(e){function i(e,n){return t&&t[e]&&(e=t[e]),e.replace(/%\\{([\\w_]+)\\}/g,function(e,t){return n[t]!==undefined?n[t]:e})}var t=e&&e.phrases,n=e&&e.months||s,r=e&&e.formats||o;this.timeAgo=function(e){var t=p.parseDate(e),s=+(new Date),o=s-t,h;return t?isNaN(o)||o<u*2?i(\"now\"):o<a?(h=Math.floor(o/u),i(r.abbr,{number:h,symbol:i(c,{abbr:i(\"s\"),expanded:h>1?i(\"seconds\"):i(\"second\")})})):o<f?(h=Math.floor(o/a),i(r.abbr,{number:h,symbol:i(c,{abbr:i(\"m\"),expanded:h>1?i(\"minutes\"):i(\"minute\")})})):o<l?(h=Math.floor(o/f),i(r.abbr,{number:h,symbol:i(c,{abbr:i(\"h\"),expanded:h>1?i(\"hours\"):i(\"hour\")})})):o<l*365?i(r.shortdate,{day:t.getDate(),month:i(n[t.getMonth()])}):i(r.longdate,{day:t.getDate(),month:i(n[t.getMonth()]),year:t.getFullYear().toString().slice(2)}):\"\"},this.localTimeStamp=function(e){var t=p.parseDate(e),s=t&&t.getHours();return t?i(r.full,{day:t.getDate(),month:i(n[t.getMonth()]),year:t.getFullYear(),hours24:h(s),hours12:s<13?s?s:\"12\":s-12,minutes:h(t.getMinutes()),seconds:h(t.getSeconds()),amPm:s<12?i(\"AM\"):i(\"PM\")}):\"\"}}var n=/(\\d{4})-?(\\d{2})-?(\\d{2})T(\\d{2}):?(\\d{2}):?(\\d{2})(Z|[\\+\\-]\\d{2}:?\\d{2})/,r=/[a-z]{3,4} ([a-z]{3}) (\\d{1,2}) (\\d{1,2}):(\\d{2}):(\\d{2}) ([\\+\\-]\\d{2}:?\\d{2}) (\\d{4})/i,i=/^\\d+$/,s=[\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"],o={abbr:\"%{number}%{symbol}\",shortdate:\"%{day} %{month}\",longdate:\"%{day} %{month} %{year}\",full:\"%{hours12}:%{minutes} %{amPm} - %{day} %{month} %{year}\"},u=1e3,a=u*60,f=a*60,l=f*24,c='<abbr title=\"%{expanded}\">%{abbr}</abbr>';p.parseDate=function(e){var o=e||\"\",u=o.toString(),a,f;return a=function(){var e;if(i.test(u))return parseInt(u,10);if(e=u.match(r))return Date.UTC(e[7],t.indexOf(s,e[1]),e[2],e[3],e[4],e[5]);if(e=u.match(n))return Date.UTC(e[1],e[2]-1,e[3],e[4],e[5],e[6])}(),a?(f=new Date(a),!isNaN(f.getTime())&&f):!1},e(p)})});\nprovide(\"tfw/util/assets\",function(e){using(\"util/env\",function(t){function r(e,r){var i=n[e],s;return t.retina()?s=\"2x\":t.ie6()||t.ie7()?s=\"gif\":s=\"default\",r&&(s+=\".rtl\"),i[s]}var n={\"embed/timeline.css\":{\"default\":\"embed/timeline.4c7bdf7c22f411f2ff2324c8d6b08523.default.css\",\"2x\":\"embed/timeline.4c7bdf7c22f411f2ff2324c8d6b08523.2x.css\",gif:\"embed/timeline.4c7bdf7c22f411f2ff2324c8d6b08523.gif.css\",\"default.rtl\":\"embed/timeline.4c7bdf7c22f411f2ff2324c8d6b08523.default.rtl.css\",\"2x.rtl\":\"embed/timeline.4c7bdf7c22f411f2ff2324c8d6b08523.2x.rtl.css\",\"gif.rtl\":\"embed/timeline.4c7bdf7c22f411f2ff2324c8d6b08523.gif.rtl.css\"}};e(r)})});\nprovide(\"tfw/widget/syndicatedbase\",function(e){using(\"tfw/widget/base\",\"tfw/widget/intent\",\"tfw/util/assets\",\"tfw/util/globals\",\"dom/classname\",\"dom/delegate\",\"dom/sandbox\",\"util/env\",\"util/twitter\",\"util/util\",function(t,n,r,i,s,o,u,a,f,l){function y(){v=E.VALID_COLOR.test(i.val(\"widgets:link-color\"))&&RegExp.$1,g=E.VALID_COLOR.test(i.val(\"widgets:border-color\"))&&RegExp.$1,m=i.val(\"widgets:theme\")}function b(e,t,n){var r;n=n||document;if(n.getElementById(e))return;r=n.createElement(\"link\"),r.id=e,r.rel=\"stylesheet\",r.type=\"text/css\",r.href=twttr.widgets.config.assetUrl()+\"/\"+t,n.getElementsByTagName(\"head\")[0].appendChild(r)}function w(e){b(\"twitter-widget-css\",r(\"embed/timeline.css\"),e)}function E(e){if(!e)return;var n,r,i=this;this.sandboxReadyCallbacks=[],t.apply(this,[e]),n=this.params(),this.targetEl=this.srcEl&&this.srcEl.parentNode||n.targetEl||document.body,this.containerWidth=this.targetEl&&this.targetEl.offsetWidth,r=n.width||this.attr(\"width\")||this.containerWidth||this.dimensions.DEFAULT_WIDTH,this.height=E.VALID_UNIT.test(n.height||this.attr(\"height\"))&&RegExp.$1,this.width=Math.max(this.dimensions.MIN_WIDTH,Math.min(E.VALID_UNIT.test(r)?RegExp.$1:this.dimensions.DEFAULT_WIDTH,this.dimensions.DEFAULT_WIDTH)),this.narrow=n.narrow||this.width<=this.dimensions.NARROW_WIDTH,this.narrow&&this.classAttr.push(\"var-narrow\"),E.VALID_COLOR.test(n.linkColor||this.dataAttr(\"link-color\"))?this.linkColor=RegExp.$1:this.linkColor=v,E.VALID_COLOR.test(n.borderColor||this.dataAttr(\"border-color\"))?this.borderColor=RegExp.$1:this.borderColor=g,this.theme=n.theme||this.attr(\"data-theme\")||m,this.theme=/(dark|light)/.test(this.theme)?this.theme:\"\",this.classAttr.push(a.touch()?\"is-touch\":\"not-touch\"),u(function(e){i.sandboxReady=!0,i.setupSandbox.call(i,e)},{\"class\":this.renderedClassNames,id:this.id},{width:\"1px\",height:\"1px\",border:\"none\",position:\"absolute\"},function(e){i.srcEl?i.targetEl.insertBefore(e,i.srcEl):i.targetEl.appendChild(e)})}var c=[\".customisable\",\".customisable:link\",\".customisable:visited\",\".customisable:hover\",\".customisable:focus\",\".customisable:active\",\".customisable-highlight:hover\",\".customisable-highlight:focus\",\"a:hover .customisable-highlight\",\"a:focus .customisable-highlight\"],h=[\"a:hover .ic-mask\",\"a:focus .ic-mask\"],p=[\".customisable-border\"],d=[\".timeline-header h1.summary\",\".timeline-header h1.summary a:link\",\".timeline-header h1.summary a:visited\"],v,m,g;E.prototype=new t,l.aug(E.prototype,{setupSandbox:function(e){var t=e.doc,n=t.createElement(\"base\"),r=t.createElement(\"style\"),i=t.getElementsByTagName(\"head\")[0],s=\"body{display:none}\",o=this,u;this.sandbox=e,e.frame.title=this.a11yTitle,w(e.doc),n.target=\"_blank\",i.appendChild(n),a.cspEnabled()||(r.type=\"text/css\",r.styleSheet?r.styleSheet.cssText=s:r.appendChild(t.createTextNode(s)),i.appendChild(r)),this.handleResize&&window.addEventListener?window.addEventListener(\"resize\",function(){o.handleResize()},!0):document.body.attachEvent(\"onresize\",function(){o.handleResize()}),e.win.onresize=function(){o.handleResize&&o.handleResize()},this.frameIsReady=!0;for(;u=this.sandboxReadyCallbacks.shift();)u.fn.apply(u.context,u.args)},callsWhenSandboxReady:function(e){var t=this;return function(){var n=[],r=arguments.length,i=0;for(;i<r;i++)n.push(arguments[i]);t.callIfSandboxReady(e,t,n)}},callIfSandboxReady:function(e,t,n){n=n||[],t.frameIsReady?e.apply(t,[!1].concat(n)):t.sandboxReadyCallbacks.push({fn:e,context:t,args:[!0].concat(n)})},contentWidth:function(){var e=this.dimensions,t=this.chromeless&&this.narrow?e.NARROW_MEDIA_PADDING_CL:this.chromeless?e.WIDE_MEDIA_PADDING_CL:this.narrow?e.NARROW_MEDIA_PADDING:e.WIDE_MEDIA_PADDING;return this.width-t},addSiteStyles:function(){var e=this,t=this.sandbox.doc,n=this.id+\"-styles\",r,i=function(t){return(e.theme==\"dark\"?\".thm-dark \":\"\")+t},s=[];if(a.cspEnabled())return;if(t.getElementById(n))return;this.headingStyle&&s.push(l.map(d,i).join(\",\")+\"{\"+this.headingStyle+\"}\"),this.linkColor&&(s.push(l.map(c,i).join(\",\")+\"{color:\"+this.linkColor+\"}\"),s.push(l.map(h,i).join(\",\")+\"{background-color:\"+this.linkColor+\"}\")),this.borderColor&&s.push(l.map(p,i).concat(this.theme==\"dark\"?[\".thm-dark.customisable-border\"]:[]).join(\",\")+\"{border-color:\"+this.borderColor+\"}\");if(!s.length)return;r=t.createElement(\"style\"),r.id=n,r.type=\"text/css\",r.styleSheet?r.styleSheet.cssText=s.join(\"\"):r.appendChild(t.createTextNode(s.join(\"\"))),t.getElementsByTagName(\"head\")[0].appendChild(r)},bindIntentHandlers:function(){var e=this,t=this.element;o.delegate(t,\"click\",\".profile\",function(t){var r;e.addUrlParams(this),r=f.intentForProfileURL(this.href);if(t.altKey||t.metaKey||t.shiftKey)return;r&&(n.open(r,e.sandbox.frame),o.preventDefault(t))}),o.delegate(t,\"click\",\".web-intent\",function(t){e.addUrlParams(this);if(t.altKey||t.metaKey||t.shiftKey)return;n.open(this.href,e.sandbox.frame),o.preventDefault(t)})}}),E.VALID_UNIT=/^([0-9]+)( ?px)?$/,E.VALID_COLOR=/^(#(?:[0-9a-f]{3}|[0-9a-f]{6}))$/i,E.retinize=function(e){if(!a.retina())return;var t=e.getElementsByTagName(\"IMG\"),n,r,i=0,s=t.length;for(;i<s;i++)n=t[i],r=n.getAttribute(\"data-src-2x\"),r&&(n.src=r)},E.scaleDimensions=function(e,t,n,r){return t>e&&t>r?(e*=r/t,t=r):e>n&&(t*=n/e,e=n,t>r&&(e*=r/t,t=r)),{width:Math.ceil(e),height:Math.ceil(t)}},E.constrainMedia=function(e,t){var n=e.getElementsByTagName(\"IMG\"),r=e.getElementsByTagName(\"IFRAME\"),i,s,o,u=0,a=0,f;for(;i=[n,r][a];a++)if(i.length)for(f=0;s=i[f];f++)o=E.scaleDimensions(s.getAttribute(\"width\")||s.width,s.getAttribute(\"height\")||s.height,t,375),o.width>0&&(s.width=o.width),o.height>0&&(s.height=o.height),u=o.height>u?o.height:u;return u},y(),e(E)})});\nprovide(\"tfw/widget/timeline\",function(e){using(\"tfw/widget/syndicatedbase\",\"util/datetime\",\"anim/transition\",\"tfw/util/article\",\"tfw/util/data\",\"tfw/util/tracking\",\"tfw/util/params\",\"util/css\",\"util/env\",\"util/iframe\",\"util/insert\",\"util/throttle\",\"util/twitter\",\"util/querystring\",\"util/typevalidator\",\"util/util\",\"dom/delegate\",\"dom/classname\",\"dom/get\",function(t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b){function I(e){if(!e)return;var n,r,i,s,o,u,f;this.a11yTitle=this._(\"Twitter Timeline Widget\"),t.apply(this,[e]),n=this.params(),r=(n.chrome||this.dataAttr(\"chrome\")||\"\").split(\" \"),this.preview=n.previewParams,this.widgetId=n.widgetId||this.dataAttr(\"widget-id\"),this.instanceId=++F,(s=n.screenName||this.dataAttr(\"screen-name\"))||(o=n.userId||this.dataAttr(\"user-id\"))?this.override={overrideType:\"user\",overrideId:o,overrideName:s,withReplies:v.asBoolean(n.showReplies||this.dataAttr(\"show-replies\"))?\"true\":\"false\"}:(s=n.favoritesScreenName||this.dataAttr(\"favorites-screen-name\"))||(o=n.favoritesUserId||this.dataAttr(\"favorites-user-id\"))?this.override={overrideType:\"favorites\",overrideId:o,overrideName:s}:((s=n.listOwnerScreenName||this.dataAttr(\"list-owner-screen-name\"))||(o=n.listOwnerId||this.dataAttr(\"list-owner-id\")))&&((u=n.listId||this.dataAttr(\"list-id\"))||(f=n.listSlug||this.dataAttr(\"list-slug\")))?this.override={overrideType:\"list\",overrideOwnerId:o,overrideOwnerName:s,overrideId:u,overrideName:f}:this.override={},this.tweetLimit=v.asInt(n.tweetLimit||this.dataAttr(\"tweet-limit\")),this.staticTimeline=this.tweetLimit>0,r.length&&(i=~m.indexOf(r,\"none\"),this.chromeless=i||~m.indexOf(r,\"transparent\"),this.headerless=i||~m.indexOf(r,\"noheader\"),this.footerless=i||~m.indexOf(r,\"nofooter\"),this.borderless=i||~m.indexOf(r,\"noborders\"),this.noscrollbar=~m.indexOf(r,\"noscrollbar\")),this.headingStyle=a.sanitize(n.headingStyle||this.dataAttr(\"heading-style\"),undefined,!0),this.classAttr.push(\"twitter-timeline-rendered\"),this.ariaPolite=n.ariaPolite||this.dataAttr(\"aria-polite\")}function q(e,n){var r=e.ownerDocument,i=b.one(O,e,\"DIV\"),s=i&&i.children[0],o=s&&s.getAttribute(\"data-expanded-media\"),u,a=0,f=b.one(M,e,\"A\"),l=f&&f.getElementsByTagName(\"B\")[0],c=l&&(l.innerText||l.textContent),h;if(!l)return;l.innerHTML=f.getAttribute(\"data-toggled-text\"),f.setAttribute(\"data-toggled-text\",c);if(y.present(e,A)){y.remove(e,A);if(!i)return;i.style.cssText=\"\",s.innerHTML=\"\";return}o&&(u=r.createElement(\"DIV\"),u.innerHTML=o,t.retinize(u),a=t.constrainMedia(u,n),s.appendChild(u)),i&&(h=Math.max(s.offsetHeight,a),i.style.cssText=\"height:\"+h+\"px\"),y.add(e,A)}var w=\"1.0\",E={CLIENT_SIDE_USER:0,CLIENT_SIDE_APP:2},S=\"timeline\",x=\"new-tweets-bar\",T=\"timeline-header\",N=\"timeline-footer\",C=\"stream\",k=\"h-feed\",L=\"tweet\",A=\"expanded\",O=\"detail-expander\",M=\"expand\",_=\"permalink\",D=\"twitter-follow-button\",P=\"no-more-pane\",H=\"pending-scroll-in\",B=\"pending-new-tweet\",j=\"show-new-tweet\",F=0;I.prototype=new t,m.aug(I.prototype,{renderedClassNames:\"twitter-timeline twitter-timeline-rendered\",dimensions:{DEFAULT_HEIGHT:\"600\",DEFAULT_WIDTH:\"520\",NARROW_WIDTH:\"320\",MIN_WIDTH:\"180\",MIN_HEIGHT:\"200\",WIDE_MEDIA_PADDING:81,NARROW_MEDIA_PADDING:16,WIDE_MEDIA_PADDING_CL:60,NARROW_MEDIA_PADDING_CL:12},create:function(e){var n=this.sandbox.doc.createElement(\"div\"),r,s=this,u,a,f,l=[],c,h;n.innerHTML=e.body,r=n.children[0]||!1;if(!r)return;this.reconfigure(e.config),this.discardStaticOverflow(r),this.augmentWidgets(r),t.retinize(r),t.constrainMedia(r,this.contentWidth()),this.searchQuery=r.getAttribute(\"data-search-query\"),this.profileId=r.getAttribute(\"data-profile-id\"),c=this.getTweetDetails(n);for(h in c)c.hasOwnProperty(h)&&l.push(h);return o.enqueue({page:\"timeline\",component:\"timeline\",element:\"initial\",action:l.length?\"results\":\"no_results\"},{widget_id:this.widgetId,widget_origin:i.url(),item_ids:l,item_details:c,client_version:w,message:this.partner,query:this.searchQuery,profile_id:this.profileId},!0,this.dnt),o.flush(),this.ariaPolite==\"assertive\"&&(a=b.one(x,r,\"DIV\"),a.setAttribute(\"aria-polite\",\"assertive\")),r.id=this.id,r.className+=\" \"+this.classAttr.join(\" \"),r.lang=this.lang,twttr.widgets.load(r),f=function(){s.sandbox.body.appendChild(r),s.staticTimeline?s.sandbox.win.setTimeout(function(){s.sandbox.frame.height=s.height=r.offsetHeight},500):s.sandbox.win.setTimeout(function(){var e=b.one(T,r,\"DIV\"),t=b.one(N,r,\"DIV\"),n=b.one(C,r,\"DIV\");t?u=e.offsetHeight+t.offsetHeight:u=e.offsetHeight,n.style.cssText=\"height:\"+(s.height-u-2)+\"px\",s.noscrollbar&&s.hideStreamScrollBar()},500),s.sandbox.frame.style.cssText=\"\",s.sandbox.frame.width=s.width,s.sandbox.frame.height=s.height,s.sandbox.frame.style.border=\"none\",s.sandbox.frame.style.maxWidth=\"100%\",s.sandbox.frame.style.minWidth=s.dimensions.MIN_WIDTH+\"px\"},this.callsWhenSandboxReady(f)(),this.srcEl&&this.srcEl.parentNode&&this.srcEl.parentNode.removeChild(this.srcEl),r},render:function(e,t){function u(){r.success=function(e){n.element=n.create(e),n.readTranslations(),n.bindInteractions(),t&&t(n.sandbox.frame);return},r.error=function(e){e&&e.headers&&t&&t(e.headers.status)},r.params=n.preview,s.timelinePreview(r);return}function a(){o.initPostLogging(),s.timeline(m.aug({id:n.widgetId,instanceId:n.instanceId,dnt:n.dnt,lang:n.lang,success:function(e){n.element=n.create(e),n.readTranslations(),n.bindInteractions(),e.headers.xPolling&&/\\d/.test(e.headers.xPolling)&&(n.pollInterval=e.headers.xPolling*1e3),n.updateTimeStamps(),n.staticTimeline||n.schedulePolling(),t&&t(n.sandbox.frame);return},error:function(e){e&&e.headers&&t&&t(e.headers.status)}},n.override))}var n=this,r={},i;if(!this.preview&&!this.widgetId){t&&t(400);return}i=this.preview?u:a,this.sandboxReady?i():window.setTimeout(i,0)},reconfigure:function(e){this.lang=e.lang,this.theme||(this.theme=e.theme),this.theme==\"dark\"&&this.classAttr.push(\"thm-dark\"),this.chromeless&&this.classAttr.push(\"var-chromeless\"),this.borderless&&this.classAttr.push(\"var-borderless\"),this.headerless&&this.classAttr.push(\"var-headerless\"),this.footerless&&this.classAttr.push(\"var-footerless\"),this.staticTimeline&&this.classAttr.push(\"var-static\"),!this.linkColor&&e.linkColor&&t.VALID_COLOR.test(e.linkColor)&&(this.linkColor=RegExp.$1),this.addSiteStyles(),!this.height&&t.VALID_UNIT.test(e.height)&&(this.height=RegExp.$1),this.height=Math.max(this.dimensions.MIN_HEIGHT,this.height?this.height:this.dimensions.DEFAULT_HEIGHT),this.preview&&this.classAttr.push(\"var-preview\"),this.narrow=this.width<=this.dimensions.NARROW_WIDTH,this.narrow&&this.classAttr.push(\"var-narrow\")},getTweetDetails:function(e){var t=b.one(k,e),n,r={},i,s,o,u,a={TWEET:0,RETWEET:10},f=0;n=t&&t.children||[];for(;i=n[f];f++)s=b.one(_,i,\"A\"),o=i.getAttribute(\"data-rendered-tweet-id\")||p.status(s.href),u=i.getAttribute(\"data-tweet-id\"),o===u?r[o]={item_type:a.TWEET}:r[o]={item_type:a.RETWEET,target_type:a.TWEET,target_id:u};return r},bindInteractions:function(){var e=this,t=this.element,n=!0;this.bindIntentHandlers(),g.delegate(t,\"click\",\".load-tweets\",function(t){n&&(n=!1,e.forceLoad(),g.stop(t))}),g.delegate(t,\"click\",\".display-sensitive-image\",function(n){e.showNSFW(b.ancestor(\".\"+L,this,t)),g.stop(n)}),g.delegate(t,\"mouseover\",\".\"+S,function(){e.mouseOver=!0}),g.delegate(t,\"mouseout\",\".\"+S,function(){e.mouseOver=!1}),g.delegate(t,\"mouseover\",\".\"+x,function(){e.mouseOverNotifier=!0}),g.delegate(t,\"mouseout\",\".\"+x,function(){e.mouseOverNotifier=!1,window.setTimeout(function(){e.hideNewTweetNotifier()},3e3)});if(this.staticTimeline)return;g.delegate(t,\"click\",\".\"+M,function(n){if(n.altKey||n.metaKey||n.shiftKey)return;q(b.ancestor(\".\"+L,this,t),e.contentWidth()),g.stop(n)}),g.delegate(t,\"click\",\"A\",function(e){g.stopPropagation(e)}),g.delegate(t,\"click\",\".with-expansion\",function(t){q(this,e.contentWidth()),g.stop(t)}),g.delegate(t,\"click\",\".load-more\",function(){e.loadMore()}),g.delegate(t,\"click\",\".\"+x,function(){e.scrollToTop(),e.hideNewTweetNotifier(!0)})},scrollToTop:function(){var e=b.one(C,this.element,\"DIV\");e.scrollTop=0,e.focus()},update:function(){var e=this,t=b.one(L,this.element,\"LI\"),n=t&&t.getAttribute(\"data-tweet-id\");this.updateTimeStamps(),this.requestTweets(n,!0,function(t){t.childNodes.length>0&&e.insertNewTweets(t)})},loadMore:function(){var e=this,t=b.all(L,this.element,\"LI\").pop(),n=t&&t.getAttribute(\"data-tweet-id\");this.requestTweets(n,!1,function(t){var r=b.one(P,e.element,\"P\"),i=t.childNodes[0];r.style.cssText=\"\",i&&i.getAttribute(\"data-tweet-id\")==n&&t.removeChild(i);if(t.childNodes.length>0){e.appendTweets(t);return}y.add(e.element,\"no-more\"),r.focus()})},forceLoad:function(){var e=this,t=!!b.all(k,this.element,\"OL\").length;this.requestTweets(1,!0,function(n){n.childNodes.length&&(e[t?\"insertNewTweets\":\"appendTweets\"](n),y.add(e.element,\"has-tweets\"))})},schedulePolling:function(e){var t=this;if(this.pollInterval===null)return;e=twttr.widgets.poll||e||this.pollInterval||1e4,e>-1&&window.setTimeout(function(){this.isUpdating||t.update(),t.schedulePolling()},e)},requestTweets:function(e,n,r){var u=this,a={id:this.widgetId,instanceId:this.instanceId,screenName:this.widgetScreenName,userId:this.widgetUserId,withReplies:this.widgetShowReplies,dnt:this.dnt,lang:this.lang};a[n?\"sinceId\":\"maxId\"]=e,a.complete=function(){this.isUpdating=!1},a.error=function(e){if(e&&e.headers){if(e.headers.status==\"404\"){u.pollInterval=null;return}if(e.headers.status==\"503\"){u.pollInterval*=1.5;return}}},a.success=function(e){var s=u.sandbox.doc.createDocumentFragment(),a=u.sandbox.doc.createElement(\"div\"),f=[],l,c;e&&e.headers&&e.headers.xPolling&&/\\d+/.test(e.headers.xPolling)&&(u.pollInterval=e.headers.xPolling*1e3);if(e&&e.body!==undefined){a.innerHTML=e.body;if(a.children[0]&&a.children[0].tagName!=\"LI\")return;l=u.getTweetDetails(a);for(c in l)l.hasOwnProperty(c)&&f.push(c);f.length&&(o.enqueue({page:\"timeline\",component:\"timeline\",element:n?\"newer\":\"older\",action:\"results\"},{widget_id:u.widgetId,widget_origin:i.url(),item_ids:f,item_details:l,client_version:w,message:u.partner,query:u.searchQuery,profile_id:u.profileId,event_initiator:n?E.CLIENT_SIDE_APP:E.CLIENT_SIDE_USER},!0,u.dnt),o.flush()),t.retinize(a),t.constrainMedia(a,u.contentWidth());while(a.children[0])s.appendChild(a.children[0]);r(s)}},s.timelinePoll(m.aug(a,this.override))},insertNewTweets:function(e){var t=this,n=b.one(C,this.element,\"DIV\"),i=b.one(k,n,\"OL\"),s=i.offsetHeight,o;this.updateTimeStamps(),i.insertBefore(e,i.firstChild),o=i.offsetHeight-s;if(n.scrollTop>40||this.mouseIsOver()){n.scrollTop=n.scrollTop+o,this.showNewTweetNotifier();return}y.remove(this.element,H),i.style.cssText=\"margin-top: -\"+o+\"px\",window.setTimeout(function(){n.scrollTop=0,y.add(t.element,H),f.cssTransitions()?i.style.cssText=\"\":r.animate(function(e){e<o?i.style.cssText=\"margin-top: -\"+(o-e)+\"px\":i.style.cssText=\"\"},o,500,r.easeOut)},500),this.gcTweets(50)},appendTweets:function(e){var t=b.one(C,this.element,\"DIV\"),n=b.one(k,t,\"OL\");this.updateTimeStamps(),n.appendChild(e)},gcTweets:function(e){var t=b.one(k,this.element,\"OL\"),n=t.children.length,r;e=e||50;for(;n>e&&(r=t.children[n-1]);n--)t.removeChild(r)},showNewTweetNotifier:function(){var e=this,t=b.one(x,this.element,\"DIV\"),n=t.children[0];t.style.cssText=\"\",y.add(this.element,B),t.removeChild(n),t.appendChild(n),y.replace(this.element,B,j),this.newNoticeDisplayTime=+(new Date),window.setTimeout(function(){e.hideNewTweetNotifier()},5e3)},hideNewTweetNotifier:function(e){var t=this;if(!e&&this.mouseOverNotifier)return;y.replace(this.element,j,B),window.setTimeout(function(){y.remove(t.element,B)},500)},augmentWidgets:function(e){var t=b.all(D,e,\"A\"),n=0,r;for(;r=t[n];n++)r.setAttribute(\"data-related\",this.related),r.setAttribute(\"data-partner\",this.partner),r.setAttribute(\"data-dnt\",this.dnt),r.setAttribute(\"data-search-query\",this.searchQuery),r.setAttribute(\"data-profile-id\",this.profileId),this.width<250&&r.setAttribute(\"data-show-screen-name\",\"false\")},discardStaticOverflow:function(e){var t=b.one(k,e,\"OL\"),n;if(this.staticTimeline){this.height=0;while(n=t.children[this.tweetLimit])t.removeChild(n)}},hideStreamScrollBar:function(){var e=b.one(C,this.element,\"DIV\"),t=b.one(k,this.element,\"OL\"),n;e.style.width=\"\",n=this.element.offsetWidth-t.offsetWidth,n>0&&(e.style.width=this.element.offsetWidth+n+\"px\")},readTranslations:function(){var e=this.element,t=\"data-dt-\";this.datetime=new n(m.compact({phrases:{now:e.getAttribute(t+\"now\"),s:e.getAttribute(t+\"s\"),m:e.getAttribute(t+\"m\"),h:e.getAttribute(t+\"h\"),second:e.getAttribute(t+\"second\"),seconds:e.getAttribute(t+\"seconds\"),minute:e.getAttribute(t+\"minute\"),minutes:e.getAttribute(t+\"minutes\"),hour:e.getAttribute(t+\"hour\"),hours:e.getAttribute(t+\"hours\")},months:e.getAttribute(t+\"months\").split(\"|\"),formats:{abbr:e.getAttribute(t+\"abbr\"),shortdate:e.getAttribute(t+\"short\"),longdate:e.getAttribute(t+\"long\")}}))},updateTimeStamps:function(){var e=b.all(_,this.element,\"A\"),t,n,r=0,i,s;for(;t=e[r];r++){i=t.getAttribute(\"data-datetime\"),s=i&&this.datetime.timeAgo(i,this.i18n),n=t.getElementsByTagName(\"TIME\")[0];if(!s)continue;if(n&&n.innerHTML){n.innerHTML=s;continue}t.innerHTML=s}},mouseIsOver:function(){return this.mouseOver},addUrlParams:function(e){var t=this,n={tw_w:this.widgetId,related:this.related,partner:this.partner,query:this.searchQuery,profile_id:this.profileId,original_referer:i.url(),tw_p:\"embeddedtimeline\"};return this.addUrlParams=u(n,function(e){var n=b.ancestor(\".\"+L,e,t.element);return n&&{tw_i:n.getAttribute(\"data-tweet-id\")}}),this.addUrlParams(e)},showNSFW:function(e){var n=b.one(\"nsfw\",e,\"DIV\"),r,i,s=0,o,u,a,l;if(!n)return;i=t.scaleDimensions(n.getAttribute(\"data-width\"),n.getAttribute(\"data-height\"),this.contentWidth(),n.getAttribute(\"data-height\")),r=!!(u=n.getAttribute(\"data-player\")),r?a=this.sandbox.doc.createElement(\"iframe\"):(a=this.sandbox.doc.createElement(\"img\"),u=n.getAttribute(f.retina()?\"data-image-2x\":\"data-image\"),a.alt=n.getAttribute(\"data-alt\"),l=this.sandbox.doc.createElement(\"a\"),l.href=n.getAttribute(\"data-href\"),l.appendChild(a)),a.title=n.getAttribute(\"data-title\"),a.src=u,a.width=i.width,a.height=i.height,o=b.ancestor(\".\"+O,n,e),s=i.height-n.offsetHeight,n.parentNode.replaceChild(r?a:l,n),o.style.cssText=\"height:\"+(o.offsetHeight+s)+\"px\"},handleResize:function(){this.handleResize=h(function(){var e=Math.min(this.dimensions.DEFAULT_WIDTH,Math.max(this.dimensions.MIN_WIDTH,this.sandbox.frame.offsetWidth));if(!this.element)return;e<this.dimensions.NARROW_WIDTH?(this.narrow=!0,y.add(this.element,\"var-narrow\")):(this.narrow=!1,y.remove(this.element,\"var-narrow\")),this.noscrollbar&&this.hideStreamScrollBar()},50,this),this.handleResize()}}),e(I)})});\nprovide(\"tfw/widget/embed\",function(e){using(\"tfw/widget/base\",\"tfw/widget/syndicatedbase\",\"util/datetime\",\"tfw/util/params\",\"dom/classname\",\"dom/get\",\"util/env\",\"util/util\",\"util/throttle\",\"util/twitter\",\"tfw/util/article\",\"tfw/util/data\",\"tfw/util/tracking\",function(t,n,r,i,s,o,u,a,f,l,c,h,p){function g(e,t,n){var r=o.one(\"subject\",e,\"BLOCKQUOTE\"),i=o.one(\"reply\",e,\"BLOCKQUOTE\"),s=r&&r.getAttribute(\"data-tweet-id\"),u=i&&i.getAttribute(\"data-tweet-id\"),a={},f={};if(!s)return;a[s]={item_type:0},p.enqueue({page:\"tweet\",section:\"subject\",component:\"tweet\",action:\"results\"},{client_version:d,widget_origin:c.url(),widget_frame:c.frameUrl(),message:t,item_ids:[s],item_details:a},!0,n);if(!u)return;f[u]={item_type:0},p.enqueue({page:\"tweet\",section:\"conversation\",component:\"tweet\",action:\"results\"},{client_version:d,widget_origin:c.url(),widget_frame:c.frameUrl(),message:t,item_ids:[u],item_details:f,associations:{4:{association_id:s,association_type:4}}},!0,n)}function y(e,t,n){var r={};if(!e)return;r[e]={item_type:0},p.enqueue({page:\"tweet\",section:\"subject\",component:\"rawembedcode\",action:\"no_results\"},{client_version:d,widget_origin:c.url(),widget_frame:c.frameUrl(),message:t,item_ids:[e],item_details:r},!0,n)}function b(e,t,n,r,i){m[e]=m[e]||[],m[e].push({s:n,f:r,r:i,lang:t})}function w(e){if(!e)return;var t,r,i;this.a11yTitle=this._(\"Embedded Tweet\"),n.apply(this,[e]),t=this.params(),r=this.srcEl&&this.srcEl.getElementsByTagName(\"A\"),i=r&&r[r.length-1],this.hideThread=(t.conversation||this.dataAttr(\"conversation\"))==\"none\"||~a.indexOf(this.classAttr,\"tw-hide-thread\"),this.hideCard=(t.cards||this.dataAttr(\"cards\"))==\"hidden\"||~a.indexOf(this.classAttr,\"tw-hide-media\");if((t.align||this.attr(\"align\"))==\"left\"||~a.indexOf(this.classAttr,\"tw-align-left\"))this.align=\"left\";else if((t.align||this.attr(\"align\"))==\"right\"||~a.indexOf(this.classAttr,\"tw-align-right\"))this.align=\"right\";else if((t.align||this.attr(\"align\"))==\"center\"||~a.indexOf(this.classAttr,\"tw-align-center\"))this.align=\"center\",this.containerWidth>this.dimensions.MIN_WIDTH*(1/.7)&&this.width>this.containerWidth*.7&&(this.width=this.containerWidth*.7);this.narrow=t.narrow||this.width<=this.dimensions.NARROW_WIDTH,this.narrow&&this.classAttr.push(\"var-narrow\"),this.tweetId=t.tweetId||i&&l.status(i.href)}var d=\"2.0\",v=\"tweetembed\",m={};w.prototype=new n,a.aug(w.prototype,{renderedClassNames:\"twitter-tweet twitter-tweet-rendered\",dimensions:{DEFAULT_HEIGHT:\"0\",DEFAULT_WIDTH:\"500\",NARROW_WIDTH:\"350\",MIN_WIDTH:\"220\",MIN_HEIGHT:\"0\",WIDE_MEDIA_PADDING:32,NARROW_MEDIA_PADDING:32},create:function(e){var t=this.sandbox.doc.createElement(\"div\"),r,i=this.sandbox.frame,s=i.style;t.innerHTML=e,r=t.children[0]||!1;if(!r)return;return this.theme==\"dark\"&&this.classAttr.push(\"thm-dark\"),this.linkColor&&this.addSiteStyles(),this.augmentWidgets(r),n.retinize(r),n.constrainMedia(r,this.contentWidth()),r.id=this.id,r.className+=\" \"+this.classAttr.join(\" \"),r.lang=this.lang,twttr.widgets.load(r),this.sandbox.body.appendChild(r),s.cssText=\"\",i.width=this.width,i.height=0,s.display=\"block\",s.border=\"none\",s.maxWidth=\"99%\",s.minWidth=this.dimensions.MIN_WIDTH+\"px\",s.padding=\"0\",g(r,this.partner,this.dnt),r},render:function(e,t){var n=this,r=\"\",i=this.tweetId,s,o,u;if(!i)return;this.hideCard&&(r+=\"c\"),this.hideThread&&(r+=\"t\"),r&&(i+=\"-\"+r),u=this.callsWhenSandboxReady(function(e){function r(){var e=n.sandbox.frame,t=e.style;n.srcEl&&n.srcEl.parentNode&&n.srcEl.parentNode.removeChild(n.srcEl),t.borderRadius=\"5px\",t.margin=\"10px 0\",t.border=\"#ddd 1px solid\",t.borderTopColor=\"#eee\",t.borderBottomColor=\"#bbb\",t.boxShadow=\"0 1px 3px rgba(0,0,0,0.15)\",n.align==\"center\"?(t.margin=\"7px auto\",t.float=\"none\"):n.align&&(n.width==n.dimensions.DEFAULT_WIDTH&&(e.width=n.dimensions.NARROW_WIDTH),t.float=n.align),n.handleResize()}var t;if((!window.getComputedStyle||n.sandbox.win.getComputedStyle(n.sandbox.body,null).display!==\"none\")&&n.element.offsetHeight)return r();t=window.setInterval(function(){(!window.getComputedStyle||n.sandbox.win.getComputedStyle(n.sandbox.body,null).display!==\"none\")&&n.element.offsetHeight&&(window.clearInterval(t),r())},100)}),s=this.callsWhenSandboxReady(function(e,r){n.element=n.create(r),n.readTimestampTranslations(),n.updateTimeStamps(),n.bindIntentHandlers(),t&&t(n.sandbox.frame)}),o=this.callsWhenSandboxReady(function(e){y(n.tweetId,n.partner,n.dnt)}),b(i,this.lang,s,o,u)},augmentWidgets:function(e){var t=o.all(\"twitter-follow-button\",e,\"A\"),n,r=0;for(;n=t[r];r++)n.setAttribute(\"data-related\",this.related),n.setAttribute(\"data-partner\",this.partner),n.setAttribute(\"data-dnt\",this.dnt),n.setAttribute(\"data-show-screen-name\",\"false\")},addUrlParams:function(e){var t=this,n={related:this.related,partner:this.partner,original_referer:c.url(),tw_p:v};return this.addUrlParams=i(n,function(e){var n=o.ancestor(\".tweet\",e,t.element);return{tw_i:n.getAttribute(\"data-tweet-id\")}}),this.addUrlParams(e)},handleResize:function(){this.handleResize=f(function(){var e=this,t=Math.min(this.dimensions.DEFAULT_WIDTH,Math.max(this.dimensions.MIN_WIDTH,this.sandbox.frame.offsetWidth));if(!this.element)return;t<this.dimensions.NARROW_WIDTH?(this.narrow=!0,s.add(this.element,\"var-narrow\")):(this.narrow=!1,s.remove(this.element,\"var-narrow\")),window.setTimeout(function(){e.sandbox.frame.height=e.height=e.element.offsetHeight},0)},50,this),this.handleResize()},readTimestampTranslations:function(){var e=this.element,t=\"data-dt-\",n=e.getAttribute(t+\"months\")||\"\";this.datetime=new r(a.compact({phrases:{AM:e.getAttribute(t+\"am\"),PM:e.getAttribute(t+\"pm\")},months:n.split(\"|\"),formats:{full:e.getAttribute(t+\"full\")}}))},updateTimeStamps:function(){var e=o.one(\"long-permalink\",this.element,\"A\"),t=e.getAttribute(\"data-datetime\"),n=t&&this.datetime.localTimeStamp(t),r=e.getElementsByTagName(\"TIME\")[0];if(!n)return;if(r&&r.innerHTML){r.innerHTML=n;return}e.innerHTML=n}}),w.fetchAndRender=function(){var e=m,t=[],n,r;m={};if(e.keys)t=e.keys();else for(n in e)e.hasOwnProperty(n)&&t.push(n);if(!t.length)return;p.initPostLogging(),r=e[t[0]][0].lang,h.tweets({ids:t.sort(),lang:r,complete:function(t){var n,r,i,s,o,u,a=[];for(n in t)if(t.hasOwnProperty(n)){o=e[n]&&e[n];for(i=0;o.length&&(s=o[i]);i++)s.s&&(s.s.call(this,t[n]),s.r&&a.push(s.r));delete e[n]}for(i=0;u=a[i];i++)u.call(this);for(r in e)if(e.hasOwnProperty(r)){o=e[r];for(i=0;o.length&&(s=o[i]);i++)s.f&&s.f.call(this,t[n])}p.flush()}})},t.afterLoad(w.fetchAndRender),e(w)})});\nprovide(\"dom/textsize\",function(e){function n(e,t,n){var r=[],i=0,s;for(;s=n[i];i++)r.push(s[0]),r.push(s[1]);return e+t+r.join(\":\")}function r(e){var t=e||\"\";return t.replace(/([A-Z])/g,function(e){return\"-\"+e.toLowerCase()})}var t={};e(function(e,i,s){var o=document.createElement(\"span\"),u={},a=\"\",f,l=0,c=0,h=[];s=s||[],i=i||\"\",a=n(e,i,s);if(t[a])return t[a];o.className=i+\" twitter-measurement\";try{for(;f=s[l];l++)o.style[f[0]]=f[1]}catch(p){for(;f=s[c];c++)h.push(r(f[0])+\":\"+f[1]);o.setAttribute(\"style\",h.join(\";\")+\";\")}return o.innerHTML=e,document.body.appendChild(o),u.width=o.clientWidth||o.offsetWidth,u.height=o.clientHeight||o.offsetHeight,document.body.removeChild(o),delete o,t[a]=u})});\nprovide(\"tfw/widget/tweetbase\",function(e){using(\"util/util\",\"tfw/widget/base\",\"util/querystring\",\"util/twitter\",\"util/uri\",function(t,n,r,i,s){function a(e){if(!e)return;var t;n.apply(this,[e]),t=this.params(),this.text=t.text||this.dataAttr(\"text\"),this.text&&/\\+/.test(this.text)&&!/ /.test(this.text)&&(this.text=this.text.replace(/\\+/g,\" \")),this.align=t.align||this.dataAttr(\"align\")||\"\",this.via=t.via||this.dataAttr(\"via\"),this.placeid=t.placeid||this.dataAttr(\"placeid\"),this.hashtags=t.hashtags||this.dataAttr(\"hashtags\"),this.screen_name=i.screenName(t.screen_name||t.screenName||this.dataAttr(\"button-screen-name\")),this.url=t.url||this.dataAttr(\"url\")}var o=document.title,u=encodeURI(location.href);a.prototype=new n,t.aug(a.prototype,{parameters:function(){var e={text:this.text,url:this.url,related:this.related,lang:this.lang,placeid:this.placeid,original_referer:location.href,id:this.id,screen_name:this.screen_name,hashtags:this.hashtags,partner:this.partner,dnt:this.dnt,_:+(new Date)};return t.compact(e),r.encode(e)}}),e(a)})});\nprovide(\"tfw/widget/tweetbutton\",function(e){using(\"tfw/widget/tweetbase\",\"util/util\",\"util/querystring\",\"util/uri\",\"util/twitter\",\"dom/textsize\",function(t,n,r,i,s,o){var u=document.title,a=encodeURI(location.href),f=[\"vertical\",\"horizontal\",\"none\"],l=function(e){t.apply(this,[e]);var r=this.params(),o=r.count||this.dataAttr(\"count\"),l=r.size||this.dataAttr(\"size\"),c=i.getScreenNameFromPage();if(r.type==\"hashtag\"||~n.indexOf(this.classAttr,\"twitter-hashtag-button\"))this.type=\"hashtag\";else if(r.type==\"mention\"||~n.indexOf(this.classAttr,\"twitter-mention-button\"))this.type=\"mention\";this.counturl=r.counturl||this.dataAttr(\"counturl\"),this.searchlink=r.searchlink||this.dataAttr(\"searchlink\"),this.button_hashtag=s.hashTag(r.button_hashtag||r.hashtag||this.dataAttr(\"button-hashtag\"),!1),this.size=l==\"large\"?\"l\":\"m\",this.type?(this.count=\"none\",c&&(this.related=this.related?c+\",\"+this.related:c)):(this.text=this.text||u,this.url=this.url||i.getCanonicalURL()||a,this.count=~n.indexOf(f,o)?o:\"horizontal\",this.count=this.count==\"vertical\"&&this.size==\"l\"?\"none\":this.count,this.via=this.via||c)};l.prototype=new t,n.aug(l.prototype,{parameters:function(){var e={text:this.text,url:this.url,via:this.via,related:this.related,count:this.count,lang:this.lang,counturl:this.counturl,searchlink:this.searchlink,placeid:this.placeid,original_referer:location.href,id:this.id,size:this.size,type:this.type,screen_name:this.screen_name,button_hashtag:this.button_hashtag,hashtags:this.hashtags,align:this.align,partner:this.partner,dnt:this.dnt,_:+(new Date)};return n.compact(e),r.encode(e)},height:function(){return this.count==\"vertical\"?62:this.size==\"m\"?20:28},width:function(){var e={ver:8,cnt:14,btn:24,xlcnt:18,xlbtn:38},t=this.count==\"vertical\",r=this.type==\"hashtag\"&&this.button_hashtag?\"Tweet %{hashtag}\":this.type==\"mention\"&&this.screen_name?\"Tweet to %{name}\":\"Tweet\",i=this._(r,{name:\"@\"+this.screen_name,hashtag:\"#\"+this.button_hashtag}),s=this._(\"K\"),u=this._(\"100K+\"),a=(t?\"8888\":\"88888\")+s,f=0,l=0,c=0,h=0,p=this.styles.base,d=p;return~n.indexOf([\"ja\",\"ko\"],this.lang)?a+=this._(\"10k unit\"):a=a.length>u.length?a:u,t?(d=p.concat(this.styles.vbubble),h=e.ver,c=e.btn):this.size==\"l\"?(p=d=p.concat(this.styles.large),c=e.xlbtn,h=e.xlcnt):(c=e.btn,h=e.cnt),this.count!=\"none\"&&(l=o(a,\"\",d).width+h),f=o(i,\"\",p.concat(this.styles.button)).width+c,t?f>l?f:l:this.calculatedWidth=f+l},render:function(e,t){var n=twttr.widgets.config.assetUrl()+\"/widgets/tweet_button.1379634856.html#\"+this.parameters();this.count&&this.classAttr.push(\"twitter-count-\"+this.count),this.element=this.create(n,this.dimensions(),{title:this._(\"Twitter Tweet Button\")}),t&&t(this.element)}}),e(l)})});\nprovide(\"tfw/widget/follow\",function(e){using(\"util/util\",\"tfw/widget/base\",\"util/querystring\",\"util/uri\",\"util/twitter\",\"dom/textsize\",function(t,n,r,i,s,o){function u(e){if(!e)return;var t,r,i,o,u;n.apply(this,[e]),t=this.params(),r=t.size||this.dataAttr(\"size\"),i=t.showScreenName||this.dataAttr(\"show-screen-name\"),u=t.count||this.dataAttr(\"count\"),this.classAttr.push(\"twitter-follow-button\"),this.showScreenName=i!=\"false\",this.showCount=t.showCount!==!1&&this.dataAttr(\"show-count\")!=\"false\",u==\"none\"&&(this.showCount=!1),this.explicitWidth=t.width||this.dataAttr(\"width\")||\"\",this.screenName=t.screen_name||t.screenName||s.screenName(this.attr(\"href\")),this.preview=t.preview||this.dataAttr(\"preview\")||\"\",this.align=t.align||this.dataAttr(\"align\")||\"\",this.size=r==\"large\"?\"l\":\"m\"}u.prototype=new n,t.aug(u.prototype,{parameters:function(){var e={screen_name:this.screenName,lang:this.lang,show_count:this.showCount,show_screen_name:this.showScreenName,align:this.align,id:this.id,preview:this.preview,size:this.size,partner:this.partner,dnt:this.dnt,_:+(new Date)};return t.compact(e),r.encode(e)},render:function(e,t){if(!this.screenName)return;var n=twttr.widgets.config.assetUrl()+\"/widgets/follow_button.1379634856.html#\"+this.parameters();this.element=this.create(n,this.dimensions(),{title:this._(\"Twitter Follow Button\")}),t&&t(this.element)},width:function(){if(this.calculatedWidth)return this.calculatedWidth;if(this.explicitWidth)return this.explicitWidth;var e={cnt:13,btn:24,xlcnt:22,xlbtn:38},n=this.showScreenName?\"Follow %{screen_name}\":\"Follow\",r=this._(n,{screen_name:\"@\"+this.screenName}),i=~t.indexOf([\"ja\",\"ko\"],this.lang)?this._(\"10k unit\"):this._(\"M\"),s=this._(\"%{followers_count} followers\",{followers_count:\"88888\"+i}),u=0,a=0,f,l,c=this.styles.base;return this.size==\"l\"?(c=c.concat(this.styles.large),f=e.xlbtn,l=e.xlcnt):(f=e.btn,l=e.cnt),this.showCount&&(a=o(s,\"\",c).width+l),u=o(r,\"\",c.concat(this.styles.button)).width+f,this.calculatedWidth=u+a}}),e(u)})});\n!function(){window.twttr=window.twttr||{},twttr.host=twttr.host||\"platform.twitter.com\",using(\"util/domready\",\"util/env\",function(e,t){function n(e){return(e||!/^http\\:$/.test(window.location.protocol))&&!twttr.ignoreSSL?\"https\":\"http\"}if(t.ie6())return;if(twttr.widgets&&twttr.widgets.loaded)return twttr.widgets.load(),!1;if(twttr.init)return!1;twttr.init=!0,twttr._e=twttr._e||[],twttr.ready=twttr.ready||function(e){twttr.widgets&&twttr.widgets.loaded?e(twttr):twttr._e.push(e)},using.path.length||(using.path=n()+\"://\"+twttr.host+\"/js\"),twttr.ignoreSSL=twttr.ignoreSSL||!1;var r=[];twttr.events={bind:function(e,t){return r.push([e,t])}},e(function(){using(\"tfw/widget/base\",\"tfw/widget/follow\",\"tfw/widget/tweetbutton\",\"tfw/widget/embed\",\"tfw/widget/timeline\",\"tfw/widget/intent\",\"tfw/util/article\",\"util/events\",\"util/util\",function(e,t,i,s,o,u,a,f,l){function m(e){var t=twttr.host;return n(e)==\"https\"&&twttr.secureHost&&(t=twttr.secureHost),n(e)+\"://\"+t}function g(){using(\"tfw/hub/client\",function(e){twttr.events.hub=e.init(p),e.init(p,!0)})}var c,h,p={widgets:{\"a.twitter-share-button\":i,\"a.twitter-mention-button\":i,\"a.twitter-hashtag-button\":i,\"a.twitter-follow-button\":t,\"blockquote.twitter-tweet\":s,\"a.twitter-timeline\":o,body:u}},d=twttr.events&&twttr.events.hub?twttr.events:{},v;p.assetUrl=m,twttr.widgets=twttr.widgets||{},l.aug(twttr.widgets,{config:{assetUrl:m},load:function(t){e.init(p),e.embed(t),twttr.widgets.loaded=!0},createShareButton:function(e,t,n,r){if(!e||!t)return n&&n(!1);r=l.aug({},r||{},{url:e,targetEl:t}),(new i(r)).render(p,n)},createHashtagButton:function(e,t,n,r){if(!e||!t)return n&&n(!1);r=l.aug({},r||{},{hashtag:e,targetEl:t,type:\"hashtag\"}),(new i(r)).render(p,n)},createMentionButton:function(e,t,n,r){if(!e||!t)return n&&n(!1);r=l.aug({},r||{},{screenName:e,targetEl:t,type:\"mention\"}),(new i(r)).render(p,n)},createFollowButton:function(e,n,r,i){if(!e||!n)return r&&r(!1);i=l.aug({},i||{},{screenName:e,targetEl:n}),(new t(i)).render(p,r)},createTweet:function(e,t,n,r){if(!e||!t)return n&&n(!1);r=l.aug({},r||{},{tweetId:e,targetEl:t}),(new s(r)).render(p,n),s.fetchAndRender()},createTimeline:function(e,t,n,r){if(!e||!t)return n&&n(!1);r=l.aug({},r||{},{widgetId:e,targetEl:t}),(new o(r)).render(p,n)}}),l.aug(twttr.events,d,f.Emitter),v=twttr.events.bind,twttr.events.bind=function(e,t){g(),this.bind=v,this.bind(e,t)};for(c=0;h=r[c];c++)twttr.events.bind(h[0],h[1]);for(c=0;h=twttr._e[c];c++)h(twttr);twttr.ready=function(e){e(twttr)},/twitter\\.com(\\:\\d+)?$/.test(document.location.host)&&(twttr.widgets.createTimelinePreview=function(e,t,n){if(!p||!t)return n&&n(!1);(new o({previewParams:e,targetEl:t,linkColor:e.link_color,theme:e.theme,height:e.height})).render(p,n)}),twttr.widgets.createTweetEmbed=twttr.widgets.createTweet,twttr.widgets.load()})})})}()});"
  },
  {
    "path": "templates-sdk/components/left_nav.cs",
    "content": "<?cs # The default side navigation for the reference docs ?><?cs \ndef:custom_left_nav() ?>\n  <div class=\"g-section g-tpl-240\" id=\"body-content\">\n    <div class=\"g-unit g-first side-nav-resizable\" id=\"side-nav\">\n      <div id=\"swapper\">\n        <div id=\"nav-panels\">\n          <div id=\"resize-packages-nav\">\n            <div id=\"packages-nav\">\n              <div id=\"index-links\">\n                <a href=\"<?cs var:toroot ?>packages.html\" <?cs if:(page.title == \"Package Index\") ?>class=\"selected\"<?cs /if ?> >Package Index</a> | \n                <a href=\"<?cs var:toroot ?>classes.html\" <?cs if:(page.title == \"Class Index\") ?>class=\"selected\"<?cs /if ?>>Class Index</a>\n              </div>\n              <ul>\n                <?cs call:package_link_list(docs.packages) ?>\n              </ul><br/>\n            </div> <!-- end packages -->\n          </div> <!-- end resize-packages -->\n          <div id=\"classes-nav\"><?cs \n            if:subcount(class.package) ?>\n            <ul>\n              <?cs call:list(\"Interfaces\", class.package.interfaces) ?>\n              <?cs call:list(\"Classes\", class.package.classes) ?>\n              <?cs call:list(\"Annotations\", class.package.annotations) ?>\n              <?cs call:list(\"Enums\", class.package.enums) ?>\n              <?cs call:list(\"Exceptions\", class.package.exceptions) ?>\n              <?cs call:list(\"Errors\", class.package.errors) ?>\n            </ul><?cs \n            elif:subcount(package) ?>\n            <ul>\n              <?cs call:class_link_list(\"Interfaces\", package.interfaces) ?>\n              <?cs call:class_link_list(\"Classes\", package.classes) ?>\n              <?cs call:class_link_list(\"Annotations\", package.annotations) ?>\n              <?cs call:class_link_list(\"Enums\", package.enums) ?>\n              <?cs call:class_link_list(\"Exceptions\", package.exceptions) ?>\n              <?cs call:class_link_list(\"Errors\", package.errors) ?>\n            </ul><?cs \n            else ?>\n              <script>\n                /*addLoadEvent(maxPackageHeight);*/\n              </script>\n              <p style=\"padding:10px\">Select a package to view its members</p><?cs \n            /if ?><br/>\n          </div><!-- end classes -->\n        </div><!-- end nav-panels -->\n        <div id=\"nav-tree\" style=\"display:none\">\n          <div id=\"index-links\">\n            <a href=\"<?cs var:toroot ?>packages.html\" <?cs if:(page.title == \"Package Index\") ?>class=\"selected\"<?cs /if ?> >Package Index</a> | \n            <a href=\"<?cs var:toroot ?>classes.html\" <?cs if:(page.title == \"Class Index\") ?>class=\"selected\"<?cs /if ?>>Class Index</a>\n          </div>\n        </div><!-- end nav-tree -->\n      </div><!-- end swapper -->\n    </div> <!-- end side-nav -->\n    <script>\n     \n          addLoadEvent(function() {\n            scrollIntoView(\"packages-nav\");\n            scrollIntoView(\"classes-nav\");\n          });\n        \n      \n    </script><?cs \n/def ?>"
  },
  {
    "path": "templates-sdk/components/masthead.cs",
    "content": "\n<?cs # The default search box that goes in the header ?><?cs \ndef:default_search_box() ?>\n\n\t\t<?cs set:temproot=toroot?>\n\t\t<?cs if:reference?>\n\t\t<?cs set:temproot=toroot?>\n\t\t<?cs else ?>\n\t\t<?cs set:toroot = toroot + \"javadoc/\"?>\n\t\t<?cs /if ?>\n\t\t  <div id=\"search\" >\n\t\t\t  <div id=\"searchForm\">\n\t\t\t\t  <form accept-charset=\"utf-8\" class=\"gsc-search-box\" \n\t\t\t\t\t\t>\n\t\t\t\t\t\n\t\t\t\t\t\t\t<input id=\"search_autocomplete\" class=\"gsc-input\" type=\"text\" size=\"33\" autocomplete=\"off\"\n\t\t\t\t\t\t\t  title=\"search javadoc\" name=\"q\"\n\t\t\t\t\t\t\t  value=\"search javadoc\"\n\t\t\t\t\t\t\t  onFocus=\"search_focus_changed(this, true)\"\n\t\t\t\t\t\t\t  onBlur=\"search_focus_changed(this, false)\"\n\t\t\t\t\t\t\t  onkeydown=\"return search_changed(event, true, '<?cs var:toroot?>')\"\n\t\t\t\t\t\t\t  onkeyup=\"return search_changed(event, false, '<?cs var:toroot?>')\" />\n\t\t\t\t\t\t  <div id=\"search_filtered_div\" class=\"no-display\">\n\t\t\t\t\t\t\t  <table id=\"search_filtered\" cellspacing=0>\n\t\t\t\t\t\t\t  </table>\n\t\t\t\t\t\t  </div>\n\t\t\t\t\t\t  \n\t\t\t\t  </form>\n\t\t\t  </div><!-- searchForm -->\n\t\t  </div><!-- search -->\n\t\t  \n\t\t  <?cs set:toroot = temproot?>\n<?cs \n/def ?>\n\n<?cs # The default API filter selector that goes in the header ?><?cs\ndef:default_api_filter() ?><?cs\n  if:reference.apilevels ?>\n  <div id=\"api-level-toggle\">\n    <input type=\"checkbox\" id=\"apiLevelCheckbox\" onclick=\"toggleApiLevelSelector(this)\" />\n    <label for=\"apiLevelCheckbox\" class=\"disabled\">Filter by API Level: </label>\n\t</br>\n    <select id=\"apiLevelSelector\">\n      <!-- option elements added by buildApiLevelSelector() -->\n    </select>\n  </div>\n  <script>\n   var SINCE_DATA = [ <?cs \n      each:since = since ?>'<?cs \n        var:since.key ?>'<?cs \n        if:!last(since) ?>, <?cs /if ?><?cs\n      /each \n    ?> ];\n    \n    var SINCE_LABELS = [ <?cs \n      each:since = since ?>'<?cs \n        var:since.name ?>'<?cs \n        if:!last(since) ?>, <?cs /if ?><?cs\n      /each \n    ?> ];\n    buildApiLevelSelector();\n    addLoadEvent(changeApiLevel);\n  </script>\n<?cs /if ?>\n<?cs /def ?>\n\n\n\n\n<?cs \ndef:custom_masthead() ?>\n<?cs if:doc.type != \"overview\" ?>\n<div style=\"min-width: 1402px;width:100%;border-bottom:2px solid #ff6600;\">\n<div style=\"width:1402px;margin:auto;\">\n  <div id=\"header\">\n  \n      <div id=\"headerRight\">\n         <?cs \n          call:default_api_filter() ?>\n    \t <?cs \t    \n          call:default_search_box() ?>\n      </div><!-- headerRight -->\n      <div id=\"headerLeft\">\n\t\t<?cs set:temproot=toroot?>\n\t\t<?cs if:reference ?>\n\t\t<?cs set:toroot = \"../\" + toroot?>\n\t\t<?cs /if ?>\n          <a style=\"text-decoration:none;\" href=\"<?cs var:toroot?>index.html\" tabindex=\"-1\"><img\n              src=\"<?cs var:toroot ?>assets/images/joyn_logo_sdk.png\" alt=\"joyn SDK\" />SDK for Android</a>\n          <ul class=\"<?cs if:home ?>home<?cs\n                      elif:(doc.type == \"source\" || doc.type == \"apilevel\") ?>source<?cs\n                      elif:doc.type == \"guides\" ?>guides<?cs\n                      elif:doc.type == \"samples\" ?>samples<?cs\n                      elif:doc.type == \"tools\" ?>tools<?cs\n                      elif:doc.type == \"faq\" ?>faq<?cs\n\t\t\t\t\t  elif:doc.type == \"tutorials\" ?>tutorials<?cs\n                      elif:doc.type == \"download\" ?>download<?cs /if ?>\">\n              <li id=\"home-link\"><a href=\"<?cs var:toroot ?>index.html\"><span>Home</span></a></li>\n              <li id=\"source-link\"><a href=\"<?cs var:toroot ?>javadoc/index.html\"\n                                  onClick=\"return loadLast('source')\"><span>Javadoc</span></a></li>\n              <li id=\"samples-link\"><a href=\"<?cs var:toroot ?>samples/index.html\"\n                                  onClick=\"return loadLast('samples')\"><span>Samples</span></a></li>\n\t\t\t  <li id=\"tutorials-link\"><a href=\"<?cs var:toroot ?>tutorials/index.html\"\n                                  onClick=\"return loadLast('tutorials')\"><span>Tutorials</span></a></li>\n              <li id=\"tools-link\"><a href=\"<?cs var:toroot ?>tools/index.html\"\n                                  onClick=\"return loadLast('tools')\"><span>Tools</span></a></li>\n              <!--<li id=\"faq-link\"><a href=\"<?cs var:toroot ?>FAQ/index.html\"\n                                  onClick=\"return loadLast('faq')\"><span>FAQ</span></a></li>-->\n              <li id=\"download-link\"><a href=\"<?cs var:toroot ?>download/index.html\"\n                                  onClick=\"return loadLast('download')\"><span>Downloads</span></a></li>\n\t\t\t  <li id=\"faq-link\"><a href=\"<?cs var:toroot ?>support.html\"\n                                  onClick=\"return loadLast('faq')\"><span>Support</span></a></li>\n          </ul> \n\t\t  <?cs set:toroot = temproot?>\n      </div>\n      \n  </div><!-- header -->\n  </div>\n  </div>\n  <?cs \n          call:static_side_nav() ?>\n  <?cs /if ?>\n\n<?cs \n/def ?>\n\n<?cs \ndef:static_side_nav() ?>\n\t<?cs if:doc.type == \"samples\" ?>\n\t<div style=\"margin: 0;position: relative;width: 100%;\">\n\t\t<div class=\"background-sdk\" style=\"padding: 0;\">\n\t\t\t<div class=\"content-block nav-block\">\n\t\t\t\t<div id=\"guide-nav\" class=\"nav\">\n\t\t\t\t\t<p <?cs if:page.title == \"Samples\" ?>class=\"selected\"<?cs /if ?> style=\"margin-top: 15px;\"><a  href=\"<?cs var:toroot ?>samples/index.html\"><b>Samples</b></a></p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"How to connect to a joyn service\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>samples/connectService.html\" >> How to connect to a joyn service</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"How to initialise a chat\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>samples/initChat.html\" >> How to initialise a chat</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"Get online contacts\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>samples/listContacts.html\">> How to get online joyn contacts</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"How to get joyn contacts supporting a given service\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>samples/serviceSupported.html\">> How to get joyn contacts supporting a given service</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"Detect if joyn service is started\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>samples/detectServices.html\">> How to detect if the joyn service is started</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<?cs elif:doc.type == \"tutorials\" ?>\n\t<div style=\"margin: 0;position: relative;width: 100%;\">\n\t\t<div class=\"background-sdk\" style=\"padding: 0;\">\n\t\t\t<div class=\"content-block nav-block\" >\n\t\t\t\t<div id=\"tutorial-nav\" class=\"nav\">\n\t\t\t\t\t<p <?cs if:page.title == \"Tutorials\" ?>class=\"selected\"<?cs /if ?> style=\"margin-top: 15px;\"><a  href=\"<?cs var:toroot ?>tutorials/index.html\"><b>Tutorials</b></a></p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"Text to speech application\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>tutorials/ttsApp.html\">> Text to speech application</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"New multimedia Capability\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>tutorials/multiCapability.html\">> New multimedia Capability</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"Popup application\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>tutorials/popUpApp.html\">> Popup application</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"New multimedia application\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>tutorials/multiApp.html\">> New multimedia application</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<?cs elif:doc.type == \"tools\" ?>\n\t<div style=\"margin: 0;position: relative;width: 100%;\">\n\t\t<div class=\"background-sdk\" style=\"padding: 0;\">\n\t\t\t<div class=\"content-block nav-block\" >\n\t\t\t\t<div id=\"tools-nav\" class=\"nav\">\n\t\t\t\t\t<p <?cs if:page.title == \"Tools\" ?>class=\"selected\"<?cs /if ?> style=\"margin-top: 15px;\"><a  href=\"<?cs var:toroot ?>tools/index.html\"><b>Tools</b></a></p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"Install joyn standalone service\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>tools/installJoynServices.html\">> Standalone joyn service</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"Get to know joyn services via the RI application\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>tools/getToKnow.html\">> RI</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\t\t\t\t\t\t\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div><?cs elif:doc.type == \"apilevel\" ?>\n\t<div style=\"margin: 0;position: relative;width: 100%;\">\n\t\t<div class=\"background-sdk\" style=\"padding: 0;\">\n\t\t\t<div class=\"content-block nav-block\" >\n\t\t\t\t<div id=\"tools-nav\" class=\"nav\">\n\t\t\t\t\t<p  style=\"margin-top: 15px;\"><a  href=\"\"><b>API Levels</b></a></p>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"API version Albatros\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>releases/Albatros.html\">> Albatros</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"API version Blackbird\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>releases/Blackbird.html\">> Blackbird</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\t\t\t\t\t\t\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<div <?cs if:page.title == \"API version Crane\" ?>class=\"selected\"<?cs /if ?>>\n\t\t\t\t\t\t\t\t<a href=\"<?cs var:toroot ?>releases/Crane.html\">> Crane</a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</li>\t\t\t\t\t\t\n\t\t\t\t\t</ul>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<?cs /if ?>\n<?cs \n/def ?>"
  },
  {
    "path": "templates-sdk/footer.cs",
    "content": "<?cs if:doc.type != \"overview\"?>\n<div id=\"footer\">\n<div class=\"footer\">\n<div style=\"margin:0 0 10px 200px;\">Copyright (C) 2013 Orange S.A.,</br> Generated by <a href=\"http://code.google.com/p/doclava/\">Doclava</a>.</div>\n</div>\n</div> <!-- end footer -->\n<?cs /if ?>\n"
  },
  {
    "path": "templates-sdk/head_tag.cs",
    "content": "\n<?cs set:temproot=toroot?>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"<?cs var:toroot ?>favicon.ico\" />\n<title><?cs \n  if:page.title ?><?cs \n    var:page.title ?> | <?cs\n  /if ?>joyn SDK</title>\n\n\n</script><?cs \nif:reference ?>\n<?cs set:doc.type = \"source\"?>\n\n<?cs set:toroot = \"../\" + toroot?>\n<script src=\"<?cs var:toroot ?>assets/android-developer-reference.js\" type=\"text/javascript\"></script>\n\n<?cs /if ?>\n<link href=\"<?cs var:toroot ?>assets/android-developer-docs-devguide.css\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"<?cs var:toroot ?>assets/android-developer-docs.css\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"<?cs var:toroot ?>assets/joyn-sdk.css\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"<?cs var:toroot ?>assets/skin-carousel-ri.css\" rel=\"stylesheet\" type=\"text/css\" />\n<link href=\"<?cs var:toroot ?>assets/skin-carousel-home.css\" rel=\"stylesheet\" type=\"text/css\" />\n<script src=\"<?cs var:toroot ?>assets/jquery-1.10.2.min.js\" type=\"text/javascript\"></script>\n<script src=\"<?cs var:toroot ?>assets/search_autocomplete.js\" type=\"text/javascript\"></script>\n<script src=\"<?cs var:toroot ?>assets/jquery-resizable.min.js\" type=\"text/javascript\"></script>\n<script src=\"<?cs var:toroot ?>assets/android-developer-docs.js\" type=\"text/javascript\"></script>\n<script src=\"<?cs var:toroot ?>assets/prettify.js\" type=\"text/javascript\"></script>\n<script src=\"<?cs var:toroot ?>assets/joyn-sdk.js\" type=\"text/javascript\"></script>\n<script src=\"<?cs var:toroot ?>assets/carousel.js\" type=\"text/javascript\"></script>\n<script type=\"text/javascript\" src=\"<?cs var:toroot ?>assets/jquery.jcarousel.min.js\"></script>\n<script type=\"text/javascript\" src=\"<?cs var:toroot ?>assets/widget.js\"></script>\n<script type=\"text/javascript\">\n  setToRoot(\"<?cs var:toroot ?>\");\n</script>\n<noscript>\n  <style type=\"text/css\">\n    html,body{overflow:auto;}\n    #body-content{position:relative; top:0;}\n    #doc-content{overflow:visible;border-left:3px solid #666;}\n    #side-nav{padding:0;}\n    #side-nav .toggle-list ul {display:block;}\n    #resize-packages-nav{border-bottom:3px solid #666;}\n  </style>\n</noscript>\n<script type=\"text/javascript\">\n\tfunction mycarousel_initCallback(carousel) {\n\t\tjQuery('.jcarousel-control a').bind('click', function() {\n\t\t\tif(jQuery(this).attr('id') != ''){\n\t\t\t\tcarousel.scroll(jQuery.jcarousel.intval(jQuery(this).attr('id')));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\t // Disable autoscrolling if the user clicks the prev or next button.\n\t\tcarousel.buttonNext.bind('click', function() {\n\t\t\tcarousel.startAuto(0);\n\t\t});\n\n\t\tcarousel.buttonPrev.bind('click', function() {\n\t\t\tcarousel.startAuto(0);\n\t\t});\n\n\t\t// Pause autoscrolling if the user moves with the cursor over the clip.\n\t\tcarousel.clip.hover(function() {\n\t\t\tcarousel.stopAuto();\n\t\t}, function() {\n\t\t\tcarousel.startAuto();\n\t\t});\n\t };\n\t \n\t function mycarousel_itemVisibleInCallback(a1,a2,index,a4) {\n\t\t$('#' + index).find(\">:first-child\").css('background-color','#ff6600');\n\t };\n\t \n\t function mycarousel_itemVisibleOutCallback(a1,a2,index,a4) {\n\t\t$('#' + index).find(\">:first-child\").css('background-color',null);\n\t };\n\tjQuery(document).ready(function() {\n\t\tjQuery('#mycarousel').jcarousel({\n\t\t\tscroll: 1,\n\t\t\tinitCallback: mycarousel_initCallback,\n\t\t\titemVisibleInCallback: {\n\t\t\t  onBeforeAnimation: mycarousel_itemVisibleInCallback\t\t\t  \n\t\t\t},\n\t\t\titemVisibleOutCallback: {\n\t\t\t  onBeforeAnimation: mycarousel_itemVisibleOutCallback\t\t\t  \n\t\t\t},\n\t\t\tauto: 5,\n\t\t\twrap: 'last'\n\t\t\t\n\t\t});\n\t});\n\t\n\tjQuery(document).ready(function() {\n\t\tjQuery('#carousel-home').jcarousel({\n\t\t\tscroll: 3,\n\t\t\tvertical:true\n\t\t});\n\t});\n\n</script>\n</head>\n\n<?cs set:toroot = temproot?>"
  },
  {
    "path": "templates-sdk/macros.cs",
    "content": "<?cs # A link to a package ?><?cs \ndef:package_link(pkg) ?>\n  <a href=\"<?cs var:toroot ?><?cs var:pkg.link ?>\"><?cs var:pkg.name ?></a><?cs \n/def ?>\n\n<?cs # A link to a type, or not if it's a primitive type\n        link: whether to create a link at the top level, always creates links in\n              recursive invocations.\n        Expects the following fields:\n            .name\n            .link\n            .isPrimitive\n            .superBounds.N.(more links)   (... super ... & ...)\n            .extendsBounds.N.(more links) (... extends ... & ...)\n            .typeArguments.N.(more links) (< ... >)\n?><?cs \ndef:type_link_impl(type, link) ?><?cs \n  if:type.link && link==\"true\" ?><?cs\n    if:type.federated ?><a href=\"<?cs var:type.link ?>\"><?cs\n      var:type.label ?></a><?cs \n    else ?><a href=\"<?cs var:toroot ?><?cs var:type.link ?>\"><?cs var:type.label ?></a><?cs\n    /if ?><?cs\n  else ?><?cs var:type.label ?><?cs\n  /if ?><?cs if:subcount(type.extendsBounds) ?><?cs\n      each:t=type.extendsBounds ?><?cs\n          if:first(t) ?>&nbsp;extends&nbsp;<?cs else ?>&nbsp;&amp;&nbsp;<?cs /if ?><?cs\n          call:type_link_impl(t, \"true\") ?><?cs\n      /each ?><?cs\n  /if ?><?cs\n  if:subcount(type.superBounds) ?><?cs\n      each:t=type.superBounds ?><?cs\n          if:first(t) ?>&nbsp;super&nbsp;<?cs else ?>&nbsp;&amp;&nbsp;<?cs /if ?><?cs\n          call:type_link_impl(t, \"true\") ?><?cs\n      /each ?><?cs\n  /if ?><?cs\n  if:subcount(type.typeArguments)\n      ?>&lt;<?cs each:t=type.typeArguments ?><?cs call:type_link_impl(t, \"true\") ?><?cs\n          if:!last(t) ?>,&nbsp;<?cs /if ?><?cs\n      /each ?>&gt;<?cs\n  /if ?><?cs\n/def ?>\n\n<?cs def:class_name(type) ?><?cs call:type_link_impl(type, \"false\") ?><?cs /def ?>\n<?cs def:type_link(type) ?><?cs call:type_link_impl(type, \"true\") ?><?cs /def ?>\n\n<?cs # a conditional link.\n      if the \"condition\" parameter evals to true then the link is displayed\n      otherwise only the text is displayed\n?><?cs\ndef:cond_link(text, root, path, condition) ?><?cs\n  if:condition ?><a href=\"<?cs var:root ?><?cs var:path ?>\"><?cs /if ?><?cs var:text ?><?cs if:condition ?></a><?cs /if ?><?cs\n/def ?>\n\n<?cs # A comma separated parameter list ?><?cs \ndef:parameter_list(params) ?><?cs\n  each:param = params ?><?cs\n      call:type_link(param.type)?> <?cs\n      var:param.name ?><?cs\n      if: name(param)!=subcount(params)-1?>, <?cs /if ?><?cs\n  /each ?><?cs\n/def ?>\n\n<?cs # Print a list of tags (e.g. description text ?><?cs \ndef:tag_list(tags) ?><?cs\n  each:tag = tags ?><?cs\n      if:tag.name == \"Text\" ?><?cs var:tag.text?><?cs\n      elif:tag.kind == \"@more\" ?><p><?cs\n      elif:tag.kind == \"@see\" ?><code><a href=\"<?cs\n        if:tag.isLocal?><?cs var:toroot ?><?cs /if ?><?cs\n        var:tag.href ?>\"><?cs var:tag.label ?></a></code><?cs\n      elif:tag.kind == \"@seeHref\" ?><a href=\"<?cs var:tag.href ?>\"><?cs var:tag.label ?></a><?cs\n      elif:tag.kind == \"@seeJustLabel\" ?><?cs var:tag.label ?><?cs\n      elif:tag.kind == \"@code\" ?><code><?cs var:tag.text ?></code><?cs\n      elif:tag.kind == \"@samplecode\" ?><pre><?cs var:tag.text ?></pre><?cs\n      elif:tag.name == \"@sample\" ?><pre><?cs var:tag.text ?></pre><?cs\n      elif:tag.name == \"@include\" ?><?cs var:tag.text ?><?cs\n      elif:tag.kind == \"@docRoot\" ?><?cs var:toroot ?><?cs\n      elif:tag.kind == \"@sdkCurrent\" ?><?cs var:sdk.current ?><?cs\n      elif:tag.kind == \"@sdkCurrentVersion\" ?><?cs var:sdk.version ?><?cs\n      elif:tag.kind == \"@sdkCurrentRelId\" ?><?cs var:sdk.rel.id ?><?cs\n      elif:tag.kind == \"@sdkPlatformVersion\" ?><?cs var:sdk.platform.version ?><?cs\n      elif:tag.kind == \"@sdkPlatformApiLevel\" ?><?cs var:sdk.platform.apiLevel ?><?cs\n      elif:tag.kind == \"@sdkPlatformMajorMinor\" ?><?cs var:sdk.platform.majorMinor ?><?cs\n      elif:tag.kind == \"@sdkPlatformReleaseDate\" ?><?cs var:sdk.platform.releaseDate ?><?cs\n      elif:tag.kind == \"@sdkPlatformDeployableDate\" ?><?cs var:sdk.platform.deployableDate ?><?cs\n      elif:tag.kind == \"@adtZipVersion\" ?><?cs var:adt.zip.version ?><?cs\n      elif:tag.kind == \"@adtZipDownload\" ?><?cs var:adt.zip.download ?><?cs\n      elif:tag.kind == \"@adtZipBytes\" ?><?cs var:adt.zip.bytes ?><?cs\n      elif:tag.kind == \"@adtZipChecksum\" ?><?cs var:adt.zip.checksum ?><?cs\n      elif:tag.kind == \"@inheritDoc\" ?><?cs # This is the case when @inheritDoc is in something\n                                              that doesn't inherit from anything?><?cs\n      elif:tag.kind == \"@attr\" ?><?cs\n      else ?>{<?cs var:tag.name?> <?cs var:tag.text ?>}<?cs\n      /if ?><?cs\n  /each ?><?cs\n/def ?>\n\n<?cs # The message about This xxx is deprecated. ?><?cs \ndef:deprecated_text(kind) ?>\n  This <?cs var:kind ?> is deprecated.<?cs \n/def ?>\n\n<?cs # Show the short-form description of something.  These come from shortDescr and deprecated ?><?cs \ndef:short_descr(obj) ?><?cs\n  if:subcount(obj.deprecated) ?>\n      <em><?cs call:deprecated_text(obj.kind) ?>\n      <?cs call:tag_list(obj.deprecated) ?></em><?cs\n  else ?><?cs call:tag_list(obj.shortDescr) ?><?cs\n  /if ?><?cs\n/def ?>\n\n<?cs # Show the red box with the deprecated warning ?><?cs \ndef:deprecated_warning(obj) ?><?cs \n  if:subcount(obj.deprecated) ?><p>\n  <p class=\"caution\">\n      <strong><?cs call:deprecated_text(obj.kind) ?></strong><br/> <?cs \n      call:tag_list(obj.deprecated) ?>\n  </p><?cs \n  /if ?><?cs \n/def ?>\n\n<?cs # print the See Also: section ?><?cs \ndef:see_also_tags(also) ?><?cs \n  if:subcount(also) ?>\n  <div class=\"jd-tagdata\">\n      <h5 class=\"jd-tagtitle\">See Also</h5>\n      <ul class=\"nolist\"><?cs \n        each:tag=also ?><li><?cs\n            if:tag.kind == \"@see\" ?><code><a href=\"<?cs var:toroot ?><?cs var:tag.href ?>\"><?cs\n                    var:tag.label ?></a></code><?cs\n            elif:tag.kind == \"@seeHref\" ?><a href=\"<?cs var:tag.href ?>\"><?cs var:tag.label ?></a><?cs\n            elif:tag.kind == \"@seeJustLabel\" ?><?cs var:tag.label ?><?cs\n            else ?>[ERROR: Unknown @see kind]<?cs\n            /if ?></li><?cs \n        /each ?>\n      </ul>\n  </div><?cs \n  /if ?>\n<?cs /def ?>\n\n<?cs # print the API Level ?><?cs\ndef:since_tags(obj) ?>\n<?cs if:reference.apilevels ?>\n  Since: <a href=\"./../<?cs var:toroot ?>releases/<?cs var:obj.since.key ?>.html\">API Level <?cs var:obj.since.name ?></a>\n<?cs /if ?>\n<?cs /def ?>\n<?cs def:federated_refs(obj) ?>\n  <?cs if:subcount(obj.federated) ?>\n    <div>\n    Also: \n    <?cs each:federated=obj.federated ?>\n      <a href=\"<?cs var:federated.url ?>\"><?cs var:federated.name ?></a><?cs \n      if:!last(federated) ?>,<?cs /if ?>\n    <?cs /each ?>\n    </div>\n  <?cs /if ?>\n<?cs /def ?>\n<?cs # Print the long-form description for something.\n       Uses the following fields: deprecated descr seeAlso since ?><?cs\ndef:description(obj) ?><?cs \n  call:deprecated_warning(obj) ?>\n  <div class=\"jd-tagdata jd-tagdescr\"><p><?cs call:tag_list(obj.descr) ?></p></div><?cs \n  if:subcount(obj.attrRefs) ?>\n  <div class=\"jd-tagdata\">\n      <h5 class=\"jd-tagtitle\">Related XML Attributes</h5>\n      <ul class=\"nolist\"><?cs \n        each:attr=obj.attrRefs ?>\n            <li><a href=\"<?cs var:toroot ?><?cs var:attr.href ?>\"><?cs var:attr.name ?></a></li><?cs \n        /each ?>\n      </ul>\n  </div><?cs \n  /if ?><?cs \n  if:subcount(obj.paramTags) ?>\n  <div class=\"jd-tagdata\">\n      <h5 class=\"jd-tagtitle\">Parameters</h5>\n      <table class=\"jd-tagtable\"><?cs \n      each:tag=obj.paramTags ?>\n        <tr>\n          <th><?cs if:tag.isTypeParameter ?>&lt;<?cs /if ?><?cs var:tag.name\n                  ?><?cs if:tag.isTypeParameter ?>&gt;<?cs /if ?></th>\n          <td><?cs call:tag_list(tag.comment) ?></td>\n        </tr><?cs \n      /each ?>\n      </table>\n  </div><?cs \n  /if ?><?cs \n  if:subcount(obj.returns) ?>\n  <div class=\"jd-tagdata\">\n      <h5 class=\"jd-tagtitle\">Returns</h5>\n      <ul class=\"nolist\"><li><?cs call:tag_list(obj.returns) ?></li></ul>\n  </div><?cs \n  /if ?><?cs \n  if:subcount(obj.throws) ?>\n  <div class=\"jd-tagdata\">\n      <h5 class=\"jd-tagtitle\">Throws</h5>\n      <table class=\"jd-tagtable\"><?cs \n      each:tag=obj.throws ?>  \n        <tr>\n            <th><?cs call:type_link(tag.type) ?></td>\n            <td><?cs call:tag_list(tag.comment) ?></td>\n        </tr><?cs \n      /each ?>\n      </table>\n  </div><?cs \n  /if ?><?cs \n  call:see_also_tags(obj.seeAlso) ?><?cs\n/def ?>\n\n<?cs # A table of links to classes with descriptions, as in a package file or the nested classes ?><?cs\ndef:class_link_table(classes) ?><?cs \n  set:count = #1 ?>\n  <table class=\"jd-sumtable-expando\"><?cs\n      each:cl=classes ?>\n        <tr class=\"<?cs if:count % #2 ?>alt-color<?cs /if ?> api apilevel-<?cs var:cl.type.since.key ?>\" >\n              <td class=\"jd-linkcol\"><?cs call:type_link(cl.type) ?></td>\n              <td class=\"jd-descrcol\" width=\"100%\"><?cs call:short_descr(cl) ?>&nbsp;</td>\n          </tr><?cs set:count = count + #1 ?><?cs\n      /each ?>\n  </table><?cs \n/def ?>\n\n<?cs # A list of links to classes, for use in the side navigation of classes when viewing a package (panel nav) ?><?cs \ndef:class_link_list(label, classes) ?><?cs \n  if:subcount(classes) ?>\n    <li><h2><?cs var:label ?></h2>\n      <ul><?cs \n      each:cl=classes ?>\n        <li class=\"api apilevel-<?cs var:cl.type.since.key ?>\"><?cs call:type_link(cl.type) ?></li><?cs \n      /each ?>\n      </ul>\n    </li><?cs \n  /if ?><?cs \n/def ?>\n\n<?cs # A list of links to classes, for use in the side navigation of classes when viewing a class (panel nav) ?><?cs \ndef:list(label, classes) ?><?cs \n  if:subcount(classes) ?>\n    <li><h2><?cs var:label ?></h2>\n      <ul><?cs \n      each:cl=classes ?>\n          <li class=\"<?cs if:class.name == cl.label?>selected <?cs /if ?>api apilevel-<?cs var:cl.since.key ?>\"><?cs call:type_link(cl) ?></li><?cs \n      /each ?>\n      </ul>\n    </li><?cs \n  /if ?><?cs \n/def ?>\n\n<?cs # A list of links to packages, for use in the side navigation of packages (panel nav) ?><?cs \ndef:package_link_list(packages) ?><?cs \n  each:pkg=packages ?>\n    <li class=\"<?cs if:(class.package.name == pkg.name) || (package.name == pkg.name)?>selected <?cs /if ?>api apilevel-<?cs var:pkg.since.key ?>\"><?cs call:package_link(pkg) ?></li><?cs \n  /each ?><?cs\n/def ?>\n\n<?cs # An expando trigger ?><?cs \ndef:expando_trigger(id, default) ?>\n  <a href=\"#\" onclick=\"return toggleInherited(this, null)\" id=\"<?cs var:id ?>\" class=\"jd-expando-trigger closed\"\n          ><img id=\"<?cs var:id ?>-trigger\"\n          src=\"<?cs var:toassets ?>images/triangle-<?cs var:default ?>.png\"\n          class=\"jd-expando-trigger-img\" /></a><?cs \n/def ?>\n\n<?cs # An expandable list of classes ?><?cs \ndef:expandable_class_list(id, classes, default) ?>\n  <div id=\"<?cs var:id ?>\">\n      <div id=\"<?cs var:id ?>-list\"\n              class=\"jd-inheritedlinks\"\n              <?cs if:default != \"list\" ?>style=\"display: none;\"<?cs /if ?>\n              >\n          <?cs if:subcount(classes) <= #20 ?>\n            <?cs each:cl=classes ?>\n              <?cs call:type_link(cl.type) ?><?cs if:!last(cl) ?>,<?cs /if ?>\n            <?cs /each ?>\n          <?cs else ?>\n            <?cs set:leftovers = subcount(classes) - #15 ?>\n            <?cs loop:i = #0, #14, #1 ?>\n              <?cs with:cl=classes[i] ?>\n                <?cs call:type_link(cl.type) ?>,\n              <?cs /with ?>\n              <?cs  if:(#i == #14) ?>and\n                <a href=\"#\" onclick=\"return toggleInherited(document.getElementById('<?cs\n                   var:id ?>', null))\"><?cs var:leftovers ?> others.</a>\n              <?cs /if ?>\n            <?cs /loop ?>\n          <?cs /if ?>\n      </div>\n      <div id=\"<?cs var:id ?>-summary\"\n              <?cs if:default != \"summary\" ?>style=\"display: none;\"<?cs /if ?>\n              ><?cs \n          call:class_link_table(classes) ?>\n      </div>\n  </div><?cs \n/def ?>\n\n<?cs include:\"components.cs\" ?>"
  },
  {
    "path": "tests/cts/provider/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\t\n    defaultConfig {\n        applicationId \"android.tests.provider\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n}\n\ndependencies {\n    // Testing-only dependencies\n    androidTestCompile 'com.android.support.test:runner:0.4.1'\n    androidTestCompile 'com.android.support.test:rules:0.4.1'\n\tcompile project(':api')\n}"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/CapabilitiesLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\n//import android.os.*;\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\npublic class CapabilitiesLogTest extends InstrumentationTestCase {\n\n    // @formatter:off\n    private static final String[] CAPABILITIES_LOG_PROJECTION = new String[] {\n            CapabilitiesLog.BASECOLUMN_ID,\n            CapabilitiesLog.CONTACT,\n            CapabilitiesLog.CAPABILITY_IMAGE_SHARE,\n            CapabilitiesLog.CAPABILITY_VIDEO_SHARE,\n            CapabilitiesLog.CAPABILITY_IM_SESSION,\n            CapabilitiesLog.CAPABILITY_FILE_TRANSFER,\n            CapabilitiesLog.CAPABILITY_GEOLOC_PUSH,\n            CapabilitiesLog.CAPABILITY_EXTENSIONS,\n            CapabilitiesLog.AUTOMATA,\n            CapabilitiesLog.TIMESTAMP\n    };\n    // @formatter:on\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(CapabilitiesLog.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the CapabilityLog according to GSMA API specifications.<br>\n     * Check the query operations\n     */\n    public void testCapabilitiesLogQuery() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            String where = CapabilitiesLog.CONTACT.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"+339000000\"\n            };\n            cursor = mProvider.query(CapabilitiesLog.CONTENT_URI, CAPABILITIES_LOG_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testCapabilitiesLogQueryById() throws RemoteException {\n        // Check that provider handles columns names and query operation by ID\n        Uri uri = Uri.withAppendedPath(CapabilitiesLog.CONTENT_URI, \"+33612345678\");\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, CAPABILITIES_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testCapabilitiesLogQueryWithoutWhereClause() throws RemoteException {\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(CapabilitiesLog.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(CAPABILITIES_LOG_PROJECTION, cursor.getColumnNames());\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testCapabilitiesLogInsert() {\n        // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(CapabilitiesLog.CAPABILITY_EXTENSIONS, \"extension1;extension2\");\n        values.put(CapabilitiesLog.CAPABILITY_FILE_TRANSFER, CapabilitiesLog.NOT_SUPPORTED);\n        values.put(CapabilitiesLog.CAPABILITY_GEOLOC_PUSH, CapabilitiesLog.NOT_SUPPORTED);\n        values.put(CapabilitiesLog.CAPABILITY_IM_SESSION, CapabilitiesLog.NOT_SUPPORTED);\n        values.put(CapabilitiesLog.CAPABILITY_IMAGE_SHARE, CapabilitiesLog.NOT_SUPPORTED);\n        values.put(CapabilitiesLog.CAPABILITY_VIDEO_SHARE, CapabilitiesLog.NOT_SUPPORTED);\n        values.put(CapabilitiesLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(CapabilitiesLog.CONTACT, \"+33612345678\");\n        values.put(CapabilitiesLog.AUTOMATA, CapabilitiesLog.NOT_SUPPORTED);\n        try {\n            mProvider.insert(CapabilitiesLog.CONTENT_URI, values);\n            fail(\"CapabilitiesLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into CapabilitiesLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testCapabilitiesLogDelete() {\n        // Check that provider does not support delete operation\n        try {\n            mProvider.delete(CapabilitiesLog.CONTENT_URI, null, null);\n            fail(\"CapabilitiesLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"delete from CapabilitiesLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testCapabilitiesLogUpdate() {\n        // Check that provider does not support update operation\n        ContentValues values = new ContentValues();\n        values.put(CapabilitiesLog.TIMESTAMP, System.currentTimeMillis());\n        try {\n            String where = CapabilitiesLog.CONTACT.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"+339000000\"\n            };\n            mProvider.update(CapabilitiesLog.CONTENT_URI, values, where, whereArgs);\n            fail(\"CapabilitiesLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of CapabilitiesLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/ChatLogGroupChatTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.chat.GroupChat;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\npublic class ChatLogGroupChatTest extends InstrumentationTestCase {\n\n    // @formatter:off\n    private final String[] CHAT_LOG_GROUPCHAT_PROJECTION = new String[] {\n            ChatLog.GroupChat.BASECOLUMN_ID, ChatLog.GroupChat.CHAT_ID, ChatLog.GroupChat.CONTACT,\n            ChatLog.GroupChat.DIRECTION, ChatLog.GroupChat.PARTICIPANTS,\n            ChatLog.GroupChat.REASON_CODE, ChatLog.GroupChat.STATE, ChatLog.GroupChat.SUBJECT,\n            ChatLog.GroupChat.TIMESTAMP\n    };\n    // @formatter:on\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(ChatLog.GroupChat.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the ChatLog.GroupChat provider according to GSMA API specifications.<br>\n     * Check the following operations:\n     * <ul>\n     * <li>query\n     * <li>insert\n     * <li>delete\n     * <li>update\n     */\n    public void testChatLogGroupQuery() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            String where = ChatLog.GroupChat.CHAT_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            cursor = mProvider.query(ChatLog.GroupChat.CONTENT_URI, CHAT_LOG_GROUPCHAT_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testChatLogGroupQueryById() throws RemoteException {\n        Uri uri = Uri.withAppendedPath(ChatLog.GroupChat.CONTENT_URI, \"123456789\");\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, CHAT_LOG_GROUPCHAT_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testChatLogGroupQueryWithoutWhereClause() throws RemoteException {\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(ChatLog.GroupChat.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(CHAT_LOG_GROUPCHAT_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testChatLogGroupInsert() {\n        // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(ChatLog.GroupChat.CHAT_ID, \"123456789\");\n        values.put(ChatLog.GroupChat.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(ChatLog.GroupChat.STATE, GroupChat.State.INVITED.toString());\n        values.put(ChatLog.GroupChat.SUBJECT, \"subject\");\n        values.put(ChatLog.GroupChat.TIMESTAMP, System.currentTimeMillis());\n        values.put(ChatLog.GroupChat.CONTACT, \"+33612345678\");\n        values.put(ChatLog.GroupChat.PARTICIPANTS, \"participant1,participant2\");\n        values.put(ChatLog.GroupChat.REASON_CODE, GroupChat.ReasonCode.UNSPECIFIED.toInt());\n        try {\n            mProvider.insert(ChatLog.GroupChat.CONTENT_URI, values);\n            fail(\"ChatLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into ChatLog.GroupChat should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testChatLogGroupDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(ChatLog.GroupChat.CONTENT_URI, null, null);\n            fail(\"ChatLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"delete of ChatLog.GroupChat should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testChatLogGroupUpdate() {\n        ContentValues values = new ContentValues();\n        values.put(ChatLog.GroupChat.TIMESTAMP, System.currentTimeMillis());\n        // Check that provider does not support update operation\n        try {\n            String where = ChatLog.GroupChat.CHAT_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            mProvider.update(ChatLog.GroupChat.CONTENT_URI, values, where, whereArgs);\n            fail(\"ChatLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of ChatLog.GroupChat should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/ChatLogMessageTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.chat.ChatLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.test.InstrumentationTestCase;\n\npublic class ChatLogMessageTest extends InstrumentationTestCase {\n\n    private static final String[] CHAT_LOG_MESSAGE_PROJECTION = new String[] {\n            ChatLog.Message.BASECOLUMN_ID, ChatLog.Message.CHAT_ID, ChatLog.Message.CONTENT,\n            ChatLog.Message.CONTACT, ChatLog.Message.DIRECTION, ChatLog.Message.READ_STATUS,\n            ChatLog.Message.MESSAGE_ID, ChatLog.Message.MIME_TYPE, ChatLog.Message.TIMESTAMP,\n            ChatLog.Message.REASON_CODE, ChatLog.Message.STATUS, ChatLog.Message.TIMESTAMP_SENT,\n            ChatLog.Message.TIMESTAMP_DELIVERED, ChatLog.Message.TIMESTAMP_DISPLAYED,\n            ChatLog.Message.EXPIRED_DELIVERY\n    };\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(ChatLog.Message.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the ChatLog.Message according to GSMA API specifications.<br>\n     * Check the following operations:\n     * <ul>\n     * <li>query\n     * <li>insert\n     * <li>delete\n     * <li>update\n     */\n\n    public void testChatLogMessageQuery() {\n        // Check that provider handles columns names and query operation with where arguments\n        Cursor cursor = null;\n        try {\n            String where = ChatLog.Message.CHAT_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            cursor = mProvider.query(ChatLog.Message.CONTENT_URI, CHAT_LOG_MESSAGE_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n        } catch (Exception e) {\n            fail(\"query of ChatLog.Message failed \" + e.getMessage());\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testChatLogMessageQueryById() {\n        // Check that provider handles columns names and query operation by ID\n        Uri uri = Uri.withAppendedPath(ChatLog.Message.CONTENT_URI, \"123456789\");\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, CHAT_LOG_MESSAGE_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n        } catch (Exception e) {\n            fail(\"By Id query of ChatLog.Message failed \" + e.getMessage());\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testChatLogMessageQueryWithoutWhereClause() {\n        // Check that provider handles columns names and query operation without where clause\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(ChatLog.Message.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            if (cursor.moveToFirst()) {\n                Utils.checkProjection(CHAT_LOG_MESSAGE_PROJECTION, cursor.getColumnNames());\n            }\n        } catch (Exception e) {\n            fail(\"Without where clause query of ChatLog.Message failed \" + e.getMessage());\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testChatLogMessageInsert() {\n        // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(ChatLog.Message.CHAT_ID, \"0123456789\");\n        values.put(ChatLog.Message.CONTENT, \"body\");\n        values.put(ChatLog.Message.CONTACT, \"+3360102030405\");\n        values.put(ChatLog.Message.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(ChatLog.Message.READ_STATUS, RcsService.ReadStatus.UNREAD.toInt());\n        values.put(ChatLog.Message.MESSAGE_ID, \"012345789\");\n        values.put(ChatLog.Message.MIME_TYPE, ChatLog.Message.MimeType.TEXT_MESSAGE);\n        values.put(ChatLog.Message.STATUS, ChatLog.Message.Content.Status.RECEIVED.toInt());\n        values.put(ChatLog.Message.REASON_CODE,\n                ChatLog.Message.Content.ReasonCode.UNSPECIFIED.toInt());\n        values.put(ChatLog.Message.TIMESTAMP, System.currentTimeMillis());\n        values.put(ChatLog.Message.TIMESTAMP_DELIVERED, 0);\n        values.put(ChatLog.Message.TIMESTAMP_DISPLAYED, 0);\n        values.put(ChatLog.Message.TIMESTAMP_SENT, 0);\n        try {\n            mProvider.insert(ChatLog.Message.CONTENT_URI, values);\n            fail(\"ChatLog is read only\");\n        } catch (Exception ex) {\n            assertTrue(\"insert into ChatLog.Message should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testChatLogMessageDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(ChatLog.Message.CONTENT_URI, null, null);\n            fail(\"ChatLog is read only\");\n        } catch (Exception ex) {\n            assertTrue(\"delete of ChatLog.Message should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testChatLogMessageUpdate() {\n        ContentValues values = new ContentValues();\n        values.put(ChatLog.Message.TIMESTAMP, System.currentTimeMillis());\n        // Check that provider does not support update operation\n        try {\n            String where = ChatLog.Message.MESSAGE_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            mProvider.update(ChatLog.Message.CONTENT_URI, values, where, whereArgs);\n            fail(\"ChatLog is read only\");\n        } catch (Exception ex) {\n            assertTrue(\"Updating a ChatLog.Message should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/FileTransferLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\npublic class FileTransferLogTest extends InstrumentationTestCase {\n\n    // @formatter:off\n    private final String[] FILE_TRANSFER_LOG_PROJECTION = new String[] {\n            FileTransferLog.BASECOLUMN_ID, \n            FileTransferLog.FT_ID, \n            FileTransferLog.CHAT_ID,\n            FileTransferLog.CONTACT, \n            FileTransferLog.FILE, \n            FileTransferLog.FILENAME,\n            FileTransferLog.MIME_TYPE, \n            FileTransferLog.FILEICON,\n            FileTransferLog.FILEICON_MIME_TYPE, \n            FileTransferLog.DIRECTION,\n            FileTransferLog.FILESIZE,\n            FileTransferLog.TRANSFERRED, \n            FileTransferLog.TIMESTAMP,\n            FileTransferLog.TIMESTAMP_SENT, \n            FileTransferLog.TIMESTAMP_DELIVERED,\n            FileTransferLog.TIMESTAMP_DISPLAYED, \n            FileTransferLog.STATE,\n            FileTransferLog.REASON_CODE, \n            FileTransferLog.READ_STATUS,\n            FileTransferLog.FILE_EXPIRATION, \n            FileTransferLog.FILEICON_EXPIRATION,\n            FileTransferLog.EXPIRED_DELIVERY,\n            FileTransferLog.DISPOSITION\n    };\n    // @formatter:on\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(FileTransferLog.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the FileTransferLog according to GSMA API specifications.<br>\n     * Check the following operations:\n     * <ul>\n     * <li>query\n     * <li>insert\n     * <li>delete\n     * <li>update\n     */\n    public void testFileTransferLogQuery() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            String where = FileTransferLog.FT_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"0123456789\"\n            };\n            cursor = mProvider.query(FileTransferLog.CONTENT_URI, FILE_TRANSFER_LOG_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testFileTransferLogQueryById() throws RemoteException {\n        // Check that provider handles columns names and query operation by ID\n        Uri uri = Uri.withAppendedPath(FileTransferLog.CONTENT_URI, \"0123456789\");\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, FILE_TRANSFER_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testFileTransferLogQueryWithoutWhereClause() throws RemoteException {\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(FileTransferLog.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(FILE_TRANSFER_LOG_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testFileTransferLogInsert() {\n        // // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(FileTransferLog.FILESIZE, 10000);\n        values.put(FileTransferLog.FILE, \"uri\");\n        values.put(FileTransferLog.FILENAME, \"filename\");\n        values.put(FileTransferLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(FileTransferLog.FT_ID, \"0123456789\");\n        values.put(FileTransferLog.MIME_TYPE, \"image/jpeg\");\n        values.put(FileTransferLog.STATE, FileTransfer.State.INVITED.toInt());\n        values.put(FileTransferLog.REASON_CODE, FileTransfer.ReasonCode.UNSPECIFIED.toInt());\n        values.put(FileTransferLog.READ_STATUS, RcsService.ReadStatus.UNREAD.toInt());\n        values.put(FileTransferLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(FileTransferLog.TIMESTAMP_DELIVERED, 0);\n        values.put(FileTransferLog.TIMESTAMP_SENT, 0);\n        values.put(FileTransferLog.TIMESTAMP_DISPLAYED, 0);\n        values.put(FileTransferLog.TRANSFERRED, 0);\n        values.put(FileTransferLog.CHAT_ID, \"0102030405\");\n\n        try {\n            mProvider.insert(FileTransferLog.CONTENT_URI, values);\n            fail(\"FileTransferLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into FileTransferLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testFileTransferLogDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(FileTransferLog.CONTENT_URI, null, null);\n            fail(\"FileTransferLog is read only\");\n        } catch (Exception e) {\n            assertTrue(\"delete of FileTransferLog should be forbidden\",\n                    e instanceof RuntimeException);\n        }\n    }\n\n    public void testFileTransferLogUpdate() {\n        ContentValues values = new ContentValues();\n        values.put(FileTransferLog.FILESIZE, 10000L);\n        values.put(FileTransferLog.FILENAME, \"filename\");\n        values.put(FileTransferLog.CONTACT, \"+3360102030405\");\n        values.put(FileTransferLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(FileTransferLog.FT_ID, \"ft_id\");\n        values.put(FileTransferLog.MIME_TYPE, \"image/jpeg\");\n        values.put(FileTransferLog.STATE, FileTransfer.State.INVITED.toInt());\n        values.put(FileTransferLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(FileTransferLog.TRANSFERRED, 0L);\n        // Check that provider does not support update operation\n        try {\n            String where = FileTransferLog.FT_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"0123456789\"\n            };\n            mProvider.update(FileTransferLog.CONTENT_URI, values, where, whereArgs);\n            fail(\"FileTransferLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of FileTransferLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/GeolocSharingLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.chat.ChatLog.Message.MimeType;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharing;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\npublic class GeolocSharingLogTest extends InstrumentationTestCase {\n\n    // @formatter:off\n    private final String[] GEOLOC_SHARING_LOG_PROJECTION = new String[] {\n            GeolocSharingLog.BASECOLUMN_ID, \n            GeolocSharingLog.CONTACT, \n            GeolocSharingLog.DIRECTION,\n            GeolocSharingLog.CONTENT, \n            GeolocSharingLog.SHARING_ID, \n            GeolocSharingLog.MIME_TYPE,\n            GeolocSharingLog.STATE, \n            GeolocSharingLog.REASON_CODE, \n            GeolocSharingLog.TIMESTAMP\n    };\n    // @formatter:on\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(GeolocSharingLog.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the GeolocSharingLog provider according to GSMA API specifications.<br>\n     * Check the following operations:\n     * <ul>\n     * <li>query\n     * <li>insert\n     * <li>delete\n     * <li>update\n     */\n    public void testGeolocSharingLogQuery() throws RemoteException {\n        /* Check that provider handles columns names and query operation */\n        Cursor cursor = null;\n        try {\n            String where = GeolocSharingLog.SHARING_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            cursor = mProvider.query(GeolocSharingLog.CONTENT_URI, GEOLOC_SHARING_LOG_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGeolocSharingLogQueryById() throws RemoteException {\n        /* Check that provider handles columns names and query operation */\n        Uri uri = Uri.withAppendedPath(GeolocSharingLog.CONTENT_URI, \"123456789\");\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, GEOLOC_SHARING_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGeolocSharingLogQueryWithoutWhereClause() throws RemoteException {\n        /* Check that provider handles columns names and query operation */\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(GeolocSharingLog.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(GEOLOC_SHARING_LOG_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGeolocSharingLogInsert() {\n        /* Check that provider does not support insert operation */\n        ContentValues values = new ContentValues();\n        values.put(GeolocSharingLog.CONTENT, \"content\");\n        values.put(GeolocSharingLog.CONTACT, \"+3360102030405\");\n        values.put(GeolocSharingLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(GeolocSharingLog.SHARING_ID, \"0123456789\");\n        values.put(GeolocSharingLog.MIME_TYPE, MimeType.GEOLOC_MESSAGE);\n        values.put(GeolocSharingLog.STATE, GeolocSharing.State.INVITED.toInt());\n        values.put(GeolocSharingLog.REASON_CODE, GeolocSharing.ReasonCode.UNSPECIFIED.toInt());\n        values.put(GeolocSharingLog.TIMESTAMP, System.currentTimeMillis());\n        try {\n            mProvider.insert(GeolocSharingLog.CONTENT_URI, values);\n            fail(\"GeolocSharingLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into GeolocSharingLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testGeolocSharingLogDelete() {\n        /* Check that provider supports delete operation */\n        try {\n            mProvider.delete(GeolocSharingLog.CONTENT_URI, null, null);\n            fail(\"GeolocSharingLog is read only\");\n\n        } catch (Exception e) {\n            assertTrue(\"delete of GeolocSharingLog should be forbidden\",\n                    e instanceof RuntimeException);\n        }\n    }\n\n    public void testGeolocSharingLogUpdate() {\n        /* Check that provider does not support update operation */\n        ContentValues values = new ContentValues();\n        values.put(GeolocSharingLog.CONTENT, \"content\");\n        values.put(GeolocSharingLog.CONTACT, \"+3360102030405\");\n        values.put(GeolocSharingLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(GeolocSharingLog.MIME_TYPE, MimeType.GEOLOC_MESSAGE);\n        values.put(GeolocSharingLog.STATE, GeolocSharing.State.INVITED.toInt());\n        values.put(GeolocSharingLog.REASON_CODE, GeolocSharing.ReasonCode.FAILED_SHARING.toInt());\n        values.put(GeolocSharingLog.TIMESTAMP, System.currentTimeMillis());\n        try {\n            String where = GeolocSharingLog.SHARING_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            mProvider.update(GeolocSharingLog.CONTENT_URI, values, where, whereArgs);\n            fail(\"GeolocSharingLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of GeolocSharingLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/GroupDeliveryInfoLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo;\nimport com.gsma.services.rcs.groupdelivery.GroupDeliveryInfoLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\n/**\n * @author Danielle Rouquier\n */\npublic class GroupDeliveryInfoLogTest extends InstrumentationTestCase {\n\n    private ContentProviderClient mProvider;\n\n    // @formatter:off\n    private static final String[] GROUPDELIVERYINFO_LOG_PROJECTION = new String[] {\n            GroupDeliveryInfoLog.BASECOLUMN_ID, \n            GroupDeliveryInfoLog.ID,\n            GroupDeliveryInfoLog.CONTACT, \n            GroupDeliveryInfoLog.CHAT_ID,\n            GroupDeliveryInfoLog.REASON_CODE, \n            GroupDeliveryInfoLog.STATUS,\n            GroupDeliveryInfoLog.TIMESTAMP_DELIVERED, \n            GroupDeliveryInfoLog.TIMESTAMP_DISPLAYED\n    };\n    // @formatter:on\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(GroupDeliveryInfoLog.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the GroupDeliveryInfoLog according to GSMA API specifications.<br>\n     * Check the query operations\n     */\n    public void testGroupDeliveryInfoLogQuery() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            String where = GroupDeliveryInfoLog.CONTACT.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"+33123456789\"\n            };\n            cursor = mProvider.query(GroupDeliveryInfoLog.CONTENT_URI,\n                    GROUPDELIVERYINFO_LOG_PROJECTION, where, whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGroupDeliveryInfoLogQueryById() throws RemoteException {\n        // Check that provider handles columns names and query operation by ID\n        Uri uri = Uri.withAppendedPath(GroupDeliveryInfoLog.CONTENT_URI, \"123456789\");\n        Cursor cursor = null;\n        try {\n            assertNotNull(mProvider);\n            cursor = mProvider.query(uri, GROUPDELIVERYINFO_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGroupDeliveryInfoLogWithoutWhereClaused() throws RemoteException {\n        // Check that provider handles columns names and query operation where clause is null\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(GroupDeliveryInfoLog.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(GROUPDELIVERYINFO_LOG_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testGroupDeliveryInfoLogInsert() {\n        // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(GroupDeliveryInfoLog.ID, \"delivinfo_id\");\n        values.put(GroupDeliveryInfoLog.CHAT_ID, \"chat_id\");\n        values.put(GroupDeliveryInfoLog.CONTACT, \"+3360102030405\");\n        values.put(GroupDeliveryInfoLog.REASON_CODE,\n                GroupDeliveryInfo.ReasonCode.UNSPECIFIED.toInt());\n        values.put(GroupDeliveryInfoLog.STATUS, GroupDeliveryInfo.Status.DELIVERED.toInt());\n        values.put(GroupDeliveryInfoLog.TIMESTAMP_DELIVERED, 0);\n        values.put(GroupDeliveryInfoLog.TIMESTAMP_DISPLAYED, 0);\n        try {\n            mProvider.insert(GroupDeliveryInfoLog.CONTENT_URI, values);\n            fail(\"GroupDeliveryInfoLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into GroupDeliveryInfoLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n\n    }\n\n    public void testGroupDeliveryInfoLogDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(GroupDeliveryInfoLog.CONTENT_URI, null, null);\n            fail(\"GroupDeliveryInfoLog is read only\");\n\n        } catch (Exception e) {\n            assertTrue(\"delete of GroupDeliveryInfoLog should be forbidden\",\n                    e instanceof RuntimeException);\n        }\n    }\n\n    public void testGroupDeliveryInfoLogUpdate() {\n        ContentValues values = new ContentValues();\n        values.put(GroupDeliveryInfoLog.TIMESTAMP_DELIVERED, 0);\n        // Check that provider does not support update operation\n        try {\n            String where = GroupDeliveryInfoLog.ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            mProvider.update(GroupDeliveryInfoLog.CONTENT_URI, values, where, whereArgs);\n            fail(\"ChatLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"Updating a GroupDeliveryInfoLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/HistoryLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n * <p/>\n * Copyright (C) 2010-2016 Orange.\n * <p/>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p/>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p/>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.chat.ChatLog;\nimport com.gsma.services.rcs.filetransfer.FileTransfer;\nimport com.gsma.services.rcs.filetransfer.FileTransferLog;\nimport com.gsma.services.rcs.history.HistoryLog;\nimport com.gsma.services.rcs.history.HistoryUriBuilder;\nimport com.gsma.services.rcs.sharing.geoloc.GeolocSharingLog;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\n\n/**\n * Created by sandrine on 31/03/2016.\n */\npublic class HistoryLogTest extends InstrumentationTestCase {\n    private ContentProviderClient mProvider;\n\n    // @formatter:off\n    private final String[] HISTORY_LOG_PROJECTION = new String[]{\n            HistoryLog.BASECOLUMN_ID,\n            HistoryLog.CHAT_ID,\n            HistoryLog.CONTACT,\n            HistoryLog.CONTENT,\n            HistoryLog.DIRECTION,\n            HistoryLog.DISPOSITION,\n            HistoryLog.DURATION,\n            HistoryLog.EXPIRED_DELIVERY,\n            HistoryLog.FILEICON,\n            HistoryLog.FILEICON_MIME_TYPE,\n            HistoryLog.FILESIZE,\n            HistoryLog.FILENAME,\n            HistoryLog.ID,\n            HistoryLog.MIME_TYPE,\n            HistoryLog.READ_STATUS,\n            HistoryLog.REASON_CODE,\n            HistoryLog.STATUS,\n            HistoryLog.PROVIDER_ID,\n            HistoryLog.TRANSFERRED,\n            HistoryLog.TIMESTAMP,\n            HistoryLog.TIMESTAMP_SENT,\n            HistoryLog.TIMESTAMP_DELIVERED,\n            HistoryLog.TIMESTAMP_DISPLAYED};\n    // @formatter:on\n\n    private Uri mUri;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(HistoryLog.CONTENT_URI);\n        assertNotNull(mProvider);\n        mUri = getUriWithAllInternalProviders();\n    }\n\n    private Uri getUriWithAllInternalProviders() {\n        return createHistoryUri(ChatLog.Message.HISTORYLOG_MEMBER_ID,\n                ChatLog.GroupChat.HISTORYLOG_MEMBER_ID, FileTransferLog.HISTORYLOG_MEMBER_ID,\n                VideoSharingLog.HISTORYLOG_MEMBER_ID, ImageSharingLog.HISTORYLOG_MEMBER_ID,\n                GeolocSharingLog.HISTORYLOG_MEMBER_ID);\n    }\n\n    private static Uri createHistoryUri(int... providerIds) {\n        HistoryUriBuilder uriBuilder = new HistoryUriBuilder(HistoryLog.CONTENT_URI);\n\n        for (int providerId : providerIds) {\n            uriBuilder.appendProvider(providerId);\n        }\n\n        return uriBuilder.build();\n    }\n\n    public void testHistoryLogQuery() throws RemoteException {\n        /* Check that provider handles columns names and query operation */\n        Cursor cursor = null;\n        try {\n            String where = HistoryLog.ID.concat(\"=?\");\n            String[] whereArgs = new String[]{\n                    \"123456789\"\n            };\n            cursor = mProvider.query(mUri, HISTORY_LOG_PROJECTION, where,\n                    whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testHistoryLogSharingLogQueryById() throws RemoteException {\n        /* Check that provider handles columns names and query operation */\n        Uri uri = Uri.withAppendedPath(mUri, \"123456789\");\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, HISTORY_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testHistoryLogQueryWithoutWhereClause() throws RemoteException {\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(mUri, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(HISTORY_LOG_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testHistoryLogInsert() {\n        // // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(HistoryLog.FILESIZE, 10000);\n        values.put(HistoryLog.FILENAME, \"filename\");\n        values.put(HistoryLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(HistoryLog.MIME_TYPE, \"image/jpeg\");\n        values.put(HistoryLog.REASON_CODE, FileTransfer.ReasonCode.UNSPECIFIED.toInt());\n        values.put(HistoryLog.READ_STATUS, RcsService.ReadStatus.UNREAD.toInt());\n        values.put(HistoryLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(HistoryLog.TIMESTAMP_DELIVERED, 0);\n        values.put(HistoryLog.TIMESTAMP_SENT, 0);\n        values.put(HistoryLog.TIMESTAMP_DISPLAYED, 0);\n        values.put(HistoryLog.TRANSFERRED, 0);\n        values.put(HistoryLog.CHAT_ID, \"0102030405\");\n\n        try {\n            mProvider.insert(mUri, values);\n            fail(\"HistoryLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into HistoryLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testHistoryLogDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(mUri, null, null);\n            fail(\"HistoryLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"delete of HistoryLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testHistoryLogUpdate() {\n        ContentValues values = new ContentValues();\n        values.put(HistoryLog.TIMESTAMP, System.currentTimeMillis());\n        // Check that provider does not support update operation\n        try {\n            String where = HistoryLog.ID.concat(\"=?\");\n            String[] whereArgs = new String[]{\n                    \"123456789\"\n            };\n            mProvider.update(mUri, values, where, whereArgs);\n            fail(\"HistoryLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of HistoryLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/ImageSharingLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.sharing.image.ImageSharing;\nimport com.gsma.services.rcs.sharing.image.ImageSharingLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\npublic class ImageSharingLogTest extends InstrumentationTestCase {\n\n    // @formatter:off\n    private final String[] IMAGE_SHARING_LOG_PROJECTION = new String[] {\n            ImageSharingLog.BASECOLUMN_ID, \n            ImageSharingLog.CONTACT, \n            ImageSharingLog.DIRECTION,\n            ImageSharingLog.FILE, \n            ImageSharingLog.FILENAME, \n            ImageSharingLog.FILESIZE,\n            ImageSharingLog.SHARING_ID, \n            ImageSharingLog.MIME_TYPE, \n            ImageSharingLog.STATE,\n            ImageSharingLog.REASON_CODE, \n            ImageSharingLog.TIMESTAMP, \n            ImageSharingLog.TRANSFERRED\n    };\n    // @formatter:on\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(ImageSharingLog.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the ImageSharingLog provider according to GSMA API specifications.<br>\n     * Check the following operations:\n     * <ul>\n     * <li>query\n     * <li>insert\n     * <li>delete\n     * <li>update\n     */\n    public void testImageSharingLogQuery() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            String where = ImageSharingLog.SHARING_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            cursor = mProvider.query(ImageSharingLog.CONTENT_URI, IMAGE_SHARING_LOG_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testImageSharingLogQueryById() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Uri uri = Uri.withAppendedPath(ImageSharingLog.CONTENT_URI, \"123456789\");\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, IMAGE_SHARING_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testImageSharingLogQueryWithoutWhereClause() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(ImageSharingLog.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(IMAGE_SHARING_LOG_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testImageSharingLogInsert() {\n        // // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(ImageSharingLog.FILESIZE, 10000L);\n        values.put(ImageSharingLog.FILENAME, \"filename\");\n        values.put(ImageSharingLog.CONTACT, \"+3360102030405\");\n        values.put(ImageSharingLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(ImageSharingLog.SHARING_ID, \"0123456789\");\n        values.put(ImageSharingLog.MIME_TYPE, \"image/jpeg\");\n        values.put(ImageSharingLog.STATE, ImageSharing.State.INVITED.toInt());\n        values.put(ImageSharingLog.REASON_CODE, ImageSharing.ReasonCode.UNSPECIFIED.toInt());\n        values.put(ImageSharingLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(ImageSharingLog.TRANSFERRED, 0L);\n        try {\n            mProvider.insert(ImageSharingLog.CONTENT_URI, values);\n            fail(\"ImageSharingLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into ImageSharingLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testImageSharingLogDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(ImageSharingLog.CONTENT_URI, null, null);\n            fail(\"ImageSharingLog is read only\");\n\n        } catch (Exception e) {\n            assertTrue(\"delete of ImageSharingLog should be forbidden\",\n                    e instanceof RuntimeException);\n        }\n    }\n\n    public void testImageSharingLogUpdate() {\n        // Check that provider does not support update operation\n        ContentValues values = new ContentValues();\n        values.put(ImageSharingLog.FILESIZE, 10000L);\n        values.put(ImageSharingLog.FILENAME, \"filename\");\n        values.put(ImageSharingLog.CONTACT, \"+3360102030405\");\n        values.put(ImageSharingLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(ImageSharingLog.MIME_TYPE, \"image/jpeg\");\n        values.put(ImageSharingLog.STATE, ImageSharing.State.INVITED.toInt());\n        values.put(ImageSharingLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(ImageSharingLog.TRANSFERRED, 0L);\n        try {\n            String where = ImageSharingLog.SHARING_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            mProvider.update(ImageSharingLog.CONTENT_URI, values, where, whereArgs);\n            fail(\"ImageSharingLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of ImageSharingLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/Utils.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport android.test.InstrumentationTestCase;\n\npublic class Utils extends InstrumentationTestCase {\n\n    public static void checkProjection(String[] expected, String[] obtained) {\n        if (expected != null) {\n            if (obtained == null) {\n                fail(\"projection is null\");\n            }\n            assertEquals(expected.length, obtained.length);\n            for (String field1 : expected) {\n                boolean found = false;\n                for (String field2 : obtained) {\n                    if (field1.equals(field2)) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    fail(\"field is not present: \".concat(field1));\n                }\n            }\n        } else {\n            if (obtained != null) {\n                fail(\"invalid Projection\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cts/provider/src/androidTest/java/android/tests/provider/VideoSharingLogTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.provider;\n\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.sharing.video.VideoSharing;\nimport com.gsma.services.rcs.sharing.video.VideoSharingLog;\n\nimport android.content.ContentProviderClient;\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.test.InstrumentationTestCase;\n\npublic class VideoSharingLogTest extends InstrumentationTestCase {\n\n    // @formatter:off\n    private final String[] VIDEO_SHARING_LOG_PROJECTION = new String[] {\n            VideoSharingLog.BASECOLUMN_ID, \n            VideoSharingLog.CONTACT, \n            VideoSharingLog.DIRECTION,\n            VideoSharingLog.DURATION, \n            VideoSharingLog.HEIGHT, \n            VideoSharingLog.REASON_CODE,\n            VideoSharingLog.SHARING_ID, \n            VideoSharingLog.STATE, \n            VideoSharingLog.TIMESTAMP,\n            VideoSharingLog.VIDEO_ENCODING, \n            VideoSharingLog.WIDTH\n    };\n    // @formatter:on\n\n    private ContentProviderClient mProvider;\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mProvider = getInstrumentation().getTargetContext().getContentResolver()\n                .acquireContentProviderClient(VideoSharingLog.CONTENT_URI);\n        assertNotNull(mProvider);\n    }\n\n    /**\n     * Test the VideoSharingLog provider according to GSMA API specifications.<br>\n     * Check the following operations:\n     * <ul>\n     * <li>query\n     * <li>insert\n     * <li>delete\n     * <li>update\n     */\n    public void testVideoSharingLogQuery() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Cursor cursor = null;\n        try {\n            String where = VideoSharingLog.SHARING_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            cursor = mProvider.query(VideoSharingLog.CONTENT_URI, VIDEO_SHARING_LOG_PROJECTION,\n                    where, whereArgs, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testVideoSharingLogQueryById() throws RemoteException {\n        // Check that provider handles columns names and query operation\n        Uri uri = Uri.withAppendedPath(VideoSharingLog.CONTENT_URI, \"123456789\");\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(uri, VIDEO_SHARING_LOG_PROJECTION, null, null, null);\n            assertNotNull(cursor);\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testVideoSharingLogQueryWithoutWhereClause() throws RemoteException {\n        Cursor cursor = null;\n        try {\n            cursor = mProvider.query(VideoSharingLog.CONTENT_URI, null, null, null, null);\n            assertNotNull(cursor);\n            Utils.checkProjection(VIDEO_SHARING_LOG_PROJECTION, cursor.getColumnNames());\n\n        } finally {\n            if (cursor != null) {\n                cursor.close();\n            }\n        }\n    }\n\n    public void testVideoSharingLogInsert() {\n        // // Check that provider does not support insert operation\n        ContentValues values = new ContentValues();\n        values.put(VideoSharingLog.CONTACT, \"+3360102030405\");\n        values.put(VideoSharingLog.DIRECTION, RcsService.Direction.INCOMING.toInt());\n        values.put(VideoSharingLog.SHARING_ID, \"123456789\");\n        values.put(VideoSharingLog.STATE, VideoSharing.State.INVITED.toInt());\n        values.put(VideoSharingLog.TIMESTAMP, System.currentTimeMillis());\n        values.put(VideoSharingLog.DURATION, 60);\n        values.put(VideoSharingLog.HEIGHT, 10);\n        values.put(VideoSharingLog.REASON_CODE, VideoSharing.ReasonCode.UNSPECIFIED.toInt());\n        values.put(VideoSharingLog.VIDEO_ENCODING, VideoSharing.Encoding.H264);\n        values.put(VideoSharingLog.WIDTH, 0);\n        try {\n            mProvider.insert(VideoSharingLog.CONTENT_URI, values);\n            fail(\"VideoSharingLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"insert into VideoSharingLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n    public void testVideoSharingLogDelete() {\n        // Check that provider supports delete operation\n        try {\n            mProvider.delete(VideoSharingLog.CONTENT_URI, null, null);\n            fail(\"VideoSharingLog is read only\");\n\n        } catch (Exception e) {\n            assertTrue(\"delete of VideoSharingLog should be forbidden\",\n                    e instanceof RuntimeException);\n        }\n    }\n\n    public void testVideoSharingLogUpdate() {\n        ContentValues values = new ContentValues();\n        values.put(VideoSharingLog.TIMESTAMP, System.currentTimeMillis());\n        // Check that provider does not support update operation\n        try {\n            String where = VideoSharingLog.SHARING_ID.concat(\"=?\");\n            String[] whereArgs = new String[] {\n                \"123456789\"\n            };\n            mProvider.update(VideoSharingLog.CONTENT_URI, values, where, whereArgs);\n            fail(\"VideoSharingLog is read only\");\n\n        } catch (Exception ex) {\n            assertTrue(\"update of VideoSharingLog should be forbidden\",\n                    ex instanceof RuntimeException);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tests/cts/provider/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"android.tests.provider\">\n\n    <uses-permission android:name=\"android.permission.RUN_INSTRUMENTATION\" />\n\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\" />\n\n    <application\n        android:label=\"@string/app_name\">\n        <uses-library android:name=\"android.test.runner\" />\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "tests/cts/provider/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">RcsApiProviderTest</string>\n\n</resources>\n"
  },
  {
    "path": "tests/cts/run-test",
    "content": "cd ../../\n./gradlew :cts_provider:cAT\necho \"See Android Test Results under: ./provider/build/reports/androidTests/connected/index.html\"\n./gradlew :cts_signature:cAT\necho \"See Android Test Results under: ./signature/build/reports/androidTests/connected/index.html\"\n\n\n\n"
  },
  {
    "path": "tests/cts/signature/README.md",
    "content": "# The Compatibility Test Suite for RCS API\n\nThis application checks the compatibility of a given RCS API with the different existing releases.\n\nBuild instruction:\n\n- create a 'libs' directory and copy in this new directory the jar file named rcs_api.jar and corresponding to the RCS API library to be tested.\n- edit the `ToTest` java class to set the `VERSION` with the reference of the RCS API XML file\n- run on the device\n<code>../../gradlew :cts_signature:installDebug</code>\n\n\n"
  },
  {
    "path": "tests/cts/signature/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\t\n    defaultConfig {\n        applicationId \"android.tests.sigtest\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n}\n\ndependencies {\n    // Testing-only dependencies\n    androidTestCompile 'com.android.support.test:runner:0.4.1'\n    androidTestCompile 'com.android.support.test:rules:0.4.1'\n\t\n\tcompile files('libs/rcs_api.jar')\n}"
  },
  {
    "path": "tests/cts/signature/src/androidTest/java/android/tests/sigtest/RcsApiSignatureTest.java",
    "content": "/*\n * Copyright (C) 2011 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.tests.sigtest;\n\nimport android.content.res.Resources;\nimport android.test.AndroidTestCase;\nimport android.tests.sigtest.JDiffClassDescription.JDiffConstructor;\nimport android.tests.sigtest.JDiffClassDescription.JDiffField;\nimport android.tests.sigtest.JDiffClassDescription.JDiffMethod;\nimport android.tests.sigtest.SignatureTestActivity.FAILURE_TYPE;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.HashSet;\n\n/**\n * A simpler version of {@link SignatureTest} that performs the signature check via a JUnit test.\n * <p/>\n * Eventually the existing {@link SignatureTest} and {@link SignatureTestActivity} will be deleted\n * once the move to a tradefederation based CTS harness is complete.\n */\npublic class RcsApiSignatureTest extends AndroidTestCase {\n\n    private static final String TAG_ROOT = \"api\";\n    private static final String TAG_PACKAGE = \"package\";\n    private static final String TAG_CLASS = \"class\";\n    private static final String TAG_INTERFACE = \"interface\";\n    private static final String TAG_IMPLEMENTS = \"implements\";\n    private static final String TAG_CONSTRUCTOR = \"constructor\";\n    private static final String TAG_METHOD = \"method\";\n    private static final String TAG_PARAM = \"parameter\";\n    private static final String TAG_EXCEPTION = \"exception\";\n    private static final String TAG_FIELD = \"field\";\n\n    private static final String MODIFIER_ABSTRACT = \"abstract\";\n    private static final String MODIFIER_FINAL = \"final\";\n    private static final String MODIFIER_NATIVE = \"native\";\n    private static final String MODIFIER_PRIVATE = \"private\";\n    private static final String MODIFIER_PROTECTED = \"protected\";\n    private static final String MODIFIER_PUBLIC = \"public\";\n    private static final String MODIFIER_STATIC = \"static\";\n    private static final String MODIFIER_SYNCHRONIZED = \"synchronized\";\n    private static final String MODIFIER_TRANSIENT = \"transient\";\n    private static final String MODIFIER_VOLATILE = \"volatile\";\n    private static final String MODIFIER_VISIBILITY = \"visibility\";\n\n    private static final String ATTRIBUTE_NAME = \"name\";\n    private static final String ATTRIBUTE_EXTENDS = \"extends\";\n    private static final String ATTRIBUTE_TYPE = \"type\";\n    private static final String ATTRIBUTE_RETURN = \"return\";\n\n    private HashSet<String> mKeyTagSet;\n    private TestResultObserver mResultObserver;\n\n    private class TestResultObserver implements ResultObserver {\n        boolean mDidFail = false;\n        StringBuilder mErrorString = new StringBuilder();\n\n        public void notifyFailure(FAILURE_TYPE type, String name, String errorMessage) {\n            mDidFail = true;\n            mErrorString.append(\"\\n\");\n            mErrorString.append(type.toString().toLowerCase());\n            mErrorString.append(\":\\t\");\n            mErrorString.append(name);\n        }\n    }\n\n    @Override\n    protected void setUp() throws Exception {\n        super.setUp();\n        mKeyTagSet = new HashSet<>();\n        mKeyTagSet.addAll(Arrays.asList(TAG_PACKAGE, TAG_CLASS, TAG_INTERFACE, TAG_IMPLEMENTS,\n                TAG_CONSTRUCTOR, TAG_METHOD, TAG_PARAM, TAG_EXCEPTION, TAG_FIELD));\n        mResultObserver = new TestResultObserver();\n    }\n\n    /**\n     * Tests that the device's API matches the expected set defined in xml.\n     * <p/>\n     * Will check the entire API, and then report the complete list of failures\n     */\n    public void testSignature() {\n        Resources r = getContext().getResources();\n        try {\n            start(r.getXml(ToTest.VERSION));\n        } catch (Exception e) {\n            mResultObserver.notifyFailure(FAILURE_TYPE.CAUGHT_EXCEPTION, e.getMessage(),\n                    e.getMessage());\n        }\n        if (mResultObserver.mDidFail) {\n            fail(mResultObserver.mErrorString.toString());\n        }\n    }\n\n    private void beginDocument(XmlPullParser parser, String firstElementName)\n            throws XmlPullParserException, IOException {\n        int type;\n        while ((type = parser.next()) != XmlPullParser.START_TAG\n                && type != XmlPullParser.END_DOCUMENT) {\n        }\n\n        if (type != XmlPullParser.START_TAG) {\n            throw new XmlPullParserException(\"No start tag found\");\n        }\n\n        if (!parser.getName().equals(firstElementName)) {\n            throw new XmlPullParserException(\"Unexpected start tag: found \" + parser.getName()\n                    + \", expected \" + firstElementName);\n        }\n    }\n\n    /**\n     * Signature test entry point.\n     */\n    private void start(XmlPullParser parser) throws XmlPullParserException, IOException {\n        JDiffClassDescription currentClass = null;\n        String currentPackage = \"\";\n        JDiffMethod currentMethod = null;\n\n        beginDocument(parser, TAG_ROOT);\n        int type;\n        while (true) {\n            while ((type = parser.next()) != XmlPullParser.START_TAG\n                    && type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.END_TAG) {\n\n            }\n\n            if (type == XmlPullParser.END_TAG) {\n                if (TAG_CLASS.equals(parser.getName()) || TAG_INTERFACE.equals(parser.getName())) {\n                    currentClass.checkSignatureCompliance();\n                } else if (TAG_PACKAGE.equals(parser.getName())) {\n                    currentPackage = \"\";\n                }\n                continue;\n            }\n\n            if (type == XmlPullParser.END_DOCUMENT) {\n                break;\n            }\n\n            String tagname = parser.getName();\n            if (!mKeyTagSet.contains(tagname)) {\n                continue;\n            }\n\n            switch (tagname) {\n                case TAG_PACKAGE:\n                    currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n                    break;\n                case TAG_CLASS:\n                    currentClass = loadClassInfo(parser, false, currentPackage);\n                    break;\n                case TAG_INTERFACE:\n                    currentClass = loadClassInfo(parser, true, currentPackage);\n                    break;\n                case TAG_IMPLEMENTS:\n                    currentClass.addImplInterface(parser.getAttributeValue(null, ATTRIBUTE_NAME));\n                    break;\n                case TAG_CONSTRUCTOR:\n                    JDiffConstructor constructor = loadConstructorInfo(parser, currentClass);\n                    currentClass.addConstructor(constructor);\n                    currentMethod = constructor;\n                    break;\n                case TAG_METHOD:\n                    currentMethod = loadMethodInfo(currentClass.getClassName(), parser);\n                    currentClass.addMethod(currentMethod);\n                    break;\n                case TAG_PARAM:\n                    currentMethod.addParam(parser.getAttributeValue(null, ATTRIBUTE_TYPE));\n                    break;\n                case TAG_EXCEPTION:\n                    currentMethod.addException(parser.getAttributeValue(null, ATTRIBUTE_TYPE));\n                    break;\n                case TAG_FIELD:\n                    JDiffField field = loadFieldInfo(currentClass.getClassName(), parser);\n                    currentClass.addField(field);\n                    break;\n                default:\n                    throw new RuntimeException(\"unknow tag exception:\" + tagname);\n            }\n        }\n    }\n\n    /**\n     * Load field information from xml to memory.\n     * \n     * @param className of the class being examined which will be shown in error messages\n     * @param parser The XmlPullParser which carries the xml information.\n     * @return the new field\n     */\n    private JDiffField loadFieldInfo(String className, XmlPullParser parser) {\n        String fieldName = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n        String fieldType = parser.getAttributeValue(null, ATTRIBUTE_TYPE);\n        int modifier = jdiffModifierToReflectionFormat(className, parser);\n        return new JDiffField(fieldName, fieldType, modifier);\n    }\n\n    /**\n     * Load method information from xml to memory.\n     * \n     * @param className of the class being examined which will be shown in error messages\n     * @param parser The XmlPullParser which carries the xml information.\n     * @return the newly loaded method.\n     */\n    private JDiffMethod loadMethodInfo(String className, XmlPullParser parser) {\n        String methodName = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n        String returnType = parser.getAttributeValue(null, ATTRIBUTE_RETURN);\n        int modifier = jdiffModifierToReflectionFormat(className, parser);\n        return new JDiffMethod(methodName, modifier, returnType);\n    }\n\n    /**\n     * Load constructor information from xml to memory.\n     * \n     * @param parser The XmlPullParser which carries the xml information.\n     * @param currentClass the current class being loaded.\n     * @return the new constructor\n     */\n    private JDiffConstructor loadConstructorInfo(XmlPullParser parser,\n            JDiffClassDescription currentClass) {\n        String name = currentClass.getClassName();\n        int modifier = jdiffModifierToReflectionFormat(name, parser);\n        return new JDiffConstructor(name, modifier);\n    }\n\n    /**\n     * Load class or interface information to memory.\n     * \n     * @param parser The XmlPullParser which carries the xml information.\n     * @param isInterface true if the current class is an interface, otherwise is false.\n     * @param pkg the name of the java package this class can be found in.\n     * @return the new class description.\n     */\n    private JDiffClassDescription loadClassInfo(XmlPullParser parser, boolean isInterface,\n            String pkg) {\n        String className = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n        JDiffClassDescription currentClass = new JDiffClassDescription(pkg, className,\n                mResultObserver);\n        currentClass.setModifier(jdiffModifierToReflectionFormat(className, parser));\n        currentClass.setType(isInterface ? JDiffClassDescription.JDiffType.INTERFACE\n                : JDiffClassDescription.JDiffType.CLASS);\n        currentClass.setExtendsClass(parser.getAttributeValue(null, ATTRIBUTE_EXTENDS));\n        return currentClass;\n    }\n\n    /**\n     * Convert string modifier to int modifier.\n     * \n     * @param name of the class/method/field being examined which will be shown in error messages\n     * @param key modifier name\n     * @param value modifier value\n     * @return converted modifier value\n     */\n    private static int modifierDescriptionToReflectedType(String name, String key, String value) {\n        switch (key) {\n            case MODIFIER_ABSTRACT:\n                return value.equals(\"true\") ? Modifier.ABSTRACT : 0;\n            case MODIFIER_FINAL:\n                return value.equals(\"true\") ? Modifier.FINAL : 0;\n            case MODIFIER_NATIVE:\n                return value.equals(\"true\") ? Modifier.NATIVE : 0;\n            case MODIFIER_STATIC:\n                return value.equals(\"true\") ? Modifier.STATIC : 0;\n            case MODIFIER_SYNCHRONIZED:\n                return value.equals(\"true\") ? Modifier.SYNCHRONIZED : 0;\n            case MODIFIER_TRANSIENT:\n                return value.equals(\"true\") ? Modifier.TRANSIENT : 0;\n            case MODIFIER_VOLATILE:\n                return value.equals(\"true\") ? Modifier.VOLATILE : 0;\n            case MODIFIER_VISIBILITY:\n                switch (value) {\n                    case MODIFIER_PRIVATE:\n                        throw new RuntimeException(\"Private visibility found in API spec: \" + name);\n                    case MODIFIER_PROTECTED:\n                        return Modifier.PROTECTED;\n                    case MODIFIER_PUBLIC:\n                        return Modifier.PUBLIC;\n                    case \"\":\n                        // If the visibility is \"\", it means it has no modifier.\n                        // which is package private. We should return 0 for this modifier.\n                        return 0;\n                    default:\n                        throw new RuntimeException(\"Unknown modifier found in API spec: \" + value);\n                }\n        }\n        return 0;\n    }\n\n    /**\n     * Transfer string modifier to int one.\n     * \n     * @param name of the class/method/field being examined which will be shown in error messages\n     * @param parser XML resource parser\n     * @return converted modifier\n     */\n    private static int jdiffModifierToReflectionFormat(String name, XmlPullParser parser) {\n        int modifier = 0;\n        for (int i = 0; i < parser.getAttributeCount(); i++) {\n            modifier |= modifierDescriptionToReflectedType(name, parser.getAttributeName(i),\n                    parser.getAttributeValue(i));\n        }\n        return modifier;\n    }\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n -->\n\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"android.tests.sigtest\">\n\n    <application\n        android:allowBackup=\"false\"\n        android:icon=\"@drawable/app_icon\"\n        android:label=\"@string/app_name\">\n        <activity\n            android:name=\"SignatureTestActivity\"\n            android:label=\"@string/title_sig_test_activity\"\n            android:icon=\"@drawable/app_icon\"\n            android:screenOrientation=\"landscape\"\n            android:stateNotNeeded=\"true\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/JDiffClassDescription.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.tests.sigtest;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.GenericArrayType;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.lang.reflect.WildcardType;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * Represents class descriptions loaded from a jdiff xml file. Used for CTS SignatureTests.\n */\npublic class JDiffClassDescription {\n    /** Indicates that the class is an annotation. */\n    private static final int CLASS_MODIFIER_ANNOTATION = 0x00002000;\n    /** Indicates that the class is an enum. */\n    private static final int CLASS_MODIFIER_ENUM = 0x00004000;\n\n    /** Indicates that the method is a bridge method. */\n    private static final int METHOD_MODIFIER_BRIDGE = 0x00000040;\n    /** Indicates that the method is takes a variable number of arguments. */\n    private static final int METHOD_MODIFIER_VAR_ARGS = 0x00000080;\n    /** Indicates that the method is a synthetic method. */\n    private static final int METHOD_MODIFIER_SYNTHETIC = 0x00001000;\n\n    public enum JDiffType {\n        INTERFACE, CLASS\n    }\n\n    // @SuppressWarnings(\"unchecked\")\n    private Class<?> mClass;\n\n    private String mPackageName;\n    private String mShortClassName;\n\n    /**\n     * Package name + short class name\n     */\n    private String mAbsoluteClassName;\n\n    private int mModifier;\n\n    private String mExtendedClass;\n    private List<String> implInterfaces = new ArrayList<>();\n    private List<JDiffField> jDiffFields = new ArrayList<>();\n    private List<JDiffMethod> jDiffMethods = new ArrayList<>();\n    private List<JDiffConstructor> jDiffConstructors = new ArrayList<>();\n\n    private ResultObserver mResultObserver;\n    private JDiffType mClassType;\n\n    /**\n     * Creates a new JDiffClassDescription.\n     * \n     * @param pkg the java package this class will end up in.\n     * @param className the name of the class.\n     */\n    public JDiffClassDescription(String pkg, String className) {\n        this(pkg, className, new ResultObserver() {\n            public void notifyFailure(SignatureTestActivity.FAILURE_TYPE type, String name,\n                    String errorMessage) {\n                // This is a null result observer that doesn't do anything.\n            }\n        });\n    }\n\n    /**\n     * Creates a new JDiffClassDescription with the specified results observer.\n     * \n     * @param pkg the java package this class belongs in.\n     * @param className the name of the class.\n     * @param resultObserver the resultObserver to get results with.\n     */\n    public JDiffClassDescription(String pkg, String className, ResultObserver resultObserver) {\n        mPackageName = pkg;\n        mShortClassName = className;\n        mResultObserver = resultObserver;\n    }\n\n    /**\n     * adds implemented interface name.\n     * \n     * @param iname name of interface\n     */\n    public void addImplInterface(String iname) {\n        implInterfaces.add(iname);\n    }\n\n    /**\n     * Adds a field.\n     * \n     * @param field the field to be added.\n     */\n    public void addField(JDiffField field) {\n        jDiffFields.add(field);\n    }\n\n    /**\n     * Adds a method.\n     * \n     * @param method the method to be added.\n     */\n    public void addMethod(JDiffMethod method) {\n        jDiffMethods.add(method);\n    }\n\n    /**\n     * Adds a constructor.\n     * \n     * @param tc the constructor to be added.\n     */\n    public void addConstructor(JDiffConstructor tc) {\n        jDiffConstructors.add(tc);\n    }\n\n    static String convertModifiersToAccessLevel(int modifiers) {\n        if ((modifiers & Modifier.PUBLIC) != 0) {\n            return \"public\";\n        } else if ((modifiers & Modifier.PRIVATE) != 0) {\n            return \"private\";\n        } else if ((modifiers & Modifier.PROTECTED) != 0) {\n            return \"protected\";\n        } else {\n            // package protected\n            return \"\";\n        }\n    }\n\n    static String convertModifersToModifierString(int modifiers) {\n        StringBuilder sb = new StringBuilder();\n        boolean isFirst = true;\n\n        // order taken from Java Language Spec, sections 8.1.1, 8.3.1, and 8.4.3\n        if ((modifiers & Modifier.ABSTRACT) != 0) {\n            isFirst = false;\n            sb.append(\"abstract\");\n        }\n        if ((modifiers & Modifier.STATIC) != 0) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(\" \");\n            }\n            sb.append(\"static\");\n        }\n        if ((modifiers & Modifier.FINAL) != 0) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(\" \");\n            }\n            sb.append(\"final\");\n        }\n        if ((modifiers & Modifier.TRANSIENT) != 0) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(\" \");\n            }\n            sb.append(\"transient\");\n        }\n        if ((modifiers & Modifier.VOLATILE) != 0) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(\" \");\n            }\n            sb.append(\"volatile\");\n        }\n        if ((modifiers & Modifier.SYNCHRONIZED) != 0) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(\" \");\n            }\n            sb.append(\"synchronized\");\n        }\n        if ((modifiers & Modifier.NATIVE) != 0) {\n            if (isFirst) {\n                isFirst = false;\n            } else {\n                sb.append(\" \");\n            }\n            sb.append(\"native\");\n        }\n        if ((modifiers & Modifier.STRICT) != 0) {\n            if (!isFirst) {\n                sb.append(\" \");\n            }\n            sb.append(\"strictfp\");\n        }\n\n        return sb.toString();\n    }\n\n    public abstract static class JDiffElement {\n        final String mName;\n        int mModifier;\n\n        public JDiffElement(String name, int modifier) {\n            mName = name;\n            mModifier = modifier;\n        }\n    }\n\n    /**\n     * Represents a field.\n     */\n    public static final class JDiffField extends JDiffElement {\n        private String mFieldType;\n\n        public JDiffField(String name, String fieldType, int modifier) {\n            super(name, modifier);\n\n            mFieldType = fieldType;\n        }\n\n        /**\n         * Make a readable string according to the class name specified.\n         * \n         * @param className The specified class name.\n         * @return A readable string to represent this field along with the class name.\n         */\n        public String toReadableString(String className) {\n            return className + \"#\" + mName + \"(\" + mFieldType + \")\";\n        }\n\n        public String toSignatureString() {\n            StringBuilder sb = new StringBuilder();\n\n            // access level\n            String accesLevel = convertModifiersToAccessLevel(mModifier);\n            if (!\"\".equals(accesLevel)) {\n                sb.append(accesLevel).append(\" \");\n            }\n\n            String modifierString = convertModifersToModifierString(mModifier);\n            if (!\"\".equals(modifierString)) {\n                sb.append(modifierString).append(\" \");\n            }\n\n            sb.append(mFieldType).append(\" \");\n\n            sb.append(mName);\n\n            return sb.toString();\n        }\n    }\n\n    /**\n     * Represents a method.\n     */\n    public static class JDiffMethod extends JDiffElement {\n        protected String mReturnType;\n        protected ArrayList<String> mParamList;\n        protected ArrayList<String> mExceptionList;\n\n        public JDiffMethod(String name, int modifier, String returnType) {\n            super(name, modifier);\n\n            if (returnType == null) {\n                mReturnType = \"void\";\n            } else {\n                mReturnType = scrubJdiffParamType(returnType);\n            }\n\n            mParamList = new ArrayList<>();\n            mExceptionList = new ArrayList<>();\n        }\n\n        /**\n         * Adds a parameter.\n         * \n         * @param param parameter type\n         */\n        public void addParam(String param) {\n            mParamList.add(scrubJdiffParamType(param));\n        }\n\n        /**\n         * Adds an exception.\n         * \n         * @param exceptionName name of exception\n         */\n        public void addException(String exceptionName) {\n            mExceptionList.add(exceptionName);\n        }\n\n        /**\n         * Makes a readable string according to the class name specified.\n         * \n         * @param className The specified class name.\n         * @return A readable string to represent this method along with the class name.\n         */\n        public String toReadableString(String className) {\n            return className + \"#\" + mName + \"(\" + convertParamList(mParamList) + \")\";\n        }\n\n        /**\n         * Converts a parameter array to a string\n         * \n         * @param params the array to convert\n         * @return converted parameter string\n         */\n        private static String convertParamList(final ArrayList<String> params) {\n            StringBuilder paramList = new StringBuilder();\n\n            if (params != null) {\n                for (String str : params) {\n                    paramList.append(str).append(\", \");\n                }\n                if (params.size() > 0) {\n                    paramList.delete(paramList.length() - 2, paramList.length());\n                }\n            }\n\n            return paramList.toString();\n        }\n\n        public String toSignatureString() {\n            StringBuilder sb = new StringBuilder();\n\n            // access level\n            String accesLevel = convertModifiersToAccessLevel(mModifier);\n            if (!\"\".equals(accesLevel)) {\n                sb.append(accesLevel).append(\" \");\n            }\n\n            String modifierString = convertModifersToModifierString(mModifier);\n            if (!\"\".equals(modifierString)) {\n                sb.append(modifierString).append(\" \");\n            }\n\n            String returnType = getReturnType();\n            if (!\"\".equals(returnType)) {\n                sb.append(returnType).append(\" \");\n            }\n\n            sb.append(mName);\n            sb.append(\"(\");\n            for (int x = 0; x < mParamList.size(); x++) {\n                sb.append(mParamList.get(x));\n                if (x + 1 != mParamList.size()) {\n                    sb.append(\", \");\n                }\n            }\n            sb.append(\")\");\n\n            // does it throw?\n            if (mExceptionList.size() > 0) {\n                sb.append(\" throws \");\n                for (int x = 0; x < mExceptionList.size(); x++) {\n                    sb.append(mExceptionList.get(x));\n                    if (x + 1 != mExceptionList.size()) {\n                        sb.append(\", \");\n                    }\n                }\n            }\n\n            return sb.toString();\n        }\n\n        /**\n         * Gets the return type.\n         * \n         * @return the return type of this method.\n         */\n        protected String getReturnType() {\n            return mReturnType;\n        }\n    }\n\n    /**\n     * Represents a constructor.\n     */\n    public static final class JDiffConstructor extends JDiffMethod {\n        public JDiffConstructor(String name, int modifier) {\n            super(name, modifier, null);\n        }\n\n        public JDiffConstructor(String name, String[] param, int modifier) {\n            super(name, modifier, null);\n            for (String aParam : param) {\n                addParam(aParam);\n            }\n        }\n\n        /**\n         * Gets the return type.\n         * \n         * @return the return type of this method.\n         */\n        @Override\n        protected String getReturnType() {\n            // Constructors have no return type.\n            return \"\";\n        }\n    }\n\n    /**\n     * Checks test class's name, modifier, fields, constructors, and methods.\n     */\n    public void checkSignatureCompliance() {\n        checkClassCompliance();\n        if (mClass != null) {\n            checkFieldsCompliance();\n            checkConstructorCompliance();\n            checkMethodCompliance();\n        }\n    }\n\n    /**\n     * Checks to ensure that the modifiers value for two methods are compatible. Allowable\n     * differences are: - synchronized is allowed to be removed from an apiMethod that has it - the\n     * native modified is ignored\n     * \n     * @param apiMethod the method read from the api file.\n     * @param reflectedMethod the method found via reflections.\n     */\n    private boolean areMethodModifiedCompatibile(JDiffMethod apiMethod, Method reflectedMethod) {\n\n        // If the apiMethod isn't synchronized\n        if (((apiMethod.mModifier & Modifier.SYNCHRONIZED) == 0) &&\n        // but the reflected method is\n                ((reflectedMethod.getModifiers() & Modifier.SYNCHRONIZED) != 0)) {\n            // that is a problem\n            return false;\n        }\n\n        // Mask off NATIVE since it is a don't care. Also mask off\n        // SYNCHRONIZED since we've already handled that check.\n        int mod1 = reflectedMethod.getModifiers() & ~(Modifier.NATIVE | Modifier.SYNCHRONIZED);\n        int mod2 = apiMethod.mModifier & ~(Modifier.NATIVE | Modifier.SYNCHRONIZED);\n\n        // We can ignore FINAL for final classes\n        if ((mModifier & Modifier.FINAL) != 0) {\n            mod1 &= ~Modifier.FINAL;\n            mod2 &= ~Modifier.FINAL;\n        }\n\n        return mod1 == mod2;\n    }\n\n    /**\n     * Checks that the method found through reflection matches the specification from the API xml\n     * file.\n     */\n    private void checkMethodCompliance() {\n        for (JDiffMethod method : jDiffMethods) {\n            try {\n                // this is because jdiff think a method in an interface is not abstract\n                if (JDiffType.INTERFACE.equals(mClassType)) {\n                    method.mModifier |= Modifier.ABSTRACT;\n                }\n\n                Method m = findMatchingMethod(method);\n                if (m == null) {\n                    mResultObserver.notifyFailure(\n                            SignatureTestActivity.FAILURE_TYPE.MISSING_METHOD,\n                            method.toReadableString(mAbsoluteClassName),\n                            \"No method with correct signature found:\" + method.toSignatureString());\n                } else {\n                    if (m.isVarArgs()) {\n                        method.mModifier |= METHOD_MODIFIER_VAR_ARGS;\n                    }\n                    if (m.isBridge()) {\n                        method.mModifier |= METHOD_MODIFIER_BRIDGE;\n                    }\n                    if (m.isSynthetic()) {\n                        method.mModifier |= METHOD_MODIFIER_SYNTHETIC;\n                    }\n\n                    // FIXME: A workaround to fix the final mismatch on enumeration\n                    if (mClass.isEnum() && method.mName.equals(\"values\")) {\n                        return;\n                    }\n\n                    if (!areMethodModifiedCompatibile(method, m)) {\n                        mResultObserver.notifyFailure(\n                                SignatureTestActivity.FAILURE_TYPE.MISMATCH_METHOD,\n                                method.toReadableString(mAbsoluteClassName),\n                                \"Non-compatible method found when looking for \"\n                                        + method.toSignatureString());\n                    }\n                }\n            } catch (Exception e) {\n                SignatureTestLog.e(\"Got exception when checking method compliance\", e);\n                mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION,\n                        method.toReadableString(mAbsoluteClassName), \"Exception!\");\n            }\n        }\n    }\n\n    /**\n     * Checks if the two types of methods are the same.\n     * \n     * @param jDiffMethod the jDiffMethod to compare\n     * @param method the reflected method to compare\n     * @return true, if both methods are the same\n     */\n    private boolean matches(JDiffMethod jDiffMethod, Method method) {\n        // If the method names aren't equal, the methods can't match.\n        if (jDiffMethod.mName.equals(method.getName())) {\n            String jdiffReturnType = jDiffMethod.mReturnType;\n            String reflectionReturnType = typeToString(method.getGenericReturnType());\n            List<String> jdiffParamList = jDiffMethod.mParamList;\n\n            // Next, compare the return types of the two methods. If\n            // they aren't equal, the methods can't match.\n            if (jdiffReturnType.equals(reflectionReturnType)) {\n                Type[] params = method.getGenericParameterTypes();\n                // Next, check the method parameters. If they have\n                // different number of parameters, the two methods\n                // can't match.\n                if (jdiffParamList.size() == params.length) {\n                    // If any of the parameters don't match, the\n                    // methods can't match.\n                    for (int i = 0; i < jdiffParamList.size(); i++) {\n                        if (!compareParam(jdiffParamList.get(i), params[i])) {\n                            return false;\n                        }\n                    }\n                    // We've passed all the tests, the methods do\n                    // match.\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Finds the reflected method specified by the method description.\n     * \n     * @param method description of the method to find\n     * @return the reflected method, or null if not found.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private Method findMatchingMethod(JDiffMethod method) {\n        Method[] methods = mClass.getDeclaredMethods();\n        for (Method m : methods) {\n            if (matches(method, m)) {\n                return m;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Compares the parameter from the API and the parameter from reflection.\n     * \n     * @param jdiffParam param parsed from the API xml file.\n     * @param reflectionParamType param gotten from the Java reflection.\n     * @return True if the two params match, otherwise return false.\n     */\n    private static boolean compareParam(String jdiffParam, Type reflectionParamType) {\n        if (jdiffParam == null) {\n            return false;\n        }\n        String reflectionParam = typeToString(reflectionParamType);\n        // Most things aren't varargs, so just do a simple compare\n        // first.\n        if (jdiffParam.equals(reflectionParam)) {\n            return true;\n        }\n        // Check for varargs. jdiff reports varargs as ..., while\n        // reflection reports them as []\n        int jdiffParamEndOffset = jdiffParam.indexOf(\"...\");\n        int reflectionParamEndOffset = reflectionParam.indexOf(\"[]\");\n        if (jdiffParamEndOffset != -1 && reflectionParamEndOffset != -1) {\n            jdiffParam = jdiffParam.substring(0, jdiffParamEndOffset);\n            reflectionParam = reflectionParam.substring(0, reflectionParamEndOffset);\n            return jdiffParam.equals(reflectionParam);\n        }\n        return false;\n    }\n\n    /**\n     * Checks whether the constructor parsed from API xml file and Java reflection are compliant.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private void checkConstructorCompliance() {\n        for (JDiffConstructor con : jDiffConstructors) {\n            try {\n                Constructor<?> c = findMatchingConstructor(con);\n                if (c == null) {\n                    mResultObserver.notifyFailure(\n                            SignatureTestActivity.FAILURE_TYPE.MISSING_METHOD,\n                            con.toReadableString(mAbsoluteClassName),\n                            \"No method with correct signature found:\" + con.toSignatureString());\n                } else {\n                    if (c.isVarArgs()) {// some method's parameter are variable args\n                        con.mModifier |= METHOD_MODIFIER_VAR_ARGS;\n                    }\n                    if (c.getModifiers() != con.mModifier) {\n                        mResultObserver.notifyFailure(\n                                SignatureTestActivity.FAILURE_TYPE.MISMATCH_METHOD,\n                                con.toReadableString(mAbsoluteClassName),\n                                \"Non-compatible method found when looking for \"\n                                        + con.toSignatureString());\n                    }\n                }\n            } catch (Exception e) {\n                SignatureTestLog.e(\"Got exception when checking constructor compliance\", e);\n                mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION,\n                        con.toReadableString(mAbsoluteClassName), \"Exception!\");\n            }\n        }\n    }\n\n    /**\n     * Searches available constructor.\n     * \n     * @param jdiffDes constructor description to find.\n     * @return reflected constructor, or null if not found.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private Constructor<?> findMatchingConstructor(JDiffConstructor jdiffDes) {\n        for (Constructor<?> c : mClass.getDeclaredConstructors()) {\n            Type[] params = c.getGenericParameterTypes();\n            boolean isStaticClass = ((mClass.getModifiers() & Modifier.STATIC) != 0);\n\n            int startParamOffset = 0;\n            int numberOfParams = params.length;\n\n            // non-static inner class -> skip implicit parent pointer\n            // as first arg\n            if (mClass.isMemberClass() && !isStaticClass && params.length >= 1) {\n                startParamOffset = 1;\n                --numberOfParams;\n            }\n\n            ArrayList<String> jdiffParamList = jdiffDes.mParamList;\n            if (jdiffParamList.size() == numberOfParams) {\n                boolean isFound = true;\n                // i counts jdiff params, j counts reflected params\n                int i = 0;\n                int j = startParamOffset;\n                while (i < jdiffParamList.size()) {\n                    if (!compareParam(jdiffParamList.get(i), params[j])) {\n                        isFound = false;\n                        break;\n                    }\n                    ++i;\n                    ++j;\n                }\n                if (isFound) {\n                    return c;\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Checks all fields in test class for compliance with the API xml.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private void checkFieldsCompliance() {\n        for (JDiffField field : jDiffFields) {\n            try {\n                Field f = findMatchingField(field);\n                if (f == null) {\n                    mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.MISSING_FIELD,\n                            field.toReadableString(mAbsoluteClassName),\n                            \"No field with correct signature found:\" + field.toSignatureString());\n                } else if (f.getModifiers() != field.mModifier) {\n                    mResultObserver.notifyFailure(\n                            SignatureTestActivity.FAILURE_TYPE.MISMATCH_FIELD,\n                            field.toReadableString(mAbsoluteClassName),\n                            \"Non-compatible field modifiers found when looking for \"\n                                    + field.toSignatureString());\n                } else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {\n                    // type name does not match, but this might be a generic\n                    String genericTypeName = null;\n                    Type type = f.getGenericType();\n                    if (type != null) {\n                        genericTypeName = type instanceof Class ? ((Class) type).getName() : type\n                                .toString();\n                    }\n                    if (genericTypeName == null || !genericTypeName.equals(field.mFieldType)) {\n                        mResultObserver.notifyFailure(\n                                SignatureTestActivity.FAILURE_TYPE.MISMATCH_FIELD,\n                                field.toReadableString(mAbsoluteClassName),\n                                \"Non-compatible field type found when looking for \"\n                                        + field.toSignatureString());\n                    }\n                }\n\n            } catch (Exception e) {\n                SignatureTestLog.e(\"Got exception when checking field compliance\", e);\n                mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION,\n                        field.toReadableString(mAbsoluteClassName), \"Exception!\");\n            }\n        }\n    }\n\n    /**\n     * Finds the reflected field specified by the field description.\n     * \n     * @param field the field description to find\n     * @return the reflected field, or null if not found.\n     */\n    private Field findMatchingField(JDiffField field) {\n        Field[] fields = mClass.getDeclaredFields();\n        for (Field f : fields) {\n            if (f.getName().equals(field.mName)) {\n                return f;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Checks if the class under test has compliant modifiers compared to the API.\n     * \n     * @return true if modifiers are compliant.\n     */\n    private boolean checkClassModifiersCompliance() {\n        int reflectionModifier = mClass.getModifiers();\n        int apiModifier = mModifier;\n\n        // If the api class isn't abstract\n        if (((apiModifier & Modifier.ABSTRACT) == 0) &&\n        // but the reflected class is\n                ((reflectionModifier & Modifier.ABSTRACT) != 0) &&\n                // and it isn't an enum\n                !isEnumType()) {\n            // that is a problem\n            return false;\n        }\n        // ABSTRACT check passed, so mask off ABSTRACT\n        reflectionModifier &= ~Modifier.ABSTRACT;\n        apiModifier &= ~Modifier.ABSTRACT;\n\n        if (isAnnotation()) {\n            reflectionModifier &= ~CLASS_MODIFIER_ANNOTATION;\n        }\n        if (mClass.isInterface()) {\n            reflectionModifier &= ~(Modifier.INTERFACE);\n        }\n        if (isEnumType() && mClass.isEnum()) {\n            reflectionModifier &= ~CLASS_MODIFIER_ENUM;\n        }\n\n        return ((reflectionModifier == apiModifier) && (isEnumType() == mClass.isEnum()));\n    }\n\n    /**\n     * Checks if the class under test is compliant with regards to annnotations when compared to the\n     * API.\n     * \n     * @return true if the class is compliant\n     */\n    private boolean checkClassAnnotationCompliace() {\n        if (mClass.isAnnotation()) {\n            // check annotation\n            for (String inter : implInterfaces) {\n                if (\"java.lang.annotation.Annotation\".equals(inter)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Checks if the class under test extends the proper classes according to the API.\n     * \n     * @return true if the class is compliant.\n     */\n    private boolean checkClassExtendsCompliance() {\n        // Nothing to check if it doesn't extend anything.\n        if (mExtendedClass != null) {\n            Class<?> superClass = mClass.getSuperclass();\n            // API indicates superclass, reflection doesn't.\n            return superClass != null\n                    && (superClass.getCanonicalName().equals(mExtendedClass) || mAbsoluteClassName\n                            .equals(\"android.hardware.SensorManager\"));\n        }\n        return true;\n    }\n\n    /**\n     * Checks if the class under test implements the proper interfaces according to the API.\n     * \n     * @return true if the class is compliant\n     */\n    private boolean checkClassImplementsCompliance() {\n        Class<?>[] interfaces = mClass.getInterfaces();\n        Set<String> interFaceSet = new HashSet<>();\n        for (Class<?> c : interfaces) {\n            interFaceSet.add(c.getCanonicalName());\n        }\n        for (String inter : implInterfaces) {\n            if (!interFaceSet.contains(inter)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Checks that the class found through reflection matches the specification from the API xml\n     * file.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private void checkClassCompliance() {\n        try {\n            mAbsoluteClassName = mPackageName + \".\" + mShortClassName;\n            mClass = findMatchingClass();\n\n            if (mClass == null) {\n                // No class found, notify the observer according to the class type\n                if (JDiffType.INTERFACE.equals(mClassType)) {\n                    mResultObserver.notifyFailure(\n                            SignatureTestActivity.FAILURE_TYPE.MISSING_INTERFACE,\n                            mAbsoluteClassName, \"Classloader is unable to find \"\n                                    + mAbsoluteClassName);\n                } else {\n                    mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.MISSING_CLASS,\n                            mAbsoluteClassName, \"Classloader is unable to find \"\n                                    + mAbsoluteClassName);\n                }\n\n                return;\n            }\n            if (!checkClassModifiersCompliance()) {\n                logMismatchInterfaceSignature(mAbsoluteClassName,\n                        \"Non-compatible class found when looking for \" + toSignatureString());\n                return;\n            }\n\n            if (!checkClassAnnotationCompliace()) {\n                logMismatchInterfaceSignature(mAbsoluteClassName, \"Annotation mismatch\");\n                return;\n            }\n\n            if (!mClass.isAnnotation()) {\n                // check father class\n                if (!checkClassExtendsCompliance()) {\n                    logMismatchInterfaceSignature(mAbsoluteClassName, \"Extends mismatch\");\n                    return;\n                }\n\n                // check implements interface\n                if (!checkClassImplementsCompliance()) {\n                    logMismatchInterfaceSignature(mAbsoluteClassName, \"Implements mismatch\");\n                }\n            }\n        } catch (Exception e) {\n            SignatureTestLog.e(\"Got exception when checking field compliance\", e);\n            mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.CAUGHT_EXCEPTION,\n                    mAbsoluteClassName, \"Exception!\");\n        }\n    }\n\n    /**\n     * Convert the class into a printable signature string.\n     * \n     * @return the signature string\n     */\n    public String toSignatureString() {\n        StringBuilder sb = new StringBuilder();\n        String accessLevel = convertModifiersToAccessLevel(mModifier);\n        if (!\"\".equals(accessLevel)) {\n            sb.append(accessLevel).append(\" \");\n        }\n        if (!JDiffType.INTERFACE.equals(mClassType)) {\n            String modifierString = convertModifersToModifierString(mModifier);\n            if (!\"\".equals(modifierString)) {\n                sb.append(modifierString).append(\" \");\n            }\n            sb.append(\"class \");\n        } else {\n            sb.append(\"interface \");\n        }\n        // class name\n        sb.append(mShortClassName);\n\n        // does it extends something?\n        if (mExtendedClass != null) {\n            sb.append(\" extends \").append(mExtendedClass).append(\" \");\n        }\n\n        // implements something?\n        if (implInterfaces.size() > 0) {\n            sb.append(\" implements \");\n            for (int x = 0; x < implInterfaces.size(); x++) {\n                String interf = implInterfaces.get(x);\n                sb.append(interf);\n                // if not last elements\n                if (x + 1 != implInterfaces.size()) {\n                    sb.append(\", \");\n                }\n            }\n        }\n        return sb.toString();\n    }\n\n    private void logMismatchInterfaceSignature(String classFullName, String errorMessage) {\n        if (JDiffType.INTERFACE.equals(mClassType)) {\n            mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.MISMATCH_INTERFACE,\n                    classFullName, errorMessage);\n        } else {\n            mResultObserver.notifyFailure(SignatureTestActivity.FAILURE_TYPE.MISMATCH_CLASS,\n                    classFullName, errorMessage);\n        }\n    }\n\n    /**\n     * Sees if the class under test is actually an enum.\n     * \n     * @return true if this class is enum\n     */\n    private boolean isEnumType() {\n        return \"java.lang.Enum\".equals(mExtendedClass);\n    }\n\n    /**\n     * Finds the reflected class for the class under test.\n     * \n     * @return the reflected class, or null if not found.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private Class<?> findMatchingClass() {\n        // even if there are no . in the string, split will return an\n        // array of length 1\n        String[] classNameParts = mShortClassName.split(\"\\\\.\");\n        String currentName = mPackageName + \".\" + classNameParts[0];\n\n        try {\n            // Check to see if the class we're looking for is the top\n            // level class.\n            Class<?> clz = Class.forName(currentName, false, this.getClass().getClassLoader());\n            if (clz.getCanonicalName().equals(mAbsoluteClassName)) {\n                return clz;\n            }\n\n            // Then it must be an inner class.\n            for (int x = 1; x < classNameParts.length; x++) {\n                clz = findInnerClassByName(clz, classNameParts[x]);\n                if (clz == null) {\n                    return null;\n                }\n                if (clz.getCanonicalName().equals(mAbsoluteClassName)) {\n                    return clz;\n                }\n            }\n        } catch (ClassNotFoundException e) {\n//            SignatureTestLog.e(\n//                    \"ClassNotFoundException for \" + mPackageName + \".\" + mShortClassName, e);\n            return null;\n        }\n        return null;\n    }\n\n    /**\n     * Searches the class for the specified inner class.\n     * \n     * @param clz the class to search in.\n     * @param simpleName the simpleName of the class to find\n     * @returns the class being searched for, or null if it can't be found.\n     */\n    private Class<?> findInnerClassByName(Class<?> clz, String simpleName) {\n        for (Class<?> c : clz.getClasses()) {\n            if (c.getSimpleName().equals(simpleName)) {\n                return c;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Sees if the class under test is actually an annotation.\n     * \n     * @return true if this class is Annotation.\n     */\n    private boolean isAnnotation() {\n        return implInterfaces.contains(\"java.lang.annotation.Annotation\");\n    }\n\n    /**\n     * Gets the class name for the class under test.\n     * \n     * @return the class name.\n     */\n    public String getClassName() {\n        return mShortClassName;\n    }\n\n    /**\n     * Sets the modifier for the class under test.\n     * \n     * @param modifier the modifier\n     */\n    public void setModifier(int modifier) {\n        mModifier = modifier;\n    }\n\n    /**\n     * Sets the return type for the class under test.\n     * \n     * @param type the return type\n     */\n    public void setType(JDiffType type) {\n        mClassType = type;\n    }\n\n    /**\n     * Sets the class that is beign extended for the class under test.\n     * \n     * @param extendsClass the class being extended.\n     */\n    public void setExtendsClass(String extendsClass) {\n        mExtendedClass = extendsClass;\n    }\n\n    /**\n     * Registers a ResultObserver to process the output from the compliance testing done in this\n     * class.\n     * \n     * @param resultObserver the observer to register.\n     */\n    public void registerResultObserver(ResultObserver resultObserver) {\n        mResultObserver = resultObserver;\n    }\n\n    /**\n     * Converts WildcardType array into a jdiff compatible string.. This is a helper function for\n     * typeToString.\n     * \n     * @param types array of types to format.\n     * @return the jdiff formatted string.\n     */\n    private static String concatWildcardTypes(Type[] types) {\n        StringBuilder sb = new StringBuilder();\n        int elementNum = 0;\n        for (Type t : types) {\n            sb.append(typeToString(t));\n            if (++elementNum < types.length) {\n                sb.append(\" & \");\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * Converts a Type into a jdiff compatible String. The returned types from this function should\n     * match the same Strings that jdiff is providing to us.\n     * \n     * @param type the type to convert.\n     * @return the jdiff formatted string.\n     */\n    private static String typeToString(Type type) {\n        if (type instanceof ParameterizedType) {\n            ParameterizedType pt = (ParameterizedType) type;\n            StringBuilder sb = new StringBuilder();\n            sb.append(typeToString(pt.getRawType()));\n            sb.append(\"<\");\n\n            int elementNum = 0;\n            Type[] types = pt.getActualTypeArguments();\n            for (Type t : types) {\n                sb.append(typeToString(t));\n                if (++elementNum < types.length) {\n                    sb.append(\", \");\n                }\n            }\n\n            sb.append(\">\");\n            return sb.toString();\n        } else if (type instanceof TypeVariable) {\n            return ((TypeVariable<?>) type).getName();\n        } else if (type instanceof Class) {\n            return ((Class<?>) type).getCanonicalName();\n        } else if (type instanceof GenericArrayType) {\n            String typeName = typeToString(((GenericArrayType) type).getGenericComponentType());\n            return typeName + \"[]\";\n        } else if (type instanceof WildcardType) {\n            WildcardType wt = (WildcardType) type;\n            Type[] lowerBounds = wt.getLowerBounds();\n            if (lowerBounds.length == 0) {\n                String name = \"? extends \" + concatWildcardTypes(wt.getUpperBounds());\n\n                // Special case for ?\n                if (name.equals(\"? extends java.lang.Object\")) {\n                    return \"?\";\n                } else {\n                    return name;\n                }\n            } else {\n                String name = concatWildcardTypes(wt.getUpperBounds()) + \" super \"\n                        + concatWildcardTypes(wt.getLowerBounds());\n                // Another special case for ?\n                name = name.replace(\"java.lang.Object\", \"?\");\n                return name;\n            }\n        } else {\n            throw new RuntimeException(\"Got an unknown java.lang.Type\");\n        }\n    }\n\n    /**\n     * Cleans up jdiff parameters to canonicalize them.\n     * \n     * @param paramType the parameter from jdiff.\n     * @return the scrubbed version of the parameter.\n     */\n    private static String scrubJdiffParamType(String paramType) {\n        // <? extends java.lang.Object and <?> are the same, so\n        // canonicalize them to one form.\n        return paramType.replace(\"<? extends java.lang.Object>\", \"<?>\");\n    }\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/RcsApiSignatureTestResult.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.sigtest;\n\n/**\n * Created by YPLO6403 on 17/03/2016.\n */\npublic class RcsApiSignatureTestResult {\n\n    private final SignatureTestActivity.FAILURE_TYPE mType;\n    private final String mClassName;\n    private final String mReason;\n\n    public RcsApiSignatureTestResult(SignatureTestActivity.FAILURE_TYPE type, String className,\n            String reason) {\n        mType = type;\n        mClassName = className;\n        mReason = reason;\n    }\n\n    public SignatureTestActivity.FAILURE_TYPE getType() {\n        return mType;\n    }\n\n    public String getClassName() {\n        return mClassName;\n    }\n\n    public String getReason() {\n        return mReason;\n    }\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/ResultObserver.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.tests.sigtest;\n\n/**\n * Interface for saving signature test result.\n */\npublic interface ResultObserver {\n    /**\n     * Notify failure.\n     * \n     * @param type Failure type.\n     * @param name Name of the failed element (interface/class/method/field)\n     * @param errorMessage a descriptive message indicating why it failed.\n     */\n    void notifyFailure(SignatureTestActivity.FAILURE_TYPE type, String name, String errorMessage);\n\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/SignatureTest.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.tests.sigtest;\n\nimport android.tests.sigtest.JDiffClassDescription.JDiffConstructor;\nimport android.tests.sigtest.JDiffClassDescription.JDiffField;\nimport android.tests.sigtest.JDiffClassDescription.JDiffMethod;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashSet;\n\n/**\n * Entry class for signature test.\n */\npublic class SignatureTest {\n    private static final String TAG_ROOT = \"api\";\n    private static final String TAG_PACKAGE = \"package\";\n    private static final String TAG_CLASS = \"class\";\n    private static final String TAG_INTERFACE = \"interface\";\n    private static final String TAG_IMPLEMENTS = \"implements\";\n    private static final String TAG_CONSTRUCTOR = \"constructor\";\n    private static final String TAG_METHOD = \"method\";\n    private static final String TAG_PARAM = \"parameter\";\n    private static final String TAG_EXCEPTION = \"exception\";\n    private static final String TAG_FIELD = \"field\";\n\n    private static final String MODIFIER_ABSTRACT = \"abstract\";\n    private static final String MODIFIER_FINAL = \"final\";\n    private static final String MODIFIER_NATIVE = \"native\";\n    private static final String MODIFIER_PRIVATE = \"private\";\n    private static final String MODIFIER_PROTECTED = \"protected\";\n    private static final String MODIFIER_PUBLIC = \"public\";\n    private static final String MODIFIER_STATIC = \"static\";\n    private static final String MODIFIER_SYNCHRONIZED = \"synchronized\";\n    private static final String MODIFIER_TRANSIENT = \"transient\";\n    private static final String MODIFIER_VOLATILE = \"volatile\";\n    private static final String MODIFIER_VISIBILITY = \"visibility\";\n\n    private static final String ATTRIBUTE_NAME = \"name\";\n    private static final String ATTRIBUTE_EXTENDS = \"extends\";\n    private static final String ATTRIBUTE_TYPE = \"type\";\n    private static final String ATTRIBUTE_RETURN = \"return\";\n\n    private static ArrayList<String> mDebugArray = new ArrayList<>();\n\n    private HashSet<String> mKeyTagSet;\n\n    private ArrayList<ResultObserver> mReportObserverList;\n\n    private ResultObserver mResultObserver;\n\n    public SignatureTest(ResultObserver resultObserver) {\n        mResultObserver = resultObserver;\n        mReportObserverList = new ArrayList<>();\n        mKeyTagSet = new HashSet<>();\n        mKeyTagSet.addAll(Arrays.asList(TAG_PACKAGE, TAG_CLASS, TAG_INTERFACE, TAG_IMPLEMENTS,\n                TAG_CONSTRUCTOR, TAG_METHOD, TAG_PARAM, TAG_EXCEPTION, TAG_FIELD));\n    }\n\n    public static void beginDocument(XmlPullParser parser, String firstElementName)\n            throws XmlPullParserException, IOException {\n        int type;\n        while ((type = parser.next()) != XmlPullParser.START_TAG\n                && type != XmlPullParser.END_DOCUMENT) {\n        }\n\n        if (type != XmlPullParser.START_TAG) {\n            throw new XmlPullParserException(\"No start tag found\");\n        }\n\n        if (!parser.getName().equals(firstElementName)) {\n            throw new XmlPullParserException(\"Unexpected start tag: found \" + parser.getName()\n                    + \", expected \" + firstElementName);\n        }\n    }\n\n    /**\n     * Signature test entry point.\n     */\n    public void start(XmlPullParser parser) throws XmlPullParserException, IOException {\n        JDiffClassDescription currentClass = null;\n        String currentPackage = \"\";\n        JDiffMethod currentMethod = null;\n\n        SignatureTest.beginDocument(parser, TAG_ROOT);\n        int type;\n        while (true) {\n            while ((type = parser.next()) != XmlPullParser.START_TAG\n                    && type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.END_TAG) {\n\n            }\n\n            if (type == XmlPullParser.END_TAG) {\n                if (TAG_CLASS.equals(parser.getName()) || TAG_INTERFACE.equals(parser.getName())) {\n                    currentClass.checkSignatureCompliance();\n                } else if (TAG_PACKAGE.equals(parser.getName())) {\n                    currentPackage = \"\";\n                }\n                continue;\n            }\n\n            if (type == XmlPullParser.END_DOCUMENT) {\n                break;\n            }\n\n            String tagname = parser.getName();\n            if (!mKeyTagSet.contains(tagname)) {\n                continue;\n            }\n\n            switch (tagname) {\n                case TAG_PACKAGE:\n                    currentPackage = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n                    break;\n                case TAG_CLASS:\n                    currentClass = loadClassInfo(parser, false, currentPackage);\n                    break;\n                case TAG_INTERFACE:\n                    currentClass = loadClassInfo(parser, true, currentPackage);\n                    break;\n                case TAG_IMPLEMENTS:\n                    currentClass.addImplInterface(parser.getAttributeValue(null, ATTRIBUTE_NAME));\n                    break;\n                case TAG_CONSTRUCTOR:\n                    JDiffConstructor constructor = loadConstructorInfo(parser, currentClass);\n                    currentClass.addConstructor(constructor);\n                    currentMethod = constructor;\n                    break;\n                case TAG_METHOD:\n                    currentMethod = loadMethodInfo(currentClass.getClassName(), parser);\n                    currentClass.addMethod(currentMethod);\n                    break;\n                case TAG_PARAM:\n                    currentMethod.addParam(parser.getAttributeValue(null, ATTRIBUTE_TYPE));\n                    break;\n                case TAG_EXCEPTION:\n                    currentMethod.addException(parser.getAttributeValue(null, ATTRIBUTE_TYPE));\n                    break;\n                case TAG_FIELD:\n                    JDiffField field = loadFieldInfo(currentClass.getClassName(), parser);\n                    currentClass.addField(field);\n                    break;\n                default:\n                    throw new RuntimeException(\"unknow tag exception:\" + tagname);\n            }\n        }\n    }\n\n    public static void log(final String msg) {\n        mDebugArray.add(msg);\n    }\n\n    public void addReportObserver(ResultObserver observer) {\n        mReportObserverList.add(observer);\n    }\n\n    public void removeReportObserver(ResultObserver observer) {\n        mReportObserverList.remove(observer);\n    }\n\n    public void clearReportObserverList() {\n        mReportObserverList.clear();\n    }\n\n    /**\n     * Load field information from xml to memory.\n     * \n     * @param className of the class being examined which will be shown in error messages\n     * @param parser The XmlPullParser which carries the xml information.\n     * @return the new field\n     */\n    private JDiffField loadFieldInfo(String className, XmlPullParser parser) {\n        String fieldName = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n        String fieldType = parser.getAttributeValue(null, ATTRIBUTE_TYPE);\n        int modifier = jdiffModifierToReflectionFormat(className, parser);\n        return new JDiffField(fieldName, fieldType, modifier);\n    }\n\n    /**\n     * Load method information from xml to memory.\n     * \n     * @param className of the class being examined which will be shown in error messages\n     * @param parser The XmlPullParser which carries the xml information.\n     * @return the newly loaded method.\n     */\n    private JDiffMethod loadMethodInfo(String className, XmlPullParser parser) {\n        String methodName = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n        String returnType = parser.getAttributeValue(null, ATTRIBUTE_RETURN);\n        int modifier = jdiffModifierToReflectionFormat(className, parser);\n        return new JDiffMethod(methodName, modifier, returnType);\n    }\n\n    /**\n     * Load constructor information from xml to memory.\n     * \n     * @param parser The XmlPullParser which carries the xml information.\n     * @param currentClass the current class being loaded.\n     * @return the new constructor\n     */\n    private JDiffConstructor loadConstructorInfo(XmlPullParser parser,\n            JDiffClassDescription currentClass) {\n        String name = currentClass.getClassName();\n        int modifier = jdiffModifierToReflectionFormat(name, parser);\n        return new JDiffConstructor(name, modifier);\n    }\n\n    /**\n     * Load class or interface information to memory.\n     * \n     * @param parser The XmlPullParser which carries the xml information.\n     * @param isInterface true if the current class is an interface, otherwise is false.\n     * @param pkg the name of the java package this class can be found in.\n     * @return the new class description.\n     */\n    private JDiffClassDescription loadClassInfo(XmlPullParser parser, boolean isInterface,\n            String pkg) {\n        String className = parser.getAttributeValue(null, ATTRIBUTE_NAME);\n        JDiffClassDescription currentClass = new JDiffClassDescription(pkg, className,\n                mResultObserver);\n        currentClass.setModifier(jdiffModifierToReflectionFormat(className, parser));\n        currentClass.setType(isInterface ? JDiffClassDescription.JDiffType.INTERFACE\n                : JDiffClassDescription.JDiffType.CLASS);\n        currentClass.setExtendsClass(parser.getAttributeValue(null, ATTRIBUTE_EXTENDS));\n        return currentClass;\n    }\n\n    /**\n     * Convert string modifier to int modifier.\n     * \n     * @param name of the class/method/field being examined which will be shown in error messages\n     * @param key modifier name\n     * @param value modifier value\n     * @return converted modifier value\n     */\n    private static int modifierDescriptionToReflectedType(String name, String key, String value) {\n        switch (key) {\n            case MODIFIER_ABSTRACT:\n                return value.equals(\"true\") ? Modifier.ABSTRACT : 0;\n            case MODIFIER_FINAL:\n                return value.equals(\"true\") ? Modifier.FINAL : 0;\n            case MODIFIER_NATIVE:\n                return value.equals(\"true\") ? Modifier.NATIVE : 0;\n            case MODIFIER_STATIC:\n                return value.equals(\"true\") ? Modifier.STATIC : 0;\n            case MODIFIER_SYNCHRONIZED:\n                return value.equals(\"true\") ? Modifier.SYNCHRONIZED : 0;\n            case MODIFIER_TRANSIENT:\n                return value.equals(\"true\") ? Modifier.TRANSIENT : 0;\n            case MODIFIER_VOLATILE:\n                return value.equals(\"true\") ? Modifier.VOLATILE : 0;\n            case MODIFIER_VISIBILITY:\n                switch (value) {\n                    case MODIFIER_PRIVATE:\n                        throw new RuntimeException(\"Private visibility found in API spec: \" + name);\n                    case MODIFIER_PROTECTED:\n                        return Modifier.PROTECTED;\n                    case MODIFIER_PUBLIC:\n                        return Modifier.PUBLIC;\n                    case \"\":\n                        // If the visibility is \"\", it means it has no modifier.\n                        // which is package private. We should return 0 for this modifier.\n                        return 0;\n                    default:\n                        throw new RuntimeException(\"Unknown modifier found in API spec: \" + value);\n                }\n        }\n        return 0;\n    }\n\n    /**\n     * Transfer string modifier to int one.\n     * \n     * @param name of the class/method/field being examined which will be shown in error messages\n     * @param parser XML resource parser\n     * @return converted modifier\n     */\n    private static int jdiffModifierToReflectionFormat(String name, XmlPullParser parser) {\n        int modifier = 0;\n        for (int i = 0; i < parser.getAttributeCount(); i++) {\n            modifier |= modifierDescriptionToReflectedType(name, parser.getAttributeName(i),\n                    parser.getAttributeValue(i));\n        }\n        return modifier;\n    }\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/SignatureTestActivity.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.tests.sigtest;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.Resources;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AdapterView;\nimport android.widget.ArrayAdapter;\nimport android.widget.ListView;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * This class is used for Signature Test. It will started by the Instrumentation class, and send\n * back the test result via IBinder.\n */\npublic class SignatureTestActivity extends Activity {\n    static final String BUNDLE_KEY_MISSING_CLASS = \"missing_class\";\n    static final String BUNDLE_KEY_MISSING_INTERFACE = \"missing_interface\";\n    static final String BUNDLE_KEY_MISSING_METHOD = \"missing_method\";\n    static final String BUNDLE_KEY_MISSING_FIELD = \"missing_field\";\n    static final String BUNDLE_KEY_MISMATCH_CLASS = \"mismatch_class_signature\";\n    static final String BUNDLE_KEY_MISMATCH_INTERFACE = \"mismatch_interface_signature\";\n    static final String BUNDLE_KEY_MISMATCH_METHOD = \"mismatch_method_signature\";\n    static final String BUNDLE_KEY_MISMATCH_FIELD = \"mismatch_field_signature\";\n    static final String BUNDLE_KEY_CAUGHT_EXCEPTION = \"caught_exception\";\n\n    private DeviceResultObserver mResultObserver;\n\n    private Bundle mBundle;\n\n    private List<RcsApiSignatureTestResult> mFailedItems = new ArrayList<>();\n    private ListView mListView;\n\n    private static final String CURRENT_RELEASE = \"crane_1_6_1\";\n\n    // @formatter:off\n    private static final Map<String,Integer> sRcsApiReleases = new HashMap<>();\n\n    static {\n        sRcsApiReleases.put(\"albatros\",R.xml.albatros);\n        sRcsApiReleases.put(\"blackbird_1_0\",R.xml.blackbird_1_0);\n        sRcsApiReleases.put(\"blackbird_1_5_1\", R.xml.blackbird_1_5_1);\n        sRcsApiReleases.put(CURRENT_RELEASE, R.xml.crane_1_6_1);\n    }\n    // @formatter:on\n\n    private ArrayAdapter<String> mSpinnerAdapter;\n    private int mSelectedResource;\n    private TestSigResultArrayAdapter mAdpater;\n\n    /**\n     * Define the type of the signature check failures.\n     */\n    public enum FAILURE_TYPE {\n        MISSING_CLASS, MISSING_INTERFACE, MISSING_METHOD, MISSING_FIELD, MISMATCH_CLASS, MISMATCH_INTERFACE, MISMATCH_METHOD, MISMATCH_FIELD, CAUGHT_EXCEPTION,\n    }\n\n    static final HashMap<FAILURE_TYPE, String> FAILURE_TYPE_TO_KEY = new HashMap<>();\n\n    static {\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_CLASS, BUNDLE_KEY_MISSING_CLASS);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_INTERFACE, BUNDLE_KEY_MISSING_INTERFACE);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_METHOD, BUNDLE_KEY_MISSING_METHOD);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_FIELD, BUNDLE_KEY_MISSING_FIELD);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_CLASS, BUNDLE_KEY_MISMATCH_CLASS);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_INTERFACE, BUNDLE_KEY_MISMATCH_INTERFACE);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_METHOD, BUNDLE_KEY_MISMATCH_METHOD);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_FIELD, BUNDLE_KEY_MISMATCH_FIELD);\n        FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.CAUGHT_EXCEPTION, BUNDLE_KEY_CAUGHT_EXCEPTION);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.rcs_api_signature);\n\n        AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {\n\n            @Override\n            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n                String selectedVersion = mSpinnerAdapter.getItem(position);\n                Log.w(\"[RCS]\", \"Selected version=\" + selectedVersion);\n                Integer resourceId = sRcsApiReleases.get(selectedVersion);\n                if (resourceId != null) {\n                    mSelectedResource = resourceId;\n                    mFailedItems.clear();\n                    mListView.setAdapter(null);\n                    CheckRcsApiSignatureTask mCheckRcsApiSignatureTask = new CheckRcsApiSignatureTask();\n                    mCheckRcsApiSignatureTask.execute();\n                }\n            }\n\n            @Override\n            public void onNothingSelected(AdapterView<?> parent) {\n\n            }\n        };\n        Spinner spinner = (Spinner) findViewById(R.id.spinner_rcs_version);\n        String[] versions = sRcsApiReleases.keySet().toArray(new String[sRcsApiReleases.size()]);\n        Arrays.sort(versions);\n        mSpinnerAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, versions);\n        spinner.setAdapter(mSpinnerAdapter);\n        int defaultSpinnerPosition = mSpinnerAdapter.getPosition(CURRENT_RELEASE);\n        spinner.setSelection(defaultSpinnerPosition);\n        spinner.setOnItemSelectedListener(listener);\n        mSelectedResource = ToTest.VERSION;\n\n        // Set list adapter\n        mListView = (ListView) findViewById(R.id.report_list);\n        TextView emptyView = (TextView) findViewById(android.R.id.empty);\n        mListView.setEmptyView(emptyView);\n    }\n\n    private class CheckRcsApiSignatureTask extends AsyncTask<Void, Void, Void> {\n\n        @Override\n        protected Void doInBackground(Void... params) {\n            Log.w(\"[RCS]\", \"Starts verifying RCS signatures\");\n            mResultObserver = new DeviceResultObserver();\n            start();\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(Void aVoid) {\n            mResultObserver.sendResult(getIntent());\n            Log.w(\"[RCS]\", \"Ends verifying RCS signatures\");\n        }\n    }\n\n    private class TestSigResultArrayAdapter extends ArrayAdapter<RcsApiSignatureTestResult> {\n\n        private final Context mCtx;\n        private final int mResourceRowLayout;\n        private final LayoutInflater mInflater;\n\n        public TestSigResultArrayAdapter(Context ctx, int resourceRowLayout,\n                List<RcsApiSignatureTestResult> items) {\n            super(ctx, 0, items);\n            mCtx = ctx;\n            mResourceRowLayout = resourceRowLayout;\n            mInflater = LayoutInflater.from(mCtx);\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            final RcsApiSignatureTestResultViewHolder holder;\n            if (convertView == null) {\n                convertView = mInflater.inflate(mResourceRowLayout, parent, false);\n                holder = new RcsApiSignatureTestResultViewHolder(convertView);\n                convertView.setTag(holder);\n            } else {\n                holder = (RcsApiSignatureTestResultViewHolder) convertView.getTag();\n            }\n            RcsApiSignatureTestResult item = getItem(position);\n            if (item != null) {\n                holder.typeTextView.setText(item.getType().toString());\n                holder.classTextView.setText(item.getClassName());\n                holder.reasonTextView.setText(item.getReason());\n            }\n            return convertView;\n        }\n    }\n\n    /**\n     * Start the signature test.\n     */\n    @SuppressWarnings(\"unchecked\")\n    private void start() {\n        SignatureTest sigTest = new SignatureTest(mResultObserver);\n        Resources r = getResources();\n        try {\n            // TODO allow user to select version within available XML files\n            sigTest.start(r.getXml(mSelectedResource));\n        } catch (Exception e) {\n            mResultObserver.notifyFailure(FAILURE_TYPE.CAUGHT_EXCEPTION, e.getMessage(),\n                    e.getMessage());\n        }\n    }\n\n    /**\n     * This class is an implementation of the ResultObserver. And it aims to record the result in\n     * the Bundle, and send back to the Instrumentation class after all results has been recorded.\n     */\n    final public class DeviceResultObserver implements ResultObserver {\n        public DeviceResultObserver() {\n            mBundle = new Bundle();\n            mBundle.putStringArrayList(BUNDLE_KEY_MISSING_FIELD, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISSING_METHOD, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_CLASS, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_FIELD, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_METHOD, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISSING_CLASS, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISSING_INTERFACE, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_INTERFACE, new ArrayList<String>());\n            mBundle.putStringArrayList(BUNDLE_KEY_CAUGHT_EXCEPTION, new ArrayList<String>());\n        }\n\n        private int getFailedClassesNumber(String keyTestType) {\n            ArrayList<String> failedClasses = mBundle.getStringArrayList(keyTestType);\n            if (failedClasses != null) {\n                return failedClasses.size();\n            }\n            throw new IllegalStateException(\"Invalid bundle for test type \" + keyTestType);\n        }\n\n        /**\n         * This method is called when all the results has been recorded. And this method will save\n         * the results in IBinder and send back to the Instrumentation class.\n         *\n         * @param intent The intent to carry the result.\n         */\n        @SuppressWarnings(\"deprecation\")\n        public void sendResult(Intent intent) {\n            SignatureTestLog.d(\"Send result\");\n            int failedClassesNumber = 0;\n            if (mBundle == null) {\n                throw new IllegalStateException(\"Invalid bundle\");\n            }\n            for (String testType : mBundle.keySet()) {\n                failedClassesNumber += getFailedClassesNumber(testType);\n            }\n            TextView result = (TextView) findViewById(R.id.test_result);\n            if (failedClassesNumber == 0) {\n                SignatureTestLog.d(\"PASS\");\n                result.setText(R.string.test_passed);\n            } else {\n                SignatureTestLog.d(\"FAIL: \" + failedClassesNumber);\n                result.setText(getString(R.string.test_failed, failedClassesNumber));\n            }\n            mAdpater = new TestSigResultArrayAdapter(\n                    SignatureTestActivity.this, R.layout.rcs_api_signature_item, mFailedItems);\n            mListView.setAdapter(mAdpater);\n        }\n\n        public void notifyFailure(FAILURE_TYPE type, String name, String errorMessage) {\n            SignatureTestLog.d(\"Failure: \");\n            SignatureTestLog.d(\"   Type: \" + type);\n            SignatureTestLog.d(\"   Name: \" + name);\n            SignatureTestLog.d(\"   Why : \" + errorMessage);\n            mBundle.getStringArrayList(SignatureTestActivity.FAILURE_TYPE_TO_KEY.get(type)).add(\n                    name);\n            mFailedItems.add(new RcsApiSignatureTestResult(type, name, errorMessage));\n        }\n    }\n\n    private class RcsApiSignatureTestResultViewHolder {\n        public final TextView typeTextView;\n        public final TextView classTextView;\n        public final TextView reasonTextView;\n\n        public RcsApiSignatureTestResultViewHolder(View base) {\n            typeTextView = (TextView) base.findViewById(R.id.test_type);\n            classTextView = (TextView) base.findViewById(R.id.test_class_name);\n            reasonTextView = (TextView) base.findViewById(R.id.test_why);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/SignatureTestLog.java",
    "content": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage android.tests.sigtest;\n\nimport android.util.Log;\n\npublic class SignatureTestLog {\n    private static final String TAG = \"CTSSignatureTest\";\n\n    public static void e(String msg, Exception e) {\n        Log.e(TAG, msg, e);\n    }\n\n    public static void d(String msg) {\n        Log.d(TAG, msg);\n    }\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/java/android/tests/sigtest/ToTest.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage android.tests.sigtest;\n\n/**\n * RCS version to be tested\n * \n * @author Jean-Marc AUFFRET\n */\npublic class ToTest {\n    public static int VERSION = R.xml.crane_1_6_1;\n}\n"
  },
  {
    "path": "tests/cts/signature/src/main/res/layout/rcs_api_signature.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n\n    <Spinner\n        android:id=\"@+id/spinner_rcs_version\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"50dip\"\n        android:layout_margin=\"20dip\"\n        android:drawSelectorOnTop=\"true\" />\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_result\" />\n\n        <TextView android:id=\"@+id/test_result\" />\n    </TableRow>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"@android:color/darker_gray\"/>\n\n    <ListView\n        android:id=\"@+id/report_list\"\n        android:layout_width=\"fill_parent\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\"\n        android:paddingTop=\"5dip\" />\n\n</TableLayout>"
  },
  {
    "path": "tests/cts/signature/src/main/res/layout/rcs_api_signature_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TableLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:padding=\"10dip\"\n    android:stretchColumns=\"1\">\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_type\" />\n\n        <TextView android:id=\"@+id/test_type\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_name\" />\n\n        <TextView android:id=\"@+id/test_class_name\" />\n    </TableRow>\n\n    <TableRow android:padding=\"2dip\">\n\n        <TextView\n            android:layout_marginEnd=\"5dip\"\n            android:layout_marginRight=\"5dip\"\n            android:text=\"@string/label_why\" />\n\n        <TextView android:id=\"@+id/test_why\" />\n    </TableRow>\n\n</TableLayout>"
  },
  {
    "path": "tests/cts/signature/src/main/res/raw/excludepackages.txt",
    "content": ""
  },
  {
    "path": "tests/cts/signature/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">RCS ApiSigTest</string>\n    <string name=\"label_result\">Test result:</string>\n    <string name=\"label_type\">Type:</string>\n    <string name=\"label_name\">Name:</string>\n    <string name=\"label_why\">Reason:</string>\n    <string name=\"test_passed\">PASS</string>\n    <string name=\"test_failed\">FAILED (%1$d)</string>\n    <string name=\"title_sig_test_activity\">RCS ApiSigTest</string>\n</resources>"
  },
  {
    "path": "tests/cts/signature/src/main/res/xml/albatros.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"Intents\"\n type=\"com.gsma.services.rcs.Intents\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Client\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_CLIENT_GET_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;.client.action.GET_STATUS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_SETTINGS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_SETTINGS&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CLIENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;client&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynContactFormatException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynContactFormatException\"\n type=\"com.gsma.services.rcs.JoynContactFormatException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService\"\n type=\"com.gsma.services.rcs.JoynService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GSMA_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.GSMA_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.GSMA_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.GSMA_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"RCSE_BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"RCSE_HOTFIXES_1_2\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynService.Build.VERSION_CODES\"\n type=\"com.gsma.services.rcs.JoynService.Build.VERSION_CODES\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynService.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CONNECTION_LOST\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SERVICE_DISABLED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"JoynServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceConfiguration\"\n type=\"com.gsma.services.rcs.JoynServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getUserDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isServiceActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n</class>\n<class name=\"JoynServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceException\"\n type=\"com.gsma.services.rcs.JoynServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<interface name=\"JoynServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n</interface>\n<class name=\"JoynServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.JoynServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.JoynServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.JoynServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"JoynServiceRegistrationListener\"\n extends=\"com.gsma.services.rcs.IJoynServiceRegistrationListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynUtils\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"JoynUtils\"\n type=\"com.gsma.services.rcs.JoynUtils\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getJoynClients\"\n return=\"java.util.List&lt;android.content.pm.ResolveInfo&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isJoynClientActivated\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n<parameter name=\"receiverResult\" type=\"android.content.BroadcastReceiver\">\n</parameter>\n</method>\n<method name=\"loadJoynClientSettings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"Capabilities\"\n type=\"com.gsma.services.rcs.capability.Capabilities\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"imageSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"videoSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"imSession\" type=\"boolean\">\n</parameter>\n<parameter name=\"fileTransfer\" type=\"boolean\">\n</parameter>\n<parameter name=\"extensions\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</constructor>\n<constructor name=\"Capabilities\"\n type=\"com.gsma.services.rcs.capability.Capabilities\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"com.gsma.services.rcs.capability.ICapabilitiesListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesLog\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<field name=\"EXTENSION_BASE_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;+g.3gpp.iari-ref&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTENSION_PREFIX_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;urn%3Aurn-7%3A3gpp-application.ims.iari.rcse&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatIntent\"\n type=\"com.gsma.services.rcs.chat.ChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;message&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatListener\"\n extends=\"com.gsma.services.rcs.chat.IChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatListener\"\n type=\"com.gsma.services.rcs.chat.ChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog\"\n type=\"com.gsma.services.rcs.chat.ChatLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.GroupChat\"\n type=\"com.gsma.services.rcs.chat.ChatLog.GroupChat\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BODY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;body&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sender&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_CHAT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Direction\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"IRRELEVANT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n</class>\n<class name=\"ChatLog.Message.Status.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.Content\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.Content\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"BLOCKED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TO_SEND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNREAD_REPORT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Status.System\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Status.System\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.System\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACCEPTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BUSY\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISCONNECTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GONE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"JOINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PENDING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Type\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatLog.Message.Type\"\n type=\"com.gsma.services.rcs.chat.ChatLog.Message.Type\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTENT\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SYSTEM\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"ChatMessage\"\n type=\"com.gsma.services.rcs.chat.ChatMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"messageId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remote\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"receiptAt\" type=\"java.util.Date\">\n</parameter>\n<parameter name=\"displayedReportRequested\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"ChatMessage\"\n type=\"com.gsma.services.rcs.chat.ChatMessage\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getReceiptDate\"\n return=\"java.util.Date\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedReportRequested\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatFor\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.Chat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChatFor\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChats\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.chat.GroupChat&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"openSingleChat\"\n return=\"com.gsma.services.rcs.chat.Chat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejoinGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewChatListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"restartGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatServiceConfiguration\"\n type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSF\" type=\"boolean\">\n</parameter>\n<parameter name=\"chatTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"isComposingTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"maxGroupChatParticipants\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthSingleChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthGroupChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxChat\" type=\"int\">\n</parameter>\n<parameter name=\"smsFallback\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptSingleChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptGroupChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"displayedDeliveryReport\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"ChatServiceConfiguration\"\n type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMaxParticipantsNumber\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxChatSessions\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSingleChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isDisplayedDeliveryReport\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGroupChatAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setDisplayedDeliveryReport\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"state\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"quitConversation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChat.Direction\"\n type=\"com.gsma.services.rcs.chat.GroupChat.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"CHAT_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_NOT_FOUND\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CLOSED_BY_USER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatIntent\"\n type=\"com.gsma.services.rcs.chat.GroupChatIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"com.gsma.services.rcs.chat.IGroupChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onParticipantDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantJoined\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contactDisplayname\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantLeft\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSessionAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSessionError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSessionStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"NewChatListener\"\n extends=\"com.gsma.services.rcs.chat.INewChatListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewChatListener\"\n type=\"com.gsma.services.rcs.chat.NewChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewGroupChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onNewSingleChat\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contacts\"\n>\n<class name=\"ContactsProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsProvider\"\n type=\"com.gsma.services.rcs.contacts.ContactsProvider\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-sharing&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactsService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactsService\"\n type=\"com.gsma.services.rcs.contacts.ContactsService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getJoynContact\"\n return=\"com.gsma.services.rcs.contacts.JoynContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"JoynContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"JoynContact\"\n type=\"com.gsma.services.rcs.contacts.JoynContact\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"registered\" type=\"boolean\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</constructor>\n<constructor name=\"JoynContact\"\n type=\"com.gsma.services.rcs.contacts.JoynContact\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ft\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransfer.Direction\"\n type=\"com.gsma.services.rcs.ft.FileTransfer.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFER_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferIntent\"\n type=\"com.gsma.services.rcs.ft.FileTransferIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ft.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.IFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferListener\"\n type=\"com.gsma.services.rcs.ft.FileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onFileTransferred\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onTransferAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onTransferError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onTransferProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onTransferStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferLog\"\n type=\"com.gsma.services.rcs.ft.FileTransferLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.ft.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransferFor\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfers\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ft.FileTransfer&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewFileTransferListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.ft.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"FileTransferServiceConfiguration\"\n type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n<parameter name=\"autoAcceptMode\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"FileTransferServiceConfiguration\"\n type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutoAcceptMode\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewFileTransferListener\"\n extends=\"com.gsma.services.rcs.ft.INewFileTransferListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewFileTransferListener\"\n type=\"com.gsma.services.rcs.ft.NewFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewFileTransfer\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ish\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharing.Direction\"\n type=\"com.gsma.services.rcs.ish.ImageSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SAVING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingIntent\"\n type=\"com.gsma.services.rcs.ish.ImageSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.ish.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FILETYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filetype&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.IImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onImageShared\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingLog\"\n type=\"com.gsma.services.rcs.ish.ImageSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.ish.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageShares\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.ish.ImageSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharingFor\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewImageSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.ish.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"ImageSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"NewImageSharingListener\"\n extends=\"com.gsma.services.rcs.ish.INewImageSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewImageSharingListener\"\n type=\"com.gsma.services.rcs.ish.NewImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewImageSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.vsh\"\n>\n<class name=\"NewVideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.INewVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"NewVideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onNewVideoSharing\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.vsh.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"clockRate\" type=\"int\">\n</parameter>\n<parameter name=\"frameRate\" type=\"int\">\n</parameter>\n<parameter name=\"bitRate\" type=\"int\">\n</parameter>\n<parameter name=\"width\" type=\"int\">\n</parameter>\n<parameter name=\"height\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"VideoCodec\"\n type=\"com.gsma.services.rcs.vsh.VideoCodec\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayload\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getVideoWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoPlayerListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoPlayerListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoPlayerListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayerListener\"\n type=\"com.gsma.services.rcs.vsh.VideoPlayerListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPlayerClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onPlayerStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRenderer.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRenderer\"\n type=\"com.gsma.services.rcs.vsh.VideoRenderer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"close\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEventListeners\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoRendererListener&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.vsh.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"open\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"start\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"stop\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoRenderer.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INTERNAL_ERROR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NETWORK_FAILURE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoRendererListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoRendererListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoRendererListener\"\n type=\"com.gsma.services.rcs.vsh.VideoRendererListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onRendererClosed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onRendererStopped\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.vsh.VideoRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoFormat\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Direction\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharing.Direction\"\n type=\"com.gsma.services.rcs.vsh.VideoSharing.Direction\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"INCOMING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"OUTGOING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.Error\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"INVITATION_DECLINED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ABORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FAILED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"7\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INITIATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INVITED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STARTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TERMINATED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"6\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingIntent\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingIntent\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.vsh.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contactDisplayname&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_FORMAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;format&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"com.gsma.services.rcs.vsh.IVideoSharingListener.Stub\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onSharingAborted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onSharingError\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingLog\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingLog\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<field name=\"CONTACT_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact_number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.JoynService\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharingFor\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharings\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.VideoSharing&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewVideoSharingListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.vsh.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.vsh.VideoPlayer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"maxTime\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"VideoSharingServiceConfiguration\"\n type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"writeToParcel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\"\n type=\"android.os.Parcelable.Creator\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n</api>"
  },
  {
    "path": "tests/cts/signature/src/main/res/xml/blackbird_1_0.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\">\n<class name=\"JoynContactFormatException\" extends=\"com.gsma.services.rcs.JoynServiceException\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n</class>\n<class name=\"JoynService\" extends=\"java.lang.Object\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynService\" type=\"com.gsma.services.rcs.JoynService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"JoynService.Build\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"API_CODENAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;GSMA&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"API_INCREMENTAL\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"API_VERSION\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"GSMA_VERSION\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"JoynService.Build.GSMA_CODES\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynService.Build.GSMA_CODES\" type=\"com.gsma.services.rcs.JoynService.Build.GSMA_CODES\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"RCSE_BLACKBIRD\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"RCSE_HOTFIXES_1_2\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"JoynService.Build.VERSION_CODES\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynService.Build.VERSION_CODES\" type=\"com.gsma.services.rcs.JoynService.Build.VERSION_CODES\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"BASE\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"JoynService.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"CONNECTION_LOST\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INTERNAL_ERROR\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SERVICE_DISABLED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"JoynServiceConfiguration\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynServiceConfiguration\" type=\"com.gsma.services.rcs.JoynServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"getUserDisplayName\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isServiceActivated\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n</class>\n<class name=\"JoynServiceException\" extends=\"java.lang.Exception\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<interface name=\"JoynServiceListener\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"onServiceConnected\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onServiceDisconnected\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n</interface>\n<class name=\"JoynServiceNotAvailableException\" extends=\"com.gsma.services.rcs.JoynServiceException\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynServiceNotAvailableException\" type=\"com.gsma.services.rcs.JoynServiceNotAvailableException\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n</class>\n<class name=\"JoynServiceNotRegisteredException\" extends=\"com.gsma.services.rcs.JoynServiceException\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynServiceNotRegisteredException\" type=\"com.gsma.services.rcs.JoynServiceNotRegisteredException\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n</class>\n<class name=\"JoynServiceRegistrationListener\" extends=\"com.gsma.services.rcs.IJoynServiceRegistrationListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynServiceRegistrationListener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onServiceRegistered\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onServiceUnregistered\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"JoynUtils\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"JoynUtils\" type=\"com.gsma.services.rcs.JoynUtils\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"getJoynClients\" return=\"java.util.List&lt;android.content.pm.ResolveInfo&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isJoynClientActivated\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n<parameter name=\"receiverResult\" type=\"android.content.BroadcastReceiver\">\n</parameter>\n</method>\n<method name=\"loadJoynClientSettings\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"appInfo\" type=\"android.content.pm.ResolveInfo\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\">\n<class name=\"Capabilities\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"Capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"imageSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"videoSharing\" type=\"boolean\">\n</parameter>\n<parameter name=\"imSession\" type=\"boolean\">\n</parameter>\n<parameter name=\"fileTransfer\" type=\"boolean\">\n</parameter>\n<parameter name=\"geolocPush\" type=\"boolean\">\n</parameter>\n<parameter name=\"ipVoiceCall\" type=\"boolean\">\n</parameter>\n<parameter name=\"ipVideoCall\" type=\"boolean\">\n</parameter>\n<parameter name=\"extensions\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</constructor>\n<constructor name=\"Capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedExtensions\" return=\"java.util.Set&lt;java.lang.String&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isExtensionSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isGeolocPushSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isIPVideoCallSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isIPVoiceCallSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isImSessionSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isImageSharingSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isVideoSharingSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"CapabilitiesListener\" extends=\"com.gsma.services.rcs.capability.ICapabilitiesListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"CapabilitiesListener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onCapabilitiesReceived\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"CapabilitiesLog\" type=\"com.gsma.services.rcs.capability.CapabilitiesLog\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CAPABILITY_EXTENSIONS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_extensions&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_file_transfer&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_geoloc_push&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_image_share&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_IM_SESSION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_im_session&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_IP_VIDEO_CALL\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_ip_video_call&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_IP_VOICE_CALL\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_ip_voice_call&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;capability_video_share&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTACT_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact_number&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"NOT_SUPPORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SUPPORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"CapabilityService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"CapabilityService\" type=\"com.gsma.services.rcs.capability.CapabilityService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getContactCapabilities\" return=\"com.gsma.services.rcs.capability.Capabilities\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\" return=\"com.gsma.services.rcs.capability.Capabilities\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<field name=\"EXTENSION_BASE_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;+g.3gpp.iari-ref&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTENSION_PREFIX_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;urn%3Aurn-7%3A3gpp-application.ims.iari.rcse&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INTENT_EXTENSIONS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\">\n<class name=\"Chat\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendDisplayedDeliveryReport\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendGeoloc\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatIntent\" type=\"com.gsma.services.rcs.chat.ChatIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_CHAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.chat.action.NEW_CHAT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_MESSAGE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;message&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatListener\" extends=\"com.gsma.services.rcs.chat.IChatListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatListener\" type=\"com.gsma.services.rcs.chat.ChatListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onComposingEvent\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"ChatLog\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog\" type=\"com.gsma.services.rcs.chat.ChatLog\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n</class>\n<class name=\"ChatLog.GroupChat\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.GroupChat\" type=\"com.gsma.services.rcs.chat.ChatLog.GroupChat\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CHAT_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;chat_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DIRECTION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;direction&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STATE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;state&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SUBJECT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;subject&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatLog.Message\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.Message\" type=\"com.gsma.services.rcs.chat.ChatLog.Message\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"BODY\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;body&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CHAT_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;chat_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTACT_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;sender&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_CHAT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DIRECTION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;direction&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MESSAGE_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;msg_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MESSAGE_STATUS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;status&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MESSAGE_TYPE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;msg_type&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;mime_type&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP_DELIVERED\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp_delivered&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp_displayed&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP_SENT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp_sent&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatLog.Message.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.Message.Direction\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"IRRELEVANT\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatLog.Message.Status\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.Message.Status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n</class>\n<class name=\"ChatLog.Message.Status.Content\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.Message.Status.Content\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.Content\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"BLOCKED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"7\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"READ\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SENDING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SENT\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"4\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TO_SEND\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNREAD\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNREAD_REPORT\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatLog.Message.Status.System\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.Message.Status.System\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Status.System\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACCEPTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"BUSY\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"7\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DISCONNECTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"GONE\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"JOINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"4\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"PENDING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatLog.Message.Type\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatLog.Message.Type\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Type\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CONTENT\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FILE_TRANSFER\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"GEOLOC\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SYSTEM\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatMessage\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"ChatMessage\" type=\"com.gsma.services.rcs.chat.ChatMessage\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"messageId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remote\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"receiptAt\" type=\"java.util.Date\">\n</parameter>\n<parameter name=\"displayedReportRequested\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"ChatMessage\" type=\"com.gsma.services.rcs.chat.ChatMessage\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getMessage\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getReceiptDate\" return=\"java.util.Date\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isDisplayedReportRequested\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ChatService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatService\" type=\"com.gsma.services.rcs.chat.ChatService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewChatListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getChat\" return=\"com.gsma.services.rcs.chat.Chat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatFor\" return=\"com.gsma.services.rcs.chat.Chat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChats\" return=\"java.util.Set&lt;com.gsma.services.rcs.chat.Chat&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getConfiguration\" return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChat\" return=\"com.gsma.services.rcs.chat.GroupChat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChatFor\" return=\"com.gsma.services.rcs.chat.GroupChat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGroupChats\" return=\"java.util.Set&lt;com.gsma.services.rcs.chat.GroupChat&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\" return=\"com.gsma.services.rcs.chat.GroupChat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contacts\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"openSingleChat\" return=\"com.gsma.services.rcs.chat.Chat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.ChatListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejoinGroupChat\" return=\"com.gsma.services.rcs.chat.GroupChat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewChatListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.NewChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"restartGroupChat\" return=\"com.gsma.services.rcs.chat.GroupChat\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ChatServiceConfiguration\" type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"warnSF\" type=\"boolean\">\n</parameter>\n<parameter name=\"chatTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"isComposingTimeout\" type=\"int\">\n</parameter>\n<parameter name=\"maxGroupChatParticipants\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthSingleChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxMsgLengthGroupChat\" type=\"int\">\n</parameter>\n<parameter name=\"maxGroupChat\" type=\"int\">\n</parameter>\n<parameter name=\"smsFallback\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptSingleChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"autoAcceptGroupChat\" type=\"boolean\">\n</parameter>\n<parameter name=\"displayedDeliveryReport\" type=\"boolean\">\n</parameter>\n<parameter name=\"maxGeolocLabelLength\" type=\"int\">\n</parameter>\n<parameter name=\"geolocExpireTime\" type=\"int\">\n</parameter>\n</constructor>\n<constructor name=\"ChatServiceConfiguration\" type=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getChatTimeout\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getGeolocExpirationTime\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getGeolocLabelMaxLength\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getGroupChatMaxParticipantsNumber\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getGroupChatMessageMaxLength\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getIsComposingTimeout\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getMaxGroupChats\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSingleChatMessageMaxLength\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isChatAutoAcceptMode\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isChatWarnSF\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isDisplayedDeliveryReport\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isGroupChatAutoAcceptMode\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isSmsFallback\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"setDisplayedDeliveryReport\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"state\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"Geoloc\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"Geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getAccuracy\" return=\"float\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getAltitude\" return=\"double\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getExpiration\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLabel\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLatitude\" return=\"double\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLongitude\" return=\"double\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"setAcuracy\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</method>\n<method name=\"setAltitude\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"altitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"setExpiration\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n</method>\n<method name=\"setLabel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"setLatitude\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"setLongitude\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GeolocMessage\" extends=\"com.gsma.services.rcs.chat.ChatMessage\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"GeolocMessage\" type=\"com.gsma.services.rcs.chat.GeolocMessage\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"messageId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remote\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<parameter name=\"receiptAt\" type=\"java.util.Date\">\n</parameter>\n<parameter name=\"imdnDisplayedRequested\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"GeolocMessage\" type=\"com.gsma.services.rcs.chat.GeolocMessage\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"geolocToString\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n</method>\n<method name=\"getGeoloc\" return=\"com.gsma.services.rcs.chat.Geoloc\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"stringToGeoloc\" return=\"com.gsma.services.rcs.chat.Geoloc\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"str\" type=\"java.lang.String\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GroupChat\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"acceptInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addParticipants\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"participants\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getChatId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getParticipants\" return=\"java.util.Set&lt;java.lang.String&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSubject\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"quitConversation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendFile\" return=\"com.gsma.services.rcs.ft.FileTransfer\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"fileicon\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendGeoloc\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendIsComposingEvent\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"sendMessage\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GroupChat.Direction\" type=\"com.gsma.services.rcs.chat.GroupChat.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GroupChat.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"CHAT_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CHAT_NOT_FOUND\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITATION_DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GroupChat.State\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ABORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CLOSED_BY_USER\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"7\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INITIATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STARTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TERMINATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"4\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNKNOWN\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GroupChatIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GroupChatIntent\" type=\"com.gsma.services.rcs.chat.GroupChatIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CHAT_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;chatId&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_SUBJECT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;subject&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GroupChatListener\" extends=\"com.gsma.services.rcs.chat.IGroupChatListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GroupChatListener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onComposingEvent\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onNewMessage\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n<method name=\"onParticipantDisconnected\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantJoined\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contactDisplayname\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onParticipantLeft\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDelivered\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageDisplayed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onReportMessageFailed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSessionAborted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onSessionError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSessionStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"NewChatListener\" extends=\"com.gsma.services.rcs.chat.INewChatListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"NewChatListener\" type=\"com.gsma.services.rcs.chat.NewChatListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onNewGroupChat\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onNewSingleChat\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"message\" type=\"com.gsma.services.rcs.chat.ChatMessage\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contacts\">\n<class name=\"ContactsProvider\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ContactsProvider\" type=\"com.gsma.services.rcs.contacts.ContactsProvider\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"MIME_TYPE_EXTENSIONS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARING\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-sharing&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_IP_VIDEO_CALL\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.ip-video-call&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_IP_VOICE_CALL\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.ip-voice-call&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARING\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-sharing&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ContactsService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ContactsService\" type=\"com.gsma.services.rcs.contacts.ContactsService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getJoynContact\" return=\"com.gsma.services.rcs.contacts.JoynContact\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContacts\" return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsOnline\" return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getJoynContactsSupporting\" return=\"java.util.Set&lt;com.gsma.services.rcs.contacts.JoynContact&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVCard\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"JoynContact\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"JoynContact\" type=\"com.gsma.services.rcs.contacts.JoynContact\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contactId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"registered\" type=\"boolean\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</constructor>\n<constructor name=\"JoynContact\" type=\"com.gsma.services.rcs.contacts.JoynContact\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getCapabilities\" return=\"com.gsma.services.rcs.capability.Capabilities\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getContactId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ft\">\n<class name=\"FileTransfer\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"FileTransfer\" type=\"com.gsma.services.rcs.ft.FileTransfer\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"transferIntf\" type=\"com.gsma.services.rcs.ft.IFileTransfer\">\n</parameter>\n</constructor>\n<method name=\"abortTransfer\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileIconName\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getTransferId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"FileTransfer.Direction\" type=\"com.gsma.services.rcs.ft.FileTransfer.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"FileTransfer.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INVITATION_DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SAVING_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TRANSFER_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"FileTransfer.State\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ABORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INITIATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STARTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TRANSFERRED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"4\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNKNOWN\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"FileTransferIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"FileTransferIntent\" type=\"com.gsma.services.rcs.ft.FileTransferIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.ft.action.NEW_FILE_TRANSFER&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILEICON\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;fileicon&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILENAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filename&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILESIZE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filesize&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILETYPE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filetype&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_TRANSFER_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;transferId&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"FileTransferListener\" extends=\"com.gsma.services.rcs.ft.IFileTransferListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"FileTransferListener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onFileTransferred\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onTransferAborted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onTransferError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onTransferProgress\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onTransferStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"FileTransferLog\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"FileTransferLog\" type=\"com.gsma.services.rcs.ft.FileTransferLog\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CONTACT_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact_number&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DIRECTION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;direction&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FILEICON\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;fileicon&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FILENAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filename&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FILESIZE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filesize&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FT_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;ft_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;mime_type&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STATE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;state&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TRANSFERRED\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;transferred&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"FileTransferService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"FileTransferService\" type=\"com.gsma.services.rcs.ft.FileTransferService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewFileTransferListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getConfiguration\" return=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\" return=\"com.gsma.services.rcs.ft.FileTransfer\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransferFor\" return=\"com.gsma.services.rcs.ft.FileTransfer\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileTransfers\" return=\"java.util.Set&lt;com.gsma.services.rcs.ft.FileTransfer&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewFileTransferListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\" return=\"com.gsma.services.rcs.ft.FileTransfer\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"transferFile\" return=\"com.gsma.services.rcs.ft.FileTransfer\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"fileicon\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ft.FileTransferListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"FileTransferServiceConfiguration\" type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n<parameter name=\"autoAcceptMode\" type=\"boolean\">\n</parameter>\n<parameter name=\"fileIcon\" type=\"boolean\">\n</parameter>\n<parameter name=\"maxFileIconSize\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"FileTransferServiceConfiguration\" type=\"com.gsma.services.rcs.ft.FileTransferServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getMaxFileIconSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getMaxSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getWarnSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isAutoAcceptMode\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isFileIconSupported\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"NewFileTransferListener\" extends=\"com.gsma.services.rcs.ft.INewFileTransferListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"NewFileTransferListener\" type=\"com.gsma.services.rcs.ft.NewFileTransferListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onNewFileTransfer\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.gsh\">\n<class name=\"GeolocSharing\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"abortSharing\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeoloc\" return=\"com.gsma.services.rcs.chat.Geoloc\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GeolocSharing.Direction\" type=\"com.gsma.services.rcs.gsh.GeolocSharing.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GeolocSharing.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INVITATION_DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SHARING_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GeolocSharing.State\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ABORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INITIATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STARTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TRANSFERRED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"4\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNKNOWN\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GeolocSharingIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GeolocSharingIntent\" type=\"com.gsma.services.rcs.gsh.GeolocSharingIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.ish.action.NEW_GEOLOC_SHARING&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_SHARING_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;sharingId&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"GeolocSharingListener\" extends=\"com.gsma.services.rcs.gsh.IGeolocSharingListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GeolocSharingListener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onGeolocShared\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onSharingError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"GeolocSharingService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"GeolocSharingService\" type=\"com.gsma.services.rcs.gsh.GeolocSharingService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewGeolocSharingListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getGeolocSharing\" return=\"com.gsma.services.rcs.gsh.GeolocSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeolocSharingFor\" return=\"com.gsma.services.rcs.gsh.GeolocSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getGeolocSharings\" return=\"java.util.Set&lt;com.gsma.services.rcs.gsh.GeolocSharing&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewGeolocSharingListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\" return=\"com.gsma.services.rcs.gsh.GeolocSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.chat.Geoloc\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.gsh.GeolocSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"NewGeolocSharingListener\" extends=\"com.gsma.services.rcs.gsh.INewGeolocSharingListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"NewGeolocSharingListener\" type=\"com.gsma.services.rcs.gsh.NewGeolocSharingListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onNewGeolocSharing\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.intent\">\n<class name=\"ChatIntents\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ACTION_INITIATE_CHAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.INITIATE_CHAT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ACTION_VIEW_CHAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.VIEW_CHAT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ClientIntents\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ACTION_CLIENT_GET_STATUS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;.client.action.GET_STATUS&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ACTION_VIEW_SETTINGS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.VIEW_SETTINGS&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CLIENT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;client&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_STATUS\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;status&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"FileTransferIntents\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ACTION_INITIATE_FT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.INITIATE_FT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ACTION_VIEW_FT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.VIEW_FT&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCallIntents\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ACTION_INITIATE_IPCALL\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.INITIATE_IPCALL&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ACTION_VIEW_IPCALL\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.action.VIEW_IPCALL&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ipcall\">\n<class name=\"AudioCodec\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"AudioCodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"sampleRate\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"AudioCodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"compare\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n</method>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEncoding\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getParameters\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getPayloadType\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSampleRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCall\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"abortCall\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addVideo\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"continueCall\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getCallId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"holdCall\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isOnHold\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeVideo\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"IPCall.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCall.Direction\" type=\"com.gsma.services.rcs.ipcall.IPCall.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCall.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"CALL_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITATION_DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCall.State\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ABORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"7\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"HOLD\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"8\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INITIATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STARTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TERMINATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNKNOWN\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCallIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallIntent\" type=\"com.gsma.services.rcs.ipcall.IPCallIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.ipcall.action.NEW_CALL&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_AUDIO_ENCODING\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;audioEncoding&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CALL_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;callId&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_VIDEO_ENCODING\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;videoEncoding&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_VIDEO_FORMAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;videoFormat&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCallListener\" extends=\"com.gsma.services.rcs.ipcall.IIPCallListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallListener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onCallAborted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onCallContinue\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onCallError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onCallHeld\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onCallStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"IPCallLog\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallLog\" type=\"com.gsma.services.rcs.ipcall.IPCallLog\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CALL_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;call_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTACT_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact_number&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DIRECTION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;direction&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DURATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;duration&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STATE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;state&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCallPlayer\" extends=\"com.gsma.services.rcs.ipcall.IIPCallPlayer.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallPlayer\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getAudioCodec\" return=\"com.gsma.services.rcs.ipcall.AudioCodec\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEventListeners\" return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IIPCallPlayerListener&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLocalAudioRtpPort\" return=\"int\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLocalVideoRtpPort\" return=\"int\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedAudioCodecs\" return=\"com.gsma.services.rcs.ipcall.AudioCodec[]\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedVideoCodecs\" return=\"com.gsma.services.rcs.ipcall.VideoCodec[]\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getVideoCodec\" return=\"com.gsma.services.rcs.ipcall.VideoCodec\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"open\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"audiocodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n<parameter name=\"videocodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remoteAudioPort\" type=\"int\">\n</parameter>\n<parameter name=\"remoteVideoPort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"stop\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"IPCallPlayer.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INTERNAL_ERROR\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"NETWORK_FAILURE\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCallPlayerListener\" extends=\"com.gsma.services.rcs.ipcall.IIPCallPlayerListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallPlayerListener\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayerListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onPlayerClosed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onPlayerError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onPlayerStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onPlayerStopped\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"IPCallRenderer\" extends=\"com.gsma.services.rcs.ipcall.IIPCallRenderer.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallRenderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener\">\n</parameter>\n</method>\n<method name=\"close\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getAudioCodec\" return=\"com.gsma.services.rcs.ipcall.AudioCodec\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEventListeners\" return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IIPCallRendererListener&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLocalVideoRtpPort\" return=\"int\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedAudioCodecs\" return=\"com.gsma.services.rcs.ipcall.AudioCodec[]\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedVideoCodecs\" return=\"com.gsma.services.rcs.ipcall.VideoCodec[]\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getVideoCodec\" return=\"com.gsma.services.rcs.ipcall.VideoCodec\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"open\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"audiocodec\" type=\"com.gsma.services.rcs.ipcall.AudioCodec\">\n</parameter>\n<parameter name=\"videocodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remoteAudioPort\" type=\"int\">\n</parameter>\n<parameter name=\"remoteVideoPort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener\">\n</parameter>\n</method>\n<method name=\"start\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"stop\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"IPCallRenderer.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INTERNAL_ERROR\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"NETWORK_FAILURE\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"IPCallRendererListener\" extends=\"com.gsma.services.rcs.ipcall.IIPCallRendererListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallRendererListener\" type=\"com.gsma.services.rcs.ipcall.IPCallRendererListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onRendererClosed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onRendererError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onRendererStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onRendererStopped\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"IPCallService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"IPCallService\" type=\"com.gsma.services.rcs.ipcall.IPCallService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewIPCallListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getConfiguration\" return=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCall\" return=\"com.gsma.services.rcs.ipcall.IPCall\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"callId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCallFor\" return=\"com.gsma.services.rcs.ipcall.IPCall\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getIPCalls\" return=\"java.util.Set&lt;com.gsma.services.rcs.ipcall.IPCall&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"initiateCall\" return=\"com.gsma.services.rcs.ipcall.IPCall\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.ipcall.IPCallPlayer\">\n</parameter>\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.ipcall.IPCallRenderer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.IPCallListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewIPCallListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"IPCallServiceConfiguration\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"IPCallServiceConfiguration\" type=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"voiceBreakout\" type=\"boolean\">\n</parameter>\n</constructor>\n<constructor name=\"IPCallServiceConfiguration\" type=\"com.gsma.services.rcs.ipcall.IPCallServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isVoiceCallBreakout\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"NewIPCallListener\" extends=\"com.gsma.services.rcs.ipcall.INewIPCallListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"NewIPCallListener\" type=\"com.gsma.services.rcs.ipcall.NewIPCallListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onNewCall\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"callId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoCodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"clockRate\" type=\"int\">\n</parameter>\n<parameter name=\"frameRate\" type=\"int\">\n</parameter>\n<parameter name=\"bitRate\" type=\"int\">\n</parameter>\n<parameter name=\"width\" type=\"int\">\n</parameter>\n<parameter name=\"height\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"VideoCodec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"compare\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.ipcall.VideoCodec\">\n</parameter>\n</method>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getBitRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getClockRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEncoding\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getFrameRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getParameters\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getPayloadType\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getVideoHeight\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getVideoWidth\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.ish\">\n<class name=\"ImageSharing\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"abortSharing\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileName\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getFileType\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ImageSharing.Direction\" type=\"com.gsma.services.rcs.ish.ImageSharing.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ImageSharing.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INVITATION_DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SAVING_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SHARING_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ImageSharing.State\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ABORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INITIATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STARTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TRANSFERRED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"4\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNKNOWN\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ImageSharingIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ImageSharingIntent\" type=\"com.gsma.services.rcs.ish.ImageSharingIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.ish.action.NEW_IMAGE_SHARING&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILENAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filename&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILESIZE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filesize&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FILETYPE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filetype&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_SHARING_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;sharingId&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ImageSharingListener\" extends=\"com.gsma.services.rcs.ish.IImageSharingListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ImageSharingListener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onImageShared\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onSharingAborted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onSharingError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingProgress\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"ImageSharingLog\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ImageSharingLog\" type=\"com.gsma.services.rcs.ish.ImageSharingLog\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CONTACT_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact_number&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DIRECTION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;direction&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FILENAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filename&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FILESIZE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;filesize&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"MIME_TYPE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;mime_type&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SHARING_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;sharing_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STATE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;state&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TRANSFERRED\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;transferred&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"ImageSharingService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ImageSharingService\" type=\"com.gsma.services.rcs.ish.ImageSharingService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewImageSharingListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getConfiguration\" return=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharing\" return=\"com.gsma.services.rcs.ish.ImageSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharingFor\" return=\"com.gsma.services.rcs.ish.ImageSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getImageSharings\" return=\"java.util.Set&lt;com.gsma.services.rcs.ish.ImageSharing&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewImageSharingListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareImage\" return=\"com.gsma.services.rcs.ish.ImageSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"filename\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.ish.ImageSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"ImageSharingServiceConfiguration\" type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"warnSize\" type=\"long\">\n</parameter>\n<parameter name=\"maxSize\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"ImageSharingServiceConfiguration\" type=\"com.gsma.services.rcs.ish.ImageSharingServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getMaxSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getWarnSize\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"NewImageSharingListener\" extends=\"com.gsma.services.rcs.ish.INewImageSharingListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"NewImageSharingListener\" type=\"com.gsma.services.rcs.ish.NewImageSharingListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onNewImageSharing\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.vsh\">\n<class name=\"NewVideoSharingListener\" extends=\"com.gsma.services.rcs.vsh.INewVideoSharingListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"NewVideoSharingListener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onNewVideoSharing\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoCodec\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoCodec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"payload\" type=\"int\">\n</parameter>\n<parameter name=\"clockRate\" type=\"int\">\n</parameter>\n<parameter name=\"frameRate\" type=\"int\">\n</parameter>\n<parameter name=\"bitRate\" type=\"int\">\n</parameter>\n<parameter name=\"width\" type=\"int\">\n</parameter>\n<parameter name=\"height\" type=\"int\">\n</parameter>\n<parameter name=\"parameters\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"VideoCodec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"compare\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n</method>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getBitRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getClockRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEncoding\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getFrameRate\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getParameters\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getPayloadType\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getVideoHeight\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getVideoWidth\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoPlayer\" extends=\"com.gsma.services.rcs.vsh.IVideoPlayer.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoPlayer\" type=\"com.gsma.services.rcs.vsh.VideoPlayer\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"close\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getCodec\" return=\"com.gsma.services.rcs.vsh.VideoCodec\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEventListeners\" return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoPlayerListener&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLocalRtpPort\" return=\"int\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedCodecs\" return=\"com.gsma.services.rcs.vsh.VideoCodec[]\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"open\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoPlayerListener\">\n</parameter>\n</method>\n<method name=\"start\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"stop\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"VideoPlayer.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INTERNAL_ERROR\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"NETWORK_FAILURE\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoPlayerListener\" extends=\"com.gsma.services.rcs.vsh.IVideoPlayerListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoPlayerListener\" type=\"com.gsma.services.rcs.vsh.VideoPlayerListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onPlayerClosed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onPlayerError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onPlayerOpened\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onPlayerStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onPlayerStopped\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"VideoRenderer\" extends=\"com.gsma.services.rcs.vsh.IVideoRenderer.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoRenderer\" type=\"com.gsma.services.rcs.vsh.VideoRenderer\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"close\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getCodec\" return=\"com.gsma.services.rcs.vsh.VideoCodec\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getEventListeners\" return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.IVideoRendererListener&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getLocalRtpPort\" return=\"int\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getSupportedCodecs\" return=\"com.gsma.services.rcs.vsh.VideoCodec[]\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"open\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.vsh.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n</method>\n<method name=\"removeAllEventListeners\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.IVideoRendererListener\">\n</parameter>\n</method>\n<method name=\"start\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"stop\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"VideoRenderer.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INTERNAL_ERROR\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"NETWORK_FAILURE\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoRendererListener\" extends=\"com.gsma.services.rcs.vsh.IVideoRendererListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoRendererListener\" type=\"com.gsma.services.rcs.vsh.VideoRendererListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onRendererClosed\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onRendererError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onRendererOpened\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onRendererStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onRendererStopped\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"VideoSharing\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<method name=\"abortSharing\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"renderer\" type=\"com.gsma.services.rcs.vsh.VideoRenderer\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getDirection\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getSharingId\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getState\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoFormat\" return=\"java.lang.String\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeEventListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Direction\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoSharing.Direction\" type=\"com.gsma.services.rcs.vsh.VideoSharing.Direction\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"INCOMING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"OUTGOING\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoSharing.Error\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"INVITATION_DECLINED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SHARING_FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoSharing.State\" extends=\"java.lang.Object\" abstract=\"false\" static=\"true\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<field name=\"ABORTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"5\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"FAILED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"7\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INITIATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"2\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"INVITED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"1\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STARTED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"3\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TERMINATED\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"6\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"UNKNOWN\" type=\"int\" transient=\"false\" volatile=\"false\" value=\"0\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoSharingIntent\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoSharingIntent\" type=\"com.gsma.services.rcs.vsh.VideoSharingIntent\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"ACTION_NEW_INVITATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;com.gsma.services.rcs.vsh.action.NEW_VIDEO_SHARING&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_CONTACT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_DISPLAY_NAME\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contactDisplayname&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_ENCODING\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;encoding&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_FORMAT\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;format&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"EXTRA_SHARING_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;sharingId&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoSharingListener\" extends=\"com.gsma.services.rcs.vsh.IVideoSharingListener.Stub\" abstract=\"true\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoSharingListener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<method name=\"onSharingAborted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"onSharingError\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"error\" type=\"int\">\n</parameter>\n</method>\n<method name=\"onSharingStarted\" return=\"void\" abstract=\"true\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n</class>\n<class name=\"VideoSharingLog\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoSharingLog\" type=\"com.gsma.services.rcs.vsh.VideoSharingLog\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</constructor>\n<field name=\"CONTACT_NUMBER\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;contact_number&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"CONTENT_URI\" type=\"android.net.Uri\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DIRECTION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;direction&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"DURATION\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;duration&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"SHARING_ID\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;sharing_id&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"STATE\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;state&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n<field name=\"TIMESTAMP\" type=\"java.lang.String\" transient=\"false\" volatile=\"false\" value=\"&quot;timestamp&quot;\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n<class name=\"VideoSharingService\" extends=\"com.gsma.services.rcs.JoynService\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<constructor name=\"VideoSharingService\" type=\"com.gsma.services.rcs.vsh.VideoSharingService\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addNewVideoSharingListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"addServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"connect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"disconnect\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getConfiguration\" return=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\" return=\"com.gsma.services.rcs.vsh.VideoSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharingFor\" return=\"com.gsma.services.rcs.vsh.VideoSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"intent\" type=\"android.content.Intent\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"getVideoSharings\" return=\"java.util.Set&lt;com.gsma.services.rcs.vsh.VideoSharing&gt;\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"isServiceRegistered\" return=\"boolean\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeNewVideoSharingListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.NewVideoSharingListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"removeServiceRegistrationListener\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.JoynServiceRegistrationListener\">\n</parameter>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n<method name=\"shareVideo\" return=\"com.gsma.services.rcs.vsh.VideoSharing\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.vsh.VideoPlayer\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.vsh.VideoSharingListener\">\n</parameter>\n<exception name=\"JoynContactFormatException\" type=\"com.gsma.services.rcs.JoynContactFormatException\">\n</exception>\n<exception name=\"JoynServiceException\" type=\"com.gsma.services.rcs.JoynServiceException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\" extends=\"java.lang.Object\" abstract=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<implements name=\"android.os.Parcelable\">\n</implements>\n<constructor name=\"VideoSharingServiceConfiguration\" type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"maxTime\" type=\"long\">\n</parameter>\n</constructor>\n<constructor name=\"VideoSharingServiceConfiguration\" type=\"com.gsma.services.rcs.vsh.VideoSharingServiceConfiguration\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"source\" type=\"android.os.Parcel\">\n</parameter>\n</constructor>\n<method name=\"describeContents\" return=\"int\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"getMaxTime\" return=\"long\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n</method>\n<method name=\"writeToParcel\" return=\"void\" abstract=\"false\" native=\"false\" synchronized=\"false\" static=\"false\" final=\"false\" deprecated=\"not deprecated\" visibility=\"public\">\n<parameter name=\"dest\" type=\"android.os.Parcel\">\n</parameter>\n<parameter name=\"flags\" type=\"int\">\n</parameter>\n</method>\n<field name=\"CREATOR\" type=\"android.os.Parcelable.Creator\" transient=\"false\" volatile=\"false\" static=\"true\" final=\"true\" deprecated=\"not deprecated\" visibility=\"public\">\n</field>\n</class>\n</package>\n</api>"
  },
  {
    "path": "tests/cts/signature/src/main/res/xml/blackbird_1_5_1.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"CommonServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getDefaultMessagingMethod\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMessagingUX\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMinimumBatteryLevel\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isConfigValid\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setDefaultMessagingMethod\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"method\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMinimumBatteryLevel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"level\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMyDisplayName\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMethod\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MinimumBatteryLevel\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Geoloc\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<method name=\"getAccuracy\"\n return=\"float\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLabel\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLatitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLongitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SEND_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SEND_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_ONE_TO_ONE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_ONE_TO_ONE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.ACTION_INITIATE_GROUP_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_ONE_TO_ONE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_ONE_TO_ONE_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Service\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE_CHANGEABLE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_COMPATIBILITY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_COMPATIBILITY&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_SERVICE_STARTING_STATE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode_changeable&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_codename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_INCREMENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_increment&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_RESPONSE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_response&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_SERVICE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_service&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_VERSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_version&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_service_starting_state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;set_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsGenericException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsIllegalArgumentException\"\n extends=\"java.lang.IllegalArgumentException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsIllegalArgumentException\" type=\"com.gsma.services.rcs.RcsIllegalArgumentException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsMaxAllowedSessionLimitReachedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPermissionDeniedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPersistentStorageException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCommonConfiguration\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceRegistrationReasonCode\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceVersion\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<field name=\"ACTION_SERVICE_PROVISIONING_DATA_CHANGED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_PROVISIONING_DATA_CHANGED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SERVICE_UP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_UP&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Direction\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.Direction[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsService.ReadStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceControl\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.RcsServiceControl\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isActivationModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAvailable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceStarted\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setActivationMode\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"active\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"RCS_STACK_PACKAGENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"extractServerException\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n</method>\n<method name=\"isIntendedException\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<parameter name=\"clazz\" type=\"java.lang.Class&lt;?&gt;\">\n</parameter>\n</method>\n</class>\n<interface name=\"RcsServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\">\n</parameter>\n</method>\n</interface>\n<class name=\"RcsServiceListener.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<class name=\"RcsServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsServiceRegistration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"RcsServiceRegistration.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceRegistrationListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"RcsUnsupportedOperationException\"\n extends=\"java.lang.UnsupportedOperationException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsUnsupportedOperationException\" type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isAutomata\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGeolocPushSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"AUTOMATA\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;automata&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_geoloc_push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<field name=\"EXTENSION_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"participants\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PARTICIPANTS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;participants&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.Content.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.Content.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.MimeType\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"GEOLOC_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;application/geoloc&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GROUPCHAT_EVENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;rcs/groupchat-event&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TEXT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;text/plain&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getContent\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getStatus\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearMessageDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGroupChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getOneToOneChat\"\n return=\"com.gsma.services.rcs.chat.OneToOneChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markMessageAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getGeolocExpirationTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGeolocLabelMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMinParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatSubjectMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getOneToOneChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isChatWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupChatSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isRespondToDisplayReportsEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setRespondToDisplayReports\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"inviteParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipant\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participant\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipants\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToLeave\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"leave\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.ParticipantStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_GROUP_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onMessageGroupDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onParticipantStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.chat.GroupChat.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"resendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"OneToOneChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_MESSAGE_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.MESSAGE_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"OneToOneChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneChatListener\"\n type=\"com.gsma.services.rcs.chat.OneToOneChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contact\"\n>\n<class name=\"ContactId\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n</class>\n<class name=\"ContactProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"MIME_TYPE_BLOCKING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_BLOCKING_TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactService\"\n type=\"com.gsma.services.rcs.contact.ContactService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"blockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getRcsContact\"\n return=\"com.gsma.services.rcs.contact.RcsContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unblockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ContactUtil\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"formatContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.contact.ContactUtil\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"getMyCountryAreaCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getMyCountryCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getVCard\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isMyCountryCodeDefined\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isValidContact\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBlockingTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isBlocked\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isOnline\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.extension\"\n>\n<class name=\"MultimediaMessagingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaMessagingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_MESSAGING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaMessagingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaMessagingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onMessageReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"MultimediaSession\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSession.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSession.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSessionService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionService\"\n type=\"com.gsma.services.rcs.extension.MultimediaSessionService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.extension.MultimediaSessionServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaMessagingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaStreamingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSessionServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendPayload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_STREAMING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaStreamingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaStreamingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPayloadReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.filetransfer\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToPauseTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToResendTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToResumeTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"pauseTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"resendTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"resumeTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_FILE_TRANSFER_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.FILE_TRANSFER_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_RESUME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.RESUME_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN_EXPIRATION\"\n type=\"long\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0L\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.filetransfer.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearFileTransferDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteFileTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFileToGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markFileTransferAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFileToGroupChat\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getImageResizeOption\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxFileTransfers\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptInRoamingEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setAutoAccept\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setAutoAcceptInRoaming\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setImageResizeOption\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"option\" type=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration.ImageResizeOption\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.groupdelivery\"\n>\n<class name=\"GroupDeliveryInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"GroupDeliveryInfo.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfo.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfoLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.history\"\n>\n<class name=\"HistoryLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PROVIDER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;provider_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"HistoryService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryService\"\n type=\"com.gsma.services.rcs.history.HistoryService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"createUniqueId\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"registerExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<parameter name=\"providerUri\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"database\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"table\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"columnMapping\" type=\"java.util.Map&lt;java.lang.String, java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unregisterExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"HistoryUriBuilder\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryUriBuilder\"\n type=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"historyLogUri\" type=\"android.net.Uri\">\n</parameter>\n</constructor>\n<method name=\"appendProvider\"\n return=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n</method>\n<method name=\"build\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.geoloc\"\n>\n<class name=\"GeolocSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.geoloc.action.NEW_GEOLOC_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingListener\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"GeolocSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingService\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocSharing\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.image\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.image.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteImageSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.video\"\n>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoDescriptor\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setRemoteInfo\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.sharing.video.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n<parameter name=\"orientationHeaderId\" type=\"int\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDuration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoDescriptor\"\n return=\"com.gsma.services.rcs.sharing.video.VideoDescriptor\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Encoding\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"H264\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;H264&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.video.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HEIGHT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;height&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"VIDEO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;video_encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"WIDTH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;width&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.upload\"\n>\n<class name=\"FileUpload\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortUpload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadInfo\"\n return=\"com.gsma.services.rcs.upload.FileUploadInfo\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUpload.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadListener\"\n type=\"com.gsma.services.rcs.upload.FileUploadListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.upload.FileUpload.State\">\n</parameter>\n</method>\n<method name=\"onUploaded\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"info\" type=\"com.gsma.services.rcs.upload.FileUploadInfo\">\n</parameter>\n</method>\n</class>\n<class name=\"FileUploadService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadService\"\n type=\"com.gsma.services.rcs.upload.FileUploadService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"canUploadFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.upload.FileUploadServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUpload\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUploads\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.upload.FileUpload&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"uploadFile\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUploadServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n</api>\n"
  },
  {
    "path": "tests/cts/signature/src/main/res/xml/crane_1_6_1.xml",
    "content": "<api>\n<package name=\"com.gsma.services.rcs\"\n>\n<class name=\"CommonServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getDefaultMessagingMethod\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMessagingUX\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMinimumBatteryLevel\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMyDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isConfigValid\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setDefaultMessagingMethod\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"method\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMinimumBatteryLevel\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"level\" type=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setMyDisplayName\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMethod\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MessagingMode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MessagingMode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"CommonServiceConfiguration.MinimumBatteryLevel\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Geoloc\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"label\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"latitude\" type=\"double\">\n</parameter>\n<parameter name=\"longitude\" type=\"double\">\n</parameter>\n<parameter name=\"expiration\" type=\"long\">\n</parameter>\n<parameter name=\"accuracy\" type=\"float\">\n</parameter>\n</constructor>\n<constructor name=\"Geoloc\"\n type=\"com.gsma.services.rcs.Geoloc\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<method name=\"getAccuracy\"\n return=\"float\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLabel\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLatitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLongitude\"\n return=\"double\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"Intents\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"Intents.Chat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SEND_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SEND_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_GROUP_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_ONE_TO_ONE_CHAT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_ONE_TO_ONE_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_INITIATE_GROUP_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.ACTION_INITIATE_GROUP_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_INITIATE_ONE_TO_ONE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.INITIATE_ONE_TO_ONE_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_VIEW_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.VIEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"Intents.Service\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_ACTIVATION_MODE_CHANGEABLE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_COMPATIBILITY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_COMPATIBILITY&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.GET_SERVICE_STARTING_STATE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SET_ACTIVATION_MODE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_ACTIVATION_MODE_CHANGEABLE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_activation_mode_changeable&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_codename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_INCREMENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_increment&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_RESPONSE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_response&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_SERVICE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_service&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_COMPATIBILITY_VERSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_compatibility_version&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_GET_SERVICE_STARTING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;get_service_starting_state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SET_ACTIVATION_MODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;set_activation_mode&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsGenericException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsGenericException\"\n type=\"com.gsma.services.rcs.RcsGenericException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsIllegalArgumentException\"\n extends=\"java.lang.IllegalArgumentException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsIllegalArgumentException\"\n type=\"com.gsma.services.rcs.RcsIllegalArgumentException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsIllegalArgumentException\" type=\"com.gsma.services.rcs.RcsIllegalArgumentException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsMaxAllowedSessionLimitReachedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsMaxAllowedSessionLimitReachedException\"\n type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPermissionDeniedException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPermissionDeniedException\"\n type=\"com.gsma.services.rcs.RcsPermissionDeniedException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsPersistentStorageException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsPersistentStorageException\"\n type=\"com.gsma.services.rcs.RcsPersistentStorageException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsService\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCommonConfiguration\"\n return=\"com.gsma.services.rcs.CommonServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceRegistrationReasonCode\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getServiceVersion\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isServiceConnected\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceRegistered\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<field name=\"ACTION_SERVICE_PROVISIONING_DATA_CHANGED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_PROVISIONING_DATA_CHANGED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_SERVICE_UP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.action.SERVICE_UP&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"API_CODENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;GSMA&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_INCREMENTAL\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"API_VERSION\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Build.VERSION_CODES\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASE\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BLACKBIRD\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CPR\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsService.Direction\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.Direction[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsService.ReadStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsService.ReadStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceControl\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.RcsServiceControl\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"isActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isActivationModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAvailable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isServiceStarted\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setActivationMode\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"active\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"RCS_STACK_PACKAGENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"RcsServiceException\"\n extends=\"java.lang.Exception\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceException\"\n type=\"com.gsma.services.rcs.RcsServiceException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"extractServerException\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n</method>\n<method name=\"isIntendedException\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"protected\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<parameter name=\"clazz\" type=\"java.lang.Class&lt;?&gt;\">\n</parameter>\n</method>\n</class>\n<interface name=\"RcsServiceListener\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"onServiceConnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceDisconnected\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\">\n</parameter>\n</method>\n</interface>\n<class name=\"RcsServiceListener.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceListener.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceNotAvailableException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<constructor name=\"RcsServiceNotAvailableException\"\n type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n</class>\n<class name=\"RcsServiceNotRegisteredException\"\n extends=\"com.gsma.services.rcs.RcsServiceException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsServiceNotRegisteredException\"\n type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsServiceRegistration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"RcsServiceRegistration.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"RcsServiceRegistrationListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsServiceRegistrationListener\"\n type=\"com.gsma.services.rcs.RcsServiceRegistrationListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onServiceRegistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"onServiceUnregistered\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.RcsServiceRegistration.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"RcsUnsupportedOperationException\"\n extends=\"java.lang.UnsupportedOperationException\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n</constructor>\n<constructor name=\"RcsUnsupportedOperationException\"\n type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"cause\" type=\"java.lang.Throwable\">\n</parameter>\n</constructor>\n<method name=\"assertException\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"e\" type=\"java.lang.Exception\">\n</parameter>\n<exception name=\"RcsUnsupportedOperationException\" type=\"com.gsma.services.rcs.RcsUnsupportedOperationException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.capability\"\n>\n<class name=\"Capabilities\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getSupportedExtensions\"\n return=\"java.util.Set&lt;java.lang.String&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"hasCapabilities\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"capabilities\" type=\"int\">\n</parameter>\n</method>\n<method name=\"isAutomata\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isExtensionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"tag\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"isFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isGeolocPushSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImSessionSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isImageSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isVideoSharingSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n</method>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"8\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARING\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"16\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilitiesListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilitiesListener\"\n type=\"com.gsma.services.rcs.capability.CapabilitiesListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onCapabilitiesReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"capabilities\" type=\"com.gsma.services.rcs.capability.Capabilities\">\n</parameter>\n</method>\n</class>\n<class name=\"CapabilitiesLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"AUTOMATA\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;automata&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_file_transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_geoloc_push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_image_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_im_session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CAPABILITY_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;capability_video_share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"NOT_SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUPPORTED\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"CapabilityService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"CapabilityService\"\n type=\"com.gsma.services.rcs.capability.CapabilityService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMyCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeCapabilitiesListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.capability.CapabilitiesListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"requestAllContactsCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"requestContactCapabilities\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<field name=\"EXTENSION_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"INTENT_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.capability.EXTENSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.chat\"\n>\n<class name=\"ChatLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"participants\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PARTICIPANTS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;participants&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SUBJECT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;subject&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"1\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;msg_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatLog.Message.Content\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.Content.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.Content.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"ChatLog.Message.GroupChatEvent.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.GroupChatEvent.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ChatLog.Message.MimeType\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"GEOLOC_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;application/geoloc&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"GROUPCHAT_EVENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;rcs/groupchat-event&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TEXT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;text/plain&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ChatMessage\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getContent\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getStatus\"\n return=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ChatService\"\n type=\"com.gsma.services.rcs.chat.ChatService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearMessageDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGroupChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneChats\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getChatMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.chat.ChatServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getOneToOneChat\"\n return=\"com.gsma.services.rcs.chat.OneToOneChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateGroupChat\"\n return=\"com.gsma.services.rcs.chat.GroupChat\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contacts\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<parameter name=\"subject\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToInitiateGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markMessageAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.GroupChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.chat.OneToOneChatListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ChatServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getGeolocExpirationTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGeolocLabelMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatMinParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getGroupChatSubjectMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getIsComposingTimeout\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getOneToOneChatMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isChatWarnSF\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupChatSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isRespondToDisplayReportsEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isSmsFallback\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setRespondToDisplayReports\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMaxParticipants\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getParticipants\"\n return=\"java.util.Map&lt;com.gsma.services.rcs.contact.ContactId, com.gsma.services.rcs.chat.GroupChat.ParticipantStatus&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSubject\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"inviteParticipants\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participants\" type=\"java.util.Set&lt;com.gsma.services.rcs.contact.ContactId&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipant\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"participant\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToInviteParticipants\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToLeave\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"leave\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"text\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GroupChat.ParticipantStatus\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChat.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.chat.GroupChat.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_GROUP_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_GROUP_CHAT&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chatId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GroupChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupChatListener\"\n type=\"com.gsma.services.rcs.chat.GroupChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onMessageGroupDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onParticipantStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.GroupChat.ParticipantStatus\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.chat.GroupChat.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.GroupChat.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneChat\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToSendMessage\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"openChat\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"resendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"message\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"com.gsma.services.rcs.chat.ChatMessage\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setComposingStatus\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ongoing\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"OneToOneChatIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_MESSAGE_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.MESSAGE_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.chat.action.NEW_ONE_TO_ONE_CHAT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MESSAGE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;messageId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mimeType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"OneToOneChatListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneChatListener\"\n type=\"com.gsma.services.rcs.chat.OneToOneChatListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onComposingEvent\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"status\" type=\"boolean\">\n</parameter>\n</method>\n<method name=\"onMessageStatusChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"mimeType\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"msgId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.chat.ChatLog.Message.Content.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onMessagesDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"msgIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.contact\"\n>\n<class name=\"ContactId\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<implements name=\"java.io.Serializable\">\n</implements>\n</class>\n<class name=\"ContactProvider\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"MIME_TYPE_BLOCKING_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_BLOCKING_TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.blocking-timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_EXTENSIONS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.extensions&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_FILE_TRANSFER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.file-transfer&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_GEOLOC_PUSH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.geoloc-push&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IMAGE_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.image-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_IM_SESSION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.im-session&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_PHONE_NUMBER\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.number&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_REGISTRATION_STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.registration-state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE_VIDEO_SHARE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;vnd.android.cursor.item/com.gsma.services.rcs.video-share&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ContactService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ContactService\"\n type=\"com.gsma.services.rcs.contact.ContactService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"blockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getRcsContact\"\n return=\"com.gsma.services.rcs.contact.RcsContact\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContacts\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsOnline\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getRcsContactsSupporting\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.contact.RcsContact&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unblockContact\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"ContactUtil\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"formatContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getInstance\"\n return=\"com.gsma.services.rcs.contact.ContactUtil\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"context\" type=\"android.content.Context\">\n</parameter>\n</method>\n<method name=\"getMyCountryAreaCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getMyCountryCode\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getVCard\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contactUri\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isMyCountryCodeDefined\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isValidContact\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"RcsContact\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBlockingTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getCapabilities\"\n return=\"com.gsma.services.rcs.capability.Capabilities\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getContactId\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getDisplayName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isBlocked\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"isOnline\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.extension\"\n>\n<class name=\"InstantMultimediaMessageIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INSTANT_MESSAGE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_INSTANT_MESSAGE&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTENT_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contentType&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SERVICE_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;serviceId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaMessagingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"flushMessages\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaMessagingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_MESSAGING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaMessagingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaMessagingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onMessageReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onMessageReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onMessagesFlushed\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"MultimediaSession\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSession.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSession.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"MultimediaSessionService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaSessionService\"\n type=\"com.gsma.services.rcs.extension.MultimediaSessionService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.extension.MultimediaSessionServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getMessagingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaMessagingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getStreamingSessions\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.extension.MultimediaStreamingSession&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"initiateMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateMessagingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaMessagingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"acceptTypes\" type=\"java.lang.String[]\">\n</parameter>\n<parameter name=\"acceptWrappedTypes\" type=\"java.lang.String[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"initiateStreamingSession\"\n return=\"com.gsma.services.rcs.extension.MultimediaStreamingSession\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"encoding\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaMessagingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"sendInstantMultimediaMessage\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<parameter name=\"contentType\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaSessionServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMessageMaxLength\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMessagingSessionInactivityTimeout\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isServiceActivated\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"serviceId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSession\"\n extends=\"com.gsma.services.rcs.extension.MultimediaSession\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSession\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getServiceId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getSessionId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.extension.MultimediaSession.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"sendPayload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n</class>\n<class name=\"MultimediaStreamingSessionIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.extension.action.NEW_STREAMING_SESSION&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SESSION_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sessionId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"MultimediaStreamingSessionListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"MultimediaStreamingSessionListener\"\n type=\"com.gsma.services.rcs.extension.MultimediaStreamingSessionListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onPayloadReceived\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"content\" type=\"byte[]\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sessionId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.extension.MultimediaSession.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.extension.MultimediaSession.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.filetransfer\"\n>\n<class name=\"FileTransfer\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getChatId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDisposition\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDelivered\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampDisplayed\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestampSent\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTransferId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToPauseTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAllowedToResendTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isAllowedToResumeTransfer\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isExpiredDelivery\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"isRead\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"pauseTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"resendTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"resumeTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransfer.Disposition\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransfer.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransfer.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileTransferIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_FILE_TRANSFER_DELIVERY_EXPIRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.FILE_TRANSFER_DELIVERY_EXPIRED&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.NEW_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ACTION_RESUME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.filetransfer.action.RESUME_FILE_TRANSFER&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_TRANSFER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISPOSITION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;disposition&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE_EXPIRATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file_expiration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;ft_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"2\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"UNKNOWN_EXPIRATION\"\n type=\"long\"\n transient=\"false\"\n volatile=\"false\"\n value=\"0L\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"FileTransferService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileTransferService\"\n type=\"com.gsma.services.rcs.filetransfer.FileTransferService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"clearFileTransferDeliveryExpiration\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteFileTransfer\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGroupFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteOneToOneFileTransfers\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileTransfer\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"isAllowedToTransferFileToGroupChat\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"markFileTransferAsRead\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFile\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"disposition\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFileToGroupChat\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"transferFileToGroupChat\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransfer\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"disposition\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.Disposition\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getImageResizeOption\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxAudioMessageDuration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxFileTransfers\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getWarnSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptInRoamingEnabled\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isAutoAcceptModeChangeable\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"isGroupFileTransferSupported\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"setAutoAccept\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setAutoAcceptInRoaming\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"enable\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"setImageResizeOption\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"option\" type=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileTransferServiceConfiguration.ImageResizeOption\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GroupFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.GroupFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onDeliveryInfoChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"status\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"chatId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"OneToOneFileTransferListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"OneToOneFileTransferListener\"\n type=\"com.gsma.services.rcs.filetransfer.OneToOneFileTransferListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"transferId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.filetransfer.FileTransfer.ReasonCode\">\n</parameter>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.groupdelivery\"\n>\n<class name=\"GroupDeliveryInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</class>\n<class name=\"GroupDeliveryInfo.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfo.Status\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.groupdelivery.GroupDeliveryInfo.Status[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GroupDeliveryInfoLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.history\"\n>\n<class name=\"HistoryLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CHAT_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;chat_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DISPOSITION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;disposition&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXPIRED_DELIVERY\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;expired_delivery&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILEICON_MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;fileicon_mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"PROVIDER_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;provider_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"READ_STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;read_status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATUS\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;status&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DELIVERED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_delivered&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_DISPLAYED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_displayed&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP_SENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp_sent&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"HistoryService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryService\"\n type=\"com.gsma.services.rcs.history.HistoryService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"createUniqueId\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"registerExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<parameter name=\"providerUri\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"database\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"table\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"columnMapping\" type=\"java.util.Map&lt;java.lang.String, java.lang.String&gt;\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"unregisterExtraHistoryLogMember\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"HistoryUriBuilder\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"HistoryUriBuilder\"\n type=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"historyLogUri\" type=\"android.net.Uri\">\n</parameter>\n</constructor>\n<method name=\"appendProvider\"\n return=\"com.gsma.services.rcs.history.HistoryUriBuilder\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"providerId\" type=\"int\">\n</parameter>\n</method>\n<method name=\"build\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.geoloc\"\n>\n<class name=\"GeolocSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getGeoloc\"\n return=\"com.gsma.services.rcs.Geoloc\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"GeolocSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"GeolocSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.geoloc.action.NEW_GEOLOC_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingListener\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"GeolocSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;content&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"5\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"GeolocSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"GeolocSharingService\"\n type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteGeolocSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getGeolocSharing\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareGeoloc\"\n return=\"com.gsma.services.rcs.sharing.geoloc.GeolocSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"geoloc\" type=\"com.gsma.services.rcs.Geoloc\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.image\"\n>\n<class name=\"ImageSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getFileSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"ImageSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.image.action.NEW_IMAGE_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingListener\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.image.ImageSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"ImageSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;file&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILENAME\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filename&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"FILESIZE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;filesize&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"3\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"MIME_TYPE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;mime_type&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TRANSFERRED\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;transferred&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"ImageSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"ImageSharingService\"\n type=\"com.gsma.services.rcs.sharing.image.ImageSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteImageSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteImageSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getImageSharing\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.image.ImageSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareImage\"\n return=\"com.gsma.services.rcs.sharing.image.ImageSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"ImageSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.sharing.video\"\n>\n<class name=\"VideoCodec\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getBitRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getClockRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFrameRate\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getParameters\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getPayloadType\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoDescriptor\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getHeight\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getWidth\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoPlayer\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoPlayer\"\n type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"getCodec\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getLocalRtpPort\"\n return=\"int\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSupportedCodecs\"\n return=\"com.gsma.services.rcs.sharing.video.VideoCodec[]\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"setRemoteInfo\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"codec\" type=\"com.gsma.services.rcs.sharing.video.VideoCodec\">\n</parameter>\n<parameter name=\"remoteHost\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"remotePort\" type=\"int\">\n</parameter>\n<parameter name=\"orientationHeaderId\" type=\"int\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharing\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"acceptInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getDirection\"\n return=\"com.gsma.services.rcs.RcsService.Direction\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getDuration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getReasonCode\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getRemoteContact\"\n return=\"com.gsma.services.rcs.contact.ContactId\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getSharingId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getTimestamp\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoDescriptor\"\n return=\"com.gsma.services.rcs.sharing.video.VideoDescriptor\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"getVideoEncoding\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n</method>\n<method name=\"rejectInvitation\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharing.Encoding\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"H264\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;H264&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharing.ReasonCode\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharing.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"VideoSharingIntent\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"ACTION_NEW_INVITATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;com.gsma.services.rcs.sharing.video.action.NEW_VIDEO_SHARING&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"EXTRA_SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharingId&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingListener\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onDeleted\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingIds\" type=\"java.util.Set&lt;java.lang.String&gt;\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.State\">\n</parameter>\n<parameter name=\"reasonCode\" type=\"com.gsma.services.rcs.sharing.video.VideoSharing.ReasonCode\">\n</parameter>\n</method>\n</class>\n<class name=\"VideoSharingLog\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<field name=\"BASECOLUMN_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTACT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;contact&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"CONTENT_URI\"\n type=\"android.net.Uri\"\n transient=\"false\"\n volatile=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DIRECTION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;direction&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"DURATION\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;duration&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HEIGHT\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;height&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"HISTORYLOG_MEMBER_ID\"\n type=\"int\"\n transient=\"false\"\n volatile=\"false\"\n value=\"4\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"REASON_CODE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;reason_code&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"SHARING_ID\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;sharing_id&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"STATE\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;state&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"TIMESTAMP\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;timestamp&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"VIDEO_ENCODING\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;video_encoding&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n<field name=\"WIDTH\"\n type=\"java.lang.String\"\n transient=\"false\"\n volatile=\"false\"\n value=\"&quot;width&quot;\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</field>\n</class>\n<class name=\"VideoSharingService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"VideoSharingService\"\n type=\"com.gsma.services.rcs.sharing.video.VideoSharingService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharing\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"deleteVideoSharings\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharingServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getVideoSharing\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"sharingId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.sharing.video.VideoSharingListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"shareVideo\"\n return=\"com.gsma.services.rcs.sharing.video.VideoSharing\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"contact\" type=\"com.gsma.services.rcs.contact.ContactId\">\n</parameter>\n<parameter name=\"player\" type=\"com.gsma.services.rcs.sharing.video.VideoPlayer\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsPersistentStorageException\" type=\"com.gsma.services.rcs.RcsPersistentStorageException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n<exception name=\"RcsServiceNotRegisteredException\" type=\"com.gsma.services.rcs.RcsServiceNotRegisteredException\">\n</exception>\n</method>\n</class>\n<class name=\"VideoSharingServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxTime\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n<package name=\"com.gsma.services.rcs.upload\"\n>\n<class name=\"FileUpload\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"abortUpload\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getState\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadId\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n<method name=\"getUploadInfo\"\n return=\"com.gsma.services.rcs.upload.FileUploadInfo\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUpload.State\"\n extends=\"java.lang.Enum\"\n abstract=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"toInt\"\n return=\"int\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"name\" type=\"java.lang.String\">\n</parameter>\n</method>\n<method name=\"valueOf\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"value\" type=\"int\">\n</parameter>\n</method>\n<method name=\"values\"\n return=\"com.gsma.services.rcs.upload.FileUpload.State[]\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"true\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadInfo\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<implements name=\"android.os.Parcelable\">\n</implements>\n<method name=\"getFile\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIcon\"\n return=\"android.net.Uri\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconExpiration\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileIconSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getFileName\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getMimeType\"\n return=\"java.lang.String\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n</class>\n<class name=\"FileUploadListener\"\n extends=\"java.lang.Object\"\n abstract=\"true\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadListener\"\n type=\"com.gsma.services.rcs.upload.FileUploadListener\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</constructor>\n<method name=\"onProgressUpdate\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"currentSize\" type=\"long\">\n</parameter>\n<parameter name=\"totalSize\" type=\"long\">\n</parameter>\n</method>\n<method name=\"onStateChanged\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"state\" type=\"com.gsma.services.rcs.upload.FileUpload.State\">\n</parameter>\n</method>\n<method name=\"onUploaded\"\n return=\"void\"\n abstract=\"true\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<parameter name=\"info\" type=\"com.gsma.services.rcs.upload.FileUploadInfo\">\n</parameter>\n</method>\n</class>\n<class name=\"FileUploadService\"\n extends=\"com.gsma.services.rcs.RcsService\"\n abstract=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<constructor name=\"FileUploadService\"\n type=\"com.gsma.services.rcs.upload.FileUploadService\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"ctx\" type=\"android.content.Context\">\n</parameter>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.RcsServiceListener\">\n</parameter>\n</constructor>\n<method name=\"addEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"canUploadFile\"\n return=\"boolean\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"connect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"true\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsPermissionDeniedException\" type=\"com.gsma.services.rcs.RcsPermissionDeniedException\">\n</exception>\n</method>\n<method name=\"disconnect\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n</method>\n<method name=\"getConfiguration\"\n return=\"com.gsma.services.rcs.upload.FileUploadServiceConfiguration\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUpload\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"uploadId\" type=\"java.lang.String\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"getFileUploads\"\n return=\"java.util.Set&lt;com.gsma.services.rcs.upload.FileUpload&gt;\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"removeEventListener\"\n return=\"void\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"listener\" type=\"com.gsma.services.rcs.upload.FileUploadListener\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n<method name=\"uploadFile\"\n return=\"com.gsma.services.rcs.upload.FileUpload\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<parameter name=\"file\" type=\"android.net.Uri\">\n</parameter>\n<parameter name=\"attachFileIcon\" type=\"boolean\">\n</parameter>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n<exception name=\"RcsMaxAllowedSessionLimitReachedException\" type=\"com.gsma.services.rcs.RcsMaxAllowedSessionLimitReachedException\">\n</exception>\n<exception name=\"RcsServiceNotAvailableException\" type=\"com.gsma.services.rcs.RcsServiceNotAvailableException\">\n</exception>\n</method>\n</class>\n<class name=\"FileUploadServiceConfiguration\"\n extends=\"java.lang.Object\"\n abstract=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<method name=\"getMaxSize\"\n return=\"long\"\n abstract=\"false\"\n native=\"false\"\n synchronized=\"false\"\n static=\"false\"\n final=\"false\"\n deprecated=\"not deprecated\"\n visibility=\"public\"\n>\n<exception name=\"RcsGenericException\" type=\"com.gsma.services.rcs.RcsGenericException\">\n</exception>\n</method>\n</class>\n</package>\n</api>\n"
  },
  {
    "path": "tests/multistack/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.orangelabs.test.stack2\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <application\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\" >\n        \n        <activity\n            android:name=\".MainActivity\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n            \n            <intent-filter>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n                <category android:name=\"android.intent.category.DEFAULT\"/>\n                <action android:name=\"com.gsma.services.rcs.action.VIEW_SETTINGS\"/>                \n            </intent-filter>            \n        </activity>\n        \n   \t\t<receiver android:name=\".GetStatusReceiver\">\n\t        <intent-filter>\n\t     \t\t<action android:name=\"com.orangelabs.test.stack2.service.action.GET_STATUS\"/>\n\t        </intent-filter>\n\t    </receiver>        \n        \n    </application>\n\n</manifest>\n"
  },
  {
    "path": "tests/multistack/res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"com.orangelabs.test.stack2.MainActivity\" >\n\n    <TextView\n        android:id=\"@+id/textView1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"10dp\"\n        android:text=\"@string/label_main\" />\n\n</RelativeLayout>"
  },
  {
    "path": "tests/multistack/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">Stack2</string>\n    <string name=\"label_main\">Simulate another RCS stack</string>\n\n</resources>\n"
  },
  {
    "path": "tests/multistack/src/com/orangelabs/test/stack2/GetStatusReceiver.java",
    "content": "\npackage com.orangelabs.test.stack2;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport com.gsma.services.rcs.Intents;\n\n/**\n * Get status intent receiver\n * \n * @author Jean-Marc AUFFRET\n */\npublic class GetStatusReceiver extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (intent.getAction().endsWith(Intents.Service.ACTION_GET_STATUS)) {\n            Bundle results = getResultExtras(true);\n            results.putString(Intents.Service.EXTRA_PACKAGENAME, context.getPackageName());\n            results.putBoolean(Intents.Service.EXTRA_STATUS, false);\n            setResultExtras(results);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/multistack/src/com/orangelabs/test/stack2/MainActivity.java",
    "content": "\npackage com.orangelabs.test.stack2;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.widget.CheckBox;\n\npublic class MainActivity extends Activity {\n    public static CheckBox statusCheckbox = null;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_main);\n    }\n}\n"
  },
  {
    "path": "tests/samples/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.rcs.api\">\n\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\" />\n    \n    <application>\n        <uses-library android:name=\"android.test.runner\" />\n    </application>\n\n    <instrumentation android:name=\".InstrumentationRunner\"\n        android:targetPackage=\"com.gsma.rcs.api\"\n        android:label=\"RCS API Signature Test\"/>\n\n    <instrumentation android:name=\"android.test.InstrumentationTestRunner\"\n        android:targetPackage=\"com.gsma.rcs.api\"\n        android:label=\"RCS API Signature Test\">\n    </instrumentation>\n\n</manifest>"
  },
  {
    "path": "tests/samples/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">ApiCodeSamples</string>\n\n</resources>\n"
  },
  {
    "path": "tests/samples/src/com/gsma/rcs/api/CapabilitySampleTest.java",
    "content": "package com.gsma.rcs.api;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.capability.Capabilities;\nimport com.gsma.services.rcs.capability.CapabilitiesListener;\nimport com.gsma.services.rcs.capability.CapabilitiesLog;\nimport com.gsma.services.rcs.capability.CapabilityService;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.test.AndroidTestCase;\nimport android.util.Log;\n\npublic class CapabilitySampleTest extends AndroidTestCase {\n    private static final String TAG = \"RCSAPI\";\n\n    private ContactId remote; \n    \n    private CapabilityService capabilityApi;\n    \n    private Synchronizer synchro = new Synchronizer();    \n\n    protected void setUp() throws Exception {\n        super.setUp();\n        \n        // Format a remote phone number for testing\n        try {\n            remote =  ContactUtil.getInstance(mContext).formatContact(\"+33681639059\"); \n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        assertNotNull(remote);\n    }\n   \n    protected void tearDown() throws Exception {\n        super.tearDown();\n    }\n\n    /**\n     * Test API methods\n     */\n    public void testApiMethods() {\n        Log.i(TAG, \"testApiMethods\");\n\n        // Instanciate the API\n        capabilityApi = new CapabilityService(mContext, new RcsServiceListener() {\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                Log.i(TAG, \"Disconnected from the RCS service\");\n            }\n\n            @Override\n            public void onServiceConnected() {\n                Log.i(TAG, \"Connected to the RCS service\");\n                \n                // Test any API method which requires a binding to the API\n                getMyCapabilities();\n                getContactCapabilities();\n                requestContactCapabilities();\n                receiveContactCapabilities();\n                \n                synchro.doNotify();\n            }   \n        });\n\n        // Connect to the API\n        try {\n            capabilityApi.connect();\n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        \n        synchro.doWait();\n        \n        // Disconnect from the API\n        capabilityApi.disconnect();       \n    }    \n    \n    /**\n     * Gets my capabilities\n     */\n    public void getMyCapabilities() {\n        Log.i(TAG, \"testGetMyCapabilities\");\n\n        try {\n            Capabilities capa = capabilityApi.getMyCapabilities();\n            if (capa != null) {\n                Log.i(TAG, \"Capabilities:\");\n                Log.i(TAG, \"- chat support: \" + capa.isImSessionSupported());\n                Log.i(TAG, \"- FT support: \" + capa.isFileTransferSupported());\n                Log.i(TAG, \"- Video share support: \" + capa.isVideoSharingSupported());\n                Log.i(TAG, \"- Image share support: \" + capa.isImageSharingSupported());\n                Log.i(TAG, \"- Geoloc share support: \" + capa.isGeolocPushSupported());\n                Log.i(TAG, \"- Extensions: \" + capa.getSupportedExtensions().size());\n            } else {\n                Log.i(TAG, \"Capabilities not found\");\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Gets capabilities of a remote contact\n     */\n    public void getContactCapabilities() {\n        Log.i(TAG, \"testGetContactCapabilities\");\n\n        try {\n            Capabilities capa = capabilityApi.getContactCapabilities(remote);\n            if (capa != null) {\n                Log.i(TAG, \"Capabilities:\");\n                Log.i(TAG, \"- chat support: \" + capa.isImSessionSupported());\n                Log.i(TAG, \"- FT support: \" + capa.isFileTransferSupported());\n                Log.i(TAG, \"- Extensions: \" + capa.getSupportedExtensions().size());\n            } else {\n                Log.i(TAG, \"Capabilities not found\");\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Requests a refresh of the capabilities for a remote contact\n     */\n    public void requestContactCapabilities() {\n        Log.i(TAG, \"testRequestContactCapabilities\");\n        \n        try {\n            capabilityApi.requestContactCapabilities(remote);\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsServiceNotRegisteredException e) {\n            Log.e(TAG, \"RCS service not registered\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Receives capabilities updates from remote contacts\n     */\n    public void receiveContactCapabilities() {\n        Log.i(TAG, \"testReceiveContactCapabilities\");\n\n        CapabilitiesListener listener = new CapabilitiesListener() {\n            public void onCapabilitiesReceived(ContactId contact, Capabilities capabilities) {\n                Log.i(TAG, \"Capabilities of \" + contact.toString() + \":\");\n                Log.i(TAG, \"- chat support: \" + capabilities.isImSessionSupported());\n                Log.i(TAG, \"- FT support: \" + capabilities.isFileTransferSupported());\n                Log.i(TAG, \"- Video share support: \" + capabilities.isVideoSharingSupported());\n                Log.i(TAG, \"- Image share support: \" + capabilities.isImageSharingSupported());\n                Log.i(TAG, \"- Geoloc share support: \" + capabilities.isGeolocPushSupported());\n                Log.i(TAG, \"- Extensions: \" + capabilities.getSupportedExtensions().size());\n            }\n        };\n        try {\n            capabilityApi.addCapabilitiesListener(listener);\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Reads capabilities of a remote contact\n     */\n    public void testReadContactCapabilities() {\n        Log.i(TAG, \"testReadContactCapabilities\");\n\n        String contactNumber = remote.toString();\n        Uri uri = Uri.withAppendedPath(CapabilitiesLog.CONTENT_URI, contactNumber);\n        Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);\n        assertNotNull(cursor);\n        if (cursor.moveToFirst()) {\n            Log.i(TAG, \"Capabilities:\");\n            Log.i(TAG, \"- chat support: \" + cursor.getInt(\n                    cursor.getColumnIndex(CapabilitiesLog.CAPABILITY_IM_SESSION)));\n            Log.i(TAG, \"- FT support: \" + cursor.getInt(\n                    cursor.getColumnIndex(CapabilitiesLog.CAPABILITY_FILE_TRANSFER)));\n            Log.i(TAG, \"- Extensions: \" + cursor.getString(\n                    cursor.getColumnIndex(CapabilitiesLog.CAPABILITY_EXTENSIONS)));\n        } else {\n            Log.i(TAG, \"Capabilities not found\");\n        }\n        cursor.close();\n    }\n\n    // TODO: create an extension\n    // TODO: global listener\n    // TODO: group of contact\n    // TODO: database directly\n    // TODO: is a RCS contact\n}\n"
  },
  {
    "path": "tests/samples/src/com/gsma/rcs/api/ChatSampleTest.java",
    "content": "package com.gsma.rcs.api;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.chat.ChatService;\nimport com.gsma.services.rcs.chat.OneToOneChat;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\n\nimport android.test.AndroidTestCase;\nimport android.util.Log;\n\npublic class ChatSampleTest extends AndroidTestCase {\n    private static final String TAG = \"RCSAPI\";\n   \n    private ContactId remote; \n    \n    private ChatService chatApi;\n\n    private Synchronizer synchro = new Synchronizer();\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        \n        // Format a remote phone number for testing\n        try {\n            remote =  ContactUtil.getInstance(mContext).formatContact(\"+33681639059\"); \n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        assertNotNull(remote);\n    }\n   \n    protected void tearDown() throws Exception {\n        super.tearDown();\n    }\n    \n    /**\n     * Test API methods\n     */\n    public void testApiMethods() {\n        Log.i(TAG, \"testApiMethods\");\n\n        // Instanciate the API\n        chatApi = new ChatService(mContext, new RcsServiceListener() {\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                Log.i(TAG, \"Disconnected from the RCS service\");\n            }\n\n            @Override\n            public void onServiceConnected() {\n                Log.i(TAG, \"Connected to the RCS service\");\n                \n                // Test any API method which requires a binding to the API\n                sendOneToOneChat();\n                \n                synchro.doNotify();\n            }   \n        });\n\n        // Connect to the API\n        try {\n            chatApi.connect();\n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        \n        synchro.doWait();\n        \n        // Disconnect from the API\n        chatApi.disconnect();       \n    }      \n\n    /**\n     * Sends a 1-1 chat message to a remote contact\n     */\n    public void sendOneToOneChat() {\n        Log.i(TAG, \"testSendOneToOneChat\");\n\n        try {\n            OneToOneChat chat = chatApi.getOneToOneChat(remote);\n            chat.sendMessage(\"Hello world!\");\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Receives 1-1 chat messages from an Intent receiver\n     */\n    public void testReceiveOneToOneChat() {\n        // Catch chat messages\n/*        IntentFilter filter = new IntentFilter(OneToOneChatIntent.ACTION_NEW_ONE_TO_ONE_CHAT_MESSAGE);\n        Intent intent = mContext.registerReceiver(null, filter);        \n        ContactId remote = intent.getParcelableExtra(OneToOneChatIntent.EXTRA_CONTACT);\n        String msgId = intent.getStringExtra(OneToOneChatIntent.EXTRA_MESSAGE_ID);\n        try {\n            chatApi.markMessageAsRead(msgId);\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }       \n        Log.i(TAG, \"Receive message \" + msgId  + \" from \" + remote.toString());\n        \n        // Open a conversation with a remote contact who has sent a chat message\n        try {\n            OneToOneChat chat = chatApi.getOneToOneChat(remote);\n            chat.openChat();\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }*/       \n    }\n        \n    // TODO: delivery report\n    // TODO: other Intents\n    // TODO: database directly (ie. Antivirus)\n}\n"
  },
  {
    "path": "tests/samples/src/com/gsma/rcs/api/CodeSamplesInstrumentationTestRunner.java",
    "content": "package com.gsma.rcs.api;\n\nimport android.test.InstrumentationTestRunner;\nimport android.test.InstrumentationTestSuite;\n\nimport junit.framework.TestSuite;\n\npublic class CodeSamplesInstrumentationTestRunner extends InstrumentationTestRunner {\n\n    @Override\n    public TestSuite getAllTests() {\n        InstrumentationTestSuite suite = new InstrumentationTestSuite(this);\n\n        suite.addTestSuite(ContactSampleTest.class);\n        return suite;\n    }\n\n    @Override\n    public ClassLoader getLoader() {\n        return CodeSamplesInstrumentationTestRunner.class.getClassLoader();\n    }\n}\n"
  },
  {
    "path": "tests/samples/src/com/gsma/rcs/api/ContactSampleTest.java",
    "content": "package com.gsma.rcs.api;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsPersistentStorageException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactService;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.contact.RcsContact;\n\nimport android.test.AndroidTestCase;\nimport android.util.Log;\n\nimport java.util.Set;\n\npublic class ContactSampleTest extends AndroidTestCase {\n    private static final String TAG = \"RCSAPI\";\n\n    private ContactId remote; \n    \n    private ContactService contactApi;\n    \n    private Synchronizer synchro = new Synchronizer();\n\n    protected void setUp() throws Exception {\n        super.setUp();\n        \n        // Format a remote phone number for testing\n        try {\n            remote =  ContactUtil.getInstance(mContext).formatContact(\"+33681639059\"); \n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        assertNotNull(remote);\n    }\n   \n    protected void tearDown() throws Exception {\n        super.tearDown();\n    }\n\n    /**\n     * Format a contact\n     */\n    public void testFormatContact() {\n        Log.i(TAG, \"testFormatContact\");\n        \n        try {\n            ContactId contact =  ContactUtil.getInstance(mContext).formatContact(\"06 81 63 90 59\");\n            Log.i(TAG, \"Formatted contact: \" + contact.toString());\n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        assertNotNull(remote);\n    }\n        \n    \n    /**\n     * Test API methods\n     */\n    public void testApiMethods() {\n        Log.i(TAG, \"testApiMethods\");\n\n        // Instanciate the API\n        contactApi = new ContactService(mContext, new RcsServiceListener() {\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                Log.i(TAG, \"Disconnected from the RCS service\");\n            }\n\n            @Override\n            public void onServiceConnected() {\n                Log.i(TAG, \"Connected to the RCS service\");\n                \n                // Test any API method which requires a binding to the API\n                getRcsContactInfo();\n                getRcsContactOnline();\n                getRcsContacts();\n                getRcsContactExt();\n                blockContact();\n                unblockContact();\n\n                synchro.doNotify();\n            }   \n        });\n\n        // Connect to the API\n        try {\n            contactApi.connect();\n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        \n        synchro.doWait();\n        \n        // Disconnect from the API\n        contactApi.disconnect();       \n    }\n       \n    /**\n     * Gets RCS info of a remote contact\n     */\n    public void getRcsContactInfo() {\n        Log.i(TAG, \"testGetRcsContactInfo\");\n\n        try {\n            RcsContact contact = contactApi.getRcsContact(remote);\n            if (contact != null) {\n                Log.i(TAG, \"Contact info:\");\n                Log.i(TAG, \"- Display name: \" + contact.getDisplayName());\n                Log.i(TAG, \"- Online: \" + contact.isOnline());\n                Log.i(TAG, \"- Blocked: \" + contact.isBlocked());\n            } else {\n                Log.i(TAG, \"Contact not found\");\n            }\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Gets online RCS contacts\n     */\n    public void getRcsContactOnline() {\n        Log.i(TAG, \"testGetRcsContactOnline\");\n\n        try {\n            Set<RcsContact> contacts = contactApi.getRcsContactsOnline();\n            Log.i(TAG, \"Number of contacts online: \" + contacts.size());\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Gets all RCS contacts\n     */\n    public void getRcsContacts() {\n        Log.i(TAG, \"testGetRcsContacts\");\n\n        try {\n            Set<RcsContact> contacts = contactApi.getRcsContacts();\n            Log.i(TAG, \"Number of RCS contacts: \" + contacts.size());\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n    \n    /**\n     * Gets RCS contacts supporting a given extension\n     */\n    public void getRcsContactExt() {\n        Log.i(TAG, \"testGetRcsContactExt\");\n\n        try {\n            Set<RcsContact> contacts = contactApi.getRcsContactsSupporting(\"ext.game\");\n            Log.i(TAG, \"Number of contacts supporting the extension 'ext.game': \" + contacts.size());\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n    \n    /**\n     * Blocks a remote contact\n     */\n    public void blockContact() {\n        Log.i(TAG, \"testBlockContact\");\n        \n        try {\n            contactApi.blockContact(remote);\n            RcsContact contact = contactApi.getRcsContact(remote);\n            assertTrue(contact.isBlocked());\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }\n\n    /**\n     * Unblocks a remote contact\n     */\n    public void unblockContact() {\n        Log.i(TAG, \"testUnblockContact\");\n        try {\n            contactApi.unblockContact(remote);\n            RcsContact contact = contactApi.getRcsContact(remote);\n            assertFalse(contact.isBlocked());\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsPersistentStorageException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }\n    }    \n}\n"
  },
  {
    "path": "tests/samples/src/com/gsma/rcs/api/MultimediaSessionSampleTest.java",
    "content": "package com.gsma.rcs.api;\n\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\nimport com.gsma.services.rcs.RcsServiceNotRegisteredException;\nimport com.gsma.services.rcs.contact.ContactId;\nimport com.gsma.services.rcs.contact.ContactUtil;\nimport com.gsma.services.rcs.extension.MultimediaMessagingSession;\nimport com.gsma.services.rcs.extension.MultimediaSessionService;\n\nimport android.test.AndroidTestCase;\nimport android.util.Log;\n\npublic class MultimediaSessionSampleTest extends AndroidTestCase {\n    private static final String TAG = \"RCSAPI\";\n\n    private ContactId remote; \n    \n    private MultimediaSessionService sessionApi;\n\n    private String serviceId = \"ext.sample\"; \n\n    private Synchronizer synchro = new Synchronizer();  \n    \n    protected void setUp() throws Exception {\n        super.setUp();\n        \n        // Format a remote phone number for testing\n        try {\n            remote =  ContactUtil.getInstance(mContext).formatContact(\"+33681639059\"); \n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        assertNotNull(remote);\n    }\n   \n    protected void tearDown() throws Exception {\n        super.tearDown();\n    }\n\n    /**\n     * Test API methods\n     */\n    public void testApiMethods() {\n        Log.i(TAG, \"testApiMethods\");\n\n        // Instanciate the API\n        sessionApi = new MultimediaSessionService(mContext, new RcsServiceListener() {\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                Log.i(TAG, \"Disconnected from the RCS service\");\n            }\n\n            @Override\n            public void onServiceConnected() {\n                Log.i(TAG, \"Connected to the RCS service\");\n                \n                // Test any API method which requires a binding to the API\n                initiateSession();\n                \n                synchro.doNotify();\n            }   \n        });\n\n        // Connect to the API\n        try {\n            sessionApi.connect();\n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        }\n        \n        synchro.doWait();\n        \n        // Disconnect from the API\n        sessionApi.disconnect();       \n    }      \n    \n    \n    /**\n     * Initiates a MM session with a remote contact\n     */\n    public void initiateSession() {\n        Log.i(TAG, \"testInitiateSession\");\n        \n        try {\n            MultimediaMessagingSession session= sessionApi.initiateMessagingSession(serviceId, remote);\n            // TODO\n        } catch (RcsPermissionDeniedException e) {\n            Log.e(TAG, \"Permission denied\");\n        } catch (RcsServiceNotAvailableException e) {\n            Log.e(TAG, \"RCS service not available\");\n        } catch (RcsServiceNotRegisteredException e) {\n            Log.e(TAG, \"RCS service not registered\");\n        } catch (RcsGenericException e) {\n            Log.e(TAG, \"Unexpected error\", e);\n        }       \n    }\n}\n"
  },
  {
    "path": "tests/samples/src/com/gsma/rcs/api/Synchronizer.java",
    "content": "package com.gsma.rcs.api;\n\npublic class Synchronizer {\n    \n    public void doWait() {\n        synchronized (this) {\n            try {\n                this.wait();\n            } catch (InterruptedException e) {\n            }\n        }\n    }\n\n    public void doNotify() {\n        synchronized (this) {\n            this.notify();\n        }\n    }\n}\n"
  },
  {
    "path": "tests/security-extension/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.rcs\"\n    android:versionCode=\"1\"\n    android:versionName=\"1.0\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"8\"\n        android:targetSdkVersion=\"18\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\">\n        <activity\n            android:name=\"com.gsma.rcs.MainActivity\"\n            android:label=\"@string/app_name\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n\n            <!-- Declare the joyn extension -->\n           \t<intent-filter>\n                <action android:name=\"com.gsma.services.rcs.capability.EXTENSION\"/>\n                <data android:mimeType=\"com.gsma.services.rcs/iari.test\"/>\n            </intent-filter>            \n            \n\t\t</activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "tests/security-extension/install.bat",
    "content": "C:\\_JMA_FT\\_Devices\\Android\\adt\\sdk\\platform-tools\\adb install test_security_extension.apk\r\npause"
  },
  {
    "path": "tests/security-extension/res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/app_label\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "tests/security-extension/res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "tests/security-extension/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">TestSecurity</string>\n    <string name=\"app_label\">Test security extension</string>\n\n</resources>\n"
  },
  {
    "path": "tests/security-extension/res/values/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme, dependent on API level. This theme is replaced\n        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Light\">\n        <!--\n            Theme customizations available in newer API levels can go in\n            res/values-vXX/styles.xml, while customizations related to\n            backward-compatibility can go here.\n        -->\n    </style>\n\n    <!-- Application theme. -->\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tests/security-extension/src/com/gsma/rcs/MainActivity.java",
    "content": "\npackage com.gsma.rcs;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\npublic class MainActivity extends Activity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        setContentView(R.layout.activity_main);\n    }\n}\n"
  },
  {
    "path": "tools/notification/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.rcs.registry\"\n    android:versionCode=\"1\"\n    android:versionName=\"2.0\" >\n\n    <uses-sdk\n        android:minSdkVersion=\"12\"\n        android:targetSdkVersion=\"21\" />\n\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\" />\n\n    <application\n         android:allowBackup=\"false\"\n        android:icon=\"@drawable/rcs_icon\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\" >\n        <activity android:name=\"com.gsma.rcs.notif.LaunchServiceActivity\"\n            android:label=\"@string/label_launch_service\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n\n        <receiver android:name=\"com.gsma.rcs.notif.DeviceBoot\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\"com.gsma.rcs.notif.RcsServiceNotifManager\"\n            android:exported=\"true\" >\n        </service>\n    </application>\n\n</manifest>"
  },
  {
    "path": "tools/notification/README.md",
    "content": "# IMS notification manager\n\nThis application manages a notification in the Android status bar to display the current IMS connection status.\n\n##Build instruction:\n\n<code>../../gradlew :notification:build</code>\n\nAdditional steps for Eclipse compatibility:\n\n<code>ant libs</code>\n\nThis will create the following jar files under the \"libs\" folder:\n- api.jar\n\nDownload the [android-support-v4.jar](https://developer.android.com/tools/support-library/setup.html) library and copy under the \"libs\" folder. \n"
  },
  {
    "path": "tools/notification/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.gsma.rcs.registry\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"2.0\"\n        archivesBaseName = \"notification\"\n    }\n}\n\ndependencies {\n    compile project(':api')\n    compile 'com.android.support:support-v4:25.0.1'\n}\n\n//Below install dependecy was added to always install RCS service before\n//a RCS client to secure that Android handles RCS permissions correctly.\ntask installServiceFirst(dependsOn: ':core:installDebug') << {\n    println 'RCS core service was installed first!'\n}\ntasks.whenTaskAdded { task ->\n    if (task.name == 'installDebug') {\n        task.dependsOn installServiceFirst\n    }\n}\n"
  },
  {
    "path": "tools/notification/build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"notification\" default=\"help\">\n\n\t<!-- This script to populate ./libs folder with generated jar files for building compatibility with Eclipse.\n\tThis script must be executed after dependent libraries have been generated by gradle.\n\tThis script must be removed after migration to Android Studio.\n\t-->\n\t<property name=\"terminal.root\" value=\".\" />\n\t<property name=\"terminal.lib_dst\" value=\"${terminal.root}/libs\" />\n\t<property name=\"terminal.lib_src1\" value=\"${terminal.root}/../../libs/api/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.target1\" value=\"api.jar\" />\n\n\t<target name=\"libs\">\n\t\t<echo>Copy ${terminal.target1} file</echo>\n\t\t<copy file=\"${terminal.lib_src1}\" tofile=\"${terminal.lib_dst}/${terminal.target1}\" />\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<echo>Delete library files</echo>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target1}\"/>\n\t</target>\n\n\t<target name=\"all\" depends=\"clean,libs\" />\n\n\t<target name=\"help\">\n\t\t<echo>Library Ant Build. Available targets:</echo>\n\t\t<echo> help: Displays this help.</echo>\n\t\t<echo> clean: Removes output files created by other targets.</echo>\n\t\t<echo> libs: Generate input libraries.</echo>\n\t\t<echo> all: Deletes then copy input libraries.</echo>\n\t</target>\n\n</project>\n"
  },
  {
    "path": "tools/notification/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "tools/notification/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-23\n"
  },
  {
    "path": "tools/notification/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">RCS notification</string>\n    <string name=\"label_launch_service\">RCS Notification</string>\n    <string name=\"notification_title_rcs_service\">RCS service</string>\n    <string name=\"ims_connected\">Connected to RCS platform</string>\n    <string name=\"ims_disconnected\">Disconnected from RCS platform</string>\n    <string name=\"ims_battery_disconnected\">Disconnected from RCS platform (Battery low)</string>\n\n</resources>"
  },
  {
    "path": "tools/notification/res/values/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme, dependent on API level. This theme is replaced\n        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Light\">\n        <!--\n            Theme customizations available in newer API levels can go in\n            res/values-vXX/styles.xml, while customizations related to\n            backward-compatibility can go here.\n        -->\n    </style>\n\n    <!-- Application theme. -->\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tools/notification/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">RCS Hinweis</string>\n    <string name=\"label_launch_service\">RCS Hinweis</string>\n    <string name=\"notification_title_rcs_service\">RCS-Dienst</string>\n    <string name=\"ims_connected\">Verbunden mit RCS-Server</string>\n    <string name=\"ims_disconnected\">Nicht mit RCS-Server verbunden</string>\n    <string name=\"ims_battery_disconnected\">Nicht mit RCS-Server verbunden (geringe Akkuladung)</string>\n\n</resources>"
  },
  {
    "path": "tools/notification/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">RCS notification</string>\n    <string name=\"notification_title_rcs_service\">Service RCS</string>\n    <string name=\"label_launch_service\">RCS Notification</string>\n    <string name=\"ims_connected\">Connecté à la plateforme RCS</string>\n    <string name=\"ims_disconnected\">Déconnecté de la plateforme RCS</string>\n    <string name=\"ims_battery_disconnected\">Déconnecté de la plateforme RCS (Batterie faible)</string>\n\n</resources>"
  },
  {
    "path": "tools/notification/res/values-v11/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme for API 11+. This theme completely replaces\n        AppBaseTheme from res/values/styles.xml on API 11+ devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Holo.Light\">\n        <!-- API 11 theme customizations can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tools/notification/res/values-v14/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme for API 14+. This theme completely replaces\n        AppBaseTheme from BOTH res/values/styles.xml and\n        res/values-v11/styles.xml on API 14+ devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Holo.Light.DarkActionBar\">\n        <!-- API 14 theme customizations can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tools/notification/src/com/gsma/rcs/notif/DeviceBoot.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.notif;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\n/**\n * On device boot starts the RCS service notification manager automatically\n * \n * @author Jean-Marc AUFFRET\n */\npublic class DeviceBoot extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        context.startService(new Intent(context, RcsServiceNotifManager.class));\n    }\n}\n"
  },
  {
    "path": "tools/notification/src/com/gsma/rcs/notif/LaunchServiceActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.notif;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\n\n/**\n * An activity to launch the RCS notification service\n */\npublic class LaunchServiceActivity extends Activity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        /* Starts the RCS service notification manager */\n        startService(new Intent(this, RcsServiceNotifManager.class));\n        finish();\n    }\n\n}\n"
  },
  {
    "path": "tools/notification/src/com/gsma/rcs/notif/RcsServiceNotifManager.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.notif;\n\nimport com.gsma.rcs.registry.R;\nimport com.gsma.services.rcs.RcsService;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceRegistration;\nimport com.gsma.services.rcs.RcsServiceRegistrationListener;\nimport com.gsma.services.rcs.capability.CapabilityService;\n\nimport android.app.Notification;\nimport android.app.NotificationManager;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.graphics.BitmapFactory;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.support.v4.app.NotificationCompat;\nimport android.util.Log;\n\n/**\n * Service manager that monitors the service availability and that displays the RCS status in the\n * notification bar.\n * \n * @author Jean-Marc AUFFRET\n */\npublic class RcsServiceNotifManager extends Service {\n\n    /**\n     * Flag to disable or enable log\n     */\n    private static final boolean isActive = true;\n\n    private static final String LOGTAG = new StringBuilder(\"[IMS]\").append(\n            RcsServiceNotifManager.class.getSimpleName()).toString();\n\n    private final static int NOTIF_ID = 1000;\n\n    private RcsServiceStartupListener mStartupEventReceiver;\n\n    private RcsService mServiceApi;\n\n    @Override\n    public void onCreate() {\n        if (isActive) {\n            Log.d(LOGTAG, \"Service started\");\n        }\n\n        notifyImsUnregistered(RcsServiceRegistration.ReasonCode.UNSPECIFIED);\n\n        RcsServiceStartupListener mStartupEventReceiver = new RcsServiceStartupListener();\n        registerReceiver(mStartupEventReceiver, new IntentFilter(RcsService.ACTION_SERVICE_UP));\n\n        connectToService(this);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (isActive) {\n            Log.d(LOGTAG, \"Service stopped\");\n        }\n\n        unregisterReceiver(mStartupEventReceiver);\n    }\n\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    private void connectToService(Context ctx) {\n        if (isActive) {\n            Log.d(LOGTAG, \"Try to connect to service API\");\n        }\n        try {\n            if (!RcsServiceControl.getInstance(ctx).isServiceStarted()) {\n                if (isActive) {\n                    Log.d(LOGTAG, \"RCS service not yet started\");\n                }\n                return;\n            }\n            mServiceApi = new CapabilityService(ctx, newRcsServiceListener());\n            mServiceApi.connect();\n        } catch (RcsServiceException e) {\n            if (isActive) {\n                Log.e(LOGTAG, \"Cannot connect service API\", e);\n            }\n        }\n    }\n\n    private class RcsServiceStartupListener extends BroadcastReceiver {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (!RcsService.ACTION_SERVICE_UP.equals(intent.getAction())) {\n                return;\n            }\n\n            if (isActive) {\n                Log.d(LOGTAG, \"Service UP\");\n            }\n            connectToService(context);\n        }\n    }\n\n    private RcsServiceListener newRcsServiceListener() {\n        return new RcsServiceListener() {\n            @Override\n            public void onServiceDisconnected(ReasonCode error) {\n                if (isActive) {\n                    Log.d(LOGTAG, \"Service API disconnected\");\n                }\n                notifyImsUnregistered(RcsServiceRegistration.ReasonCode.CONNECTION_LOST);\n            }\n\n            @Override\n            public void onServiceConnected() {\n                if (isActive) {\n                    Log.d(LOGTAG, \"Service API connected\");\n                }\n                try {\n                    mServiceApi.addEventListener(mRcsRegistrationListener);\n                    if (mServiceApi.isServiceRegistered()) {\n                        if (isActive) {\n                            Log.d(LOGTAG, \"IMS is registered\");\n                        }\n                        notifyImsRegistered();\n                    } else {\n                        if (isActive) {\n                            Log.d(LOGTAG, \"IMS is unregistered\");\n                        }\n                        RcsServiceRegistration.ReasonCode reason = mServiceApi\n                                .getServiceRegistrationReasonCode();\n                        notifyImsUnregistered(reason);\n                    }\n                } catch (RcsServiceException e) {\n                    if (isActive) {\n                        Log.w(LOGTAG, \"Cannot add RCS Service Registration Listener\", e);\n                    }\n                }\n            }\n        };\n    }\n\n    private RcsServiceRegistrationListener mRcsRegistrationListener = new RcsServiceRegistrationListener() {\n        @Override\n        public void onServiceUnregistered(RcsServiceRegistration.ReasonCode reason) {\n            if (isActive) {\n                Log.d(LOGTAG, \"IMS has been unregistered\");\n            }\n            notifyImsUnregistered(reason);\n        }\n\n        @Override\n        public void onServiceRegistered() {\n            if (isActive) {\n                Log.d(LOGTAG, \"IMS has been registered\");\n            }\n            notifyImsRegistered();\n        }\n    };\n\n    private void notifyImsRegistered() {\n        addImsConnectionNotification(true, getString(R.string.ims_connected));\n    }\n\n    private void notifyImsUnregistered(RcsServiceRegistration.ReasonCode reason) {\n        String label;\n        if (RcsServiceRegistration.ReasonCode.BATTERY_LOW == reason) {\n            label = getString(R.string.ims_battery_disconnected);\n        } else {\n            label = getString(R.string.ims_disconnected);\n        }\n        addImsConnectionNotification(false, label);\n    }\n\n    private void addImsConnectionNotification(boolean connected, String label) {\n        String title = this.getString(R.string.notification_title_rcs_service);\n        Notification notif = buildImsConnectionNotification(null, title, label, connected);\n        notif.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_FOREGROUND_SERVICE;\n        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);\n        notificationManager.notify(NOTIF_ID, notif);\n    }\n\n    private Notification buildImsConnectionNotification(PendingIntent intent, String title,\n            String message, boolean connected) {\n        NotificationCompat.Builder notif = new NotificationCompat.Builder(this);\n        notif.setContentIntent(intent);\n        // With Android 5.0 Lollipop it is no longer possible to use colored icons in the\n        // notification area.\n        // Only large icon supports colors but only small icon can be shown in notification bar.\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            if (connected) {\n                notif.setLargeIcon(BitmapFactory.decodeResource(getResources(),\n                        R.drawable.ri_notif_on_icon_color));\n                notif.setSmallIcon(R.drawable.ri_notif_on_icon_white);\n            } else {\n                notif.setLargeIcon(BitmapFactory.decodeResource(getResources(),\n                        R.drawable.ri_notif_off_icon_color));\n                notif.setSmallIcon(R.drawable.ri_notif_off_icon_white);\n            }\n        } else {\n            if (connected) {\n                notif.setSmallIcon(R.drawable.ri_notif_on_icon_color);\n            } else {\n                notif.setSmallIcon(R.drawable.ri_notif_off_icon_color);\n            }\n        }\n        notif.setWhen(System.currentTimeMillis());\n        notif.setAutoCancel(false);\n        notif.setOnlyAlertOnce(true);\n        notif.setContentTitle(title);\n        notif.setContentText(message);\n        return notif.build();\n    }\n}\n"
  },
  {
    "path": "tools/provisioning/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.rcs.tools.http.provisioning\"\n    android:versionCode=\"1\"\n    android:versionName=\"2.0\">\n\n    <uses-sdk\n        android:minSdkVersion=\"12\"\n        android:targetSdkVersion=\"23\" />\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@drawable/rcs_icon\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\">\n        <activity\n            android:name=\".ProvisioningTemplateActivity\"\n            android:label=\"@string/app_name\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "tools/provisioning/README.md",
    "content": "# RCS provisioning template\n\nThis application connects to the provisioning server and saves the device configuration into a template under the SDCARD.<br>\nThis template (named \"/sdcard/provisioning_template.xml\") can be used to provision the RCS core stack manually (even for other MSISDNs).<br>\nRequirement: you must have a valid SIM card to interface the provisioning server.\n"
  },
  {
    "path": "tools/provisioning/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.gsma.rcs.tools.http.provisioning\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"2.0\"\n        archivesBaseName = \"RCSJTA_provisioning_template\"\n    }\n\n}"
  },
  {
    "path": "tools/provisioning/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "tools/provisioning/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-23\n"
  },
  {
    "path": "tools/provisioning/res/layout/activity_main.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    tools:context=\"com.gsma.rcs.tools.http.provisioning.ProvisioningTemplateActivity\" >\n\n    <Button\n        android:id=\"@+id/connect\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginLeft=\"5dip\"\n        android:layout_marginRight=\"5dip\"\n        android:paddingTop=\"10dip\"\n        android:text=\"@string/button_connect\" />\n\n    <ProgressBar\n        android:id=\"@+id/pBAsync\"\n        style=\"@android:style/Widget.ProgressBar.Horizontal\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/connect\"\n        android:layout_margin=\"10dp\" />\n\n    <TextView\n        android:id=\"@+id/result\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/pBAsync\"\n      />\n\n</RelativeLayout>"
  },
  {
    "path": "tools/provisioning/res/values/dimens.xml",
    "content": "<resources>\n\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "tools/provisioning/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">RCS template</string>\n    <string name=\"button_connect\">Generate RCS provisioning template</string>\n    <string name=\"LabelPermissionsError\">You must accept permissions to use RSC Provisioning template</string>\n    <string name=\"LabelTitlePermissionsError\">ALERT</string>\n\n</resources>"
  },
  {
    "path": "tools/provisioning/res/values/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme, dependent on API level. This theme is replaced\n        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Light\">\n        <!--\n            Theme customizations available in newer API levels can go in\n            res/values-vXX/styles.xml, while customizations related to\n            backward-compatibility can go here.\n        -->\n    </style>\n\n    <!-- Application theme. -->\n    <style name=\"AppTheme\" parent=\"AppBaseTheme\">\n        <!-- All customizations that are NOT specific to a particular API-level can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tools/provisioning/res/values-v11/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme for API 11+. This theme completely replaces\n        AppBaseTheme from res/values/styles.xml on API 11+ devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Holo.Light\">\n        <!-- API 11 theme customizations can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tools/provisioning/res/values-v14/styles.xml",
    "content": "<resources>\n\n    <!--\n        Base application theme for API 14+. This theme completely replaces\n        AppBaseTheme from BOTH res/values/styles.xml and\n        res/values-v11/styles.xml on API 14+ devices.\n    -->\n    <style name=\"AppBaseTheme\" parent=\"android:Theme.Holo.Light.DarkActionBar\">\n        <!-- API 14 theme customizations can go here. -->\n    </style>\n\n</resources>\n"
  },
  {
    "path": "tools/provisioning/res/values-w820dp/dimens.xml",
    "content": "<resources>\n\n    <!--\n         Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively).\n    -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n\n</resources>\n"
  },
  {
    "path": "tools/provisioning/src/com/gsma/rcs/tools/http/provisioning/ProvisioningTemplateActivity.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTE: This file has been modified by Sony Mobile Communications Inc.\n * Modifications are licensed under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.tools.http.provisioning;\n\nimport android.Manifest;\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.pm.PackageManager;\nimport android.content.res.Configuration;\nimport android.net.Uri;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.util.Log;\nimport android.view.View;\nimport android.view.View.OnClickListener;\nimport android.widget.Button;\nimport android.widget.ProgressBar;\nimport android.widget.TextView;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.CookieHandler;\nimport java.net.CookieManager;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.NoSuchElementException;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * This activity creates a provisioning template by querying the DM server. The current MSISDN is\n * replaced by a token to be reused for manual provisioning.\n * \n * @author yplo6403\n */\npublic class ProvisioningTemplateActivity extends Activity {\n    private static final String PARAM_TERMINAL_MODEL = \"terminal_model\";\n    private static final String TOKEN_MSISDN = \"__s__MSISDN__e__\";\n    private static final String PROVISIONING_FILENAME = \"provisioning_template.xml\";\n\n    private Button mButton;\n\n    private static String REGEXP_EXTRACT_URI = \"<parm name=\\\"Public_user_Identity\\\" value=\\\"sip:(.*)@(.*)\\\"/>\";\n    /**\n     * Pattern to extract Uri from SIP header\n     */\n    private final static Pattern PATTERN_EXTRACT_URI = Pattern.compile(REGEXP_EXTRACT_URI);\n\n    /**\n     * List of permissions needed for service Just need to ask one permission per dangerous group\n     */\n    private static final Set<String> sAllPermissionsList = new HashSet<>(\n            Arrays.asList(Manifest.permission.WRITE_EXTERNAL_STORAGE));\n\n    private static final int MY_PERMISSION_REQUEST_ALL = 5428;\n    private Set<String> mPermissionsToAsk;\n\n    /**\n     * get URI from SIP identity header\n     *\n     * @param header the SIP header\n     * @return the Uri\n     */\n    public static String extractMsisdnFromProvisioningResponse(String header) {\n        Matcher matcher = PATTERN_EXTRACT_URI.matcher(header);\n        if (matcher.find()) {\n            return matcher.group(1);\n        }\n        throw new NoSuchElementException(\"Cannot found MSISDN!\");\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n        mButton = (Button) findViewById(R.id.connect);\n        mButton.setOnClickListener(btnConnectListener);\n        CookieManager cookieManager = new CookieManager();\n        CookieHandler.setDefault(cookieManager);\n    }\n\n    private OnClickListener btnConnectListener = new OnClickListener() {\n\n        @Override\n        public void onClick(View v) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                askPermissions();\n            } else {\n                onClickAfterCheckPermissions();\n            }\n        }\n    };\n\n    private void onClickAfterCheckPermissions() {\n        TextView textView = (TextView) findViewById(R.id.result);\n        ProgressBar progressBar = (ProgressBar) findViewById(R.id.pBAsync);\n        try {\n            URL url = new URL(\"http\" + \"://\" + buildProvisioningAddress());\n            HttpProvisioningClient client = new HttpProvisioningClient(url, progressBar, textView,\n                    mButton);\n            client.execute();\n        } catch (MalformedURLException e) {\n            textView.setText(\"MalformedURLException occurred: \" + e.getMessage() + \"!\");\n        }\n    }\n\n    private class HttpProvisioningClient extends AsyncTask<Object, Integer, String> {\n\n        private static final String PARAM_RCS_VERSION = \"rcs_version\";\n        private static final String PARAM_RCS_PROFILE = \"rcs_profile\";\n\n        private URL mUrl;\n        private final TextView mTextView;\n        private final ProgressBar mProgress;\n        private final Button mGenerateButton;\n\n        public HttpProvisioningClient(URL url, final ProgressBar progress, final TextView textview,\n                final Button generateButton) {\n            mUrl = url;\n            mProgress = progress;\n            mTextView = textview;\n            mGenerateButton = generateButton;\n        }\n\n        @Override\n        protected void onPreExecute() {\n            mTextView.setText(\"\");\n            mProgress.setProgress(0);\n            mProgress.setMax(100);\n            mGenerateButton.setEnabled(false);\n        }\n\n        @Override\n        protected String doInBackground(Object... arg0) {\n            return getConfig();\n        }\n\n        protected void onProgressUpdate(Integer... progress) {\n            mProgress.setProgress(progress[0]);\n        }\n\n        protected void onPostExecute(String result) {\n            mTextView.setText(result);\n            mGenerateButton.setEnabled(true);\n        }\n\n        private String getConfig() {\n            publishProgress(0);\n            HttpURLConnection urlConnection = null;\n            try {\n                /*\n                 * Firstly, we query the DM server with HTTP protocol to get the current MSISDN and\n                 * a cookie.\n                 */\n                urlConnection = (HttpURLConnection) mUrl.openConnection();\n                int respCode = urlConnection.getResponseCode();\n                String message = urlConnection.getResponseMessage();\n                if (HttpURLConnection.HTTP_OK == respCode) {\n                    mUrl = getHttpsRequestArguments();\n                    urlConnection.disconnect();\n                    urlConnection = null;\n                    publishProgress(50);\n                    /*\n                     * Secondly, we query the DM server with HTTPs to get the provisioning file.\n                     */\n                    urlConnection = (HttpURLConnection) mUrl.openConnection();\n                    respCode = urlConnection.getResponseCode();\n                    message = urlConnection.getResponseMessage();\n                    if (HttpURLConnection.HTTP_OK == respCode) {\n                        publishProgress(100);\n                        InputStream in = new BufferedInputStream(urlConnection.getInputStream());\n                        String content = readStream(in);\n                        try {\n                            String msisdn = extractMsisdnFromProvisioningResponse(content);\n                            saveProvisioningTemplate(content, msisdn);\n                        } catch (NoSuchElementException e) {\n                            return \"Second request failed: code=\" + respCode + \" message='\"\n                                    + e.getMessage() + \"'!\";\n                        }\n\n                        return \"Success! /sdcard/provisioning_template.xml is available\";\n                    } else {\n                        return \"Second request failed: code=\" + respCode + \" message='\" + message\n                                + \"'!\";\n                    }\n                } else {\n                    publishProgress(0);\n                    return \"First request failed: code=\" + respCode + \" message='\" + message + \"'!\";\n                }\n            } catch (FileNotFoundException e) {\n                publishProgress(0);\n                return \"FileNotFoundException occurred: '\" + e.getMessage() + \"'!\";\n            } catch (MalformedURLException e) {\n                publishProgress(0);\n                return \"MalformedURLException occurred: '\" + e.getMessage() + \"'!\";\n            } catch (IOException e) {\n                publishProgress(0);\n                return \"IOException occurred: '\" + e.getMessage() + \"'!\";\n            } finally {\n                if (urlConnection != null) {\n                    urlConnection.disconnect();\n                }\n            }\n        }\n\n        private String readStream(InputStream in) throws IOException {\n            try {\n                StringBuilder sb = new StringBuilder();\n                BufferedReader r = new BufferedReader(new InputStreamReader(in), 1000);\n                for (String line = r.readLine(); line != null; line = r.readLine()) {\n                    sb.append(line).append(\"\\n\");\n                }\n                return sb.toString();\n            } finally {\n                try {\n                    in.close();\n                } catch (IOException ignore) {\n\n                }\n            }\n        }\n\n        private URL getHttpsRequestArguments() throws MalformedURLException {\n            Uri.Builder uriBuilder = new Uri.Builder();\n            uriBuilder.scheme(\"https\");\n            uriBuilder.authority(buildProvisioningAddress());\n            uriBuilder.appendQueryParameter(PARAM_RCS_VERSION, \"5.1B\");\n            uriBuilder.appendQueryParameter(PARAM_RCS_PROFILE, \"joyn_blackbird\");\n            uriBuilder.appendQueryParameter(PARAM_TERMINAL_MODEL, Build.DEVICE);\n            return new URL(uriBuilder.build().toString());\n        }\n\n        private void saveProvisioningTemplate(String provisioning, String msisdn)\n                throws FileNotFoundException {\n            File dirProvTemplate = Environment.getExternalStorageDirectory();\n            PrintWriter out = null;\n            try {\n                File file = new File(dirProvTemplate, PROVISIONING_FILENAME);\n                out = new PrintWriter(file);\n                if (msisdn.startsWith(\"+\")) {\n                    msisdn = msisdn.substring(1);\n                }\n                String template = provisioning.replaceAll(msisdn, TOKEN_MSISDN);\n                out.println(template);\n            } finally {\n                if (out != null) {\n                    out.close();\n                }\n            }\n        }\n    }\n\n    private String buildProvisioningAddress() {\n        String mnc = String.format(\"%03d\", getMobileNetworkCode());\n        String mcc = String.format(\"%03d\", getMobileCountryCode());\n        return \"config.rcs.mnc\" + mnc + \".mcc\" + mcc + \".pub.3gppnetwork.org\";\n    }\n\n    private int getMobileCountryCode() {\n        Configuration config = getResources().getConfiguration();\n        return config.mcc;\n    }\n\n    private int getMobileNetworkCode() {\n        Configuration config = getResources().getConfiguration();\n        return config.mnc;\n    }\n\n    /**\n     * Main function to ask permissions\n     */\n    private void askPermissions() {\n        mPermissionsToAsk = getNotGrantedPermissions();\n        if (mPermissionsToAsk.size() > 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            requestPermissions(mPermissionsToAsk.toArray(new String[mPermissionsToAsk.size()]),\n                    MY_PERMISSION_REQUEST_ALL);\n        } else {\n            onClickAfterCheckPermissions();\n        }\n    }\n\n    /**\n     * Check all permissions's status\n     * \n     * @return Set of permissions that are not granted\n     */\n    private Set<String> getNotGrantedPermissions() {\n        Set<String> permissionsToAsk = new HashSet<>();\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            return permissionsToAsk;\n        }\n        for (String permission : sAllPermissionsList) {\n            if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(permission)) {\n                permissionsToAsk.add(permission);\n            }\n        }\n        return permissionsToAsk;\n    }\n\n    @Override\n    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {\n        switch (requestCode) {\n            case MY_PERMISSION_REQUEST_ALL:\n                Set<String> grantedPermissions = new HashSet<>();\n                for (int i = 0; i < permissions.length; i++) {\n                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {\n                        grantedPermissions.add(permissions[i]);\n                    } else if (grantResults[i] == PackageManager.PERMISSION_DENIED) {\n                        Log.w(\"Permissions\", \"Permission Denied: \" + permissions[i]);\n                    }\n                }\n                if (grantedPermissions.equals(mPermissionsToAsk)) {\n                    onClickAfterCheckPermissions();\n                } else {\n                    AlertDialog.Builder builder = new AlertDialog.Builder(\n                            ProvisioningTemplateActivity.this);\n                    builder.setMessage(getString(R.string.LabelPermissionsError)).setTitle(\n                            getString(R.string.LabelTitlePermissionsError));\n                    AlertDialog dialog = builder.create();\n                    dialog.show();\n                }\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "tools/settings/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.gsma.rcs.core.control\">\n\n    <uses-permission android:name=\"com.gsma.services.permission.RCS\" />\n\n    <application\n        android:name=\"com.gsma.rcs.core.control.CoreControlApplication\"\n        android:icon=\"@drawable/rcs_icon\"\n        android:label=\"@string/app_name\">\n        <activity\n            android:name=\"com.gsma.rcs.core.control.settings.SettingsDisplay\"\n            android:icon=\"@drawable/rcs_icon\"\n            android:label=\"@string/rcs_settings_title_settings\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\"com.gsma.rcs.core.control.settings.UserprofileSettingsDisplay\"\n            android:label=\"@string/rcs_settings_title_userprofile_settings\" />\n        <activity\n            android:name=\"com.gsma.rcs.core.control.settings.MessagingSettingsDisplay\"\n            android:label=\"@string/rcs_settings_title_messaging_settings\" />\n        <activity\n            android:name=\"com.gsma.rcs.core.control.settings.AboutSettings\"\n            android:label=\"@string/rcs_settings_title_about\" />\n\n        <receiver\n            android:name=\"com.gsma.rcs.core.control.settings.ControlCoreReceiver\"\n            android:exported=\"true\">\n            <intent-filter>\n                <action android:name=\"com.gsma.services.rcs.action.VIEW_SETTINGS\" />\n            </intent-filter>\n        </receiver>\n    </application>\n\n</manifest>"
  },
  {
    "path": "tools/settings/README.md",
    "content": "# RCS core stack settings\n\nThis application controls the activation of the RCS core stack.<br>\nIt also displays the RCS core stack settings and enables user to modify them.\n\n##Build instruction:\n\n<code>../../gradlew :settings:build</code>\n\n**Additional steps for Eclipse compatibility:**\n\n<code>ant libs</code>\n\nThis will create the following jar files under the \"libs\" folder:\n- api.jar\n- api_cnx.jar\n\nSet up the api connection library by importing the Android project '../libs/api_cnx/build/intermediates/bundles/debug/'"
  },
  {
    "path": "tools/settings/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n\n    //Required to support the old folder structure\n    sourceSets {\n        main {\n            manifest.srcFile 'AndroidManifest.xml'\n            java.srcDirs = ['src']\n            resources.srcDirs = ['src']\n            aidl.srcDirs = ['src']\n            renderscript.srcDirs = ['src']\n            res.srcDirs = ['res']\n            assets.srcDirs = ['assets']\n            jniLibs.srcDirs = ['libs']\n        }\n        androidTest.setRoot('tests')\n    }\n\n    //Required to support builds although lint errors exist\n    lintOptions {\n        abortOnError false\n    }\n\n    compileSdkVersion rootProject.compileSdkVersion\n    buildToolsVersion rootProject.buildToolsVersion\n\n    defaultConfig {\n        applicationId \"com.gsma.rcs.core.control\"\n        minSdkVersion rootProject.minSdkVersion\n        targetSdkVersion rootProject.targetSdkVersion\n        versionCode 1\n        versionName \"2.0\"\n        archivesBaseName = \"settings\"\n    }\n}\n\ndependencies {\n    compile project(':api')\n    compile project(':api_cnx')\n}\n\n//Below install dependecy was added to always install RCS service before\n//a RCS client to secure that Android handles RCS permissions correctly.\ntask installServiceFirst(dependsOn: ':core:installDebug') << {\n    println 'RCS core service was installed first!'\n}\ntasks.whenTaskAdded { task ->\n    if (task.name == 'installDebug') {\n        task.dependsOn installServiceFirst\n    }\n}\n"
  },
  {
    "path": "tools/settings/build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project name=\"settings\" default=\"help\">\n\n\t<!-- This script to populate ./libs folder with generated jar files for building compatibility with Eclipse.\n\tThis script must be executed after dependent libraries have been generated by gradle.\n\tThis script must be removed after migration to Android Studio.\n\t-->\n\t<property name=\"terminal.root\" value=\".\" />\n\t<property name=\"terminal.lib_dst\" value=\"${terminal.root}/libs\" />\n\t<property name=\"terminal.lib_src1\" value=\"${terminal.root}/../../libs/api/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.target1\" value=\"api.jar\" />\n\t<property name=\"terminal.lib_src2\" value=\"${terminal.root}/../../libs/api_cnx/build/intermediates/bundles/release/classes.jar\" />\n\t<property name=\"terminal.target2\" value=\"api_cnx.jar\" />\n\n\t<target name=\"libs\">\n\t\t<echo>Copy ${terminal.target1} file</echo>\n\t\t<copy file=\"${terminal.lib_src1}\" tofile=\"${terminal.lib_dst}/${terminal.target1}\" />\n\t\t<echo>Copy ${terminal.target2} file</echo>\n\t\t<copy file=\"${terminal.lib_src2}\" tofile=\"${terminal.lib_dst}/${terminal.target2}\" />\n\t</target>\n\n\t<target name=\"clean\">\n\t\t<echo>Delete library files</echo>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target1}\"/>\n\t\t<delete file=\"${terminal.lib_dst}/${terminal.target2}\"/>\n\t</target>\n\n\t<target name=\"all\" depends=\"clean,libs\" />\n\n\t<target name=\"help\">\n\t\t<echo>Library Ant Build. Available targets:</echo>\n\t\t<echo> help: Displays this help.</echo>\n\t\t<echo> clean: Removes output files created by other targets.</echo>\n\t\t<echo> libs: Generate input libraries.</echo>\n\t\t<echo> all: Deletes then copy input libraries.</echo>\n\t</target>\n\n</project>\n"
  },
  {
    "path": "tools/settings/project.properties",
    "content": "# This file is automatically generated by Android Tools.\n# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n#\n# This file must be checked in Version Control Systems.\n#\n# To customize properties used by the Ant build system edit\n# \"ant.properties\", and override values to adapt the script to your\n# project structure.\n#\n# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):\n#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt\n\n# Project target.\ntarget=android-23\nandroid.library.reference.1=../../libs/api_cnx/build/intermediates/bundles/debug\n"
  },
  {
    "path": "tools/settings/res/layout/app_about.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"fill_parent\"\n    android:orientation=\"vertical\" >\n\n    <ImageView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"10dp\"\n        android:layout_marginTop=\"10dp\"\n        android:src=\"@drawable/rcs_icon\" >\n    </ImageView>\n\n    <TextView\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:text=\"@string/label_about_title\"\n        android:textAppearance=\"?android:attr/textAppearanceLarge\"\n        android:textStyle=\"bold\" />\n\n    <TextView\n        android:id=\"@+id/app_version\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n    <TextView\n        android:id=\"@+id/gsma_version\"\n        android:layout_width=\"fill_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\"\n        android:gravity=\"center_vertical|center_horizontal\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\" />\n\n</LinearLayout>"
  },
  {
    "path": "tools/settings/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <string name=\"app_name\">RCS settings</string>\n    <string name=\"title_msg\">Information</string>\n    <string name=\"menu_about\">About</string>\n    <string name=\"rcs_settings_label_ok\">OK</string>\n    <string name=\"rcs_settings_label_cancel\">Cancel</string>\n    <string name=\"rcs_settings_title_settings\">RCS Settings</string>\n    <string name=\"rcs_settings_title_userprofile_settings\">User profile settings</string>\n    <string name=\"rcs_settings_title_messaging_settings\">Messaging settings</string>\n    <string name=\"rcs_settings_title_filetransfer_invitation\">File transfer settings</string>\n    <string name=\"rcs_settings_title_chat_invitation\">Chat settings</string>\n    <string name=\"rcs_settings_title_about\">About settings</string>\n    <string name=\"rcs_settings_summary_about\">About the RCS service</string>\n    <string name=\"rcs_settings_summary_messaging_settings\">Manage messaging settings</string>\n    <string name=\"rcs_settings_summary_rcs_service_on\">Select to turn off the RCS service</string>\n    <string name=\"rcs_settings_summary_rcs_service_off\">Select to turn on the RCS service</string>\n    <string name=\"rcs_settings_summary_min_battery_level\">Stop the RCS service if battery low</string>\n    <string name=\"rcs_settings_summary_image_resize_option\">Select the resize option for outgoing image transfer</string>\n    <string name=\"rcs_settings_summary_ft_auto_accept\">Auto accept file transfer</string>\n    <string name=\"rcs_settings_summary_ft_auto_accept_in_roaming\">Auto accept file transfer while roaming</string>\n    <string name=\"rcs_settings_summary_chat_displayed_notification\">Send displayed notification during a chat</string>\n    <string name=\"rcs_settings_summary_messaging_method\">Select messaging method</string>\n    <string name=\"rcs_settings_label_displayed_notification\">Displayed notification</string>\n    <string name=\"rcs_settings_label_rcs_service\">RCS service</string>\n    <string name=\"rcs_settings_label_confirm\">Confirmation</string>\n    <string name=\"rcs_settings_label_rcs_service_shutdown\">RCS service will be terminated</string>\n    <string name=\"rcs_settings_label_ft_auto_accept\">Auto accept</string>\n    <string name=\"rcs_settings_label_ft_auto_accept_in_roaming\">Auto accept in roaming</string>\n    <string name=\"rcs_settings_label_min_battery_level\">Minimum battery level</string>\n    <string name=\"rcs_settings_label_messaging_method\">Messaging method</string>\n    <string name=\"rcs_settings_label_albatros_20\">Albatros 2.0</string>\n    <string name=\"rcs_settings_label_blackbird_15\">Blackbird 1.5</string>\n    <string name=\"rcs_settings_label_unknown\">Unknown</string>\n\t<string name=\"rcs_settings_label_wait_cnx_start\">Initializing...</string>\n\t\n    <!-- About menu -->\n    <string name=\"label_about_title\">RCS service</string>\n    <string name=\"label_about_app_version\">App release %s</string>\n    <string name=\"label_api_unavailable\">RCS service not available</string>\n    <string name=\"label_api_failed\">Call API method has failed</string>\n    <string name=\"label_service_not_available\">The service is not available. Please retry later.</string>\n    <string name=\"text_service_activate_unchangeable\">RCS activation cannot be changed</string>\n\n    <string-array name=\"rcs_settings_list_messaging_method_value\">\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </string-array>\n    <string-array name=\"rcs_settings_list_messaging_method_label\">\n        <item>Automatic</item>\n        <item>RCS</item>\n        <item>Non RCS</item>\n    </string-array>\n    <string-array name=\"rcs_settings_list_battery_level_value\">\n        <item>0</item>\n        <item>5</item>\n        <item>10</item>\n        <item>20</item>\n    </string-array>\n    <string-array name=\"rcs_settings_list_battery_level_label\">\n        <item>Never stop</item>\n        <item>5%</item>\n        <item>10%</item>\n        <item>20%</item>\n    </string-array>\n\n    <string name=\"rcs_settings_summary_userprofile_settings\">Manage user profile settings</string>\n    <string name=\"rcs_settings_title_caller_id\">Caller identity</string>\n    <string name=\"rcs_settings_title_displayname\">Display name</string>\n    <string name=\"rcs_settings_summary_edit_displayname\">Display name associated to my phone number in outgoing calls</string>\n    <string name=\"rcs_settings_label_image_resize_option\">Image resize option</string>\n\n    <string-array name=\"rcs_settings_list_image_resize_option_value\">\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </string-array>\n    <string-array name=\"rcs_settings_list_image_resize_option_label\">\n        <item>Always perform</item>\n        <item>Only above maximum size</item>\n        <item>Ask</item>\n    </string-array>\n\n</resources>"
  },
  {
    "path": "tools/settings/res/xml/rcs_settings_messaging_preferences.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <ListPreference\n        android:dialogTitle=\"@string/rcs_settings_label_messaging_method\"\n        android:entries=\"@array/rcs_settings_list_messaging_method_label\"\n        android:entryValues=\"@array/rcs_settings_list_messaging_method_value\"\n        android:key=\"messaging_method\"\n        android:summary=\"@string/rcs_settings_summary_messaging_method\"\n        android:title=\"@string/rcs_settings_label_messaging_method\" />\n\n    <PreferenceCategory android:title=\"@string/rcs_settings_title_filetransfer_invitation\" >\n        <CheckBoxPreference\n            android:key=\"ft_auto_accept\"\n            android:showDefault=\"true\"\n            android:summary=\"@string/rcs_settings_summary_ft_auto_accept\"\n            android:title=\"@string/rcs_settings_label_ft_auto_accept\" />\n        <CheckBoxPreference\n            android:key=\"ft_auto_accept_in_roaming\"\n            android:showDefault=\"true\"\n            android:summary=\"@string/rcs_settings_summary_ft_auto_accept_in_roaming\"\n            android:title=\"@string/rcs_settings_label_ft_auto_accept_in_roaming\" />\n\n        <ListPreference\n            android:dialogTitle=\"@string/rcs_settings_label_image_resize_option\"\n            android:entries=\"@array/rcs_settings_list_image_resize_option_label\"\n            android:entryValues=\"@array/rcs_settings_list_image_resize_option_value\"\n            android:key=\"image_resize_option\"\n            android:summary=\"@string/rcs_settings_summary_image_resize_option\"\n            android:title=\"@string/rcs_settings_label_image_resize_option\" />\n    </PreferenceCategory>\n    <PreferenceCategory android:title=\"@string/rcs_settings_title_chat_invitation\" >\n        <CheckBoxPreference\n            android:key=\"chat_displayed_notification\"\n            android:showDefault=\"true\"\n            android:summary=\"@string/rcs_settings_summary_chat_displayed_notification\"\n            android:title=\"@string/rcs_settings_label_displayed_notification\" />\n    </PreferenceCategory>\n\n</PreferenceScreen>"
  },
  {
    "path": "tools/settings/res/xml/rcs_settings_preferences.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <CheckBoxPreference\n        android:key=\"rcs_activation\"\n        android:summaryOff=\"@string/rcs_settings_summary_rcs_service_off\"\n        android:summaryOn=\"@string/rcs_settings_summary_rcs_service_on\"\n        android:title=\"@string/rcs_settings_label_rcs_service\" />\n\n    <ListPreference\n        android:dialogTitle=\"@string/rcs_settings_label_min_battery_level\"\n        android:entries=\"@array/rcs_settings_list_battery_level_label\"\n        android:entryValues=\"@array/rcs_settings_list_battery_level_value\"\n        android:key=\"min_battery_level\"\n        android:summary=\"@string/rcs_settings_summary_min_battery_level\"\n        android:title=\"@string/rcs_settings_label_min_battery_level\" />\n\n    <PreferenceScreen\n        android:key=\"userprofile_settings\"\n        android:summary=\"@string/rcs_settings_summary_userprofile_settings\"\n        android:title=\"@string/rcs_settings_title_userprofile_settings\" >\n        <intent\n            android:action=\"android.intent.action.MAIN\"\n            android:targetClass=\"com.gsma.rcs.core.control.settings.UserprofileSettingsDisplay\"\n            android:targetPackage=\"com.gsma.rcs.core.control\" />\n    </PreferenceScreen>\n    <PreferenceScreen\n        android:key=\"messaging_settings\"\n        android:summary=\"@string/rcs_settings_summary_messaging_settings\"\n        android:title=\"@string/rcs_settings_title_messaging_settings\" >\n        <intent\n            android:action=\"android.intent.action.MAIN\"\n            android:targetClass=\"com.gsma.rcs.core.control.settings.MessagingSettingsDisplay\"\n            android:targetPackage=\"com.gsma.rcs.core.control\" />\n    </PreferenceScreen>\n    <PreferenceScreen\n        android:key=\"about_settings\"\n        android:summary=\"@string/rcs_settings_summary_about\"\n        android:title=\"@string/menu_about\" >\n        <intent\n            android:action=\"android.intent.action.MAIN\"\n            android:targetClass=\"com.gsma.rcs.core.control.settings.AboutSettings\"\n            android:targetPackage=\"com.gsma.rcs.core.control\" />\n    </PreferenceScreen>\n\n</PreferenceScreen>"
  },
  {
    "path": "tools/settings/res/xml/rcs_settings_userprofile_preferences.xml",
    "content": "<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n\n    <PreferenceCategory android:title=\"@string/rcs_settings_title_caller_id\" >\n        <EditTextPreference\n            android:dialogTitle=\"@string/rcs_settings_title_displayname\"\n            android:key=\"edit_displayname\"\n            android:maxLength=\"25\"\n            android:summary=\"@string/rcs_settings_summary_edit_displayname\" />\n    </PreferenceCategory>\n\n</PreferenceScreen>"
  },
  {
    "path": "tools/settings/src/com/gsma/rcs/core/control/CoreControlApplication.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.control;\n\nimport com.gsma.services.rcs.RcsServiceControl;\n\nimport com.gsma.rcs.api.connection.ConnectionManager;\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Handler;\nimport android.os.Looper;\n\n/**\n * This subclass of Application allows to get a resource content from a static context\n * \n * @author Philippe LEMORDANT\n */\npublic class CoreControlApplication extends Application {\n\n    /**\n     * Delay (ms) before starting connection manager.\n     */\n    public static final long DELAY_FOR_STARTING_CNX_MANAGER = 2000;\n\n    public static boolean sCnxManagerStarted = false;\n\n    private static RcsServiceControl mRcsServiceControl;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        Context context = getApplicationContext();\n        mRcsServiceControl = RcsServiceControl.getInstance(context);\n\n        final ConnectionManager cnxManager = ConnectionManager.createInstance(context,\n                mRcsServiceControl, RcsServiceName.FILE_TRANSFER, RcsServiceName.CHAT,\n                RcsServiceName.CONTACT);\n\n        /* Do not execute the ConnectionManager on the main thread */\n        Handler mainThreadHandler = new Handler(Looper.getMainLooper());\n\n        mainThreadHandler.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                cnxManager.start();\n                sCnxManagerStarted = true;\n            }\n        }, DELAY_FOR_STARTING_CNX_MANAGER);\n    }\n\n    /**\n     * Gets the RCS service control singleton\n     * \n     * @return the RCS service control singleton\n     */\n    public static RcsServiceControl getRcsServiceControl() {\n        return mRcsServiceControl;\n    }\n\n}\n"
  },
  {
    "path": "tools/settings/src/com/gsma/rcs/core/control/settings/AboutSettings.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.control.settings;\n\nimport com.gsma.services.rcs.RcsService.Build;\n\nimport com.gsma.rcs.core.control.R;\n\nimport android.app.Activity;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.widget.TextView;\n\n/**\n * About the Core stack\n * \n * @author Jean-Marc AUFFRET\n */\npublic class AboutSettings extends Activity {\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        /* Set layout */\n        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);\n        setContentView(R.layout.app_about);\n\n        // Display application release\n        TextView releaseView = (TextView) findViewById(R.id.app_version);\n        releaseView.setText(getString(R.string.label_about_app_version, getAppVersion()));\n\n        // Display GSMA version\n        TextView gsmaView = (TextView) findViewById(R.id.gsma_version);\n        gsmaView.setText(getGsmaVersion());\n    }\n\n    /**\n     * Returns the application version from manifest file\n     *\n     * @return Application version or null if not found\n     */\n    private String getAppVersion() {\n        String version = null;\n        try {\n            PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), 0);\n            version = info.versionName + \".\" + info.versionCode;\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        return version;\n    }\n\n    /**\n     * Returns the GSMA version\n     *\n     * @return String\n     */\n    private String getGsmaVersion() {\n        StringBuilder version = new StringBuilder(Build.API_CODENAME);\n        version.append(\" \");\n        switch (Build.API_VERSION) {\n            case Build.VERSION_CODES.BASE:\n                version.append(\"Albatros 2.0.\");\n                break;\n            case Build.VERSION_CODES.BLACKBIRD:\n                version.append(\"Blackbird 1.5.\");\n                break;\n            case Build.VERSION_CODES.CPR:\n                version.append(\"Crane Priority Release 1.6.\");\n                break;\n            default:\n                version.append(\"Unknown 0.0\");\n        }\n        version.append(Build.API_INCREMENTAL);\n        return version.toString();\n    }\n}\n"
  },
  {
    "path": "tools/settings/src/com/gsma/rcs/core/control/settings/ControlCoreReceiver.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.control.settings;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.Log;\n\n/**\n * Control Core receiver\n * \n * @author YPLO6403\n */\npublic class ControlCoreReceiver extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        Log.e(\"[RI]\", \"Broadcast is received\");\n        Intent displaySettings = new Intent(context, SettingsDisplay.class);\n        displaySettings.putExtras(intent);\n        displaySettings.setAction(intent.getAction());\n        displaySettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        context.startActivity(displaySettings);\n    }\n\n}\n"
  },
  {
    "path": "tools/settings/src/com/gsma/rcs/core/control/settings/MessagingSettingsDisplay.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.control.settings;\n\nimport com.gsma.services.rcs.CommonServiceConfiguration.MessagingMethod;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.filetransfer.FileTransferService;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration;\nimport com.gsma.services.rcs.filetransfer.FileTransferServiceConfiguration.ImageResizeOption;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsPreferenceActivity;\nimport com.gsma.rcs.core.control.R;\n\nimport android.os.Bundle;\nimport android.preference.CheckBoxPreference;\nimport android.preference.ListPreference;\nimport android.preference.Preference;\n\n/**\n * Messaging settings display\n *\n * @author jexa7410\n */\n@SuppressWarnings(\"deprecation\")\npublic class MessagingSettingsDisplay extends RcsPreferenceActivity implements\n        Preference.OnPreferenceChangeListener {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        addPreferencesFromResource(R.xml.rcs_settings_messaging_preferences);\n\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER, RcsServiceName.CHAT)) {\n            showMessage(R.string.label_service_not_available);\n            return;\n        }\n\n        ListPreference messagingMethod = (ListPreference) findPreference(\"messaging_method\");\n        messagingMethod.setPersistent(false);\n        messagingMethod.setOnPreferenceChangeListener(this);\n\n        CheckBoxPreference chat_displayed_notification = (CheckBoxPreference) findPreference(\"chat_displayed_notification\");\n        chat_displayed_notification.setPersistent(false);\n        chat_displayed_notification.setOnPreferenceChangeListener(this);\n\n        ListPreference imageResizeOption = (ListPreference) findPreference(\"image_resize_option\");\n        imageResizeOption.setPersistent(false);\n        imageResizeOption.setOnPreferenceChangeListener(this);\n\n        CheckBoxPreference ftAutoAccept = (CheckBoxPreference) findPreference(\"ft_auto_accept\");\n        ftAutoAccept.setPersistent(false);\n        ftAutoAccept.setOnPreferenceChangeListener(this);\n        ftAutoAccept.setDisableDependentsState(false);\n        ftAutoAccept.setShouldDisableView(true);\n\n        CheckBoxPreference ftAutoAcceptInRoaming = (CheckBoxPreference) findPreference(\"ft_auto_accept_in_roaming\");\n        ftAutoAcceptInRoaming.setPersistent(false);\n        ftAutoAcceptInRoaming.setOnPreferenceChangeListener(this);\n        ftAutoAcceptInRoaming.setDependency(\"ft_auto_accept\");\n        try {\n            FileTransferService fileTransferService = getFileTransferApi();\n            FileTransferServiceConfiguration configuration = fileTransferService.getConfiguration();\n            chat_displayed_notification.setChecked(getChatApi().getConfiguration()\n                    .isRespondToDisplayReportsEnabled());\n            imageResizeOption\n                    .setValue(String.valueOf(configuration.getImageResizeOption().toInt()));\n            ftAutoAccept.setChecked(configuration.isAutoAcceptEnabled());\n            ftAutoAccept.setEnabled(configuration.isAutoAcceptModeChangeable());\n            ftAutoAcceptInRoaming.setChecked(configuration.isAutoAcceptInRoamingEnabled());\n            messagingMethod.setValue(String.valueOf(fileTransferService.getCommonConfiguration()\n                    .getDefaultMessagingMethod().toInt()));\n            startMonitorServices(RcsServiceName.FILE_TRANSFER);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    public boolean onPreferenceChange(Preference preference, Object objValue) {\n        try {\n            if (\"chat_displayed_notification\".equals(preference.getKey())) {\n                getChatApi().getConfiguration().setRespondToDisplayReports((Boolean) objValue);\n            } else if (\"image_resize_option\".equals(preference.getKey())) {\n                ImageResizeOption option = ImageResizeOption.valueOf(Integer\n                        .parseInt((String) objValue));\n                getFileTransferApi().getConfiguration().setImageResizeOption(option);\n            } else if (\"ft_auto_accept\".equals(preference.getKey())) {\n                Boolean aa = (Boolean) objValue;\n                getFileTransferApi().getConfiguration().setAutoAccept(aa);\n                if (!aa) {\n                    getFileTransferApi().getConfiguration().setAutoAcceptInRoaming(false);\n                }\n            } else if (\"ft_auto_accept_in_roaming\".equals(preference.getKey())) {\n                getFileTransferApi().getConfiguration().setAutoAcceptInRoaming((Boolean) objValue);\n            } else if (\"messaging_method\".equals(preference.getKey())) {\n                getFileTransferApi().getCommonConfiguration().setDefaultMessagingMethod(\n                        MessagingMethod.valueOf(Integer.parseInt((String) objValue)));\n            }\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "tools/settings/src/com/gsma/rcs/core/control/settings/SettingsDisplay.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.control.settings;\n\nimport com.gsma.services.rcs.CommonServiceConfiguration;\nimport com.gsma.services.rcs.CommonServiceConfiguration.MinimumBatteryLevel;\nimport com.gsma.services.rcs.RcsGenericException;\nimport com.gsma.services.rcs.RcsPermissionDeniedException;\nimport com.gsma.services.rcs.RcsServiceControl;\nimport com.gsma.services.rcs.RcsServiceException;\nimport com.gsma.services.rcs.RcsServiceListener;\nimport com.gsma.services.rcs.RcsServiceNotAvailableException;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.ExceptionUtil;\nimport com.gsma.rcs.api.connection.utils.RcsPreferenceActivity;\nimport com.gsma.rcs.core.control.CoreControlApplication;\nimport com.gsma.rcs.core.control.R;\n\nimport android.app.AlertDialog;\nimport android.app.Dialog;\nimport android.app.ProgressDialog;\nimport android.content.DialogInterface;\nimport android.os.AsyncTask;\nimport android.os.Bundle;\nimport android.preference.CheckBoxPreference;\nimport android.preference.ListPreference;\nimport android.preference.Preference;\nimport android.preference.PreferenceScreen;\nimport android.util.Log;\n\n/**\n * Settings display\n * \n * @author Jean-Marc AUFFRET\n */\n@SuppressWarnings(\"deprecation\")\npublic class SettingsDisplay extends RcsPreferenceActivity implements\n        Preference.OnPreferenceChangeListener {\n\n    private static final int PROGRESS_INIT_INCREMENT = 100;\n\n    private final static int SERVICE_DEACTIVATION_CONFIRMATION_DIALOG = 1;\n\n    private static final String LOGTAG = \"[SET][\" + SettingsDisplay.class.getSimpleName() + \"]\";\n\n    private RcsServiceControl mRcsServiceControl;\n\n    private CheckBoxPreference mRcsActivationCheckbox;\n\n    private ListPreference mBatteryLevel;\n\n    private RcsServiceListener mRcsServiceListener;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        addPreferencesFromResource(R.xml.rcs_settings_preferences);\n\n        initialize();\n\n        mRcsActivationCheckbox = (CheckBoxPreference) getPreferenceScreen().findPreference(\n                \"rcs_activation\");\n        mBatteryLevel = (ListPreference) findPreference(\"min_battery_level\");\n\n        mRcsServiceControl = CoreControlApplication.getRcsServiceControl();\n\n        if (!CoreControlApplication.sCnxManagerStarted) {\n            new WaitForConnectionManagerStart()\n                    .execute(CoreControlApplication.DELAY_FOR_STARTING_CNX_MANAGER);\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        Log.i(LOGTAG, \"onResume\");\n        startMonitorApiCnx(mRcsServiceListener, RcsServiceName.FILE_TRANSFER, RcsServiceName.CHAT);\n\n        if (!mRcsServiceControl.isAvailable()) {\n            initCheckbox(mRcsActivationCheckbox, false, false);\n            enablePreferences(false);\n            showMessage(R.string.label_service_not_available);\n            return;\n        }\n\n        try {\n            boolean isServiceActivated = mRcsServiceControl.isActivated();\n            boolean isChangeable = mRcsServiceControl.isActivationModeChangeable();\n            boolean isServiceConnected = isServiceConnected(RcsServiceName.FILE_TRANSFER);\n            initCheckbox(mRcsActivationCheckbox, (isServiceActivated), isChangeable);\n            enablePreferences(isServiceActivated && isServiceConnected);\n            if (isServiceConnected) {\n                initBatteryLevel(getFileTransferApi().getCommonConfiguration());\n            }\n\n        } catch (RcsServiceException e) {\n            enablePreferences(false);\n            Log.d(LOGTAG, e.getMessage());\n        }\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        stopMonitorApiCnx();\n    }\n\n    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {\n        try {\n            if (preference == mRcsActivationCheckbox) {\n                if (mRcsActivationCheckbox.isChecked()) {\n                    try {\n                        mRcsServiceControl.setActivationMode(true);\n\n                    } catch (RcsPermissionDeniedException e) {\n                        showMessage(R.string.text_service_activate_unchangeable);\n                    }\n                } else {\n                    if (mRcsServiceControl.isActivated()) {\n                        showDialog(SERVICE_DEACTIVATION_CONFIRMATION_DIALOG);\n                    }\n                }\n                return true;\n            }\n        } catch (RcsServiceException e) {\n            showException(e);\n        }\n        return super.onPreferenceTreeClick(preferenceScreen, preference);\n    }\n\n    @Override\n    protected Dialog onCreateDialog(int id) {\n        switch (id) {\n            case SERVICE_DEACTIVATION_CONFIRMATION_DIALOG:\n                AlertDialog dialog = new AlertDialog.Builder(this)\n                        .setIcon(android.R.drawable.ic_dialog_info)\n                        .setTitle(R.string.rcs_settings_label_confirm)\n                        .setMessage(R.string.rcs_settings_label_rcs_service_shutdown)\n                        .setNegativeButton(R.string.rcs_settings_label_cancel,\n                                new DialogInterface.OnClickListener() {\n                                    public void onClick(DialogInterface dialog, int button) {\n                                        mRcsActivationCheckbox.setChecked(!mRcsActivationCheckbox\n                                                .isChecked());\n                                    }\n                                })\n                        .setOnCancelListener(new DialogInterface.OnCancelListener() {\n                            public void onCancel(DialogInterface dialog) {\n                                mRcsActivationCheckbox.setChecked(!mRcsActivationCheckbox\n                                        .isChecked());\n                            }\n                        })\n                        .setPositiveButton(R.string.rcs_settings_label_ok,\n                                new DialogInterface.OnClickListener() {\n                                    public void onClick(DialogInterface dialog, int button) {\n                                        /* Stop running service */\n                                        enablePreferences(false);\n                                        try {\n                                            mRcsServiceControl.setActivationMode(false);\n\n                                        } catch (RcsPermissionDeniedException e) {\n                                            showMessage(R.string.text_service_activate_unchangeable);\n\n                                        } catch (RcsGenericException e) {\n                                            showException(e);\n                                        }\n                                    }\n                                }).setCancelable(true).create();\n                registerDialog(dialog);\n                return dialog;\n        }\n        return super.onCreateDialog(id);\n    }\n\n    @Override\n    public boolean onPreferenceChange(Preference preference, Object objValue) {\n        if (\"min_battery_level\".equals(preference.getKey())) {\n            try {\n                int level = Integer.parseInt((String) objValue);\n                CommonServiceConfiguration configuration = getFileTransferApi()\n                        .getCommonConfiguration();\n                configuration.setMinimumBatteryLevel(MinimumBatteryLevel.valueOf(level));\n\n            } catch (RcsServiceException e) {\n                showException(e);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Initialize the service activation checkbox\n     * \n     * @param checked checked\n     * @param enabled enabled\n     */\n    private void initCheckbox(CheckBoxPreference checkbox, boolean checked, boolean enabled) {\n        checkbox.setChecked(checked);\n        checkbox.setEnabled(enabled);\n    }\n\n    private void initialize() {\n        mRcsServiceListener = new RcsServiceListener() {\n\n            @Override\n            public void onServiceConnected() {\n                try {\n                    enablePreferences(true);\n                    initCheckbox(mRcsActivationCheckbox, true,\n                            mRcsServiceControl.isActivationModeChangeable());\n                    initBatteryLevel(getFileTransferApi().getCommonConfiguration());\n\n                } catch (RcsServiceNotAvailableException ignore) {\n\n                } catch (RcsServiceException e) {\n                    Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n                }\n            }\n\n            @Override\n            public void onServiceDisconnected(ReasonCode reasonCode) {\n                boolean changeable;\n                try {\n                    changeable = mRcsServiceControl.isActivationModeChangeable();\n\n                } catch (RcsGenericException e) {\n                    Log.w(LOGTAG, ExceptionUtil.getFullStackTrace(e));\n                    changeable = true;\n                }\n                enablePreferences(false);\n                initCheckbox(mRcsActivationCheckbox, false, changeable);\n            }\n        };\n    }\n\n    /**\n     * Enable / disable preferences\n     * \n     * @param enabled enabled\n     */\n    private void enablePreferences(boolean enabled) {\n        findPreference(\"min_battery_level\").setEnabled(enabled);\n        findPreference(\"userprofile_settings\").setEnabled(enabled);\n        findPreference(\"messaging_settings\").setEnabled(enabled);\n    }\n\n    /**\n     * Initialize battery level from configuration\n     * \n     * @param configuration configuration\n     * @throws RcsServiceException\n     */\n    private void initBatteryLevel(CommonServiceConfiguration configuration)\n            throws RcsServiceException {\n        mBatteryLevel.setPersistent(false);\n        mBatteryLevel.setOnPreferenceChangeListener(this);\n        mBatteryLevel.setValue(String.valueOf(configuration.getMinimumBatteryLevel().toInt()));\n    }\n\n    private class WaitForConnectionManagerStart extends AsyncTask<Long, Void, Void> {\n\n        private ProgressDialog mProgressDialog;\n\n        @Override\n        protected void onPreExecute() {\n            mProgressDialog = SettingsDisplay.this.showProgressDialog(SettingsDisplay.this\n                    .getString(R.string.rcs_settings_label_wait_cnx_start));\n        }\n\n        @Override\n        protected Void doInBackground(Long... duration) {\n            long delay = (duration[0] / PROGRESS_INIT_INCREMENT);\n            for (int i = 0; i < PROGRESS_INIT_INCREMENT; i++) {\n                try {\n                    Thread.sleep(delay);\n                    if (CoreControlApplication.sCnxManagerStarted) {\n                        break;\n                    }\n                } catch (InterruptedException ignore) {\n                }\n            }\n            return null;\n        }\n\n        @Override\n        protected void onPostExecute(Void res) {\n            mProgressDialog.cancel();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "tools/settings/src/com/gsma/rcs/core/control/settings/UserprofileSettingsDisplay.java",
    "content": "/*******************************************************************************\n * Software Name : RCS IMS Stack\n *\n * Copyright (C) 2010-2016 Orange.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ******************************************************************************/\n\npackage com.gsma.rcs.core.control.settings;\n\nimport com.gsma.services.rcs.RcsServiceException;\n\nimport com.gsma.rcs.api.connection.ConnectionManager.RcsServiceName;\nimport com.gsma.rcs.api.connection.utils.RcsPreferenceActivity;\nimport com.gsma.rcs.core.control.R;\n\nimport android.os.Bundle;\nimport android.preference.EditTextPreference;\nimport android.preference.Preference;\n\n/**\n * Presence settings display\n * \n * @author jexa7410\n */\npublic class UserprofileSettingsDisplay extends RcsPreferenceActivity implements\n        Preference.OnPreferenceChangeListener {\n\n    private EditTextPreference displaynameEdit;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n\n        addPreferencesFromResource(R.xml.rcs_settings_userprofile_preferences);\n\n        displaynameEdit = (EditTextPreference) findPreference(\"edit_displayname\");\n        displaynameEdit.setPersistent(false);\n        displaynameEdit.setOnPreferenceChangeListener(this);\n\n        if (!isServiceConnected(RcsServiceName.FILE_TRANSFER)) {\n            showMessage(R.string.label_service_not_available);\n            return;\n        }\n\n        try {\n            String name = getContactApi().getCommonConfiguration().getMyDisplayName();\n            displaynameEdit.setText(name);\n            displaynameEdit.setTitle(name);\n\n        } catch (RcsServiceException e) {\n            showExceptionThenExit(e);\n        }\n    }\n\n    public boolean onPreferenceChange(Preference preference, Object objValue) {\n        if (\"edit_displayname\".equals(preference.getKey())) {\n            String name = (String) objValue;\n            try {\n                getContactApi().getCommonConfiguration().setMyDisplayName(name);\n                displaynameEdit.setTitle(name);\n\n            } catch (RcsServiceException e) {\n                showExceptionThenExit(e);\n            }\n        }\n        return true;\n    }\n}\n"
  }
]